1 /*
2   SOLID - Software Library for Interference Detection
3   Copyright (C) 1997-1998  Gino van den Bergen
4 
5   This library is free software; you can redistribute it and/or
6   modify it under the terms of the GNU Library General Public
7   License as published by the Free Software Foundation; either
8   version 2 of the License, or (at your option) any later version.
9 
10   This library is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   Library General Public License for more details.
14 
15   You should have received a copy of the GNU Library General Public
16   License along with this library; if not, write to the Free
17   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 
19   Please send remarks, questions and bug reports to gino@win.tue.nl,
20   or write to:
21                   Gino van den Bergen
22 		  Department of Mathematics and Computing Science
23 		  Eindhoven University of Technology
24 		  P.O. Box 513, 5600 MB Eindhoven, The Netherlands
25 */
26 
27 #ifdef _MSC_VER
28 #pragma warning(disable:4786) // identifier was truncated to '255'
29 #endif // _MSC_VER
30 
31 #include "BBoxTree.h"
32 #include "Transform.h"
33 
34 #include <algorithm>
35 #include <new>
36 
37 class BBoxCompAxis {
38 public:
39   int axis;
operator ()(const BBoxNode & p1,const BBoxNode & p2) const40   bool operator()(const BBoxNode& p1, const BBoxNode& p2) const {
41     return p1.bbox.getCenter()[axis] < p2.bbox.getCenter()[axis];
42   }
BBoxCompAxis(int a)43   BBoxCompAxis(int a) : axis(a) {}
44 } bboxCompAxis[3] = { X, Y, Z };
45 
46 
47 extern BBoxInternal *free_node;
48 
fitBBox()49 void BBoxLeaf::fitBBox() {
50   bbox.setEmpty();
51   for (int i = 0; i < poly->numVerts(); ++i) {
52     bbox.include((*poly)[i]);
53   }
54 }
55 
BBoxInternal(int n,BBoxLeaf * l)56 BBoxInternal::BBoxInternal(int n, BBoxLeaf *l) {
57   tag = INTERNAL;
58   bbox.setEmpty();
59   for (int j = 0; j < n; ++j) {
60     bbox.include(l[j].bbox);
61   }
62 
63   int axis = bbox.longestAxis();
64   int i = 0, mid = n;
65   while (i < mid) {
66     if (l[i].bbox.getCenter()[axis] < bbox.getCenter()[axis]) ++i;
67     else swap(l[i], l[--mid]);
68   }
69   if (mid == 0 || mid == n) mid = n / 2;
70 
71   if (mid >= 2) {
72     rson = free_node;
73     new(free_node++) BBoxInternal(mid, &l[0]);
74   }
75   else rson = &l[0];
76   if (n - mid >= 2) {
77     lson = free_node;
78     new(free_node++) BBoxInternal(n - mid, &l[mid]);
79   }
80   else lson = &l[mid];
81 }
82 
83 #ifdef STATISTICS
84 int num_box_tests = 0;
85 #endif
86 
sep_axes_test(const Vector & a,const Vector & b,const Matrix & abs_b2a,const Vector & pos_b2a,const Matrix & abs_a2b,const Vector & pos_a2b)87 inline bool sep_axes_test(const Vector& a, const Vector& b,
88 			  const Matrix& abs_b2a, const Vector& pos_b2a,
89 			  const Matrix& abs_a2b, const Vector& pos_a2b) {
90 #ifdef STATISTICS
91   ++num_box_tests;
92 #endif
93 
94   if (a[X] + dot(abs_b2a[X], b) < fabs(pos_b2a[X])) return false;
95   if (a[Y] + dot(abs_b2a[Y], b) < fabs(pos_b2a[Y])) return false;
96   if (a[Z] + dot(abs_b2a[Z], b) < fabs(pos_b2a[Z])) return false;
97 
98   if (b[X] + dot(abs_a2b[X], a) < fabs(pos_a2b[X])) return false;
99   if (b[Y] + dot(abs_a2b[Y], a) < fabs(pos_a2b[Y])) return false;
100   if (b[Z] + dot(abs_a2b[Z], a) < fabs(pos_a2b[Z])) return false;
101 
102   return true;
103 }
104 
intersect(const BBox & a,const BBox & b,const Transform & b2a,const Matrix & abs_b2a,const Transform & a2b,const Matrix & abs_a2b)105 inline bool intersect(const BBox& a, const BBox& b,
106 		      const Transform& b2a, const Matrix& abs_b2a,
107 		      const Transform& a2b, const Matrix& abs_a2b) {
108   return sep_axes_test(a.getExtent(), b.getExtent(),
109 		       abs_b2a, b2a(b.getCenter()) - a.getCenter(),
110 		       abs_a2b, a2b(a.getCenter()) - b.getCenter());
111 }
112 
113 
114 
intersect(const BBoxNode * tree,const Convex & c,const BBox & bb,const Transform & b2a,Vector & v)115 bool intersect(const BBoxNode *tree, const Convex& c, const BBox& bb,
116 	       const Transform& b2a, Vector& v) {
117   if (!intersect(tree->bbox, bb)) return false;
118 
119   if (tree->tag == BBoxNode::LEAF)
120     return intersect(*((const BBoxLeaf *)tree)->poly, c, b2a, v);
121   else {
122     return intersect(((const BBoxInternal *)tree)->lson, c, bb, b2a, v) ||
123       intersect(((const BBoxInternal *)tree)->rson, c, bb, b2a, v);
124   }
125 }
126 
127 
intersect(const BBoxNode * a,const BBoxNode * b,const Transform & b2a,const Matrix & abs_b2a,const Transform & a2b,const Matrix & abs_a2b,Vector & v)128 bool intersect(const BBoxNode *a, const BBoxNode *b,
129 	       const Transform& b2a, const Matrix& abs_b2a,
130 	       const Transform& a2b, const Matrix& abs_a2b, Vector& v) {
131   if (!intersect(a->bbox, b->bbox, b2a, abs_b2a, a2b, abs_a2b)) return false;
132 
133   if (a->tag == BBoxNode::LEAF && b->tag == BBoxNode::LEAF) {
134     return intersect(*((const BBoxLeaf *)a)->poly,
135 		     *((const BBoxLeaf *)b)->poly, b2a, v);
136   }
137   else if (a->tag == BBoxNode::LEAF ||
138 	   (b->tag != BBoxNode::LEAF && a->bbox.size() < b->bbox.size())) {
139     return
140       intersect(a, ((const BBoxInternal *)b)->lson,
141 		b2a, abs_b2a, a2b, abs_a2b, v) ||
142       intersect(a, ((const BBoxInternal *)b)->rson,
143 		b2a, abs_b2a, a2b, abs_a2b, v);
144   }
145   else {
146     return
147       intersect(((const BBoxInternal *)a)->lson, b, b2a, abs_b2a, a2b, abs_a2b, v) ||
148       intersect(((const BBoxInternal *)a)->rson, b, b2a, abs_b2a, a2b, abs_a2b, v);
149   }
150 }
151 
152 
153 
find_prim(const BBoxNode * tree,const Convex & c,const BBox & bb,const Transform & b2a,Vector & v,ShapePtr & p)154 bool find_prim(const BBoxNode *tree, const Convex& c, const BBox& bb,
155 	       const Transform& b2a, Vector& v, ShapePtr& p) {
156   if (!intersect(tree->bbox, bb)) return false;
157 
158   if (tree->tag == BBoxNode::LEAF) {
159     if  (intersect(*((const BBoxLeaf *)tree)->poly, c, b2a, v)) {
160       p = ((const BBoxLeaf *)tree)->poly;
161       return true;
162     }
163     else return false;
164   }
165   else {
166     return find_prim(((const BBoxInternal *)tree)->lson, c, bb, b2a, v, p) ||
167       find_prim(((const BBoxInternal *)tree)->rson, c, bb, b2a, v, p);
168   }
169 }
170 
171 
find_prim(const BBoxNode * a,const BBoxNode * b,const Transform & b2a,const Matrix & abs_b2a,const Transform & a2b,const Matrix & abs_a2b,Vector & v,ShapePtr & pa,ShapePtr & pb)172 bool find_prim(const BBoxNode *a, const BBoxNode *b,
173 	       const Transform& b2a, const Matrix& abs_b2a,
174 	       const Transform& a2b, const Matrix& abs_a2b,
175 	       Vector& v, ShapePtr& pa, ShapePtr& pb) {
176   if (!intersect(a->bbox, b->bbox, b2a, abs_b2a, a2b, abs_a2b)) return false;
177 
178   if (a->tag == BBoxNode::LEAF && b->tag == BBoxNode::LEAF) {
179     if (intersect(*((const BBoxLeaf *)a)->poly,
180 		  *((const BBoxLeaf *)b)->poly, b2a, v)) {
181       pa = ((const BBoxLeaf *)a)->poly;
182       pb = ((const BBoxLeaf *)b)->poly;
183       return true;
184     }
185     else return false;
186   }
187   else if (a->tag == BBoxNode::LEAF ||
188 	   (b->tag != BBoxNode::LEAF && a->bbox.size() < b->bbox.size())) {
189     return
190       find_prim(a, ((const BBoxInternal *)b)->lson,
191 		b2a, abs_b2a, a2b, abs_a2b, v, pa, pb) ||
192       find_prim(a, ((const BBoxInternal *)b)->rson,
193 		b2a, abs_b2a, a2b, abs_a2b, v, pa, pb);
194   }
195   else {
196     return
197       find_prim(((const BBoxInternal *)a)->lson, b, b2a, abs_b2a, a2b, abs_a2b, v, pa, pb) ||
198       find_prim(((const BBoxInternal *)a)->rson, b, b2a, abs_b2a, a2b, abs_a2b, v, pa, pb);
199   }
200 }
201 
202 
203 
common_point(const BBoxNode * tree,const Convex & c,const BBox & bb,const Transform & b2a,Vector & v,Point & pa,Point & pb)204 bool common_point(const BBoxNode *tree, const Convex& c, const BBox& bb,
205 		  const Transform& b2a, Vector& v, Point& pa, Point& pb) {
206   if (!intersect(tree->bbox, bb)) return false;
207 
208   if (tree->tag == BBoxNode::LEAF)
209     return common_point(*((const BBoxLeaf *)tree)->poly, c, b2a, v, pa, pb);
210   else {
211     return common_point(((const BBoxInternal *)tree)->lson, c, bb, b2a, v, pa, pb) ||
212       common_point(((const BBoxInternal *)tree)->rson, c, bb, b2a, v, pa, pb);
213   }
214 }
215 
216 
common_point(const BBoxNode * a,const BBoxNode * b,const Transform & b2a,const Matrix & abs_b2a,const Transform & a2b,const Matrix & abs_a2b,Vector & v,Point & pa,Point & pb)217 bool common_point(const BBoxNode *a, const BBoxNode *b,
218 		  const Transform& b2a, const Matrix& abs_b2a,
219 		  const Transform& a2b, const Matrix& abs_a2b,
220 		  Vector& v, Point& pa, Point& pb) {
221   if (!intersect(a->bbox, b->bbox, b2a, abs_b2a, a2b, abs_a2b)) return false;
222 
223   if (a->tag == BBoxNode::LEAF && b->tag == BBoxNode::LEAF) {
224     return common_point(*((const BBoxLeaf *)a)->poly,
225 			*((const BBoxLeaf *)b)->poly, b2a, v, pa, pb);
226   }
227   else if (a->tag == BBoxNode::LEAF ||
228 	   (b->tag != BBoxNode::LEAF && a->bbox.size() < b->bbox.size())) {
229     return
230       common_point(a, ((const BBoxInternal *)b)->lson,
231 		   b2a, abs_b2a, a2b, abs_a2b, v, pa, pb) ||
232       common_point(a, ((const BBoxInternal *)b)->rson,
233 		   b2a, abs_b2a, a2b, abs_a2b, v, pa, pb);
234   }
235   else {
236     return
237       common_point(((const BBoxInternal *)a)->lson, b, b2a, abs_b2a, a2b, abs_a2b, v, pa, pb) ||
238       common_point(((const BBoxInternal *)a)->rson, b, b2a, abs_b2a, a2b, abs_a2b, v, pa ,pb);
239   }
240 }
241 
242 
243 
244 
245