root/trunk/dep/src/g3dlite/Box.cpp @ 2

Revision 2, 7.9 kB (checked in by yumileroy, 17 years ago)

[svn] * Proper SVN structure

Original author: Neo2003
Date: 2008-10-02 16:23:55-05:00

Line 
1/**
2  @file Box.cpp
3  Box class
4
5  @maintainer Morgan McGuire, matrix@graphics3d.com
6
7  @created 2001-06-02
8  @edited  2006-02-05
9*/
10
11#include "G3D/Box.h"
12#include "G3D/debug.h"
13#include "G3D/Plane.h"
14#include "G3D/AABox.h"
15#include "G3D/CoordinateFrame.h"
16
17namespace G3D {
18
19/**
20 Sets a field on four vertices.  Used by the constructor.
21 */
22#define setMany(i0, i1, i2, i3, field, extreme) \
23    _corner[i0].field = _corner[i1].field = \
24    _corner[i2].field = _corner[i3].field = \
25    (extreme).field
26
27Box::Box() {
28}
29
30
31Box::Box(const AABox& b) {
32    init(b.low(), b.high());
33}
34
35
36Box::Box(
37    const Vector3& min,
38    const Vector3& max) {
39
40    init(min.min(max), min.max(max));
41
42}
43
44void Box::init(
45    const Vector3& min,
46    const Vector3& max) {
47
48    setMany(0, 1, 2, 3, z, max);
49    setMany(4, 5, 6, 7, z, min);
50
51    setMany(1, 2, 5, 6, x, max);
52    setMany(0, 3, 4, 7, x, min);
53
54    setMany(3, 2, 6, 7, y, max);
55    setMany(0, 1, 5, 4, y, min);
56
57    _extent = max - min;
58
59    _axis[0] = Vector3::unitX();
60    _axis[1] = Vector3::unitY();
61    _axis[2] = Vector3::unitZ();
62
63    _volume = _extent.x * _extent.y * _extent.z;
64    _area = 2 * 
65        (_extent.x * _extent.y +
66         _extent.y * _extent.z +
67         _extent.z * _extent.x);
68
69    _center = (max + min) / 2;
70}
71
72
73float Box::volume() const {
74    return _volume;
75}
76
77
78float Box::surfaceArea() const {
79    return _area;
80}
81
82
83void Box::getLocalFrame(CoordinateFrame& frame) const {
84
85    frame.rotation = Matrix3(
86        _axis[0][0], _axis[1][0], _axis[2][0],
87        _axis[0][1], _axis[1][1], _axis[2][1],
88        _axis[0][2], _axis[1][2], _axis[2][2]);
89
90    frame.translation = _center;
91}
92
93
94CoordinateFrame Box::localFrame() const {
95    CoordinateFrame out;
96    getLocalFrame(out);
97    return out;
98}
99
100
101void Box::getFaceCorners(int f, Vector3& v0, Vector3& v1, Vector3& v2, Vector3& v3) const {
102    switch (f) {
103    case 0:
104        v0 = _corner[0]; v1 = _corner[1]; v2 = _corner[2]; v3 = _corner[3];
105        break;
106
107    case 1:
108        v0 = _corner[1]; v1 = _corner[5]; v2 = _corner[6]; v3 = _corner[2];
109        break;
110
111    case 2:
112        v0 = _corner[7]; v1 = _corner[6]; v2 = _corner[5]; v3 = _corner[4];
113        break;
114
115    case 3:
116        v0 = _corner[2]; v1 = _corner[6]; v2 = _corner[7]; v3 = _corner[3];
117        break;
118
119    case 4:
120        v0 = _corner[3]; v1 = _corner[7]; v2 = _corner[4]; v3 = _corner[0];
121        break;
122
123    case 5:
124        v0 = _corner[1]; v1 = _corner[0]; v2 = _corner[4]; v3 = _corner[5];
125        break;
126
127    default:
128        debugAssert((f >= 0) && (f < 6));
129    }
130}
131
132
133bool Box::culledBy(
134    const Array<Plane>&         plane,
135        int&                                cullingPlaneIndex,
136        const uint32                    inMask,
137        uint32&                                 outMask) const {
138
139        return culledBy(plane.getCArray(), plane.size(), cullingPlaneIndex, inMask, outMask);
140}
141
142
143bool Box::culledBy(
144    const Array<Plane>&         plane,
145        int&                                cullingPlaneIndex,
146        const uint32                    inMask) const {
147
148        return culledBy(plane.getCArray(), plane.size(), cullingPlaneIndex, inMask);
149}
150
151
152int32 Box::dummy = 0;
153
154bool Box::culledBy(
155    const class Plane*  plane,
156    int                 numPlanes,
157        int&                            cullingPlane,
158        const uint32            _inMask,
159    uint32&             childMask) const {
160
161        uint32 inMask = _inMask;
162        assert(numPlanes < 31);
163
164    childMask = 0;
165
166    // See if there is one plane for which all of the
167        // vertices are in the negative half space.
168    for (int p = 0; p < numPlanes; p++) {
169
170                // Only test planes that are not masked
171                if ((inMask & 1) != 0) {
172               
173                        Vector3 corner;
174
175            int numContained = 0;
176            int v = 0;
177
178            // We can early-out only if we have found one point on each
179            // side of the plane (i.e. if we are straddling).  That
180            // occurs when (numContained < v) && (numContained > 0)
181                        for (v = 0; (v < 8) && ((numContained == v) || (numContained == 0)); ++v) {
182                if (plane[p].halfSpaceContains(getCorner(v))) {
183                    ++numContained;
184                }
185                        }
186
187                        if (numContained == 0) {
188                                // Plane p culled the box
189                                cullingPlane = p;
190
191                // The caller should not recurse into the children,
192                // since the parent is culled.  If they do recurse,
193                // make them only test against this one plane, which
194                // will immediately cull the volume.
195                childMask = 1 << p;
196                                return true;
197
198            } else if (numContained < v) {
199                // The bounding volume straddled the plane; we have
200                // to keep testing against this plane
201                childMask |= (1 << p);
202            }
203                }
204
205        // Move on to the next bit.
206                inMask = inMask >> 1;
207    }
208
209    // None of the planes could cull this box
210        cullingPlane = -1;
211    return false;
212}
213
214
215bool Box::culledBy(
216    const class Plane*  plane,
217    int                 numPlanes,
218        int&                            cullingPlane,
219        const uint32            _inMask) const {
220
221        uint32 inMask = _inMask;
222        assert(numPlanes < 31);
223
224    // See if there is one plane for which all of the
225        // vertices are in the negative half space.
226    for (int p = 0; p < numPlanes; p++) {
227
228                // Only test planes that are not masked
229                if ((inMask & 1) != 0) {
230               
231                        bool culled = true;
232
233            int v;
234
235                        // Assume this plane culls all points.  See if there is a point
236                        // not culled by the plane... early out when at least one point
237            // is in the positive half space.
238                        for (v = 0; (v < 8) && culled; ++v) {
239                culled = ! plane[p].halfSpaceContains(getCorner(v));
240                        }
241
242                        if (culled) {
243                                // Plane p culled the box
244                                cullingPlane = p;
245
246                                return true;
247            }
248                }
249
250        // Move on to the next bit.
251                inMask = inMask >> 1;
252    }
253
254    // None of the planes could cull this box
255        cullingPlane = -1;
256    return false;
257}
258
259
260bool Box::contains(
261    const Vector3&      point) const {
262
263    // Form axes from three edges, transform the point into that
264    // space, and perform 3 interval tests
265
266    Vector3 u = _corner[4] - _corner[0];
267    Vector3 v = _corner[3] - _corner[0];
268    Vector3 w = _corner[1] - _corner[0];
269
270    Matrix3 M = Matrix3(u.x, v.x, w.x,
271                        u.y, v.y, w.y,
272                        u.z, v.z, w.z);
273
274    // M^-1 * (point - _corner[0]) = point in unit cube's object space
275    // compute the inverse of M
276    Vector3 osPoint = M.inverse() * (point - _corner[0]);
277
278    return
279        (osPoint.x >= 0) && 
280        (osPoint.y >= 0) &&
281        (osPoint.z >= 0) &&
282        (osPoint.x <= 1) &&
283        (osPoint.y <= 1) &&
284        (osPoint.z <= 1);
285}
286
287#undef setMany
288
289#if 0
290void Box::getRandomSurfacePoint(Vector3& P, Vector3& N) const {
291    float aXY = _extent.x * _extent.y;
292    float aYZ = _extent.y * _extent.z;
293    float aZX = _extent.z * _extent.x;
294
295    float r = (float)random(0, aXY + aYZ + aZX);
296
297    // Choose evenly between positive and negative face planes
298    float d = (random(0, 1) < 0.5f) ? -1.0f : 1.0f;
299
300    // The probability of choosing a given face is proportional to
301    // its area.
302    if (r < aXY) {
303        P = _axis[0] * (float)random(-0.5, 0.5) * _extent.x +
304            _axis[1] * (float)random(-0.5, 0.5) * _extent.y +
305            _center + _axis[2] * d * _extent.z * 0.5f;
306        N = _axis[2] * d;
307    } else if (r < aYZ) {
308        P = _axis[1] * (float)random(-0.5, 0.5) * _extent.y +
309            _axis[2] * (float)random(-0.5, 0.5) * _extent.z +
310            _center + _axis[0] * d * _extent.x * 0.5f;
311        N = _axis[0] * d;
312    } else {
313        P = _axis[2] * (float)random(-0.5, 0.5) * _extent.z +
314            _axis[0] *(float) random(-0.5, 0.5) * _extent.x +
315            _center + _axis[1] * d * _extent.y * 0.5f;
316        N = _axis[1] * d;
317    }
318}
319
320
321Vector3 Box::randomInteriorPoint() const {
322    Vector3 sum = _center;
323
324    for (int a = 0; a < 3; ++a) {
325        sum += _axis[a] * (float)random(-0.5, 0.5) * _extent[a];
326    }
327
328    return sum;
329}
330#endif
331
332
333void Box::getBounds(class AABox& aabb) const {
334
335    Vector3 lo = _corner[0];
336    Vector3 hi = lo;
337
338    for (int v = 1; v < 8; ++v) {
339        const Vector3& C = _corner[v];
340        lo = lo.min(C);
341        hi = hi.max(C);
342    }
343
344    aabb = AABox(lo, hi);
345}
346
347
348} // namespace
Note: See TracBrowser for help on using the browser.