CadQuery / CadQuery/cadquery

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

Open
#2,080 2 comments 0 reactions 0 assignees View on GitHub
bug
Dominant language
Python
Stars
5.8k
Forks
541
Avg merge
3d 2h
Merged PRs (30d)
5

Description

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.

https://github.com/CadQuery/cadquery/issues/1503 seems related, but was closed after a workaround. It's not immediately clear to me if it's exactly the same or not.

https://github.com/CadQuery/cadquery/issues/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](https://github.com/user-attachments/files/31335097/model.zip)

```python
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]} ")
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.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start by running the provided script with the attached model1.step and model2.step files, focusing on importStep(), cut(), and union(). Compare the first and subsequent operations in both operand orders and check how the resulting TopoDS_Shape is handled. Done means the reproduced first operation no longer raises ValueError and produces the same valid result as later identical operations.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
computer-graphics
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.