Skip to content

ValueError: Null TopoDS_Shape object on the first boolean cut/union of two shapes, but not subsequent operations #2080

Description

@johnbeard

In some cases, when conducting a boolean cut or union on two almost-identical shapes, OCC returns a null TopoDS_Shape, which produces a raise of a ValueError: Null TopoDS_Shape object. It's not clear what triggers it, but it seems to happen rarely, but reliably on the same shapes when it happens.

However, only the first operation on the two shapes fails. Subsequent identical operations on the same object work as originally expected.

#1503 seems related, but was closed after a workaround. It's not immediately clear to me if it's exactly the same or not.

#1452 also could be similar (but it's a union operation)

To Reproduce

Using the two attached very similar objects (these are real objects I tried to do a difference for in the KiCad 3D package library):

model.zip

import sys
from pathlib import Path

import cadquery as cq


def main(argv: list[str]) -> int:
    if len(argv) != 3:
        print(f"Usage: {argv[0]} <model1.step> <model2.step>")
        return 2

    old_path = Path(argv[1])
    new_path = Path(argv[2])

    old = cq.importers.importStep(str(old_path))
    new = cq.importers.importStep(str(new_path))

    old_volume = old.val().Volume()
    new_volume = new.val().Volume()
    print(f"{str(old_path)} volume: {old_volume:.4f} mm^3")
    print(f"{str(new_path)} volume: {new_volume:.4f} mm^3")

    i = 0

    # Repeat n identical cut operations:
    # Failure on the first attempt and success on subsequent attempts.
    for i in range(1, 5):
        print(f"\nCut attempt {i}....")

        try:
            added = new.cut(old)
        except ValueError as exc:
            print(f"  Cut {i} raised {type(exc).__name__}: {exc}")
        else:
            added_volume = added.val().Volume()
            print(f"  Cut {i} succeeded. Added volume: {added_volume:.4f} mm^3")

if __name__ == "__main__":
    sys.exit(main(sys.argv))

Output of the above script on these files:

./null_topods.py model1.step model2.step 
model1.step volume: 281.1875 mm^3
model2.step volume: 281.8517 mm^3

Cut attempt 1....
  Cut 1 raised ValueError: Null TopoDS_Shape object

Cut attempt 2....
  Cut 2 succeeded. Added volume: 0.9051 mm^3

Cut attempt 3....
  Cut 3 succeeded. Added volume: 0.9051 mm^3

Cut attempt 4....
  Cut 4 succeeded. Added volume: 0.9051 mm^3

The same happens with the reverse order of model2.step model1.step.

The same happens if you change cut() to union().

Both models look like this, the differences are small:

Image

Environment

OS: Arch Linux

Was CadQuery installed using Conda?: No, installed with pip. Python 3.11.16,

cadquery                 2.6.1
cadquery-ocp             7.8.1.1.post1

I have seen these failures cropping up in diff attempts for at about year, but I don't have good records of what versions it was first seen in.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions