Search code examples
python3dpygamepyglet

Pygame's rect.clip function in 3D


Explain (Imagine the picture being in 3D)

I have made a Cuboid object that stores all the coordinates of the corners in a cuboid, just like the pygame rect object. I need the overlapping volume of two of the aforementioned cuboids to then make a new cuboid object from that (the grey rectangle in the picture, again, imagine it being in 3D).

Is there a generic algebraic formula for this or do I have to make a method for each specific case?

I am using pyglets coordinate system, that is to say, going up is positive y going right is positive x and going forward is positive z.

The cuboid Class:

def __init__(self, pos, width, height, depth):
    self.pos = pos

    self.width = width
    self.height = height
    self.depth = depth

    self.Update()

def Update(self):
    self.size = (self.width, self.height, self.depth)

    self.topleft_front = (self.pos[0], self.pos[1] + self.height, -self.pos[2])
    self.topright_front = (self.pos[0] + self.width, self.pos[1] + self.height, -self.pos[2])
    self.bottomleft_front = (self.pos[0], self.pos[1], -self.pos[2])
    self.bottomright_front = (self.pos[0] + self.width, self.pos[1], -self.pos[2])

    self.topleft_back = (self.pos[0], self.pos[1] + self.height, -self.pos[2] - self.depth)
    self.topright_back = (self.pos[0] + self.width, self.pos[1] + self.height, -self.pos[2] - self.depth)
    self.bottomleft_back = (self.pos[0], self.pos[1], -self.pos[2] - self.depth)
    self.bottomright_back = (self.pos[0] + self.width, self.pos[1], -self.pos[2] - self.depth)

    self.center = (self.pos[0] + self.width / 2, self.pos[1] + self.height / 2, -self.pos[2] - self.depth / 2)

def collidecube(self, cube):
    if (self.pos[0] < cube.pos[0] + cube.width) and (
    self.pos[0] + self.width > cube.pos[0]) and (
    self.pos[1] < cube.pos[1] + cube.height) and (
    self.pos[1] + self.height > cube.pos[1]) and (
    self.pos[2] < cube.pos[2] + cube.depth) and (
    self.pos[2] + self.depth > cube.pos[2]):
        return True

    else:
        return False

def Clip(self, cube):
    if self.collidecube(cube):
        pass

Solution

  • The issue can be be reduced to find the overlapping range of two ranges.

    e.g. range [a0, a1] ^ [b0, b1] = [c0, c1]

    a0                  a1
      x----------------x
                x-----------------x
              b0                   b1
    
                x======x
              c0        c1
    

    If a0 is less than a1 and b0 is less than b1, then

    c0 = max(a0, b0)
    c1 = min(a1, b1) 
    

    if c1 is less than c0, then the ranges don't intersect. This algorithm can be applied to all 3 dimensions.

    If it is sufficient to verify whether the ranges are intersecting, then the condition is:

    isect = a0 < b1 and b0 < a1  
    

    Note, if b0 is greater than a1 or if b1 is less than a0, the there is no overlapping range.