ValueError: Null TopoDS_Shape object on the first boolean cut/union of two shapes, but not subsequent operations
- 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:
## 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