strands-cad 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- strands_cad-0.3.0/.gitignore +16 -0
- strands_cad-0.3.0/PKG-INFO +145 -0
- strands_cad-0.3.0/README.md +102 -0
- strands_cad-0.3.0/examples/quickstart.py +18 -0
- strands_cad-0.3.0/pyproject.toml +67 -0
- strands_cad-0.3.0/strands_cad/__init__.py +40 -0
- strands_cad-0.3.0/strands_cad/_common.py +77 -0
- strands_cad-0.3.0/strands_cad/install_extras.py +33 -0
- strands_cad-0.3.0/strands_cad/tools/__init__.py +44 -0
- strands_cad-0.3.0/strands_cad/tools/bambu.py +336 -0
- strands_cad-0.3.0/strands_cad/tools/cadquery_tools.py +210 -0
- strands_cad-0.3.0/strands_cad/tools/gcode.py +182 -0
- strands_cad-0.3.0/strands_cad/tools/mesh_gen.py +286 -0
- strands_cad-0.3.0/strands_cad/tools/meta.py +115 -0
- strands_cad-0.3.0/strands_cad/tools/mf3.py +145 -0
- strands_cad-0.3.0/strands_cad/tools/neural_tools.py +400 -0
- strands_cad-0.3.0/strands_cad/tools/preview.py +107 -0
- strands_cad-0.3.0/strands_cad/tools/printability.py +248 -0
- strands_cad-0.3.0/strands_cad/tools/scad.py +286 -0
- strands_cad-0.3.0/strands_cad/tools/sdf_tools.py +404 -0
- strands_cad-0.3.0/strands_cad/tools/sim.py +209 -0
- strands_cad-0.3.0/strands_cad/tools/slice.py +181 -0
- strands_cad-0.3.0/strands_cad/tools/stl.py +505 -0
- strands_cad-0.3.0/tests/test_load.py +36 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: strands-cad
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: 🔧 Atomic CAD, mesh, SDF, cadquery, neural & print tools for Strands agents — prompt-to-print pipeline
|
|
5
|
+
Project-URL: Homepage, https://github.com/cagataycali/strands-cad
|
|
6
|
+
Project-URL: Repository, https://github.com/cagataycali/strands-cad
|
|
7
|
+
Project-URL: Issues, https://github.com/cagataycali/strands-cad/issues
|
|
8
|
+
Author: Cagatay Cali
|
|
9
|
+
License: MIT
|
|
10
|
+
Keywords: 3d,3d-printing,3mf,agents,bambu,cad,cadquery,mesh,openscad,sdf,shap-e,stl,strands
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Multimedia :: Graphics :: 3D Modeling
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering
|
|
21
|
+
Requires-Python: >=3.10
|
|
22
|
+
Requires-Dist: cadquery>=2.5
|
|
23
|
+
Requires-Dist: fast-simplification>=0.1
|
|
24
|
+
Requires-Dist: ipywidgets>=8.0
|
|
25
|
+
Requires-Dist: meshio>=5.0
|
|
26
|
+
Requires-Dist: mujoco>=3.0
|
|
27
|
+
Requires-Dist: numpy>=1.24
|
|
28
|
+
Requires-Dist: paho-mqtt>=2.0
|
|
29
|
+
Requires-Dist: pillow>=10.0
|
|
30
|
+
Requires-Dist: requests>=2.31
|
|
31
|
+
Requires-Dist: scikit-image>=0.22
|
|
32
|
+
Requires-Dist: scipy>=1.11
|
|
33
|
+
Requires-Dist: strands-agents>=0.1.0
|
|
34
|
+
Requires-Dist: torch>=2.0
|
|
35
|
+
Requires-Dist: torchvision>=0.15
|
|
36
|
+
Requires-Dist: trimesh>=4.0
|
|
37
|
+
Provides-Extra: dev
|
|
38
|
+
Requires-Dist: build; extra == 'dev'
|
|
39
|
+
Requires-Dist: pytest-cov; extra == 'dev'
|
|
40
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
41
|
+
Requires-Dist: twine; extra == 'dev'
|
|
42
|
+
Description-Content-Type: text/markdown
|
|
43
|
+
|
|
44
|
+
# 🔧 strands-cad
|
|
45
|
+
|
|
46
|
+
**Atomic CAD, mesh, SDF, cadquery, neural & print tools for [Strands](https://github.com/strands-agents) agents.**
|
|
47
|
+
|
|
48
|
+
Four independent paths to a printable 3D asset:
|
|
49
|
+
|
|
50
|
+
| Path | Tool | Best For |
|
|
51
|
+
|---|---|---|
|
|
52
|
+
| **Parametric SCAD** | `scad_render_stl` | Mechanical, brackets, parametric families |
|
|
53
|
+
| **B-rep CAD (NURBS)** | `cq_render_stl` / `cq_render_step` | Fillets, chamfers, engineering-grade parts |
|
|
54
|
+
| **SDF / implicit math** | `sdf_render_stl` | Organic, twisted, TPMS, blended surfaces |
|
|
55
|
+
| **Neural (text/image → 3D)** | `neural_text_to_stl` | AI generation from prompt or reference photo |
|
|
56
|
+
|
|
57
|
+
All roads lead to STL → 3MF → Bambu Lab.
|
|
58
|
+
|
|
59
|
+
## Install
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
pip install strands-cad
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Everything is a hard dependency — no extras needed. Includes:
|
|
66
|
+
`trimesh, sdf (fogleman), cadquery, shap-e, torch, scikit-image, fast-simplification, mujoco, paho-mqtt, scipy, numpy, meshio`.
|
|
67
|
+
|
|
68
|
+
**External** (system):
|
|
69
|
+
- `openscad` for `scad_*` tools (`brew install openscad`)
|
|
70
|
+
- `bambu-studio` for `slice_bambu` (bambulab.com)
|
|
71
|
+
|
|
72
|
+
## The 51 Atomic Tools
|
|
73
|
+
|
|
74
|
+
| Layer | Tools |
|
|
75
|
+
|---|---|
|
|
76
|
+
| **SCAD** (parametric) | `scad_probe`, `scad_render_stl`, `scad_render_png`, `scad_validate` |
|
|
77
|
+
| **CadQuery** (B-rep, NURBS) | `cq_render_stl`, `cq_render_step`, `cq_import_step`, `cq_render_svg` |
|
|
78
|
+
| **SDF** (implicit math) | `sdf_render_stl`, `sdf_list_primitives`, `sdf_gyroid_infill`, `sdf_from_function`, `sdf_lattice_infill_stl` |
|
|
79
|
+
| **Neural** (AI generation) | `neural_text_to_stl`, `neural_image_to_stl` |
|
|
80
|
+
| **Point Cloud** | `pointcloud_from_stl`, `pointcloud_to_stl`, `pointcloud_downsample` |
|
|
81
|
+
| **STL / Mesh** | `stl_parse`, `stl_volume`, `stl_bbox`, `stl_weight`, `stl_repair`, `stl_transform`, `stl_convert`, `mesh_decimate`, `mesh_normalize`, `mesh_boolean`, `mesh_combine`, `mesh_hollow` |
|
|
82
|
+
| **3MF** | `mf3_pack`, `mf3_unpack`, `mf3_read_metadata` |
|
|
83
|
+
| **Slice** | `slice_bambu`, `slice_profile_get`, `slice_estimate` |
|
|
84
|
+
| **Bambu Printer** | `bambu_connect`, `bambu_send`, `bambu_status`, `bambu_control`, `bambu_camera`, `bambu_ams` |
|
|
85
|
+
| **Sim** | `sim_build_mjcf`, `sim_run_headless`, `sim_view_live`, `sim_inertia_from_stl` |
|
|
86
|
+
| **Preview** | `preview_serve`, `preview_stop` |
|
|
87
|
+
| **Meta** | `bom_parse`, `bom_total`, `journal_append` |
|
|
88
|
+
|
|
89
|
+
## Quick Examples
|
|
90
|
+
|
|
91
|
+
### Parametric CAD (CadQuery)
|
|
92
|
+
```python
|
|
93
|
+
from strands_cad import cq_render_stl
|
|
94
|
+
|
|
95
|
+
cq_render_stl(script='''
|
|
96
|
+
result = (
|
|
97
|
+
cq.Workplane("XY").box(60, 40, 5)
|
|
98
|
+
.edges().fillet(2)
|
|
99
|
+
.faces(">Z").hole(20)
|
|
100
|
+
)
|
|
101
|
+
''', output_stl="bracket.stl")
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Implicit Math (SDF)
|
|
105
|
+
```python
|
|
106
|
+
from strands_cad import sdf_render_stl
|
|
107
|
+
|
|
108
|
+
sdf_render_stl(
|
|
109
|
+
expression="torus(30, 8).twist(radians(180)/60)",
|
|
110
|
+
output_stl="twisted_torus.stl",
|
|
111
|
+
resolution=0.4,
|
|
112
|
+
)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### AI Text → 3D (Shap-E)
|
|
116
|
+
```python
|
|
117
|
+
from strands_cad import neural_text_to_stl
|
|
118
|
+
|
|
119
|
+
neural_text_to_stl(
|
|
120
|
+
prompt="a stylized rocket ship",
|
|
121
|
+
output_stl="rocket.stl",
|
|
122
|
+
steps=64,
|
|
123
|
+
)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Full agent
|
|
127
|
+
```python
|
|
128
|
+
from strands import Agent
|
|
129
|
+
from strands_cad import ALL_TOOLS
|
|
130
|
+
|
|
131
|
+
agent = Agent(tools=ALL_TOOLS)
|
|
132
|
+
agent("Generate a mechanical bracket with M4 mounting holes, "
|
|
133
|
+
"verify weight in PLA, and pack it for my Bambu P1S.")
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Design Principles
|
|
137
|
+
|
|
138
|
+
- **Atomic** — one tool = one verb = one input shape = one output shape
|
|
139
|
+
- **No orchestration** inside tools; the agent composes
|
|
140
|
+
- **No hidden state** except the Bambu MQTT connection handle
|
|
141
|
+
- **Standard response**: `{status, content: [{text}], ...extras}`
|
|
142
|
+
|
|
143
|
+
## License
|
|
144
|
+
|
|
145
|
+
MIT
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# 🔧 strands-cad
|
|
2
|
+
|
|
3
|
+
**Atomic CAD, mesh, SDF, cadquery, neural & print tools for [Strands](https://github.com/strands-agents) agents.**
|
|
4
|
+
|
|
5
|
+
Four independent paths to a printable 3D asset:
|
|
6
|
+
|
|
7
|
+
| Path | Tool | Best For |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| **Parametric SCAD** | `scad_render_stl` | Mechanical, brackets, parametric families |
|
|
10
|
+
| **B-rep CAD (NURBS)** | `cq_render_stl` / `cq_render_step` | Fillets, chamfers, engineering-grade parts |
|
|
11
|
+
| **SDF / implicit math** | `sdf_render_stl` | Organic, twisted, TPMS, blended surfaces |
|
|
12
|
+
| **Neural (text/image → 3D)** | `neural_text_to_stl` | AI generation from prompt or reference photo |
|
|
13
|
+
|
|
14
|
+
All roads lead to STL → 3MF → Bambu Lab.
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pip install strands-cad
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Everything is a hard dependency — no extras needed. Includes:
|
|
23
|
+
`trimesh, sdf (fogleman), cadquery, shap-e, torch, scikit-image, fast-simplification, mujoco, paho-mqtt, scipy, numpy, meshio`.
|
|
24
|
+
|
|
25
|
+
**External** (system):
|
|
26
|
+
- `openscad` for `scad_*` tools (`brew install openscad`)
|
|
27
|
+
- `bambu-studio` for `slice_bambu` (bambulab.com)
|
|
28
|
+
|
|
29
|
+
## The 51 Atomic Tools
|
|
30
|
+
|
|
31
|
+
| Layer | Tools |
|
|
32
|
+
|---|---|
|
|
33
|
+
| **SCAD** (parametric) | `scad_probe`, `scad_render_stl`, `scad_render_png`, `scad_validate` |
|
|
34
|
+
| **CadQuery** (B-rep, NURBS) | `cq_render_stl`, `cq_render_step`, `cq_import_step`, `cq_render_svg` |
|
|
35
|
+
| **SDF** (implicit math) | `sdf_render_stl`, `sdf_list_primitives`, `sdf_gyroid_infill`, `sdf_from_function`, `sdf_lattice_infill_stl` |
|
|
36
|
+
| **Neural** (AI generation) | `neural_text_to_stl`, `neural_image_to_stl` |
|
|
37
|
+
| **Point Cloud** | `pointcloud_from_stl`, `pointcloud_to_stl`, `pointcloud_downsample` |
|
|
38
|
+
| **STL / Mesh** | `stl_parse`, `stl_volume`, `stl_bbox`, `stl_weight`, `stl_repair`, `stl_transform`, `stl_convert`, `mesh_decimate`, `mesh_normalize`, `mesh_boolean`, `mesh_combine`, `mesh_hollow` |
|
|
39
|
+
| **3MF** | `mf3_pack`, `mf3_unpack`, `mf3_read_metadata` |
|
|
40
|
+
| **Slice** | `slice_bambu`, `slice_profile_get`, `slice_estimate` |
|
|
41
|
+
| **Bambu Printer** | `bambu_connect`, `bambu_send`, `bambu_status`, `bambu_control`, `bambu_camera`, `bambu_ams` |
|
|
42
|
+
| **Sim** | `sim_build_mjcf`, `sim_run_headless`, `sim_view_live`, `sim_inertia_from_stl` |
|
|
43
|
+
| **Preview** | `preview_serve`, `preview_stop` |
|
|
44
|
+
| **Meta** | `bom_parse`, `bom_total`, `journal_append` |
|
|
45
|
+
|
|
46
|
+
## Quick Examples
|
|
47
|
+
|
|
48
|
+
### Parametric CAD (CadQuery)
|
|
49
|
+
```python
|
|
50
|
+
from strands_cad import cq_render_stl
|
|
51
|
+
|
|
52
|
+
cq_render_stl(script='''
|
|
53
|
+
result = (
|
|
54
|
+
cq.Workplane("XY").box(60, 40, 5)
|
|
55
|
+
.edges().fillet(2)
|
|
56
|
+
.faces(">Z").hole(20)
|
|
57
|
+
)
|
|
58
|
+
''', output_stl="bracket.stl")
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Implicit Math (SDF)
|
|
62
|
+
```python
|
|
63
|
+
from strands_cad import sdf_render_stl
|
|
64
|
+
|
|
65
|
+
sdf_render_stl(
|
|
66
|
+
expression="torus(30, 8).twist(radians(180)/60)",
|
|
67
|
+
output_stl="twisted_torus.stl",
|
|
68
|
+
resolution=0.4,
|
|
69
|
+
)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### AI Text → 3D (Shap-E)
|
|
73
|
+
```python
|
|
74
|
+
from strands_cad import neural_text_to_stl
|
|
75
|
+
|
|
76
|
+
neural_text_to_stl(
|
|
77
|
+
prompt="a stylized rocket ship",
|
|
78
|
+
output_stl="rocket.stl",
|
|
79
|
+
steps=64,
|
|
80
|
+
)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Full agent
|
|
84
|
+
```python
|
|
85
|
+
from strands import Agent
|
|
86
|
+
from strands_cad import ALL_TOOLS
|
|
87
|
+
|
|
88
|
+
agent = Agent(tools=ALL_TOOLS)
|
|
89
|
+
agent("Generate a mechanical bracket with M4 mounting holes, "
|
|
90
|
+
"verify weight in PLA, and pack it for my Bambu P1S.")
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Design Principles
|
|
94
|
+
|
|
95
|
+
- **Atomic** — one tool = one verb = one input shape = one output shape
|
|
96
|
+
- **No orchestration** inside tools; the agent composes
|
|
97
|
+
- **No hidden state** except the Bambu MQTT connection handle
|
|
98
|
+
- **Standard response**: `{status, content: [{text}], ...extras}`
|
|
99
|
+
|
|
100
|
+
## License
|
|
101
|
+
|
|
102
|
+
MIT
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Quickstart — spin up an agent with all strands-cad tools."""
|
|
2
|
+
from strands import Agent
|
|
3
|
+
from strands_cad import ALL_TOOLS
|
|
4
|
+
|
|
5
|
+
agent = Agent(
|
|
6
|
+
tools=ALL_TOOLS,
|
|
7
|
+
system_prompt=(
|
|
8
|
+
"You are a 3D-printing assistant with atomic CAD/mesh/slice/print tools. "
|
|
9
|
+
"Compose the tools to accomplish the user's goal. "
|
|
10
|
+
"Every tool does one job — chain them yourself."
|
|
11
|
+
),
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
if __name__ == "__main__":
|
|
15
|
+
# Example: "Analyze the STL at /tmp/part.stl and estimate its PLA weight."
|
|
16
|
+
import sys
|
|
17
|
+
q = " ".join(sys.argv[1:]) or "List every tool you have and one-line what each does."
|
|
18
|
+
print(agent(q))
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "strands-cad"
|
|
7
|
+
version = "0.3.0"
|
|
8
|
+
description = "🔧 Atomic CAD, mesh, SDF, cadquery, neural & print tools for Strands agents — prompt-to-print pipeline"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [{ name = "Cagatay Cali" }]
|
|
13
|
+
keywords = ["3d", "cad", "openscad", "cadquery", "sdf", "shap-e", "3d-printing", "bambu", "mesh", "stl", "3mf", "strands", "agents"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 4 - Beta",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"License :: OSI Approved :: MIT License",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Programming Language :: Python :: 3.10",
|
|
20
|
+
"Programming Language :: Python :: 3.11",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
"Programming Language :: Python :: 3.13",
|
|
23
|
+
"Topic :: Multimedia :: Graphics :: 3D Modeling",
|
|
24
|
+
"Topic :: Scientific/Engineering",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
dependencies = [
|
|
28
|
+
"strands-agents>=0.1.0",
|
|
29
|
+
# Core mesh
|
|
30
|
+
"numpy>=1.24",
|
|
31
|
+
"scipy>=1.11",
|
|
32
|
+
"trimesh>=4.0",
|
|
33
|
+
"scikit-image>=0.22",
|
|
34
|
+
"fast-simplification>=0.1",
|
|
35
|
+
# Real CAD (B-rep / NURBS)
|
|
36
|
+
"cadquery>=2.5",
|
|
37
|
+
# Neural helpers (Shap-E installed separately from git — see README)
|
|
38
|
+
"torch>=2.0",
|
|
39
|
+
"torchvision>=0.15",
|
|
40
|
+
"ipywidgets>=8.0",
|
|
41
|
+
"Pillow>=10.0",
|
|
42
|
+
# Sim
|
|
43
|
+
"mujoco>=3.0",
|
|
44
|
+
# Bambu printer control
|
|
45
|
+
"paho-mqtt>=2.0",
|
|
46
|
+
"requests>=2.31",
|
|
47
|
+
# Mesh IO
|
|
48
|
+
"meshio>=5.0",
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
# NOTE: `sdf` (fogleman) and `shap-e` (openai) are only on GitHub —
|
|
52
|
+
# PyPI disallows direct git URLs, so users install them separately:
|
|
53
|
+
# pip install strands-cad
|
|
54
|
+
# pip install git+https://github.com/fogleman/sdf.git # for SDF tools
|
|
55
|
+
# pip install git+https://github.com/openai/shap-e.git # for neural tools
|
|
56
|
+
# Or use the post-install helper: `python -m strands_cad.install_extras`
|
|
57
|
+
|
|
58
|
+
[project.optional-dependencies]
|
|
59
|
+
dev = ["pytest>=8.0", "pytest-cov", "build", "twine"]
|
|
60
|
+
|
|
61
|
+
[project.urls]
|
|
62
|
+
Homepage = "https://github.com/cagataycali/strands-cad"
|
|
63
|
+
Repository = "https://github.com/cagataycali/strands-cad"
|
|
64
|
+
Issues = "https://github.com/cagataycali/strands-cad/issues"
|
|
65
|
+
|
|
66
|
+
[tool.hatch.build.targets.wheel]
|
|
67
|
+
packages = ["strands_cad"]
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""strands-cad — atomic 3D tools for Strands agents."""
|
|
2
|
+
__version__ = "0.3.0"
|
|
3
|
+
|
|
4
|
+
from strands_cad.tools import (
|
|
5
|
+
scad_probe, scad_render_stl, scad_render_png, scad_validate,
|
|
6
|
+
stl_parse, stl_volume, stl_bbox, stl_weight, stl_repair,
|
|
7
|
+
stl_transform, stl_convert,
|
|
8
|
+
mesh_decimate, mesh_normalize, mesh_boolean, mesh_combine, mesh_hollow,
|
|
9
|
+
mf3_pack, mf3_unpack, mf3_read_metadata,
|
|
10
|
+
slice_bambu, slice_profile_get, slice_estimate,
|
|
11
|
+
bambu_connect, bambu_send, bambu_status, bambu_control,
|
|
12
|
+
bambu_camera, bambu_ams,
|
|
13
|
+
sim_build_mjcf, sim_run_headless, sim_view_live, sim_inertia_from_stl,
|
|
14
|
+
preview_serve, preview_stop,
|
|
15
|
+
bom_parse, bom_total, journal_append,
|
|
16
|
+
sdf_render_stl, sdf_list_primitives, sdf_gyroid_infill,
|
|
17
|
+
sdf_from_function, sdf_lattice_infill_stl,
|
|
18
|
+
cq_render_stl, cq_render_step, cq_import_step, cq_render_svg,
|
|
19
|
+
neural_text_to_stl, neural_image_to_stl,
|
|
20
|
+
pointcloud_from_stl, pointcloud_to_stl, pointcloud_downsample,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
ALL_TOOLS = [
|
|
24
|
+
scad_probe, scad_render_stl, scad_render_png, scad_validate,
|
|
25
|
+
stl_parse, stl_volume, stl_bbox, stl_weight, stl_repair,
|
|
26
|
+
stl_transform, stl_convert,
|
|
27
|
+
mesh_decimate, mesh_normalize, mesh_boolean, mesh_combine, mesh_hollow,
|
|
28
|
+
mf3_pack, mf3_unpack, mf3_read_metadata,
|
|
29
|
+
slice_bambu, slice_profile_get, slice_estimate,
|
|
30
|
+
bambu_connect, bambu_send, bambu_status, bambu_control,
|
|
31
|
+
bambu_camera, bambu_ams,
|
|
32
|
+
sim_build_mjcf, sim_run_headless, sim_view_live, sim_inertia_from_stl,
|
|
33
|
+
preview_serve, preview_stop,
|
|
34
|
+
bom_parse, bom_total, journal_append,
|
|
35
|
+
sdf_render_stl, sdf_list_primitives, sdf_gyroid_infill,
|
|
36
|
+
sdf_from_function, sdf_lattice_infill_stl,
|
|
37
|
+
cq_render_stl, cq_render_step, cq_import_step, cq_render_svg,
|
|
38
|
+
neural_text_to_stl, neural_image_to_stl,
|
|
39
|
+
pointcloud_from_stl, pointcloud_to_stl, pointcloud_downsample,
|
|
40
|
+
]
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""Shared utilities (STL parsing, response format)."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
import struct
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def ok(text: str, **extra: Any) -> dict:
|
|
9
|
+
"""Standard success response."""
|
|
10
|
+
r = {"status": "success", "content": [{"text": text}]}
|
|
11
|
+
r.update(extra)
|
|
12
|
+
return r
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def err(text: str) -> dict:
|
|
16
|
+
"""Standard error response."""
|
|
17
|
+
return {"status": "error", "content": [{"text": text}]}
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def parse_stl(path: str | Path):
|
|
21
|
+
"""Parse binary or ASCII STL → (verts:list[tuple[float,float,float]], tris:list[tuple[int,int,int]]).
|
|
22
|
+
|
|
23
|
+
Deduplicates verts (rounded to 4 decimals).
|
|
24
|
+
"""
|
|
25
|
+
p = Path(path)
|
|
26
|
+
if not p.exists():
|
|
27
|
+
raise FileNotFoundError(str(p))
|
|
28
|
+
with open(p, "rb") as f:
|
|
29
|
+
head = f.read(80)
|
|
30
|
+
rest = f.read(200).decode("latin-1", "ignore")
|
|
31
|
+
f.seek(0)
|
|
32
|
+
is_ascii = head.startswith(b"solid") and "facet" in rest
|
|
33
|
+
if is_ascii:
|
|
34
|
+
text = f.read().decode("ascii", errors="ignore")
|
|
35
|
+
verts, tris, v_map, current = [], [], {}, []
|
|
36
|
+
for line in text.splitlines():
|
|
37
|
+
s = line.strip()
|
|
38
|
+
if s.startswith("vertex"):
|
|
39
|
+
x, y, z = map(float, s.split()[1:4])
|
|
40
|
+
key = (round(x, 4), round(y, 4), round(z, 4))
|
|
41
|
+
if key not in v_map:
|
|
42
|
+
v_map[key] = len(verts)
|
|
43
|
+
verts.append(key)
|
|
44
|
+
current.append(v_map[key])
|
|
45
|
+
elif s.startswith("endfacet"):
|
|
46
|
+
if len(current) == 3:
|
|
47
|
+
tris.append(tuple(current))
|
|
48
|
+
current = []
|
|
49
|
+
return verts, tris
|
|
50
|
+
# binary
|
|
51
|
+
f.seek(80)
|
|
52
|
+
n = struct.unpack("<I", f.read(4))[0]
|
|
53
|
+
verts, tris, v_map = [], [], {}
|
|
54
|
+
for _ in range(n):
|
|
55
|
+
f.read(12) # normal
|
|
56
|
+
idx = []
|
|
57
|
+
for _ in range(3):
|
|
58
|
+
x, y, z = struct.unpack("<fff", f.read(12))
|
|
59
|
+
key = (round(x, 4), round(y, 4), round(z, 4))
|
|
60
|
+
if key not in v_map:
|
|
61
|
+
v_map[key] = len(verts)
|
|
62
|
+
verts.append(key)
|
|
63
|
+
idx.append(v_map[key])
|
|
64
|
+
f.read(2) # attribute byte count
|
|
65
|
+
tris.append(tuple(idx))
|
|
66
|
+
return verts, tris
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def signed_volume_cm3(verts, tris) -> float:
|
|
70
|
+
"""Signed-tetrahedron volume in cm³ (STL is in mm)."""
|
|
71
|
+
vol = 0.0
|
|
72
|
+
for a_i, b_i, c_i in tris:
|
|
73
|
+
a, b, c = verts[a_i], verts[b_i], verts[c_i]
|
|
74
|
+
vol += (a[0] * (b[1] * c[2] - b[2] * c[1])
|
|
75
|
+
- a[1] * (b[0] * c[2] - b[2] * c[0])
|
|
76
|
+
+ a[2] * (b[0] * c[1] - b[1] * c[0])) / 6.0
|
|
77
|
+
return abs(vol) / 1000.0
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""Install optional git-only deps for strands-cad SDF + neural tools.
|
|
2
|
+
|
|
3
|
+
Usage:
|
|
4
|
+
python -m strands_cad.install_extras # install both
|
|
5
|
+
python -m strands_cad.install_extras sdf # SDF only
|
|
6
|
+
python -m strands_cad.install_extras neural # neural only
|
|
7
|
+
"""
|
|
8
|
+
import subprocess
|
|
9
|
+
import sys
|
|
10
|
+
|
|
11
|
+
EXTRAS = {
|
|
12
|
+
"sdf": "git+https://github.com/fogleman/sdf.git",
|
|
13
|
+
"neural": "git+https://github.com/openai/shap-e.git",
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def main():
|
|
18
|
+
which = sys.argv[1:] or list(EXTRAS.keys())
|
|
19
|
+
for name in which:
|
|
20
|
+
if name not in EXTRAS:
|
|
21
|
+
print(f"❌ unknown extra '{name}'. Options: {list(EXTRAS.keys())}")
|
|
22
|
+
sys.exit(1)
|
|
23
|
+
url = EXTRAS[name]
|
|
24
|
+
print(f"→ installing {name} from {url}")
|
|
25
|
+
rc = subprocess.call([sys.executable, "-m", "pip", "install", url])
|
|
26
|
+
if rc != 0:
|
|
27
|
+
print(f"❌ failed to install {name}")
|
|
28
|
+
sys.exit(rc)
|
|
29
|
+
print("✅ all requested extras installed")
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
if __name__ == "__main__":
|
|
33
|
+
main()
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""Atomic tools for strands-cad."""
|
|
2
|
+
from strands_cad.tools.scad import scad_probe, scad_render_stl, scad_render_png, scad_validate
|
|
3
|
+
from strands_cad.tools.stl import (
|
|
4
|
+
stl_parse, stl_volume, stl_bbox, stl_weight, stl_repair, stl_transform, stl_convert,
|
|
5
|
+
mesh_decimate, mesh_normalize, mesh_boolean, mesh_combine, mesh_hollow,
|
|
6
|
+
)
|
|
7
|
+
from strands_cad.tools.mf3 import mf3_pack, mf3_unpack, mf3_read_metadata
|
|
8
|
+
from strands_cad.tools.slice import slice_bambu, slice_profile_get, slice_estimate
|
|
9
|
+
from strands_cad.tools.bambu import (
|
|
10
|
+
bambu_connect, bambu_send, bambu_status, bambu_control, bambu_camera, bambu_ams
|
|
11
|
+
)
|
|
12
|
+
from strands_cad.tools.sim import sim_build_mjcf, sim_run_headless, sim_view_live, sim_inertia_from_stl
|
|
13
|
+
from strands_cad.tools.preview import preview_serve, preview_stop
|
|
14
|
+
from strands_cad.tools.meta import bom_parse, bom_total, journal_append
|
|
15
|
+
from strands_cad.tools.sdf_tools import (
|
|
16
|
+
sdf_render_stl, sdf_list_primitives, sdf_gyroid_infill,
|
|
17
|
+
sdf_from_function, sdf_lattice_infill_stl,
|
|
18
|
+
)
|
|
19
|
+
from strands_cad.tools.cadquery_tools import (
|
|
20
|
+
cq_render_stl, cq_render_step, cq_import_step, cq_render_svg,
|
|
21
|
+
)
|
|
22
|
+
from strands_cad.tools.neural_tools import (
|
|
23
|
+
neural_text_to_stl, neural_image_to_stl,
|
|
24
|
+
pointcloud_from_stl, pointcloud_to_stl, pointcloud_downsample,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
__all__ = [
|
|
28
|
+
"scad_probe", "scad_render_stl", "scad_render_png", "scad_validate",
|
|
29
|
+
"stl_parse", "stl_volume", "stl_bbox", "stl_weight", "stl_repair",
|
|
30
|
+
"stl_transform", "stl_convert",
|
|
31
|
+
"mesh_decimate", "mesh_normalize", "mesh_boolean", "mesh_combine", "mesh_hollow",
|
|
32
|
+
"mf3_pack", "mf3_unpack", "mf3_read_metadata",
|
|
33
|
+
"slice_bambu", "slice_profile_get", "slice_estimate",
|
|
34
|
+
"bambu_connect", "bambu_send", "bambu_status", "bambu_control",
|
|
35
|
+
"bambu_camera", "bambu_ams",
|
|
36
|
+
"sim_build_mjcf", "sim_run_headless", "sim_view_live", "sim_inertia_from_stl",
|
|
37
|
+
"preview_serve", "preview_stop",
|
|
38
|
+
"bom_parse", "bom_total", "journal_append",
|
|
39
|
+
"sdf_render_stl", "sdf_list_primitives", "sdf_gyroid_infill",
|
|
40
|
+
"sdf_from_function", "sdf_lattice_infill_stl",
|
|
41
|
+
"cq_render_stl", "cq_render_step", "cq_import_step", "cq_render_svg",
|
|
42
|
+
"neural_text_to_stl", "neural_image_to_stl",
|
|
43
|
+
"pointcloud_from_stl", "pointcloud_to_stl", "pointcloud_downsample",
|
|
44
|
+
]
|