Metadata-Version: 2.4
Name: cad-tools
Version: 0.1.0
Summary: Generate 3D CAD models (STEP/STL) and multi-view renders from a declarative JSON intermediate representation, built on build123d.
Project-URL: Homepage, https://github.com/ToPo-ToPo-ToPo/cad-tools
Project-URL: Repository, https://github.com/ToPo-ToPo-ToPo/cad-tools
Author: ToPo
License: MIT
License-File: LICENSE
Keywords: 3d,build123d,cad,mcp,parametric,step,stl
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Manufacturing
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Multimedia :: Graphics :: 3D Modeling
Classifier: Topic :: Scientific/Engineering
Requires-Python: <3.13,>=3.12
Requires-Dist: build123d>=0.10.0
Requires-Dist: mcp[cli]>=1.2
Requires-Dist: numpy>=2.1
Requires-Dist: pillow>=11.0
Requires-Dist: pyvista>=0.45
Description-Content-Type: text/markdown

# cad-tools

[![Python](https://img.shields.io/badge/python-3.12-blue.svg)](https://www.python.org/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![Built on build123d](https://img.shields.io/badge/built%20on-build123d-orange.svg)](https://build123d.readthedocs.io/)

宣言的な JSON（semantic IR）から [build123d](https://build123d.readthedocs.io/) で
3D CAD モデルを生成し、**STEP / STL 出力**と **4 ビュー PNG レンダリング**を行う Python ライブラリ。

命令的な CAD コードではなく「どんな形状か」を JSON で記述するだけでモデルが組み上がる。
**AI エージェントが MCP 経由で形状を反復設計する**ことを主眼に設計している。

![L字ブラケットの 4 ビューレンダリング](https://raw.githubusercontent.com/ToPo-ToPo-ToPo/cad-tools/main/docs/images/l_bracket.png)

> 上図はサンプル `examples/l_bracket.py` の出力。ISO / 正面 / 上面 / 右側面の 4 ビュー。

---

## 特長

- **宣言的な IR** — プリミティブ・穴・面取り・中空などを JSON で組み合わせるだけ
- **相対配置** — 既存形状の面中心・角・中心（アンカー）を基準に部品を置ける
- **headless レンダリング** — VTK / PyVista による GUI 不要の 4 ビュー描画（CAD 風の輪郭付き）
- **MCP サーバ** — エージェントが「IR を渡す → 画像が返る」ループで設計を反復できる
- **標準フォーマット出力** — STEP（CAD）/ STL（メッシュ）/ PNG（確認用）

---

## インストール

Python 3.12 が必要。[uv](https://docs.astral.sh/uv/) を推奨する。

```bash
uv add cad-tools
```

pip の場合:

```bash
pip install cad-tools
```

> GUI / GPU の無い環境（コンテナ・CI）では、描画時に Xvfb 仮想ディスプレイを自動起動する。
> Linux では `Xvfb` がインストールされていること（例: `apt-get install xvfb`）。

---

## クイックスタート

```python
from cad_tools import Build123dEmitter, render_part

ir = {
    "features": [
        {"id": "base", "type": "box", "size": [40, 30, 10]},
        {"id": "post", "type": "cylinder", "radius": 5, "height": 20,
         "reference": {"feature": "base", "anchor": "top_face_center"}},
        {"id": "hole", "type": "hole", "target": "base", "diameter": 6, "depth": 10,
         "reference": {"feature": "base", "anchor": "top_face_center"}},
    ]
}

part = Build123dEmitter(ir).build()   # build123d の Solid を返す
render_part(part, "render.png")        # 4 ビュー PNG を書き出す
```

STEP / STL に出力するには build123d の関数をそのまま使える:

```python
from build123d import export_step, export_stl

export_step(part, "part.step")
export_stl(part, "part.stl")
```

---

## 公開 API

```python
from cad_tools import (
    Build123dEmitter,    # IR から build123d パーツを構築するメインクラス
    load_ir,             # JSON ファイルから IR を読み込む
    validate_ir,         # IR の構造を検証する（不正なら ValueError）
    render_part,         # パーツを 4 ビュー PNG に描画
    render_step,         # STEP ファイルを読み込んで 4 ビュー PNG に描画
    get_anchor_position, # ソリッドのアンカー座標を取得
    apply_transform,     # 回転・平行移動を適用
)
```

| 名前 | シグネチャ | 説明 |
|---|---|---|
| `Build123dEmitter(ir)` | `.build() -> Solid` | IR を検証・構築して build123d の Solid を返す |
| `render_part(part, png_path)` | `-> Path` | パーツを 2x2 マルチビュー PNG に描画 |
| `render_step(step_path, png_path)` | `-> Path` | STEP を読み込んで同様に描画 |
| `validate_ir(ir)` | `-> None` | 構造を検証（問題があれば `ValueError`） |
| `load_ir(path)` | `-> dict` | JSON ファイルから IR を読む |

---

## サンプル

リポジトリの `examples/` に IR の書き方を示すサンプルがある。各サンプルは
STEP / STL / 4 ビュー PNG を `workspace/<サンプル名>/` に書き出す（フォルダは自動作成）。

```bash
uv run python -m examples              # 全サンプルを生成
uv run python -m examples.l_bracket    # 個別に生成
```

| サンプル | 内容 | 使う機能 |
|---|---|---|
| `l_bracket` | L 字ブラケット（底板＋垂直板＋取り付け穴） | box, reference, linear 穴 |
| `flange` | 円形フランジ（中央穴＋ボルト円＋面取り） | cylinder, circular 穴, chamfer |
| `enclosure` | 角丸の中空ケース（上面開口＋4 隅穴） | fillet, shell, grid 穴 |
| `hex_standoff` | 六角スペーサ（貫通穴） | prism, hole |
| `o_ring` | O リング（ガスケット） | torus |
| `funnel` | 漏斗（上下開口の円錐台） | cone（テーパ）, shell |
| `ball_stud` | ボールスタッド（軸＋先端球） | cylinder, sphere, reference offset |
| `angle_bracket` | 補強リブ付き L 字ブラケット（曲げラウンド＋ボルト穴＋リブ） | extrude（L 断面＋角丸）, hole, transform |

---

## semantic IR リファレンス

IR は `features` のリスト。各 feature は `id`（一意）と `type` を持ち、`type` ごとの
フィールドを足す。feature はリスト順に処理され、`hole` / `fillet` / `chamfer` / `shell`
は `target` に指定した既存 feature を変更する。

```json
{
  "features": [
    {"id": "base", "type": "box", "size": [40, 30, 10]},
    {"id": "post", "type": "cylinder", "radius": 5, "height": 20,
     "reference": {"feature": "base", "anchor": "top_face_center"}},
    {"id": "h1", "type": "hole", "target": "base", "diameter": 6, "depth": 10,
     "reference": {"feature": "base", "anchor": "top_face_center"}}
  ]
}
```

### feature.type

| type | 種別 | 必須フィールド | 任意フィールド |
|---|---|---|---|
| `box` | 加算 | `size:[x,y,z]` | |
| `cylinder` | 加算 | `radius`, `height` | |
| `sphere` | 加算 | `radius` | |
| `cone` | 加算 | `radius`, `height` | `top_radius`（既定 0 = 尖り） |
| `torus` | 加算 | `major_radius`, `minor_radius` | |
| `prism` | 加算 | `radius`, `sides`, `height` | 正多角柱 |
| `extrude` | 加算 | `profile:[[x,y],...]`, `height` | `fillet_corners`（断面の角丸） |
| `hole` | 減算 | `target`, `diameter`, `depth` | `count`, `pattern` |
| `fillet` | 変更 | `target`, `radius` | `edges` |
| `chamfer` | 変更 | `target`, `length` | `edges` |
| `shell` | 変更 | `target`, `thickness` | `openings` |

### 配置（加算プリミティブ共通）

| キー | 説明 |
|---|---|
| `reference` | `{feature, anchor, offset?}` — 既存 feature のアンカーを基準に配置 |
| `position` | `[x, y, z]` — 絶対座標に配置（reference が無い場合） |
| `transform` | `{rotate:[rx,ry,rz], translate:[x,y,z]}` — 回転・平行移動（度） |

**anchor** に使える値:

- `center`
- `top_face_center` / `bottom_face_center` / `left_face_center` /
  `right_face_center` / `front_face_center` / `back_face_center`
- 角（8 種）: `top_left_front` / `top_right_front` / `top_left_back` /
  `top_right_back` / `bottom_left_front` / `bottom_right_front` /
  `bottom_left_back` / `bottom_right_back`

### hole の複数穴

`pattern` を付けると複数の穴を一括で開ける（`count` は linear / circular で使用）。

| pattern.kind | 指定 | 説明 |
|---|---|---|
| `linear` | `spacing:[dx,dy,dz]` | 基準位置から等間隔に `count` 個 |
| `grid` | `counts:[nx,ny]`, `spacing:[dx,dy]` | +x / +y に nx × ny 個の格子 |
| `circular` | `radius:R`（任意で `axis`, `start_angle`, `center`） | 円周上に `count` 個（ボルト円） |

### extrude の `fillet_corners`（断面の角丸）

押し出し前に 2D 断面の指定頂点をラウンドにする。L 字の内隅などに使う。
`corners` は `profile` の頂点インデックス（0 始まり、入力順）のリスト。

```json
{"id": "body", "type": "extrude", "height": 40,
 "profile": [[0,0],[50,0],[50,6],[6,6],[6,40],[0,40]],
 "fillet_corners": {"corners": [3], "radius": 6}}
```

### fillet / chamfer の `edges`

`all`（既定）/ `vertical` / `horizontal` / `top` / `bottom`

### shell の `openings`

開口する面の名前リスト。例 `["top"]`。省略すると全閉の中空になる。
使える面: `top` / `bottom` / `left` / `right` / `front` / `back`

### 例（円周ボルト穴＋面取り）

```json
{
  "features": [
    {"id": "flange", "type": "cylinder", "radius": 25, "height": 10},
    {"id": "bolts", "type": "hole", "target": "flange", "diameter": 4, "depth": 10,
     "reference": {"feature": "flange", "anchor": "top_face_center"},
     "count": 8, "pattern": {"kind": "circular", "radius": 18}},
    {"id": "edge", "type": "chamfer", "target": "flange", "length": 1, "edges": "top"}
  ]
}
```

---

## MCP サーバ

AI エージェントが「IR を渡す → 4 ビュー画像が返る」ループで形状を反復設計できる。

```bash
cad-tools-mcp                          # インストール後のコンソールスクリプト
# または
python -m cad_tools.mcp_server         # モジュールとして起動（stdio）
```

リポジトリ直下の `.mcp.json` により Claude Code では自動検出される。

| ツール | 入力 | 出力 |
|---|---|---|
| `validate_cad` | `ir` | 妥当性（`valid` / エラー文）。モデル構築なしの軽量チェック |
| `render_cad` | `ir`, `save_dir?` | **4 ビュー PNG 画像** ＋ サマリ。`save_dir` 指定で STEP/STL/PNG も保存 |
| `export_cad` | `ir`, `output_dir`, `basename?` | STEP/STL/PNG をディスクに保存しパスを返す |

`render_cad` は画像をインライン返却するため、エージェントが生成形状を直接「見て」
確認できる。構築に失敗した場合は例外ではなくエラー文を返すので、IR を自己修正しやすい。

---

## 開発

```bash
git clone https://github.com/ToPo-ToPo-ToPo/cad-tools
cd cad-tools
uv sync                                  # 依存と本パッケージを editable install

uv run python test.py                    # 複合アセンブリ
uv run python test_ring.py               # リング
uv run python test_schema_extensions.py  # IR 拡張機能（全 12 ケース）

uv build                                 # wheel / sdist を dist/ に生成
```

### プロジェクト構成

```
cad_tools/          ライブラリ本体（配布パッケージ）
├── __init__.py     公開 API
├── emitter.py      semantic IR → build123d ジオメトリ
├── validator.py    IR の構造検証
├── references.py   アンカー（面中心・角・中心）による相対配置
├── transforms.py   回転・平行移動
├── renderer.py     VTK/PyVista による headless マルチビュー描画
├── generate.py     ファイル入出力の CLI
└── mcp_server.py   MCP サーバ（validate_cad / render_cad / export_cad）
examples/           サンプル（l_bracket / flange / ...）
experimental/       退避した試作レンダラ（Blender / FreeCAD）
docs/images/        README 用の画像
```

---

## レンダラについて

default は **VTK / PyVista** ベースの headless 実装（`cad_tools/renderer.py`）。
特徴エッジ抽出で CAD 風の輪郭を出し、STL 三角分割のノイズを除く。
過去に試した Blender / FreeCAD 版は headless 運用が不安定なため
`experimental/` に退避している（経緯は `experimental/README.md`）。

---

## ライセンス

[MIT](LICENSE)
