import cadquery as Cq

def binary_intersection(a: Cq.Assembly) -> Cq.Shape:
    objs = [s.toCompound() for _, s in a.traverse()
            if isinstance(s, Cq.Assembly)]
    obj1, obj2 = objs[:2]
    return obj1.intersect(obj2)

def visualize_intersection(assembly: Cq.Assembly, tol: float=1e-6) -> Cq.Shape:
    """
    Given an assembly, test the pairwise intersection volume of its components.
    Return the pairs whose intersection volume exceeds `tol`.
    """
    m = {name: (i, shape.moved(loc))
         for i, (shape, name, loc, _)
         in enumerate(assembly)}
    for name, (i1, sh1) in m.items():
        for name2, (i2, sh2) in m.items():
            if name == name2:
                assert i1 == i2
                continue
            if i2 <= i1:
                # Remove the upper diagonal
                continue
            head = name.split('/', 2)[1]
            head2 = name2.split('/', 2)[1]
            if head == head2:
                # Do not test into subassemblies
                continue

            isect = sh1.intersect(sh2)
            vol = isect.Volume()
            if vol > tol:
                return isect
    return None

def pairwise_intersection(assembly: Cq.Assembly, tol: float=1e-6) -> list[(str, str, float)]:
    """
    Given an assembly, test the pairwise intersection volume of its components.
    Return the pairs whose intersection volume exceeds `tol`.
    """
    m = {name: (i, shape.moved(loc))
         for i, (shape, name, loc, _)
         in enumerate(assembly)}
    result = []
    for name, (i1, sh1) in m.items():
        for name2, (i2, sh2) in m.items():
            if name == name2:
                assert i1 == i2
                continue
            if i2 <= i1:
                # Remove the upper diagonal
                continue
            head = name.split('/', 2)[1]
            head2 = name2.split('/', 2)[1]
            if head == head2:
                # Do not test into subassemblies
                continue


            vol = sh1.intersect(sh2).Volume()
            if vol > tol:
                result.append((name, name2, vol))
    return result