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