raystrack 1.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,811 @@
1
+ from __future__ import annotations
2
+
3
+ import math
4
+
5
+ import numba as nb
6
+ import numpy as np
7
+
8
+ INF = 1.0e20
9
+ STACK_SIZE = 64
10
+
11
+
12
+ @nb.njit(inline="always", cache=True, fastmath=True)
13
+ def _aabb_tmin(o0, o1, o2, inv0, inv1, inv2, bmin0, bmin1, bmin2, bmax0, bmax1, bmax2):
14
+ tmin = (bmin0 - o0) * inv0
15
+ tmax = (bmax0 - o0) * inv0
16
+ if tmin > tmax:
17
+ tmin, tmax = tmax, tmin
18
+
19
+ tymin = (bmin1 - o1) * inv1
20
+ tymax = (bmax1 - o1) * inv1
21
+ if tymin > tymax:
22
+ tymin, tymax = tymax, tymin
23
+ if (tmin > tymax) or (tymin > tmax):
24
+ return INF
25
+ if tymin > tmin:
26
+ tmin = tymin
27
+ if tymax < tmax:
28
+ tmax = tymax
29
+
30
+ tzmin = (bmin2 - o2) * inv2
31
+ tzmax = (bmax2 - o2) * inv2
32
+ if tzmin > tzmax:
33
+ tzmin, tzmax = tzmax, tzmin
34
+ if (tmin > tzmax) or (tzmin > tmax):
35
+ return INF
36
+ if tzmin > tmin:
37
+ tmin = tzmin
38
+ if tzmax < tmax:
39
+ tmax = tzmax
40
+ if tmax < 0.0:
41
+ return INF
42
+ return tmin if tmin > 0.0 else 0.0
43
+
44
+
45
+ @nb.njit(inline="always", cache=True)
46
+ def _skip_surface(surface_id: int, surf_active, emit_sid: int, min_sid: int) -> bool:
47
+ if surf_active[surface_id] == 0:
48
+ return True
49
+ if surface_id < min_sid:
50
+ return True
51
+ return surface_id == emit_sid
52
+
53
+
54
+ @nb.njit(parallel=True, fastmath=True, cache=True)
55
+ def trace_cpu_firsthit(
56
+ orig,
57
+ dirs,
58
+ v0,
59
+ e1,
60
+ e2,
61
+ norm,
62
+ sid,
63
+ surf_active,
64
+ emit_sid,
65
+ min_sid,
66
+ out_hit_sid,
67
+ out_front,
68
+ ):
69
+ n_rays = orig.shape[0]
70
+ n_tri = v0.shape[0]
71
+ for k in nb.prange(n_rays):
72
+ o0 = orig[k, 0]
73
+ o1 = orig[k, 1]
74
+ o2 = orig[k, 2]
75
+ d0 = dirs[k, 0]
76
+ d1 = dirs[k, 1]
77
+ d2 = dirs[k, 2]
78
+
79
+ best = INF
80
+ hit = -1
81
+ front = 0
82
+
83
+ for i in range(n_tri):
84
+ surf = sid[i]
85
+ if _skip_surface(surf, surf_active, emit_sid, min_sid):
86
+ continue
87
+
88
+ px = d1 * e2[i, 2] - d2 * e2[i, 1]
89
+ py = d2 * e2[i, 0] - d0 * e2[i, 2]
90
+ pz = d0 * e2[i, 1] - d1 * e2[i, 0]
91
+ det = e1[i, 0] * px + e1[i, 1] * py + e1[i, 2] * pz
92
+ if abs(det) < 1e-7:
93
+ continue
94
+
95
+ inv_det = 1.0 / det
96
+ tx = o0 - v0[i, 0]
97
+ ty = o1 - v0[i, 1]
98
+ tz = o2 - v0[i, 2]
99
+ u = (tx * px + ty * py + tz * pz) * inv_det
100
+ if u < 0.0 or u > 1.0:
101
+ continue
102
+
103
+ qx = ty * e1[i, 2] - tz * e1[i, 1]
104
+ qy = tz * e1[i, 0] - tx * e1[i, 2]
105
+ qz = tx * e1[i, 1] - ty * e1[i, 0]
106
+ v = (d0 * qx + d1 * qy + d2 * qz) * inv_det
107
+ if v < 0.0 or u + v > 1.0:
108
+ continue
109
+
110
+ t_param = (e2[i, 0] * qx + e2[i, 1] * qy + e2[i, 2] * qz) * inv_det
111
+ if 1e-6 < t_param < best:
112
+ best = t_param
113
+ hit = surf
114
+ front = 1 if -(d0 * norm[i, 0] + d1 * norm[i, 1] + d2 * norm[i, 2]) > 0.0 else 0
115
+
116
+ out_hit_sid[k] = hit
117
+ out_front[k] = front if hit >= 0 else 0
118
+
119
+
120
+ @nb.njit(parallel=True, fastmath=True, cache=True)
121
+ def trace_cpu_bvh_firsthit(
122
+ orig,
123
+ dirs,
124
+ v0,
125
+ e1,
126
+ e2,
127
+ norm,
128
+ sid,
129
+ surf_active,
130
+ bb_min,
131
+ bb_max,
132
+ left,
133
+ right,
134
+ start,
135
+ count,
136
+ emit_sid,
137
+ min_sid,
138
+ out_hit_sid,
139
+ out_front,
140
+ ):
141
+ n_rays = orig.shape[0]
142
+ for k in nb.prange(n_rays):
143
+ o0 = orig[k, 0]
144
+ o1 = orig[k, 1]
145
+ o2 = orig[k, 2]
146
+ d0 = dirs[k, 0]
147
+ d1 = dirs[k, 1]
148
+ d2 = dirs[k, 2]
149
+
150
+ inv0 = 1.0 / d0 if abs(d0) > 1e-9 else 1e10
151
+ inv1 = 1.0 / d1 if abs(d1) > 1e-9 else 1e10
152
+ inv2 = 1.0 / d2 if abs(d2) > 1e-9 else 1e10
153
+
154
+ root_t = _aabb_tmin(
155
+ o0,
156
+ o1,
157
+ o2,
158
+ inv0,
159
+ inv1,
160
+ inv2,
161
+ bb_min[0, 0],
162
+ bb_min[0, 1],
163
+ bb_min[0, 2],
164
+ bb_max[0, 0],
165
+ bb_max[0, 1],
166
+ bb_max[0, 2],
167
+ )
168
+ if root_t >= INF:
169
+ out_hit_sid[k] = -1
170
+ out_front[k] = 0
171
+ continue
172
+
173
+ stack = np.empty(STACK_SIZE, np.int32)
174
+ tstack = np.empty(STACK_SIZE, np.float32)
175
+ sp = 0
176
+ stack[sp] = 0
177
+ tstack[sp] = root_t
178
+ sp += 1
179
+
180
+ best = INF
181
+ hit = -1
182
+ front = 0
183
+
184
+ while sp > 0:
185
+ sp -= 1
186
+ node = stack[sp]
187
+ node_t = tstack[sp]
188
+ if node_t >= best:
189
+ continue
190
+
191
+ if count[node] > 0:
192
+ for t in range(count[node]):
193
+ tri = start[node] + t
194
+ surf = sid[tri]
195
+ if _skip_surface(surf, surf_active, emit_sid, min_sid):
196
+ continue
197
+
198
+ px = d1 * e2[tri, 2] - d2 * e2[tri, 1]
199
+ py = d2 * e2[tri, 0] - d0 * e2[tri, 2]
200
+ pz = d0 * e2[tri, 1] - d1 * e2[tri, 0]
201
+ det = e1[tri, 0] * px + e1[tri, 1] * py + e1[tri, 2] * pz
202
+ if abs(det) < 1e-7:
203
+ continue
204
+
205
+ inv_det = 1.0 / det
206
+ tx = o0 - v0[tri, 0]
207
+ ty = o1 - v0[tri, 1]
208
+ tz = o2 - v0[tri, 2]
209
+ u = (tx * px + ty * py + tz * pz) * inv_det
210
+ if u < 0.0 or u > 1.0:
211
+ continue
212
+
213
+ qx = ty * e1[tri, 2] - tz * e1[tri, 1]
214
+ qy = tz * e1[tri, 0] - tx * e1[tri, 2]
215
+ qz = tx * e1[tri, 1] - ty * e1[tri, 0]
216
+ v = (d0 * qx + d1 * qy + d2 * qz) * inv_det
217
+ if v < 0.0 or u + v > 1.0:
218
+ continue
219
+
220
+ t_param = (e2[tri, 0] * qx + e2[tri, 1] * qy + e2[tri, 2] * qz) * inv_det
221
+ if 1e-6 < t_param < best:
222
+ best = t_param
223
+ hit = surf
224
+ front = 1 if -(d0 * norm[tri, 0] + d1 * norm[tri, 1] + d2 * norm[tri, 2]) > 0.0 else 0
225
+ else:
226
+ ln = left[node]
227
+ rn = right[node]
228
+ tl = _aabb_tmin(
229
+ o0,
230
+ o1,
231
+ o2,
232
+ inv0,
233
+ inv1,
234
+ inv2,
235
+ bb_min[ln, 0],
236
+ bb_min[ln, 1],
237
+ bb_min[ln, 2],
238
+ bb_max[ln, 0],
239
+ bb_max[ln, 1],
240
+ bb_max[ln, 2],
241
+ )
242
+ tr = _aabb_tmin(
243
+ o0,
244
+ o1,
245
+ o2,
246
+ inv0,
247
+ inv1,
248
+ inv2,
249
+ bb_min[rn, 0],
250
+ bb_min[rn, 1],
251
+ bb_min[rn, 2],
252
+ bb_max[rn, 0],
253
+ bb_max[rn, 1],
254
+ bb_max[rn, 2],
255
+ )
256
+
257
+ if tl < tr:
258
+ if tr < best and sp < STACK_SIZE:
259
+ stack[sp] = rn
260
+ tstack[sp] = tr
261
+ sp += 1
262
+ if tl < best and sp < STACK_SIZE:
263
+ stack[sp] = ln
264
+ tstack[sp] = tl
265
+ sp += 1
266
+ else:
267
+ if tl < best and sp < STACK_SIZE:
268
+ stack[sp] = ln
269
+ tstack[sp] = tl
270
+ sp += 1
271
+ if tr < best and sp < STACK_SIZE:
272
+ stack[sp] = rn
273
+ tstack[sp] = tr
274
+ sp += 1
275
+
276
+ out_hit_sid[k] = hit
277
+ out_front[k] = front if hit >= 0 else 0
278
+
279
+
280
+ @nb.njit(parallel=True, fastmath=True, cache=True)
281
+ def trace_cpu_combined(
282
+ orig,
283
+ dirs,
284
+ v0,
285
+ e1,
286
+ e2,
287
+ norm,
288
+ sid,
289
+ surf_active,
290
+ emit_sid,
291
+ matrix_min_sid,
292
+ out_hit_sid,
293
+ out_front,
294
+ out_any_hitmask,
295
+ ):
296
+ n_rays = orig.shape[0]
297
+ n_tri = v0.shape[0]
298
+ for k in nb.prange(n_rays):
299
+ o0 = orig[k, 0]
300
+ o1 = orig[k, 1]
301
+ o2 = orig[k, 2]
302
+ d0 = dirs[k, 0]
303
+ d1 = dirs[k, 1]
304
+ d2 = dirs[k, 2]
305
+
306
+ best_matrix = INF
307
+ hit = -1
308
+ front = 0
309
+ any_hit = 0
310
+
311
+ for i in range(n_tri):
312
+ surf = sid[i]
313
+ if surf == emit_sid or surf_active[surf] == 0:
314
+ continue
315
+
316
+ px = d1 * e2[i, 2] - d2 * e2[i, 1]
317
+ py = d2 * e2[i, 0] - d0 * e2[i, 2]
318
+ pz = d0 * e2[i, 1] - d1 * e2[i, 0]
319
+ det = e1[i, 0] * px + e1[i, 1] * py + e1[i, 2] * pz
320
+ if abs(det) < 1e-7:
321
+ continue
322
+
323
+ inv_det = 1.0 / det
324
+ tx = o0 - v0[i, 0]
325
+ ty = o1 - v0[i, 1]
326
+ tz = o2 - v0[i, 2]
327
+ u = (tx * px + ty * py + tz * pz) * inv_det
328
+ if u < 0.0 or u > 1.0:
329
+ continue
330
+
331
+ qx = ty * e1[i, 2] - tz * e1[i, 1]
332
+ qy = tz * e1[i, 0] - tx * e1[i, 2]
333
+ qz = tx * e1[i, 1] - ty * e1[i, 0]
334
+ v = (d0 * qx + d1 * qy + d2 * qz) * inv_det
335
+ if v < 0.0 or u + v > 1.0:
336
+ continue
337
+
338
+ t_param = (e2[i, 0] * qx + e2[i, 1] * qy + e2[i, 2] * qz) * inv_det
339
+ if t_param <= 1e-6:
340
+ continue
341
+
342
+ any_hit = 1
343
+ if surf < matrix_min_sid:
344
+ continue
345
+ if t_param < best_matrix:
346
+ best_matrix = t_param
347
+ hit = surf
348
+ front = 1 if -(d0 * norm[i, 0] + d1 * norm[i, 1] + d2 * norm[i, 2]) > 0.0 else 0
349
+
350
+ out_hit_sid[k] = hit
351
+ out_front[k] = front if hit >= 0 else 0
352
+ out_any_hitmask[k] = any_hit
353
+
354
+
355
+ @nb.njit(parallel=True, fastmath=True, cache=True)
356
+ def trace_cpu_bvh_combined(
357
+ orig,
358
+ dirs,
359
+ v0,
360
+ e1,
361
+ e2,
362
+ norm,
363
+ sid,
364
+ surf_active,
365
+ bb_min,
366
+ bb_max,
367
+ left,
368
+ right,
369
+ start,
370
+ count,
371
+ emit_sid,
372
+ matrix_min_sid,
373
+ out_hit_sid,
374
+ out_front,
375
+ out_any_hitmask,
376
+ ):
377
+ n_rays = orig.shape[0]
378
+ for k in nb.prange(n_rays):
379
+ o0 = orig[k, 0]
380
+ o1 = orig[k, 1]
381
+ o2 = orig[k, 2]
382
+ d0 = dirs[k, 0]
383
+ d1 = dirs[k, 1]
384
+ d2 = dirs[k, 2]
385
+
386
+ inv0 = 1.0 / d0 if abs(d0) > 1e-9 else 1e10
387
+ inv1 = 1.0 / d1 if abs(d1) > 1e-9 else 1e10
388
+ inv2 = 1.0 / d2 if abs(d2) > 1e-9 else 1e10
389
+
390
+ root_t = _aabb_tmin(
391
+ o0,
392
+ o1,
393
+ o2,
394
+ inv0,
395
+ inv1,
396
+ inv2,
397
+ bb_min[0, 0],
398
+ bb_min[0, 1],
399
+ bb_min[0, 2],
400
+ bb_max[0, 0],
401
+ bb_max[0, 1],
402
+ bb_max[0, 2],
403
+ )
404
+ if root_t >= INF:
405
+ out_hit_sid[k] = -1
406
+ out_front[k] = 0
407
+ out_any_hitmask[k] = 0
408
+ continue
409
+
410
+ stack = np.empty(STACK_SIZE, np.int32)
411
+ tstack = np.empty(STACK_SIZE, np.float32)
412
+ sp = 0
413
+ stack[sp] = 0
414
+ tstack[sp] = root_t
415
+ sp += 1
416
+
417
+ best_matrix = INF
418
+ hit = -1
419
+ front = 0
420
+ any_hit = 0
421
+
422
+ while sp > 0:
423
+ sp -= 1
424
+ node = stack[sp]
425
+ node_t = tstack[sp]
426
+ if node_t >= best_matrix:
427
+ continue
428
+
429
+ if count[node] > 0:
430
+ for t in range(count[node]):
431
+ tri = start[node] + t
432
+ surf = sid[tri]
433
+ if surf == emit_sid or surf_active[surf] == 0:
434
+ continue
435
+
436
+ px = d1 * e2[tri, 2] - d2 * e2[tri, 1]
437
+ py = d2 * e2[tri, 0] - d0 * e2[tri, 2]
438
+ pz = d0 * e2[tri, 1] - d1 * e2[tri, 0]
439
+ det = e1[tri, 0] * px + e1[tri, 1] * py + e1[tri, 2] * pz
440
+ if abs(det) < 1e-7:
441
+ continue
442
+
443
+ inv_det = 1.0 / det
444
+ tx = o0 - v0[tri, 0]
445
+ ty = o1 - v0[tri, 1]
446
+ tz = o2 - v0[tri, 2]
447
+ u = (tx * px + ty * py + tz * pz) * inv_det
448
+ if u < 0.0 or u > 1.0:
449
+ continue
450
+
451
+ qx = ty * e1[tri, 2] - tz * e1[tri, 1]
452
+ qy = tz * e1[tri, 0] - tx * e1[tri, 2]
453
+ qz = tx * e1[tri, 1] - ty * e1[tri, 0]
454
+ v = (d0 * qx + d1 * qy + d2 * qz) * inv_det
455
+ if v < 0.0 or u + v > 1.0:
456
+ continue
457
+
458
+ t_param = (e2[tri, 0] * qx + e2[tri, 1] * qy + e2[tri, 2] * qz) * inv_det
459
+ if t_param <= 1e-6:
460
+ continue
461
+
462
+ any_hit = 1
463
+ if surf < matrix_min_sid:
464
+ continue
465
+ if t_param < best_matrix:
466
+ best_matrix = t_param
467
+ hit = surf
468
+ front = 1 if -(d0 * norm[tri, 0] + d1 * norm[tri, 1] + d2 * norm[tri, 2]) > 0.0 else 0
469
+ else:
470
+ ln = left[node]
471
+ rn = right[node]
472
+ tl = _aabb_tmin(
473
+ o0,
474
+ o1,
475
+ o2,
476
+ inv0,
477
+ inv1,
478
+ inv2,
479
+ bb_min[ln, 0],
480
+ bb_min[ln, 1],
481
+ bb_min[ln, 2],
482
+ bb_max[ln, 0],
483
+ bb_max[ln, 1],
484
+ bb_max[ln, 2],
485
+ )
486
+ tr = _aabb_tmin(
487
+ o0,
488
+ o1,
489
+ o2,
490
+ inv0,
491
+ inv1,
492
+ inv2,
493
+ bb_min[rn, 0],
494
+ bb_min[rn, 1],
495
+ bb_min[rn, 2],
496
+ bb_max[rn, 0],
497
+ bb_max[rn, 1],
498
+ bb_max[rn, 2],
499
+ )
500
+
501
+ if tl < tr:
502
+ if tr < best_matrix and sp < STACK_SIZE:
503
+ stack[sp] = rn
504
+ tstack[sp] = tr
505
+ sp += 1
506
+ if tl < best_matrix and sp < STACK_SIZE:
507
+ stack[sp] = ln
508
+ tstack[sp] = tl
509
+ sp += 1
510
+ else:
511
+ if tl < best_matrix and sp < STACK_SIZE:
512
+ stack[sp] = ln
513
+ tstack[sp] = tl
514
+ sp += 1
515
+ if tr < best_matrix and sp < STACK_SIZE:
516
+ stack[sp] = rn
517
+ tstack[sp] = tr
518
+ sp += 1
519
+
520
+ out_hit_sid[k] = hit
521
+ out_front[k] = front if hit >= 0 else 0
522
+ out_any_hitmask[k] = any_hit
523
+
524
+
525
+ @nb.njit(cache=True)
526
+ def reduce_first_hits(hit_sid, front_flag, out_front, out_back):
527
+ for i in range(out_front.shape[0]):
528
+ out_front[i] = 0
529
+ out_back[i] = 0
530
+ for i in range(hit_sid.shape[0]):
531
+ hit = hit_sid[i]
532
+ if hit < 0:
533
+ continue
534
+ if front_flag[i] != 0:
535
+ out_front[hit] += 1
536
+ else:
537
+ out_back[hit] += 1
538
+
539
+
540
+ @nb.njit(parallel=True, fastmath=True, cache=True)
541
+ def trace_cpu_hitmask(orig, dirs, v0, e1, e2, sid, surf_active, emit_sid, min_sid, out_hitmask):
542
+ n_rays = orig.shape[0]
543
+ n_tri = v0.shape[0]
544
+ for k in nb.prange(n_rays):
545
+ o0 = orig[k, 0]
546
+ o1 = orig[k, 1]
547
+ o2 = orig[k, 2]
548
+ d0 = dirs[k, 0]
549
+ d1 = dirs[k, 1]
550
+ d2 = dirs[k, 2]
551
+
552
+ out_hitmask[k] = 0
553
+ for i in range(n_tri):
554
+ surf = sid[i]
555
+ if _skip_surface(surf, surf_active, emit_sid, min_sid):
556
+ continue
557
+
558
+ px = d1 * e2[i, 2] - d2 * e2[i, 1]
559
+ py = d2 * e2[i, 0] - d0 * e2[i, 2]
560
+ pz = d0 * e2[i, 1] - d1 * e2[i, 0]
561
+ det = e1[i, 0] * px + e1[i, 1] * py + e1[i, 2] * pz
562
+ if abs(det) < 1e-7:
563
+ continue
564
+
565
+ inv_det = 1.0 / det
566
+ tx = o0 - v0[i, 0]
567
+ ty = o1 - v0[i, 1]
568
+ tz = o2 - v0[i, 2]
569
+ u = (tx * px + ty * py + tz * pz) * inv_det
570
+ if u < 0.0 or u > 1.0:
571
+ continue
572
+
573
+ qx = ty * e1[i, 2] - tz * e1[i, 1]
574
+ qy = tz * e1[i, 0] - tx * e1[i, 2]
575
+ qz = tx * e1[i, 1] - ty * e1[i, 0]
576
+ v = (d0 * qx + d1 * qy + d2 * qz) * inv_det
577
+ if v < 0.0 or u + v > 1.0:
578
+ continue
579
+
580
+ t_param = (e2[i, 0] * qx + e2[i, 1] * qy + e2[i, 2] * qz) * inv_det
581
+ if t_param > 1e-6:
582
+ out_hitmask[k] = 1
583
+ break
584
+
585
+
586
+ @nb.njit(parallel=True, fastmath=True, cache=True)
587
+ def trace_cpu_bvh_hitmask(
588
+ orig,
589
+ dirs,
590
+ v0,
591
+ e1,
592
+ e2,
593
+ sid,
594
+ surf_active,
595
+ bb_min,
596
+ bb_max,
597
+ left,
598
+ right,
599
+ start,
600
+ count,
601
+ emit_sid,
602
+ min_sid,
603
+ out_hitmask,
604
+ ):
605
+ n_rays = orig.shape[0]
606
+ for k in nb.prange(n_rays):
607
+ o0 = orig[k, 0]
608
+ o1 = orig[k, 1]
609
+ o2 = orig[k, 2]
610
+ d0 = dirs[k, 0]
611
+ d1 = dirs[k, 1]
612
+ d2 = dirs[k, 2]
613
+
614
+ inv0 = 1.0 / d0 if abs(d0) > 1e-9 else 1e10
615
+ inv1 = 1.0 / d1 if abs(d1) > 1e-9 else 1e10
616
+ inv2 = 1.0 / d2 if abs(d2) > 1e-9 else 1e10
617
+
618
+ root_t = _aabb_tmin(
619
+ o0,
620
+ o1,
621
+ o2,
622
+ inv0,
623
+ inv1,
624
+ inv2,
625
+ bb_min[0, 0],
626
+ bb_min[0, 1],
627
+ bb_min[0, 2],
628
+ bb_max[0, 0],
629
+ bb_max[0, 1],
630
+ bb_max[0, 2],
631
+ )
632
+ if root_t >= INF:
633
+ out_hitmask[k] = 0
634
+ continue
635
+
636
+ stack = np.empty(STACK_SIZE, np.int32)
637
+ tstack = np.empty(STACK_SIZE, np.float32)
638
+ sp = 0
639
+ stack[sp] = 0
640
+ tstack[sp] = root_t
641
+ sp += 1
642
+
643
+ hit_any = 0
644
+ while sp > 0 and hit_any == 0:
645
+ sp -= 1
646
+ node = stack[sp]
647
+
648
+ if count[node] > 0:
649
+ for t in range(count[node]):
650
+ tri = start[node] + t
651
+ surf = sid[tri]
652
+ if _skip_surface(surf, surf_active, emit_sid, min_sid):
653
+ continue
654
+
655
+ px = d1 * e2[tri, 2] - d2 * e2[tri, 1]
656
+ py = d2 * e2[tri, 0] - d0 * e2[tri, 2]
657
+ pz = d0 * e2[tri, 1] - d1 * e2[tri, 0]
658
+ det = e1[tri, 0] * px + e1[tri, 1] * py + e1[tri, 2] * pz
659
+ if abs(det) < 1e-7:
660
+ continue
661
+
662
+ inv_det = 1.0 / det
663
+ tx = o0 - v0[tri, 0]
664
+ ty = o1 - v0[tri, 1]
665
+ tz = o2 - v0[tri, 2]
666
+ u = (tx * px + ty * py + tz * pz) * inv_det
667
+ if u < 0.0 or u > 1.0:
668
+ continue
669
+
670
+ qx = ty * e1[tri, 2] - tz * e1[tri, 1]
671
+ qy = tz * e1[tri, 0] - tx * e1[tri, 2]
672
+ qz = tx * e1[tri, 1] - ty * e1[tri, 0]
673
+ v = (d0 * qx + d1 * qy + d2 * qz) * inv_det
674
+ if v < 0.0 or u + v > 1.0:
675
+ continue
676
+
677
+ t_param = (e2[tri, 0] * qx + e2[tri, 1] * qy + e2[tri, 2] * qz) * inv_det
678
+ if t_param > 1e-6:
679
+ hit_any = 1
680
+ break
681
+ else:
682
+ ln = left[node]
683
+ rn = right[node]
684
+ tl = _aabb_tmin(
685
+ o0,
686
+ o1,
687
+ o2,
688
+ inv0,
689
+ inv1,
690
+ inv2,
691
+ bb_min[ln, 0],
692
+ bb_min[ln, 1],
693
+ bb_min[ln, 2],
694
+ bb_max[ln, 0],
695
+ bb_max[ln, 1],
696
+ bb_max[ln, 2],
697
+ )
698
+ tr = _aabb_tmin(
699
+ o0,
700
+ o1,
701
+ o2,
702
+ inv0,
703
+ inv1,
704
+ inv2,
705
+ bb_min[rn, 0],
706
+ bb_min[rn, 1],
707
+ bb_min[rn, 2],
708
+ bb_max[rn, 0],
709
+ bb_max[rn, 1],
710
+ bb_max[rn, 2],
711
+ )
712
+
713
+ if tl < tr:
714
+ if tr < INF and sp < STACK_SIZE:
715
+ stack[sp] = rn
716
+ tstack[sp] = tr
717
+ sp += 1
718
+ if tl < INF and sp < STACK_SIZE:
719
+ stack[sp] = ln
720
+ tstack[sp] = tl
721
+ sp += 1
722
+ else:
723
+ if tl < INF and sp < STACK_SIZE:
724
+ stack[sp] = ln
725
+ tstack[sp] = tl
726
+ sp += 1
727
+ if tr < INF and sp < STACK_SIZE:
728
+ stack[sp] = rn
729
+ tstack[sp] = tr
730
+ sp += 1
731
+
732
+ out_hitmask[k] = hit_any
733
+
734
+
735
+ @nb.njit(inline="always", cache=True)
736
+ def _tregenza_patch_id(dx, dy, dz):
737
+ if dz <= 0.0:
738
+ return -1
739
+
740
+ ring_hi_sin = (
741
+ 0.20791169081775934,
742
+ 0.40673664307580015,
743
+ 0.5877852522924731,
744
+ 0.7431448254773942,
745
+ 0.8660254037844386,
746
+ 0.9510565162951535,
747
+ 0.9945218953682733,
748
+ 1.0,
749
+ )
750
+ ring_n = (30, 30, 24, 24, 18, 12, 6, 1)
751
+ ring_start = (0, 30, 60, 84, 108, 126, 138, 144)
752
+
753
+ ridx = 7
754
+ for j in range(8):
755
+ if dz < ring_hi_sin[j] or j == 7:
756
+ ridx = j
757
+ break
758
+
759
+ n_az = ring_n[ridx]
760
+ base = ring_start[ridx]
761
+ if n_az == 1:
762
+ return base
763
+
764
+ az = math.degrees(math.atan2(dy, dx))
765
+ if az < 0.0:
766
+ az += 360.0
767
+ width = 360.0 / n_az
768
+ off = (180.0 / n_az) if (ridx & 1) == 1 else 0.0
769
+ t = az - off
770
+ if t < 0.0:
771
+ t += 360.0
772
+ elif t >= 360.0:
773
+ t -= 360.0
774
+ aidx = int(t // width)
775
+ if aidx >= n_az:
776
+ aidx = n_az - 1
777
+ return base + aidx
778
+
779
+
780
+ @nb.njit(cache=True)
781
+ def bin_tregenza_cpu(dirs, hitmask, counts):
782
+ for i in range(counts.shape[0]):
783
+ counts[i] = 0
784
+ for i in range(dirs.shape[0]):
785
+ if hitmask[i] != 0:
786
+ continue
787
+ pid = _tregenza_patch_id(dirs[i, 0], dirs[i, 1], dirs[i, 2])
788
+ if pid >= 0:
789
+ counts[pid] += 1
790
+
791
+
792
+ @nb.njit(cache=True)
793
+ def count_upward_misses_cpu(dirs, hitmask):
794
+ total = 0
795
+ for i in range(dirs.shape[0]):
796
+ if hitmask[i] == 0 and dirs[i, 2] > 0.0:
797
+ total += 1
798
+ return total
799
+
800
+
801
+ __all__ = [
802
+ "trace_cpu_firsthit",
803
+ "trace_cpu_bvh_firsthit",
804
+ "trace_cpu_combined",
805
+ "trace_cpu_bvh_combined",
806
+ "reduce_first_hits",
807
+ "trace_cpu_hitmask",
808
+ "trace_cpu_bvh_hitmask",
809
+ "bin_tregenza_cpu",
810
+ "count_upward_misses_cpu",
811
+ ]