optional BoundingBox

This commit is contained in:
David Rose 2007-06-02 00:59:32 +00:00
parent 2c85e350ee
commit faad1e333d
35 changed files with 2022 additions and 231 deletions

View File

@ -32,6 +32,8 @@
#include "bamWriter.h"
#include "clockObject.h"
#include "boundingSphere.h"
#include "boundingBox.h"
#include "config_mathutil.h"
TypeHandle CollisionNode::_type_handle;
@ -309,41 +311,43 @@ set_from_collide_mask(CollideMask mask) {
void CollisionNode::
compute_internal_bounds(PandaNode::BoundsData *bdata, int pipeline_stage,
Thread *current_thread) const {
// First, get ourselves a fresh, empty bounding volume.
PT(BoundingVolume) bound = new BoundingSphere;
// Now actually compute the bounding volume by putting it around all
// of our solids' bounding volumes.
pvector<CPT(BoundingVolume) > child_volumes_ref;
pvector<const BoundingVolume *> child_volumes;
pvector<CPT(BoundingVolume) > cpt_volumes;
bool all_box = true;
Solids::const_iterator gi;
for (gi = _solids.begin(); gi != _solids.end(); ++gi) {
CPT(CollisionSolid) solid = (*gi).get_read_pointer();
CPT(BoundingVolume) volume = solid->get_bounds();
cpt_volumes.push_back(volume);
child_volumes.push_back(volume);
}
const BoundingVolume **child_begin = &child_volumes[0];
const BoundingVolume **child_end = child_begin + child_volumes.size();
bool success =
bound->around(child_begin, child_end);
#ifdef NOTIFY_DEBUG
if (!success) {
collide_cat.error()
<< "Unable to generate bounding volume for " << *this << ":\n"
<< "Cannot put " << bound->get_type() << " around:\n";
for (int i = 0; i < (int)child_volumes.size(); i++) {
collide_cat.error(false)
<< " " << *child_volumes[i] << "\n";
if (!volume->is_empty()) {
child_volumes_ref.push_back(volume);
child_volumes.push_back(volume);
if (!volume->is_exact_type(BoundingBox::get_class_type())) {
all_box = false;
}
}
}
#endif
bdata->_internal_bounds = bound;
PT(GeometricBoundingVolume) gbv = new BoundingBox;
if (bounds_type == BoundingVolume::BT_box ||
(bounds_type != BoundingVolume::BT_sphere && all_box)) {
// If all of the child volumes are a BoundingBox, then our volume
// is also a BoundingBox.
gbv = new BoundingBox;
} else {
// Otherwise, it's a sphere.
gbv = new BoundingSphere;
}
if (child_volumes.size() > 0) {
const BoundingVolume **child_begin = &child_volumes[0];
const BoundingVolume **child_end = child_begin + child_volumes.size();
((BoundingVolume *)gbv)->around(child_begin, child_end);
}
bdata->_internal_bounds = gbv;
bdata->_internal_vertices = 0;
bdata->_internal_bounds_stale = false;
}

View File

@ -25,7 +25,7 @@
#include "collisionSegment.h"
#include "config_collide.h"
#include "cullTraverserData.h"
#include "boundingSphere.h"
#include "boundingBox.h"
#include "pointerToArray.h"
#include "geomNode.h"
#include "geom.h"
@ -386,27 +386,31 @@ write(ostream &out, int indent_level) const {
////////////////////////////////////////////////////////////////////
PT(BoundingVolume) CollisionPolygon::
compute_internal_bounds() const {
// First, get ourselves a fresh, empty bounding volume.
PT(BoundingVolume) bound = CollisionSolid::compute_internal_bounds();
nassertr(bound != (BoundingVolume*)0L, bound);
GeometricBoundingVolume *gbv = DCAST(GeometricBoundingVolume, bound);
// Now actually compute the bounding volume by putting it around all
// of our vertices.
LMatrix4f to_3d_mat;
rederive_to_3d_mat(to_3d_mat);
pvector<LPoint3f> vertices;
Points::const_iterator pi;
for (pi = _points.begin(); pi != _points.end(); ++pi) {
vertices.push_back(to_3d((*pi)._p, to_3d_mat));
if (_points.empty()) {
return new BoundingBox;
}
const LPoint3f *vertices_begin = &vertices[0];
const LPoint3f *vertices_end = vertices_begin + vertices.size();
gbv->around(vertices_begin, vertices_end);
LMatrix4f to_3d_mat;
rederive_to_3d_mat(to_3d_mat);
return bound;
Points::const_iterator pi = _points.begin();
LPoint3f p = to_3d((*pi)._p, to_3d_mat);
LPoint3f x = p;
LPoint3f n = p;
for (++pi; pi != _points.end(); ++pi) {
p = to_3d((*pi)._p, to_3d_mat);
n.set(min(n[0], p[0]),
min(n[1], p[1]),
min(n[2], p[2]));
x.set(max(x[0], p[0]),
max(x[1], p[1]),
max(x[2], p[2]));
}
return new BoundingBox(n, x);
}
////////////////////////////////////////////////////////////////////

View File

@ -450,12 +450,19 @@ center_trackball(const NodePath &object) {
// We expect at least a geometric bounding volume around the world.
nassertv(volume != (BoundingVolume *)NULL);
nassertv(volume->is_of_type(GeometricBoundingVolume::get_class_type()));
GeometricBoundingVolume *gbv = DCAST(GeometricBoundingVolume, volume);
CPT(GeometricBoundingVolume) gbv = DCAST(GeometricBoundingVolume, volume);
// Determine the bounding sphere around the world. The topmost
// BoundingVolume might itself be a sphere (it's likely), but since
// it might not, we'll take no chances and make our own sphere.
PT(BoundingSphere) sphere = new BoundingSphere;
if (object.has_parent()) {
CPT(TransformState) net_transform = object.get_parent().get_net_transform();
PT(GeometricBoundingVolume) new_gbv = DCAST(GeometricBoundingVolume, gbv->make_copy());
new_gbv->xform(net_transform->get_mat());
gbv = new_gbv;
}
// Determine the bounding sphere around the object. The
// BoundingVolume might be a sphere (it's likely), but since it
// might not, we'll take no chances and make our own sphere.
PT(BoundingSphere) sphere = new BoundingSphere(gbv->get_approx_center(), 0.0f);
if (!sphere->extend_by(gbv)) {
framework_cat.warning()
<< "Cannot determine bounding volume of " << object << "\n";
@ -497,7 +504,7 @@ center_trackball(const NodePath &object) {
distance = radius / ctan(deg_2_rad(min(fov[0], fov[1]) / 2.0f));
// Ensure the far plane is far enough back to see the entire object.
float ideal_far_plane = distance + radius;
float ideal_far_plane = distance + radius * 1.5;
lens->set_far(max(lens->get_default_far(), ideal_far_plane));
// And that the near plane is far enough forward.

View File

@ -26,7 +26,9 @@
#include "bamReader.h"
#include "bamWriter.h"
#include "boundingSphere.h"
#include "boundingBox.h"
#include "mutexHolder.h"
#include "config_mathutil.h"
UpdateSeq Geom::_next_modified;
PStatCollector Geom::_draw_primitive_setup_pcollector("Draw:Primitive:Setup");
@ -1074,30 +1076,32 @@ void Geom::
compute_internal_bounds(Geom::CData *cdata, Thread *current_thread) const {
int num_vertices = 0;
// First, get ourselves a fresh, empty bounding volume.
PT(BoundingVolume) bound = new BoundingSphere;
GeometricBoundingVolume *gbv = DCAST(GeometricBoundingVolume, bound);
// Get the vertex data, after animation.
CPT(GeomVertexData) vertex_data = cdata->_data.get_read_pointer();
vertex_data = vertex_data->animate_vertices(current_thread);
// Now actually compute the bounding volume. We do this by using
// calc_tight_bounds to determine our minmax first.
LPoint3f points[2];
// calc_tight_bounds to determine our box first.
LPoint3f min, max;
bool found_any = false;
do_calc_tight_bounds(points[0], points[1], found_any, vertex_data,
do_calc_tight_bounds(min, max, found_any, vertex_data,
false, LMatrix4f::ident_mat(), cdata, current_thread);
if (found_any) {
// Then we put the bounding volume around both of those points.
// Technically, we should put it around the eight points at the
// corners of the rectangular solid, but we happen to know that
// the two diagonally opposite points is good enough to define any
// of our bound volume types.
if (bounds_type == BoundingVolume::BT_sphere) {
// The user specifically requested a BoundingSphere, so oblige.
BoundingBox box(min, max);
box.local_object();
const LPoint3f *points_begin = &points[0];
const LPoint3f *points_end = points_begin + 2;
gbv->around(points_begin, points_end);
PT(BoundingSphere) sphere = new BoundingSphere;
sphere->extend_by(&box);
cdata->_internal_bounds = sphere;
} else {
// The user requested a BoundingBox, or did not specify.
cdata->_internal_bounds = new BoundingBox(min, max);
}
Primitives::const_iterator pi;
for (pi = cdata->_primitives.begin();
@ -1106,9 +1110,16 @@ compute_internal_bounds(Geom::CData *cdata, Thread *current_thread) const {
CPT(GeomPrimitive) prim = (*pi).get_read_pointer();
num_vertices += prim->get_num_vertices();
}
} else {
// No points; empty bounding volume.
if (bounds_type == BoundingVolume::BT_sphere) {
cdata->_internal_bounds = new BoundingSphere;
} else {
cdata->_internal_bounds = new BoundingBox;
}
}
cdata->_internal_bounds = bound;
cdata->_nested_vertices = num_vertices;
cdata->_internal_bounds_stale = false;
}

View File

@ -21,8 +21,10 @@
#include "graphicsPipe.h"
#include "drawCullHandler.h"
#include "boundingSphere.h"
#include "boundingBox.h"
#include "geomVertexWriter.h"
#include "geomTristrips.h"
#include "geomTriangles.h"
#include "pStatTimer.h"
#include "cullBinManager.h"
#include "configVariableInt.h"
@ -115,6 +117,7 @@ PipeOcclusionCullTraverser(GraphicsOutput *host) {
_internal_cull_handler = NULL;
make_sphere();
make_box();
make_solid_test_state();
_live = true;
@ -199,8 +202,8 @@ set_scene(SceneSetup *scene_setup, GraphicsStateGuardianBase *gsgbase) {
_current_query = NULL;
_next_query = NULL;
make_sphere();
make_sphere(); // Temporary, so we can experiment with num vertices
// Begin by rendering all the occluders into our internal scene.
PStatTimer timer2(_draw_occlusion_pcollector);
@ -433,7 +436,7 @@ make_sphere() {
// static const int num_stacks = 8;
PT(GeomVertexData) vdata = new GeomVertexData
("occlusion", GeomVertexFormat::get_v3(), Geom::UH_static);
("occlusion_sphere", GeomVertexFormat::get_v3(), Geom::UH_static);
GeomVertexWriter vertex(vdata, InternalName::get_vertex());
PT(GeomTristrips) strip = new GeomTristrips(Geom::UH_stream);
@ -474,6 +477,57 @@ compute_sphere_point(float latitude, float longitude) {
return p;
}
////////////////////////////////////////////////////////////////////
// Function: PipeOcclusionCullTraverser::make_box
// Access: Private
// Description: Constructs a unit box for testing visibility of
// bounding boxes.
////////////////////////////////////////////////////////////////////
void PipeOcclusionCullTraverser::
make_box() {
PT(GeomVertexData) vdata = new GeomVertexData
("occlusion_box", GeomVertexFormat::get_v3(), Geom::UH_static);
GeomVertexWriter vertex(vdata, InternalName::get_vertex());
vertex.add_data3f(0.0f, 0.0f, 0.0f);
vertex.add_data3f(0.0f, 0.0f, 1.0f);
vertex.add_data3f(0.0f, 1.0f, 0.0f);
vertex.add_data3f(0.0f, 1.0f, 1.0f);
vertex.add_data3f(1.0f, 0.0f, 0.0f);
vertex.add_data3f(1.0f, 0.0f, 1.0f);
vertex.add_data3f(1.0f, 1.0f, 0.0f);
vertex.add_data3f(1.0f, 1.0f, 1.0f);
PT(GeomTriangles) tris = new GeomTriangles(Geom::UH_static);
tris->add_vertices(0, 4, 5);
tris->close_primitive();
tris->add_vertices(0, 5, 1);
tris->close_primitive();
tris->add_vertices(4, 6, 7);
tris->close_primitive();
tris->add_vertices(4, 7, 5);
tris->close_primitive();
tris->add_vertices(6, 2, 3);
tris->close_primitive();
tris->add_vertices(6, 3, 7);
tris->close_primitive();
tris->add_vertices(2, 0, 1);
tris->close_primitive();
tris->add_vertices(2, 1, 3);
tris->close_primitive();
tris->add_vertices(1, 5, 7);
tris->close_primitive();
tris->add_vertices(1, 7, 3);
tris->close_primitive();
tris->add_vertices(2, 6, 4);
tris->close_primitive();
tris->add_vertices(2, 4, 0);
tris->close_primitive();
_box_geom = new Geom(vdata);
_box_geom->add_primitive(tris);
}
////////////////////////////////////////////////////////////////////
// Function: PipeOcclusionCullTraverser::make_solid_test_state
// Access: Private
@ -514,7 +568,7 @@ get_volume_viz(const BoundingVolume *vol,
return false;
}
if (vol->is_of_type(BoundingSphere::get_class_type())) {
if (vol->is_exact_type(BoundingSphere::get_class_type())) {
const BoundingSphere *sphere = DCAST(BoundingSphere, vol);
CPT(TransformState) local_transform =
TransformState::make_pos_hpr_scale(sphere->get_center(),
@ -530,14 +584,49 @@ get_volume_viz(const BoundingVolume *vol,
// since it's intersecting the near plane.
const LPoint3f &center = modelview_transform->get_pos();
const LVecBase3f &radius = modelview_transform->get_scale();
float max_radius = max(max(radius[0], radius[1]), radius[2]);
if (center[1] <= max_radius) {
if (center[1] - radius[1] < 0.0f) {
return false;
}
// The sphere looks good.
geom = _sphere_geom;
return true;
} else if (vol->is_exact_type(BoundingBox::get_class_type())) {
const BoundingBox *box = DCAST(BoundingBox, vol);
CPT(TransformState) local_transform =
TransformState::make_pos_hpr_scale(box->get_minq(),
LVecBase3f(0, 0, 0),
box->get_maxq() - box->get_minq());
net_transform = net_transform->compose(local_transform);
modelview_transform = _internal_trav->get_world_transform()->compose(net_transform);
// See if the bounding box is clipped by the near plane. If it
// is, the occlusion test may fail, so we won't bother performing
// it for this object. Anyway, it's not occluded by anything,
// since it's intersecting the near plane.
static const LPoint3f points[8] = {
LPoint3f(0.0f, 0.0f, 0.0f),
LPoint3f(0.0f, 0.0f, 1.0f),
LPoint3f(0.0f, 1.0f, 0.0f),
LPoint3f(0.0f, 1.0f, 1.0f),
LPoint3f(1.0f, 0.0f, 0.0f),
LPoint3f(1.0f, 0.0f, 1.0f),
LPoint3f(1.0f, 1.0f, 0.0f),
LPoint3f(1.0f, 1.0f, 1.0f),
};
const LMatrix4f &mat = modelview_transform->get_mat();
for (int i = 0; i < 8; ++i) {
LPoint3f p = points[i] * mat;
if (p[1] < 0.0f) {
return false;
}
}
// The box looks good.
geom = _box_geom;
return true;
}
// Don't have a suitable representation for this bounding volume.

View File

@ -74,6 +74,8 @@ protected:
private:
void make_sphere();
static Vertexf compute_sphere_point(float latitude, float longitude);
void make_box();
void make_solid_test_state();
bool get_volume_viz(const BoundingVolume *vol,
@ -111,6 +113,7 @@ private:
PT(OcclusionQueryContext) _next_query;
PT(Geom) _sphere_geom;
PT(Geom) _box_geom;
CPT(RenderState) _solid_test_state;
class PendingObject {

View File

@ -13,6 +13,7 @@
#define SOURCES \
boundingHexahedron.I boundingHexahedron.h boundingLine.I \
boundingLine.h \
boundingBox.I boundingBox.h \
boundingPlane.I boundingPlane.h \
boundingSphere.I boundingSphere.h \
boundingVolume.I boundingVolume.h config_mathutil.h \
@ -39,6 +40,7 @@
#define INCLUDED_SOURCES \
boundingHexahedron.cxx boundingLine.cxx \
boundingBox.cxx \
boundingPlane.cxx \
boundingSphere.cxx \
boundingVolume.cxx config_mathutil.cxx fftCompressor.cxx \
@ -59,6 +61,7 @@
#define INSTALL_HEADERS \
boundingHexahedron.I boundingHexahedron.h boundingLine.I \
boundingLine.h \
boundingBox.I boundingBox.h \
boundingPlane.I boundingPlane.h \
boundingSphere.I boundingSphere.h boundingVolume.I \
boundingVolume.h config_mathutil.h fftCompressor.h \

View File

@ -0,0 +1,120 @@
// Filename: boundingBox.I
// Created by: drose (31May07)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: BoundingBox::Constructor
// Access: Published
// Description: Constructs an empty box object.
////////////////////////////////////////////////////////////////////
INLINE_MATHUTIL BoundingBox::
BoundingBox() {
}
////////////////////////////////////////////////////////////////////
// Function: BoundingBox::Constructor
// Access: Published
// Description: Constructs a specific box object.
////////////////////////////////////////////////////////////////////
INLINE_MATHUTIL BoundingBox::
BoundingBox(const LPoint3f &min, const LPoint3f &max) :
_min(min), _max(max)
{
#ifdef NDEBUG
_flags = F_empty;
nassertv(!_min.is_nan() && !_max.is_nan());
nassertv(_min[0] <= _max[0] && _min[1] <= _max[1] && _min[2] <= _max[2]);
#endif // NDEBUG
_flags = 0;
}
////////////////////////////////////////////////////////////////////
// Function: BoundingBox::get_minq
// Access: Public
// Description: An inline accessor for the minimum value. get_min()
// would also work, but it is a virtual non-inline
// method.
////////////////////////////////////////////////////////////////////
INLINE_MATHUTIL const LPoint3f &BoundingBox::
get_minq() const {
nassertr(!is_empty(), _min);
nassertr(!is_infinite(), _min);
return _min;
}
////////////////////////////////////////////////////////////////////
// Function: BoundingBox::get_maxq
// Access: Public
// Description: An inline accessor for the maximum value. get_max()
// would also work, but it is a virtual non-inline
// method.
////////////////////////////////////////////////////////////////////
INLINE_MATHUTIL const LPoint3f &BoundingBox::
get_maxq() const {
nassertr(!is_empty(), _max);
nassertr(!is_infinite(), _max);
return _max;
}
////////////////////////////////////////////////////////////////////
// Function: BoundingBox::get_num_points
// Access: Published
// Description: Returns 8: the number of vertices of a rectangular solid.
////////////////////////////////////////////////////////////////////
INLINE_MATHUTIL int BoundingBox::
get_num_points() const {
return 8;
}
////////////////////////////////////////////////////////////////////
// Function: BoundingBox::get_point
// Access: Published
// Description: Returns the nth vertex of the rectangular solid.
////////////////////////////////////////////////////////////////////
INLINE_MATHUTIL LPoint3f BoundingBox::
get_point(int n) const {
nassertr(n >= 0 && n < 8, LPoint3f::zero());
// We do some trickery assuming that _min and _max are consecutive
// in memory.
const LPoint3f *a = &_min;
return LPoint3f(a[(n>>2)&1][0], a[(n>>1)&1][1], a[(n)&1][2]);
}
////////////////////////////////////////////////////////////////////
// Function: BoundingBox::get_num_planes
// Access: Published
// Description: Returns 6: the number of faces of a rectangular solid.
////////////////////////////////////////////////////////////////////
INLINE_MATHUTIL int BoundingBox::
get_num_planes() const {
return 6;
}
////////////////////////////////////////////////////////////////////
// Function: BoundingBox::get_plane
// Access: Published
// Description: Returns the nth face of the rectangular solid.
////////////////////////////////////////////////////////////////////
INLINE_MATHUTIL Planef BoundingBox::
get_plane(int n) const {
nassertr(n >= 0 && n < 6, Planef());
return Planef(get_point(plane_def[n][0]),
get_point(plane_def[n][1]),
get_point(plane_def[n][2]));
}

View File

@ -0,0 +1,643 @@
// Filename: boundingBox.cxx
// Created by: drose (31May07)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "boundingBox.h"
#include "boundingSphere.h"
#include "boundingHexahedron.h"
#include "boundingLine.h"
#include "boundingPlane.h"
#include "config_mathutil.h"
#include "dcast.h"
#include <math.h>
#include <algorithm>
const int BoundingBox::plane_def[6][3] = {
{ 0, 4, 5 },
{ 4, 6, 7 },
{ 6, 2, 3 },
{ 2, 0, 1 },
{ 1, 5, 7 },
{ 2, 6, 4 },
};
TypeHandle BoundingBox::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: BoundingBox::make_copy
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
BoundingVolume *BoundingBox::
make_copy() const {
return new BoundingBox(*this);
}
////////////////////////////////////////////////////////////////////
// Function: BoundingBox::get_min
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
LPoint3f BoundingBox::
get_min() const {
nassertr(!is_empty(), _min);
nassertr(!is_infinite(), _min);
return _min;
}
////////////////////////////////////////////////////////////////////
// Function: BoundingBox::get_max
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
LPoint3f BoundingBox::
get_max() const {
nassertr(!is_empty(), _max);
nassertr(!is_infinite(), _max);
return _max;
}
////////////////////////////////////////////////////////////////////
// Function: BoundingBox::get_volume
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
float BoundingBox::
get_volume() const {
nassertr(!is_infinite(), 0.0f);
if (is_empty()) {
return 0.0f;
}
// Volume of a box: width x depth x height
return (_max[0] - _min[0]) * (_max[1] - _min[1]) * (_max[2] - _min[2]);
}
////////////////////////////////////////////////////////////////////
// Function: BoundingBox::get_approx_center
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
LPoint3f BoundingBox::
get_approx_center() const {
nassertr(!is_empty(), LPoint3f::zero());
nassertr(!is_infinite(), LPoint3f::zero());
return (_min + _max) * 0.5f;
}
////////////////////////////////////////////////////////////////////
// Function: BoundingBox::xform
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void BoundingBox::
xform(const LMatrix4f &mat) {
nassertv(!mat.is_nan());
if (!is_empty() && !is_infinite()) {
// We need to transform the eight corners of the cube, and then
// determine the new box.
LPoint3f x = get_point(0) * mat;
LPoint3f n = x;
for (int i = 1; i < 8; ++i) {
LPoint3f p = get_point(i) * mat;
n.set(min(n[0], p[0]), min(n[1], p[1]), min(n[2], p[2]));
x.set(max(x[0], p[0]), max(x[1], p[1]), max(x[2], p[2]));
}
_max = x;
_min = n;
}
}
////////////////////////////////////////////////////////////////////
// Function: BoundingBox::output
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void BoundingBox::
output(ostream &out) const {
if (is_empty()) {
out << "bbox, empty";
} else if (is_infinite()) {
out << "bbox, infinite";
} else {
out << "bbox, (" << _min << ") to (" << _max << ")";
}
}
////////////////////////////////////////////////////////////////////
// Function: BoundingBox::extend_other
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
bool BoundingBox::
extend_other(BoundingVolume *other) const {
return other->extend_by_box(this);
}
////////////////////////////////////////////////////////////////////
// Function: BoundingBox::around_other
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
bool BoundingBox::
around_other(BoundingVolume *other,
const BoundingVolume **first,
const BoundingVolume **last) const {
return other->around_boxes(first, last);
}
////////////////////////////////////////////////////////////////////
// Function: BoundingBox::contains_other
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
int BoundingBox::
contains_other(const BoundingVolume *other) const {
return other->contains_box(this);
}
////////////////////////////////////////////////////////////////////
// Function: BoundingBox::extend_by_point
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
bool BoundingBox::
extend_by_point(const LPoint3f &point) {
nassertr(!point.is_nan(), false);
if (is_empty()) {
_min = point;
_max = point;
_flags = 0;
} else if (!is_infinite()) {
_min.set(min(_min[0], point[0]), min(_min[1], point[1]), min(_min[2], point[2]));
_max.set(max(_max[0], point[0]), max(_max[1], point[1]), max(_max[2], point[2]));
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: BoundingBox::extend_by_sphere
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
bool BoundingBox::
extend_by_sphere(const BoundingSphere *sphere) {
return extend_by_finite(sphere);
}
////////////////////////////////////////////////////////////////////
// Function: BoundingBox::extend_by_box
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
bool BoundingBox::
extend_by_box(const BoundingBox *box) {
nassertr(!box->is_empty() && !box->is_infinite(), false);
nassertr(!is_infinite(), false);
if (is_empty()) {
_min = box->_min;
_max = box->_max;
_flags = 0;
} else {
_min.set(min(_min[0], box->_min[0]),
min(_min[1], box->_min[1]),
min(_min[2], box->_min[2]));
_max.set(max(_max[0], box->_max[0]),
max(_max[1], box->_max[1]),
max(_max[2], box->_max[2]));
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: BoundingBox::extend_by_hexahedron
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
bool BoundingBox::
extend_by_hexahedron(const BoundingHexahedron *hexahedron) {
return extend_by_finite(hexahedron);
}
////////////////////////////////////////////////////////////////////
// Function: BoundingBox::extend_by_finite
// Access: Protected
// Description:
////////////////////////////////////////////////////////////////////
bool BoundingBox::
extend_by_finite(const FiniteBoundingVolume *volume) {
nassertr(!volume->is_empty(), false);
LVector3f min1 = volume->get_min();
LVector3f max1 = volume->get_max();
if (is_empty()) {
_min = min1;
_max = max1;
_flags = 0;
} else {
_min.set(min(_min[0], min1[0]),
min(_min[1], min1[1]),
min(_min[2], min1[2]));
_max.set(max(_max[0], max1[0]),
max(_max[1], max1[1]),
max(_max[2], max1[2]));
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: BoundingBox::around_points
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
bool BoundingBox::
around_points(const LPoint3f *first, const LPoint3f *last) {
nassertr(first != last, false);
// Get the minmax of all the points to construct a bounding box.
const LPoint3f *p = first;
#ifndef NDEBUG
// Skip any NaN points.
int skipped_nan = 0;
while (p != last && (*p).is_nan()) {
++p;
++skipped_nan;
}
if (p == last) {
mathutil_cat.warning()
<< "BoundingBox around NaN\n";
return false;
}
#endif
_min = *p;
_max = *p;
++p;
#ifndef NDEBUG
// Skip more NaN points.
while (p != last && (*p).is_nan()) {
++p;
++skipped_nan;
}
#endif
while (p != last) {
#ifndef NDEBUG
// Skip more NaN points.
if ((*p).is_nan()) {
++skipped_nan;
} else
#endif
{
_min.set(min(_min[0], (*p)[0]),
min(_min[1], (*p)[1]),
min(_min[2], (*p)[2]));
_max.set(max(_max[0], (*p)[0]),
max(_max[1], (*p)[1]),
max(_max[2], (*p)[2]));
}
++p;
}
#ifndef NDEBUG
if (skipped_nan != 0) {
mathutil_cat.warning()
<< "BoundingBox ignored " << skipped_nan << " NaN points of "
<< (last - first) << " total.\n";
}
#endif
_flags = 0;
return true;
}
////////////////////////////////////////////////////////////////////
// Function: BoundingBox::around_spheres
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
bool BoundingBox::
around_spheres(const BoundingVolume **first,
const BoundingVolume **last) {
return around_finite(first, last);
}
////////////////////////////////////////////////////////////////////
// Function: BoundingBox::around_boxes
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
bool BoundingBox::
around_boxes(const BoundingVolume **first,
const BoundingVolume **last) {
return around_finite(first, last);
}
////////////////////////////////////////////////////////////////////
// Function: BoundingBox::around_hexahedrons
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
bool BoundingBox::
around_hexahedrons(const BoundingVolume **first,
const BoundingVolume **last) {
return around_finite(first, last);
}
////////////////////////////////////////////////////////////////////
// Function: BoundingBox::around_finite
// Access: Protected
// Description:
////////////////////////////////////////////////////////////////////
bool BoundingBox::
around_finite(const BoundingVolume **first,
const BoundingVolume **last) {
nassertr(first != last, false);
// We're given a set of bounding volumes, at least the first one of
// which is guaranteed to be finite and nonempty. Some others may
// not be.
// First, get the box of all the points to construct a bounding
// box.
const BoundingVolume **p = first;
nassertr(!(*p)->is_empty() && !(*p)->is_infinite(), false);
const FiniteBoundingVolume *vol = DCAST(FiniteBoundingVolume, *p);
_min = vol->get_min();
_max = vol->get_max();
for (++p; p != last; ++p) {
nassertr(!(*p)->is_infinite(), false);
if (!(*p)->is_empty()) {
const FiniteBoundingVolume *vol = DCAST(FiniteBoundingVolume, *p);
LPoint3f min1 = vol->get_min();
LPoint3f max1 = vol->get_max();
_min.set(min(_min[0], min1[0]),
min(_min[1], min1[1]),
min(_min[2], min1[2]));
_max.set(max(_max[0], max1[0]),
max(_max[1], max1[1]),
max(_max[2], max1[2]));
}
}
_flags = 0;
return true;
}
////////////////////////////////////////////////////////////////////
// Function: BoundingBox::contains_point
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
int BoundingBox::
contains_point(const LPoint3f &point) const {
nassertr(!point.is_nan(), IF_no_intersection);
if (is_empty()) {
return IF_no_intersection;
} else if (is_infinite()) {
return IF_possible | IF_some | IF_all;
} else {
if (point[0] >= _min[0] && point[0] <= _max[0] &&
point[1] >= _min[1] && point[1] <= _max[1] &&
point[2] >= _min[2] && point[2] <= _max[2]) {
return IF_possible | IF_some | IF_all;
} else {
return IF_no_intersection;
}
}
}
////////////////////////////////////////////////////////////////////
// Function: BoundingBox::contains_lineseg
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
int BoundingBox::
contains_lineseg(const LPoint3f &a, const LPoint3f &b) const {
nassertr(!a.is_nan() && !b.is_nan(), IF_no_intersection);
if (a == b) {
return contains_point(a);
}
if (is_empty()) {
return IF_no_intersection;
} else if (is_infinite()) {
return IF_possible | IF_some | IF_all;
} else {
// Set a bit for each plane a and b are on the wrong side of.
unsigned int a_bits = 0;
if (a[0] < _min[0]) {
a_bits |= 0x01;
} else if (a[0] > _max[0]) {
a_bits |= 0x02;
}
if (a[1] < _min[1]) {
a_bits |= 0x04;
} else if (a[1] > _max[1]) {
a_bits |= 0x08;
}
if (a[2] < _min[2]) {
a_bits |= 0x10;
} else if (a[2] > _max[2]) {
a_bits |= 0x20;
}
unsigned int b_bits = 0;
if (b[0] < _min[0]) {
b_bits |= 0x01;
} else if (b[0] > _max[0]) {
b_bits |= 0x02;
}
if (b[1] < _min[1]) {
b_bits |= 0x04;
} else if (b[1] > _max[1]) {
b_bits |= 0x08;
}
if (b[2] < _min[2]) {
b_bits |= 0x10;
} else if (b[2] > _max[2]) {
b_bits |= 0x20;
}
if ((a_bits & b_bits) != 0) {
// If there are any bits in common, the segment is wholly
// outside the box (both points are on the wrong side of the
// same plane).
return IF_no_intersection;
} else if ((a_bits | b_bits) == 0) {
// If there are no bits at all, the segment is wholly within the
// box.
return IF_possible | IF_some | IF_all;
} else if (a_bits == 0 || b_bits == 0) {
// If either point is within the box, the segment is partially
// within the box.
return IF_possible | IF_some;
} else {
unsigned int differ = (a_bits ^ b_bits);
if (differ == 0x03 || differ == 0x0c || differ == 0x30) {
// If the line segment stretches straight across the box, the
// segment is partially within.
return IF_possible | IF_some;
} else {
// Otherwise, it's hard to tell whether it does or doesn't.
return IF_possible;
}
}
}
}
////////////////////////////////////////////////////////////////////
// Function: BoundingBox::contains_sphere
// Access: Protected, Virtual
// Description: Double-dispatch support: called by contains_other()
// when the type we're testing for intersection is known
// to be a sphere.
////////////////////////////////////////////////////////////////////
int BoundingBox::
contains_sphere(const BoundingSphere *sphere) const {
return contains_finite(sphere);
}
////////////////////////////////////////////////////////////////////
// Function: BoundingBox::contains_box
// Access: Protected, Virtual
// Description: Double-dispatch support: called by contains_other()
// when the type we're testing for intersection is known
// to be a box.
////////////////////////////////////////////////////////////////////
int BoundingBox::
contains_box(const BoundingBox *box) const {
nassertr(!is_empty() && !is_infinite(), 0);
nassertr(!box->is_empty() && !box->is_infinite(), 0);
const LPoint3f &min1 = box->get_minq();
const LPoint3f &max1 = box->get_maxq();
if (min1[0] >= _min[0] && max1[0] <= _max[0] &&
min1[1] >= _min[1] && max1[1] <= _max[1] &&
min1[2] >= _min[2] && max1[2] <= _max[2]) {
// The other volume is completely within this volume.
return IF_possible | IF_some | IF_all;
} else if (max1[0] >= _min[0] && min1[0] <= _max[0] &&
max1[1] >= _min[1] && min1[1] <= _max[1] &&
max1[2] >= _min[2] && min1[2] <= _max[2]) {
// The other volume is partially within this volume.
return IF_possible;
} else {
// The other volume is not within this volume.
return IF_no_intersection;
}
}
////////////////////////////////////////////////////////////////////
// Function: BoundingBox::contains_hexahedron
// Access: Protected, Virtual
// Description: Double-dispatch support: called by contains_other()
// when the type we're testing for intersection is known
// to be a hexahedron.
////////////////////////////////////////////////////////////////////
int BoundingBox::
contains_hexahedron(const BoundingHexahedron *hexahedron) const {
return contains_finite(hexahedron);
}
////////////////////////////////////////////////////////////////////
// Function: BoundingBox::contains_line
// Access: Protected, Virtual
// Description: Double-dispatch support: called by contains_other()
// when the type we're testing for intersection is known
// to be a line.
////////////////////////////////////////////////////////////////////
int BoundingBox::
contains_line(const BoundingLine *line) const {
return line->contains_box(this) & ~IF_all;
}
////////////////////////////////////////////////////////////////////
// Function: BoundingBox::contains_plane
// Access: Protected, Virtual
// Description: Double-dispatch support: called by contains_other()
// when the type we're testing for intersection is known
// to be a plane.
////////////////////////////////////////////////////////////////////
int BoundingBox::
contains_plane(const BoundingPlane *plane) const {
return plane->contains_box(this) & ~IF_all;
}
////////////////////////////////////////////////////////////////////
// Function: BoundingBox::contains_finite
// Access: Protected
// Description:
////////////////////////////////////////////////////////////////////
int BoundingBox::
contains_finite(const FiniteBoundingVolume *volume) const {
nassertr(!is_empty() && !is_infinite(), 0);
nassertr(!volume->is_empty() && !volume->is_infinite(), 0);
LPoint3f min1 = volume->get_min();
LPoint3f max1 = volume->get_max();
if (min1[0] >= _min[0] && max1[0] <= _max[0] &&
min1[1] >= _min[1] && max1[1] <= _max[1] &&
min1[2] >= _min[2] && max1[2] <= _max[2]) {
// The other volume is completely within this volume.
return IF_possible | IF_some | IF_all;
} else if (max1[0] >= _min[0] && min1[0] <= _max[0] &&
max1[1] >= _min[1] && min1[1] <= _max[1] &&
max1[2] >= _min[2] && min1[2] <= _max[2]) {
// The other volume is partially within this volume.
return IF_possible;
} else {
// The other volume is not within this volume.
return IF_no_intersection;
}
}

View File

@ -0,0 +1,126 @@
// Filename: boundingBox.h
// Created by: drose (31May07)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifndef BOUNDINGBOX_H
#define BOUNDINGBOX_H
#include "pandabase.h"
#include "finiteBoundingVolume.h"
#include "plane.h"
////////////////////////////////////////////////////////////////////
// Class : BoundingBox
// Description : An axis-aligned bounding box; that is, a minimum and
// maximum coordinate triple.
//
// This box is always axis-aligned. If you need a more
// general bounding box, try BoundingHexahedron.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA BoundingBox : public FiniteBoundingVolume {
PUBLISHED:
INLINE_MATHUTIL BoundingBox();
INLINE_MATHUTIL BoundingBox(const LPoint3f &min, const LPoint3f &max);
ALLOC_DELETED_CHAIN(BoundingBox);
public:
virtual BoundingVolume *make_copy() const;
virtual LPoint3f get_min() const;
virtual LPoint3f get_max() const;
virtual float get_volume() const;
virtual LPoint3f get_approx_center() const;
virtual void xform(const LMatrix4f &mat);
virtual void output(ostream &out) const;
PUBLISHED:
INLINE_MATHUTIL int get_num_points() const;
INLINE_MATHUTIL LPoint3f get_point(int n) const;
INLINE_MATHUTIL int get_num_planes() const;
INLINE_MATHUTIL Planef get_plane(int n) const;
public:
// Inline accessors for speed.
INLINE_MATHUTIL const LPoint3f &get_minq() const;
INLINE_MATHUTIL const LPoint3f &get_maxq() const;
protected:
virtual bool extend_other(BoundingVolume *other) const;
virtual bool around_other(BoundingVolume *other,
const BoundingVolume **first,
const BoundingVolume **last) const;
virtual int contains_other(const BoundingVolume *other) const;
virtual bool extend_by_point(const LPoint3f &point);
virtual bool extend_by_sphere(const BoundingSphere *sphere);
virtual bool extend_by_box(const BoundingBox *box);
virtual bool extend_by_hexahedron(const BoundingHexahedron *hexahedron);
bool extend_by_finite(const FiniteBoundingVolume *volume);
virtual bool around_points(const LPoint3f *first,
const LPoint3f *last);
virtual bool around_spheres(const BoundingVolume **first,
const BoundingVolume **last);
virtual bool around_boxes(const BoundingVolume **first,
const BoundingVolume **last);
virtual bool around_hexahedrons(const BoundingVolume **first,
const BoundingVolume **last);
bool around_finite(const BoundingVolume **first,
const BoundingVolume **last);
virtual int contains_point(const LPoint3f &point) const;
virtual int contains_lineseg(const LPoint3f &a, const LPoint3f &b) const;
virtual int contains_hexahedron(const BoundingHexahedron *hexahedron) const;
virtual int contains_sphere(const BoundingSphere *sphere) const;
virtual int contains_box(const BoundingBox *box) const;
virtual int contains_line(const BoundingLine *line) const;
virtual int contains_plane(const BoundingPlane *plane) const;
int contains_finite(const FiniteBoundingVolume *volume) const;
private:
LPoint3f _min;
LPoint3f _max;
static const int plane_def[6][3];
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
FiniteBoundingVolume::init_type();
register_type(_type_handle, "BoundingBox",
FiniteBoundingVolume::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
friend class BoundingSphere;
};
#include "boundingBox.I"
#endif

View File

@ -16,26 +16,52 @@
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: BoundingHexahedron::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE_MATHUTIL BoundingHexahedron::
BoundingHexahedron() {
}
////////////////////////////////////////////////////////////////////
// Function: BoundingHexahedron::get_num_points
// Access: Published
// Description: Returns 8: the number of vertices of a hexahedron.
////////////////////////////////////////////////////////////////////
INLINE_MATHUTIL int BoundingHexahedron::
get_num_points() const {
return num_points;
}
////////////////////////////////////////////////////////////////////
// Function: BoundingHexahedron::get_point
// Access: Published
// Description: Returns the nth vertex of the hexahedron.
////////////////////////////////////////////////////////////////////
INLINE_MATHUTIL LPoint3f BoundingHexahedron::
get_point(int n) const {
nassertr(n >= 0 && n < num_points, LPoint3f(0.0f, 0.0f, 0.0f));
nassertr(n >= 0 && n < num_points, LPoint3f::zero());
return _points[n];
}
////////////////////////////////////////////////////////////////////
// Function: BoundingHexahedron::get_num_planes
// Access: Published
// Description: Returns 6: the number of faces of a hexahedron.
////////////////////////////////////////////////////////////////////
INLINE_MATHUTIL int BoundingHexahedron::
get_num_planes() const {
return num_planes;
}
////////////////////////////////////////////////////////////////////
// Function: BoundingHexahedron::get_plane
// Access: Published
// Description: Returns the nth face of the hexahedron.
////////////////////////////////////////////////////////////////////
INLINE_MATHUTIL Planef BoundingHexahedron::
get_plane(int n) const {
nassertr(n >= 0 && n < num_planes, Planef());

View File

@ -18,6 +18,7 @@
#include "boundingHexahedron.h"
#include "boundingSphere.h"
#include "boundingBox.h"
#include "config_mathutil.h"
#include <math.h>
@ -25,6 +26,11 @@
TypeHandle BoundingHexahedron::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: BoundingHexahedron::Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
BoundingHexahedron::
BoundingHexahedron(const Frustumf &frustum, bool is_ortho,
CoordinateSystem cs) {
@ -60,6 +66,11 @@ BoundingHexahedron(const Frustumf &frustum, bool is_ortho,
}
}
////////////////////////////////////////////////////////////////////
// Function: BoundingHexahedron::Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
BoundingHexahedron::
BoundingHexahedron(const LPoint3f &fll, const LPoint3f &flr,
const LPoint3f &fur, const LPoint3f &ful,
@ -79,11 +90,21 @@ BoundingHexahedron(const LPoint3f &fll, const LPoint3f &flr,
set_planes();
}
////////////////////////////////////////////////////////////////////
// Function: BoundingHexahedron::make_copy
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
BoundingVolume *BoundingHexahedron::
make_copy() const {
return new BoundingHexahedron(*this);
}
////////////////////////////////////////////////////////////////////
// Function: BoundingHexahedron::get_min
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
LPoint3f BoundingHexahedron::
get_min() const {
nassertr(!is_empty(), LPoint3f(0.0f, 0.0f, 0.0f));
@ -98,6 +119,11 @@ get_min() const {
return m;
}
////////////////////////////////////////////////////////////////////
// Function: BoundingHexahedron::get_max
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
LPoint3f BoundingHexahedron::
get_max() const {
nassertr(!is_empty(), LPoint3f(0.0f, 0.0f, 0.0f));
@ -112,6 +138,11 @@ get_max() const {
return m;
}
////////////////////////////////////////////////////////////////////
// Function: BoundingHexahedron::get_approx_center
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
LPoint3f BoundingHexahedron::
get_approx_center() const {
nassertr(!is_empty(), LPoint3f(0.0f, 0.0f, 0.0f));
@ -119,6 +150,11 @@ get_approx_center() const {
return _centroid;
}
////////////////////////////////////////////////////////////////////
// Function: BoundingHexahedron::xform
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void BoundingHexahedron::
xform(const LMatrix4f &mat) {
if (!is_empty() && !is_infinite()) {
@ -130,6 +166,11 @@ xform(const LMatrix4f &mat) {
}
}
////////////////////////////////////////////////////////////////////
// Function: BoundingHexahedron::output
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void BoundingHexahedron::
output(ostream &out) const {
if (is_empty()) {
@ -141,6 +182,11 @@ output(ostream &out) const {
}
}
////////////////////////////////////////////////////////////////////
// Function: BoundingHexahedron::write
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void BoundingHexahedron::
write(ostream &out, int indent_level) const {
if (is_empty()) {
@ -158,11 +204,21 @@ write(ostream &out, int indent_level) const {
}
}
////////////////////////////////////////////////////////////////////
// Function: BoundingHexahedron::extend_other
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
bool BoundingHexahedron::
extend_other(BoundingVolume *other) const {
return other->extend_by_hexahedron(this);
}
////////////////////////////////////////////////////////////////////
// Function: BoundingHexahedron::around_other
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
bool BoundingHexahedron::
around_other(BoundingVolume *other,
const BoundingVolume **first,
@ -170,56 +226,21 @@ around_other(BoundingVolume *other,
return other->around_hexahedrons(first, last);
}
////////////////////////////////////////////////////////////////////
// Function: BoundingHexahedron::contains_other
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
int BoundingHexahedron::
contains_other(const BoundingVolume *other) const {
return other->contains_hexahedron(this);
}
bool BoundingHexahedron::
extend_by_point(const LPoint3f &) {
mathutil_cat.error()
<< "BoundingHexahedron::extend_by_point() called\n";
return false;
}
bool BoundingHexahedron::
extend_by_sphere(const BoundingSphere *) {
mathutil_cat.error()
<< "BoundingHexahedron::extend_by_sphere() called\n";
return false;
}
bool BoundingHexahedron::
extend_by_hexahedron(const BoundingHexahedron *) {
mathutil_cat.error()
<< "BoundingHexahedron::extend_by_hexahedron() called\n";
return false;
}
bool BoundingHexahedron::
around_points(const LPoint3f *, const LPoint3f *) {
mathutil_cat.error()
<< "BoundingHexahedron::around_points() called\n";
return false;
}
bool BoundingHexahedron::
around_spheres(const BoundingVolume **,
const BoundingVolume **) {
mathutil_cat.error()
<< "BoundingHexahedron::around_spheres() called\n";
return false;
}
bool BoundingHexahedron::
around_hexahedrons(const BoundingVolume **,
const BoundingVolume **) {
mathutil_cat.error()
<< "BoundingHexahedron::around_hexahedrons() called\n";
return false;
}
////////////////////////////////////////////////////////////////////
// Function: BoundingHexahedron::contains_point
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
int BoundingHexahedron::
contains_point(const LPoint3f &point) const {
if (is_empty()) {
@ -241,6 +262,11 @@ contains_point(const LPoint3f &point) const {
}
}
////////////////////////////////////////////////////////////////////
// Function: BoundingHexahedron::contains_lineseg
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
int BoundingHexahedron::
contains_lineseg(const LPoint3f &a, const LPoint3f &b) const {
if (is_empty()) {
@ -267,6 +293,11 @@ contains_lineseg(const LPoint3f &a, const LPoint3f &b) const {
}
}
////////////////////////////////////////////////////////////////////
// Function: BoundingHexahedron::contains_sphere
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
int BoundingHexahedron::
contains_sphere(const BoundingSphere *sphere) const {
nassertr(!is_empty(), 0);
@ -297,37 +328,111 @@ contains_sphere(const BoundingSphere *sphere) const {
return result;
}
////////////////////////////////////////////////////////////////////
// Function: BoundingHexahedron::contains_box
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
int BoundingHexahedron::
contains_hexahedron(const BoundingHexahedron *hexahedron) const {
contains_box(const BoundingBox *box) const {
nassertr(!is_empty(), 0);
nassertr(!hexahedron->is_empty(), 0);
nassertr(!box->is_empty(), 0);
// Check minmax.
LPoint3f min1 = get_min();
LPoint3f min2 = hexahedron->get_min();
LPoint3f max1 = get_max();
LPoint3f max2 = hexahedron->get_max();
// Put the box inside a sphere for the purpose of this test.
const LPoint3f &min = box->get_minq();
const LPoint3f &max = box->get_maxq();
LPoint3f center = (min + max) * 0.5f;
float radius2 = (max - center).length_squared();
if (min1[0] > max2[0] || min1[1] > max2[1] || min1[2] > max2[2] ||
min2[0] > max1[0] || min2[1] > max1[1] || min2[2] > max1[2] ||
max1[0] < min2[0] || max1[1] < min2[1] || max1[2] < min2[2] ||
max2[0] < min1[0] || max2[1] < min1[1] || max2[2] < min1[2]) {
return IF_no_intersection;
}
int result = IF_possible | IF_some | IF_all;
int result = IF_possible | IF_all;
for (int i = 0; i < num_planes; i++) {
const Planef &p = _planes[i];
float dist = p.dist_to_plane(center);
float dist2 = dist * dist;
for (int i = 0; i < num_points; i++) {
if (contains_point(hexahedron->_points[i])) {
result |= IF_some;
} else {
result &= ~IF_all;
if (dist >= 0.0f && dist2 > radius2) {
// The sphere is completely in front of this plane; it's thus
// completely outside of the hexahedron.
return IF_no_intersection;
} else if (dist < 0.0f && dist2 < radius2) {
// The sphere is not completely behind this plane, but some of
// it is.
// Look a little closer.
bool all_in = true;
for (int i = 0; i < 8 && all_in; ++i) {
if (p.dist_to_plane(box->get_point(i)) < 0.0f) {
// This point is outside the plane.
all_in = false;
}
}
if (!all_in) {
result &= ~IF_all;
}
}
}
return result;
}
////////////////////////////////////////////////////////////////////
// Function: BoundingHexahedron::contains_hexahedron
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
int BoundingHexahedron::
contains_hexahedron(const BoundingHexahedron *hexahedron) const {
nassertr(!is_empty(), 0);
nassertr(!hexahedron->is_empty(), 0);
// Put the hexahedron inside a sphere for the purposes of this test.
LPoint3f min = hexahedron->get_min();
LPoint3f max = hexahedron->get_max();
LPoint3f center = (min + max) * 0.5f;
float radius2 = (max - center).length_squared();
int result = IF_possible | IF_some | IF_all;
for (int i = 0; i < num_planes; i++) {
const Planef &p = _planes[i];
float dist = p.dist_to_plane(center);
float dist2 = dist * dist;
if (dist >= 0.0f && dist2 > radius2) {
// The sphere is completely in front of this plane; it's thus
// completely outside of the hexahedron.
return IF_no_intersection;
} else if (dist < 0.0f && dist2 < radius2) {
// The sphere is not completely behind this plane, but some of
// it is.
// Look a little closer.
bool all_in = true;
for (int i = 0; i < 8 && all_in; ++i) {
if (p.dist_to_plane(hexahedron->get_point(i)) < 0.0f) {
// This point is outside the plane.
all_in = false;
}
}
if (!all_in) {
result &= ~IF_all;
}
}
}
return result;
}
////////////////////////////////////////////////////////////////////
// Function: BoundingHexahedron::set_planes
// Access: Private
// Description:
////////////////////////////////////////////////////////////////////
void BoundingHexahedron::
set_planes() {
_planes[0] = Planef(_points[0], _points[3], _points[2]);
@ -358,6 +463,11 @@ set_planes() {
}
}
////////////////////////////////////////////////////////////////////
// Function: BoundingHexahedron::set_centroid
// Access: Private
// Description:
////////////////////////////////////////////////////////////////////
void BoundingHexahedron::
set_centroid() {
LPoint3f net = _points[0];

View File

@ -32,21 +32,24 @@
// Class : BoundingHexahedron
// Description : This defines a bounding convex hexahedron. It is
// typically used to represent a frustum, but may
// represent any enclosing convex hexahedron.
//
// This class does not support any of the around() or
// extend_by() functions, but all other functionality
// should be well-defined.
// represent any enclosing convex hexahedron, including
// simple boxes. However, if all you want is an
// axis-aligned bounding box, you may be better off with
// the simpler BoundingBox class.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA BoundingHexahedron : public FiniteBoundingVolume {
public:
INLINE_MATHUTIL BoundingHexahedron();
PUBLISHED:
BoundingHexahedron(const Frustumf &frustum, bool is_ortho,
CoordinateSystem cs = CS_default);
BoundingHexahedron(const LPoint3f &fll, const LPoint3f &flr,
const LPoint3f &fur, const LPoint3f &ful,
const LPoint3f &nll, const LPoint3f &nlr,
const LPoint3f &nur, const LPoint3f &nul);
public:
ALLOC_DELETED_CHAIN(BoundingHexahedron);
virtual BoundingVolume *make_copy() const;
@ -59,6 +62,7 @@ public:
virtual void output(ostream &out) const;
virtual void write(ostream &out, int indent_level = 0) const;
PUBLISHED:
INLINE_MATHUTIL int get_num_points() const;
INLINE_MATHUTIL LPoint3f get_point(int n) const;
INLINE_MATHUTIL int get_num_planes() const;
@ -71,21 +75,10 @@ protected:
const BoundingVolume **last) const;
virtual int contains_other(const BoundingVolume *other) const;
virtual bool extend_by_point(const LPoint3f &point);
virtual bool extend_by_sphere(const BoundingSphere *sphere);
virtual bool extend_by_hexahedron(const BoundingHexahedron *hexahedron);
virtual bool around_points(const LPoint3f *first,
const LPoint3f *last);
virtual bool around_spheres(const BoundingVolume **first,
const BoundingVolume **last);
virtual bool around_hexahedrons(const BoundingVolume **first,
const BoundingVolume **last);
virtual int contains_point(const LPoint3f &point) const;
virtual int contains_lineseg(const LPoint3f &a, const LPoint3f &b) const;
virtual int contains_sphere(const BoundingSphere *sphere) const;
virtual int contains_box(const BoundingBox *box) const;
virtual int contains_hexahedron(const BoundingHexahedron *hexahedron) const;
private:

View File

@ -16,10 +16,21 @@
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: BoundingLine::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE_MATHUTIL BoundingLine::
BoundingLine() {
}
////////////////////////////////////////////////////////////////////
// Function: BoundingLine::Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE_MATHUTIL BoundingLine::
BoundingLine(const LPoint3f &a, const LPoint3f &b) :
_origin(a), _vector(b - a)
@ -31,6 +42,11 @@ BoundingLine(const LPoint3f &a, const LPoint3f &b) :
}
}
////////////////////////////////////////////////////////////////////
// Function: BoundingLine::get_point_a
// Access: Published
// Description: Returns the first point that defines the line.
////////////////////////////////////////////////////////////////////
INLINE_MATHUTIL const LPoint3f &BoundingLine::
get_point_a() const {
nassertr(!is_empty(), _origin);
@ -38,6 +54,11 @@ get_point_a() const {
return _origin;
}
////////////////////////////////////////////////////////////////////
// Function: BoundingLine::get_point_b
// Access: Published
// Description: Returns the second point that defines the line.
////////////////////////////////////////////////////////////////////
INLINE_MATHUTIL LPoint3f BoundingLine::
get_point_b() const {
nassertr(!is_empty(), _origin);

View File

@ -24,11 +24,21 @@
TypeHandle BoundingLine::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: BoundingLine::make_copy
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
BoundingVolume *BoundingLine::
make_copy() const {
return new BoundingLine(*this);
}
////////////////////////////////////////////////////////////////////
// Function: BoundingLine::get_approx_center
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
LPoint3f BoundingLine::
get_approx_center() const {
nassertr(!is_empty(), LPoint3f(0.0f, 0.0f, 0.0f));
@ -36,6 +46,11 @@ get_approx_center() const {
return (get_point_a() + get_point_b()) / 2.0;
}
////////////////////////////////////////////////////////////////////
// Function: BoundingLine::xform
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void BoundingLine::
xform(const LMatrix4f &mat) {
nassertv(!mat.is_nan());
@ -51,6 +66,11 @@ xform(const LMatrix4f &mat) {
}
}
////////////////////////////////////////////////////////////////////
// Function: BoundingLine::output
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void BoundingLine::
output(ostream &out) const {
if (is_empty()) {
@ -62,11 +82,21 @@ output(ostream &out) const {
}
}
////////////////////////////////////////////////////////////////////
// Function: BoundingLine::extend_other
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
bool BoundingLine::
extend_other(BoundingVolume *other) const {
return other->extend_by_line(this);
}
////////////////////////////////////////////////////////////////////
// Function: BoundingLine::around_other
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
bool BoundingLine::
around_other(BoundingVolume *other,
const BoundingVolume **first,
@ -74,12 +104,21 @@ around_other(BoundingVolume *other,
return other->around_lines(first, last);
}
////////////////////////////////////////////////////////////////////
// Function: BoundingLine::contains_other
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
int BoundingLine::
contains_other(const BoundingVolume *other) const {
return other->contains_line(this);
}
////////////////////////////////////////////////////////////////////
// Function: BoundingLine::extend_by_line
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
bool BoundingLine::
extend_by_line(const BoundingLine *line) {
nassertr(!line->is_empty() && !line->is_infinite(), false);
@ -95,6 +134,11 @@ extend_by_line(const BoundingLine *line) {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: BoundingLine::contains_sphere
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
int BoundingLine::
contains_sphere(const BoundingSphere *sphere) const {
nassertr(!is_empty() && !is_infinite(), 0);
@ -109,6 +153,31 @@ contains_sphere(const BoundingSphere *sphere) const {
}
}
////////////////////////////////////////////////////////////////////
// Function: BoundingLine::contains_box
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
int BoundingLine::
contains_box(const BoundingBox *box) const {
nassertr(!is_empty() && !is_infinite(), 0);
nassertr(!box->is_empty() && !box->is_infinite(), 0);
LPoint3f center = (box->get_minq() + box->get_maxq()) * 0.5f;
float r2 = (box->get_maxq() - box->get_minq()).length_squared() * 0.25f;
if (r2 >= sqr_dist_to_line(center)) {
return IF_possible;
} else {
return IF_no_intersection;
}
}
////////////////////////////////////////////////////////////////////
// Function: BoundingLine::sqr_dist_to_line
// Access: Protected
// Description:
////////////////////////////////////////////////////////////////////
float BoundingLine::
sqr_dist_to_line(const LPoint3f &point) const {
nassertr(!point.is_nan(), 0.0f);

View File

@ -35,8 +35,10 @@
// arbitrary points on the line.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA BoundingLine : public GeometricBoundingVolume {
PUBLISHED:
public:
INLINE_MATHUTIL BoundingLine();
PUBLISHED:
INLINE_MATHUTIL BoundingLine(const LPoint3f &a, const LPoint3f &b);
ALLOC_DELETED_CHAIN(BoundingLine);
@ -62,6 +64,7 @@ protected:
virtual bool extend_by_line(const BoundingLine *line);
virtual int contains_sphere(const BoundingSphere *sphere) const;
virtual int contains_box(const BoundingBox *box) const;
float sqr_dist_to_line(const LPoint3f &point) const;
@ -88,6 +91,7 @@ private:
static TypeHandle _type_handle;
friend class BoundingSphere;
friend class BoundingBox;
};
#include "boundingLine.I"

View File

@ -151,3 +151,50 @@ contains_sphere(const BoundingSphere *sphere) const {
return IF_no_intersection;
}
}
////////////////////////////////////////////////////////////////////
// Function: BoundingPlane::contains_box
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
int BoundingPlane::
contains_box(const BoundingBox *box) const {
nassertr(!is_empty() && !is_infinite(), 0);
nassertr(!box->is_empty() && !box->is_infinite(), 0);
// Put the box inside a sphere for the purpose of this test.
const LPoint3f &min = box->get_minq();
const LPoint3f &max = box->get_maxq();
LPoint3f center = (min + max) * 0.5f;
float radius2 = (max - center).length_squared();
int result = IF_possible | IF_some | IF_all;
float dist = _plane.dist_to_plane(center);
float dist2 = dist * dist;
if (dist >= 0.0f && dist2 > radius2) {
// The sphere is completely in front of this plane; it's thus
// completely outside of the hexahedron.
return IF_no_intersection;
} else if (dist < 0.0f && dist2 < radius2) {
// The sphere is not completely behind this plane, but some of
// it is.
// Look a little closer.
bool all_in = true;
for (int i = 0; i < 8 && all_in; ++i) {
if (_plane.dist_to_plane(box->get_point(i)) < 0.0f) {
// This point is outside the plane.
all_in = false;
}
}
if (!all_in) {
result &= ~IF_all;
}
}
return result;
}

View File

@ -59,6 +59,7 @@ protected:
virtual bool extend_by_plane(const BoundingPlane *plane);
virtual int contains_sphere(const BoundingSphere *sphere) const;
virtual int contains_box(const BoundingBox *box) const;
private:
Planef _plane;
@ -81,6 +82,7 @@ private:
static TypeHandle _type_handle;
friend class BoundingSphere;
friend class BoundingBox;
};
#include "boundingPlane.I"

View File

@ -16,10 +16,21 @@
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: BoundingSphere::Constructor
// Access: Published
// Description: Constructs an empty sphere.
////////////////////////////////////////////////////////////////////
INLINE_MATHUTIL BoundingSphere::
BoundingSphere() {
}
////////////////////////////////////////////////////////////////////
// Function: BoundingSphere::Constructor
// Access: Published
// Description: Constructs a specific sphere.
////////////////////////////////////////////////////////////////////
INLINE_MATHUTIL BoundingSphere::
BoundingSphere(const LPoint3f &center, float radius) :
_center(center), _radius(radius)
@ -30,6 +41,11 @@ BoundingSphere(const LPoint3f &center, float radius) :
}
}
////////////////////////////////////////////////////////////////////
// Function: BoundingSphere::get_center
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE_MATHUTIL const LPoint3f &BoundingSphere::
get_center() const {
nassertr(!is_empty(), _center);
@ -37,6 +53,11 @@ get_center() const {
return _center;
}
////////////////////////////////////////////////////////////////////
// Function: BoundingSphere::get_radius
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE_MATHUTIL float BoundingSphere::
get_radius() const {
nassertr(!is_empty(), 0.0f);

View File

@ -17,6 +17,7 @@
////////////////////////////////////////////////////////////////////
#include "boundingSphere.h"
#include "boundingBox.h"
#include "boundingHexahedron.h"
#include "boundingLine.h"
#include "boundingPlane.h"
@ -28,11 +29,21 @@
TypeHandle BoundingSphere::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: BoundingSphere::make_copy
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
BoundingVolume *BoundingSphere::
make_copy() const {
return new BoundingSphere(*this);
}
////////////////////////////////////////////////////////////////////
// Function: BoundingSphere::get_min
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
LPoint3f BoundingSphere::
get_min() const {
nassertr(!is_empty(), LPoint3f(0.0f, 0.0f, 0.0f));
@ -42,6 +53,11 @@ get_min() const {
_center[2] - _radius);
}
////////////////////////////////////////////////////////////////////
// Function: BoundingSphere::get_max
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
LPoint3f BoundingSphere::
get_max() const {
nassertr(!is_empty(), LPoint3f(0.0f, 0.0f, 0.0f));
@ -51,6 +67,27 @@ get_max() const {
_center[2] + _radius);
}
////////////////////////////////////////////////////////////////////
// Function: BoundingSphere::get_volume
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
float BoundingSphere::
get_volume() const {
nassertr(!is_infinite(), 0.0f);
if (is_empty()) {
return 0.0f;
}
// Volume of a sphere: four-thirds pi r cubed.
return 4.0f / 3.0f * MathNumbers::pi_f * _radius * _radius * _radius;
}
////////////////////////////////////////////////////////////////////
// Function: BoundingSphere::get_approx_center
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
LPoint3f BoundingSphere::
get_approx_center() const {
nassertr(!is_empty(), LPoint3f(0.0f, 0.0f, 0.0f));
@ -58,6 +95,11 @@ get_approx_center() const {
return get_center();
}
////////////////////////////////////////////////////////////////////
// Function: BoundingSphere::xform
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void BoundingSphere::
xform(const LMatrix4f &mat) {
nassertv(!mat.is_nan());
@ -99,6 +141,11 @@ xform(const LMatrix4f &mat) {
}
}
////////////////////////////////////////////////////////////////////
// Function: BoundingSphere::output
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void BoundingSphere::
output(ostream &out) const {
if (is_empty()) {
@ -110,11 +157,21 @@ output(ostream &out) const {
}
}
////////////////////////////////////////////////////////////////////
// Function: BoundingSphere::extend_other
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
bool BoundingSphere::
extend_other(BoundingVolume *other) const {
return other->extend_by_sphere(this);
}
////////////////////////////////////////////////////////////////////
// Function: BoundingSphere::around_other
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
bool BoundingSphere::
around_other(BoundingVolume *other,
const BoundingVolume **first,
@ -122,12 +179,22 @@ around_other(BoundingVolume *other,
return other->around_spheres(first, last);
}
////////////////////////////////////////////////////////////////////
// Function: BoundingSphere::contains_other
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
int BoundingSphere::
contains_other(const BoundingVolume *other) const {
return other->contains_sphere(this);
}
////////////////////////////////////////////////////////////////////
// Function: BoundingSphere::extend_by_point
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
bool BoundingSphere::
extend_by_point(const LPoint3f &point) {
nassertr(!point.is_nan(), false);
@ -146,6 +213,11 @@ extend_by_point(const LPoint3f &point) {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: BoundingSphere::extend_by_sphere
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
bool BoundingSphere::
extend_by_sphere(const BoundingSphere *sphere) {
nassertr(!sphere->is_empty() && !sphere->is_infinite(), false);
@ -163,39 +235,76 @@ extend_by_sphere(const BoundingSphere *sphere) {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: BoundingSphere::extend_by_box
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
bool BoundingSphere::
extend_by_hexahedron(const BoundingHexahedron *hexahedron) {
return extend_by_finite(hexahedron);
}
bool BoundingSphere::
extend_by_finite(const FiniteBoundingVolume *volume) {
nassertr(!volume->is_empty(), false);
LVector3f min1 = volume->get_min();
LVector3f max1 = volume->get_max();
extend_by_box(const BoundingBox *box) {
const LVector3f &min1 = box->get_minq();
const LVector3f &max1 = box->get_maxq();
if (is_empty()) {
_center = (min1 + max1) * 0.5f;
_radius = length(LVector3f(max1 - _center));
_flags = 0;
} else {
LVector3f v = max1 - _center;
float dist2 = dot(v, v);
if (dist2 > _radius * _radius) {
_radius = sqrtf(dist2);
} else {
// Find the minimum radius necessary to reach the corner.
float max_dist2 = -1.0;
for (int i = 0; i < 8; ++i) {
float dist2 = (box->get_point(i) - _center).length_squared();
if (dist2 > max_dist2) {
max_dist2 = dist2;
}
}
if (max_dist2 > _radius * _radius) {
_radius = csqrt(max_dist2);
}
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: BoundingSphere::extend_by_hexahedron
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
bool BoundingSphere::
extend_by_hexahedron(const BoundingHexahedron *hexahedron) {
nassertr(!hexahedron->is_empty(), false);
BoundingBox box(hexahedron->get_min(), hexahedron->get_max());
box.local_object();
return extend_by_box(&box);
}
////////////////////////////////////////////////////////////////////
// Function: BoundingSphere::extend_by_finite
// Access: Protected
// Description:
////////////////////////////////////////////////////////////////////
bool BoundingSphere::
extend_by_finite(const FiniteBoundingVolume *volume) {
nassertr(!volume->is_empty(), false);
BoundingBox box(volume->get_min(), volume->get_max());
box.local_object();
return extend_by_box(&box);
}
////////////////////////////////////////////////////////////////////
// Function: BoundingSphere::around_points
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
bool BoundingSphere::
around_points(const LPoint3f *first, const LPoint3f *last) {
nassertr(first != last, false);
// First, get the minmax of all the points to construct a bounding
// First, get the box of all the points to construct a bounding
// box.
const LPoint3f *p = first;
@ -279,42 +388,66 @@ around_points(const LPoint3f *first, const LPoint3f *last) {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: BoundingSphere::around_spheres
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
bool BoundingSphere::
around_spheres(const BoundingVolume **first,
const BoundingVolume **last) {
return around_finite(first, last);
}
////////////////////////////////////////////////////////////////////
// Function: BoundingSphere::around_boxes
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
bool BoundingSphere::
around_boxes(const BoundingVolume **first,
const BoundingVolume **last) {
return around_finite(first, last);
}
////////////////////////////////////////////////////////////////////
// Function: BoundingSphere::around_hexahedrons
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
bool BoundingSphere::
around_hexahedrons(const BoundingVolume **first,
const BoundingVolume **last) {
return around_finite(first, last);
}
////////////////////////////////////////////////////////////////////
// Function: BoundingSphere::around_finite
// Access: Protected
// Description:
////////////////////////////////////////////////////////////////////
bool BoundingSphere::
around_finite(const BoundingVolume **first,
const BoundingVolume **last) {
nassertr(first != last, false);
// We're given a set of bounding volumes, at least the first one of
// which is guaranteed to be finite and nonempty. Some others may
// not be.
// We're given a set of bounding volumes, all of which are finite,
// and at least the first one of which is guaranteed to be nonempty.
// Some others may not be.
// First, get the minmax of all the points to construct a bounding
// First, get the box of all the points to construct a bounding
// box.
const BoundingVolume **p = first;
nassertr(!(*p)->is_empty() && !(*p)->is_infinite(), false);
nassertr((*p)->is_of_type(FiniteBoundingVolume::get_class_type()), false);
const FiniteBoundingVolume *vol = DCAST(FiniteBoundingVolume, *p);
LPoint3f min_box = vol->get_min();
LPoint3f max_box = vol->get_max();
bool any_unknown = false;
bool any_spheres = vol->is_exact_type(BoundingSphere::get_class_type());
for (++p; p != last; ++p) {
nassertr(!(*p)->is_infinite(), false);
if (!(*p)->is_empty() &&
(*p)->is_of_type(FiniteBoundingVolume::get_class_type())) {
if (!(*p)->is_empty()) {
const FiniteBoundingVolume *vol = DCAST(FiniteBoundingVolume, *p);
LPoint3f min1 = vol->get_min();
LPoint3f max1 = vol->get_max();
@ -325,8 +458,8 @@ around_finite(const BoundingVolume **first,
max(max_box[1], max1[1]),
max(max_box[2], max1[2]));
if (!(*p)->is_of_type(BoundingSphere::get_class_type())) {
any_unknown = true;
if (vol->is_exact_type(BoundingSphere::get_class_type())) {
any_spheres = true;
}
}
}
@ -334,27 +467,39 @@ around_finite(const BoundingVolume **first,
// Now take the center of the bounding box as the center of the sphere.
_center = (min_box + max_box) * 0.5f;
if (any_unknown) {
// If we have any volumes in the list that we don't know what to
// do with, we'll have to make the bounding sphere large enough to
// enclose the bounding box. Less than ideal, but too bad.
if (!any_spheres) {
// Since there are no spheres in the list, we have to make this
// sphere fully enclose all of the bounding boxes.
_radius = length(max_box - _center);
} else {
// Otherwise, we do understand all the volumes in the list; make
// the sphere as tight as we can.
// We might be able to go tighter, by lopping off the corners of
// the spheres.
_radius = 0.0f;
for (p = first; p != last; ++p) {
if (!(*p)->is_empty()) {
if ((*p)->is_of_type(BoundingSphere::get_class_type())) {
if ((*p)->is_exact_type(BoundingSphere::get_class_type())) {
// This is a sphere; consider its corner.
const BoundingSphere *sphere = DCAST(BoundingSphere, *p);
float dist = length(sphere->_center - _center);
_radius = max(_radius, dist + sphere->_radius);
} else {
// Shouldn't get here, unless we missed a type from above.
mathutil_cat.error()
<< "Unexpected type in BoundingSphere::around_finite()\n";
nassertr(false, false);
// This is a nonsphere. We fit around it.
const FiniteBoundingVolume *vol = DCAST(FiniteBoundingVolume, *p);
BoundingBox box(vol->get_min(), vol->get_max());
box.local_object();
// Find the minimum radius necessary to reach the corner.
float max_dist2 = -1.0;
for (int i = 0; i < 8; ++i) {
float dist2 = (box.get_point(i) - _center).length_squared();
if (dist2 > max_dist2) {
max_dist2 = dist2;
}
}
_radius = max(_radius, csqrt(max_dist2));
}
}
}
@ -364,6 +509,11 @@ around_finite(const BoundingVolume **first,
return true;
}
////////////////////////////////////////////////////////////////////
// Function: BoundingSphere::contains_point
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
int BoundingSphere::
contains_point(const LPoint3f &point) const {
nassertr(!point.is_nan(), IF_no_intersection);
@ -382,6 +532,11 @@ contains_point(const LPoint3f &point) const {
}
}
////////////////////////////////////////////////////////////////////
// Function: BoundingSphere::contains_lineseg
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
int BoundingSphere::
contains_lineseg(const LPoint3f &a, const LPoint3f &b) const {
nassertr(!a.is_nan() && !b.is_nan(), IF_no_intersection);
@ -470,6 +625,18 @@ contains_sphere(const BoundingSphere *sphere) const {
}
}
////////////////////////////////////////////////////////////////////
// Function: BoundingSphere::contains_box
// Access: Protected, Virtual
// Description: Double-dispatch support: called by contains_other()
// when the type we're testing for intersection is known
// to be a box.
////////////////////////////////////////////////////////////////////
int BoundingSphere::
contains_box(const BoundingBox *box) const {
return box->contains_sphere(this) & ~IF_all;
}
////////////////////////////////////////////////////////////////////
// Function: BoundingSphere::contains_hexahedron
// Access: Protected, Virtual

View File

@ -40,6 +40,7 @@ public:
virtual LPoint3f get_min() const;
virtual LPoint3f get_max() const;
virtual float get_volume() const;
virtual LPoint3f get_approx_center() const;
virtual void xform(const LMatrix4f &mat);
@ -60,6 +61,7 @@ protected:
virtual bool extend_by_point(const LPoint3f &point);
virtual bool extend_by_sphere(const BoundingSphere *sphere);
virtual bool extend_by_box(const BoundingBox *box);
virtual bool extend_by_hexahedron(const BoundingHexahedron *hexahedron);
bool extend_by_finite(const FiniteBoundingVolume *volume);
@ -67,6 +69,8 @@ protected:
const LPoint3f *last);
virtual bool around_spheres(const BoundingVolume **first,
const BoundingVolume **last);
virtual bool around_boxes(const BoundingVolume **first,
const BoundingVolume **last);
virtual bool around_hexahedrons(const BoundingVolume **first,
const BoundingVolume **last);
bool around_finite(const BoundingVolume **first,
@ -76,6 +80,7 @@ protected:
virtual int contains_lineseg(const LPoint3f &a, const LPoint3f &b) const;
virtual int contains_hexahedron(const BoundingHexahedron *hexahedron) const;
virtual int contains_sphere(const BoundingSphere *sphere) const;
virtual int contains_box(const BoundingBox *box) const;
virtual int contains_line(const BoundingLine *line) const;
virtual int contains_plane(const BoundingPlane *plane) const;

View File

@ -28,7 +28,7 @@ BoundingVolume() {
////////////////////////////////////////////////////////////////////
// Function: BoundingVolume::is_empty
// Access: Public
// Access: Published
// Description: Any kind of volume might be empty. This is a
// degenerate volume that contains no points; it's not
// the same as, for instance, a sphere with radius zero,
@ -42,7 +42,7 @@ is_empty() const {
////////////////////////////////////////////////////////////////////
// Function: BoundingVolume::is_infinite
// Access: Public
// Access: Published
// Description: The other side of the empty coin is an infinite
// volume. This is a degenerate state of a normally
// finite volume that contains all points. (Note that
@ -63,7 +63,7 @@ is_infinite() const {
////////////////////////////////////////////////////////////////////
// Function: BoundingVolume::set_infinite
// Access: Public
// Access: Published
// Description: Marks the volume as infinite, even if it is normally
// finite. You can think of this as an infinite
// extend_by() operation.
@ -75,7 +75,7 @@ set_infinite() {
////////////////////////////////////////////////////////////////////
// Function: BoundingVolume::extend_by
// Access: Public
// Access: Published
// Description: Increases the size of the volume to include the given
// volume.
////////////////////////////////////////////////////////////////////
@ -96,7 +96,7 @@ extend_by(const BoundingVolume *vol) {
////////////////////////////////////////////////////////////////////
// Function: BoundingVolume::contains
// Access: Public
// Access: Published
// Description: Returns the appropriate set of IntersectionFlags to
// indicate the amount of intersection with the
// indicated volume.

View File

@ -26,7 +26,7 @@ TypeHandle BoundingVolume::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: BoundingVolume::around
// Access: Public
// Access: Published
// Description: Resets the volume to enclose only the volumes
// indicated. Returns true if successful, false if the
// volume doesn't know how to do that or can't do that.
@ -72,7 +72,7 @@ around(const BoundingVolume **first, const BoundingVolume **last) {
////////////////////////////////////////////////////////////////////
// Function: BoundingVolume::write
// Access: Public
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
void BoundingVolume::
@ -80,6 +80,27 @@ write(ostream &out, int indent_level) const {
indent(out, indent_level) << *this << "\n";
}
////////////////////////////////////////////////////////////////////
// Function: BoundingVolume::string_bounds_type
// Access: Public, Static
// Description: Returns the BoundsType corresponding to the indicated
// string.
////////////////////////////////////////////////////////////////////
BoundingVolume::BoundsType BoundingVolume::
string_bounds_type(const string &str) {
if (strcmp(str.c_str(), "best") == 0) {
return BT_best;
} else if (strcmp(str.c_str(), "sphere") == 0) {
return BT_sphere;
} else if (strcmp(str.c_str(), "box") == 0) {
return BT_box;
}
return BT_invalid;
}
////////////////////////////////////////////////////////////////////
// Function: BoundingVolume::extend_by_sphere
// Access: Protected, Virtual
@ -89,6 +110,23 @@ write(ostream &out, int indent_level) const {
////////////////////////////////////////////////////////////////////
bool BoundingVolume::
extend_by_sphere(const BoundingSphere *) {
mathutil_cat.warning()
<< get_type() << "::extend_by_sphere() called\n";
_flags = F_infinite;
return false;
}
////////////////////////////////////////////////////////////////////
// Function: BoundingVolume::extend_by_box
// Access: Protected, Virtual
// Description: Double-dispatch support: called by extend_other()
// when the type we're extending by is known to be a
// box.
////////////////////////////////////////////////////////////////////
bool BoundingVolume::
extend_by_box(const BoundingBox *) {
mathutil_cat.warning()
<< get_type() << "::extend_by_box() called\n";
_flags = F_infinite;
return false;
}
@ -102,6 +140,8 @@ extend_by_sphere(const BoundingSphere *) {
////////////////////////////////////////////////////////////////////
bool BoundingVolume::
extend_by_hexahedron(const BoundingHexahedron *) {
mathutil_cat.warning()
<< get_type() << "::extend_by_hexahedron() called\n";
_flags = F_infinite;
return false;
}
@ -115,6 +155,8 @@ extend_by_hexahedron(const BoundingHexahedron *) {
////////////////////////////////////////////////////////////////////
bool BoundingVolume::
extend_by_line(const BoundingLine *) {
mathutil_cat.warning()
<< get_type() << "::extend_by_line() called\n";
_flags = F_infinite;
return false;
}
@ -128,6 +170,8 @@ extend_by_line(const BoundingLine *) {
////////////////////////////////////////////////////////////////////
bool BoundingVolume::
extend_by_plane(const BoundingPlane *) {
mathutil_cat.warning()
<< get_type() << "::extend_by_plane() called\n";
_flags = F_infinite;
return false;
}
@ -141,6 +185,23 @@ extend_by_plane(const BoundingPlane *) {
////////////////////////////////////////////////////////////////////
bool BoundingVolume::
around_spheres(const BoundingVolume **, const BoundingVolume **) {
mathutil_cat.warning()
<< get_type() << "::around_spheres() called\n";
_flags = F_infinite;
return false;
}
////////////////////////////////////////////////////////////////////
// Function: BoundingVolume::around_boxes
// Access: Protected, Virtual
// Description: Double-dispatch support: called by around_other()
// when the type of the first element in the list is
// known to be a nonempty box.
////////////////////////////////////////////////////////////////////
bool BoundingVolume::
around_boxes(const BoundingVolume **, const BoundingVolume **) {
mathutil_cat.warning()
<< get_type() << "::around_boxes() called\n";
_flags = F_infinite;
return false;
}
@ -154,6 +215,8 @@ around_spheres(const BoundingVolume **, const BoundingVolume **) {
////////////////////////////////////////////////////////////////////
bool BoundingVolume::
around_hexahedrons(const BoundingVolume **, const BoundingVolume **) {
mathutil_cat.warning()
<< get_type() << "::around_hexahedrons() called\n";
_flags = F_infinite;
return false;
}
@ -174,6 +237,9 @@ around_lines(const BoundingVolume **, const BoundingVolume **) {
return true;
}
mathutil_cat.warning()
<< get_type() << "::around_lines() called\n";
// Otherwise, we might do better, and we require each class to
// define a function. If we get here, the function isn't defined,
// so we return false to indicate this.
@ -196,6 +262,9 @@ around_planes(const BoundingVolume **, const BoundingVolume **) {
return true;
}
mathutil_cat.warning()
<< get_type() << "::around_planes() called\n";
// Otherwise, we might do better, and we require each class to
// define a function. If we get here, the function isn't defined,
// so we return false to indicate this.
@ -211,6 +280,22 @@ around_planes(const BoundingVolume **, const BoundingVolume **) {
////////////////////////////////////////////////////////////////////
int BoundingVolume::
contains_sphere(const BoundingSphere *) const {
mathutil_cat.warning()
<< get_type() << "::contains_sphere() called\n";
return IF_dont_understand;
}
////////////////////////////////////////////////////////////////////
// Function: BoundingVolume::contains_box
// Access: Protected, Virtual
// Description: Double-dispatch support: called by contains_other()
// when the type we're testing for intersection is known
// to be a box.
////////////////////////////////////////////////////////////////////
int BoundingVolume::
contains_box(const BoundingBox *) const {
mathutil_cat.warning()
<< get_type() << "::contains_box() called\n";
return IF_dont_understand;
}
@ -223,6 +308,8 @@ contains_sphere(const BoundingSphere *) const {
////////////////////////////////////////////////////////////////////
int BoundingVolume::
contains_hexahedron(const BoundingHexahedron *) const {
mathutil_cat.warning()
<< get_type() << "::contains_hexahedron() called\n";
return IF_dont_understand;
}
@ -235,6 +322,8 @@ contains_hexahedron(const BoundingHexahedron *) const {
////////////////////////////////////////////////////////////////////
int BoundingVolume::
contains_line(const BoundingLine *) const {
mathutil_cat.warning()
<< get_type() << "::contains_line() called\n";
return IF_dont_understand;
}
@ -247,5 +336,42 @@ contains_line(const BoundingLine *) const {
////////////////////////////////////////////////////////////////////
int BoundingVolume::
contains_plane(const BoundingPlane *) const {
mathutil_cat.warning()
<< get_type() << "::contains_plane() called\n";
return IF_dont_understand;
}
ostream &
operator << (ostream &out, BoundingVolume::BoundsType type) {
switch (type) {
case BoundingVolume::BT_best:
return out << "best";
case BoundingVolume::BT_sphere:
return out << "sphere";
case BoundingVolume::BT_box:
return out << "box";
case BoundingVolume::BT_invalid:
return out << "invalid";
}
mathutil_cat.error()
<< "Invalid BoundingVolume::BoundsType value: " << (int)type << "\n";
nassertr(false, out);
return out;
}
istream &
operator >> (istream &in, BoundingVolume::BoundsType &type) {
string word;
in >> word;
type = BoundingVolume::string_bounds_type(word);
if (type == BoundingVolume::BT_invalid) {
mathutil_cat->error()
<< "Invalid BoundingVolume::BoundsType string: " << word << "\n";
}
return in;
}

View File

@ -26,6 +26,7 @@
#include "deletedChain.h"
class BoundingSphere;
class BoundingBox;
class BoundingHexahedron;
class BoundingLine;
class BoundingPlane;
@ -42,8 +43,10 @@ class BoundingPlane;
// sort.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA BoundingVolume : public TypedReferenceCount {
PUBLISHED:
public:
INLINE_MATHUTIL BoundingVolume();
PUBLISHED:
virtual BoundingVolume *make_copy() const=0;
INLINE_MATHUTIL bool is_empty() const;
@ -96,6 +99,19 @@ PUBLISHED:
virtual void output(ostream &out) const=0;
virtual void write(ostream &out, int indent_level = 0) const;
// This enum is used to control the automatic generation of bounding
// volumes.
enum BoundsType {
BT_best,
BT_sphere,
BT_box,
BT_invalid, // Do not use this one
};
public:
static BoundsType string_bounds_type(const string &str);
protected:
enum Flags {
F_empty = 0x01,
@ -118,12 +134,15 @@ protected:
// These functions are the second dispatch point. They actually do
// the work.
virtual bool extend_by_sphere(const BoundingSphere *sphere);
virtual bool extend_by_box(const BoundingBox *box);
virtual bool extend_by_hexahedron(const BoundingHexahedron *hexahedron);
virtual bool extend_by_line(const BoundingLine *line);
virtual bool extend_by_plane(const BoundingPlane *plane);
virtual bool around_spheres(const BoundingVolume **first,
const BoundingVolume **last);
virtual bool around_boxes(const BoundingVolume **first,
const BoundingVolume **last);
virtual bool around_hexahedrons(const BoundingVolume **first,
const BoundingVolume **last);
virtual bool around_lines(const BoundingVolume **first,
@ -132,6 +151,7 @@ protected:
const BoundingVolume **last);
virtual int contains_sphere(const BoundingSphere *sphere) const;
virtual int contains_box(const BoundingBox *box) const;
virtual int contains_hexahedron(const BoundingHexahedron *hexahedron) const;
virtual int contains_line(const BoundingLine *line) const;
virtual int contains_plane(const BoundingPlane *plane) const;
@ -155,6 +175,7 @@ private:
static TypeHandle _type_handle;
friend class BoundingSphere;
friend class BoundingBox;
friend class BoundingHexahedron;
friend class BoundingLine;
friend class BoundingPlane;
@ -164,4 +185,7 @@ INLINE_MATHUTIL ostream &operator << (ostream &out, const BoundingVolume &bound)
#include "boundingVolume.I"
EXPCL_PANDA ostream &operator << (ostream &out, BoundingVolume::BoundsType type);
EXPCL_PANDA istream &operator >> (istream &in, BoundingVolume::BoundsType &type);
#endif

View File

@ -22,6 +22,7 @@
#include "finiteBoundingVolume.h"
#include "omniBoundingVolume.h"
#include "boundingSphere.h"
#include "boundingBox.h"
#include "boundingHexahedron.h"
#include "boundingLine.h"
#include "boundingPlane.h"
@ -44,9 +45,16 @@ ConfigVariableDouble fft_exponent
ConfigVariableDouble fft_error_threshold
("fft-error-threshold", 0.2);
ConfigVariableEnum<BoundingVolume::BoundsType> bounds_type
("bounds-type", BoundingVolume::BT_sphere,
PRC_DESC("Specify the type of bounding volume that is created automatically "
"by Panda to enclose geometry. Use 'sphere' or 'box', or use "
"'best' to let Panda decide which is most appropriate."));
ConfigureFn(config_mathutil) {
BoundingHexahedron::init_type();
BoundingSphere::init_type();
BoundingBox::init_type();
BoundingVolume::init_type();
FiniteBoundingVolume::init_type();
GeometricBoundingVolume::init_type();

View File

@ -22,6 +22,8 @@
#include "pandabase.h"
#include "notifyCategoryProxy.h"
#include "configVariableDouble.h"
#include "configVariableEnum.h"
#include "boundingVolume.h"
NotifyCategoryDecl(mathutil, EXPCL_PANDA, EXPTP_PANDA);
@ -29,6 +31,7 @@ extern ConfigVariableDouble fft_offset;
extern ConfigVariableDouble fft_factor;
extern ConfigVariableDouble fft_exponent;
extern ConfigVariableDouble fft_error_threshold;
extern EXPCL_PANDA ConfigVariableEnum<BoundingVolume::BoundsType> bounds_type;
#endif

View File

@ -17,5 +17,28 @@
////////////////////////////////////////////////////////////////////
#include "finiteBoundingVolume.h"
#include "boundingBox.h"
TypeHandle FiniteBoundingVolume::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: FiniteBoundingVolume::get_volume
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
float FiniteBoundingVolume::
get_volume() const {
nassertr(!is_infinite(), 0.0f);
if (is_empty()) {
return 0.0f;
}
mathutil_cat.warning()
<< get_type() << "::get_volume() called\n";
// We don't know how to compute the volume of this shape correctly;
// just calculate the volume of its containing box.
BoundingBox box(get_min(), get_max());
box.local_object();
return box.get_volume();
}

View File

@ -34,7 +34,7 @@ class EXPCL_PANDA FiniteBoundingVolume : public GeometricBoundingVolume {
PUBLISHED:
virtual LPoint3f get_min() const=0;
virtual LPoint3f get_max() const=0;
virtual float get_volume() const;
public:
static TypeHandle get_class_type() {

View File

@ -1,5 +1,6 @@
#include "boundingHexahedron.cxx"
#include "boundingLine.cxx"
#include "boundingBox.cxx"
#include "boundingPlane.cxx"
#include "boundingSphere.cxx"
#include "boundingVolume.cxx"

View File

@ -117,6 +117,16 @@ extend_by_sphere(const BoundingSphere *) {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: OmniBoundingVolume::extend_by_box
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
bool OmniBoundingVolume::
extend_by_box(const BoundingBox *) {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: OmniBoundingVolume::extend_by_hexahedron
// Access: Public, Virtual
@ -148,6 +158,17 @@ around_spheres(const BoundingVolume **,
return true;
}
////////////////////////////////////////////////////////////////////
// Function: OmniBoundingVolume::around_boxes
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
bool OmniBoundingVolume::
around_boxes(const BoundingVolume **,
const BoundingVolume **) {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: OmniBoundingVolume::around_hexahedrons
// Access: Public, Virtual
@ -189,6 +210,16 @@ contains_sphere(const BoundingSphere *) const {
return IF_possible | IF_some | IF_all;
}
////////////////////////////////////////////////////////////////////
// Function: OmniBoundingVolume::contains_box
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
int OmniBoundingVolume::
contains_box(const BoundingBox *) const {
return IF_possible | IF_some | IF_all;
}
////////////////////////////////////////////////////////////////////
// Function: OmniBoundingVolume::contains_hexahedron
// Access: Public, Virtual

View File

@ -50,12 +50,15 @@ protected:
virtual bool extend_by_point(const LPoint3f &point);
virtual bool extend_by_sphere(const BoundingSphere *sphere);
virtual bool extend_by_box(const BoundingBox *box);
virtual bool extend_by_hexahedron(const BoundingHexahedron *hexahedron);
virtual bool around_points(const LPoint3f *first,
const LPoint3f *last);
virtual bool around_spheres(const BoundingVolume **first,
const BoundingVolume **last);
virtual bool around_boxes(const BoundingVolume **first,
const BoundingVolume **last);
virtual bool around_hexahedrons(const BoundingVolume **first,
const BoundingVolume **last);
@ -63,6 +66,7 @@ protected:
virtual int contains_lineseg(const LPoint3f &a, const LPoint3f &b) const;
virtual int contains_hexahedron(const BoundingHexahedron *hexahedron) const;
virtual int contains_sphere(const BoundingSphere *sphere) const;
virtual int contains_box(const BoundingBox *box) const;
public:
static TypeHandle get_class_type() {

View File

@ -30,10 +30,12 @@
#include "geomNode.h"
#include "config_pgraph.h"
#include "boundingSphere.h"
#include "boundingBox.h"
#include "boundingHexahedron.h"
#include "portalClipper.h"
#include "geom.h"
#include "geomTristrips.h"
#include "geomTriangles.h"
#include "geomLinestrips.h"
#include "geomVertexWriter.h"
@ -426,6 +428,50 @@ make_bounds_viz(const BoundingVolume *vol) {
geom = new Geom(vdata);
geom->add_primitive(strip);
} else if (vol->is_of_type(FiniteBoundingVolume::get_class_type())) {
const FiniteBoundingVolume *fvol = DCAST(FiniteBoundingVolume, vol);
BoundingBox box(fvol->get_min(), fvol->get_max());
box.local_object();
PT(GeomVertexData) vdata = new GeomVertexData
("bounds", GeomVertexFormat::get_v3(),
Geom::UH_stream);
GeomVertexWriter vertex(vdata, InternalName::get_vertex());
for (int i = 0; i < 8; ++i ) {
vertex.add_data3f(box.get_point(i));
}
PT(GeomTriangles) tris = new GeomTriangles(Geom::UH_stream);
tris->add_vertices(0, 4, 5);
tris->close_primitive();
tris->add_vertices(0, 5, 1);
tris->close_primitive();
tris->add_vertices(4, 6, 7);
tris->close_primitive();
tris->add_vertices(4, 7, 5);
tris->close_primitive();
tris->add_vertices(6, 2, 3);
tris->close_primitive();
tris->add_vertices(6, 3, 7);
tris->close_primitive();
tris->add_vertices(2, 0, 1);
tris->close_primitive();
tris->add_vertices(2, 1, 3);
tris->close_primitive();
tris->add_vertices(1, 5, 7);
tris->close_primitive();
tris->add_vertices(1, 7, 3);
tris->close_primitive();
tris->add_vertices(2, 6, 4);
tris->close_primitive();
tris->add_vertices(2, 4, 0);
tris->close_primitive();
geom = new Geom(vdata);
geom->add_primitive(tris);
} else {
pgraph_cat.warning()
<< "Don't know how to draw a representation of "

View File

@ -33,6 +33,8 @@
#include "pset.h"
#include "config_pgraph.h"
#include "graphicsStateGuardianBase.h"
#include "boundingBox.h"
#include "config_mathutil.h"
TypeHandle GeomNode::_type_handle;
@ -682,30 +684,46 @@ compute_internal_bounds(PandaNode::BoundsData *bdata, int pipeline_stage,
Thread *current_thread) const {
int num_vertices = 0;
// First, get ourselves a fresh, empty bounding volume.
PT(BoundingVolume) bound = new BoundingSphere;
CDLockedStageReader cdata(_cycler, pipeline_stage, current_thread);
// Now actually compute the bounding volume by putting it around all
// of our geoms' bounding volumes.
pvector<const BoundingVolume *> child_volumes;
CDStageReader cdata(_cycler, pipeline_stage, current_thread);
bool all_box = true;
GeomList::const_iterator gi;
CPT(GeomList) geoms = cdata->get_geoms();
for (gi = geoms->begin(); gi != geoms->end(); ++gi) {
const GeomEntry &entry = (*gi);
CPT(Geom) geom = entry._geom.get_read_pointer();
child_volumes.push_back(geom->get_bounds());
const BoundingVolume *volume = geom->get_bounds();
if (!volume->is_empty()) {
child_volumes.push_back(volume);
if (!volume->is_exact_type(BoundingBox::get_class_type())) {
all_box = false;
}
}
num_vertices += geom->get_nested_vertices();
}
const BoundingVolume **child_begin = &child_volumes[0];
const BoundingVolume **child_end = child_begin + child_volumes.size();
PT(GeometricBoundingVolume) gbv;
bound->around(child_begin, child_end);
if (bounds_type == BoundingVolume::BT_box ||
(bounds_type != BoundingVolume::BT_sphere && all_box)) {
// If all of the child volumes are a BoundingBox, then our volume
// is also a BoundingBox.
gbv = new BoundingBox;
} else {
// Otherwise, it's a sphere.
gbv = new BoundingSphere;
}
bdata->_internal_bounds = bound;
if (child_volumes.size() > 0) {
const BoundingVolume **child_begin = &child_volumes[0];
const BoundingVolume **child_end = child_begin + child_volumes.size();
((BoundingVolume *)gbv)->around(child_begin, child_end);
}
bdata->_internal_bounds = gbv;
bdata->_internal_vertices = num_vertices;
bdata->_internal_bounds_stale = false;
}

View File

@ -143,6 +143,7 @@ private:
typedef CycleDataReader<CData> CDReader;
typedef CycleDataWriter<CData> CDWriter;
typedef CycleDataStageReader<CData> CDStageReader;
typedef CycleDataLockedStageReader<CData> CDLockedStageReader;
typedef CycleDataStageWriter<CData> CDStageWriter;
public:

View File

@ -27,7 +27,9 @@
#include "accumulatedAttribs.h"
#include "clipPlaneAttrib.h"
#include "boundingSphere.h"
#include "boundingBox.h"
#include "pStatTimer.h"
#include "config_mathutil.h"
// This category is just temporary for debugging convenience.
NotifyCategoryDecl(drawmask, EXPCL_PANDA, EXPTP_PANDA);
@ -3413,10 +3415,17 @@ update_bounds(int pipeline_stage, PandaNode::CDLockedStageReader &cdata) {
pvector<CPT(BoundingVolume) > child_volumes_ref;
pvector<const BoundingVolume *> child_volumes;
bool all_box = true;
CPT(BoundingVolume) internal_bounds =
get_internal_bounds(pipeline_stage, current_thread);
child_volumes_ref.push_back(internal_bounds);
child_volumes.push_back(internal_bounds);
if (!internal_bounds->is_empty()) {
child_volumes_ref.push_back(internal_bounds);
child_volumes.push_back(internal_bounds);
if (!internal_bounds->is_exact_type(BoundingBox::get_class_type())) {
all_box = false;
}
}
int num_vertices = cdata->_internal_vertices;
@ -3466,8 +3475,13 @@ update_bounds(int pipeline_stage, PandaNode::CDLockedStageReader &cdata) {
}
off_clip_planes = orig_cp->compose_off(child_cdataw->_off_clip_planes);
child_volumes_ref.push_back(child_cdataw->_external_bounds);
child_volumes.push_back(child_cdataw->_external_bounds);
if (!child_cdataw->_external_bounds->is_empty()) {
child_volumes_ref.push_back(child_cdataw->_external_bounds);
child_volumes.push_back(child_cdataw->_external_bounds);
if (!child_cdataw->_external_bounds->is_exact_type(BoundingBox::get_class_type())) {
all_box = false;
}
}
num_vertices += child_cdataw->_nested_vertices;
} else {
@ -3498,8 +3512,13 @@ update_bounds(int pipeline_stage, PandaNode::CDLockedStageReader &cdata) {
}
off_clip_planes = orig_cp->compose_off(child_cdata->_off_clip_planes);
child_volumes_ref.push_back(child_cdata->_external_bounds);
child_volumes.push_back(child_cdata->_external_bounds);
if (!child_cdata->_external_bounds->is_empty()) {
child_volumes_ref.push_back(child_cdata->_external_bounds);
child_volumes.push_back(child_cdata->_external_bounds);
if (!child_cdata->_external_bounds->is_exact_type(BoundingBox::get_class_type())) {
all_box = false;
}
}
num_vertices += child_cdata->_nested_vertices;
}
}
@ -3543,21 +3562,33 @@ update_bounds(int pipeline_stage, PandaNode::CDLockedStageReader &cdata) {
cdataw->_off_clip_planes = off_clip_planes;
cdataw->_nested_vertices = num_vertices;
// Compute the bounding sphere around all of our child
// volumes.
PT(GeometricBoundingVolume) gbv = new BoundingSphere;
const BoundingVolume **child_begin = &child_volumes[0];
const BoundingVolume **child_end = child_begin + child_volumes.size();
((BoundingVolume *)gbv)->around(child_begin, child_end);
// If we have a transform, apply it to the bounding volume we
// just computed.
CPT(TransformState) transform = get_transform(current_thread);
if (!transform->is_identity()) {
gbv->xform(transform->get_mat());
}
PT(GeometricBoundingVolume) gbv;
cdataw->_external_bounds = gbv;
if (bounds_type == BoundingVolume::BT_box ||
(bounds_type != BoundingVolume::BT_sphere && all_box && transform->is_identity())) {
// If all of the child volumes are a BoundingBox, and we
// have no transform, then our volume is also a
// BoundingBox.
gbv = new BoundingBox;
} else {
// Otherwise, it's a sphere.
gbv = new BoundingSphere;
}
if (child_volumes.size() > 0) {
const BoundingVolume **child_begin = &child_volumes[0];
const BoundingVolume **child_end = child_begin + child_volumes.size();
((BoundingVolume *)gbv)->around(child_begin, child_end);
}
// If we have a transform, apply it to the bounding volume we
// just computed.
if (!transform->is_identity()) {
gbv->xform(transform->get_mat());
}
cdataw->_external_bounds = gbv;
cdataw->_last_update = next_update;
if (drawmask_cat.is_debug()) {