Skip to content

Analytical Ground Truth

Closed-form solutions for validation and benchmarking.

brepax.analytical

Closed-form analytical solutions for ground-truth validation.

disk_disk

Closed-form solutions for two-disk Boolean operations.

Provides analytically differentiable union area, stratum classification, and boundary distance for pairs of 2D disks. Used as ground truth for validating numerical gradient methods.

disk_disk_boundary_distance(c1, r1, c2, r2)

Distance from current configuration to the nearest stratum boundary.

Measures the minimum of distance to external tangency (d = r1 + r2) and internal tangency (d = |r1 - r2|).

Source code in src/brepax/analytical/disk_disk.py
def disk_disk_boundary_distance(
    c1: Float[Array, "2"],
    r1: Float[Array, ""],
    c2: Float[Array, "2"],
    r2: Float[Array, ""],
) -> Float[Array, ""]:
    """Distance from current configuration to the nearest stratum boundary.

    Measures the minimum of distance to external tangency (d = r1 + r2)
    and internal tangency (d = |r1 - r2|).
    """
    d = jnp.linalg.norm(c1 - c2)
    dist_external = jnp.abs(d - (r1 + r2))
    dist_internal = jnp.abs(d - jnp.abs(r1 - r2))
    return jnp.minimum(dist_external, dist_internal)

disk_disk_stratum_label(c1, r1, c2, r2)

Classify the topological stratum of a two-disk configuration.

Returns:

Type Description
Integer[Array, '']

Integer-valued scalar: 0 = disjoint, 1 = intersecting, 2 = contained.

Source code in src/brepax/analytical/disk_disk.py
def disk_disk_stratum_label(
    c1: Float[Array, "2"],
    r1: Float[Array, ""],
    c2: Float[Array, "2"],
    r2: Float[Array, ""],
) -> Integer[Array, ""]:
    """Classify the topological stratum of a two-disk configuration.

    Returns:
        Integer-valued scalar: 0 = disjoint, 1 = intersecting, 2 = contained.
    """
    d = jnp.linalg.norm(c1 - c2)
    return jnp.where(
        d >= r1 + r2,
        0,
        jnp.where(d <= jnp.abs(r1 - r2), 2, 1),
    )

disk_disk_union_area(c1, r1, c2, r2)

Compute the union area of two disks analytically.

Uses the standard two-circle intersection area formula: A_union = A_1 + A_2 - A_intersection.

Parameters:

Name Type Description Default
c1 Float[Array, 2]

Center of disk 1.

required
r1 Float[Array, '']

Radius of disk 1.

required
c2 Float[Array, 2]

Center of disk 2.

required
r2 Float[Array, '']

Radius of disk 2.

required

Returns:

Type Description
Float[Array, '']

Union area as a scalar.

Source code in src/brepax/analytical/disk_disk.py
def disk_disk_union_area(
    c1: Float[Array, "2"],
    r1: Float[Array, ""],
    c2: Float[Array, "2"],
    r2: Float[Array, ""],
) -> Float[Array, ""]:
    """Compute the union area of two disks analytically.

    Uses the standard two-circle intersection area formula:
    A_union = A_1 + A_2 - A_intersection.

    Args:
        c1: Center of disk 1.
        r1: Radius of disk 1.
        c2: Center of disk 2.
        r2: Radius of disk 2.

    Returns:
        Union area as a scalar.
    """
    d = jnp.linalg.norm(c1 - c2)
    area1 = jnp.pi * r1**2
    area2 = jnp.pi * r2**2
    intersection = _intersection_area(d, r1, r2)
    return area1 + area2 - intersection

sphere_sphere

Closed-form solutions for two-sphere Boolean operations.

Provides analytically differentiable union volume, stratum classification, and boundary distance for pairs of 3D spheres. Extends the two-disk pattern to three dimensions.

sphere_sphere_boundary_distance(c1, r1, c2, r2)

Distance from current configuration to the nearest stratum boundary.

Measures the minimum of distance to external tangency (d = r1 + r2) and internal tangency (d = |r1 - r2|).

Source code in src/brepax/analytical/sphere_sphere.py
def sphere_sphere_boundary_distance(
    c1: Float[Array, "3"],
    r1: Float[Array, ""],
    c2: Float[Array, "3"],
    r2: Float[Array, ""],
) -> Float[Array, ""]:
    """Distance from current configuration to the nearest stratum boundary.

    Measures the minimum of distance to external tangency (d = r1 + r2)
    and internal tangency (d = |r1 - r2|).
    """
    d = jnp.linalg.norm(c1 - c2)
    dist_external = jnp.abs(d - (r1 + r2))
    dist_internal = jnp.abs(d - jnp.abs(r1 - r2))
    return jnp.minimum(dist_external, dist_internal)

sphere_sphere_stratum_label(c1, r1, c2, r2)

Classify the topological stratum of a two-sphere configuration.

Returns:

Type Description
Integer[Array, '']

Integer-valued scalar: 0 = disjoint, 1 = intersecting, 2 = contained.

Source code in src/brepax/analytical/sphere_sphere.py
def sphere_sphere_stratum_label(
    c1: Float[Array, "3"],
    r1: Float[Array, ""],
    c2: Float[Array, "3"],
    r2: Float[Array, ""],
) -> Integer[Array, ""]:
    """Classify the topological stratum of a two-sphere configuration.

    Returns:
        Integer-valued scalar: 0 = disjoint, 1 = intersecting, 2 = contained.
    """
    d = jnp.linalg.norm(c1 - c2)
    return jnp.where(
        d >= r1 + r2,
        0,
        jnp.where(d <= jnp.abs(r1 - r2), 2, 1),
    )

sphere_sphere_union_volume(c1, r1, c2, r2)

Compute the union volume of two spheres analytically.

Uses the spherical cap intersection formula: V_union = V_1 + V_2 - V_intersection.

Parameters:

Name Type Description Default
c1 Float[Array, 3]

Center of sphere 1.

required
r1 Float[Array, '']

Radius of sphere 1.

required
c2 Float[Array, 3]

Center of sphere 2.

required
r2 Float[Array, '']

Radius of sphere 2.

required

Returns:

Type Description
Float[Array, '']

Union volume as a scalar.

Source code in src/brepax/analytical/sphere_sphere.py
def sphere_sphere_union_volume(
    c1: Float[Array, "3"],
    r1: Float[Array, ""],
    c2: Float[Array, "3"],
    r2: Float[Array, ""],
) -> Float[Array, ""]:
    """Compute the union volume of two spheres analytically.

    Uses the spherical cap intersection formula:
    V_union = V_1 + V_2 - V_intersection.

    Args:
        c1: Center of sphere 1.
        r1: Radius of sphere 1.
        c2: Center of sphere 2.
        r2: Radius of sphere 2.

    Returns:
        Union volume as a scalar.
    """
    d = jnp.linalg.norm(c1 - c2)
    vol1 = (4.0 / 3.0) * jnp.pi * r1**3
    vol2 = (4.0 / 3.0) * jnp.pi * r2**3
    intersection = _intersection_volume(d, r1, r2)
    return vol1 + vol2 - intersection