Line-Mesh intersections using a BVH with AABB volumes

../../_images/bvh_aabb_intersections.png

this example computes the intersections between a list of rays/lines and a mesh, using a Bounding Volume Hierarchy (BVH) with axis-aligned bounding boxes (AABBs) as bounding volumes for the tree nodes. AABBs typically provide a better fit of the geometry of the mesh and its primitives than oriented bounding boxes. However, they are (slightly) more expensive to compute.

  • Load a quad mesh from an OBJ file.

  • Convert the quads of the mesh to triangles for accurate intersections.

  • Build a BVH with AABB nodes.

  • Construct a list of intersection lines.

  • Traverse the tree to find the intersection of each line, if one exist.

  • Keep track of the boxes of the leaf nodes of the tree for visualisation.

  • Visualize the mesh, the lines, the boxes, and the intersections.

import compas
from compas.colors import Color
from compas.datastructures import Mesh
from compas.geometry import Line
from compas.geometry import Point
from compas_model.datastructures import BVH
from compas_model.datastructures import AABBNode
from compas_model.geometry import intersection_ray_triangle
from compas_viewer import Viewer
from compas_viewer.config import Config

mesh = Mesh.from_obj(compas.get("tubemesh.obj"))

# =============================================================================
# Build BVH
# =============================================================================

trimesh: Mesh = mesh.copy()
trimesh.quads_to_triangles()

tree = BVH.from_mesh(trimesh, nodetype=AABBNode)

# =============================================================================
# Intersections
# =============================================================================

lines = [Line.from_point_and_vector([2, i * 0.1, 0], [0, 0, 3]) for i in range(60)]

boxes = []
points = []

for line in lines:
    for node in tree.intersect_line(line):
        if node.is_leaf:
            triangle = node.objects[0][2]
            result = intersection_ray_triangle(line, triangle)
            if result:
                boxes.append(node.box)
                points.append(Point(*result))

# =============================================================================
# Viz
# =============================================================================

config = Config()
config.camera.target = [2.3, 1.8, 1.4]
config.camera.position = [5.2, -2.8, 4.4]

viewer = Viewer(config=config)

viewer.scene.add(mesh)
viewer.scene.add(lines, linecolor=Color.blue(), linewidth=2)
viewer.scene.add(boxes, facecolor=Color.green(), opacity=0.25)
viewer.scene.add(points, pointcolor=Color.red(), pointsize=10)

viewer.show()