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 */
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 CPT(TransformState) wrt_space = entry.get_wrt_space();
240 const LMatrix4 &wrt_mat = wrt_space->get_mat();
241
242 LPoint3 from_origin = line->get_origin() * wrt_mat;
243 LVector3 from_direction = line->get_direction() * wrt_mat;
244
245 double t1, t2;
246 if (!intersects_line(t1, t2, from_origin, from_direction, 0.0f)) {
247 // No intersection.
248 return nullptr;
249 }
250
251 if (collide_cat.is_debug()) {
252 collide_cat.debug()
253 << "intersection detected from " << entry.get_from_node_path()
254 << " into " << entry.get_into_node_path() << "\n";
255 }
256 PT(CollisionEntry) new_entry = new CollisionEntry(entry);
257
258 LPoint3 into_intersection_point = from_origin + t1 * from_direction;
259 new_entry->set_surface_point(into_intersection_point);
260
262 new_entry->set_surface_normal(get_effective_normal());
263 } else {
264 LVector3 normal = into_intersection_point - get_center();
265 normal.normalize();
266 new_entry->set_surface_normal(normal);
267 }
268
269 return new_entry;
270}
271
272/**
273 * Double dispatch point for box as a FROM object
274 */
275PT(CollisionEntry) CollisionSphere::
276test_intersection_from_box(const CollisionEntry &entry) const {
277 const CollisionBox *box;
278 DCAST_INTO_R(box, entry.get_from(), nullptr);
279
280 // Instead of transforming the box into the sphere's coordinate space, we do
281 // it the other way around. It's easier that way.
282 CPT(TransformState) inv_wrt_space = entry.get_inv_wrt_space();
283 const LMatrix4 &inv_wrt_mat = inv_wrt_space->get_mat();
284
285 LPoint3 center = inv_wrt_mat.xform_point(_center);
286 PN_stdfloat radius_sq = inv_wrt_mat.xform_vec(LVector3(0, 0, _radius)).length_squared();
287
288 LPoint3 box_min = box->get_min();
289 LPoint3 box_max = box->get_max();
290
291 // Arvo's algorithm.
292 PN_stdfloat d = 0;
293 PN_stdfloat s;
294
295 if (center[0] < box_min[0]) {
296 s = center[0] - box_min[0];
297 d += s * s;
298
299 } else if (center[0] > box_max[0]) {
300 s = center[0] - box_max[0];
301 d += s * s;
302 }
303
304 if (center[1] < box_min[1]) {
305 s = center[1] - box_min[1];
306 d += s * s;
307
308 } else if (center[1] > box_max[1]) {
309 s = center[1] - box_max[1];
310 d += s * s;
311 }
312
313 if (center[2] < box_min[2]) {
314 s = center[2] - box_min[2];
315 d += s * s;
316
317 } else if (center[2] > box_max[2]) {
318 s = center[2] - box_max[2];
319 d += s * s;
320 }
321
322 if (d > radius_sq) {
323 return nullptr;
324 }
325
326 if (collide_cat.is_debug()) {
327 collide_cat.debug()
328 << "intersection detected from " << entry.get_from_node_path()
329 << " into " << entry.get_into_node_path() << "\n";
330 }
331
332 PT(CollisionEntry) new_entry = new CollisionEntry(entry);
333
334 // To get the interior point, clamp the sphere center to the AABB.
335 CPT(TransformState) wrt_space = entry.get_wrt_space();
336 LPoint3 interior = wrt_space->get_mat().xform_point(center.fmax(box_min).fmin(box_max));
337 new_entry->set_interior_point(interior);
338
339 // Now extrapolate the surface point and normal from that.
340 LVector3 normal = interior - _center;
341 normal.normalize();
342 new_entry->set_surface_point(_center + normal * _radius);
343 new_entry->set_surface_normal(
345 ? get_effective_normal() : normal);
346
347 return new_entry;
348}
349
350/**
351 *
352 */
353PT(CollisionEntry) CollisionSphere::
354test_intersection_from_ray(const CollisionEntry &entry) const {
355 const CollisionRay *ray;
356 DCAST_INTO_R(ray, entry.get_from(), nullptr);
357
358 CPT(TransformState) wrt_space = entry.get_wrt_space();
359 const LMatrix4 &wrt_mat = wrt_space->get_mat();
360
361 LPoint3 from_origin = ray->get_origin() * wrt_mat;
362 LVector3 from_direction = ray->get_direction() * wrt_mat;
363
364 double t1, t2;
365 if (!intersects_line(t1, t2, from_origin, from_direction, 0.0f)) {
366 // No intersection.
367 return nullptr;
368 }
369
370 if (t2 < 0.0) {
371 // Both intersection points are before the start of the ray.
372 return nullptr;
373 }
374
375 t1 = max(t1, 0.0);
376
377 if (collide_cat.is_debug()) {
378 collide_cat.debug()
379 << "intersection detected from " << entry.get_from_node_path()
380 << " into " << entry.get_into_node_path() << "\n";
381 }
382 PT(CollisionEntry) new_entry = new CollisionEntry(entry);
383
384 LPoint3 into_intersection_point = from_origin + t1 * from_direction;
385 new_entry->set_surface_point(into_intersection_point);
386
388 new_entry->set_surface_normal(get_effective_normal());
389 } else {
390 LVector3 normal = into_intersection_point - get_center();
391 normal.normalize();
392 new_entry->set_surface_normal(normal);
393 }
394
395 return new_entry;
396}
397
398/**
399 *
400 */
401PT(CollisionEntry) CollisionSphere::
402test_intersection_from_segment(const CollisionEntry &entry) const {
403 const CollisionSegment *segment;
404 DCAST_INTO_R(segment, entry.get_from(), nullptr);
405
406 CPT(TransformState) wrt_space = entry.get_wrt_space();
407 const LMatrix4 &wrt_mat = wrt_space->get_mat();
408
409 LPoint3 from_a = segment->get_point_a() * wrt_mat;
410 LPoint3 from_b = segment->get_point_b() * wrt_mat;
411 LVector3 from_direction = from_b - from_a;
412
413 double t1, t2;
414 if (!intersects_line(t1, t2, from_a, from_direction, 0.0f)) {
415 // No intersection.
416 return nullptr;
417 }
418
419 if (t2 < 0.0 || t1 > 1.0) {
420 // Both intersection points are before the start of the segment or after
421 // the end of the segment.
422 return nullptr;
423 }
424
425 t1 = max(t1, 0.0);
426
427 if (collide_cat.is_debug()) {
428 collide_cat.debug()
429 << "intersection detected from " << entry.get_from_node_path()
430 << " into " << entry.get_into_node_path() << "\n";
431 }
432 PT(CollisionEntry) new_entry = new CollisionEntry(entry);
433
434 LPoint3 into_intersection_point = from_a + t1 * from_direction;
435 new_entry->set_surface_point(into_intersection_point);
436
438 new_entry->set_surface_normal(get_effective_normal());
439 } else {
440 LVector3 normal = into_intersection_point - get_center();
441 normal.normalize();
442 new_entry->set_surface_normal(normal);
443 }
444
445 return new_entry;
446}
447
448/**
449 *
450 */
451PT(CollisionEntry) CollisionSphere::
452test_intersection_from_capsule(const CollisionEntry &entry) const {
453 const CollisionCapsule *capsule;
454 DCAST_INTO_R(capsule, entry.get_from(), nullptr);
455
456 CPT(TransformState) wrt_space = entry.get_wrt_space();
457 const LMatrix4 &wrt_mat = wrt_space->get_mat();
458
459 LPoint3 from_a = capsule->get_point_a() * wrt_mat;
460 LPoint3 from_b = capsule->get_point_b() * wrt_mat;
461 LVector3 from_direction = from_b - from_a;
462
463 LVector3 from_radius_v =
464 LVector3(capsule->get_radius(), 0.0f, 0.0f) * wrt_mat;
465 PN_stdfloat from_radius = length(from_radius_v);
466
467 double t1, t2;
468 if (!intersects_line(t1, t2, from_a, from_direction, from_radius)) {
469 // No intersection.
470 return nullptr;
471 }
472
473 if (t2 < 0.0 || t1 > 1.0) {
474 // Both intersection points are before the start of the capsule or after
475 // the end of the capsule.
476 return nullptr;
477 }
478
479 PN_stdfloat t = (t1 + t2) * (PN_stdfloat)0.5;
480 t = max(t, (PN_stdfloat)0.0);
481 t = min(t, (PN_stdfloat)1.0);
482 LPoint3 inner_point = from_a + t * from_direction;
483
484 if (collide_cat.is_debug()) {
485 collide_cat.debug()
486 << "intersection detected from " << entry.get_from_node_path()
487 << " into " << entry.get_into_node_path() << "\n";
488 }
489 PT(CollisionEntry) new_entry = new CollisionEntry(entry);
490
491 LVector3 normal = inner_point - get_center();
492 normal.normalize();
493 new_entry->set_surface_point(get_center() + normal * get_radius());
494 new_entry->set_interior_point(inner_point - normal * from_radius);
495
497 new_entry->set_surface_normal(get_effective_normal());
498 } else {
499 new_entry->set_surface_normal(normal);
500 }
501
502 return new_entry;
503}
504
505/**
506 *
507 */
508PT(CollisionEntry) CollisionSphere::
509test_intersection_from_parabola(const CollisionEntry &entry) const {
510 const CollisionParabola *parabola;
511 DCAST_INTO_R(parabola, entry.get_from(), nullptr);
512
513 CPT(TransformState) wrt_space = entry.get_wrt_space();
514 const LMatrix4 &wrt_mat = wrt_space->get_mat();
515
516 // Convert the parabola into local coordinate space.
517 LParabola local_p(parabola->get_parabola());
518 local_p.xform(wrt_mat);
519
520 double t;
521 if (!intersects_parabola(t, local_p, parabola->get_t1(), parabola->get_t2(),
522 local_p.calc_point(parabola->get_t1()),
523 local_p.calc_point(parabola->get_t2()))) {
524 // No intersection.
525 return nullptr;
526 }
527
528 if (collide_cat.is_debug()) {
529 collide_cat.debug()
530 << "intersection detected from " << entry.get_from_node_path()
531 << " into " << entry.get_into_node_path() << "\n";
532 }
533 PT(CollisionEntry) new_entry = new CollisionEntry(entry);
534
535 LPoint3 into_intersection_point = local_p.calc_point(t);
536 new_entry->set_surface_point(into_intersection_point);
537
539 new_entry->set_surface_normal(get_effective_normal());
540 } else {
541 LVector3 normal = into_intersection_point - get_center();
542 normal.normalize();
543 new_entry->set_surface_normal(normal);
544 }
545
546 return new_entry;
547}
548
549/**
550 * Fills the _viz_geom GeomNode up with Geoms suitable for rendering this
551 * solid.
552 */
553void CollisionSphere::
554fill_viz_geom() {
555 if (collide_cat.is_debug()) {
556 collide_cat.debug()
557 << "Recomputing viz for " << *this << "\n";
558 }
559
560 static const int num_slices = 16;
561 static const int num_stacks = 8;
562
563 PT(GeomVertexData) vdata = new GeomVertexData
564 ("collision", GeomVertexFormat::get_v3(),
565 Geom::UH_static);
566 GeomVertexWriter vertex(vdata, InternalName::get_vertex());
567
568 PT(GeomTristrips) strip = new GeomTristrips(Geom::UH_static);
569 for (int sl = 0; sl < num_slices; ++sl) {
570 PN_stdfloat longitude0 = (PN_stdfloat)sl / (PN_stdfloat)num_slices;
571 PN_stdfloat longitude1 = (PN_stdfloat)(sl + 1) / (PN_stdfloat)num_slices;
572 vertex.add_data3(compute_point(0.0, longitude0));
573 for (int st = 1; st < num_stacks; ++st) {
574 PN_stdfloat latitude = (PN_stdfloat)st / (PN_stdfloat)num_stacks;
575 vertex.add_data3(compute_point(latitude, longitude0));
576 vertex.add_data3(compute_point(latitude, longitude1));
577 }
578 vertex.add_data3(compute_point(1.0, longitude0));
579
580 strip->add_next_vertices(num_stacks * 2);
581 strip->close_primitive();
582 }
583
584 PT(Geom) geom = new Geom(vdata);
585 geom->add_primitive(strip);
586
587 _viz_geom->add_geom(geom, get_solid_viz_state());
588 _bounds_viz_geom->add_geom(geom, get_solid_bounds_viz_state());
589}
590
591/**
592 * Determine the point(s) of intersection of a parametric line with the
593 * sphere. The line is infinite in both directions, and passes through "from"
594 * and from+delta. If the line does not intersect the sphere, the function
595 * returns false, and t1 and t2 are undefined. If it does intersect the
596 * sphere, it returns true, and t1 and t2 are set to the points along the
597 * equation from+t*delta that correspond to the two points of intersection.
598 */
599bool CollisionSphere::
600intersects_line(double &t1, double &t2,
601 const LPoint3 &from, const LVector3 &delta,
602 PN_stdfloat inflate_radius) const {
603 // Solve the equation for the intersection of a line with a sphere using the
604 // quadratic equation.
605
606 // A line segment from f to f+d is defined as all P such that P = f + td for
607 // 0 <= t <= 1.
608
609 // A sphere with radius r about point c is defined as all P such that r^2 =
610 // (P - c)^2.
611
612 // Substituting P in the above we have:
613
614 // r^2 = (f + td - c)^2 = (f^2 + ftd - fc + ftd + t^2d^2 - tdc - fc - tdc +
615 // c^2) = t^2(d^2) + t(fd + fd - dc - dc) + (f^2 - fc - fc + c^2) = t^2(d^2)
616 // + t(2d(f - c)) + (f - c)^2
617
618 // Thus, the equation is quadratic in t, and we have at^2 + bt + c = 0
619
620 // Where a = d^2 b = 2d(f - c) c = (f - c)^2 - r^2
621
622 // Solving for t using the quadratic equation gives us the point of
623 // intersection along the line segment. Actually, there are two solutions
624 // (since it is quadratic): one for the front of the sphere, and one for the
625 // back. In the case where the line is tangent to the sphere, there is only
626 // one solution (and the radical is zero).
627
628 double A = dot(delta, delta);
629
630 LVector3 fc = from - get_center();
631 double fc_d2 = dot(fc, fc);
632 double radius = get_radius() + inflate_radius;
633 double C = fc_d2 - radius * radius;
634
635 if (A == 0.0) {
636 // Degenerate case where delta is zero. This is effectively a test
637 // against a point (or sphere, for nonzero inflate_radius).
638 t1 = 0.0;
639 t2 = 0.0;
640 return C < 0.0;
641 }
642
643 double B = 2.0f * dot(delta, fc);
644 double radical = B*B - 4.0*A*C;
645
646 if (IS_NEARLY_ZERO(radical)) {
647 // Tangent.
648 t1 = t2 = -B /(2.0*A);
649 return true;
650
651 } else if (radical < 0.0) {
652 // No real roots: no intersection with the line.
653 return false;
654 }
655
656 double reciprocal_2A = 1.0/(2.0*A);
657 double sqrt_radical = sqrtf(radical);
658 t1 = ( -B - sqrt_radical ) * reciprocal_2A;
659 t2 = ( -B + sqrt_radical ) * reciprocal_2A;
660
661 return true;
662}
663
664/**
665 * Determine a point of intersection of a parametric parabola with the sphere.
666 *
667 * We only consider the segment of the parabola between t1 and t2, which has
668 * already been computed as corresponding to points p1 and p2. If there is an
669 * intersection, t is set to the parametric point of intersection, and true is
670 * returned; otherwise, false is returned.
671 */
672bool CollisionSphere::
673intersects_parabola(double &t, const LParabola &parabola,
674 double t1, double t2,
675 const LPoint3 &p1, const LPoint3 &p2) const {
676 if (t1 == t2) {
677 // Special case: a single point.
678 if ((p1 - _center).length_squared() > _radius * _radius) {
679 // No intersection.
680 return false;
681 }
682 t = t1;
683 return true;
684 }
685
686 // To directly test for intersection between a parabola (quadratic) and a
687 // sphere (also quadratic) requires solving a quartic equation. Doable, but
688 // hard, and I'm a programmer, not a mathematician. So I'll solve it the
689 // programmer's way instead, by approximating the parabola with a series of
690 // line segments. Hence, this function works by recursively subdividing the
691 // parabola as necessary.
692
693 // First, see if the line segment (p1 - p2) comes sufficiently close to the
694 // parabola. Do this by computing the parametric intervening point and
695 // comparing its distance from the linear intervening point.
696 double tmid = (t1 + t2) * 0.5;
697 if (tmid != t1 && tmid != t2) {
698 LPoint3 pmid = parabola.calc_point(tmid);
699 LPoint3 pmid2 = (p1 + p2) * 0.5f;
700
701 if ((pmid - pmid2).length_squared() > 0.001f) {
702 // Subdivide.
703 if (intersects_parabola(t, parabola, t1, tmid, p1, pmid)) {
704 return true;
705 }
706 return intersects_parabola(t, parabola, tmid, t2, pmid, p2);
707 }
708 }
709
710 // The line segment is sufficiently close; compare the segment itself.
711 double t1a, t2a;
712 if (!intersects_line(t1a, t2a, p1, p2 - p1, 0.0f)) {
713 return false;
714 }
715
716 if (t2a < 0.0 || t1a > 1.0) {
717 return false;
718 }
719
720 t = max(t1a, 0.0);
721 return true;
722}
723
724/**
725 * Returns a point on the surface of the sphere. latitude and longitude range
726 * from 0.0 to 1.0. This is used by fill_viz_geom() to create a visible
727 * representation of the sphere.
728 */
729LVertex CollisionSphere::
730compute_point(PN_stdfloat latitude, PN_stdfloat longitude) const {
731 PN_stdfloat s1, c1;
732 csincos(latitude * MathNumbers::pi, &s1, &c1);
733
734 PN_stdfloat s2, c2;
735 csincos(longitude * 2.0f * MathNumbers::pi, &s2, &c2);
736
737 LVertex p(s1 * c2, s1 * s2, c1);
738 return p * get_radius() + get_center();
739}
740
741/**
742 * Factory method to generate a CollisionSphere object
743 */
746 BamReader::get_factory()->register_factory(get_class_type(), make_CollisionSphere);
747}
748
749/**
750 * Function to write the important information in the particular object to a
751 * Datagram
752 */
754write_datagram(BamWriter *manager, Datagram &me) {
756 _center.write_datagram(me);
757 me.add_stdfloat(_radius);
758}
759
760/**
761 * Factory method to generate a CollisionSphere object
762 */
763TypedWritable *CollisionSphere::
764make_CollisionSphere(const FactoryParams &params) {
766 DatagramIterator scan;
767 BamReader *manager;
768
769 parse_params(params, scan, manager);
770 me->fillin(scan, manager);
771 return me;
772}
773
774/**
775 * Function that reads out of the datagram (or asks manager to read) all of
776 * the data that is needed to re-create this object and stores it in the
777 * appropiate place
778 */
779void CollisionSphere::
780fillin(DatagramIterator& scan, BamReader* manager) {
781 CollisionSolid::fillin(scan, manager);
782 _center.read_datagram(scan);
783 _radius = scan.get_stdfloat();
784}
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 is an abstract class for any volume in any sense which can be said to define the locality of ref...
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.
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.
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 void xform(const LMatrix4 &mat)
Transforms the solid by the indicated matrix.
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
static const GeomVertexFormat * get_v3()
Returns a standard vertex format with just a 3-component vertex position.
A lightweight class that represents a single element that may be timed and/or counted via stats.
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.
STTransform::operator CPT TransformState() const
This is used internally to convert an STTransform into a TransformState pointer.
Definition stTransform.I:98