| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534 |
- /**
- * PANDA 3D SOFTWARE
- * Copyright (c) Carnegie Mellon University. All rights reserved.
- *
- * All use of this software is subject to the terms of the revised BSD
- * license. You should have received a copy of this license along
- * with this source code in a file named "LICENSE."
- *
- * @file intersectionBoundingVolume.cxx
- * @author drose
- * @date 2012-02-08
- */
- #include "intersectionBoundingVolume.h"
- #include "unionBoundingVolume.h"
- #include "config_mathutil.h"
- #include "dcast.h"
- TypeHandle IntersectionBoundingVolume::_type_handle;
- /**
- *
- */
- IntersectionBoundingVolume::
- IntersectionBoundingVolume(const IntersectionBoundingVolume ©) :
- GeometricBoundingVolume(copy),
- _components(copy._components)
- {
- }
- /**
- *
- */
- BoundingVolume *IntersectionBoundingVolume::
- make_copy() const {
- return new IntersectionBoundingVolume(*this);
- }
- /**
- *
- */
- LPoint3 IntersectionBoundingVolume::
- get_approx_center() const {
- nassertr(!is_empty(), LPoint3::zero());
- nassertr(!is_infinite(), LPoint3::zero());
- LPoint3 center = LPoint3::zero();
- for (Components::const_iterator ci = _components.begin();
- ci != _components.end();
- ++ci) {
- center += (*ci)->get_approx_center();
- }
- return center / (PN_stdfloat)_components.size();
- }
- /**
- *
- */
- void IntersectionBoundingVolume::
- xform(const LMatrix4 &mat) {
- nassertv(!mat.is_nan());
- for (Components::iterator ci = _components.begin();
- ci != _components.end();
- ++ci) {
- PT(GeometricBoundingVolume) copy = DCAST(GeometricBoundingVolume, (*ci)->make_copy());
- copy->xform(mat);
- (*ci) = copy;
- }
- }
- /**
- *
- */
- void IntersectionBoundingVolume::
- output(std::ostream &out) const {
- if (is_empty()) {
- out << "intersection, empty";
- } else if (is_infinite()) {
- out << "intersection, infinite";
- } else {
- out << "intersection [";
- for (Components::const_iterator ci = _components.begin();
- ci != _components.end();
- ++ci) {
- out << " " << *(*ci);
- }
- out << " ]";
- }
- }
- /**
- *
- */
- void IntersectionBoundingVolume::
- write(std::ostream &out, int indent_level) const {
- if (is_empty()) {
- indent(out, indent_level) << "intersection, empty\n";
- } else if (is_infinite()) {
- indent(out, indent_level) << "intersection, infinite\n";
- } else {
- indent(out, indent_level) << "intersection {\n";
- for (Components::const_iterator ci = _components.begin();
- ci != _components.end();
- ++ci) {
- (*ci)->write(out, indent_level + 2);
- }
- indent(out, indent_level) << "}\n";
- }
- }
- /**
- * Removes all components from the volume.
- */
- void IntersectionBoundingVolume::
- clear_components() {
- _components.clear();
- _flags = F_infinite;
- }
- /**
- * Adds a new component to the volume. This does not necessarily increase the
- * total number of components by one, and you may or may not be able to find
- * this component in the volume by a subsequent call to get_component();
- * certain optimizations may prevent the component from being added, or have
- * other unexpected effects on the total set of components.
- */
- void IntersectionBoundingVolume::
- add_component(const GeometricBoundingVolume *component) {
- CPT(GeometricBoundingVolume) gbv;
- if (component->is_exact_type(UnionBoundingVolume::get_class_type())) {
- // Here's a special case. We'll construct a new union that includes only
- // those components that have some intersection with our existing
- // components. (No need to include the components that have no
- // intersection.)
- PT(UnionBoundingVolume) unionv = DCAST(UnionBoundingVolume, component->make_copy());
- unionv->filter_intersection(this);
- // Save the modified union in a PT() so it won't be destructed.
- gbv = unionv.p();
- if (unionv->get_num_components() == 1) {
- // If there's only one component left, use just that one.
- gbv = unionv->get_component(0);
- }
- component = gbv;
- }
- if (component->is_empty()) {
- _flags = F_empty;
- _components.clear();
- } else if (component->is_infinite() || is_empty()) {
- // No-op.
- } else if (component->is_exact_type(IntersectionBoundingVolume::get_class_type())) {
- // Another special case. Just more components.
- const IntersectionBoundingVolume *other = DCAST(IntersectionBoundingVolume, component);
- for (Components::const_iterator ci = other->_components.begin();
- ci != other->_components.end();
- ++ci) {
- add_component(*ci);
- }
- } else {
- // The general case.
- size_t i = 0;
- while (i < _components.size()) {
- const GeometricBoundingVolume *existing = _components[i];
- ++i;
- int result = component->contains(existing);
- if ((result & IF_all) != 0) {
- // The existing component is entirely within this one; no need to do
- // anything with it.
- return;
- } else if (result == 0) {
- // No intersection between these components; we're now empty.
- _flags = F_empty;
- _components.clear();
- return;
- }
- result = existing->contains(component);
- if ((result & IF_all) != 0) {
- // This new component is entirely within an existing component; no
- // need to keep the existing one.
- --i;
- _components.erase(_components.begin() + i);
- } else if (result == 0) {
- // No intersection between these components; we're now empty.
- _flags = F_empty;
- _components.clear();
- return;
- }
- }
- _flags &= ~F_infinite;
- _components.push_back(component);
- }
- }
- /**
- *
- */
- bool IntersectionBoundingVolume::
- extend_other(BoundingVolume *other) const {
- return other->extend_by_intersection(this);
- }
- /**
- *
- */
- bool IntersectionBoundingVolume::
- around_other(BoundingVolume *other,
- const BoundingVolume **first,
- const BoundingVolume **last) const {
- return other->around_intersections(first, last);
- }
- /**
- *
- */
- int IntersectionBoundingVolume::
- contains_other(const BoundingVolume *other) const {
- return other->contains_intersection(this);
- }
- /**
- *
- */
- int IntersectionBoundingVolume::
- contains_point(const LPoint3 &point) const {
- nassertr(!point.is_nan(), IF_no_intersection);
- int result = IF_possible | IF_some | IF_all;
- for (Components::const_iterator ci = _components.begin();
- ci != _components.end();
- ++ci) {
- int this_result = (*ci)->contains(point);
- if ((this_result & IF_dont_understand) != 0) {
- result |= IF_dont_understand;
- break;
- }
- result &= this_result;
- if ((result & IF_possible) == 0) {
- // No point in looking further.
- break;
- }
- }
- return result;
- }
- /**
- *
- */
- int IntersectionBoundingVolume::
- contains_lineseg(const LPoint3 &a, const LPoint3 &b) const {
- nassertr(!a.is_nan() && !b.is_nan(), IF_no_intersection);
- int result = IF_possible | IF_some | IF_all;
- for (Components::const_iterator ci = _components.begin();
- ci != _components.end();
- ++ci) {
- int this_result = (*ci)->contains(a, b);
- if ((this_result & IF_dont_understand) != 0) {
- result |= IF_dont_understand;
- break;
- }
- result &= this_result;
- if ((result & IF_possible) == 0) {
- // No point in looking further.
- break;
- }
- }
- return result;
- }
- /**
- * Double-dispatch support: called by contains_other() when the type we're
- * testing for intersection is known to be a sphere.
- */
- int IntersectionBoundingVolume::
- contains_sphere(const BoundingSphere *sphere) const {
- int result = IF_possible | IF_some | IF_all;
- for (Components::const_iterator ci = _components.begin();
- ci != _components.end();
- ++ci) {
- int this_result = (*ci)->contains_sphere(sphere);
- if ((this_result & IF_dont_understand) != 0) {
- result |= IF_dont_understand;
- break;
- }
- result &= this_result;
- if ((result & IF_possible) == 0) {
- // No point in looking further.
- break;
- }
- }
- return result;
- }
- /**
- * Double-dispatch support: called by contains_other() when the type we're
- * testing for intersection is known to be a box.
- */
- int IntersectionBoundingVolume::
- contains_box(const BoundingBox *box) const {
- int result = IF_possible | IF_some | IF_all;
- for (Components::const_iterator ci = _components.begin();
- ci != _components.end();
- ++ci) {
- int this_result = (*ci)->contains_box(box);
- if ((this_result & IF_dont_understand) != 0) {
- result |= IF_dont_understand;
- break;
- }
- result &= this_result;
- if ((result & IF_possible) == 0) {
- // No point in looking further.
- break;
- }
- }
- return result;
- }
- /**
- * Double-dispatch support: called by contains_other() when the type we're
- * testing for intersection is known to be a hexahedron.
- */
- int IntersectionBoundingVolume::
- contains_hexahedron(const BoundingHexahedron *hexahedron) const {
- int result = IF_possible | IF_some | IF_all;
- for (Components::const_iterator ci = _components.begin();
- ci != _components.end();
- ++ci) {
- int this_result = (*ci)->contains_hexahedron(hexahedron);
- if ((this_result & IF_dont_understand) != 0) {
- result |= IF_dont_understand;
- break;
- }
- result &= this_result;
- if ((result & IF_possible) == 0) {
- // No point in looking further.
- break;
- }
- }
- return result;
- }
- /**
- * Double-dispatch support: called by contains_other() when the type we're
- * testing for intersection is known to be a line.
- */
- int IntersectionBoundingVolume::
- contains_line(const BoundingLine *line) const {
- int result = IF_possible | IF_some | IF_all;
- for (Components::const_iterator ci = _components.begin();
- ci != _components.end();
- ++ci) {
- int this_result = (*ci)->contains_line(line);
- if ((this_result & IF_dont_understand) != 0) {
- result |= IF_dont_understand;
- break;
- }
- result &= this_result;
- if ((result & IF_possible) == 0) {
- // No point in looking further.
- break;
- }
- }
- return result;
- }
- /**
- * Double-dispatch support: called by contains_other() when the type we're
- * testing for intersection is known to be a plane.
- */
- int IntersectionBoundingVolume::
- contains_plane(const BoundingPlane *plane) const {
- int result = IF_possible | IF_some | IF_all;
- for (Components::const_iterator ci = _components.begin();
- ci != _components.end();
- ++ci) {
- int this_result = (*ci)->contains_plane(plane);
- if ((this_result & IF_dont_understand) != 0) {
- result |= IF_dont_understand;
- break;
- }
- result &= this_result;
- if ((result & IF_possible) == 0) {
- // No point in looking further.
- break;
- }
- }
- return result;
- }
- /**
- * Double-dispatch support: called by contains_other() when the type we're
- * testing for intersection is known to be a union object.
- */
- int IntersectionBoundingVolume::
- contains_union(const UnionBoundingVolume *unionv) const {
- int result = IF_possible | IF_some | IF_all;
- for (Components::const_iterator ci = _components.begin();
- ci != _components.end();
- ++ci) {
- int this_result = (*ci)->contains_union(unionv);
- if ((this_result & IF_dont_understand) != 0) {
- result |= IF_dont_understand;
- break;
- }
- result &= this_result;
- if ((result & IF_possible) == 0) {
- // No point in looking further.
- break;
- }
- }
- return result;
- }
- /**
- * Double-dispatch support: called by contains_other() when the type we're
- * testing for intersection is known to be an intersection object.
- */
- int IntersectionBoundingVolume::
- contains_intersection(const IntersectionBoundingVolume *intersection) const {
- int result = IF_possible | IF_some | IF_all;
- for (Components::const_iterator ci = _components.begin();
- ci != _components.end();
- ++ci) {
- int this_result = (*ci)->contains_intersection(intersection);
- if ((this_result & IF_dont_understand) != 0) {
- result |= IF_dont_understand;
- break;
- }
- result &= this_result;
- if ((result & IF_possible) == 0) {
- // No point in looking further.
- break;
- }
- }
- return result;
- }
- /**
- * Generic handler for a FiniteBoundingVolume.
- */
- int IntersectionBoundingVolume::
- contains_finite(const FiniteBoundingVolume *volume) const {
- int result = IF_possible | IF_some | IF_all;
- for (Components::const_iterator ci = _components.begin();
- ci != _components.end();
- ++ci) {
- int this_result = (*ci)->contains_finite(volume);
- if ((this_result & IF_dont_understand) != 0) {
- result |= IF_dont_understand;
- break;
- }
- result &= this_result;
- if ((result & IF_possible) == 0) {
- // No point in looking further.
- break;
- }
- }
- return result;
- }
- /**
- * Generic handler for a GeometricBoundingVolume.
- */
- int IntersectionBoundingVolume::
- contains_geometric(const GeometricBoundingVolume *volume) const {
- int result = IF_possible | IF_some | IF_all;
- for (Components::const_iterator ci = _components.begin();
- ci != _components.end();
- ++ci) {
- int this_result = (*ci)->contains_geometric(volume);
- if ((this_result & IF_dont_understand) != 0) {
- result |= IF_dont_understand;
- break;
- }
- result &= this_result;
- if ((result & IF_possible) == 0) {
- // No point in looking further.
- break;
- }
- }
- return result;
- }
- /**
- * Generic reverse-direction comparison. Called by BoundingVolumes that do
- * not implement contains_intersection() explicitly. This returns the test of
- * whether the other volume contains this volume.
- */
- int IntersectionBoundingVolume::
- other_contains_intersection(const BoundingVolume *volume) const {
- int result = IF_possible | IF_some | IF_all;
- for (Components::const_iterator ci = _components.begin();
- ci != _components.end();
- ++ci) {
- int this_result = volume->contains(*ci);
- if ((this_result & IF_dont_understand) != 0) {
- result |= IF_dont_understand;
- break;
- }
- result &= this_result;
- if ((result & IF_possible) == 0) {
- // No point in looking further.
- break;
- }
- }
- return result;
- }
|