Panda3D
Loading...
Searching...
No Matches
collisionSphere.cxx
Go to the documentation of this file.
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 collisionSphere.cxx
10 * @author drose
11 * @date 2000-04-24
12 */
13
14#include "collisionSphere.h"
15#include "collisionLine.h"
16#include "collisionRay.h"
17#include "collisionHandler.h"
18#include "collisionEntry.h"
19#include "collisionSegment.h"
20#include "collisionCapsule.h"
21#include "collisionParabola.h"
22#include "collisionBox.h"
23#include "config_collide.h"
24#include "boundingSphere.h"
25#include "datagram.h"
26#include "datagramIterator.h"
27#include "bamReader.h"
28#include "bamWriter.h"
29#include "nearly_zero.h"
30#include "cmath.h"
31#include "mathNumbers.h"
32#include "geom.h"
33#include "geomTristrips.h"
34#include "geomVertexWriter.h"
35
36using std::max;
37using std::min;
38
39PStatCollector CollisionSphere::_volume_pcollector(
40 "Collision Volumes:CollisionSphere");
41PStatCollector CollisionSphere::_test_pcollector(
42 "Collision Tests:CollisionSphere");
43TypeHandle CollisionSphere::_type_handle;
44
45/**
46 *
47 */
48CollisionSolid *CollisionSphere::
49make_copy() {
50 return new CollisionSphere(*this);
51}
52
53/**
54 *
55 */
56PT(CollisionEntry) CollisionSphere::
57test_intersection(const CollisionEntry &entry) const {
58 return entry.get_into()->test_intersection_from_sphere(entry);
59}
60
61/**
62 * Transforms the solid by the indicated matrix.
63 */
64void CollisionSphere::
65xform(const LMatrix4 &mat) {
66 _center = _center * mat;
67
68 // This is a little cheesy and fails miserably in the presence of a non-
69 // uniform scale.
70 LVector3 radius_v = LVector3(_radius, 0.0f, 0.0f) * mat;
71 _radius = length(radius_v);
72 mark_viz_stale();
73 mark_internal_bounds_stale();
74}
75
76/**
77 * Returns the point in space deemed to be the "origin" of the solid for
78 * collision purposes. The closest intersection point to this origin point is
79 * considered to be the most significant.
80 */
83 return get_center();
84}
85
86/**
87 * Returns a PStatCollector that is used to count the number of bounding
88 * volume tests made against a solid of this type in a given frame.
89 */
92 return _volume_pcollector;
93}
94
95/**
96 * Returns a PStatCollector that is used to count the number of intersection
97 * tests made against a solid of this type in a given frame.
98 */
101 return _test_pcollector;
102}
103
104/**
105 *
106 */
107void CollisionSphere::
108output(std::ostream &out) const {
109 out << "sphere, c (" << get_center() << "), r " << get_radius();
110}
111
112/**
113 *
114 */
115PT(BoundingVolume) CollisionSphere::
116compute_internal_bounds() const {
117 return new BoundingSphere(_center, _radius);
118}
119
120/**
121 *
122 */
123PT(CollisionEntry) CollisionSphere::
124test_intersection_from_sphere(const CollisionEntry &entry) const {
125 const CollisionSphere *sphere;
126 DCAST_INTO_R(sphere, entry.get_from(), nullptr);
127
128 CPT(TransformState) wrt_space = entry.get_wrt_space();
129
130 const LMatrix4 &wrt_mat = wrt_space->get_mat();
131
132 LPoint3 from_b = sphere->get_center() * wrt_mat;
133
134 LPoint3 into_center(get_center());
135 PN_stdfloat into_radius(get_radius());
136
137 LVector3 from_radius_v =
138 LVector3(sphere->get_radius(), 0.0f, 0.0f) * wrt_mat;
139 PN_stdfloat from_radius = length(from_radius_v);
140
141 LPoint3 into_intersection_point(from_b);
142 double t1, t2;
143 LPoint3 contact_point(into_intersection_point);
144 PN_stdfloat actual_t = 0.0f;
145
146 LVector3 vec = from_b - into_center;
147 PN_stdfloat dist2 = dot(vec, vec);
148 if (dist2 > (into_radius + from_radius) * (into_radius + from_radius)) {
149 // No intersection with the current position. Check the delta from the
150 // previous frame.
151 CPT(TransformState) wrt_prev_space = entry.get_wrt_prev_space();
152 LPoint3 from_a = sphere->get_center() * wrt_prev_space->get_mat();
153
154 if (!from_a.almost_equal(from_b)) {
155 LVector3 from_direction = from_b - from_a;
156 if (!intersects_line(t1, t2, from_a, from_direction, from_radius)) {
157 // No intersection.
158 return nullptr;
159 }
160
161 if (t2 < 0.0 || t1 > 1.0) {
162 // Both intersection points are before the start of the segment or
163 // after the end of the segment.
164 return nullptr;
165 }
166
167 // doubles, not floats, to satisfy min and max templates.
168 actual_t = min(1.0, max(0.0, t1));
169 contact_point = from_a + actual_t * (from_b - from_a);
170
171 if (t1 < 0.0) {
172 // Point a is within the sphere. The first intersection point is
173 // point a itself.
174 into_intersection_point = from_a;
175 } else {
176 // Point a is outside the sphere, and point b is either inside the
177 // sphere or beyond it. The first intersection point is at t1.
178 into_intersection_point = from_a + t1 * from_direction;
179 }
180 } else {
181 // No delta, therefore no intersection.
182 return nullptr;
183 }
184 }
185
186 if (collide_cat.is_debug()) {
187 collide_cat.debug()
188 << "intersection detected from " << entry.get_from_node_path()
189 << " into " << entry.get_into_node_path() << "\n";
190 }
191 PT(CollisionEntry) new_entry = new CollisionEntry(entry);
192
193 LPoint3 from_center = sphere->get_center() * wrt_mat;
194
195 LVector3 surface_normal;
196 LVector3 v(into_intersection_point - into_center);
197 PN_stdfloat vec_length = v.length();
198 if (IS_NEARLY_ZERO(vec_length)) {
199 // If we don't have a collision normal (e.g. the centers are exactly
200 // coincident), then make up an arbitrary normal--any one is as good as
201 // any other.
202 surface_normal.set(1.0, 0.0, 0.0);
203 } else {
204 surface_normal = v / vec_length;
205 }
206
207 LVector3 eff_normal = (has_effective_normal() && sphere->get_respect_effective_normal()) ? get_effective_normal() : surface_normal;
208
209 LVector3 contact_normal;
210 LVector3 v2 = contact_point - into_center;
211 PN_stdfloat v2_len = v2.length();
212 if (IS_NEARLY_ZERO(v2_len)) {
213 // If we don't have a collision normal (e.g. the centers are exactly
214 // coincident), then make up an arbitrary normal--any one is as good as
215 // any other.
216 contact_normal.set(1.0, 0.0, 0.0);
217 } else {
218 contact_normal = v2 / v2_len;
219 }
220
221 new_entry->set_surface_normal(eff_normal);
222 new_entry->set_surface_point(into_center + surface_normal * into_radius);
223 new_entry->set_interior_point(from_center - surface_normal * from_radius);
224 new_entry->set_contact_pos(contact_point);
225 new_entry->set_contact_normal(contact_normal);
226 new_entry->set_t(actual_t);
227
228 return new_entry;
229}
230
231/**
232 *
233 */
234PT(CollisionEntry) CollisionSphere::
235test_intersection_from_line(const CollisionEntry &entry) const {
236 const CollisionLine *line;
237 DCAST_INTO_R(line, entry.get_from(), nullptr);
238
239 const LMatrix4 &wrt_mat = entry.get_wrt_mat();
240
241 LPoint3 from_origin = line->get_origin() * wrt_mat;
242 LVector3 from_direction = line->get_direction() * wrt_mat;
243
244 double t1, t2;
245 if (!intersects_line(t1, t2, from_origin, from_direction, 0.0f)) {
246 // No intersection.
247 return nullptr;
248 }
249
250 if (collide_cat.is_debug()) {
251 collide_cat.debug()
252 << "intersection detected from " << entry.get_from_node_path()
253 << " into " << entry.get_into_node_path() << "\n";
254 }
255 PT(CollisionEntry) new_entry = new CollisionEntry(entry);
256
257 LPoint3 into_intersection_point = from_origin + t1 * from_direction;
258 new_entry->set_surface_point(into_intersection_point);
259
261 new_entry->set_surface_normal(get_effective_normal());
262 } else {
263 LVector3 normal = into_intersection_point - get_center();
264 normal.normalize();
265 new_entry->set_surface_normal(normal);
266 }
267
268 return new_entry;
269}
270
271/**
272 * Double dispatch point for box as a FROM object
273 */
274PT(CollisionEntry) CollisionSphere::
275test_intersection_from_box(const CollisionEntry &entry) const {
276 const CollisionBox *box;
277 DCAST_INTO_R(box, entry.get_from(), nullptr);
278
279 // Instead of transforming the box into the sphere's coordinate space, we do
280 // it the other way around. It's easier that way.
281 const LMatrix4 &wrt_mat = entry.get_inv_wrt_mat();
282
283 LPoint3 center = wrt_mat.xform_point(_center);
284 PN_stdfloat radius_sq = wrt_mat.xform_vec(LVector3(0, 0, _radius)).length_squared();
285
286 LPoint3 box_min = box->get_min();
287 LPoint3 box_max = box->get_max();
288
289 // Arvo's algorithm.
290 PN_stdfloat d = 0;
291 PN_stdfloat s;
292
293 if (center[0] < box_min[0]) {
294 s = center[0] - box_min[0];
295 d += s * s;
296
297 } else if (center[0] > box_max[0]) {
298 s = center[0] - box_max[0];
299 d += s * s;
300 }
301
302 if (center[1] < box_min[1]) {
303 s = center[1] - box_min[1];
304 d += s * s;
305
306 } else if (center[1] > box_max[1]) {
307 s = center[1] - box_max[1];
308 d += s * s;
309 }
310
311 if (center[2] < box_min[2]) {
312 s = center[2] - box_min[2];
313 d += s * s;
314
315 } else if (center[2] > box_max[2]) {
316 s = center[2] - box_max[2];
317 d += s * s;
318 }
319
320 if (d > radius_sq) {
321 return nullptr;
322 }
323
324 if (collide_cat.is_debug()) {
325 collide_cat.debug()
326 << "intersection detected from " << entry.get_from_node_path()
327 << " into " << entry.get_into_node_path() << "\n";
328 }
329
330 PT(CollisionEntry) new_entry = new CollisionEntry(entry);
331
332 // To get the interior point, clamp the sphere center to the AABB.
333 LPoint3 interior = entry.get_wrt_mat().xform_point(center.fmax(box_min).fmin(box_max));
334 new_entry->set_interior_point(interior);
335
336 // Now extrapolate the surface point and normal from that.
337 LVector3 normal = interior - _center;
338 normal.normalize();
339 new_entry->set_surface_point(_center + normal * _radius);
340 new_entry->set_surface_normal(
342 ? get_effective_normal() : normal);
343
344 return new_entry;
345}
346
347/**
348 *
349 */
350PT(CollisionEntry) CollisionSphere::
351test_intersection_from_ray(const CollisionEntry &entry) const {
352 const CollisionRay *ray;
353 DCAST_INTO_R(ray, entry.get_from(), nullptr);
354
355 const LMatrix4 &wrt_mat = entry.get_wrt_mat();
356
357 LPoint3 from_origin = ray->get_origin() * wrt_mat;
358 LVector3 from_direction = ray->get_direction() * wrt_mat;
359
360 double t1, t2;
361 if (!intersects_line(t1, t2, from_origin, from_direction, 0.0f)) {
362 // No intersection.
363 return nullptr;
364 }
365
366 if (t2 < 0.0) {
367 // Both intersection points are before the start of the ray.
368 return nullptr;
369 }
370
371 t1 = max(t1, 0.0);
372
373 if (collide_cat.is_debug()) {
374 collide_cat.debug()
375 << "intersection detected from " << entry.get_from_node_path()
376 << " into " << entry.get_into_node_path() << "\n";
377 }
378 PT(CollisionEntry) new_entry = new CollisionEntry(entry);
379
380 LPoint3 into_intersection_point = from_origin + t1 * from_direction;
381 new_entry->set_surface_point(into_intersection_point);
382
384 new_entry->set_surface_normal(get_effective_normal());
385 } else {
386 LVector3 normal = into_intersection_point - get_center();
387 normal.normalize();
388 new_entry->set_surface_normal(normal);
389 }
390
391 return new_entry;
392}
393
394/**
395 *
396 */
397PT(CollisionEntry) CollisionSphere::
398test_intersection_from_segment(const CollisionEntry &entry) const {
399 const CollisionSegment *segment;
400 DCAST_INTO_R(segment, entry.get_from(), nullptr);
401
402 const LMatrix4 &wrt_mat = entry.get_wrt_mat();
403
404 LPoint3 from_a = segment->get_point_a() * wrt_mat;
405 LPoint3 from_b = segment->get_point_b() * wrt_mat;
406 LVector3 from_direction = from_b - from_a;
407
408 double t1, t2;
409 if (!intersects_line(t1, t2, from_a, from_direction, 0.0f)) {
410 // No intersection.
411 return nullptr;
412 }
413
414 if (t2 < 0.0 || t1 > 1.0) {
415 // Both intersection points are before the start of the segment or after
416 // the end of the segment.
417 return nullptr;
418 }
419
420 t1 = max(t1, 0.0);
421
422 if (collide_cat.is_debug()) {
423 collide_cat.debug()
424 << "intersection detected from " << entry.get_from_node_path()
425 << " into " << entry.get_into_node_path() << "\n";
426 }
427 PT(CollisionEntry) new_entry = new CollisionEntry(entry);
428
429 LPoint3 into_intersection_point = from_a + t1 * from_direction;
430 new_entry->set_surface_point(into_intersection_point);
431
433 new_entry->set_surface_normal(get_effective_normal());
434 } else {
435 LVector3 normal = into_intersection_point - get_center();
436 normal.normalize();
437 new_entry->set_surface_normal(normal);
438 }
439
440 return new_entry;
441}
442
443/**
444 *
445 */
446PT(CollisionEntry) CollisionSphere::
447test_intersection_from_capsule(const CollisionEntry &entry) const {
448 const CollisionCapsule *capsule;
449 DCAST_INTO_R(capsule, entry.get_from(), nullptr);
450
451 const LMatrix4 &wrt_mat = entry.get_wrt_mat();
452
453 LPoint3 from_a = capsule->get_point_a() * wrt_mat;
454 LPoint3 from_b = capsule->get_point_b() * wrt_mat;
455 LVector3 from_direction = from_b - from_a;
456
457 LVector3 from_radius_v =
458 LVector3(capsule->get_radius(), 0.0f, 0.0f) * wrt_mat;
459 PN_stdfloat from_radius = length(from_radius_v);
460
461 double t1, t2;
462 if (!intersects_line(t1, t2, from_a, from_direction, from_radius)) {
463 // No intersection.
464 return nullptr;
465 }
466
467 if (t2 < 0.0 || t1 > 1.0) {
468 // Both intersection points are before the start of the capsule or after
469 // the end of the capsule.
470 return nullptr;
471 }
472
473 PN_stdfloat t = (t1 + t2) * (PN_stdfloat)0.5;
474 t = max(t, (PN_stdfloat)0.0);
475 t = min(t, (PN_stdfloat)1.0);
476 LPoint3 inner_point = from_a + t * from_direction;
477
478 if (collide_cat.is_debug()) {
479 collide_cat.debug()
480 << "intersection detected from " << entry.get_from_node_path()
481 << " into " << entry.get_into_node_path() << "\n";
482 }
483 PT(CollisionEntry) new_entry = new CollisionEntry(entry);
484
485 LVector3 normal = inner_point - get_center();
486 normal.normalize();
487 new_entry->set_surface_point(get_center() + normal * get_radius());
488 new_entry->set_interior_point(inner_point - normal * from_radius);
489
491 new_entry->set_surface_normal(get_effective_normal());
492 } else {
493 new_entry->set_surface_normal(normal);
494 }
495
496 return new_entry;
497}
498
499/**
500 *
501 */
502PT(CollisionEntry) CollisionSphere::
503test_intersection_from_parabola(const CollisionEntry &entry) const {
504 const CollisionParabola *parabola;
505 DCAST_INTO_R(parabola, entry.get_from(), nullptr);
506
507 const LMatrix4 &wrt_mat = entry.get_wrt_mat();
508
509 // Convert the parabola into local coordinate space.
510 LParabola local_p(parabola->get_parabola());
511 local_p.xform(wrt_mat);
512
513 double t;
514 if (!intersects_parabola(t, local_p, parabola->get_t1(), parabola->get_t2(),
515 local_p.calc_point(parabola->get_t1()),
516 local_p.calc_point(parabola->get_t2()))) {
517 // No intersection.
518 return nullptr;
519 }
520
521 if (collide_cat.is_debug()) {
522 collide_cat.debug()
523 << "intersection detected from " << entry.get_from_node_path()
524 << " into " << entry.get_into_node_path() << "\n";
525 }
526 PT(CollisionEntry) new_entry = new CollisionEntry(entry);
527
528 LPoint3 into_intersection_point = local_p.calc_point(t);
529 new_entry->set_surface_point(into_intersection_point);
530
532 new_entry->set_surface_normal(get_effective_normal());
533 } else {
534 LVector3 normal = into_intersection_point - get_center();
535 normal.normalize();
536 new_entry->set_surface_normal(normal);
537 }
538
539 return new_entry;
540}
541
542/**
543 * Fills the _viz_geom GeomNode up with Geoms suitable for rendering this
544 * solid.
545 */
546void CollisionSphere::
547fill_viz_geom() {
548 if (collide_cat.is_debug()) {
549 collide_cat.debug()
550 << "Recomputing viz for " << *this << "\n";
551 }
552
553 static const int num_slices = 16;
554 static const int num_stacks = 8;
555
556 PT(GeomVertexData) vdata = new GeomVertexData
557 ("collision", GeomVertexFormat::get_v3(),
558 Geom::UH_static);
559 GeomVertexWriter vertex(vdata, InternalName::get_vertex());
560
561 PT(GeomTristrips) strip = new GeomTristrips(Geom::UH_static);
562 for (int sl = 0; sl < num_slices; ++sl) {
563 PN_stdfloat longitude0 = (PN_stdfloat)sl / (PN_stdfloat)num_slices;
564 PN_stdfloat longitude1 = (PN_stdfloat)(sl + 1) / (PN_stdfloat)num_slices;
565 vertex.add_data3(compute_point(0.0, longitude0));
566 for (int st = 1; st < num_stacks; ++st) {
567 PN_stdfloat latitude = (PN_stdfloat)st / (PN_stdfloat)num_stacks;
568 vertex.add_data3(compute_point(latitude, longitude0));
569 vertex.add_data3(compute_point(latitude, longitude1));
570 }
571 vertex.add_data3(compute_point(1.0, longitude0));
572
573 strip->add_next_vertices(num_stacks * 2);
574 strip->close_primitive();
575 }
576
577 PT(Geom) geom = new Geom(vdata);
578 geom->add_primitive(strip);
579
580 _viz_geom->add_geom(geom, get_solid_viz_state());
581 _bounds_viz_geom->add_geom(geom, get_solid_bounds_viz_state());
582}
583
584/**
585 * Determine the point(s) of intersection of a parametric line with the
586 * sphere. The line is infinite in both directions, and passes through "from"
587 * and from+delta. If the line does not intersect the sphere, the function
588 * returns false, and t1 and t2 are undefined. If it does intersect the
589 * sphere, it returns true, and t1 and t2 are set to the points along the
590 * equation from+t*delta that correspond to the two points of intersection.
591 */
592bool CollisionSphere::
593intersects_line(double &t1, double &t2,
594 const LPoint3 &from, const LVector3 &delta,
595 PN_stdfloat inflate_radius) const {
596 // Solve the equation for the intersection of a line with a sphere using the
597 // quadratic equation.
598
599 // A line segment from f to f+d is defined as all P such that P = f + td for
600 // 0 <= t <= 1.
601
602 // A sphere with radius r about point c is defined as all P such that r^2 =
603 // (P - c)^2.
604
605 // Substituting P in the above we have:
606
607 // r^2 = (f + td - c)^2 = (f^2 + ftd - fc + ftd + t^2d^2 - tdc - fc - tdc +
608 // c^2) = t^2(d^2) + t(fd + fd - dc - dc) + (f^2 - fc - fc + c^2) = t^2(d^2)
609 // + t(2d(f - c)) + (f - c)^2
610
611 // Thus, the equation is quadratic in t, and we have at^2 + bt + c = 0
612
613 // Where a = d^2 b = 2d(f - c) c = (f - c)^2 - r^2
614
615 // Solving for t using the quadratic equation gives us the point of
616 // intersection along the line segment. Actually, there are two solutions
617 // (since it is quadratic): one for the front of the sphere, and one for the
618 // back. In the case where the line is tangent to the sphere, there is only
619 // one solution (and the radical is zero).
620
621 double A = dot(delta, delta);
622
623 LVector3 fc = from - get_center();
624 double fc_d2 = dot(fc, fc);
625 double radius = get_radius() + inflate_radius;
626 double C = fc_d2 - radius * radius;
627
628 if (A == 0.0) {
629 // Degenerate case where delta is zero. This is effectively a test
630 // against a point (or sphere, for nonzero inflate_radius).
631 t1 = 0.0;
632 t2 = 0.0;
633 return C < 0.0;
634 }
635
636 double B = 2.0f * dot(delta, fc);
637 double radical = B*B - 4.0*A*C;
638
639 if (IS_NEARLY_ZERO(radical)) {
640 // Tangent.
641 t1 = t2 = -B /(2.0*A);
642 return true;
643
644 } else if (radical < 0.0) {
645 // No real roots: no intersection with the line.
646 return false;
647 }
648
649 double reciprocal_2A = 1.0/(2.0*A);
650 double sqrt_radical = sqrtf(radical);
651 t1 = ( -B - sqrt_radical ) * reciprocal_2A;
652 t2 = ( -B + sqrt_radical ) * reciprocal_2A;
653
654 return true;
655}
656
657/**
658 * Determine a point of intersection of a parametric parabola with the sphere.
659 *
660 * We only consider the segment of the parabola between t1 and t2, which has
661 * already been computed as corresponding to points p1 and p2. If there is an
662 * intersection, t is set to the parametric point of intersection, and true is
663 * returned; otherwise, false is returned.
664 */
665bool CollisionSphere::
666intersects_parabola(double &t, const LParabola &parabola,
667 double t1, double t2,
668 const LPoint3 &p1, const LPoint3 &p2) const {
669 if (t1 == t2) {
670 // Special case: a single point.
671 if ((p1 - _center).length_squared() > _radius * _radius) {
672 // No intersection.
673 return false;
674 }
675 t = t1;
676 return true;
677 }
678
679 // To directly test for intersection between a parabola (quadratic) and a
680 // sphere (also quadratic) requires solving a quartic equation. Doable, but
681 // hard, and I'm a programmer, not a mathematician. So I'll solve it the
682 // programmer's way instead, by approximating the parabola with a series of
683 // line segments. Hence, this function works by recursively subdividing the
684 // parabola as necessary.
685
686 // First, see if the line segment (p1 - p2) comes sufficiently close to the
687 // parabola. Do this by computing the parametric intervening point and
688 // comparing its distance from the linear intervening point.
689 double tmid = (t1 + t2) * 0.5;
690 if (tmid != t1 && tmid != t2) {
691 LPoint3 pmid = parabola.calc_point(tmid);
692 LPoint3 pmid2 = (p1 + p2) * 0.5f;
693
694 if ((pmid - pmid2).length_squared() > 0.001f) {
695 // Subdivide.
696 if (intersects_parabola(t, parabola, t1, tmid, p1, pmid)) {
697 return true;
698 }
699 return intersects_parabola(t, parabola, tmid, t2, pmid, p2);
700 }
701 }
702
703 // The line segment is sufficiently close; compare the segment itself.
704 double t1a, t2a;
705 if (!intersects_line(t1a, t2a, p1, p2 - p1, 0.0f)) {
706 return false;
707 }
708
709 if (t2a < 0.0 || t1a > 1.0) {
710 return false;
711 }
712
713 t = max(t1a, 0.0);
714 return true;
715}
716
717/**
718 * Returns a point on the surface of the sphere. latitude and longitude range
719 * from 0.0 to 1.0. This is used by fill_viz_geom() to create a visible
720 * representation of the sphere.
721 */
722LVertex CollisionSphere::
723compute_point(PN_stdfloat latitude, PN_stdfloat longitude) const {
724 PN_stdfloat s1, c1;
725 csincos(latitude * MathNumbers::pi, &s1, &c1);
726
727 PN_stdfloat s2, c2;
728 csincos(longitude * 2.0f * MathNumbers::pi, &s2, &c2);
729
730 LVertex p(s1 * c2, s1 * s2, c1);
731 return p * get_radius() + get_center();
732}
733
734/**
735 * Factory method to generate a CollisionSphere object
736 */
739 BamReader::get_factory()->register_factory(get_class_type(), make_CollisionSphere);
740}
741
742/**
743 * Function to write the important information in the particular object to a
744 * Datagram
745 */
747write_datagram(BamWriter *manager, Datagram &me) {
749 _center.write_datagram(me);
750 me.add_stdfloat(_radius);
751}
752
753/**
754 * Factory method to generate a CollisionSphere object
755 */
756TypedWritable *CollisionSphere::
757make_CollisionSphere(const FactoryParams &params) {
759 DatagramIterator scan;
760 BamReader *manager;
761
762 parse_params(params, scan, manager);
763 me->fillin(scan, manager);
764 return me;
765}
766
767/**
768 * Function that reads out of the datagram (or asks manager to read) all of
769 * the data that is needed to re-create this object and stores it in the
770 * appropiate place
771 */
772void CollisionSphere::
773fillin(DatagramIterator& scan, BamReader* manager) {
774 CollisionSolid::fillin(scan, manager);
775 _center.read_datagram(scan);
776 _radius = scan.get_stdfloat();
777}
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void parse_params(const FactoryParams &params, DatagramIterator &scan, BamReader *&manager)
Takes in a FactoryParams, passed from a WritableFactory into any TypedWritable's make function,...
Definition bamReader.I:275
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition bamReader.h:110
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition bamReader.I:177
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition bamWriter.h:63
This defines a bounding sphere, consisting of a center and a radius.
This is an abstract class for any volume in any sense which can be said to define the locality of ref...
A cuboid collision volume or object.
This implements a solid consisting of a cylinder with hemispherical endcaps, also known as a capsule ...
Defines a single collision event.
get_into
Returns the CollisionSolid pointer for the particular solid was collided into.
get_from_node_path
Returns the NodePath that represents the CollisionNode that contains the CollisionSolid that triggere...
get_into_node_path
Returns the NodePath that represents the specific CollisionNode or GeomNode instance that was collide...
get_from
Returns the CollisionSolid pointer for the particular solid that triggered this collision.
An infinite line, similar to a CollisionRay, except that it extends in both directions.
This defines a parabolic arc, or subset of an arc, similar to the path of a projectile or falling obj...
get_t1
Returns the starting point on the parabola.
get_t2
Returns the ending point on the parabola.
get_parabola
Returns the parabola specified by this solid.
An infinite ray, with a specific origin and direction.
A finite line segment, with two specific endpoints but no thickness.
The abstract base class for all things that can collide with other things in the world,...
virtual void write_datagram(BamWriter *manager, Datagram &me)
Function to write the important information in the particular object to a Datagram.
bool has_effective_normal() const
Returns true if a special normal was set by set_effective_normal(), false otherwise.
const LVector3 & get_effective_normal() const
Returns the normal that was set by set_effective_normal().
get_respect_effective_normal
See set_respect_effective_normal().
A spherical collision volume or object.
virtual LPoint3 get_collision_origin() const
Returns the point in space deemed to be the "origin" of the solid for collision purposes.
static void register_with_read_factory()
Factory method to generate a CollisionSphere object.
virtual PStatCollector & get_volume_pcollector()
Returns a PStatCollector that is used to count the number of bounding volume tests made against a sol...
virtual void write_datagram(BamWriter *manager, Datagram &me)
Function to write the important information in the particular object to a Datagram.
virtual PStatCollector & get_test_pcollector()
Returns a PStatCollector that is used to count the number of intersection tests made against a solid ...
A class to retrieve the individual data elements previously stored in a Datagram.
PN_stdfloat get_stdfloat()
Extracts either a 32-bit or a 64-bit floating-point number, according to Datagram::set_stdfloat_doubl...
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition datagram.h:38
void add_stdfloat(PN_stdfloat value)
Adds either a 32-bit or a 64-bit floating-point number, according to set_stdfloat_double().
Definition datagram.I:133
An instance of this class is passed to the Factory when requesting it to do its business and construc...
void register_factory(TypeHandle handle, CreateFunc *func, void *user_data=nullptr)
Registers a new kind of thing the Factory will be able to create.
Definition factory.I:73
Defines a series of triangle strips.
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
static const GeomVertexFormat * get_v3()
Returns a standard vertex format with just a 3-component vertex position.
This object provides a high-level interface for quickly writing a sequence of numeric values from a v...
A container for geometry primitives.
Definition geom.h:54
A lightweight class that represents a single element that may be timed and/or counted via stats.
Indicates a coordinate-system transform on vertices.
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
Base class for objects that can be written to and read from Bam files.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.