Plan 9 from Bell Labs’s /usr/web/sources/contrib/maht/inferno/appl/cmd/MiniLight/minilight/python/spatialindex.py

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#  MiniLight Python : minimal global illumination renderer
#
#  Copyright (c) 2007-2008, Harrison Ainsworth / HXA7241 and Juraj Sukop.
#  http://www.hxa7241.org/


from triangle import Triangle, TOLERANCE
from vector3f import Vector3f, MAX

MAX_LEVELS = 44
MAX_ITEMS  =  8

class SpatialIndex(object):

    def __init__(self, arg, items, level=0):
        if type(arg) == Vector3f:
            items = [(item.get_bound(), item) for item in items]
            bound = list(arg) * 2
            for item in items:
                for j in range(6):
                    if (bound[j] > item[0][j]) ^ (j > 2):
                        bound[j] = item[0][j]
            size = max(list(Vector3f(bound[3:6]) - Vector3f(bound[0:3])))
            self.bound = bound[0:3] + list(Vector3f(bound[3:6]).clamped(Vector3f(bound[0:3]) + Vector3f(size), MAX))
        else:
            self.bound = arg
        self.is_branch = len(items) > MAX_ITEMS and level < MAX_LEVELS - 1
        if self.is_branch:
            q1 = 0
            self.vector = [None] * 8
            for s in range(8):
                sub_bound = []
                for j in range(6):
                    m = j % 3
                    if (((s >> m) & 1) != 0) ^ (j > 2):
                        sub_bound.append((self.bound[m] + self.bound[m + 3]) * 0.5)
                    else:
                        sub_bound.append(self.bound[j])
                sub_items = []
                for item in items:
                    item_bound = item[0]
                    if item_bound[3] >= sub_bound[0] and item_bound[0] < sub_bound[3] and \
                       item_bound[4] >= sub_bound[1] and item_bound[1] < sub_bound[4] and \
                       item_bound[5] >= sub_bound[2] and item_bound[2] < sub_bound[5]:
                           sub_items.append(item)
                q1 += 1 if len(sub_items) == len(item) else 0
                q2 = (sub_bound[3] - sub_bound[0]) < (TOLERANCE * 4.0)
                if len(sub_items) > 0:
                    self.vector[s] = SpatialIndex(sub_bound, sub_items, MAX_LEVELS if q1 > 1 or q2 else level + 1)
        else:
            self.vector = [item[1] for item in items]

    def get_intersection(self, ray_origin, ray_direction, last_hit, start=None):
        start = start if start else ray_origin
        hit_object = hit_position = None
        if self.is_branch:
            sub_cell = 1 if start[0] >= (self.bound[0] + self.bound[3]) * 0.5 else 0
            if start[1] >= (self.bound[1] + self.bound[4]) * 0.5:
                sub_cell |= 2
            if start[2] >= (self.bound[2] + self.bound[5]) * 0.5:
                sub_cell |= 4
            cell_position = start
            while True:
                if self.vector[sub_cell]:
                    hit_object, hit_position = self.vector[sub_cell].get_intersection(ray_origin, ray_direction, last_hit, cell_position)
                    if hit_object:
                        break
                step = float(2**1024 - 2**971)
                axis = 0
                for i in range(3):
                    high = (sub_cell >> i) & 1
                    face = self.bound[i + high * 3] if (ray_direction[i] < 0.0) ^ (0 != high) else (self.bound[i] + self.bound[i + 3]) * 0.5
                    try:
                        distance = (face - ray_origin[i]) / ray_direction[i]
                    except:
                        distance = float(1e30000)
                    if distance <= step:
                        step = distance
                        axis = i
                if (((sub_cell >> axis) & 1) == 1) ^ (ray_direction[axis] < 0.0):
                    break
                cell_position = ray_origin + ray_direction * step
                sub_cell = sub_cell ^ (1 << axis)
        else:
            nearest_distance = float(2**1024 - 2**971)
            for item in self.vector:
                if item != last_hit:
                    distance = item.get_intersection(ray_origin, ray_direction)
                    if distance and (distance < nearest_distance):
                        hit = ray_origin + ray_direction * distance
                        if (self.bound[0] - hit[0] <= TOLERANCE) and \
                           (hit[0] - self.bound[3] <= TOLERANCE) and \
                           (self.bound[1] - hit[1] <= TOLERANCE) and \
                           (hit[1] - self.bound[4] <= TOLERANCE) and \
                           (self.bound[2] - hit[2] <= TOLERANCE) and \
                           (hit[2] - self.bound[5] <= TOLERANCE):
                               hit_object = item
                               hit_position = hit
                               nearest_distance = distance
        return hit_object, hit_position

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.