gdiam.cpp
Go to the documentation of this file.
1/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
2 * gdiam.C -
3 * Computes diameter, and a tight-fitting bounding box of a
4 * point-set in 3d.
5 *
6 * Copyright 2000 Sariel Har-Peled (ssaarriieell@cs.uiuc.edu)
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2,
11 * or (at your option) any later version.
12 *
13 * Code is based on the paper:
14 * A Practical Approach for Computing the Diameter of a
15 * Point-Set (in ACM Sym. on Computation Geometry
16 * SoCG 2001)
17 * Sariel Har-Peled (http://www.uiuc.edu/~sariel)
18 *--------------------------------------------------------------
19 * History
20 * 3/28/01 -
21 * This is a more robust version of the code. It should
22 * handlereally abnoxious inputs well (i.e., points with equal
23 * coordinates, etc.
24\*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
25
26#include "gdiam.h"
27
28#include <assert.h>
29#include <math.h>
30#include <stdio.h>
31#include <stdlib.h>
32
33#include <algorithm>
34#include <vector>
35
36#include <memory.h>
37
38/*--- Constants ---*/
39
40#define HEAP_LIMIT 10000
41#define HEAP_DELTA 10000
42#define PI 3.14159265958979323846
43
44/*--- Start of Code ---*/
45
46typedef long double ldouble;
47
48class GFSPPair;
49
50/*void computeExtremePairDir( const ArrPoint3d & arr,
51 const Point3d & dir,
52 GPointPair & pp,
53 int start,
54 int end
55 );
56*/
57
59{
60private:
61 GBBox bbox;
62 //int left_ind, p_pnt_right; // range in the array
63 gdiam_point *p_pnt_left, *p_pnt_right;
64 gdiam_real bbox_diam, bbox_diam_proj;
65 GFSPTreeNode *left, *right;
66 gdiam_point_t center;
67
68public:
69 void
70 dump() const
71 {
72 printf("dump...\n");
73 //printf( "\tNode: Range: [%d, %d]\n", left_ind, p_pnt_right );
74 }
75
76 int
77 size() const
78 {
79 return (int)(p_pnt_right - p_pnt_left);
80 }
81
83 getCenter() const
84 {
85 return (gdiam_point)center;
86 }
87
88 int
90 {
91 int sum;
92
93 if ((left == NULL) && (right == NULL))
94 {
95 return 1;
96 }
97
98 sum = 1;
99
100 if (left != NULL)
101 {
102 sum += left->nodes_number();
103 }
104
105 if (right != NULL)
106 {
107 sum += right->nodes_number();
108 }
109
110 return sum;
111 }
112
113 GFSPTreeNode(gdiam_point* _p_pnt_left, gdiam_point* _p_pnt_right)
114 {
115 bbox.init();
116 left = right = NULL;
117 p_pnt_left = _p_pnt_left;
118 p_pnt_right = _p_pnt_right;
119 bbox_diam = bbox_diam_proj = -1;
120 }
121
123 maxDiam() const
124 {
125 return bbox_diam;
126 }
127
130 {
131 return bbox_diam_proj;
132 }
133
136 {
137 return left;
138 }
139
142 {
143 return right;
144 }
145
146 bool
148 {
149 return (size() > 1);
150 }
151
152 const gdiam_point*
154 {
155 return p_pnt_left;
156 }
157
158 const gdiam_point*
160 {
161 return p_pnt_left + (rand() % (p_pnt_right - p_pnt_left + 1));
162 }
163
164 const gdiam_point*
166 {
167 return p_pnt_right;
168 }
169
170
171 friend class GFSPTree;
172
173 const GBBox&
174 getBBox() const
175 {
176 return bbox;
177 }
178};
179
181{
182private:
183 gdiam_point* arr;
184 GFSPTreeNode* root;
185
186public:
187 void
188 init(const gdiam_point* _arr, int size)
189 {
190 arr = (gdiam_point*)malloc(sizeof(gdiam_point) * size);
191 assert(arr != NULL);
192
193 for (int ind = 0; ind < size; ind++)
194 {
195 arr[ind] = _arr[ind];
196 }
197
198 root = build_node(arr, arr + size - 1);
199 }
200
201 static void
203 {
204 if (node == NULL)
205 {
206 return;
207 }
208
209 terminate(node->left);
210 terminate(node->right);
211
212 node->left = node->right = NULL;
213
214 delete node;
215 }
216
217 void
219 {
220 free(arr);
221 arr = NULL;
222
224 root = NULL;
225 }
226
227 const gdiam_point*
228 getPoints() const
229 {
230 return arr;
231 }
232
233 int
235 {
236 return root->nodes_number();
237 }
238
240 brute_diameter(int a_lo, int a_hi, int b_lo, int b_hi, GPointPair& diam) const
241 {
242 for (int ind = a_lo; ind <= a_hi; ind++)
243 for (int jnd = b_lo; jnd <= b_hi; jnd++)
244 {
245 diam.update_diam(arr[ind], arr[jnd]);
246 }
247
248 return diam.distance;
249 }
250
252 brute_diameter(int a_lo, int a_hi, int b_lo, int b_hi, GPointPair& diam, const gdiam_point dir)
253 const
254 {
255 for (int ind = a_lo; ind <= a_hi; ind++)
256 for (int jnd = b_lo; jnd <= b_hi; jnd++)
257 {
258 diam.update_diam(arr[ind], arr[jnd], dir);
259 }
260
261 return diam.distance;
262 }
263
266 const gdiam_point* a_hi,
267 const gdiam_point* b_lo,
268 const gdiam_point* b_hi,
269 GPointPair& diam) const
270 {
271 for (const gdiam_point* ind = a_lo; ind <= a_hi; ind++)
272 for (const gdiam_point* jnd = b_lo; jnd <= b_hi; jnd++)
273 {
274 diam.update_diam(*ind, *jnd);
275 }
276
277 return diam.distance;
278 }
279
282 const gdiam_point* a_hi,
283 const gdiam_point* b_lo,
284 const gdiam_point* b_hi,
285 GPointPair& diam,
286 const gdiam_point dir) const
287 {
288 for (const gdiam_point* ind = a_lo; ind <= a_hi; ind++)
289 for (const gdiam_point* jnd = b_lo; jnd <= b_hi; jnd++)
290 {
291 diam.update_diam(*ind, *jnd, dir);
292 }
293
294 return diam.distance;
295 }
296
298 getPoint(int ind) const
299 {
300 return arr[ind];
301 }
302
305 {
306 return root;
307 }
308
311 {
312 if (left > right)
313 {
314 printf("what!?\n");
315 fflush(stdout);
316 assert(left <= right);
317 }
318
319 while ((right > left) && (pnt_isEqual(*right, *left)))
320 {
321 right--;
322 }
323
324 GFSPTreeNode* node = new GFSPTreeNode(left, right);
325
326 node->bbox.init();
327
328 for (const gdiam_point* ind = left; ind <= right; ind++)
329 {
330 node->bbox.bound(*ind);
331 }
332
333 node->bbox_diam = node->bbox.get_diam();
334
335 node->bbox.center(node->center);
336
337 return node;
338 }
339
340 // return how many elements on left side.
341 int
342 split_array(gdiam_point* left, gdiam_point* right, int dim, const gdiam_real& val)
343 {
344 const gdiam_point* start_left = left;
345
346 while (left < right)
347 {
348 if ((*left)[dim] < val)
349 {
350 left++;
351 }
352 else if ((*right)[dim] >= val)
353 {
354 right--;
355 }
356 else
357 {
358 gdiam_exchange(*right, *left);
359 }
360 }
361
362 return left - start_left;
363 }
364
365 void
367 {
368 int dim, left_size;
369 gdiam_real split_val;
370
371 if (node->left != NULL)
372 {
373 return;
374 }
375
376 GBBox& bb(node->bbox);
377
378 dim = bb.getLongestDim();
379 split_val = (bb.min_coord(dim) + bb.max_coord(dim)) / 2.0;
380
381 left_size = split_array(node->p_pnt_left, node->p_pnt_right, dim, split_val);
382
383 if (left_size <= 0.0)
384 {
385 printf("bb: %g %g\n", bb.min_coord(dim), bb.max_coord(dim));
386 printf("left: %p, right: %p\n", node->p_pnt_left, node->p_pnt_right);
387 assert(left_size > 0);
388 }
389
390 if (left_size >= (node->p_pnt_right - node->p_pnt_left + 1))
391 {
392 printf("left size too large?\n");
393 fflush(stdout);
394 assert(left_size < (node->p_pnt_right - node->p_pnt_left + 1));
395 }
396
397 node->left = build_node(node->p_pnt_left, node->p_pnt_left + left_size - 1);
398 node->right = build_node(node->p_pnt_left + left_size, node->p_pnt_right);
399 }
400
401 void findExtremeInProjection(GFSPPair& pair, GPointPair& max_pair_diam);
402};
403
404void
405bbox_vertex(const GBBox& bb, gdiam_point_t& ver, int vert)
406{
407 ver[0] = ((vert & 0x1) != 0) ? bb.min_coord(0) : bb.max_coord(0);
408 ver[1] = ((vert & 0x2) != 0) ? bb.min_coord(1) : bb.max_coord(1);
409 ver[2] = ((vert & 0x4) != 0) ? bb.min_coord(2) : bb.max_coord(2);
410}
411
413bbox_proj_dist(const GBBox& bb1, const GBBox& bb2, gdiam_point_cnt proj)
414{
415 gdiam_point_t a, b;
416 gdiam_real rl;
417
418 rl = 0;
419
420 for (int ind = 0; ind < 8; ind++)
421 {
422 bbox_vertex(bb1, a, ind);
423
424 //printf( "\n\n" );
425 for (int jnd = 0; jnd < 8; jnd++)
426 {
427 bbox_vertex(bb2, b, jnd);
428 //pnt_dump( b );
429 rl = max(rl, pnt_distance(a, b, proj));
430 }
431 }
432
433 return rl;
434}
435
437{
438private:
439 GFSPTreeNode *left, *right;
440 double max_diam;
441
442public:
443 void
445 {
446 left = _left;
447 right = _right;
448
449 GBBox bb;
450
451 bb.init(left->getBBox(), right->getBBox());
452 //printf( "\t\tbbox: \n" );
453 //bb.dump();
454 max_diam = bb.get_diam();
455 //printf( "\t\tmax_diam: %g\n", max_diam );
456 }
457
458 void
459 init(GFSPTreeNode* _left, GFSPTreeNode* _right, gdiam_point proj_dir, gdiam_real dist)
460 {
461 left = _left;
462 right = _right;
463
464 GBBox bb;
465
466 bb.init(left->getBBox(), right->getBBox());
467 //printf( "\t\tbbox: \n" );
468 //bb.dump();
469
470 //max_diam = dist + _left->getBBox().get_diam()
471 // + _right->getBBox().get_diam();
472 max_diam = max(max(bbox_proj_dist(_left->getBBox(), _right->getBBox(), proj_dir),
473 bbox_proj_dist(_left->getBBox(), _left->getBBox(), proj_dir)),
474 bbox_proj_dist(_right->getBBox(), _right->getBBox(), proj_dir));
475
476 //printf( "diam: %g, smart diam: %g\n",
477 // max_diam,
478 // bbox_proj_dist( _left->getBBox(),
479 // _right->getBBox(),
480 // proj_dir ) );
481
482 //printf( "dist: %g, %g, %g:\n",
483 // dist, _left->getBBox().get_diam(),
484 // _right->getBBox().get_diam() );
485
486 //bb.get_diam_proj( proj_dir );
487 //printf( "\t\tmax_diam: %g\n", max_diam );
488 }
489
490 // error 2r/l - approximate cos of the max possible angle in the pair
491 double
493 {
494 double l, two_r;
495
496 l = pnt_distance(left->getCenter(), right->getCenter());
497 two_r = max(left->maxDiam(), right->maxDiam());
498
499 if (l == 0.0)
500 {
501 return 10;
502 }
503
504 return two_r / l;
505 }
506
509 {
510 return left;
511 }
512
515 {
516 return right;
517 }
518
519 void
520 dump() const
521 {
522 printf("[\n");
523 left->dump();
524 right->dump();
525 printf("\tmax_diam; %g\n", max_diam);
526 }
527
528 bool
529 isBelowThreshold(int threshold) const
530 {
531 if (left->size() > threshold)
532 {
533 return false;
534 }
535
536 if (right->size() > threshold)
537 {
538 return false;
539 }
540
541 return true;
542 }
543
544 double
545 directDiameter(const GFSPTree& tree, GPointPair& diam) const
546 {
547 return tree.brute_diameter(left->ptr_pnt_left(),
548 left->ptr_pnt_right(),
549 right->ptr_pnt_left(),
550 right->ptr_pnt_right(),
551 diam);
552 }
553
554 double
555 directDiameter(const GFSPTree& tree, GPointPair& diam, const gdiam_point dir) const
556 {
557 return tree.brute_diameter(left->ptr_pnt_left(),
558 left->ptr_pnt_right(),
559 right->ptr_pnt_left(),
560 right->ptr_pnt_right(),
561 diam,
562 dir);
563 }
564
565 double
566 maxDiam() const
567 {
568 return max_diam;
569 }
570
571 double
573 {
574 double sub_diam;
575
576 sub_diam = left->maxDiam() + right->maxDiam();
577
578 if (sub_diam > (max_diam / 10.0))
579 {
580 return max_diam;
581 }
582
583 return max_diam - sub_diam / 2.0;
584 }
585};
586
587
588class g_heap_pairs_p;
589
590#define UDM_SIMPLE 1
591#define UDM_BIG_SAMPLE 2
592
594{
595private:
596 GFSPTree tree;
597 //double diam;
598 GPointPair pair_diam;
599 int points_num;
600 int threshold_brute;
601 int update_diam_mode;
602
603public:
604 GTreeDiamAlg(gdiam_point* arr, int size, int mode)
605 {
606 tree.init(arr, size);
607 //diam = 0;
608 pair_diam.init(arr[0]);
609 points_num = size;
610 threshold_brute = 40;
611 update_diam_mode = mode;
612 }
613
614 void
616 {
617 tree.term();
618 }
619
620 int
621 size() const
622 {
623 return points_num;
624 }
625
626 const GPointPair&
628 {
629 return pair_diam;
630 }
631
632 int
634 {
635 return tree.nodes_number();
636 }
637
638 void addPairHeap(g_heap_pairs_p& heap, GFSPTreeNode* left, GFSPTreeNode* right);
639 void addPairHeap(g_heap_pairs_p& heap,
640 GFSPTreeNode* left,
641 GFSPTreeNode* right,
642 gdiam_point proj,
643 GFSPPair& father);
644 void split_pair(GFSPPair& pair, g_heap_pairs_p& heap, double eps);
645 void split_pair_proj(GFSPPair& pair, g_heap_pairs_p& heap, double eps, gdiam_point proj);
646 void compute_by_heap(double eps);
647 void compute_by_heap_proj(double eps, gdiam_point proj);
648
649 double
651 {
652 return pair_diam.distance;
653 }
654};
655
656/*--- Heap implementation ---*/
657
658typedef int (*ptrCompareFunc)(void* aPtr, void* bPtr);
659typedef void* voidPtr_t;
660
667
668void
669heap_init(heap_t* pHeap, ptrCompareFunc _pCompFunc)
670{
671 assert(pHeap != NULL);
672 assert(_pCompFunc != NULL);
673
674 memset(pHeap, 0, sizeof(heap_t));
675
676 pHeap->pCompFunc = _pCompFunc;
677 pHeap->max_size = 100;
678 pHeap->pArr = (voidPtr_t*)malloc(sizeof(void*) * pHeap->max_size);
679 assert(pHeap->pArr != NULL);
680 pHeap->curr_size = 0;
681}
682
683static void
684resize(heap_t* pHeap, int size)
685{
686 int max_sz;
687 voidPtr_t* pTmp;
688
689 if (size <= pHeap->max_size)
690 {
691 return;
692 }
693
694 max_sz = size * 2;
695 pTmp = (voidPtr_t*)malloc(max_sz * sizeof(void*));
696 assert(pTmp != NULL);
697 memset(pTmp, 0, max_sz * sizeof(void*));
698 memcpy(pTmp, pHeap->pArr, pHeap->curr_size * sizeof(void*));
699 free(pHeap->pArr);
700 pHeap->pArr = pTmp;
701}
702
703void
705{
706 assert(pHeap != NULL);
707
708 if (pHeap->pArr != NULL)
709 {
710 free(pHeap->pArr);
711 }
712
713 memset(pHeap, 0, sizeof(heap_t));
714}
715
716void
717heap_insert(heap_t* pHeap, void* pData)
718{
719 int ind, father;
720 voidPtr_t pTmp;
721
722 resize(pHeap, pHeap->curr_size + 1);
723
724 ind = pHeap->curr_size;
725 pHeap->curr_size++;
726
727 pHeap->pArr[ind] = pData;
728
729 while (ind > 0)
730 {
731 father = (ind - 1) / 2;
732
733 if ((*pHeap->pCompFunc)(pHeap->pArr[ind], pHeap->pArr[father]) <= 0)
734 {
735 break;
736 }
737
738 pTmp = pHeap->pArr[ind];
739 pHeap->pArr[ind] = pHeap->pArr[father];
740 pHeap->pArr[father] = pTmp;
741
742 ind = father;
743 }
744}
745
746void*
748{
749 return pHeap->pArr[0];
750}
751
752void*
754{
755 void* res;
756 void* pTmp;
757 int ind, left, right, max_ind;
758
759 if (pHeap->curr_size <= 0)
760 {
761 return NULL;
762 }
763
764 res = pHeap->pArr[0];
765
766 //printf( "pHeap->curr_size: %d\n", pHeap->curr_size );
767 //printf( "res= %p\n", res );
768
769 pHeap->curr_size--;
770 pHeap->pArr[0] = pHeap->pArr[pHeap->curr_size];
771 pHeap->pArr[pHeap->curr_size] = NULL;
772 ind = 0;
773
774 while (ind < pHeap->curr_size)
775 {
776 left = 2 * ind + 1;
777 right = 2 * ind + 2;
778
779 if (left >= pHeap->curr_size)
780 {
781 break;
782 }
783
784 if (right >= pHeap->curr_size)
785 {
786 right = left;
787 }
788
789 if ((*pHeap->pCompFunc)(pHeap->pArr[left], pHeap->pArr[right]) <= 0)
790 {
791 max_ind = right;
792 }
793 else
794 {
795 max_ind = left;
796 }
797
798 if ((*pHeap->pCompFunc)(pHeap->pArr[ind], pHeap->pArr[max_ind]) >= 0)
799 {
800 break;
801 }
802
803 pTmp = pHeap->pArr[ind];
804 pHeap->pArr[ind] = pHeap->pArr[max_ind];
805 pHeap->pArr[max_ind] = pTmp;
806
807 ind = max_ind;
808 }
809
810 return res;
811}
812
813bool
815{
816 assert(pHeap != NULL);
817
818 return (pHeap->curr_size <= 0);
819}
820
821int
822compare_pairs(void* _a, void* _b)
823{
824 const GFSPPair& a(*(GFSPPair*)_a);
825 const GFSPPair& b(*(GFSPPair*)_b);
826
827 if (a.maxDiam() < b.maxDiam())
828 {
829 return -1;
830 }
831
832 if (a.maxDiam() > b.maxDiam())
833 {
834 return 1;
835 }
836
837 return 0;
838}
839
841{
842private:
843 heap_t heap;
844
845public:
847 {
848 heap_init(&heap, compare_pairs);
849 }
850
852 {
853 while (size() > 0)
854 {
855 pop();
856 }
857
858 heap_term(&heap);
859 }
860
861 void
863 {
864 //printf( "pushing: (%p, %p)\n", pair.get_left(),
865 // pair.get_right() );
866 GFSPPair* p_pair = new GFSPPair(pair);
867 heap_insert(&heap, (void*)p_pair);
868 }
869
870 int
871 size() const
872 {
873 return heap.curr_size;
874 }
875
878 {
879 return *(GFSPPair*)heap_top(&heap);
880 }
881
882 void
884 {
885 GFSPPair* ptr = (GFSPPair*)heap_delete_max(&heap);
886
887 delete ptr;
888 }
889};
890
891/* heap.implementation end */
892
893
894void
895computeExtremePair(const gdiam_point* arr, int size, int dim, GPointPair& pp)
896{
897 pp.init(arr[0]);
898
899 for (int ind = 1; ind < size; ind++)
900 {
901 const gdiam_point pnt(arr[ind]);
902
903 if (pnt[dim] < pp.p[dim])
904 {
905 pp.p = pnt;
906 }
907
908 if (pnt[dim] > pp.q[dim])
909 {
910 pp.q = pnt;
911 }
912 }
913
914 pp.distance = pnt_distance(pp.p, pp.q);
915}
916
917void
919{
920 g_heap_pairs_p heap;
921 int heap_limit, heap_delta;
922
923 heap_limit = HEAP_LIMIT;
924 heap_delta = HEAP_DELTA;
925
926 GFSPTreeNode* root = tree.getRoot();
927
928 computeExtremePair(tree.getPoints(), points_num, root->getBBox().getLongestDim(), pair_diam);
929
930 GFSPPair root_pair;
931
932 root_pair.init(root, root);
933
934 heap.push(root_pair);
935 //queue_a.pushx( root_pair );
936
937 int count = 0;
938
939 while (heap.size() > 0)
940 {
941 //printf( "heap.size: %d\n", heap.size() );
942 //printf( "%d: curr_diam: %g\n", count++, pair_diam.distance );
943 GFSPPair pair = heap.top();
944 heap.pop();
945 split_pair(pair, heap, eps);
946
947 //if ( ( count & 0x3ff ) == 0 ) {
948 // printf( "heap.size: %d\n", heap.size() );
949 //}
950 if ((count & 0x3ff) == 0)
951 {
952 if (((int)heap.size()) > heap_limit)
953 {
954 threshold_brute *= 2;
955 printf("threshold_brute: %d\n", threshold_brute);
956 heap_limit += heap_delta;
957 }
958 }
959
960 count++;
961 }
962}
963
964void
966{
967 g_heap_pairs_p heap;
968 int heap_limit, heap_delta;
969 GPointPair pair_diam_x;
970
971
972 //pnt_dump( proj );
973 //printf( "length = %g\n", pnt_length( proj ) );
974
975 heap_limit = HEAP_LIMIT;
976 heap_delta = HEAP_DELTA;
977
978 GFSPTreeNode* root = tree.getRoot();
979
980 computeExtremePair(tree.getPoints(), points_num, root->getBBox().getLongestDim(), pair_diam_x);
981 pair_diam.init(pair_diam_x.p, pair_diam_x.q, proj);
982
983 GFSPPair root_pair;
984
985 root_pair.init(root, root, proj, 0);
986
987 //printf( "root pair distance: %g\n", root_pair.maxDiam() );
988 heap.push(root_pair);
989 //queue_a.pushx( root_pair );
990
991 int count = 0;
992
993 while (heap.size() > 0)
994 {
995 //printf( "heap.size: %d\n", heap.size() );
996 //printf( "%d: curr_diam: %g\n", count++, pair_diam.distance );
997 GFSPPair pair = heap.top();
998 heap.pop();
999 //printf( "pair distance: %g\n", pair.maxDiam() );
1000 split_pair_proj(pair, heap, eps, proj);
1001
1002 //if ( ( count & 0x3ff ) == 0 ) {
1003 // printf( "heap.size: %d\n", heap.size() );
1004 //}
1005 if ((count & 0x3ff) == 0)
1006 {
1007 if (((int)heap.size()) > heap_limit)
1008 {
1009 threshold_brute *= 2;
1010 printf("threshold_brute: %d\n", threshold_brute);
1011 heap_limit += heap_delta;
1012 }
1013 }
1014
1015 count++;
1016 //printf( "Poping!\n" );
1017 }
1018}
1019
1020void
1022{
1023 if (update_diam_mode == UDM_SIMPLE)
1024 {
1025 const gdiam_point p(*(left->ptr_pnt_left()));
1026 const gdiam_point q(*(right->ptr_pnt_left()));
1027
1028 pair_diam.update_diam(p, q);
1029 }
1030 else if (update_diam_mode == UDM_BIG_SAMPLE)
1031 {
1032 if ((left->size() < 100) || (right->size() < 100))
1033 {
1034 const gdiam_point p(*(left->ptr_pnt_left()));
1035 const gdiam_point q(*(right->ptr_pnt_left()));
1036
1037 pair_diam.update_diam(p, q);
1038 }
1039 else
1040 {
1041#define UMD_SIZE 5
1042 gdiam_point arr_left[UMD_SIZE], arr_right[UMD_SIZE];
1043
1044 for (int ind = 0; ind < UMD_SIZE; ind++)
1045 {
1046 const gdiam_point p(*(left->ptr_pnt_rand()));
1047 const gdiam_point q(*(right->ptr_pnt_rand()));
1048 arr_left[ind] = p;
1049 arr_right[ind] = q;
1050
1051 //pair_diam.update_diam( p, q );
1052 }
1053
1054 for (int ind = 0; ind < UMD_SIZE; ind++)
1055 for (int jnd = 0; jnd < UMD_SIZE; jnd++)
1056 pair_diam.update_diam(arr_left[ind], arr_right[jnd]);
1057 }
1058 }
1059 else
1060 {
1061 assert(false);
1062 }
1063
1064 //printf( "old_diam; %g\n", diam );
1065 //diam = max( diam, pnt_distance( p, q ) );
1066 //printf( "new_diam; %g\n", diam );
1067
1068 GFSPPair pair;
1069
1070 pair.init(left, right);
1071
1072 if (pair.maxDiam() <= pair_diam.distance)
1073 {
1074 return;
1075 }
1076
1077 heap.push(pair);
1078}
1079
1080void
1082 GFSPTreeNode* left,
1083 GFSPTreeNode* right,
1084 gdiam_point proj,
1085 GFSPPair& father)
1086{
1087 const gdiam_point p(*(left->ptr_pnt_left()));
1088 const gdiam_point q(*(right->ptr_pnt_left()));
1089
1090 //printf( "addPairHeap( ?, %p, %p, ? )\n", left, right );
1091 pair_diam.update_diam(p, q, proj);
1092 //printf( "old_diam; %g\n", diam );
1093 //diam = max( diam, pnt_distance( p, q ) );
1094 //printf( "new_diam; %g\n", diam );
1095
1096 GFSPPair pair;
1097
1098 pair.init(left, right, proj, pnt_distance(p, q, proj));
1099
1100 if (pair.maxDiam() <= pair_diam.distance)
1101 {
1102 return;
1103 }
1104
1105 //printf( "pair.maxDiam: %g, father.maxDiam: %g\n",
1106 // pair.maxDiam(), father.maxDiam() );
1107 //printf( "pair_diam.distance: %g\n", pair_diam.distance );
1108 //pnt_dump( proj );
1109 heap.push(pair);
1110}
1111
1112void
1114{
1115 bool f_is_left_splitable, f_is_right_splitable;
1116
1117 //printf( "pair.maxDiam: %g, limit: %g\n",
1118 // pair.maxDiam(), ((1.0 + eps) * pair_diam.distance ));
1119
1120 if (pair.maxDiam() <= ((1.0 + eps) * pair_diam.distance))
1121 {
1122 return;
1123 }
1124
1125 if (pair.isBelowThreshold(threshold_brute))
1126 {
1127 pair.directDiameter(tree, pair_diam, proj);
1128 return;
1129 }
1130
1131 //printf( "Curr pair: (%p, %p)\n", pair.get_left(), pair.get_right() );
1132 f_is_left_splitable = pair.get_left()->isSplitable();
1133 f_is_right_splitable = pair.get_right()->isSplitable();
1134 assert(f_is_left_splitable || f_is_right_splitable);
1135
1136 if (f_is_left_splitable)
1137 {
1138 tree.split_node(pair.get_left());
1139 }
1140
1141 if (f_is_right_splitable)
1142 {
1143 tree.split_node(pair.get_right());
1144 }
1145
1146 if (f_is_left_splitable && f_is_right_splitable)
1147 {
1148 addPairHeap(heap, pair.get_left()->get_left(), pair.get_right()->get_left(), proj, pair);
1149 addPairHeap(heap, pair.get_left()->get_left(), pair.get_right()->get_right(), proj, pair);
1150
1151 // to avoid exponential blowup
1152 if (pair.get_left() != pair.get_right())
1154 heap, pair.get_left()->get_right(), pair.get_right()->get_left(), proj, pair);
1155
1156 addPairHeap(heap, pair.get_left()->get_right(), pair.get_right()->get_right(), proj, pair);
1157 return;
1158 }
1159
1160 if (f_is_left_splitable)
1161 {
1162 addPairHeap(heap, pair.get_left()->get_left(), pair.get_right(), proj, pair);
1163 addPairHeap(heap, pair.get_left()->get_right(), pair.get_right(), proj, pair);
1164 return;
1165 }
1166
1167 if (f_is_right_splitable)
1168 {
1169 addPairHeap(heap, pair.get_left(), pair.get_right()->get_left(), proj, pair);
1170 addPairHeap(heap, pair.get_left(), pair.get_right()->get_right(), proj, pair);
1171 return;
1172 }
1173}
1174
1175void
1177{
1178 bool f_is_left_splitable, f_is_right_splitable;
1179
1180 if (pair.maxDiam() <= ((1.0 + eps) * pair_diam.distance))
1181 {
1182 return;
1183 }
1184
1185 if (pair.isBelowThreshold(threshold_brute))
1186 {
1187 pair.directDiameter(tree, pair_diam);
1188 return;
1189 }
1190
1191 f_is_left_splitable = pair.get_left()->isSplitable();
1192 f_is_right_splitable = pair.get_right()->isSplitable();
1193 assert(f_is_left_splitable || f_is_right_splitable);
1194
1195 if (f_is_left_splitable)
1196 {
1197 tree.split_node(pair.get_left());
1198 }
1199
1200 if (f_is_right_splitable)
1201 {
1202 tree.split_node(pair.get_right());
1203 }
1204
1205 if (f_is_left_splitable && f_is_right_splitable)
1206 {
1207 addPairHeap(heap, pair.get_left()->get_left(), pair.get_right()->get_left());
1208 addPairHeap(heap, pair.get_left()->get_left(), pair.get_right()->get_right());
1209
1210 // to avoid exponential blowup
1211 if (pair.get_left() != pair.get_right())
1212 addPairHeap(heap, pair.get_left()->get_right(), pair.get_right()->get_left());
1213
1214 addPairHeap(heap, pair.get_left()->get_right(), pair.get_right()->get_right());
1215 return;
1216 }
1217
1218 if (f_is_left_splitable)
1219 {
1220 addPairHeap(heap, pair.get_left()->get_left(), pair.get_right());
1221 addPairHeap(heap, pair.get_left()->get_right(), pair.get_right());
1222 return;
1223 }
1224
1225 if (f_is_right_splitable)
1226 {
1227 addPairHeap(heap, pair.get_left(), pair.get_right()->get_left());
1228 addPairHeap(heap, pair.get_left(), pair.get_right()->get_right());
1229 return;
1230 }
1231}
1232
1235{
1236 //gdiam_real diam;
1237 GPointPair pair;
1238
1239 GTreeDiamAlg* pAlg = new GTreeDiamAlg(start, size, UDM_SIMPLE);
1240 pAlg->compute_by_heap(eps);
1241
1242 pair = pAlg->getDiameter();
1243
1244 delete pAlg;
1245
1246 return pair;
1247}
1248
1251{
1252 //gdiam_real diam;
1253 GPointPair pair;
1254
1255 GTreeDiamAlg* pAlg = new GTreeDiamAlg(start, size, UDM_BIG_SAMPLE);
1256 pAlg->compute_by_heap(eps);
1257
1258 pair = pAlg->getDiameter();
1259
1260 delete pAlg;
1261
1262 return pair;
1263}
1264
1266gdiam_convert(gdiam_real* start, int size)
1267{
1268 gdiam_point* p_arr;
1269
1270 assert(start != NULL);
1271 assert(size > 0);
1272
1273 p_arr = (gdiam_point*)malloc(sizeof(gdiam_point) * size);
1274 assert(p_arr != NULL);
1275
1276 for (int ind = 0; ind < size; ind++)
1277 {
1278 p_arr[ind] = (gdiam_point) & (start[ind * 3]);
1279 }
1280
1281 return p_arr;
1282}
1283
1286{
1287 gdiam_point* p_arr;
1288 GPointPair pair;
1289
1290 p_arr = gdiam_convert(start, size);
1291 pair = gdiam_approx_diam(p_arr, size, eps);
1292 free(p_arr);
1293
1294 return pair;
1295}
1296
1299{
1300 gdiam_point* p_arr;
1301 GPointPair pair;
1302
1303 p_arr = gdiam_convert(start, size);
1304 pair = gdiam_approx_diam_UDM(p_arr, size, eps);
1305 free(p_arr);
1306
1307 return pair;
1308}
1309
1311gdiam_approx_const_mvbb(gdiam_point* start, int size, gdiam_real eps, GBBox* p_ap_bbox)
1312{
1313 //gdiam_real diam;
1314 GPointPair pair, pair_2;
1315
1316 GTreeDiamAlg* pAlg = new GTreeDiamAlg(start, size, UDM_SIMPLE);
1317 pAlg->compute_by_heap(eps);
1318
1319 pair = pAlg->getDiameter();
1320
1321 /* Comput ethe resulting diameter */
1322 gdiam_point_t dir, dir_2, dir_3;
1323
1324 dir[0] = pair.p[0] - pair.q[0];
1325 dir[1] = pair.p[1] - pair.q[1];
1326 dir[2] = pair.p[2] - pair.q[2];
1327 pnt_normalize(dir);
1328
1329 // printf( "Before computing second direction!\n" );
1330 //fflush( stdout );
1331 pAlg->compute_by_heap_proj(eps, dir);
1332 //printf( "second direction computed!\n" );
1333 //fflush( stdout );
1334
1335 pair_2 = pAlg->getDiameter();
1336 dir_2[0] = pair_2.p[0] - pair_2.q[0];
1337 dir_2[1] = pair_2.p[1] - pair_2.q[1];
1338 dir_2[2] = pair_2.p[2] - pair_2.q[2];
1339
1340 gdiam_real prd;
1341
1342 prd = pnt_dot_prod(dir, dir_2);
1343 dir_2[0] = dir_2[0] - prd * dir[0];
1344 dir_2[1] = dir_2[1] - prd * dir[1];
1345 dir_2[2] = dir_2[2] - prd * dir[2];
1346
1347 pnt_normalize(dir);
1348 pnt_normalize(dir_2);
1349
1350 pnt_cross_prod(dir, dir_2, dir_3);
1351 pnt_normalize(dir_3);
1352
1353 gdiam_bbox bbox;
1354 GBBox ap_bbox;
1355
1356 if ((pnt_length(dir_2) < 1e-6) && (pnt_length(dir_3) < 1e-6))
1357 {
1358 gdiam_generate_orthonormal_base(dir, dir_2, dir_3);
1359 }
1360
1361 if ((pnt_length(dir) == 0.0) || (pnt_length(dir_2) < 1e-6) || (pnt_length(dir_3) < 1e-6))
1362 {
1363 gdiam_generate_orthonormal_base(dir, dir_2, dir_3);
1364 pnt_dump(dir);
1365 pnt_dump(dir_2);
1366 pnt_dump(dir_3);
1367
1368 fflush(stdout);
1369 fflush(stderr);
1370 assert(false);
1371 }
1372
1373 bbox.init(dir, dir_2, dir_3);
1374 ap_bbox.init();
1375
1376 for (int ind = 0; ind < size; ind++)
1377 {
1378 bbox.bound(start[ind]);
1379 ap_bbox.bound(start[ind]);
1380 }
1381
1382 //printf( "Axis parallel bounding box:\n" );
1383 //ap_bbox.dump();
1384
1385 //printf( "Arbitrarily oriented bounding box:\n" );
1386 //bbox.dump();
1387
1388 delete pAlg;
1389
1390 if (ap_bbox.volume() < bbox.volume())
1391 {
1392 bbox.init(ap_bbox);
1393 }
1394
1395 if (p_ap_bbox != NULL)
1396 {
1397 *p_ap_bbox = ap_bbox;
1398 }
1399
1400 return bbox;
1401}
1402
1405{
1406 gdiam_point* p_arr;
1407 gdiam_bbox gbbox;
1408
1409 p_arr = gdiam_convert(start, size);
1410 gbbox = gdiam_approx_const_mvbb(p_arr, size, eps, NULL);
1411 free(p_arr);
1412
1413 return gbbox;
1414}
1415
1416/*-----------------------------------------------------------------------
1417 * Code for computing best bounding box in a given drection
1418\*-----------------------------------------------------------------------*/
1419
1420void
1422{
1423 assert(pnt_length(in) > 0.0);
1424
1425 pnt_normalize(in);
1426
1427 // stupid cases..
1428 if (in[0] == 0.0)
1429 {
1430 if (in[1] == 0.0)
1431 {
1432 pnt_init_normalize(out1, 1, 0, 0);
1433 pnt_init_normalize(out2, 0, 1, 0);
1434 return;
1435 }
1436
1437 if (in[2] == 0.0)
1438 {
1439 pnt_init_normalize(out1, 1, 0, 0);
1440 pnt_init_normalize(out2, 0, 0, 1);
1441 return;
1442 }
1443
1444 pnt_init_normalize(out1, 0, -in[2], in[1]);
1445 pnt_init_normalize(out2, 1, 0, 0);
1446 return;
1447 }
1448
1449 if ((in[1] == 0.0) && (in[2] == 0.0))
1450 {
1451 pnt_init_normalize(out1, 0, 1, 0);
1452 pnt_init_normalize(out2, 0, 0, 1);
1453 return;
1454 }
1455
1456 if (in[1] == 0.0)
1457 {
1458 pnt_init_normalize(out1, -in[2], 0, in[0]);
1459 pnt_init_normalize(out2, 0, 1, 0);
1460 return;
1461 }
1462
1463 if (in[2] == 0.0)
1464 {
1465 pnt_init_normalize(out1, -in[1], in[0], 0);
1466 pnt_init_normalize(out2, 0, 0, 1);
1467 return;
1468 }
1469
1470 // all entries in the vector are not zero.
1471 pnt_init_normalize(out1, -in[1], in[0], 0);
1472 pnt_cross_prod(in, out1, out2);
1473
1474 pnt_normalize(out2);
1475}
1476
1478{
1479public:
1482
1483 void
1485 {
1486 src = pnt;
1487 x = pnt_dot_prod(pnt, base_x);
1488 y = pnt_dot_prod(pnt, base_y);
1489 }
1490
1492 dist(const point2d& pnt)
1493 {
1494 return sqrt((x - pnt.x) * (x - pnt.x) + (y - pnt.y) * (y - pnt.y));
1495 }
1496
1497 void
1498 dump() const
1499 {
1500 printf("(%g, %g)\n", x, y);
1501 }
1502
1503 bool
1504 equal(const point2d& pnt) const
1505 {
1506 return ((x == pnt.x) && (y == pnt.y));
1507 }
1508
1509 bool
1510 equal_real(const point2d& pnt) const
1511 {
1512 return ((fabs(x - pnt.x) < 1e-8) && (fabs(y - pnt.y) < 1e-8));
1513 }
1514};
1515
1517
1518class vec_point_2d : public std::vector<point2d_ptr>
1519{
1520};
1521
1522inline ldouble
1523Area(const point2d& a, const point2d& b, const point2d& c)
1524{
1525 double x1, y1, x2, y2, len;
1526
1527 x1 = b.x - a.x;
1528 y1 = b.y - a.y;
1529
1530 x2 = c.x - a.x;
1531 y2 = c.y - a.y;
1532
1533 if ((x1 != 0.0) || (y1 != 0.0))
1534 {
1535 len = sqrt(x1 * x1 + y1 * y1);
1536 x1 /= len;
1537 y1 /= len;
1538 }
1539
1540 if ((x2 != 0.0) || (y2 != 0.0))
1541 {
1542 len = sqrt(x2 * x2 + y2 * y2);
1543 x2 /= len;
1544 y2 /= len;
1545 }
1546
1547 ldouble area;
1548
1549 area = x1 * y2 - x2 * y1;
1550 //area = (ldouble)a.x * (ldouble)b.y - (ldouble)a.y * (ldouble)b.x +
1551 // (ldouble)a.y * (ldouble)c.x - (ldouble)a.x * (ldouble)c.y +
1552 // (ldouble)b.x * (ldouble)c.y - (ldouble)c.x * (ldouble)b.y;
1553
1554 //printf( "area: %g\n", area );
1555 return area;
1556}
1557
1558inline int
1559AreaSign(const point2d& a, const point2d& b, const point2d& c)
1560{
1561 ldouble area;
1562
1563 area = a.x * b.y - a.y * b.x + a.y * c.x - a.x * c.y + b.x * c.y - c.x * b.y;
1564
1565 //printf( "area: %g\n", area );
1566 return ((area < (ldouble)0.0) ? -1 : ((area > (ldouble)0.0) ? 1 : 0));
1567}
1568
1569inline bool
1570Left(const point2d& a, const point2d& b, const point2d& c)
1571{
1572 return AreaSign(a, b, c) > 0;
1573}
1574
1575inline bool
1576Left_colinear(const point2d& a, const point2d& b, const point2d& c)
1577{
1578 return AreaSign(a, b, c) >= 0;
1579}
1580
1582{
1583public:
1585
1586 bool
1588 {
1589 int sgn;
1590 gdiam_real len1, len2;
1591
1592 if (a->equal(*b))
1593 {
1594 return false;
1595 }
1596
1597 assert(a != NULL);
1598 assert(b != NULL);
1599
1600 if (a->equal(base))
1601 {
1602 //assert( false );
1603 return true;
1604 }
1605
1606 if (b->equal(base))
1607 {
1608 // assert( false );
1609 return false;
1610 }
1611
1612 //printf( "before: %p %p...\n", a, b );
1613 //fflush( stdout );
1614 /*
1615 if ( a->equal( base ) )
1616 return true;
1617 if ( b->equal( base ) )
1618 return false;
1619 */
1620 //printf( "a: (%g, %g)\n", a->x, a->y );
1621 //printf( "b: (%g, %g)\n", b->x, b->y );
1622 //fflush( stdout );
1623
1624 sgn = AreaSign(base, *a, *b);
1625
1626 if (sgn != 0)
1627 {
1628 return (sgn > 0);
1629 }
1630
1631 len1 = base.dist(*a);
1632 len2 = base.dist(*b);
1633
1634 //printf( "bogi!\n" );
1635 //fflush( stdout );
1636
1637 return (len1 > len2);
1638 }
1639};
1640
1643{
1644 point2d_ptr min_pnt = in[0];
1645
1646 index = 0;
1647
1648 for (int ind = 0; ind < (int)in.size(); ind++)
1649 {
1650 if (in[ind]->y < min_pnt->y)
1651 {
1652 min_pnt = in[ind];
1653 index = ind;
1654 }
1655 else if ((in[ind]->y == min_pnt->y) && (in[ind]->x < min_pnt->x))
1656 {
1657 min_pnt = in[ind];
1658 index = ind;
1659 }
1660 }
1661
1662 return min_pnt;
1663}
1664
1665void
1667{
1668 for (int ind = 0; ind < (int)vec.size(); ind++)
1669 {
1670 printf("-- %11d (%-11g, %-11g)\n", ind, vec[ind]->x, vec[ind]->y);
1671 }
1672
1673 printf("\n\n");
1674}
1675
1676static void
1677print_pnt(point2d_ptr pnt)
1678{
1679 printf("(%g, %g)\n", pnt->x, pnt->y);
1680}
1681
1682void
1684{
1685 ldouble area;
1686
1687 //dump( ch );
1688 //fflush( stdout );
1689 //fflush( stderr );
1690 for (int ind = 0; ind < (int)(ch.size() - 2); ind++)
1691 assert(Left(*(ch[ind]), *(ch[ind + 1]), *(ch[ind + 2])));
1692
1693 assert(Left(*(ch[ch.size() - 2]), *(ch[ch.size() - 1]), *(ch[0])));
1694 assert(Left(*(ch[ch.size() - 1]), *(ch[0]), *(ch[1])));
1695
1696 for (int ind = 0; ind < (int)(in.size() - 2); ind++)
1697 {
1698 for (int jnd = 0; jnd < (int)(ch.size() - 1); jnd++)
1699 {
1700 if (ch[jnd]->equal_real(*(in[ind])))
1701 {
1702 continue;
1703 }
1704
1705 if (ch[jnd + 1]->equal(*(in[ind])))
1706 {
1707 continue;
1708 }
1709
1710 if (!Left_colinear(*(ch[jnd]), *(ch[jnd + 1]), *(in[ind])))
1711 {
1712 area = Area(*(ch[jnd]), *(ch[jnd + 1]), *(in[ind]));
1713
1714 if (fabs(area) < 1e-12)
1715 {
1716 continue;
1717 }
1718
1719 printf("Failure in progress!\n\n");
1720 print_pnt(ch[jnd]);
1721 print_pnt(ch[jnd + 1]);
1722 print_pnt(in[ind]);
1723
1724 //dump( ch );
1725 printf("ch[ jnd ]: (%g, %g)\n", ch[jnd]->x, ch[jnd]->y);
1726 printf("ch[ jnd + 1 ]: (%g, %g)\n", ch[jnd + 1]->x, ch[jnd + 1]->y);
1727 printf("ch[ ind ]: (%g, %g)\n", in[ind]->x, in[ind]->y);
1728 printf("Area: %g\n", (double)Area(*(ch[jnd]), *(ch[jnd + 1]), *(in[ind])));
1729 printf("jnd: %d, jnd + 1: %d, ind: %d\n", jnd, jnd + 1, ind);
1730 fflush(stdout);
1731 fflush(stderr);
1732
1733 assert(Left(*(ch[jnd]), *(ch[jnd + 1]), *(in[ind])));
1734 }
1735 }
1736
1737 if (ch[0]->equal(*(in[ind])))
1738 {
1739 continue;
1740 }
1741
1742 if (ch[ch.size() - 1]->equal(*(in[ind])))
1743 {
1744 continue;
1745 }
1746
1747 assert(Left(*(ch[ch.size() - 1]), *(ch[0]), *(in[ind])));
1748 }
1749
1750 printf("Convex hull seems to be ok!\n");
1751}
1752
1753static void
1754remove_duplicate(vec_point_2d& in, point2d_ptr ptr, int start)
1755{
1756 int dest;
1757
1758 dest = start;
1759
1760 while (start < (int)in.size())
1761 {
1762 if (in[start]->equal_real(*ptr))
1763 {
1764 start++;
1765 continue;
1766 }
1767
1768 in[dest++] = in[start++];
1769 }
1770
1771 while ((int)in.size() > dest)
1772 {
1773 in.pop_back();
1774 }
1775}
1776
1777static void
1778remove_consecutive_dup(vec_point_2d& in)
1779{
1780 int dest, pos;
1781
1782 if (in.size() < 1)
1783 {
1784 return;
1785 }
1786
1787 dest = pos = 0;
1788
1789 // copy first entry
1790 in[dest++] = in[pos++];
1791
1792 while (pos < ((int)in.size() - 1))
1793 {
1794 if (in[pos - 1]->equal_real(*(in[pos])))
1795 {
1796 pos++;
1797 continue;
1798 }
1799
1800 in[dest++] = in[pos++];
1801 }
1802
1803 in[dest++] = in[pos++];
1804
1805 while ((int)in.size() > dest)
1806 {
1807 in.pop_back();
1808 }
1809}
1810
1811void
1813{
1814
1815 CompareByAngle comp;
1816 int ind, position;
1817
1818 assert(in.size() > 1);
1819
1820 comp.base = *(get_min_point(in, position));
1821 std::swap(in[0], in[position]);
1822
1823 remove_duplicate(in, in[0], 1);
1824
1825 /*
1826 printf( "comp.base: (%g, %g)\n",
1827 comp.base.x,
1828 comp.base.y );
1829 */
1830 for (int ind = 0; ind < (int)in.size(); ind++)
1831 {
1832 assert(in[ind] != NULL);
1833 }
1834
1835 /*
1836 if ( in.size() == 24 ) {
1837 dump( in );
1838 fflush( stdout );
1839 fflush( stderr );
1840 }*/
1841
1842 //printf( "sort( %d, %d, comp )\n", 1, in.size() );
1843 sort(in.begin() + 1, in.end(), comp);
1844 remove_consecutive_dup(in);
1845
1846 //dump( in );
1847 /*
1848 for ( int ind = 0; ind < (int)in.size(); ind++ ) {
1849 double x_delta, y_delta;
1850
1851 x_delta = in[ ind ]->x - comp.base.x;
1852 y_delta = in[ ind ]->y - comp.base.y;
1853
1854 printf( "-- %11d (%-11g, %-11g) atan2: %-11g\n",
1855 ind, in[ ind ]->x,
1856 in[ ind ]->y,
1857 atan2( y_delta, x_delta ) );
1858 }*/
1859
1860 //fflush( stdout );
1861 //printf( "pushing...\n" );
1862 //fflush( stdout );
1863 out.push_back(in[in.size() - 1]);
1864 out.push_back(in[0]);
1865
1866 // perform the graham scan
1867 ind = 1;
1868 int last;
1869
1870 while (ind < (int)in.size())
1871 {
1872 if (out[out.size() - 1]->equal_real(*(in[ind])))
1873 {
1874 ind++;
1875 continue;
1876 }
1877
1878 last = out.size();
1879 assert(last > 1);
1880
1881 if (Left(*(out[last - 2]), *(out[last - 1]), *(in[ind])))
1882 {
1883 if (!out[last - 1]->equal(*(in[ind])))
1884 {
1885 out.push_back(in[ind]);
1886 }
1887
1888 ind++;
1889 }
1890 else
1891 {
1892 if (out.size() < 3)
1893 {
1894 dump(out);
1895 printf("Input:\n");
1896 dump(in);
1897 printf("ind: %d\n", ind);
1898 fflush(stdout);
1899 assert(out.size() > 2);
1900 }
1901
1902 out.pop_back();
1903 }
1904 }
1905
1906 // we pushed in[ in.size() -1 ] twice in the output
1907 out.pop_back();
1908
1909 //verify_convex_hull( in, out );
1910}
1911
1913{
1916
1917 void
1919 {
1920 out[0] = vertices[ind][0] - vertices[(ind + 1) % 4][0];
1921 out[1] = vertices[ind][1] - vertices[(ind + 1) % 4][1];
1922 }
1923
1924 void
1926 {
1927 printf("--- bbox 2d ----------------------------\n");
1928
1929 for (int ind = 0; ind < 4; ind++)
1930 printf("%d: (%g, %g)\n", ind, vertices[ind][0], vertices[ind][1]);
1931
1932 for (int ind = 0; ind < 4; ind++)
1933 {
1934 gdiam_point_2d_t dir;
1935
1936 get_dir(ind, dir);
1937
1938 printf("dir %d: (%g, %g)\n", ind, dir[0], dir[1]);
1939 }
1940
1941 printf("\\----------------------------------\n");
1942 }
1943};
1944
1945#define EPS 1e-6
1946
1947inline bool
1949{
1950 return (((b - EPS) < a) && (a < (b + EPS)));
1951}
1952
1954{
1955private:
1956 vec_point_2d ch;
1957 gdiam_real* angles;
1958
1959public:
1960 void
1962 {
1963 for (int ind = 0; ind < (int)ch.size(); ind++)
1964 {
1965 printf("%d: (%g, %g)\n", ind, ch[ind]->x, ch[ind]->y);
1966 }
1967 }
1968
1969 void
1971 {
1972 int u2;
1973 double ang;
1974 double x1, y1, x2, y2;
1975
1976 u2 = (u + 1) % ch.size();
1977
1978 x1 = ch[u]->x;
1979 y1 = ch[u]->y;
1980 x2 = ch[u2]->x;
1981 y2 = ch[u2]->y;
1982
1983 ang = atan2(y2 - y1, x2 - x1);
1984
1985 if (ang < 0)
1986 {
1987 ang += 2.0 * PI;
1988 }
1989
1990 angles[u] = ang;
1991
1992 // floating point nonsence. A huck to solve this...
1993 if ((u > 0) && (angles[u] < angles[u - 1]) && eq_real(angles[u], angles[u - 1]))
1994 {
1995 angles[u] = angles[u - 1];
1996 }
1997
1998 /*
1999 printf( "angles[ %4d ]: %.20f ", u, ang );
2000 if ( u > 0 )
2001 printf( "%2d", (angles[ u ] >= angles[ u - 1 ] ) );
2002 if ( u > 1 ) {
2003 printf( " area: %.20f ", (double)Area( *( ch[ u - 2 ] ),
2004 *( ch[ u - 1 ] ),
2005 *( ch[ u ] ) ) );
2006 }
2007 printf( "\n" );
2008 */
2009 }
2010
2011 /* Finding the first vertex whose edge is over a given angle */
2012 int
2013 find_vertex(int start_vertex, double trg_angle)
2014 {
2015 double prev_angle, curr_angle;
2016 bool f_found;
2017 int ver, prev_vertex;
2018
2019 f_found = false;
2020
2021 prev_vertex = start_vertex - 1;
2022
2023 if (prev_vertex < 0)
2024 {
2025 prev_vertex = ch.size() - 1;
2026 }
2027
2028 prev_angle = angles[prev_vertex];
2029 ver = start_vertex;
2030
2031 while (!f_found)
2032 {
2033 curr_angle = angles[ver];
2034
2035 if (prev_angle <= curr_angle)
2036 f_found = ((prev_angle < trg_angle) && (trg_angle <= curr_angle));
2037 else
2038 f_found = ((prev_angle < trg_angle) || (trg_angle <= curr_angle));
2039
2040 if (f_found)
2041 {
2042 break;
2043 }
2044 else
2045 {
2046 prev_angle = curr_angle;
2047 }
2048
2049 ver = (ver + 1) % ch.size();
2050 }
2051
2052 return ver;
2053 }
2054
2055 /* Computing the intersection point of two lines, each given by a
2056 point and slope */
2057 void
2059 double a_angle,
2060 int b_ind,
2061 double b_angle,
2062 gdiam_real& x,
2063 gdiam_real& y)
2064 {
2065 double a_slope, b_slope, x_a, x_b, y_a, y_b;
2066
2067 if (eq_real(a_angle, 0.0) || eq_real(a_angle, PI))
2068 {
2069 x = ch[b_ind]->x;
2070 y = ch[a_ind]->y;
2071 return;
2072 }
2073
2074 if (eq_real(a_angle, PI / 2.0) || eq_real(a_angle, PI * 1.5))
2075 {
2076 x = ch[a_ind]->x;
2077 y = ch[b_ind]->y;
2078 return;
2079 }
2080
2081 a_slope = tan(a_angle);
2082 b_slope = tan(b_angle);
2083 x_a = ch[a_ind]->x;
2084 y_a = ch[a_ind]->y;
2085 x_b = ch[b_ind]->x;
2086 y_b = ch[b_ind]->y;
2087
2088 double a_const, b_const, x_out, y_out;
2089
2090 // Let see:
2091 // l_a = y = a_slope * x + a_const ->
2092 // y_a = a_slope * x_a + a_const (since (x_a, y_a) in l_a
2093 // a_const = y_a - a_slope * x_a
2094 a_const = y_a - a_slope * x_a;
2095 //printf( "a_const: %g, y_a: %g, a_slope: %g, x_a: %g\n",
2096 // a_const, y_a, a_slope, x_a );
2097
2098 b_const = y_b - b_slope * x_b;
2099 //printf( "b_const: %g, y_b: %g, b_slope: %g, x_b: %g\n",
2100 // b_const, y_b, b_slope, x_b );
2101
2102 x_out = -(a_const - b_const) / (a_slope - b_slope);
2103 y_out = a_slope * x_out + a_const;
2104 /*
2105 x = (y_b - y_a + x_a * a_slope - x_b * a_slope)
2106 / (a_slope - b_slope);
2107 y = ((y_a - x_a * a_slope) / a_slope - (y_b - x_b * b_slope)
2108 / b_slope) /
2109 (1.0 / a_slope - 1.0 / b_slope );
2110 printf( "gill: (%g, %g)\nMine: (%g, %g)\n",
2111 x, y, x_out, y_out );
2112 */
2113 //printf( "a_angle: %g, b_angle: %g\n",
2114 // a_angle / PI, b_angle/ PI );
2115 //printf( "a_slope: %g, b_slope: %g\n",
2116 // a_slope, b_slope );
2117 //printf( "on line_b: %g\n",
2118 // b_slope * x_out + b_const - y_out );
2119 x = x_out;
2120 y = y_out;
2121 //printf( "line_a : y = %g * x + %g\n",
2122 // a_slope, a_const );
2123 //printf( "line_b : y = %g * x + %g\n",
2124 // b_slope, b_const );
2125 //printf( "a: (%g, %g)\n"
2126 // "b: (%g, %g)\n",
2127 // x_a, y_a, x_b, y_b );
2128
2129 //printf( "out: (%g, %g)\n", x, y );
2130 }
2131
2132 void
2133 get_bbox(int a_ind,
2134 gdiam_real a_angle,
2135 int b_ind,
2136 gdiam_real b_angle,
2137 int c_ind,
2138 gdiam_real c_angle,
2139 int d_ind,
2140 gdiam_real d_angle,
2141 bbox_2d_info& bbox,
2142 gdiam_real& area)
2143 {
2144 /*
2145 printf( "get_bbox: (%d, %g,\n"
2146 "%d, %g\n"
2147 "%d, %g\n"
2148 "%d, %g )\n",
2149 a_ind, a_angle / PI,
2150 b_ind, b_angle / PI,
2151 c_ind, c_angle / PI,
2152 d_ind, d_angle / PI );*/
2153
2154 compute_crossing(a_ind, a_angle, b_ind, b_angle, bbox.vertices[0][0], bbox.vertices[0][1]);
2155 compute_crossing(b_ind, b_angle, c_ind, c_angle, bbox.vertices[1][0], bbox.vertices[1][1]);
2156 compute_crossing(c_ind, c_angle, d_ind, d_angle, bbox.vertices[2][0], bbox.vertices[2][1]);
2157 compute_crossing(d_ind, d_angle, a_ind, a_angle, bbox.vertices[3][0], bbox.vertices[3][1]);
2158
2159 area = pnt_distance_2d(bbox.vertices[0], bbox.vertices[1]) *
2160 pnt_distance_2d(bbox.vertices[0], bbox.vertices[3]);
2161 }
2162
2163 /* Given one angle (bbx direction), find the other three */
2164 void
2165 get_angles(int ind, gdiam_real& angle_1, gdiam_real& angle_2, gdiam_real& angle_3)
2166 {
2167 double angle;
2168
2169 angle = angles[ind];
2170 angle_1 = angle + PI * 0.5;
2171 //printf( "angle = %g\n", angle / PI );
2172 //printf( "angle1 = %g\n", angle_1 / PI );
2173
2174 if (angle_1 >= (2.0 * PI))
2175 {
2176 angle_1 -= 2.0 * PI;
2177 }
2178
2179 //printf( "angle1 = %g\n", angle_1 / PI );
2180
2181
2182 angle_2 = angle + PI;
2183
2184 if (angle_2 >= (2.0 * PI))
2185 {
2186 angle_2 -= 2.0 * PI;
2187 }
2188
2189 angle_3 = angle + 1.5 * PI;
2190
2191 if (angle_3 >= (2.0 * PI))
2192 {
2193 angle_3 -= 2.0 * PI;
2194 }
2195 }
2196
2197 void
2199 {
2200 int u, v, s, t;
2201 gdiam_real ang1, ang2, ang3, tmp_area;
2202 bbox_2d_info tmp_bbox;
2203
2204 angles = (gdiam_real*)malloc(sizeof(gdiam_real) * (int)ch.size());
2205 assert(angles != NULL);
2206
2207 /* Pre-computing all edge directions */
2208 for (u = 0; u < (int)ch.size(); u++)
2209 {
2211 }
2212
2213 /* Initializing the search */
2214 //printf( "_angles[ 0 ]: %g\n", angles[ 0 ] );
2215 get_angles(0, ang1, ang2, ang3);
2216
2217 //printf( "_angles[ 0 ]: %g\n", angles[ 0 ] );
2218 s = find_vertex(0, ang1);
2219 //printf( "_angles[ 0 ]: %g\n", angles[ 0 ] );
2220 v = find_vertex(s, ang2);
2221 t = find_vertex(v, ang3);
2222
2223 //printf( "_angles[ 0 ]: %g\n", angles[ 0 ] );
2224 get_bbox(0, angles[0], s, ang1, v, ang2, t, ang3, min_bbox, min_area);
2225 //min_bbox.dump();
2226
2227 //printf( "min_area: %g\n", min_area );
2228 /* Performing a double rotating calipers */
2229 for (u = 1; u < (int)ch.size(); u++)
2230 {
2231 get_angles(u, ang1, ang2, ang3);
2232 s = find_vertex(s, ang1);
2233 v = find_vertex(v, ang2);
2234 t = find_vertex(t, ang3);
2235 get_bbox(u, angles[u], s, ang1, v, ang2, t, ang3, tmp_bbox, tmp_area);
2236
2237 //tmp_bbox.dump();
2238 //printf( "tmp_area: %g\n", tmp_area );
2239 if (min_area > tmp_area)
2240 {
2241 min_area = tmp_area;
2242 min_bbox = tmp_bbox;
2243 }
2244 }
2245
2246 free(angles);
2247 angles = NULL;
2248 }
2249
2250 void
2252 {
2253 //printf( "before cunvex hull\n" );
2254 convex_hull(points, ch);
2255 //printf( "cunvex hull done!\n" );
2256 //dump_ch();
2257 compute_min_bbox_inner(min_bbox, min_area);
2258 //min_bbox.dump();
2259 }
2260};
2261
2262void
2263dump_points(gdiam_point* in_arr, int size)
2264{
2265 for (int ind = 0; ind < size; ind++)
2266 {
2267 printf("%d: (%g, %g, %g)\n", ind, in_arr[ind][0], in_arr[ind][1], in_arr[ind][2]);
2268 }
2269}
2270
2271#define ZERO_EPS (1e-6)
2272
2273static void
2274construct_base_inner(gdiam_point pnt1, gdiam_point pnt2, gdiam_point pnt3)
2275{
2276 pnt_normalize(pnt1);
2277 pnt_normalize(pnt2);
2278 pnt_normalize(pnt3);
2279
2280 if ((pnt_length(pnt1) < ZERO_EPS) && (pnt_length(pnt2) < ZERO_EPS) &&
2281 (pnt_length(pnt3) < ZERO_EPS))
2282 {
2283 assert(false);
2284 }
2285
2286 if ((pnt_length(pnt1) < ZERO_EPS) && (pnt_length(pnt2) < ZERO_EPS))
2287 {
2288 gdiam_generate_orthonormal_base(pnt3, pnt1, pnt2);
2289 return;
2290 }
2291
2292 if ((pnt_length(pnt1) < ZERO_EPS) && (pnt_length(pnt3) < ZERO_EPS))
2293 {
2294 gdiam_generate_orthonormal_base(pnt2, pnt1, pnt3);
2295 return;
2296 }
2297
2298 if ((pnt_length(pnt2) < ZERO_EPS) && (pnt_length(pnt3) < ZERO_EPS))
2299 {
2300 gdiam_generate_orthonormal_base(pnt1, pnt2, pnt3);
2301 return;
2302 }
2303
2304 if (pnt_length(pnt1) < ZERO_EPS)
2305 {
2306 pnt_cross_prod(pnt2, pnt3, pnt1);
2307 return;
2308 }
2309
2310 if (pnt_length(pnt2) < ZERO_EPS)
2311 {
2312 pnt_cross_prod(pnt1, pnt3, pnt2);
2313 return;
2314 }
2315
2316 if (pnt_length(pnt3) < ZERO_EPS)
2317 {
2318 pnt_cross_prod(pnt1, pnt2, pnt3);
2319 return;
2320 }
2321}
2322
2323void
2325{
2326 construct_base_inner(pnt1, pnt2, pnt3);
2327 pnt_scale_and_add(pnt2, -pnt_dot_prod(pnt1, pnt2), pnt1);
2328 pnt_normalize(pnt2);
2329
2330 pnt_scale_and_add(pnt3, -pnt_dot_prod(pnt1, pnt3), pnt1);
2331 pnt_scale_and_add(pnt3, -pnt_dot_prod(pnt2, pnt3), pnt2);
2332 pnt_normalize(pnt3);
2333}
2334
2336{
2337private:
2338 gdiam_point_t base_x, base_y, base_proj;
2339 point2d* arr;
2340 vec_point_2d points, ch;
2341 gdiam_bbox bbox;
2342 gdiam_point* in_arr;
2343 int size;
2344
2345public:
2347 {
2348 term();
2349 }
2350
2351 void
2352 init(gdiam_point dir, gdiam_point* _in_arr, int _size)
2353 {
2354 arr = NULL;
2355
2356 if (pnt_length(dir) == 0.0)
2357 {
2358 dump_points(_in_arr, _size);
2359 pnt_dump(dir);
2360 fflush(stdout);
2361 fflush(stderr);
2362 assert(pnt_length(dir) > 0.0);
2363 }
2364
2365 size = _size;
2366 in_arr = _in_arr;
2367 assert(size > 0);
2368
2369 pnt_copy(base_proj, dir);
2370 gdiam_generate_orthonormal_base(base_proj, base_x, base_y);
2371
2372 arr = (point2d*)malloc(sizeof(point2d) * size);
2373 assert(arr != 0);
2374
2375 for (int ind = 0; ind < size; ind++)
2376 {
2377 arr[ind].init(in_arr[ind], base_x, base_y);
2378 points.push_back(&(arr[ind]));
2379 }
2380 }
2381
2382 void
2384 {
2385 MinAreaRectangle mar;
2386 bbox_2d_info min_bbox;
2387 gdiam_real min_area;
2388 double x1, y1, x2, y2;
2389 gdiam_point_t out_1, out_2;
2390
2391 mar.compute_min_bbox(points, min_bbox, min_area);
2392
2393 // We take the resulting min_area rectangle and lift it back to 3d...
2394 x1 = min_bbox.vertices[0][0] - min_bbox.vertices[1][0];
2395 y1 = min_bbox.vertices[0][1] - min_bbox.vertices[1][1];
2396 x2 = min_bbox.vertices[0][0] - min_bbox.vertices[3][0];
2397 y2 = min_bbox.vertices[0][1] - min_bbox.vertices[3][1];
2398
2399 //printf( "prod: %g\n", x1 * x2 + y1 * y2 );
2400
2401 double len;
2402
2403 len = sqrt(x1 * x1 + y1 * y1);
2404
2405 if (len > 0.0)
2406 {
2407 x1 /= len;
2408 y1 /= len;
2409 }
2410
2411 len = sqrt(x2 * x2 + y2 * y2);
2412
2413 if (len > 0.0)
2414 {
2415 x2 /= len;
2416 y2 /= len;
2417 }
2418
2419 pnt_zero(out_1);
2420 pnt_scale_and_add(out_1, x1, base_x);
2421 pnt_scale_and_add(out_1, y1, base_y);
2422 pnt_normalize(out_1);
2423
2424 pnt_zero(out_2);
2425 pnt_scale_and_add(out_2, x2, base_x);
2426 pnt_scale_and_add(out_2, y2, base_y);
2427 pnt_normalize(out_2);
2428
2429 construct_base(base_proj, out_1, out_2);
2430
2431 if ((!(fabs(pnt_dot_prod(base_proj, out_1)) < 1e-6)) ||
2432 (!(fabs(pnt_dot_prod(base_proj, out_2)) < 1e-6)) ||
2433 (!(fabs(pnt_dot_prod(out_1, out_2)) < 1e-6)))
2434 {
2435 printf("should be all close to zero: %g, %g, %g\n",
2436 pnt_dot_prod(base_proj, out_1),
2437 pnt_dot_prod(base_proj, out_2),
2438 pnt_dot_prod(out_1, out_2));
2439 pnt_dump(base_proj);
2440 pnt_dump(out_1);
2441 pnt_dump(out_2);
2442
2443
2444 printf("real points:\n");
2445 dump_points(in_arr, size);
2446
2447 printf("points on CH:\n");
2448 dump(points);
2449
2450 printf("BBox:\n");
2451 min_bbox.dump();
2452
2453 fflush(stdout);
2454 fflush(stderr);
2455 assert(fabs(pnt_dot_prod(base_proj, out_1)) < 1e-6);
2456 assert(fabs(pnt_dot_prod(base_proj, out_2)) < 1e-6);
2457 assert(fabs(pnt_dot_prod(out_1, out_2)) < 1e-6);
2458 }
2459
2460 bbox.init(base_proj, out_1, out_2);
2461
2462 for (int ind = 0; ind < size; ind++)
2463 {
2464 bbox.bound(in_arr[ind]);
2465 }
2466 }
2467
2468 gdiam_bbox&
2470 {
2471 return bbox;
2472 }
2473
2474 void
2476 {
2477 if (arr != NULL)
2478 {
2479 free(arr);
2480 arr = NULL;
2481 }
2482 }
2483
2484 void
2486 {
2487 }
2488};
2489
2491gdiam_mvbb_optimize(gdiam_point* start, int size, gdiam_bbox bb_out, int times)
2492{
2493 gdiam_bbox bb_tmp;
2494
2495 //printf( "gdiam_mvbb_optimize called\n" );
2496
2497 for (int ind = 0; ind < times; ind++)
2498 {
2499 ProjPointSet pps;
2500
2501 if (pnt_length(bb_out.get_dir(ind % 3)) == 0.0)
2502 {
2503 printf("Dumping!\n");
2504 bb_out.dump();
2505 fflush(stdout);
2506 continue;
2507 }
2508
2509 pps.init(bb_out.get_dir(ind % 3), start, size);
2510
2511 pps.compute();
2512
2513 //printf( "Old volume: %g\n", bb_out.volume() );
2514 bb_tmp = pps.get_bbox();
2515 //printf( "New volume: %g\n", bb_tmp.volume() );
2516 //printf( "Old bounding box:\n" );
2517 //bb2.dump();
2518
2519 if (bb_tmp.volume() < bb_out.volume())
2520 {
2521 bb_out = bb_tmp;
2522 }
2523 }
2524
2525 return bb_out;
2526}
2527
2530{
2531 gdiam_bbox bb, bb2;
2532
2533 bb = gdiam_approx_const_mvbb(start, size, 0.0, NULL);
2534 bb2 = gdiam_mvbb_optimize(start, size, bb, 10);
2535
2536 //bb2.dump();
2537
2538 return bb2;
2539}
2540
2541static int
2542gcd2(int a, int b)
2543{
2544 if (a == 0 || a == b)
2545 {
2546 return b;
2547 }
2548
2549 if (b == 0)
2550 {
2551 return a;
2552 }
2553
2554 if (a > b)
2555 {
2556 return gcd2(a % b, b);
2557 }
2558 else
2559 {
2560 return gcd2(a, b % a);
2561 }
2562}
2563
2564static int
2565gcd3(int a, int b, int c)
2566{
2567 a = abs(a);
2568 b = abs(b);
2569 c = abs(c);
2570
2571 if (a == 0)
2572 {
2573 return gcd2(b, c);
2574 }
2575
2576 if (b == 0)
2577 {
2578 return gcd2(a, c);
2579 }
2580
2581 if (c == 0)
2582 {
2583 return gcd2(a, b);
2584 }
2585
2586 return gcd2(a, gcd2(b, c));
2587}
2588
2589static void
2590try_direction(gdiam_bbox& bb,
2591 gdiam_bbox& bb_out,
2592 gdiam_point* start,
2593 int size,
2594 int x_coef,
2595 int y_coef,
2596 int z_coef)
2597{
2598 gdiam_bbox bb_new;
2599
2600 if (gcd3(x_coef, y_coef, z_coef) > 1)
2601 {
2602 return;
2603 }
2604
2605 if ((x_coef == 0) && (y_coef == 0) && (z_coef == 0))
2606 {
2607 return;
2608 }
2609
2610 //printf( "trying: (%d, %d, %d)\n",
2611 // x_coef, y_coef, z_coef );
2612 //fflush( stdout );
2613 gdiam_point_t new_dir;
2614 bb.combine(new_dir, x_coef, y_coef, z_coef);
2615
2616 ProjPointSet pps;
2617
2618 pps.init(new_dir, start, size);
2619
2620 pps.compute();
2621
2622 bb_new = pps.get_bbox();
2623 bb_new = gdiam_mvbb_optimize(start, size, bb_new, 10);
2624
2625 if (bb_new.volume() < bb_out.volume())
2626 {
2627 bb_out = bb_new;
2628 }
2629}
2630
2632gdiam_approx_mvbb_grid(gdiam_point* start, int size, int grid_size)
2633{
2634 gdiam_bbox bb, bb_out;
2635
2636 bb_out = bb = gdiam_approx_const_mvbb(start, size, 0.0, NULL);
2637
2638 if (bb.volume() == 0)
2639 {
2640 dump_points(start, size);
2641 printf("1zero volume???\n");
2642 bb.dump();
2643 }
2644
2645 bb_out = bb = gdiam_mvbb_optimize(start, size, bb_out, 10);
2646
2647 if (bb.volume() == 0)
2648 {
2649 printf("2zero volume???\n");
2650 bb.dump();
2651 }
2652
2653 //trying: (1, -4, 4)
2654 //try_direction( bb, bb_out, start, size,
2655 // 1, -4, 4 );
2656
2657 for (int x_coef = -grid_size; x_coef <= grid_size; x_coef++)
2658 for (int y_coef = -grid_size; y_coef <= grid_size; y_coef++)
2659 for (int z_coef = 0; z_coef <= grid_size; z_coef++)
2660 try_direction(bb, bb_out, start, size, x_coef, y_coef, z_coef);
2661
2662 bb_out = gdiam_mvbb_optimize(start, size, bb_out, 10);
2663
2664 return bb_out;
2665}
2666
2667static void
2668register_point(gdiam_point pnt,
2669 gdiam_point* tops,
2670 gdiam_point* bottoms,
2671 int grid_size,
2672 gdiam_bbox& bb)
2673{
2674 gdiam_point_t pnt_bb, pnt_bottom, pnt_top;
2675 int x_ind, y_ind, position;
2676
2677 bb.get_normalized_coordinates(pnt, pnt_bb);
2678
2679 // x_ind
2680 x_ind = (int)(pnt_bb[0] * grid_size);
2681 assert((-1 <= x_ind) && (x_ind <= grid_size));
2682
2683 if (x_ind < 0)
2684 {
2685 x_ind = 0;
2686 }
2687
2688 if (x_ind >= grid_size)
2689 {
2690 x_ind = grid_size - 1;
2691 }
2692
2693 // y_ind
2694 y_ind = (int)(pnt_bb[1] * grid_size);
2695 assert((-1 <= y_ind) && (y_ind <= grid_size));
2696
2697 if (y_ind < 0)
2698 {
2699 y_ind = 0;
2700 }
2701
2702 if (y_ind >= grid_size)
2703 {
2704 y_ind = grid_size - 1;
2705 }
2706
2707 position = x_ind + y_ind * grid_size;
2708
2709 if (tops[position] == NULL)
2710 {
2711 tops[position] = bottoms[position] = pnt;
2712 return;
2713 }
2714
2715 bb.get_normalized_coordinates(tops[position], pnt_top);
2716
2717 if (pnt_top[2] < pnt_bb[2])
2718 {
2719 tops[position] = pnt;
2720 }
2721
2722 bb.get_normalized_coordinates(bottoms[position], pnt_bottom);
2723
2724 if (pnt_bottom[2] > pnt_bb[2])
2725 {
2726 bottoms[position] = pnt;
2727 }
2728}
2729
2730// gdiam_convex_sample
2731
2732// We are given a point set, and (hopefully) a tight fitting
2733// bounding box. We compute a smplae of the given size that represents
2734// the point-set. The only guarenteed is that if we use ample of size m,
2735// we get an approximation of quality about 1/\sqrt{m}. Note that we pad
2736// the sample if necessary to get the desired size.
2738gdiam_convex_sample(gdiam_point* start, int size, gdiam_bbox& bb, int sample_size)
2739{
2740 int grid_size, mem_size, grid_entries;
2741 gdiam_point *bottoms, *tops, *out_arr;
2742 int out_count;
2743
2744 assert(sample_size > 1);
2745
2746 // we want the grid to be on the two minor dimensions.
2748
2749 grid_size = (int)sqrt(sample_size / 2);
2750
2751 grid_entries = grid_size * grid_size;
2752 mem_size = (int)(sizeof(gdiam_point) * grid_size * grid_size);
2753
2754 bottoms = (gdiam_point*)malloc(mem_size);
2755 tops = (gdiam_point*)malloc(mem_size);
2756 out_arr = (gdiam_point*)malloc(sizeof(gdiam_point) * sample_size);
2757
2758 assert(bottoms != NULL);
2759 assert(tops != NULL);
2760 assert(out_arr != NULL);
2761
2762 for (int ind = 0; ind < grid_entries; ind++)
2763 {
2764 tops[ind] = bottoms[ind] = NULL;
2765 }
2766
2767 // No we stream the points registering them with the relevant
2768 // shaft in the grid.
2769 for (int ind = 0; ind < size; ind++)
2770 register_point(start[ind], tops, bottoms, grid_size, bb);
2771
2772 out_count = 0;
2773
2774 for (int ind = 0; ind < grid_entries; ind++)
2775 {
2776 if (tops[ind] == NULL)
2777 {
2778 continue;
2779 }
2780
2781 out_arr[out_count++] = tops[ind];
2782
2783 if (tops[ind] != bottoms[ind])
2784 {
2785 out_arr[out_count++] = bottoms[ind];
2786 }
2787 }
2788
2789 // We dont have neough entries in our sample - lets randomly pick
2790 // points.
2791 while (out_count < sample_size)
2792 {
2793 out_arr[out_count++] = start[rand() % size];
2794 }
2795
2796 free(tops);
2797 free(bottoms);
2798
2799 return out_arr;
2800}
2801
2803gdiam_approx_mvbb_grid_sample(gdiam_point* start, int size, int grid_size, int sample_size)
2804{
2805 gdiam_bbox bb, bb_new;
2806 gdiam_point* sample;
2807
2808 if (sample_size >= size)
2809 {
2810 return gdiam_approx_mvbb_grid(start, size, grid_size);
2811 }
2812
2813 //printf( "gdiam_approx_mvbb_grid_sample(...) called\n" );
2814 //fflush( stdout );
2815
2816 bb = gdiam_approx_const_mvbb(start, size, 0.0, NULL);
2817 //printf( "guess from const approximation:\n" );
2818
2819 sample = gdiam_convex_sample(start, size, bb, sample_size);
2820
2821 bb_new = gdiam_approx_mvbb_grid(sample, sample_size, grid_size);
2822
2823 //printf( "new volume on sample: %g\n",
2824 // bb_new.volume() );
2825 //fflush( stdout );
2826
2827 for (int ind = 0; ind < size; ind++)
2828 {
2829 bb_new.bound(start[ind]);
2830 }
2831
2832 //printf( "new volume on resized input: %g\n",
2833 // bb_new.volume() );
2834
2835 //bb_new = gdiam_mvbb_optimize( start, size, bb_new, 10 );
2836 //printf(s "optimized new volume: %g\n",
2837 // bb_new.volume() );
2838
2839 return bb_new;
2840}
2841
2843gdiam_approx_mvbb_grid_sample(gdiam_real* start, int size, int grid_size, int sample_size)
2844{
2845 gdiam_point* p_arr;
2846 gdiam_bbox bb;
2847
2848 //printf( "gdiam_approx_mvbb_grid_sample( ?, %d, ...)\n", size );
2849 //fflush( stdout );
2850
2851 p_arr = gdiam_convert(start, size);
2852 bb = gdiam_approx_mvbb_grid_sample(p_arr, size, grid_size, sample_size);
2853 free(p_arr);
2854
2855 return bb;
2856}
2857
2858/* gdiam.C - End of File ------------------------------------------*/
uint8_t index
constexpr T c
Definition gdiam.h:291
int getLongestDim() const
Definition gdiam.h:409
void bound(const gdiam_point pnt)
Definition gdiam.h:385
void init(const GBBox &a, const GBBox &b)
Definition gdiam.h:298
gdiam_real volume() const
Definition gdiam.h:336
const gdiam_real & max_coord(int coord) const
Definition gdiam.h:379
const gdiam_real & min_coord(int coord) const
Definition gdiam.h:373
void center(gdiam_point out) const
Definition gdiam.h:327
gdiam_real get_diam() const
Definition gdiam.h:431
void init(GFSPTreeNode *_left, GFSPTreeNode *_right)
Definition gdiam.cpp:444
void init(GFSPTreeNode *_left, GFSPTreeNode *_right, gdiam_point proj_dir, gdiam_real dist)
Definition gdiam.cpp:459
bool isBelowThreshold(int threshold) const
Definition gdiam.cpp:529
GFSPTreeNode * get_left()
Definition gdiam.cpp:508
double directDiameter(const GFSPTree &tree, GPointPair &diam, const gdiam_point dir) const
Definition gdiam.cpp:555
double maxDiam() const
Definition gdiam.cpp:566
double minAprxDiam() const
Definition gdiam.cpp:572
double getProjectionError() const
Definition gdiam.cpp:492
double directDiameter(const GFSPTree &tree, GPointPair &diam) const
Definition gdiam.cpp:545
GFSPTreeNode * get_right()
Definition gdiam.cpp:514
void dump() const
Definition gdiam.cpp:520
bool isSplitable() const
Definition gdiam.cpp:147
gdiam_real maxDiam() const
Definition gdiam.cpp:123
GFSPTreeNode * get_left()
Definition gdiam.cpp:135
const GBBox & getBBox() const
Definition gdiam.cpp:174
GFSPTreeNode(gdiam_point *_p_pnt_left, gdiam_point *_p_pnt_right)
Definition gdiam.cpp:113
const gdiam_point * ptr_pnt_rand()
Definition gdiam.cpp:159
const gdiam_point * ptr_pnt_right()
Definition gdiam.cpp:165
int nodes_number() const
Definition gdiam.cpp:89
const gdiam_point * ptr_pnt_left()
Definition gdiam.cpp:153
gdiam_real maxDiamProj() const
Definition gdiam.cpp:129
friend class GFSPTree
Definition gdiam.cpp:171
GFSPTreeNode * get_right()
Definition gdiam.cpp:141
void dump() const
Definition gdiam.cpp:70
gdiam_point getCenter() const
Definition gdiam.cpp:83
int size() const
Definition gdiam.cpp:77
void split_node(GFSPTreeNode *node)
Definition gdiam.cpp:366
const gdiam_point * getPoints() const
Definition gdiam.cpp:228
static void terminate(GFSPTreeNode *node)
Definition gdiam.cpp:202
GFSPTreeNode * build_node(gdiam_point *left, gdiam_point *right)
Definition gdiam.cpp:310
gdiam_real brute_diameter(int a_lo, int a_hi, int b_lo, int b_hi, GPointPair &diam, const gdiam_point dir) const
Definition gdiam.cpp:252
void term()
Definition gdiam.cpp:218
gdiam_real brute_diameter(const gdiam_point *a_lo, const gdiam_point *a_hi, const gdiam_point *b_lo, const gdiam_point *b_hi, GPointPair &diam) const
Definition gdiam.cpp:265
gdiam_real brute_diameter(const gdiam_point *a_lo, const gdiam_point *a_hi, const gdiam_point *b_lo, const gdiam_point *b_hi, GPointPair &diam, const gdiam_point dir) const
Definition gdiam.cpp:281
void init(const gdiam_point *_arr, int size)
Definition gdiam.cpp:188
int split_array(gdiam_point *left, gdiam_point *right, int dim, const gdiam_real &val)
Definition gdiam.cpp:342
gdiam_point getPoint(int ind) const
Definition gdiam.cpp:298
int nodes_number() const
Definition gdiam.cpp:234
void findExtremeInProjection(GFSPPair &pair, GPointPair &max_pair_diam)
gdiam_real brute_diameter(int a_lo, int a_hi, int b_lo, int b_hi, GPointPair &diam) const
Definition gdiam.cpp:240
GFSPTreeNode * getRoot()
Definition gdiam.cpp:304
gdiam_point q
Definition gdiam.h:194
void init(const gdiam_point _p, const gdiam_point _q)
Definition gdiam.h:202
gdiam_point p
Definition gdiam.h:194
void update_diam(const gdiam_point _p, const gdiam_point _q)
Definition gdiam.h:260
gdiam_real distance
Definition gdiam.h:193
void term()
Definition gdiam.cpp:615
void split_pair(GFSPPair &pair, g_heap_pairs_p &heap, double eps)
Definition gdiam.cpp:1176
void split_pair_proj(GFSPPair &pair, g_heap_pairs_p &heap, double eps, gdiam_point proj)
Definition gdiam.cpp:1113
int nodes_number() const
Definition gdiam.cpp:633
double diameter()
Definition gdiam.cpp:650
void addPairHeap(g_heap_pairs_p &heap, GFSPTreeNode *left, GFSPTreeNode *right)
Definition gdiam.cpp:1021
void compute_by_heap_proj(double eps, gdiam_point proj)
Definition gdiam.cpp:965
const GPointPair & getDiameter() const
Definition gdiam.cpp:627
void compute_by_heap(double eps)
Definition gdiam.cpp:918
GTreeDiamAlg(gdiam_point *arr, int size, int mode)
Definition gdiam.cpp:604
int size() const
Definition gdiam.cpp:621
void compute_min_bbox(vec_point_2d &points, bbox_2d_info &min_bbox, gdiam_real &min_area)
Definition gdiam.cpp:2251
void get_bbox(int a_ind, gdiam_real a_angle, int b_ind, gdiam_real b_angle, int c_ind, gdiam_real c_angle, int d_ind, gdiam_real d_angle, bbox_2d_info &bbox, gdiam_real &area)
Definition gdiam.cpp:2133
void compute_edge_dir(int u)
Definition gdiam.cpp:1970
void compute_crossing(int a_ind, double a_angle, int b_ind, double b_angle, gdiam_real &x, gdiam_real &y)
Definition gdiam.cpp:2058
int find_vertex(int start_vertex, double trg_angle)
Definition gdiam.cpp:2013
void compute_min_bbox_inner(bbox_2d_info &min_bbox, gdiam_real &min_area)
Definition gdiam.cpp:2198
void get_angles(int ind, gdiam_real &angle_1, gdiam_real &angle_2, gdiam_real &angle_3)
Definition gdiam.cpp:2165
void init()
Definition gdiam.cpp:2485
void compute()
Definition gdiam.cpp:2383
void term()
Definition gdiam.cpp:2475
void init(gdiam_point dir, gdiam_point *_in_arr, int _size)
Definition gdiam.cpp:2352
gdiam_bbox & get_bbox()
Definition gdiam.cpp:2469
void push(GFSPPair &pair)
Definition gdiam.cpp:862
GFSPPair top()
Definition gdiam.cpp:877
int size() const
Definition gdiam.cpp:871
gdiam_point get_dir(int ind)
Definition gdiam.h:593
void bound(const gdiam_point pnt)
Definition gdiam.h:742
void combine(gdiam_point out, double a_coef, double b_coef, double c_coef)
Definition gdiam.h:616
gdiam_real volume() const
Definition gdiam.h:552
void get_normalized_coordinates(gdiam_point in, gdiam_point out)
Definition gdiam.h:793
void set_third_dim_longest()
Definition gdiam.h:564
void init(const GBBox &bb)
Definition gdiam.h:682
void dump() const
Definition gdiam.h:651
gdiam_real dist(const point2d &pnt)
Definition gdiam.cpp:1492
gdiam_point src
Definition gdiam.cpp:1481
bool equal(const point2d &pnt) const
Definition gdiam.cpp:1504
gdiam_real x
Definition gdiam.cpp:1480
void init(gdiam_point pnt, gdiam_point base_x, gdiam_point base_y)
Definition gdiam.cpp:1484
gdiam_real y
Definition gdiam.cpp:1480
bool equal_real(const point2d &pnt) const
Definition gdiam.cpp:1510
void dump() const
Definition gdiam.cpp:1498
bool Left_colinear(const point2d &a, const point2d &b, const point2d &c)
Definition gdiam.cpp:1576
bool eq_real(gdiam_real a, gdiam_real b)
Definition gdiam.cpp:1948
long double ldouble
Definition gdiam.cpp:46
GPointPair gdiam_approx_diam_pair(gdiam_real *start, int size, gdiam_real eps)
Definition gdiam.cpp:1285
int compare_pairs(void *_a, void *_b)
Definition gdiam.cpp:822
int(* ptrCompareFunc)(void *aPtr, void *bPtr)
Definition gdiam.cpp:658
point2d_ptr get_min_point(vec_point_2d &in, int &index)
Definition gdiam.cpp:1642
#define ZERO_EPS
Definition gdiam.cpp:2271
gdiam_bbox gdiam_approx_mvbb_grid(gdiam_point *start, int size, int grid_size)
Definition gdiam.cpp:2632
#define PI
Definition gdiam.cpp:42
int AreaSign(const point2d &a, const point2d &b, const point2d &c)
Definition gdiam.cpp:1559
point2d * point2d_ptr
Definition gdiam.cpp:1516
#define UDM_BIG_SAMPLE
Definition gdiam.cpp:591
void heap_insert(heap_t *pHeap, void *pData)
Definition gdiam.cpp:717
void construct_base(gdiam_point pnt1, gdiam_point pnt2, gdiam_point pnt3)
Definition gdiam.cpp:2324
#define HEAP_LIMIT
Definition gdiam.cpp:40
#define EPS
Definition gdiam.cpp:1945
GPointPair gdiam_approx_diam(gdiam_point *start, int size, gdiam_real eps)
Definition gdiam.cpp:1234
bool Left(const point2d &a, const point2d &b, const point2d &c)
Definition gdiam.cpp:1570
void bbox_vertex(const GBBox &bb, gdiam_point_t &ver, int vert)
Definition gdiam.cpp:405
void dump(vec_point_2d &vec)
Definition gdiam.cpp:1666
gdiam_point * gdiam_convex_sample(gdiam_point *start, int size, gdiam_bbox &bb, int sample_size)
Definition gdiam.cpp:2738
bool heap_is_empty(heap_t *pHeap)
Definition gdiam.cpp:814
void verify_convex_hull(vec_point_2d &in, vec_point_2d &ch)
Definition gdiam.cpp:1683
gdiam_bbox gdiam_approx_mvbb_grid_sample(gdiam_point *start, int size, int grid_size, int sample_size)
Definition gdiam.cpp:2803
gdiam_bbox gdiam_approx_mvbb(gdiam_point *start, int size, gdiam_real eps)
Definition gdiam.cpp:2529
void gdiam_generate_orthonormal_base(gdiam_point in, gdiam_point out1, gdiam_point out2)
Definition gdiam.cpp:1421
void computeExtremePair(const gdiam_point *arr, int size, int dim, GPointPair &pp)
Definition gdiam.cpp:895
#define HEAP_DELTA
Definition gdiam.cpp:41
gdiam_bbox gdiam_mvbb_optimize(gdiam_point *start, int size, gdiam_bbox bb_out, int times)
Definition gdiam.cpp:2491
gdiam_bbox gdiam_approx_const_mvbb(gdiam_point *start, int size, gdiam_real eps, GBBox *p_ap_bbox)
Definition gdiam.cpp:1311
void * heap_delete_max(heap_t *pHeap)
Definition gdiam.cpp:753
GPointPair gdiam_approx_diam_UDM(gdiam_point *start, int size, gdiam_real eps)
Definition gdiam.cpp:1250
GPointPair gdiam_approx_diam_pair_UDM(gdiam_real *start, int size, gdiam_real eps)
Definition gdiam.cpp:1298
void * voidPtr_t
Definition gdiam.cpp:659
ldouble Area(const point2d &a, const point2d &b, const point2d &c)
Definition gdiam.cpp:1523
#define UDM_SIMPLE
Definition gdiam.cpp:590
void convex_hull(vec_point_2d &in, vec_point_2d &out)
Definition gdiam.cpp:1812
#define UMD_SIZE
void * heap_top(heap_t *pHeap)
Definition gdiam.cpp:747
void heap_init(heap_t *pHeap, ptrCompareFunc _pCompFunc)
Definition gdiam.cpp:669
gdiam_real bbox_proj_dist(const GBBox &bb1, const GBBox &bb2, gdiam_point_cnt proj)
Definition gdiam.cpp:413
gdiam_point * gdiam_convert(gdiam_real *start, int size)
Definition gdiam.cpp:1266
void heap_term(heap_t *pHeap)
Definition gdiam.cpp:704
void dump_points(gdiam_point *in_arr, int size)
Definition gdiam.cpp:2263
gdiam_real pnt_length(const gdiam_point pnt)
Definition gdiam.h:68
void pnt_cross_prod(const gdiam_point a, const gdiam_point b, const gdiam_point out)
Definition gdiam.h:115
void pnt_scale_and_add(gdiam_point dest, gdiam_real coef, gdiam_point_cnt vec)
Definition gdiam.h:183
gdiam_real pnt_dot_prod(gdiam_point_cnt a, gdiam_point_cnt b)
Definition gdiam.h:109
gdiam_real pnt_distance_2d(gdiam_point_2d p, gdiam_point_2d q)
Definition gdiam.h:123
const gdiam_real * gdiam_point_cnt
Definition gdiam.h:25
void pnt_init_normalize(gdiam_point pnt, gdiam_real x, gdiam_real y, gdiam_real z)
Definition gdiam.h:166
void pnt_zero(gdiam_point dst)
Definition gdiam.h:97
gdiam_real * gdiam_point
Definition gdiam.h:24
void pnt_copy(gdiam_point_t dest, gdiam_point_t src)
Definition gdiam.h:89
gdiam_real * gdiam_point_2d
Definition gdiam.h:23
gdiam_real gdiam_point_t[GDIAM_DIM]
Definition gdiam.h:21
bool pnt_isEqual(const gdiam_point p, const gdiam_point q)
Definition gdiam.h:176
double gdiam_real
Definition gdiam.h:20
void gdiam_exchange(T &a, T &b)
Definition gdiam.h:59
void pnt_normalize(gdiam_point pnt)
Definition gdiam.h:74
gdiam_real gdiam_point_2d_t[2]
Definition gdiam.h:22
gdiam_real pnt_distance(gdiam_point p, gdiam_point q)
Definition gdiam.h:132
void pnt_dump(gdiam_point_cnt pnt)
Definition gdiam.h:103
T max(T t1, T t2)
Definition gdiam.h:51
#define q
double a(double t, double a0, double j)
Definition CtrlUtil.h:45
This file offers overloads of toIce() and fromIce() functions for STL container types.
std::vector< T > abs(const std::vector< T > &v)
double angle(const Point &a, const Point &b, const Point &c)
Definition point.hpp:109
point2d base
Definition gdiam.cpp:1584
bool operator()(const point2d_ptr &a, const point2d_ptr &b)
Definition gdiam.cpp:1587
void get_dir(int ind, gdiam_point_2d out)
Definition gdiam.cpp:1918
gdiam_real area
Definition gdiam.cpp:1915
gdiam_point_2d_t vertices[4]
Definition gdiam.cpp:1914
void dump()
Definition gdiam.cpp:1925
int curr_size
Definition gdiam.cpp:664
ptrCompareFunc pCompFunc
Definition gdiam.cpp:665
int max_size
Definition gdiam.cpp:664
voidPtr_t * pArr
Definition gdiam.cpp:663