左右分屏与叠加对比,全程在客户端完成 ------ 无需 AutoCAD、无需上传服务器、无需等待转换后端。

为什么 CAD「diff」比文本 diff 更难
工程师早已习惯 git diff。图纸却不同:几何、句柄(handle)、图层、块参照,以及浮点坐标,没法像源码那样一行行对齐。多数团队仍在两个 AutoCAD 窗口间来回切换,或导出 PDF 后肉眼比对。
我们希望给 CAD 做一套更接近代码评审的工具,同时坚持 cad-viewer 的承诺:在浏览器内完成 DWG/DXF 解析与渲染,图纸不离开用户设备。这就是 @mlightcad/cad-diff-viewer:基于 @mlightcad/cad-simple-viewer 的可复用图纸对比组件。
在线体验 : mlightcad.com/cad-viewer/...
把旧版图纸拖到左窗格、新版拖到右窗格。查看器会标注 删除 / 新增 / 修改 实体,并以灰 / 红 / 绿的对比显示模式着色。
演示页里有什么
在线页面是对 AcApDiffViewer 的一层薄宿主。你不必自己拼两个查看器 ------ 只需提供一个容器,组件会创建两侧 WebGL 画布。
| 能力 | 说明 |
|---|---|
| 左右分屏(Side-by-side) | 左旧右新;未变更几何保持灰色 |
| 叠加(Overlay) | 新图作为只读叠加层叠在旧图画布上,便于发现位移 |
| 结果面板 | 按变更类型或实体类型分组;支持上一条 / 下一条导航 |
| 变更集云线 | 邻近差异聚类后生成修订云线标注 |
| 标注工具 | 云线、标注框、文字、矩形、圆、箭头、图章等 |
| 设置 | 对比颜色 + 类似 AutoCAD 的 COMPARE* 系统变量,支持实时预览 |
| 隐私 | DWG/DXF 留在标签页内,由 LibreDWG WASM 本地解析 |
界面文案走共享 i18n(en / zh / tr / cs 等)。
架构三步走
AcApDiffViewer 不会重新实现 CAD 转换。它会:
- 创建一个带两块画布的
AcApDocManager(左 = 旧图,右 = 新图)。 - 把每个文件打开到各自的文档会话中。
- 对两个模型空间数据库运行
acapCompareDrawings,把命中结果映射为 对比角色(compare roles),并开启 对比显示模式 ------ 用 GPU 着色替换 ACI / TrueColor,便于审图。
TypeScript
import { AcApDiffViewer } from '@mlightcad/cad-diff-viewer'
const viewer = new AcApDiffViewer({
container: document.getElementById('diff-host')!,
compareColors: {
unchanged: 0x9ca3af,
deleted: 0xe11d48, // 左 / 旧
added: 0x22c55e, // 右 / 新
modified: 0xe11d48
},
webworkerFileUrls: {
mtextRender: './workers/mtext-renderer-worker.js',
dwgParser: './workers/libredwg-parser-worker.js'
}
})
await viewer.openDocument('left', file.name, await file.arrayBuffer())
宿主只需注册 DWG 转换器(参见 cad-diff-viewer-example)并挂载组件。解析仍在 Worker 中进行,界面保持流畅。
对比显示如何工作(为什么看起来「一种颜色」)
普通查看保留每个实体的 CAD 颜色。对比显示则反过来:
- 每个批处理片元先被强制成 基色(默认灰
#9ca3af)。 - 带角色覆盖的实体再换成删除 / 新增 / 修改色。
- 选择与悬停仍优先于对比着色。
着色发生在 批处理高亮着色器 中,而不是在 CPU 上改写材质。每个 slot 的遮罩纹理用 B 通道承载角色;R/G 仍用于选择 / 悬停。
- 左右分屏: 左侧标删除(及左侧修改);右侧标新增(及右侧修改)。
- 叠加: 右侧数据库再次转换,作为左侧画布上的只读叠加层(GPU 场景不会在两块画布间搬移)。左侧修改画成删除(红);右侧修改画成新增(绿)。两侧未变更几何都落在灰色基色上,便于看出移动。
Diff 算法(受 AutoCAD COMPARE 启发)
acapCompareDrawings(leftDb, rightDb, options) 对比 模型空间、顶层 实体。选项对齐常见的 COMPARE 系统变量:
| 系统变量 | 默认值 | 作用 |
|---|---|---|
COMPAREPROPS |
0 |
属性差异位码(颜色、图层、线型等)。0 表示忽略仅属性变更 |
COMPAREHATCH |
0 |
是否包含填充(hatch) |
COMPARETEXT |
1 |
是否包含 TEXT / MTEXT / ATTRIB / ATTDEF |
COMPARETOLERANCE |
6 |
几何精度(6 → 1e-6) |
COMPARERCMARGIN |
5 |
变更集聚类与云线边距 |
每个实体会得到:
- 指纹(fingerprint) ------ DXF 类型 + 量化后的几何(端点、圆心/半径、文字内容、INSERT 变换等;必要时回退到包围盒);
- 属性键(property key) ------ 仅包含已启用的 COMPAREPROPS 位。
匹配顺序: 先同句柄且同 DXF 类型(典型于原地编辑),再在剩余实体中按同类型(启用图层时还加图层)与指纹匹配。
分类:
| 指纹 | 属性 | 结果 |
|---|---|---|
| 相同 | 相同 | 未变更 |
| 相同 | 不同 | 修改(仅属性,需 COMPAREPROPS ≠ 0) |
| 不同(句柄匹配) | --- | 修改 |
| 无匹配 | --- | 删除(仅左)或新增(仅右) |
邻近命中会归入 变更集(change sets)。工具栏可据此生成修订云线;结果面板按 删除 → 修改 → 新增 导航。
坦诚说明的限制(与 AutoCAD COMPARE 精神一致)
好用的开源工具需要把范围说清楚:
- 仅 模型空间、顶层实体 ------ 不含图纸空间、块定义内部嵌套,也不覆盖仅布局层工作。
- INSERT 视为一个对象(名称 + 变换 + 自身属性)。块定义内部的编辑不会被遍历。
- 对比看的是 实体存储值,不是解析后的 ByLayer / ByBlock 最终外观。在图层表里改图层颜色,不会把该层上所有实体标成「已修改」。
- 指纹覆盖常见几何;少见类型回退到包围盒,可能漏匹配或过度匹配。
- 叠加模式没有单独的「修改」色 ------ 会并入红 / 绿。
包 README 中有完整说明,方便集成方对齐预期。
在 cad-viewer 技术栈中的位置
@mlightcad/data-model → 数据库与实体模型
@mlightcad/cad-simple-viewer → DocManager、WebGL 视图、标注、i18n
@mlightcad/cad-diff-viewer → AcApDiffViewer + acapCompareDrawings
npm :@mlightcad/cad-diff-viewer(MIT)
API 文档 :cad-viewer.readthedocs.io
或直接打开托管演示:CAD Diff Viewer。
适合谁用
- 审图流程 ------ 建筑 / 机电等专业在没有桌面版 COMPARE 时对比修订集。
- SaaS 与 CMS 嵌入 ------ 在工单或 PR 旁加入图纸评审;文件仍留在客户端。
- 隐私敏感组织 ------ 没有「先上传再转换」这一跳。
- 开源集成方 ------ 挂载一个组件即可;也可直接调用
acapCompareDrawings做无头对比,再接自己的 UI。
若你基于此做了产品,欢迎在 GitHub Discussions / Issues 或 X @mlightcad 告诉我们。
结语
文本有了 diff,表格有了协同审阅,图纸却常常还是「打开两个文件仔细看」。CAD Diff Viewer 是我们迈向浏览器原生图纸评审的一步:与 cad-viewer 同一套无服务器栈、借鉴 AutoCAD 的对比语义,以及用一个容器就能挂进任意宿主的 UI。
在线演示 : mlightcad.com/cad-viewer/...
仓库 : github.com/mlightcad/c...
欢迎 Star、提 Issue 和 PR。