Panda3D
 All Classes Functions Variables Enumerations
collisionInvSphere.cxx
1 // Filename: collisionInvSphere.cxx
2 // Created by: drose (05Jan05)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "collisionInvSphere.h"
16 #include "collisionSphere.h"
17 #include "collisionLine.h"
18 #include "collisionRay.h"
19 #include "collisionSegment.h"
20 #include "collisionHandler.h"
21 #include "collisionEntry.h"
22 #include "config_collide.h"
23 #include "omniBoundingVolume.h"
24 #include "datagram.h"
25 #include "datagramIterator.h"
26 #include "bamReader.h"
27 #include "bamWriter.h"
28 #include "nearly_zero.h"
29 #include "geom.h"
30 #include "geomTristrips.h"
31 #include "geomVertexWriter.h"
32 
33 PStatCollector CollisionInvSphere::_volume_pcollector("Collision Volumes:CollisionInvSphere");
34 PStatCollector CollisionInvSphere::_test_pcollector("Collision Tests:CollisionInvSphere");
35 TypeHandle CollisionInvSphere::_type_handle;
36 
37 ////////////////////////////////////////////////////////////////////
38 // Function: CollisionInvSphere::make_copy
39 // Access: Public, Virtual
40 // Description:
41 ////////////////////////////////////////////////////////////////////
42 CollisionSolid *CollisionInvSphere::
43 make_copy() {
44  return new CollisionInvSphere(*this);
45 }
46 
47 ////////////////////////////////////////////////////////////////////
48 // Function: CollisionInvSphere::test_intersection
49 // Access: Public, Virtual
50 // Description:
51 ////////////////////////////////////////////////////////////////////
53 test_intersection(const CollisionEntry &) const {
54  report_undefined_from_intersection(get_type());
55  return NULL;
56 }
57 
58 ////////////////////////////////////////////////////////////////////
59 // Function: CollisionInvSphere::get_volume_pcollector
60 // Access: Public, Virtual
61 // Description: Returns a PStatCollector that is used to count the
62 // number of bounding volume tests made against a solid
63 // of this type in a given frame.
64 ////////////////////////////////////////////////////////////////////
67  return _volume_pcollector;
68 }
69 
70 ////////////////////////////////////////////////////////////////////
71 // Function: CollisionInvSphere::get_test_pcollector
72 // Access: Public, Virtual
73 // Description: Returns a PStatCollector that is used to count the
74 // number of intersection tests made against a solid
75 // of this type in a given frame.
76 ////////////////////////////////////////////////////////////////////
79  return _test_pcollector;
80 }
81 
82 ////////////////////////////////////////////////////////////////////
83 // Function: CollisionInvSphere::output
84 // Access: Public, Virtual
85 // Description:
86 ////////////////////////////////////////////////////////////////////
87 void CollisionInvSphere::
88 output(ostream &out) const {
89  out << "invsphere, c (" << get_center() << "), r " << get_radius();
90 }
91 
92 ////////////////////////////////////////////////////////////////////
93 // Function: CollisionInvSphere::compute_internal_bounds
94 // Access: Protected, Virtual
95 // Description:
96 ////////////////////////////////////////////////////////////////////
98 compute_internal_bounds() const {
99  // An inverse sphere always has an infinite bounding volume, since
100  // everything outside the sphere is solid matter.
101  return new OmniBoundingVolume();
102 }
103 
104 ////////////////////////////////////////////////////////////////////
105 // Function: CollisionInvSphere::test_intersection_from_sphere
106 // Access: Public, Virtual
107 // Description:
108 ////////////////////////////////////////////////////////////////////
109 PT(CollisionEntry) CollisionInvSphere::
110 test_intersection_from_sphere(const CollisionEntry &entry) const {
111  const CollisionSphere *sphere;
112  DCAST_INTO_R(sphere, entry.get_from(), 0);
113 
114  const LMatrix4 &wrt_mat = entry.get_wrt_mat();
115 
116  LPoint3 from_center = sphere->get_center() * wrt_mat;
117  LVector3 from_radius_v =
118  LVector3(sphere->get_radius(), 0.0f, 0.0f) * wrt_mat;
119  PN_stdfloat from_radius = length(from_radius_v);
120 
121  LPoint3 into_center = get_center();
122  PN_stdfloat into_radius = get_radius();
123 
124  LVector3 vec = from_center - into_center;
125  PN_stdfloat dist2 = dot(vec, vec);
126  if (dist2 < (into_radius - from_radius) * (into_radius - from_radius)) {
127  // No intersection--the sphere is within the hollow.
128  return NULL;
129  }
130 
131  if (collide_cat.is_debug()) {
132  collide_cat.debug()
133  << "intersection detected from " << entry.get_from_node_path()
134  << " into " << entry.get_into_node_path() << "\n";
135  }
136  PT(CollisionEntry) new_entry = new CollisionEntry(entry);
137 
138  LVector3 surface_normal;
139  PN_stdfloat vec_length = vec.length();
140  if (IS_NEARLY_ZERO(vec_length)) {
141  // If we don't have a collision normal (e.g. the centers are
142  // exactly coincident), then make up an arbitrary normal--any one
143  // is as good as any other.
144  surface_normal.set(1.0, 0.0, 0.0);
145  } else {
146  surface_normal = vec / -vec_length;
147  }
148 
149  LVector3 normal = (has_effective_normal() && sphere->get_respect_effective_normal()) ? get_effective_normal() : surface_normal;
150 
151  new_entry->set_surface_normal(normal);
152  new_entry->set_surface_point(into_center - surface_normal * into_radius);
153  new_entry->set_interior_point(from_center - surface_normal * from_radius);
154 
155  return new_entry;
156 }
157 
158 ////////////////////////////////////////////////////////////////////
159 // Function: CollisionInvSphere::test_intersection_from_line
160 // Access: Public, Virtual
161 // Description:
162 ////////////////////////////////////////////////////////////////////
163 PT(CollisionEntry) CollisionInvSphere::
164 test_intersection_from_line(const CollisionEntry &entry) const {
165  const CollisionLine *line;
166  DCAST_INTO_R(line, entry.get_from(), 0);
167 
168  const LMatrix4 &wrt_mat = entry.get_wrt_mat();
169 
170  LPoint3 from_origin = line->get_origin() * wrt_mat;
171  LVector3 from_direction = line->get_direction() * wrt_mat;
172 
173  double t1, t2;
174  if (!intersects_line(t1, t2, from_origin, from_direction, 0.0f)) {
175  // The line is in the middle of space, and therefore intersects
176  // the sphere.
177  t1 = t2 = 0.0;
178  }
179 
180  if (collide_cat.is_debug()) {
181  collide_cat.debug()
182  << "intersection detected from " << entry.get_from_node_path()
183  << " into " << entry.get_into_node_path() << "\n";
184  }
185  PT(CollisionEntry) new_entry = new CollisionEntry(entry);
186 
187  LPoint3 into_intersection_point = from_origin + t2 * from_direction;
188  new_entry->set_surface_point(into_intersection_point);
189 
190  if (has_effective_normal() && line->get_respect_effective_normal()) {
191  new_entry->set_surface_normal(get_effective_normal());
192  } else {
193  LVector3 normal = into_intersection_point - get_center();
194  normal.normalize();
195  new_entry->set_surface_normal(-normal);
196  }
197 
198  return new_entry;
199 }
200 
201 ////////////////////////////////////////////////////////////////////
202 // Function: CollisionInvSphere::test_intersection_from_ray
203 // Access: Public, Virtual
204 // Description:
205 ////////////////////////////////////////////////////////////////////
206 PT(CollisionEntry) CollisionInvSphere::
207 test_intersection_from_ray(const CollisionEntry &entry) const {
208  const CollisionRay *ray;
209  DCAST_INTO_R(ray, entry.get_from(), 0);
210 
211  const LMatrix4 &wrt_mat = entry.get_wrt_mat();
212 
213  LPoint3 from_origin = ray->get_origin() * wrt_mat;
214  LVector3 from_direction = ray->get_direction() * wrt_mat;
215 
216  double t1, t2;
217  if (!intersects_line(t1, t2, from_origin, from_direction, 0.0f)) {
218  // The ray is in the middle of space, and therefore intersects
219  // the sphere.
220  t1 = t2 = 0.0;
221  }
222 
223  t2 = max(t2, 0.0);
224 
225  if (collide_cat.is_debug()) {
226  collide_cat.debug()
227  << "intersection detected from " << entry.get_from_node_path()
228  << " into " << entry.get_into_node_path() << "\n";
229  }
230  PT(CollisionEntry) new_entry = new CollisionEntry(entry);
231 
232  LPoint3 into_intersection_point;
233  into_intersection_point = from_origin + t2 * from_direction;
234  new_entry->set_surface_point(into_intersection_point);
235 
236  if (has_effective_normal() && ray->get_respect_effective_normal()) {
237  new_entry->set_surface_normal(get_effective_normal());
238  } else {
239  LVector3 normal = into_intersection_point - get_center();
240  normal.normalize();
241  new_entry->set_surface_normal(-normal);
242  }
243 
244  return new_entry;
245 }
246 
247 ////////////////////////////////////////////////////////////////////
248 // Function: CollisionInvSphere::test_intersection_from_segment
249 // Access: Public, Virtual
250 // Description:
251 ////////////////////////////////////////////////////////////////////
252 PT(CollisionEntry) CollisionInvSphere::
253 test_intersection_from_segment(const CollisionEntry &entry) const {
254  const CollisionSegment *segment;
255  DCAST_INTO_R(segment, entry.get_from(), 0);
256 
257  const LMatrix4 &wrt_mat = entry.get_wrt_mat();
258 
259  LPoint3 from_a = segment->get_point_a() * wrt_mat;
260  LPoint3 from_b = segment->get_point_b() * wrt_mat;
261  LVector3 from_direction = from_b - from_a;
262 
263  double t1, t2;
264  if (!intersects_line(t1, t2, from_a, from_direction, 0.0f)) {
265  // The segment is in the middle of space, and therefore intersects
266  // the sphere.
267  t1 = t2 = 0.0;
268  }
269 
270  double t;
271  if (t2 <= 0.0) {
272  // The segment is completely below the shell.
273  t = 0.0;
274 
275  } else if (t1 >= 1.0) {
276  // The segment is completely above the shell.
277  t = 1.0;
278 
279  } else if (t2 <= 1.0) {
280  // The bottom edge of the segment intersects the shell.
281  t = min(t2, 1.0);
282 
283  } else if (t1 >= 0.0) {
284  // The top edge of the segment intersects the shell.
285  t = max(t1, 0.0);
286 
287  } else {
288  // Neither edge of the segment intersects the shell. It follows
289  // that both intersection points are within the hollow center of
290  // the sphere; therefore, there is no intersection.
291  return NULL;
292  }
293 
294  if (collide_cat.is_debug()) {
295  collide_cat.debug()
296  << "intersection detected from " << entry.get_from_node_path()
297  << " into " << entry.get_into_node_path() << "\n";
298  }
299  PT(CollisionEntry) new_entry = new CollisionEntry(entry);
300 
301  LPoint3 into_intersection_point = from_a + t * from_direction;
302  new_entry->set_surface_point(into_intersection_point);
303 
304  if (has_effective_normal() && segment->get_respect_effective_normal()) {
305  new_entry->set_surface_normal(get_effective_normal());
306  } else {
307  LVector3 normal = into_intersection_point - get_center();
308  normal.normalize();
309  new_entry->set_surface_normal(-normal);
310  }
311 
312  return new_entry;
313 }
314 
315 ////////////////////////////////////////////////////////////////////
316 // Function: CollisionInvSphere::fill_viz_geom
317 // Access: Protected, Virtual
318 // Description: Fills the _viz_geom GeomNode up with Geoms suitable
319 // for rendering this solid.
320 ////////////////////////////////////////////////////////////////////
321 void CollisionInvSphere::
322 fill_viz_geom() {
323  if (collide_cat.is_debug()) {
324  collide_cat.debug()
325  << "Recomputing viz for " << *this << "\n";
326  }
327 
328  static const int num_slices = 16;
329  static const int num_stacks = 8;
330 
331  PT(GeomVertexData) vdata = new GeomVertexData
332  ("collision", GeomVertexFormat::get_v3(),
333  Geom::UH_static);
334  GeomVertexWriter vertex(vdata, InternalName::get_vertex());
335 
336  PT(GeomTristrips) strip = new GeomTristrips(Geom::UH_static);
337  for (int sl = 0; sl < num_slices; ++sl) {
338  PN_stdfloat longitude0 = (PN_stdfloat)sl / (PN_stdfloat)num_slices;
339  PN_stdfloat longitude1 = (PN_stdfloat)(sl + 1) / (PN_stdfloat)num_slices;
340  vertex.add_data3(compute_point(0.0, longitude0));
341  for (int st = 1; st < num_stacks; ++st) {
342  PN_stdfloat latitude = (PN_stdfloat)st / (PN_stdfloat)num_stacks;
343  vertex.add_data3(compute_point(latitude, longitude1));
344  vertex.add_data3(compute_point(latitude, longitude0));
345  }
346  vertex.add_data3(compute_point(1.0, longitude0));
347 
348  strip->add_next_vertices(num_stacks * 2);
349  strip->close_primitive();
350  }
351 
352  PT(Geom) geom = new Geom(vdata);
353  geom->add_primitive(strip);
354 
355  _viz_geom->add_geom(geom, get_solid_viz_state());
356 }
357 
358 ////////////////////////////////////////////////////////////////////
359 // Function: CollisionInvSphere::register_with_read_factory
360 // Access: Public, Static
361 // Description: Factory method to generate a CollisionInvSphere object
362 ////////////////////////////////////////////////////////////////////
363 void CollisionInvSphere::
365  BamReader::get_factory()->register_factory(get_class_type(), make_CollisionInvSphere);
366 }
367 
368 ////////////////////////////////////////////////////////////////////
369 // Function: CollisionInvSphere::write_datagram
370 // Access: Public
371 // Description: Function to write the important information in
372 // the particular object to a Datagram
373 ////////////////////////////////////////////////////////////////////
376  CollisionSphere::write_datagram(manager, me);
377 }
378 
379 ////////////////////////////////////////////////////////////////////
380 // Function: CollisionInvSphere::make_CollisionInvSphere
381 // Access: Protected
382 // Description: Factory method to generate a CollisionInvSphere object
383 ////////////////////////////////////////////////////////////////////
384 TypedWritable *CollisionInvSphere::
385 make_CollisionInvSphere(const FactoryParams &params) {
387  DatagramIterator scan;
388  BamReader *manager;
389 
390  parse_params(params, scan, manager);
391  me->fillin(scan, manager);
392  return me;
393 }
394 
395 ////////////////////////////////////////////////////////////////////
396 // Function: CollisionInvSphere::fillin
397 // Access: Protected
398 // Description: Function that reads out of the datagram (or asks
399 // manager to read) all of the data that is needed to
400 // re-create this object and stores it in the appropiate
401 // place
402 ////////////////////////////////////////////////////////////////////
403 void CollisionInvSphere::
404 fillin(DatagramIterator& scan, BamReader* manager) {
405  CollisionSphere::fillin(scan, manager);
406 }
407 
This object provides a high-level interface for quickly writing a sequence of numeric values from a v...
An infinite ray, with a specific origin and direction.
Definition: collisionRay.h:31
bool get_respect_effective_normal() const
See set_respect_effective_normal().
virtual void write_datagram(BamWriter *manager, Datagram &me)
Function to write the important information in the particular object to a Datagram.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:122
The abstract base class for all things that can collide with other things in the world, and all the things they can collide with (except geometry).
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:37
This is a three-component vector distance (as opposed to a three-component point, which represents a ...
Definition: lvector3.h:100
Defines a series of triangle strips.
Definition: geomTristrips.h:25
This is a three-component point in space (as opposed to a three-component vector, which represents a ...
Definition: lpoint3.h:99
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:73
A spherical collision volume or object.
This is an abstract class for any volume in any sense which can be said to define the locality of ref...
A lightweight class that represents a single element that may be timed and/or counted via stats...
A finite line segment, with two specific endpoints but no thickness.
This is a 4-by-4 transform matrix.
Definition: lmatrix.h:451
Defines a single collision event.
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
A container for geometry primitives.
Definition: geom.h:58
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:40
void register_factory(TypeHandle handle, CreateFunc *func)
Registers a new kind of thing the Factory will be able to create.
Definition: factory.I:90
static void register_with_read_factory()
Factory method to generate a CollisionInvSphere object.
void add_next_vertices(int num_vertices)
Adds the next n vertices in sequence, beginning from the last vertex added to the primitive + 1...
An infinite line, similar to a CollisionRay, except that it extends in both directions.
Definition: collisionLine.h:28
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:213
virtual PStatCollector & get_volume_pcollector()
Returns a PStatCollector that is used to count the number of bounding volume tests made against a sol...
This is a special kind of GeometricBoundingVolume that fills all of space.
A class to retrieve the individual data elements previously stored in a Datagram. ...
virtual void write_datagram(BamWriter *manager, Datagram &me)
Function to write the important information in the particular object to a Datagram.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
bool normalize()
Normalizes the vector in place.
Definition: lvecBase3.h:782
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:43
An inverted sphere: this is a sphere whose collision surface is the inside surface of the sphere...
virtual PStatCollector & get_test_pcollector()
Returns a PStatCollector that is used to count the number of intersection tests made against a solid ...