martinchristen/pyRT

View on GitHub
pyrt/geometry/bbox.py

Summary

Maintainability
A
0 mins
Test Coverage
""""
This file contains all bounding box realated stuff

The main class is "BBox"
"""

from .shape import Shape
from ..math import Vec3, Ray, HitRecord
from ..math.vecops import *



class BBox(Shape):
    """
    This class represents an axis aligned bounding box.
    """
    def __init__(self, vmin: Vec3, vmax):
        """

        :param vmin: minimum coord of bbox
        :param vmax: maximum coord of bbox
        """
        self.min = vmin
        self.max = vmax
        self.extent = self.max - self.min

    def __setitem__(self, key, value):
        assert type(value) is Vec3, "value is not a Vec3"

        if key == 0:
            self.min = value
        elif key == 1:
            self.max = value
        else:
            raise IndexError("Can only set index 0 (min) and index 1 (max)")

    def __getitem__(self, key):
        if key == 0:
            return self.min
        elif key == 1:
            return self.max
        else:
            raise IndexError("Can only get index 0 (min) and index 1 (max)")

        pass

    def __str__(self):
        return "BBOX: " + str(self.min) + "-" + str(self.max)

    def maxComponent(self):
        """
        Return the max component of bounding box
        
        :return: max component (x=0, y=1, z=2)
        """
        r = 0
        if self.extent.y > self.extent.x:
            r = 1
        if self.extent.z > self.extent.y:
            r = 2
        return r

    def expandPoint(self, pt: Vec3):
        """
        Expands the bounding box by a point (represented as Vec3)

        :param pt: point to expand bounding box
        """
        self.min = min3(self.min, pt)
        self.max = max3(self.max, pt)
        self.extent = self.max - self.min

    def expand(self, bbox):
        """
        Expands the bounding box by another box

        :param bbox: bounding box to expand
        """
        self.min = min3(self.min, bbox.min)
        self.max = max3(self.max, bbox.max)
        self.extent = self.max - self.min

    def hit(self, ray: Ray, hitrecord: HitRecord) -> bool:
        tmin = (self[ray.sign[0]].x - ray.start.x) * ray.invdir.x
        tmax = (self[1 - ray.sign[0]].x - ray.start.x) * ray.invdir.x
        tymin = (self[ray.sign[1]].y - ray.start.y) * ray.invdir.y
        tymax = (self[1 - ray.sign[1]].y - ray.start.y) * ray.invdir.y
        tzmin = (self[ray.sign[2]].z - ray.start.z) * ray.invdir.z
        tzmax = (self[1 - ray.sign[2]].z - ray.start.z) * ray.invdir.z
        tmin = max(max(tmin, tymin), tzmin)
        tmax = min(min(tmax, tymax), tzmax)
        tmin = (self[ray.sign[0]].x - ray.start.x) * ray.invdir.x

        if tmin > tmax:
            return False

        hitrecord.t = tmin
        hitrecord.point = ray.start + ray.direction * tmin
        return True

    def hitShadow(self, ray: Ray) -> bool:
        tmin = (self[ray.sign[0]].x - ray.start.x) * ray.invdir.x
        tmax = (self[1 - ray.sign[0]].x - ray.start.x) * ray.invdir.x
        tymin = (self[ray.sign[1]].y - ray.start.y) * ray.invdir.y
        tymax = (self[1 - ray.sign[1]].y - ray.start.y) * ray.invdir.y
        tzmin = (self[ray.sign[2]].z - ray.start.z) * ray.invdir.z
        tzmax = (self[1 - ray.sign[2]].z - ray.start.z) * ray.invdir.z
        tmin = max(max(tmin, tymin), tzmin)
        tmax = min(min(tmax, tymax), tzmax)
        tmin = (self[ray.sign[0]].x - ray.start.x) * ray.invdir.x

        return tmin < tmax


    def surfaceArea(self) -> float:
        return 2. * (self.extent.x * self.extent.z +
                    self.extent.x * self.extent.y +
                    self.extent.y * self.extent.z)