intersectionBoundingVolume.cxx 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  1. /**
  2. * PANDA 3D SOFTWARE
  3. * Copyright (c) Carnegie Mellon University. All rights reserved.
  4. *
  5. * All use of this software is subject to the terms of the revised BSD
  6. * license. You should have received a copy of this license along
  7. * with this source code in a file named "LICENSE."
  8. *
  9. * @file intersectionBoundingVolume.cxx
  10. * @author drose
  11. * @date 2012-02-08
  12. */
  13. #include "intersectionBoundingVolume.h"
  14. #include "unionBoundingVolume.h"
  15. #include "config_mathutil.h"
  16. #include "dcast.h"
  17. TypeHandle IntersectionBoundingVolume::_type_handle;
  18. /**
  19. *
  20. */
  21. IntersectionBoundingVolume::
  22. IntersectionBoundingVolume(const IntersectionBoundingVolume &copy) :
  23. GeometricBoundingVolume(copy),
  24. _components(copy._components)
  25. {
  26. }
  27. /**
  28. *
  29. */
  30. BoundingVolume *IntersectionBoundingVolume::
  31. make_copy() const {
  32. return new IntersectionBoundingVolume(*this);
  33. }
  34. /**
  35. *
  36. */
  37. LPoint3 IntersectionBoundingVolume::
  38. get_approx_center() const {
  39. nassertr(!is_empty(), LPoint3::zero());
  40. nassertr(!is_infinite(), LPoint3::zero());
  41. LPoint3 center = LPoint3::zero();
  42. for (Components::const_iterator ci = _components.begin();
  43. ci != _components.end();
  44. ++ci) {
  45. center += (*ci)->get_approx_center();
  46. }
  47. return center / (PN_stdfloat)_components.size();
  48. }
  49. /**
  50. *
  51. */
  52. void IntersectionBoundingVolume::
  53. xform(const LMatrix4 &mat) {
  54. nassertv(!mat.is_nan());
  55. for (Components::iterator ci = _components.begin();
  56. ci != _components.end();
  57. ++ci) {
  58. PT(GeometricBoundingVolume) copy = DCAST(GeometricBoundingVolume, (*ci)->make_copy());
  59. copy->xform(mat);
  60. (*ci) = copy;
  61. }
  62. }
  63. /**
  64. *
  65. */
  66. void IntersectionBoundingVolume::
  67. output(std::ostream &out) const {
  68. if (is_empty()) {
  69. out << "intersection, empty";
  70. } else if (is_infinite()) {
  71. out << "intersection, infinite";
  72. } else {
  73. out << "intersection [";
  74. for (Components::const_iterator ci = _components.begin();
  75. ci != _components.end();
  76. ++ci) {
  77. out << " " << *(*ci);
  78. }
  79. out << " ]";
  80. }
  81. }
  82. /**
  83. *
  84. */
  85. void IntersectionBoundingVolume::
  86. write(std::ostream &out, int indent_level) const {
  87. if (is_empty()) {
  88. indent(out, indent_level) << "intersection, empty\n";
  89. } else if (is_infinite()) {
  90. indent(out, indent_level) << "intersection, infinite\n";
  91. } else {
  92. indent(out, indent_level) << "intersection {\n";
  93. for (Components::const_iterator ci = _components.begin();
  94. ci != _components.end();
  95. ++ci) {
  96. (*ci)->write(out, indent_level + 2);
  97. }
  98. indent(out, indent_level) << "}\n";
  99. }
  100. }
  101. /**
  102. * Removes all components from the volume.
  103. */
  104. void IntersectionBoundingVolume::
  105. clear_components() {
  106. _components.clear();
  107. _flags = F_infinite;
  108. }
  109. /**
  110. * Adds a new component to the volume. This does not necessarily increase the
  111. * total number of components by one, and you may or may not be able to find
  112. * this component in the volume by a subsequent call to get_component();
  113. * certain optimizations may prevent the component from being added, or have
  114. * other unexpected effects on the total set of components.
  115. */
  116. void IntersectionBoundingVolume::
  117. add_component(const GeometricBoundingVolume *component) {
  118. CPT(GeometricBoundingVolume) gbv;
  119. if (component->is_exact_type(UnionBoundingVolume::get_class_type())) {
  120. // Here's a special case. We'll construct a new union that includes only
  121. // those components that have some intersection with our existing
  122. // components. (No need to include the components that have no
  123. // intersection.)
  124. PT(UnionBoundingVolume) unionv = DCAST(UnionBoundingVolume, component->make_copy());
  125. unionv->filter_intersection(this);
  126. // Save the modified union in a PT() so it won't be destructed.
  127. gbv = unionv.p();
  128. if (unionv->get_num_components() == 1) {
  129. // If there's only one component left, use just that one.
  130. gbv = unionv->get_component(0);
  131. }
  132. component = gbv;
  133. }
  134. if (component->is_empty()) {
  135. _flags = F_empty;
  136. _components.clear();
  137. } else if (component->is_infinite() || is_empty()) {
  138. // No-op.
  139. } else if (component->is_exact_type(IntersectionBoundingVolume::get_class_type())) {
  140. // Another special case. Just more components.
  141. const IntersectionBoundingVolume *other = DCAST(IntersectionBoundingVolume, component);
  142. for (Components::const_iterator ci = other->_components.begin();
  143. ci != other->_components.end();
  144. ++ci) {
  145. add_component(*ci);
  146. }
  147. } else {
  148. // The general case.
  149. size_t i = 0;
  150. while (i < _components.size()) {
  151. const GeometricBoundingVolume *existing = _components[i];
  152. ++i;
  153. int result = component->contains(existing);
  154. if ((result & IF_all) != 0) {
  155. // The existing component is entirely within this one; no need to do
  156. // anything with it.
  157. return;
  158. } else if (result == 0) {
  159. // No intersection between these components; we're now empty.
  160. _flags = F_empty;
  161. _components.clear();
  162. return;
  163. }
  164. result = existing->contains(component);
  165. if ((result & IF_all) != 0) {
  166. // This new component is entirely within an existing component; no
  167. // need to keep the existing one.
  168. --i;
  169. _components.erase(_components.begin() + i);
  170. } else if (result == 0) {
  171. // No intersection between these components; we're now empty.
  172. _flags = F_empty;
  173. _components.clear();
  174. return;
  175. }
  176. }
  177. _flags &= ~F_infinite;
  178. _components.push_back(component);
  179. }
  180. }
  181. /**
  182. *
  183. */
  184. bool IntersectionBoundingVolume::
  185. extend_other(BoundingVolume *other) const {
  186. return other->extend_by_intersection(this);
  187. }
  188. /**
  189. *
  190. */
  191. bool IntersectionBoundingVolume::
  192. around_other(BoundingVolume *other,
  193. const BoundingVolume **first,
  194. const BoundingVolume **last) const {
  195. return other->around_intersections(first, last);
  196. }
  197. /**
  198. *
  199. */
  200. int IntersectionBoundingVolume::
  201. contains_other(const BoundingVolume *other) const {
  202. return other->contains_intersection(this);
  203. }
  204. /**
  205. *
  206. */
  207. int IntersectionBoundingVolume::
  208. contains_point(const LPoint3 &point) const {
  209. nassertr(!point.is_nan(), IF_no_intersection);
  210. int result = IF_possible | IF_some | IF_all;
  211. for (Components::const_iterator ci = _components.begin();
  212. ci != _components.end();
  213. ++ci) {
  214. int this_result = (*ci)->contains(point);
  215. if ((this_result & IF_dont_understand) != 0) {
  216. result |= IF_dont_understand;
  217. break;
  218. }
  219. result &= this_result;
  220. if ((result & IF_possible) == 0) {
  221. // No point in looking further.
  222. break;
  223. }
  224. }
  225. return result;
  226. }
  227. /**
  228. *
  229. */
  230. int IntersectionBoundingVolume::
  231. contains_lineseg(const LPoint3 &a, const LPoint3 &b) const {
  232. nassertr(!a.is_nan() && !b.is_nan(), IF_no_intersection);
  233. int result = IF_possible | IF_some | IF_all;
  234. for (Components::const_iterator ci = _components.begin();
  235. ci != _components.end();
  236. ++ci) {
  237. int this_result = (*ci)->contains(a, b);
  238. if ((this_result & IF_dont_understand) != 0) {
  239. result |= IF_dont_understand;
  240. break;
  241. }
  242. result &= this_result;
  243. if ((result & IF_possible) == 0) {
  244. // No point in looking further.
  245. break;
  246. }
  247. }
  248. return result;
  249. }
  250. /**
  251. * Double-dispatch support: called by contains_other() when the type we're
  252. * testing for intersection is known to be a sphere.
  253. */
  254. int IntersectionBoundingVolume::
  255. contains_sphere(const BoundingSphere *sphere) const {
  256. int result = IF_possible | IF_some | IF_all;
  257. for (Components::const_iterator ci = _components.begin();
  258. ci != _components.end();
  259. ++ci) {
  260. int this_result = (*ci)->contains_sphere(sphere);
  261. if ((this_result & IF_dont_understand) != 0) {
  262. result |= IF_dont_understand;
  263. break;
  264. }
  265. result &= this_result;
  266. if ((result & IF_possible) == 0) {
  267. // No point in looking further.
  268. break;
  269. }
  270. }
  271. return result;
  272. }
  273. /**
  274. * Double-dispatch support: called by contains_other() when the type we're
  275. * testing for intersection is known to be a box.
  276. */
  277. int IntersectionBoundingVolume::
  278. contains_box(const BoundingBox *box) const {
  279. int result = IF_possible | IF_some | IF_all;
  280. for (Components::const_iterator ci = _components.begin();
  281. ci != _components.end();
  282. ++ci) {
  283. int this_result = (*ci)->contains_box(box);
  284. if ((this_result & IF_dont_understand) != 0) {
  285. result |= IF_dont_understand;
  286. break;
  287. }
  288. result &= this_result;
  289. if ((result & IF_possible) == 0) {
  290. // No point in looking further.
  291. break;
  292. }
  293. }
  294. return result;
  295. }
  296. /**
  297. * Double-dispatch support: called by contains_other() when the type we're
  298. * testing for intersection is known to be a hexahedron.
  299. */
  300. int IntersectionBoundingVolume::
  301. contains_hexahedron(const BoundingHexahedron *hexahedron) const {
  302. int result = IF_possible | IF_some | IF_all;
  303. for (Components::const_iterator ci = _components.begin();
  304. ci != _components.end();
  305. ++ci) {
  306. int this_result = (*ci)->contains_hexahedron(hexahedron);
  307. if ((this_result & IF_dont_understand) != 0) {
  308. result |= IF_dont_understand;
  309. break;
  310. }
  311. result &= this_result;
  312. if ((result & IF_possible) == 0) {
  313. // No point in looking further.
  314. break;
  315. }
  316. }
  317. return result;
  318. }
  319. /**
  320. * Double-dispatch support: called by contains_other() when the type we're
  321. * testing for intersection is known to be a line.
  322. */
  323. int IntersectionBoundingVolume::
  324. contains_line(const BoundingLine *line) const {
  325. int result = IF_possible | IF_some | IF_all;
  326. for (Components::const_iterator ci = _components.begin();
  327. ci != _components.end();
  328. ++ci) {
  329. int this_result = (*ci)->contains_line(line);
  330. if ((this_result & IF_dont_understand) != 0) {
  331. result |= IF_dont_understand;
  332. break;
  333. }
  334. result &= this_result;
  335. if ((result & IF_possible) == 0) {
  336. // No point in looking further.
  337. break;
  338. }
  339. }
  340. return result;
  341. }
  342. /**
  343. * Double-dispatch support: called by contains_other() when the type we're
  344. * testing for intersection is known to be a plane.
  345. */
  346. int IntersectionBoundingVolume::
  347. contains_plane(const BoundingPlane *plane) const {
  348. int result = IF_possible | IF_some | IF_all;
  349. for (Components::const_iterator ci = _components.begin();
  350. ci != _components.end();
  351. ++ci) {
  352. int this_result = (*ci)->contains_plane(plane);
  353. if ((this_result & IF_dont_understand) != 0) {
  354. result |= IF_dont_understand;
  355. break;
  356. }
  357. result &= this_result;
  358. if ((result & IF_possible) == 0) {
  359. // No point in looking further.
  360. break;
  361. }
  362. }
  363. return result;
  364. }
  365. /**
  366. * Double-dispatch support: called by contains_other() when the type we're
  367. * testing for intersection is known to be a union object.
  368. */
  369. int IntersectionBoundingVolume::
  370. contains_union(const UnionBoundingVolume *unionv) const {
  371. int result = IF_possible | IF_some | IF_all;
  372. for (Components::const_iterator ci = _components.begin();
  373. ci != _components.end();
  374. ++ci) {
  375. int this_result = (*ci)->contains_union(unionv);
  376. if ((this_result & IF_dont_understand) != 0) {
  377. result |= IF_dont_understand;
  378. break;
  379. }
  380. result &= this_result;
  381. if ((result & IF_possible) == 0) {
  382. // No point in looking further.
  383. break;
  384. }
  385. }
  386. return result;
  387. }
  388. /**
  389. * Double-dispatch support: called by contains_other() when the type we're
  390. * testing for intersection is known to be an intersection object.
  391. */
  392. int IntersectionBoundingVolume::
  393. contains_intersection(const IntersectionBoundingVolume *intersection) const {
  394. int result = IF_possible | IF_some | IF_all;
  395. for (Components::const_iterator ci = _components.begin();
  396. ci != _components.end();
  397. ++ci) {
  398. int this_result = (*ci)->contains_intersection(intersection);
  399. if ((this_result & IF_dont_understand) != 0) {
  400. result |= IF_dont_understand;
  401. break;
  402. }
  403. result &= this_result;
  404. if ((result & IF_possible) == 0) {
  405. // No point in looking further.
  406. break;
  407. }
  408. }
  409. return result;
  410. }
  411. /**
  412. * Generic handler for a FiniteBoundingVolume.
  413. */
  414. int IntersectionBoundingVolume::
  415. contains_finite(const FiniteBoundingVolume *volume) const {
  416. int result = IF_possible | IF_some | IF_all;
  417. for (Components::const_iterator ci = _components.begin();
  418. ci != _components.end();
  419. ++ci) {
  420. int this_result = (*ci)->contains_finite(volume);
  421. if ((this_result & IF_dont_understand) != 0) {
  422. result |= IF_dont_understand;
  423. break;
  424. }
  425. result &= this_result;
  426. if ((result & IF_possible) == 0) {
  427. // No point in looking further.
  428. break;
  429. }
  430. }
  431. return result;
  432. }
  433. /**
  434. * Generic handler for a GeometricBoundingVolume.
  435. */
  436. int IntersectionBoundingVolume::
  437. contains_geometric(const GeometricBoundingVolume *volume) const {
  438. int result = IF_possible | IF_some | IF_all;
  439. for (Components::const_iterator ci = _components.begin();
  440. ci != _components.end();
  441. ++ci) {
  442. int this_result = (*ci)->contains_geometric(volume);
  443. if ((this_result & IF_dont_understand) != 0) {
  444. result |= IF_dont_understand;
  445. break;
  446. }
  447. result &= this_result;
  448. if ((result & IF_possible) == 0) {
  449. // No point in looking further.
  450. break;
  451. }
  452. }
  453. return result;
  454. }
  455. /**
  456. * Generic reverse-direction comparison. Called by BoundingVolumes that do
  457. * not implement contains_intersection() explicitly. This returns the test of
  458. * whether the other volume contains this volume.
  459. */
  460. int IntersectionBoundingVolume::
  461. other_contains_intersection(const BoundingVolume *volume) const {
  462. int result = IF_possible | IF_some | IF_all;
  463. for (Components::const_iterator ci = _components.begin();
  464. ci != _components.end();
  465. ++ci) {
  466. int this_result = volume->contains(*ci);
  467. if ((this_result & IF_dont_understand) != 0) {
  468. result |= IF_dont_understand;
  469. break;
  470. }
  471. result &= this_result;
  472. if ((result & IF_possible) == 0) {
  473. // No point in looking further.
  474. break;
  475. }
  476. }
  477. return result;
  478. }