pberlizov/ViminCADConverter

GitHub: pberlizov/ViminCADConverter

将网格或点云逆向转换为可执行的参数化CAD脚本,从而恢复可编辑的机械零件特征。

Stars: 0 | Forks: 0

# ViminCADConverter **网格 / 点云 → 参数化 CAD:** 将 **STL、OBJ、 PLY** 网格或 **`.xyz` / `.pts` / `.csv` / `.npy`** 点云转换为可运行的 **Python + [build123d](https://github.com/gumyr/build123d)** 脚本,当安装了 `build123d` 时,可选择导出 **STEP** 和预览 **STL**。包含 **CLI**、**FastAPI** (`mesh2cad-api`)、**Gradio UI** (`mesh2cad-ui`)、可选的 **Redis + RQ** worker,以及 **Docker / Kubernetes** 示例。 可安装的 Python 包和 CLI 入口点保留了 **`mesh2cad`** 的名称(导入 `mesh2cad`,命令为 `mesh2cad`、`mesh2cad-api`、`mesh2cad-ui`)。 目前的涵盖范围: - **棱柱形路径**:成对的平行平面 → 基础拉伸轮廓(凸形或简单凹形),支持: - 根据圆柱体拟合推断出的通孔,包括当孔轴线穿过毛坯面时的倾斜/非平行轴 - 与通孔配对的沉孔(锥体基本体),包括倾斜沉孔 - 盲孔,包括带有明确轴线指定的倾斜/非平行盲孔 - **旋转形路径**:当全局形状看起来像旋转体且存在强 **圆柱体** 基本体时,生成 **姿态感知的旋转** 脚本(`REVOLVE_PLANE` + 根据推断出的轴确定的 `Axis(ORIGIN, AXIS_DIR)`)。 - **build123d 脚本优先的合成**:当安装了 `build123d` 时,生成的 Python 代码可以在稍后执行,以生成 `STEP` 和预览 `STL` 导出。 当前的 CAD 特征支持: - 根据成对的平行毛坯面和拉伸轮廓恢复 `BaseExtrudeFeature`。 - 根据圆柱体基本体推断 `ThroughHoleFeature`,包括当圆柱体基本体轴线穿过推断出的毛坯面时的倾斜/非平行孔轴线。 - `CounterSinkHoleFeature` 支持与通孔配对的沉孔圆锥体,包括与倾斜孔轴线对齐的倾斜沉孔。 - `BlindHoleFeature` 推断,支持倾斜/非平行轴线。 - `RevolveSolidFeature` 用于以强圆柱体基本体为主的简单旋转零件。 - 生成 `build123d` 脚本输出,可选择执行以生成 `STEP` 和预览 `STL`。 范围与客观说明: - **凸台和型腔** 使用保守的判定条件(基本体置信度、最小支持、轮廓跨度与凸台半径之比、型腔凸环纵横比),因此充满噪点的扫描会产生较少的虚假修饰符;极其模糊的几何形状可能仍然会漏检或多检特征。 - **有机/艺术曲面**、**多实体装配体**(配合、各零件树状结构)、**钣金展开/折弯语义** 以及 **源 CAD 特征历史记录** 不会被恢复为第一类模型。当输入网格具有 **多个不连通的组件** 时,pipeline 会保留一个实体(默认为按面积计算的最大实体,或通过 `repair_component_index` 指定)并发出 **警告**;相对于宽度极其 **薄板** 的毛坯会触发 **钣金范围** 警告。NURBS 或细分“按原样扫描”的曲面不会被导出——输出仍然保持为 **build123d** 基本体组合。 ## 路线图(深度与广度) 我们将 **深化当前路径**(更干净的草图、孔、框架、验证)和 **开发新的机械工作流**(例如额外的零件类别)视为并行目标,而不是非此即彼。每一个有意义的变更都应附带 **测试**(单元/冒烟测试),并在适用的情况下更新 `benchmarks/cases.json` 中的 **benchmark 目录**,以确保 CI 机制严谨有效。 ## 安装 从本仓库的克隆版本开始: ``` pip install -e . # 仅使用 CLI + numpy stack pip install -e ".[dev]" # pytest pip install -e ".[api]" # FastAPI + uvicorn + pydantic pip install -e ".[full]" # adds build123d, open3d, gradio, … pip install -e ".[queue]" # optional: redis + rq for Redis-backed job workers pip install -e ".[open3d]" # optional: Open3d for MESH2CAD_USE_OPEN3D_METRICS (also in [full]) pip install -e ".[cad]" # optional: build123d only (Dockerfile.full / in-container STEP export) ``` 要求 **Python ≥ 3.11**。 ## 使用说明 ### 命令行(`mesh2cad`) 典型工作流: ``` # Mesh → report + build123d script + 安装了 build123d 时可选的 STEP/STL mesh2cad part.stl --output-dir ./out # 仅 script 和 metrics(不执行 CAD) mesh2cad part.stl --no-build --sample-count 8000 # 固定 sample 数量(禁用自动 sample 调优) mesh2cad part.stl --no-auto-tune # Point cloud 输入;可选的 ICP 调优用于验证 mesh2cad cloud.xyz --no-build --icp-iterations 15 ``` `--output-dir` 下的输出包含结构化报告和生成的 Python 代码;当安装了 **`build123d`** 且启用了构建时,如果 pipeline 成功运行,您还将获得 STEP/预览 STL。 ### HTTP API (`mesh2cad-api`) ``` export MESH2CAD_STATE_DIR=/var/lib/mesh2cad # required for uploads and job storage mesh2cad-api # default http://127.0.0.1:8000 - use MESH2CAD_BIND_HOST=0.0.0.0 in containers ``` - **交互式文档:** `http://:8000/docs` (OpenAPI)。 - **健康检查:** `GET /health`(进程运行中),`GET /ready`(SQLite + 状态目录可写;当设置了 **`MESH2CAD_JOB_BACKEND=rq`** 时还会检查 **Redis**)。 **同步** 上传 + 处理(`multipart/form-data`,字段 `file`): ``` curl -sS -X POST "http://127.0.0.1:8000/v1/process" \ -H "X-API-Key: YOUR_KEY" \ -F "file=@./part.stl" \ -F "build=true" \ -F "include_script=true" ``` JSON 正文包含常规的 pipeline 字段,以及 **`session_id`** 和一个路径的 **`artifacts`** 映射,例如 **`/v1/process/artifacts//step`**(当 **`build123d`** 成功运行时的 STEP 文件)、**`…/report`**、**`…/script`**、**`…/preview`**、**`…/input`**。对该 URL 发起 `GET` 请求(与其他 `/v1` 路由遵循相同的 **`MESH2CAD_API_KEYS`** 规则)即可下载二进制文件,无需轮询异步任务。 Multipart 上传的文件和构建输出存储在 **`$MESH2CAD_STATE_DIR/v1_sync//`** 目录下(表单字段 **`output_dir`** 不用于 multipart,以确保路径可预测)。如果频繁进行同步上传,请按计划定期清理旧的 **`v1_sync`** 目录。 **JSON** `POST /v1/process`(正文字段 **`input_path`** 指向服务器上已存在的文件)返回相同的 pipeline JSON,但 **不包含** **`session_id`** / **`artifacts`**;在这种情况下,请使用异步 **`POST /v1/jobs`** + **`GET /v1/jobs/{id}/artifacts/...`** 来获取可下载的文件。 当未配置 **`MESH2CAD_API_KEYS`** 时(仅限本地开发),请省略 **`X-API-Key`**。 **异步** 任务(表单字段与 `/v1/process` 相同;轮询 `GET /v1/jobs/{id}` 或订阅 `GET /v1/jobs/{id}/events`): ``` curl -sS -X POST "http://127.0.0.1:8000/v1/jobs" \ -H "X-API-Key: YOUR_KEY" \ -H "Idempotency-Key: unique-string" \ -F "file=@./part.stl" ``` 当设置了 **`MESH2CAD_API_KEYS`** 时,请在每次调用 `/v1` 时发送 **`X-API-Key`** 或 **`Authorization: Bearer `**。 **遗留路由**(`POST /process`、`POST /process/submit`,以及 `/process/jobs/...` 下的任务轮询)为旧版集成保留;新开发的工作应使用 **`/v1`**。 ### Web UI (`mesh2cad-ui`) ``` mesh2cad-ui # default http://127.0.0.1:7860 - Gradio: path or upload, JSON + downloads ``` 使用 **`MESH2CAD_STATE_DIR`**(或 **`$TMPDIR`**)存储临时上传文件和任务文件。首次运行浏览器 UI 时可能会提示创建管理员用户(有关设置 URL 请参阅应用日志)。 ### Docker(单机) ``` cp deploy/env.example .env # optional; edit MESH2CAD_* and ports docker compose up --build # API on port 8000 (MESH2CAD_HOST_PORT) ``` **Redis + 后台 worker**(当任务耗时较长或您希望 API 进程保持响应时推荐使用): ``` docker compose -f docker-compose.yml -f docker-compose.queue.yml up -d --build ``` 详细信息:**[docs/deploy-docker.md](docs/deploy-docker.md)**。 ### Kubernetes 面向生产的配置包(集群内 Redis,包含 API + `mesh2cad-rq-worker` 的 **单个 Pod**,**ReadWriteOnce** PVC): ``` kubectl apply -k deploy/k8s ``` 在应用(apply)之前,请编辑 **`deploy/k8s/deployment-api.yaml`** 中的镜像引用。仅使用线程的变体和 Ingress 模板:**`deploy/k8s/README.md`**。 ## 当前的面向用户部署方案 本项目目前 **可作为** **单租户** 服务 **进行部署**:一个持久化的 **`MESH2CAD_STATE_DIR`**,一套协同工作的 API + 任务集群,且对 Postgres 或 S3 没有硬性依赖。这适用于内部工具、按客户分配的 VM,或为每个客户分配一个 namespace。 | 您应该具备 | 原因 | |-----------------|-----| | 用于 `MESH2CAD_STATE_DIR` 的 **持久化磁盘** | SQLite、上传文件和任务产物都存放在这里。 | | 应用前方的 **TLS**(反向代理或 Ingress) | 加密流量;为浏览器 UI 设置 **`MESH2CAD_SECURE_COOKIES=true`**。 | | 在任何不受信任的网络中配置 **`MESH2CAD_API_KEYS`** | 否则 `/v1` 将处于开放状态。 | | 用于准生产环境负载的 **Redis + RQ** | `docker-compose.queue.yml` 或 **`kubectl apply -k deploy/k8s`**,以防止长时间运行的任务阻塞 Uvicorn;参见 **[docs/operations.md](docs/operations.md)**。 | | **备份 + 保留策略** | `scripts/backup-mesh2cad-state.sh`(主机端)或 `kubectl exec` + `tar`(参见运维文档);定期执行 **`mesh2cad-purge-jobs`**。 | | **可观测性(可选)** | **`MESH2CAD_LOG_JSON`**、**`MESH2CAD_LOG_LEVEL`**;用于 Prometheus 的 **`MESH2CAD_METRICS_ENABLED`** - 当设置了密钥时,**`GET /metrics`** 遵循与 **`/v1`** 相同的 **`MESH2CAD_API_KEYS`** 规则(未设置时为开放状态;但仍建议配置网络策略)。 | **预构建镜像:** CI 可以发布 **`ghcr.io//:latest`**(API + 队列客户端)和 **`:cad`**(包含 **build123d** 以实现容器内 STEP 导出)。拉取这些 tag 并将您的 compose 或 Kubernetes 清单指向它们。 **可选分发方式:** 将 **`mesh2cad`** 包发布到 PyPI(或私有索引),以便用户无需克隆即可执行 `pip install "mesh2cad[api]"`;您仍然需要进程管理器或容器来长时间运行 **`mesh2cad-api`**。 **对于“当前”部署不是必需的,但多租户 SaaS 规模扩展需要:** 用于元数据的共享 Postgres、用于产物的对象存储 / 预签名下载,以及多个无状态 API 副本(避免 SQLite 竞争)。 ## 环境变量 | 变量 | 用途 | |----------|---------| | `MESH2CAD_STATE_DIR` | SQLite 数据库 + 上传文件 + 任务目录(测试时会自动设置一个临时目录)。 | | `MESH2CAD_JOB_TIMEOUT_SEC` | Worker 子进程的挂钟时间(默认为 `900`)。 | | `MESH2CAD_MAX_UPLOAD_MB` | UI 和 `/v1` 的上传大小上限。 | | `MESH2CAD_SECURE_COOKIES` | 在 HTTPS 后端设置为 `true`。 | | `MESH2CAD_API_KEYS` | 以逗号分隔的密钥,只要此变量不为空,访问 **`/v1/*`**、遗留的 **`/process*`** 以及 **`GET /metrics`**(当启用指标时)都需要提供。 | | `MESH2CAD_WEBHOOK_SECRET` | 用于任务 webhooks 的可选 HMAC 密钥(`X-Mesh2cad-Signature` 带有 `sha256=` 前缀)。 | | `MESH2CAD_CORS_ORIGINS` | 允许进行 CORS 的以逗号分隔的源列表。 | | `MESH2CAD_LOG_LEVEL` | Python 日志级别(`INFO`、`DEBUG` 等)。 | | `MESH2CAD_LOG_JSON` | 设置为 `true` 以在 stderr 输出 JSON 行(便于日志采集)。 | | `MESH2CAD_METRICS_ENABLED` | 设置为 `true` 以在 **`GET /metrics`** 暴露 Prometheus 文本格式。当设置了 **`MESH2CAD_API_KEYS`** 时,客户端必须发送与 **`/v1`** 相同的 **`X-API-Key`** / Bearer token。 | | `MESH2CAD_RATE_LIMIT_PER_MINUTE` | 针对单个客户端 IP,对 `POST /v1/process`、`POST /v1/jobs`、`POST /process` 的限制上限(默认为 `120`)。 | | `MESH2CAD_RATE_LIMIT_BACKEND` | 设置为 **`redis`** 并配合 **`MESH2CAD_REDIS_URL`** 以在多个 API 副本之间实现共享速率限制。 | | `MESH2CAD_RATE_LIMIT_REDIS_PREFIX` | 用于速率计数器的 Redis 键前缀(默认为 `meshcad:rl`)。 | | `MESH2CAD_MAX_REQUEST_MB` | POST/PUT/PATCH 请求的最大 `Content-Length`(默认为 `256` MiB)。 | | `MESH2CAD_MAX_REQUEST_BYTES` | 可选的精确字节数上限(设置后将覆盖 MB 配置)。 | | `MESH2CAD_JOB_WORKERS` | 当 **`MESH2CAD_JOB_BACKEND=thread`** 时用于异步任务的线程池大小(默认为 `2`)。 | | `MESH2CAD_JOB_BACKEND` | `thread`(默认值,进程内线程池)或使用 **`rq`** 并配合 **`MESH2CAD_REDIS_URL`** 进行基于 Redis 的任务。 | | `MESH2CAD_REDIS_URL` | 使用 **`rq`** 时的 Redis URL(例如 `redis://redis:6379/0`)。 | | `MESH2CAD_RQ_QUEUE` | RQ 队列名称(默认为 `mesh2cad`)。 | | `MESH2CAD_RQ_WORKER_NAME` | 可选的 RQ worker 显示名称(默认为 `mesh2cad-1`)。 | | `MESH2CAD_BIND_HOST` | 用于 **`mesh2cad-api`** 的 Uvicorn 绑定地址(默认为 `127.0.0.1`;在容器中使用 `0.0.0.0`)。 | | `MESH2CAD_BIND_PORT` | Uvicorn 端口(默认为 `8000`)。 | | `MESH2CAD_USE_OPEN3D_METRICS` | 当设为 `true`/`1` 且安装了 `open3d` 时,验证过程将使用 Open3D 光线投射计算点到网格的距离(否则回退到 trimesh)。 | | `MESH2CAD_USE_OPEN3D_CLOUD` | 当设为 `true`/`1` 且安装了 `open3d` 时,大型点云将使用 Open3D 进行 **法线估计**(参见 `MESH2CAD_OPEN3D_CLOUD_MIN_POINTS`)。 | | `MESH2CAD_OPEN3D_CLOUD_MIN_POINTS` | 切换至 Open3D 进行法线估计的最小点数要求(默认为 `50000`)。 | | `MESH2CAD_JOB_RETENTION_DAYS` | **`mesh2cad-purge-jobs --days`** 的默认值(见下文)。 | | `MESH2CAD_WEBHOOK_ALLOW_HTTP` | 设置为 `true` 以允许 `http://` 的 webhook URL(仅限开发环境)。 | | `MESH2CAD_RELAX_INPUT_PATH_GUARD` | 设置为 `true`/`1`/`on` 以允许 JSON 中的 **`input_path`** / **`output_dir`** 指向 **`MESH2CAD_STATE_DIR`** 之外的路径(仅限本地调试;**严禁** 在不受信任的网络中使用)。 | **HTTP API 路径策略:** 在服务器上引用 **`input_path`**(以及可选的 **`output_dir`**)的 JSON 正文必须解析为 **`MESH2CAD_STATE_DIR`** 下的路径,除非启用了 **`MESH2CAD_RELAX_INPUT_PATH_GUARD`**。在生产环境中,请使用 multipart 上传或将输入文件复制到状态目录中。 ### 任务保留 处于终态(`completed` / `failed` / `cancelled`)且时间超过 **N** 天(根据 `updated_at` 判断)的任务可以从 SQLite 和磁盘上移除: ``` mesh2cad-purge-jobs --days 30 ``` 建议按计划(例如每周 cron)运行此命令,以免 `MESH2CAD_STATE_DIR` 无限增长。 ### 单副本与水平扩展 - **当前状态:** SQLite、磁盘上的任务产物、进程内速率限制,以及(默认情况下)**线程池** 任务运行器都是 **基于单主机的假设**。除非您了解 SQLite 的并发限制,或者使用 **粘性会话(sticky sessions)** 并接受按进程计算的速率限制,否则每个 `MESH2CAD_STATE_DIR` **仅运行一个 API 副本**。 - **水平扩展的 job worker:** 设置 **`MESH2CAD_JOB_BACKEND=rq`** 和 **`MESH2CAD_REDIS_URL`**,然后运行 **`mesh2cad-rq-worker`**(参见 **`docker-compose.queue.yml`**)。在 Kubernetes 中使用 **ReadWriteOnce** PVC 时,请在一个 Pod 中同时运行 API 和 worker(`kubectl apply -k deploy/k8s`)。Worker 之间仍然共享 **`MESH2CAD_STATE_DIR`** 和 SQLite;WAL 模式会有所帮助,但您应该尽量减少并发写入操作。参见 **[docs/operations.md](docs/operations.md)** 和 **`deploy/k8s/README.md`**。 - **长期规模扩展:** 用于产物的共享对象存储和非 SQLite 任务存储依然是超越 RQ 的产品未来发展方向。 ### Docker 和 Kubernetes(参考) 镜像:**`Dockerfile`**(API + 队列)、**`Dockerfile.full`**(**`[cad]`** / build123d)。Compose 配置:**`docker-compose.yml`**、**`docker-compose.queue.yml`**。健康检查使用 **`GET /ready`**。推送到 **`main`** / **`master`** 分支的操作可以发布 **`ghcr.io//:latest`**、**`:cad`** 以及带有 SHA 标签的变体(**Publish container images** 工作流)。完整检查清单:**[docs/deploy-docker.md](docs/deploy-docker.md)**。 ## 安全与隐私 - 默认情况下,处理过程在 **本地** 进行;本仓库不包含对付费的第三方“AI mesh” API 的调用。 - **请勿提交** 真实的 API 密钥、token 或生产环境密码(`.env` 已在 gitignore 中配置)。自动化测试仅使用 **虚拟(dummy)** 凭证;在真实部署中请务必更改默认设置。 - 如果不慎将密钥粘贴到了聊天记录、工单或提交记录中,请立即 **吊销并轮换** 该密钥——必须假设它已经泄露。 ## 基准测试与北极星指标 - 测试目录:`benchmarks/cases.json`(合成网格、**`.xyz` 点云**、`benchmarks/fixtures/` 下的小型 **测试夹具文件**,以及可选的由 **build123d** 构建的网格)。运行器:`mesh2cad.benchmarks.runner。测试用例可以设置 **`build_export`: true** 以运行 STEP/STL 导出(需要可选依赖 **build123d**);可选的 **`expect_warning_substr`** 会检查合并后的 pipeline 警告(例如验证表面的字符串)。**`expect_route_any_of`** 和 **`min_feature_kind_counts_by_route`** 允许对路由敏感的测试用例(例如胶囊体),而无需进行脆弱的单一断言。可选的 **`repair_component_index`** 会在推断之前选择多实体组件。**`build123d_two_hole_plate`** 生成器通过 **build123d** 将预览 STL 实体化(当未安装 build123d 时在 `pytest` 中会被跳过);CI 会在 **test-with-build123d** 工作流任务中运行这些测试用例。 ## 开发 ``` pytest -q ``` CI (`.github/workflows/ci.yml`) 会在 Python **3.11** 和 **3.12** 环境下,通过 `pip install -e ".[dev,api]"` 运行主测试套件,并且会有一个单独的任务负责安装 **build123d**,以执行需要用到它的验证测试。
标签:AV绕过, CAD逆向重构, FastAPI, Python, 三维网格处理, 参数化建模, 子域名突变, 搜索引擎查询, 无后门, 点云处理, 网络测绘, 请求拦截, 逆向工具