Oolite 1.91.0.7644-241112-7f5034b
Loading...
Searching...
No Matches
Octree Class Reference

#include <Octree.h>

+ Inheritance diagram for Octree:
+ Collaboration diagram for Octree:

Instance Methods

(id) - initWithDictionary:
 
(Octree *) - octreeScaledBy:
 
(void) - drawOctree
 
(void) - drawOctreeCollisions
 
(GLfloat) - isHitByLine:v0:
 
(BOOL) - isHitByOctree:withOrigin:andIJK:
 
(BOOL) - isHitByOctree:withOrigin:andIJK:andScales:s1:
 
(NSDictionary *) - dictionaryRepresentation
 
(GLfloat) - volume
 
(Vector) - randomPoint
 
(size_t) - totalSize
 
(id) - init [implementation]
 
(id) - initWithData:radius: [implementation]
 
(void) - dealloc [implementation]
 
(BOOL) - hasCollision [implementation]
 
(void) - setHasCollision: [implementation]
 
(Octree_details- octreeDetails [implementation]
 
(void) - drawOctreeFromLocation:loc:scale: [implementation]
 
(void) - drawOctreeCollisionFromLocation:loc:scale: [implementation]
 

Class Methods

(static Vector) + offsetForOctant [implementation]
 
(static BOOL) + isHitByLineSub [implementation]
 
(static BOOL) + isHitByLine [implementation]
 
(static BOOL) + isHitByOctree [implementation]
 
(static GLfloat) + volumeOfOctree [implementation]
 
(static Vector) + randomFullNodeFrom [implementation]
 

Private Attributes

GLfloat _radius
 
uint32_t _nodeCount
 
const int_octree
 
BOOL _hasCollision
 
unsigned char * _collisionOctree
 
NSData * _data
 

Detailed Description

Definition at line 39 of file Octree.h.

Method Documentation

◆ dealloc

- (void) dealloc
implementation

Definition at line 47 of file Octree.m.

131{
132 DESTROY(_data);
133 free(_collisionOctree);
134
135 [super dealloc];
136}
#define DESTROY(x)
Definition OOCocoa.h:77
unsigned char * _collisionOctree
Definition Octree.h:47
NSData * _data
Definition Octree.h:49

◆ dictionaryRepresentation

- (NSDictionary *) dictionaryRepresentation

Definition at line 497 of file Octree.m.

668{
669 return [NSDictionary dictionaryWithObjectsAndKeys:
670 _data, @"octree",
671 [NSNumber numberWithFloat:_radius], @"radius",
672 nil];
673}

References change_oct, isHitByOctree(), Octree_details::octree, Octree_details::octree_collision, OctreeDebugLog, and Octree_details::radius.

+ Here is the call graph for this function:

◆ drawOctree

- (void) drawOctree

Definition at line 170 of file Octree.m.

179{
181
183 OOGL(glEnable(GL_BLEND));
184 OOGLBEGIN(GL_LINES);
185 glColor4f(0.4f, 0.4f, 0.4f, 0.5f);
186
187 // it's a series of cubes
188 [self drawOctreeFromLocation:0 :_radius : kZeroVector];
189
190 OOGLEND();
191
192 OODebugEndWireframe(state);
193 OOCheckOpenGLErrors(@"Octree after drawing %@", self);
194}
void OODebugEndWireframe(OODebugWFState state)
OODebugWFState OODebugBeginWireframe(BOOL ignoreZ)
#define OO_ENTER_OPENGL()
#define OOGLBEGIN
Definition OOOpenGL.h:253
BOOL OOCheckOpenGLErrors(NSString *format,...)
Definition OOOpenGL.m:39
#define OOGL(statement)
Definition OOOpenGL.h:251
#define OOGLEND
Definition OOOpenGL.h:254

◆ drawOctreeCollisionFromLocation:loc:scale:

- (void) drawOctreeCollisionFromLocation: (uint32_t)
loc: (GLfloat)
scale: (Vector) offset 
implementation

Provided by category Octree(Private).

Definition at line 270 of file Octree.m.

289 :(uint32_t)loc :(GLfloat)scale :(Vector)offset
290{
291 if (_octree[loc] == 0)
292 {
293 return;
294 }
295
296 if ((_octree[loc] != 0)&&(_collisionOctree[loc] != (unsigned char)0)) // full - draw
297 {
299
300 GLfloat red = (GLfloat)(_collisionOctree[loc])/255.0;
301 glColor4f(1.0, 0.0, 0.0, red); // 50% translucent
302
304 _collisionOctree[loc]--;
305
306 // draw a cube
307 OOGL(glDisable(GL_CULL_FACE)); // face culling
308
309 OOGL(glDisable(GL_TEXTURE_2D));
310
311 OOGLBEGIN(GL_LINE_STRIP);
312 glVertex3f(-scale + offset.x, -scale + offset.y, -scale + offset.z);
313 glVertex3f(-scale + offset.x, scale + offset.y, -scale + offset.z);
314 glVertex3f(scale + offset.x, scale + offset.y, -scale + offset.z);
315 glVertex3f(scale + offset.x, -scale + offset.y, -scale + offset.z);
316 glVertex3f(-scale + offset.x, -scale + offset.y, -scale + offset.z);
317 OOGLEND();
318
319 OOGLBEGIN(GL_LINE_STRIP);
320 glVertex3f(-scale + offset.x, -scale + offset.y, scale + offset.z);
321 glVertex3f(-scale + offset.x, scale + offset.y, scale + offset.z);
322 glVertex3f(scale + offset.x, scale + offset.y, scale + offset.z);
323 glVertex3f(scale + offset.x, -scale + offset.y, scale + offset.z);
324 glVertex3f(-scale + offset.x, -scale + offset.y, scale + offset.z);
325 OOGLEND();
326
327 OOGLBEGIN(GL_LINES);
328 glVertex3f(-scale + offset.x, -scale + offset.y, -scale + offset.z);
329 glVertex3f(-scale + offset.x, -scale + offset.y, scale + offset.z);
330
331 glVertex3f(-scale + offset.x, scale + offset.y, -scale + offset.z);
332 glVertex3f(-scale + offset.x, scale + offset.y, scale + offset.z);
333
334 glVertex3f(scale + offset.x, scale + offset.y, -scale + offset.z);
335 glVertex3f(scale + offset.x, scale + offset.y, scale + offset.z);
336
337 glVertex3f(scale + offset.x, -scale + offset.y, -scale + offset.z);
338 glVertex3f(scale + offset.x, -scale + offset.y, scale + offset.z);
339 OOGLEND();
340
341 OOGL(glEnable(GL_CULL_FACE)); // face culling
342 }
343 if (_octree[loc] > 0)
344 {
345 GLfloat sc = 0.5f * scale;
346 [self drawOctreeCollisionFromLocation:loc + _octree[loc] + 0 :sc :make_vector(offset.x - sc, offset.y - sc, offset.z - sc)];
347 [self drawOctreeCollisionFromLocation:loc + _octree[loc] + 1 :sc :make_vector(offset.x - sc, offset.y - sc, offset.z + sc)];
348 [self drawOctreeCollisionFromLocation:loc + _octree[loc] + 2 :sc :make_vector(offset.x - sc, offset.y + sc, offset.z - sc)];
349 [self drawOctreeCollisionFromLocation:loc + _octree[loc] + 3 :sc :make_vector(offset.x - sc, offset.y + sc, offset.z + sc)];
350 [self drawOctreeCollisionFromLocation:loc + _octree[loc] + 4 :sc :make_vector(offset.x + sc, offset.y - sc, offset.z - sc)];
351 [self drawOctreeCollisionFromLocation:loc + _octree[loc] + 5 :sc :make_vector(offset.x + sc, offset.y - sc, offset.z + sc)];
352 [self drawOctreeCollisionFromLocation:loc + _octree[loc] + 6 :sc :make_vector(offset.x + sc, offset.y + sc, offset.z - sc)];
353 [self drawOctreeCollisionFromLocation:loc + _octree[loc] + 7 :sc :make_vector(offset.x + sc, offset.y + sc, offset.z + sc)];
354 }
355}
static BOOL drawTestForCollisions
Definition Octree.m:270
const int * _octree
Definition Octree.h:44
voidpf uLong offset
Definition ioapi.h:140

References drawTestForCollisions, OOCheckOpenGLErrors(), OODebugBeginWireframe(), and OODebugEndWireframe().

+ Here is the call graph for this function:

◆ drawOctreeCollisions

- (void) drawOctreeCollisions

Definition at line 270 of file Octree.m.

273{
275
276 // it's a series of cubes
278 if (_hasCollision)
279 {
280 [self drawOctreeCollisionFromLocation:0 :_radius :kZeroVector];
281 }
283
284 OODebugEndWireframe(state);
285 OOCheckOpenGLErrors(@"Octree after drawing collisions for %@", self);
286}
BOOL _hasCollision
Definition Octree.h:45

◆ drawOctreeFromLocation:loc:scale:

- (void) drawOctreeFromLocation: (uint32_t)
loc: (GLfloat)
scale: (Vector) offset 
implementation

Provided by category Octree(Private).

Definition at line 170 of file Octree.m.

204 :(uint32_t)loc :(GLfloat)scale :(Vector)offset
205{
206 if (_octree[loc] == 0)
207 {
208 return;
209 }
210
212
213 if (_octree[loc] == -1) // full
214 {
215 // draw a cube
216 glVertex3f(-scale + offset.x, -scale + offset.y, -scale + offset.z);
217 glVertex3f(-scale + offset.x, scale + offset.y, -scale + offset.z);
218 glVertex3f(-scale + offset.x, scale + offset.y, -scale + offset.z);
219 glVertex3f(scale + offset.x, scale + offset.y, -scale + offset.z);
220 glVertex3f(scale + offset.x, scale + offset.y, -scale + offset.z);
221 glVertex3f(scale + offset.x, -scale + offset.y, -scale + offset.z);
222 glVertex3f(scale + offset.x, -scale + offset.y, -scale + offset.z);
223 glVertex3f(-scale + offset.x, -scale + offset.y, -scale + offset.z);
224
225
226 glVertex3f(-scale + offset.x, -scale + offset.y, scale + offset.z);
227 glVertex3f(-scale + offset.x, scale + offset.y, scale + offset.z);
228 glVertex3f(-scale + offset.x, scale + offset.y, scale + offset.z);
229 glVertex3f(scale + offset.x, scale + offset.y, scale + offset.z);
230 glVertex3f(scale + offset.x, scale + offset.y, scale + offset.z);
231 glVertex3f(scale + offset.x, -scale + offset.y, scale + offset.z);
232 glVertex3f(scale + offset.x, -scale + offset.y, scale + offset.z);
233 glVertex3f(-scale + offset.x, -scale + offset.y, scale + offset.z);
234
235 glVertex3f(-scale + offset.x, -scale + offset.y, -scale + offset.z);
236 glVertex3f(-scale + offset.x, -scale + offset.y, scale + offset.z);
237
238 glVertex3f(-scale + offset.x, scale + offset.y, -scale + offset.z);
239 glVertex3f(-scale + offset.x, scale + offset.y, scale + offset.z);
240
241 glVertex3f(scale + offset.x, scale + offset.y, -scale + offset.z);
242 glVertex3f(scale + offset.x, scale + offset.y, scale + offset.z);
243
244 glVertex3f(scale + offset.x, -scale + offset.y, -scale + offset.z);
245 glVertex3f(scale + offset.x, -scale + offset.y, scale + offset.z);
246 }
247 else if (_octree[loc] > 0)
248 {
249 GLfloat sc = 0.5f * scale;
250 OCTREE_COLOR(0.4f, 0.4f, 0.4f, 0.5f);
251 [self drawOctreeFromLocation:loc + _octree[loc] + 0 :sc :make_vector(offset.x - sc, offset.y - sc, offset.z - sc)];
252 OCTREE_COLOR(0.0f, 0.0f, 1.0f, 0.5f);
253 [self drawOctreeFromLocation:loc + _octree[loc] + 1 :sc :make_vector(offset.x - sc, offset.y - sc, offset.z + sc)];
254 OCTREE_COLOR(0.0f, 1.0f, 0.0f, 0.5f);
255 [self drawOctreeFromLocation:loc + _octree[loc] + 2 :sc :make_vector(offset.x - sc, offset.y + sc, offset.z - sc)];
256 OCTREE_COLOR(0.0f, 1.0f, 1.0f, 0.5f);
257 [self drawOctreeFromLocation:loc + _octree[loc] + 3 :sc :make_vector(offset.x - sc, offset.y + sc, offset.z + sc)];
258 OCTREE_COLOR(1.0f, 0.0f, 0.0f, 0.5f);
259 [self drawOctreeFromLocation:loc + _octree[loc] + 4 :sc :make_vector(offset.x + sc, offset.y - sc, offset.z - sc)];
260 OCTREE_COLOR(1.0f, 0.0f, 1.0f, 0.5f);
261 [self drawOctreeFromLocation:loc + _octree[loc] + 5 :sc :make_vector(offset.x + sc, offset.y - sc, offset.z + sc)];
262 OCTREE_COLOR(1.0f, 1.0f, 0.0f, 0.5f);
263 [self drawOctreeFromLocation:loc + _octree[loc] + 6 :sc :make_vector(offset.x + sc, offset.y + sc, offset.z - sc)];
264 OCTREE_COLOR(1.0f, 1.0f, 1.0f, 0.5f);
265 [self drawOctreeFromLocation:loc + _octree[loc] + 7 :sc :make_vector(offset.x + sc, offset.y + sc, offset.z + sc)];
266 }
267}
#define OCTREE_COLOR(r, g, b, a)
Definition Octree.m:200

◆ hasCollision

- (BOOL) hasCollision
implementation

Provided by category Octree(Private).

Definition at line 47 of file Octree.m.

140{
141 return _hasCollision;
142}

◆ init

- (id) init
implementation

Definition at line 47 of file Octree.m.

81{
82 // -init makes no sense, since octrees are immutable.
83 [self release];
84 [NSException raise:NSInternalInconsistencyException format:@"Call of invalid initializer %s", __FUNCTION__];
85 return nil;
86}
return nil

◆ initWithData:radius:

- (id) initWithData: (NSData *) data
radius: (GLfloat) radius 
implementation

Definition at line 47 of file Octree.m.

90 :(NSData *)data
91 radius:(GLfloat)radius
92{
93 if ((self = [super init]))
94 {
95 _data = [data copy];
96 _radius = radius;
97
98 NSUInteger nodeCount = [_data length] / sizeof *_octree;
99 NSParameterAssert(nodeCount < UINT32_MAX);
100 _nodeCount = (uint32_t)nodeCount;
101
102 _octree = [_data bytes];
103
104 _collisionOctree = calloc(1, _nodeCount);
105 if (_octree == NULL || _collisionOctree == NULL)
106 {
107 [self release];
108 return nil;
109 }
110 }
111
112 return self;
113}
id init()
Definition Octree.m:80
GLfloat _radius
Definition Octree.h:42
uint32_t _nodeCount
Definition Octree.h:43

◆ initWithDictionary:

- (id) initWithDictionary: (NSDictionary *) dictionary

Definition at line 47 of file Octree.m.

116 :(NSDictionary *)dict
117{
118 NSData *data = [dict objectForKey:@"octree"];
119 if (![data isKindOfClass:[NSData class]] || ([data length] % sizeof (int)) != 0)
120 {
121 // Invalid representation.
122 [self release];
123 return nil;
124 }
125
126 return [self initWithData:data radius:[dict oo_floatForKey:@"radius"]];
127}

◆ isHitByLine

+ (static BOOL) isHitByLine (const int *) octbuffer
(unsigned char *) collbuffer
(int) level
(GLfloat) rad
(Vector) v0
(Vector) v1
(Vector) off
(int) face_hit 
implementation

Definition at line 372 of file Octree.m.

373{
374 // displace the line by the offset
375 Vector u0 = make_vector(v0.x + off.x, v0.y + off.y, v0.z + off.z);
376 Vector u1 = make_vector(v1.x + off.x, v1.y + off.y, v1.z + off.z);
377
378 OctreeDebugLog(@"DEBUG octant: [%d] radius: %.2f vs. line: (%.2f, %.2f, %.2f) - (%.2f, %.2f, %.2f)",
379 level, rad, u0.x, u0.y, u0.z, u1.x, u1.y, u1.z);
380
381 if (octbuffer[level] == 0)
382 {
383 OctreeDebugLog(@"DEBUG Hit an empty octant: [%d]", level);
384 return NO;
385 }
386
387 if (octbuffer[level] == -1)
388 {
389 OctreeDebugLog(@"DEBUG Hit a solid octant: [%d]", level);
390 collbuffer[level] = 2; // green
391 hit_dist = sqrt(u0.x * u0.x + u0.y * u0.y + u0.z * u0.z);
392 return YES;
393 }
394
395 int faces = face_hit;
396 if (faces == 0)
397 faces = lineCubeIntersection(u0, u1, rad);
398
399 if (faces == 0)
400 {
401 OctreeDebugLog(@"----> Line misses octant: [%d].", level);
402 return NO;
403 }
404
405 int octantIntersected = 0;
406
407 if (faces > 0)
408 {
409 Vector vi = lineIntersectionWithFace(u0, u1, faces, rad);
410
411 if (CUBE_FACE_FRONT & faces)
412 octantIntersected = ((vi.x < 0.0)? 1: 5) + ((vi.y < 0.0)? 0: 2);
413 if (CUBE_FACE_BACK & faces)
414 octantIntersected = ((vi.x < 0.0)? 0: 4) + ((vi.y < 0.0)? 0: 2);
415
416 if (CUBE_FACE_RIGHT & faces)
417 octantIntersected = ((vi.y < 0.0)? 4: 6) + ((vi.z < 0.0)? 0: 1);
418 if (CUBE_FACE_LEFT & faces)
419 octantIntersected = ((vi.y < 0.0)? 0: 2) + ((vi.z < 0.0)? 0: 1);
420
421 if (CUBE_FACE_TOP & faces)
422 octantIntersected = ((vi.x < 0.0)? 2: 6) + ((vi.z < 0.0)? 0: 1);
423 if (CUBE_FACE_BOTTOM & faces)
424 octantIntersected = ((vi.x < 0.0)? 0: 4) + ((vi.z < 0.0)? 0: 1);
425
426 OctreeDebugLog(@"----> found intersection with face 0x%2x of cube of radius %.2f at (%.2f, %.2f, %.2f) octant:%d",
427 faces, rad, vi.x, vi.y, vi.z, octantIntersected);
428 }
429 else
430 {
431 OctreeDebugLog(@"----> inside cube of radius %.2f octant:%d", rad, octantIntersected);
432 }
433
434 hasCollided = YES;
435
436 collbuffer[level] = 1; // red
437
438 OctreeDebugLog(@"%@", @"----> testing octants...");
439
440 int nextLevel = level + octbuffer[level];
441
442 GLfloat rd2 = 0.5f * rad;
443
444 // first test the intersected octant, then the three adjacent, then the next three adjacent, the finally the diagonal octant
445 int oct0, oct1, oct2, oct3; // test oct0 then oct1, oct2, oct3 then (7 - oct1), (7 - oct2), (7 - oct3) then (7 - oct0)
446 oct0 = octantIntersected;
447 oct1 = oct0 ^ 0x01; // adjacent x
448 oct2 = oct0 ^ 0x02; // adjacent y
449 oct3 = oct0 ^ 0x04; // adjacent z
450
451 OctreeDebugLog(@"----> testing first octant hit [+%d]", oct0);
452 if (isHitByLineSub(octbuffer, collbuffer, nextLevel, rad, rd2, u0, u1, oct0)) return YES; // first octant
453
454 // test the three adjacent octants
455
456 OctreeDebugLog(@"----> testing next three octants [+%d] [+%d] [+%d]", oct1, oct2, oct3);
457 if (isHitByLineSub(octbuffer, collbuffer, nextLevel, rad, rd2, u0, u1, oct1)) return YES; // second octant
458 if (isHitByLineSub(octbuffer, collbuffer, nextLevel, rad, rd2, u0, u1, oct2)) return YES; // third octant
459 if (isHitByLineSub(octbuffer, collbuffer, nextLevel, rad, rd2, u0, u1, oct3)) return YES; // fourth octant
460
461 // go to the next four octants
462
463 oct0 ^= 0x07; oct1 ^= 0x07; oct2 ^= 0x07; oct3 ^= 0x07;
464
465 OctreeDebugLog(@"----> testing back three octants [+%d] [+%d] [+%d]", oct1, oct2, oct3);
466 if (isHitByLineSub(octbuffer, collbuffer, nextLevel, rad, rd2, u0, u1, oct1)) return YES; // fifth octant
467 if (isHitByLineSub(octbuffer, collbuffer, nextLevel, rad, rd2, u0, u1, oct2)) return YES; // sixth octant
468 if (isHitByLineSub(octbuffer, collbuffer, nextLevel, rad, rd2, u0, u1, oct3)) return YES; // seventh octant
469
470 // and check the last octant
471 OctreeDebugLog(@"----> testing final octant [+%d]", oct0);
472 if (isHitByLineSub(octbuffer, collbuffer, nextLevel, rad, rd2, u0, u1, oct0)) return YES; // last octant
473
474 return NO;
475}
Vector lineIntersectionWithFace(Vector p1, Vector p2, long mask, GLfloat rd)
Definition OOVoxel.m:77
int lineCubeIntersection(Vector v0, Vector v1, GLfloat rd)
Definition OOVoxel.m:140
static GLfloat hit_dist
Definition Octree.m:371
#define OctreeDebugLog(format,...)
Definition Octree.m:37
static BOOL hasCollided
Definition Octree.m:370
static BOOL isHitByLineSub(const int *octbuffer, unsigned char *collbuffer, int nextLevel, GLfloat rad, GLfloat rd2, Vector v0, Vector v1, int octantMask)
Definition Octree.m:359

References hasCollided, hit_dist, lineCubeIntersection(), lineIntersectionWithFace(), and OctreeDebugLog.

+ Here is the call graph for this function:

◆ isHitByLine:v0:

- (GLfloat) isHitByLine: (Vector)
v0: (Vector) v1 

Definition at line 372 of file Octree.m.

477 :(Vector)v0 :(Vector)v1
478{
479 memset(_collisionOctree, 0, _nodeCount * sizeof *_collisionOctree);
480 hasCollided = NO;
481
483 {
484 OctreeDebugLog(@"DEBUG Hit at distance %.2f", hit_dist);
486 return hit_dist;
487 }
488 else
489 {
490 OctreeDebugLog(@"%@", @"DEBUG Missed!");
492 return 0.0f;
493 }
494}
const Vector kZeroVector
Definition OOVector.m:28
static BOOL isHitByLine(const int *octbuffer, unsigned char *collbuffer, int level, GLfloat rad, Vector v0, Vector v1, Vector off, int face_hit)
Definition Octree.m:372

◆ isHitByLineSub

+ (static BOOL) isHitByLineSub (const int *) octbuffer
(unsigned char *) collbuffer
(int) nextLevel
(GLfloat) rad
(GLfloat) rd2
(Vector) v0
(Vector) v1
(int) octantMask 
implementation

Definition at line 359 of file Octree.m.

360{
361 if (octbuffer[nextLevel + octantMask])
362 {
363 Vector moveLine = offsetForOctant(octantMask, rad);
364 return isHitByLine(octbuffer, collbuffer, nextLevel + octantMask, rd2, v0, v1, moveLine, 0);
365 }
366 else return NO;
367}
static Vector offsetForOctant(int oct, GLfloat r)
Definition Octree.m:170

References isHitByLine().

+ Here is the call graph for this function:

◆ isHitByOctree

+ (static BOOL) isHitByOctree (Octree_details) axialDetails
(Octree_details) otherDetails
(Vector) otherPosition
(Triangle) other_ijk 
implementation

Definition at line 497 of file Octree.m.

499{
500 const int *axialBuffer = axialDetails.octree;
501 const int *otherBuffer = otherDetails.octree;
502
503 if (axialBuffer[0] == 0)
504 {
505 OctreeDebugLog(@"%@", @"DEBUG Axial octree is empty.");
506 return NO;
507 }
508
509 if (!otherBuffer)
510 {
511 OctreeDebugLog(@"%@", @"DEBUG Other octree is undefined.");
512 return NO;
513 }
514
515 if (otherBuffer[0] == 0)
516 {
517 OctreeDebugLog(@"%@", @"DEBUG Other octree is empty.");
518 return NO;
519 }
520
521 GLfloat axialRadius = axialDetails.radius;
522 GLfloat otherRadius = otherDetails.radius;
523
524 if (otherRadius < axialRadius) // test axial cube against other sphere
525 {
526 // 'crude and simple' - test sphere against cube...
527 if ((otherPosition.x + otherRadius < -axialRadius)||(otherPosition.x - otherRadius > axialRadius)||
528 (otherPosition.y + otherRadius < -axialRadius)||(otherPosition.y - otherRadius > axialRadius)||
529 (otherPosition.z + otherRadius < -axialRadius)||(otherPosition.z - otherRadius > axialRadius))
530 {
531 OctreeDebugLog(@"%@", @"----> Other sphere does not intersect axial cube");
532 return NO;
533 }
534 }
535 else // test axial sphere against other cube
536 {
537 Vector d2 = vector_flip(otherPosition);
538 Vector axialPosition = resolveVectorInIJK(d2, other_ijk);
539 if ((axialPosition.x + axialRadius < -otherRadius)||(axialPosition.x - axialRadius > otherRadius)||
540 (axialPosition.y + axialRadius < -otherRadius)||(axialPosition.y - axialRadius > otherRadius)||
541 (axialPosition.z + axialRadius < -otherRadius)||(axialPosition.z - axialRadius > otherRadius))
542 {
543 OctreeDebugLog(@"%@", @"----> Axial sphere does not intersect other cube");
544 return NO;
545 }
546 }
547
548 // from here on, this Octree and the other Octree are considered to be intersecting
549 unsigned char *axialCollisionBuffer = axialDetails.octree_collision;
550 unsigned char *otherCollisionBuffer = otherDetails.octree_collision;
551 if (axialBuffer[0] == -1)
552 {
553 // we are SOLID - is the other octree?
554 if (otherBuffer[0] == -1)
555 {
556 // YES so octrees collide
557 axialCollisionBuffer[0] = (unsigned char)255; // mark
558 otherCollisionBuffer[0] = (unsigned char)255; // mark
559
560 OctreeDebugLog(@"%@", @"DEBUG Octrees collide!");
561 return YES;
562 }
563 // the other octree must be decomposed
564 // and each of its octants tested against the axial octree
565 // if any of them collides with this octant
566 // then we have a solid collision
567
568 OctreeDebugLog(@"%@", @"----> testing other octants...");
569
570 // work out the nearest octant to the axial octree
571 int nearest_oct = ((otherPosition.x > 0.0)? 0:4)|((otherPosition.y > 0.0)? 0:2)|((otherPosition.z > 0.0)? 0:1);
572
573 int nextLevel = otherBuffer[0];
574 const int *nextBuffer = &otherBuffer[nextLevel];
575 unsigned char *nextCollisionBuffer = &otherCollisionBuffer[nextLevel];
576 Octree_details nextDetails;
577 Vector voff, nextPosition;
578 unsigned i, oct;
579
580 nextDetails.radius = 0.5f * otherRadius;
581 for (i = 0; i < 8; i++)
582 {
583 oct = nearest_oct ^ change_oct[i]; // work from nearest to furthest
584 if (nextBuffer[oct]) // don't test empty octants
585 {
586 nextDetails.octree = &nextBuffer[oct];
587 nextDetails.octree_collision = &nextCollisionBuffer[oct];
588
589 voff = resolveVectorInIJK(offsetForOctant(oct, otherRadius), other_ijk);
590 nextPosition = vector_subtract(otherPosition, voff);
591 if (isHitByOctree(axialDetails, nextDetails, nextPosition, other_ijk)) // test octant
592 return YES;
593 }
594 }
595
596 // otherwise
597 return NO;
598 }
599 // we are not solid
600 // we must test each of our octants against
601 // the other octree, if any of them collide
602 // we have a solid collision
603
604 OctreeDebugLog(@"%@", @"----> testing axial octants...");
605
606 // work out the nearest octant to the other octree
607 int nearest_oct = ((otherPosition.x > 0.0)? 4:0)|((otherPosition.y > 0.0)? 2:0)|((otherPosition.z > 0.0)? 1:0);
608
609 int nextLevel = axialBuffer[0];
610 const int *nextBuffer = &axialBuffer[nextLevel];
611 unsigned char *nextCollisionBuffer = &axialCollisionBuffer[nextLevel];
612 Vector nextPosition;
613 Octree_details nextDetails;
614 unsigned i, oct;
615
616 nextDetails.radius = 0.5f * axialRadius;
617 for (i = 0; i < 8; i++)
618 {
619 oct = nearest_oct ^ change_oct[i]; // work from nearest to furthest
620 if (nextBuffer[oct]) // don't test empty octants
621 {
622 nextDetails.octree = &nextBuffer[oct];
623 nextDetails.octree_collision = &nextCollisionBuffer[oct];
624
625 nextPosition = vector_add(otherPosition, offsetForOctant(oct, axialRadius));
626 if (isHitByOctree(nextDetails, otherDetails, nextPosition, other_ijk))
627 {
628 return YES; // test octant
629 }
630 }
631 }
632 // otherwise we're done!
633 return NO;
634}
static const int change_oct[]
Definition Octree.m:68
static BOOL isHitByOctree(Octree_details axialDetails, Octree_details otherDetails, Vector otherPosition, Triangle other_ijk)
Definition Octree.m:497
unsigned char * octree_collision
Definition Octree.m:47
GLfloat radius
Definition Octree.m:45
const int * octree
Definition Octree.m:46

◆ isHitByOctree:withOrigin:andIJK:

- (BOOL) isHitByOctree: (Octree *) other
withOrigin: (Vector) origin
andIJK: (Triangle) ijk 

Definition at line 497 of file Octree.m.

637 :(Octree *)other withOrigin:(Vector)v0 andIJK:(Triangle)ijk
638{
639 if (other == nil) return NO;
640
641 BOOL hit = isHitByOctree([self octreeDetails], [other octreeDetails], v0, ijk);
642
644 [other setHasCollision: [other hasCollision] || hit];
645
646 return hit;
647}
Octree_details octreeDetails()
Definition Octree.m:151
void setHasCollision:(BOOL value)
Definition Octree.m:145
BOOL hasCollision()
Definition Octree.m:139

◆ isHitByOctree:withOrigin:andIJK:andScales:s1:

- (BOOL) isHitByOctree: (Octree *) other
withOrigin: (Vector) origin
andIJK: (Triangle) ijk
andScales: (GLfloat)
s1: (GLfloat) s2 

Definition at line 497 of file Octree.m.

650 :(Octree *)other withOrigin:(Vector)v0 andIJK:(Triangle)ijk andScales:(GLfloat) s1 :(GLfloat)s2
651{
652 Octree_details details1 = [self octreeDetails];
653 Octree_details details2 = [other octreeDetails];
654
655 details1.radius *= s1;
656 details2.radius *= s2;
657
658 BOOL hit = isHitByOctree(details1, details2, v0, ijk);
659
661 [other setHasCollision: [other hasCollision] || hit];
662
663 return hit;
664}

◆ octreeDetails

- (Octree_details) octreeDetails
implementation

Provided by category Octree(Private).

Definition at line 47 of file Octree.m.

152{
153 Octree_details details =
154 {
155 .octree = _octree,
156 .radius = _radius,
157 .octree_collision = _collisionOctree
158 };
159 return details;
160}

◆ octreeScaledBy:

- (Octree *) octreeScaledBy: (GLfloat) factor

Definition at line 47 of file Octree.m.

163 :(GLfloat)factor
164{
165 // Since octree data is immutable, we can share.
166 return [[[Octree alloc] initWithData:_data radius:_radius * factor] autorelease];
167}

◆ offsetForOctant

+ (static Vector) offsetForOctant (int) oct
(GLfloat) r 
implementation

Definition at line 170 of file Octree.m.

171{
172 return make_vector((0.5f - (GLfloat)((oct >> 2) & 1)) * r, (0.5f - (GLfloat)((oct >> 1) & 1)) * r, (0.5f - (GLfloat)(oct & 1)) * r);
173}

◆ randomFullNodeFrom

+ (static Vector) randomFullNodeFrom (Octree_details) details
(Vector) offset 
implementation

Definition at line 730 of file Octree.m.

731{
732 const int *octBuffer = details.octree;
733 GLfloat octRadius = details.radius;
734
735 if (octBuffer[0] == 0) return offset;
736 if (octBuffer[0] == -1) return offset;
737
738 // We are not empty or solid.
739 // Pick a location from a random octant.
740 Octree_details nextDetails;
741 int nextLevel = octBuffer[0];
742 const int *nextBuffer = &octBuffer[nextLevel];
743 unsigned i, oct;
744
745 nextDetails.radius = 0.5f * octRadius;
746 nextDetails.octree_collision = NULL;
747 oct = Ranrot() & 7;
748
749 for (i = 0; i < 8; i++)
750 {
751 int octant = oct ^ i;
752 if (nextBuffer[octant]) // don't test empty octants
753 {
754 nextDetails.octree = &nextBuffer[octant];
755 Vector voff = vector_add(offset, offsetForOctant(octant, octRadius));
756 return randomFullNodeFrom(nextDetails, voff);
757 }
758 }
759 return offset;
760}
static Vector randomFullNodeFrom(Octree_details details, Vector offset)
Definition Octree.m:730
unsigned Ranrot(void)

References Octree_details::octree, Octree_details::octree_collision, Octree_details::radius, randomFullNodeFrom(), and Ranrot().

+ Here is the call graph for this function:

◆ randomPoint

- (Vector) randomPoint

Definition at line 730 of file Octree.m.

764{
766}

◆ setHasCollision:

- (void) setHasCollision: (BOOL) value
implementation

Provided by category Octree(Private).

Definition at line 47 of file Octree.m.

145 :(BOOL)value
146{
147 _hasCollision = !!value;
148}

◆ totalSize

- (size_t) totalSize

Definition at line 730 of file Octree.m.

771{
772 return [self oo_objectSize] + _nodeCount * [_data oo_objectSize] + [_data length] + _nodeCount * sizeof *_collisionOctree;
773}

◆ volume

- (GLfloat) volume

Definition at line 676 of file Octree.m.

716{
717 /* For backwards compatibility, limit octree iteration for volume
718 calculation to five levels. Raising the limit means lower calculated
719 volumes for large ships.
720
721 EMMSTRAN: consider raising the limit but fudging mass lock calculations
722 to compensate. See http://aegidian.org/bb/viewtopic.php?f=3&t=9176 .
723 Then again, five levels of iteration might be fine.
724 -- Ahruman 2011-03-10
725 */
726 return volumeOfOctree([self octreeDetails], 5);
727}
static GLfloat volumeOfOctree(Octree_details octree_details, unsigned depthLimit)
Definition Octree.m:676

References Octree_details::octree, Octree_details::octree_collision, Octree_details::radius, and volumeOfOctree().

+ Here is the call graph for this function:

◆ volumeOfOctree

+ (static GLfloat) volumeOfOctree (Octree_details) octree_details
(unsigned) depthLimit 
implementation

Definition at line 676 of file Octree.m.

677{
678 const int *octBuffer = octree_details.octree;
679 GLfloat octRadius = octree_details.radius;
680
681 if (octBuffer[0] == 0)
682 {
683 return 0.0f;
684 }
685
686 if (octBuffer[0] == -1 || depthLimit == 0)
687 {
688 return octRadius * octRadius * octRadius;
689 }
690 depthLimit--;
691
692 // We are not empty or solid.
693 // We sum the volume of each of our octants.
694 GLfloat sumVolume = 0.0f;
695 Octree_details nextDetails;
696 int nextLevel = octBuffer[0];
697 const int *nextBuffer = &octBuffer[nextLevel];
698 unsigned i;
699
700 nextDetails.radius = 0.5f * octRadius;
701 nextDetails.octree_collision = NULL; // Placate static analyzer
702
703 for (i = 0; i < 8; i++)
704 {
705 if (nextBuffer[i]) // don't test empty octants
706 {
707 nextDetails.octree = &nextBuffer[i];
708 sumVolume += volumeOfOctree(nextDetails, depthLimit);
709 }
710 }
711 return sumVolume;
712}

Member Data Documentation

◆ _collisionOctree

- (unsigned char*) _collisionOctree
private

Definition at line 47 of file Octree.h.

◆ _data

- (NSData*) _data
private

Definition at line 49 of file Octree.h.

◆ _hasCollision

- (BOOL) _hasCollision
private

Definition at line 45 of file Octree.h.

◆ _nodeCount

- (uint32_t) _nodeCount
private

Definition at line 43 of file Octree.h.

◆ _octree

- (const int*) _octree
private

Definition at line 44 of file Octree.h.

◆ _radius

- (GLfloat) _radius
private

Definition at line 42 of file Octree.h.


The documentation for this class was generated from the following files: