1
$\begingroup$

I want to make a box out of selected verts' bounding box in local space

enter image description here

enter image description here

$\endgroup$

1 Answer 1

2
$\begingroup$

Draw oriented bounding box with GPU module

enter image description here

enter image description here

# suppose in edit mode

import bpy, gpu
import numpy as np
from mathutils import Vector
from gpu_extras.batch import batch_for_shader

def ret_obb(verts):
    points = np.asarray(verts)
    means = np.mean(points, axis=1)

    cov = np.cov(points, y = None,rowvar = 0,bias = 1)

    v, vect = np.linalg.eig(cov)

    tvect = np.transpose(vect)
    points_r = np.dot(points, np.linalg.inv(tvect))

    co_min = np.min(points_r, axis=0)
    co_max = np.max(points_r, axis=0)
    
    xmin, xmax = co_min[0], co_max[0]
    ymin, ymax = co_min[1], co_max[1]
    zmin, zmax = co_min[2], co_max[2]

    xdif = (xmax - xmin) * 0.5
    ydif = (ymax - ymin) * 0.5
    zdif = (zmax - zmin) * 0.5

    cx = xmin + xdif
    cy = ymin + ydif
    cz = zmin + zdif

    corners = np.array([
        [cx - xdif, cy - ydif, cz - zdif],
        [cx - xdif, cy + ydif, cz - zdif],
        [cx + xdif, cy + ydif, cz - zdif],
        [cx + xdif, cy - ydif, cz - zdif],
        [cx - xdif, cy - ydif, cz + zdif],
        [cx - xdif, cy + ydif, cz + zdif],
        [cx + xdif, cy + ydif, cz + zdif],
        [cx + xdif, cy - ydif, cz + zdif],
    ])

    corners = np.dot(corners, tvect)

    return [Vector((el[0], el[1], el[2])) for el in corners]


bpy.ops.object.mode_set(mode = 'OBJECT')
oj          = bpy.context.object
verts       = [v.co for v in oj.data.vertices if v.select]
obb_local   = ret_obb(verts)
mat         = oj.matrix_world
obb_world   = [mat @ v for v in obb_local]
bpy.ops.object.mode_set(mode = 'EDIT')

# draw with GPU Module
coords = [(v[0], v[1], v[2]) for v in obb_world]

indices = (
    (0, 1), (1, 2), (2, 3), (3, 0),
    (4, 5), (5, 6), (6, 7), (7, 4),
    (0, 4), (1, 5), (2, 6), (3, 7))

shader = gpu.shader.from_builtin('3D_UNIFORM_COLOR')
batch = batch_for_shader(shader, 'LINES', {"pos": coords}, indices=indices)


def draw():
    shader.bind()
    shader.uniform_float("color", (1, 0, 0, 1))
    batch.draw(shader)


bpy.types.SpaceView3D.draw_handler_add(draw, (), 'WINDOW', 'POST_VIEW')
$\endgroup$
2
  • $\begingroup$ Where does the magic happen, what finds out the orientation of the bounding box? And is the orientation such that the bounding box has the smallest volume, or its biggest dimension is as small as possible, or it's some heuristic... Could you elaborate? $\endgroup$ Commented Sep 7, 2023 at 11:16
  • 1
    $\begingroup$ Here is the same algorithm for minimum volume, a general search engine should be able to find an explanation: blender.stackexchange.com/questions/261049/… $\endgroup$
    – X Y
    Commented Sep 7, 2023 at 12:01

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .