caddiff 0.3.4__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.
- caddiff-0.3.4/LICENSE +202 -0
- caddiff-0.3.4/NOTICE +18 -0
- caddiff-0.3.4/PKG-INFO +358 -0
- caddiff-0.3.4/README.md +329 -0
- caddiff-0.3.4/caddiff/__init__.py +20 -0
- caddiff-0.3.4/caddiff/bom_diff.py +143 -0
- caddiff-0.3.4/caddiff/boolean_worker.py +106 -0
- caddiff-0.3.4/caddiff/build_pptx.py +766 -0
- caddiff-0.3.4/caddiff/cli.py +168 -0
- caddiff-0.3.4/caddiff/console.py +29 -0
- caddiff-0.3.4/caddiff/fcenv.py +159 -0
- caddiff-0.3.4/caddiff/geom_diff.py +772 -0
- caddiff-0.3.4/caddiff/i18n.py +362 -0
- caddiff-0.3.4/caddiff/make_moved_fixture.py +84 -0
- caddiff-0.3.4/caddiff/render_diff.py +1843 -0
- caddiff-0.3.4/caddiff/report.py +427 -0
- caddiff-0.3.4/caddiff/run_pipeline.py +434 -0
- caddiff-0.3.4/caddiff/version.py +8 -0
- caddiff-0.3.4/caddiff.egg-info/PKG-INFO +358 -0
- caddiff-0.3.4/caddiff.egg-info/SOURCES.txt +24 -0
- caddiff-0.3.4/caddiff.egg-info/dependency_links.txt +1 -0
- caddiff-0.3.4/caddiff.egg-info/entry_points.txt +2 -0
- caddiff-0.3.4/caddiff.egg-info/requires.txt +6 -0
- caddiff-0.3.4/caddiff.egg-info/top_level.txt +1 -0
- caddiff-0.3.4/pyproject.toml +75 -0
- caddiff-0.3.4/setup.cfg +4 -0
caddiff-0.3.4/LICENSE
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
|
|
2
|
+
Apache License
|
|
3
|
+
Version 2.0, January 2004
|
|
4
|
+
http://www.apache.org/licenses/
|
|
5
|
+
|
|
6
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
7
|
+
|
|
8
|
+
1. Definitions.
|
|
9
|
+
|
|
10
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
11
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
12
|
+
|
|
13
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
14
|
+
the copyright owner that is granting the License.
|
|
15
|
+
|
|
16
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
17
|
+
other entities that control, are controlled by, or are under common
|
|
18
|
+
control with that entity. For the purposes of this definition,
|
|
19
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
20
|
+
direction or management of such entity, whether by contract or
|
|
21
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
22
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
23
|
+
|
|
24
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
25
|
+
exercising permissions granted by this License.
|
|
26
|
+
|
|
27
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
28
|
+
including but not limited to software source code, documentation
|
|
29
|
+
source, and configuration files.
|
|
30
|
+
|
|
31
|
+
"Object" form shall mean any form resulting from mechanical
|
|
32
|
+
transformation or translation of a Source form, including but
|
|
33
|
+
not limited to compiled object code, generated documentation,
|
|
34
|
+
and conversions to other media types.
|
|
35
|
+
|
|
36
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
37
|
+
Object form, made available under the License, as indicated by a
|
|
38
|
+
copyright notice that is included in or attached to the work
|
|
39
|
+
(an example is provided in the Appendix below).
|
|
40
|
+
|
|
41
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
42
|
+
form, that is based on (or derived from) the Work and for which the
|
|
43
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
44
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
45
|
+
of this License, Derivative Works shall not include works that remain
|
|
46
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
47
|
+
the Work and Derivative Works thereof.
|
|
48
|
+
|
|
49
|
+
"Contribution" shall mean any work of authorship, including
|
|
50
|
+
the original version of the Work and any modifications or additions
|
|
51
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
52
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
53
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
54
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
55
|
+
means any form of electronic, verbal, or written communication sent
|
|
56
|
+
to the Licensor or its representatives, including but not limited to
|
|
57
|
+
communication on electronic mailing lists, source code control systems,
|
|
58
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
59
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
60
|
+
excluding communication that is conspicuously marked or otherwise
|
|
61
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
62
|
+
|
|
63
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
64
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
65
|
+
subsequently incorporated within the Work.
|
|
66
|
+
|
|
67
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
68
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
69
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
70
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
71
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
72
|
+
Work and such Derivative Works in Source or Object form.
|
|
73
|
+
|
|
74
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
75
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
76
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
77
|
+
(except as stated in this section) patent license to make, have made,
|
|
78
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
79
|
+
where such license applies only to those patent claims licensable
|
|
80
|
+
by such Contributor that are necessarily infringed by their
|
|
81
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
82
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
83
|
+
institute patent litigation against any entity (including a
|
|
84
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
85
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
86
|
+
or contributory patent infringement, then any patent licenses
|
|
87
|
+
granted to You under this License for that Work shall terminate
|
|
88
|
+
as of the date such litigation is filed.
|
|
89
|
+
|
|
90
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
91
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
92
|
+
modifications, and in Source or Object form, provided that You
|
|
93
|
+
meet the following conditions:
|
|
94
|
+
|
|
95
|
+
(a) You must give any other recipients of the Work or
|
|
96
|
+
Derivative Works a copy of this License; and
|
|
97
|
+
|
|
98
|
+
(b) You must cause any modified files to carry prominent notices
|
|
99
|
+
stating that You changed the files; and
|
|
100
|
+
|
|
101
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
102
|
+
that You distribute, all copyright, patent, trademark, and
|
|
103
|
+
attribution notices from the Source form of the Work,
|
|
104
|
+
excluding those notices that do not pertain to any part of
|
|
105
|
+
the Derivative Works; and
|
|
106
|
+
|
|
107
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
108
|
+
distribution, then any Derivative Works that You distribute must
|
|
109
|
+
include a readable copy of the attribution notices contained
|
|
110
|
+
within such NOTICE file, excluding those notices that do not
|
|
111
|
+
pertain to any part of the Derivative Works, in at least one
|
|
112
|
+
of the following places: within a NOTICE text file distributed
|
|
113
|
+
as part of the Derivative Works; within the Source form or
|
|
114
|
+
documentation, if provided along with the Derivative Works; or,
|
|
115
|
+
within a display generated by the Derivative Works, if and
|
|
116
|
+
wherever such third-party notices normally appear. The contents
|
|
117
|
+
of the NOTICE file are for informational purposes only and
|
|
118
|
+
do not modify the License. You may add Your own attribution
|
|
119
|
+
notices within Derivative Works that You distribute, alongside
|
|
120
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
121
|
+
that such additional attribution notices cannot be construed
|
|
122
|
+
as modifying the License.
|
|
123
|
+
|
|
124
|
+
You may add Your own copyright statement to Your modifications and
|
|
125
|
+
may provide additional or different license terms and conditions
|
|
126
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
127
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
128
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
129
|
+
the conditions stated in this License.
|
|
130
|
+
|
|
131
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
132
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
133
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
134
|
+
this License, without any additional terms or conditions.
|
|
135
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
136
|
+
the terms of any separate license agreement you may have executed
|
|
137
|
+
with Licensor regarding such Contributions.
|
|
138
|
+
|
|
139
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
140
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
141
|
+
except as required for reasonable and customary use in describing the
|
|
142
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
143
|
+
|
|
144
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
145
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
146
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
147
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
148
|
+
implied, including, without limitation, any warranties or conditions
|
|
149
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
150
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
151
|
+
appropriateness of using or redistributing the Work and assume any
|
|
152
|
+
risks associated with Your exercise of permissions under this License.
|
|
153
|
+
|
|
154
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
155
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
156
|
+
unless required by applicable law (such as deliberate and grossly
|
|
157
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
158
|
+
liable to You for damages, including any direct, indirect, special,
|
|
159
|
+
incidental, or consequential damages of any character arising as a
|
|
160
|
+
result of this License or out of the use or inability to use the
|
|
161
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
162
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
163
|
+
other commercial damages or losses), even if such Contributor
|
|
164
|
+
has been advised of the possibility of such damages.
|
|
165
|
+
|
|
166
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
167
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
168
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
169
|
+
or other liability obligations and/or rights consistent with this
|
|
170
|
+
License. However, in accepting such obligations, You may act only
|
|
171
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
172
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
173
|
+
defend, and hold each Contributor harmless for any liability
|
|
174
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
175
|
+
of your accepting any such warranty or additional liability.
|
|
176
|
+
|
|
177
|
+
END OF TERMS AND CONDITIONS
|
|
178
|
+
|
|
179
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
180
|
+
|
|
181
|
+
To apply the Apache License to your work, attach the following
|
|
182
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
183
|
+
replaced with your own identifying information. (Don't include
|
|
184
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
185
|
+
comment syntax for the file format. We also recommend that a
|
|
186
|
+
file or class name and description of purpose be included on the
|
|
187
|
+
same "printed page" as the copyright notice for easier
|
|
188
|
+
identification within third-party archives.
|
|
189
|
+
|
|
190
|
+
Copyright 2026 The caddiff Authors
|
|
191
|
+
|
|
192
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
193
|
+
you may not use this file except in compliance with the License.
|
|
194
|
+
You may obtain a copy of the License at
|
|
195
|
+
|
|
196
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
197
|
+
|
|
198
|
+
Unless required by applicable law or agreed to in writing, software
|
|
199
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
200
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
201
|
+
See the License for the specific language governing permissions and
|
|
202
|
+
limitations under the License.
|
caddiff-0.3.4/NOTICE
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
caddiff
|
|
2
|
+
git diff for CAD assemblies
|
|
3
|
+
|
|
4
|
+
Copyright 2026 The caddiff Authors
|
|
5
|
+
|
|
6
|
+
This product includes software developed by third parties. The third-party
|
|
7
|
+
components, their licenses, and the form in which each one is distributed are
|
|
8
|
+
listed in THIRD_PARTY_LICENSES.md.
|
|
9
|
+
|
|
10
|
+
The source code of this project is licensed under the Apache License, Version
|
|
11
|
+
2.0 (see LICENSE). The third-party components that are bundled inside the
|
|
12
|
+
published Docker image are not covered by that license: each of them remains
|
|
13
|
+
under its own upstream license. Read THIRD_PARTY_LICENSES.md before
|
|
14
|
+
redistributing the image or an image derived from it.
|
|
15
|
+
|
|
16
|
+
This product includes Open CASCADE Technology (OCCT), distributed under the
|
|
17
|
+
GNU Lesser General Public License version 2.1 with the Open CASCADE Exception
|
|
18
|
+
1.0.
|
caddiff-0.3.4/PKG-INFO
ADDED
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: caddiff
|
|
3
|
+
Version: 0.3.4
|
|
4
|
+
Summary: git diff for CAD assemblies — compare two STEP/STP assemblies and show what changed
|
|
5
|
+
Author: The caddiff Authors
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/angel291592/caddiff
|
|
8
|
+
Project-URL: Documentation, https://github.com/angel291592/caddiff/tree/main/docs
|
|
9
|
+
Project-URL: Demo, https://angel291592.github.io/caddiff/report.html
|
|
10
|
+
Project-URL: Changelog, https://github.com/angel291592/caddiff/blob/main/CHANGELOG.md
|
|
11
|
+
Project-URL: Issues, https://github.com/angel291592/caddiff/issues
|
|
12
|
+
Keywords: cad,step,stp,diff,freecad,bom,assembly,git,cli
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Environment :: Console
|
|
15
|
+
Classifier: Intended Audience :: Manufacturing
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering
|
|
19
|
+
Classifier: Topic :: Software Development :: Version Control :: Git
|
|
20
|
+
Requires-Python: >=3.9
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
License-File: NOTICE
|
|
24
|
+
Provides-Extra: pptx
|
|
25
|
+
Requires-Dist: python-pptx>=0.6.23; extra == "pptx"
|
|
26
|
+
Provides-Extra: test
|
|
27
|
+
Requires-Dist: pytest>=7; extra == "test"
|
|
28
|
+
Dynamic: license-file
|
|
29
|
+
|
|
30
|
+
<div align="center">
|
|
31
|
+
|
|
32
|
+
# caddiff
|
|
33
|
+
|
|
34
|
+
English | [简体中文](https://github.com/angel291592/caddiff/blob/main/README.zh-CN.md)
|
|
35
|
+
|
|
36
|
+
**git diff for CAD assemblies.**
|
|
37
|
+
|
|
38
|
+
Two STEP files in, one picture of *what changed* out — plus a change list your CI can gate on.
|
|
39
|
+
|
|
40
|
+
[](https://github.com/angel291592/caddiff/actions/workflows/ci.yml)
|
|
41
|
+
[](https://github.com/angel291592/caddiff/blob/main/LICENSE)
|
|
42
|
+
[](pyproject.toml)
|
|
43
|
+
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+

|
|
47
|
+
|
|
48
|
+
> Green-ish magenta marks the changed geometry; the red box locates it; the blue arrow
|
|
49
|
+
> shows a 5.00 mm displacement. Both images are generated by `caddiff` from the synthetic
|
|
50
|
+
> fixture in [`examples/`](https://github.com/angel291592/caddiff/tree/main/examples) — no customer data anywhere in this repo.
|
|
51
|
+
> **[Browse the full sample report, rendered online, no install needed →](https://angel291592.github.io/caddiff/report.html)**
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## The problem
|
|
56
|
+
|
|
57
|
+
You put your CAD in git. Now someone asks: *"what actually changed between v1.2 and v1.3?"*
|
|
58
|
+
|
|
59
|
+
`git diff` is useless here. A STEP file is plain text, so git prints four thousand lines of
|
|
60
|
+
coordinates and tells you nothing. Worse, git will happily **merge** two STEP files into a
|
|
61
|
+
file that is syntactically valid and geometrically wrong — and nothing warns you.
|
|
62
|
+
|
|
63
|
+
Commercial CAD suites sell a fix for this (SOLIDWORKS Compare, TransMagic, 3DViewStation).
|
|
64
|
+
The open-source side had almost nothing: the few projects in this space render a visual
|
|
65
|
+
diff and stop there — no BOM alignment, no report, no CI story.
|
|
66
|
+
|
|
67
|
+
`caddiff` is the missing piece: a command-line tool that answers *what changed* with a
|
|
68
|
+
picture and a machine-readable list.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Quick start
|
|
73
|
+
|
|
74
|
+
### Docker (recommended — nothing to install)
|
|
75
|
+
|
|
76
|
+
```console
|
|
77
|
+
$ docker run --rm -v "$PWD:/data" ghcr.io/angel291592/caddiff:v0.3.4 \
|
|
78
|
+
diff /data/old.stp /data/new.stp -o /data/report
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
`v0.3.4` is the released image. An `edge` tag also tracks `main` if you want to live on
|
|
82
|
+
top of the tree — but for anything you gate a CI run on, pin a released tag (or a digest).
|
|
83
|
+
|
|
84
|
+
### Local install
|
|
85
|
+
|
|
86
|
+
`caddiff` itself has **zero third-party dependencies** — but the geometry and rendering
|
|
87
|
+
steps run inside FreeCAD, so `FREECAD_PYTHON` must point at an interpreter that can
|
|
88
|
+
`import FreeCAD`:
|
|
89
|
+
|
|
90
|
+
```console
|
|
91
|
+
$ pip install caddiff # add [pptx] if you want --pptx
|
|
92
|
+
$ export FREECAD_PYTHON=/path/to/FreeCAD/bin/python.exe # Windows: the FreeCAD distribution ships its own python
|
|
93
|
+
$ export FREECAD_PYTHON=/usr/bin/python3 # Linux: the system python3,
|
|
94
|
+
$ export PYTHONPATH=/usr/lib/freecad/lib # with FreeCAD's modules on the path
|
|
95
|
+
$ caddiff diff old.stp new.stp -o report
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
On Linux, do **not** point `FREECAD_PYTHON` at `.../freecad/bin/freecad-python3`: that file
|
|
99
|
+
is the FreeCAD **GUI application**, so handing it a script opens the GUI and never returns.
|
|
100
|
+
The system `python3` + `PYTHONPATH` above is what works, and it is how the Docker image is
|
|
101
|
+
configured (see [`docs/pipeline.md`](https://github.com/angel291592/caddiff/blob/main/docs/pipeline.md)).
|
|
102
|
+
|
|
103
|
+
If `FREECAD_PYTHON` is unset, `caddiff` searches the usual Linux locations and `PATH`, and
|
|
104
|
+
**fails with an actionable message** rather than silently falling back to a Python that
|
|
105
|
+
cannot import FreeCAD.
|
|
106
|
+
|
|
107
|
+
### With `git difftool`
|
|
108
|
+
|
|
109
|
+
So that `git diff for CAD assemblies` is literally true:
|
|
110
|
+
|
|
111
|
+
```console
|
|
112
|
+
$ git config --global difftool.caddiff.cmd 'caddiff difftool "$LOCAL" "$REMOTE"'
|
|
113
|
+
$ git difftool -t caddiff HEAD~1 -- bracket.stp
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
See [`docs/git-integration.md`](https://github.com/angel291592/caddiff/blob/main/docs/git-integration.md) for why CAD files need
|
|
117
|
+
`.gitattributes` treatment and how to pick revisions.
|
|
118
|
+
|
|
119
|
+
### As a GitHub Action (pull-request gate)
|
|
120
|
+
|
|
121
|
+
The repo ships a ready-made Action that pulls the same prebuilt image, runs the diff on
|
|
122
|
+
two files in your repo, and uploads the report directory as a workflow artifact:
|
|
123
|
+
|
|
124
|
+
```yaml
|
|
125
|
+
- uses: angel291592/caddiff@v0.3.4
|
|
126
|
+
id: caddiff
|
|
127
|
+
with:
|
|
128
|
+
old: models/base.stp
|
|
129
|
+
new: models/pr.stp
|
|
130
|
+
image: ghcr.io/angel291592/caddiff:v0.3.4
|
|
131
|
+
|
|
132
|
+
- name: React to differences
|
|
133
|
+
if: steps.caddiff.outputs.has-differences == 'true'
|
|
134
|
+
run: echo "::warning::${{ steps.caddiff.outputs.diff-count }} CAD change(s) detected"
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Outputs read from `diff_manifest.json` (`has-differences`, `diff-count`, `report-dir`) — the
|
|
138
|
+
action fails only on exit code 2 (caddiff could not run); exit code 1 (differences
|
|
139
|
+
found) is a result, and the report is still uploaded.
|
|
140
|
+
|
|
141
|
+
`image:` is spelled out on purpose. `@v0.3.4` resolves `action.yml` from the `v0.3.4`
|
|
142
|
+
tag, and that tag's default is frozen at the *previous* release — so without this line
|
|
143
|
+
the action and the geometry engine would run different versions. Same rule as the
|
|
144
|
+
`docker run` above: pin the image, not the branch.
|
|
145
|
+
|
|
146
|
+
Known limits: fork PRs cannot comment on the PR with the default read-only token, and
|
|
147
|
+
the report is delivered as an artifact rather than a PR comment — see the notes at the
|
|
148
|
+
top of [`action.yml`](https://github.com/angel291592/caddiff/blob/main/action.yml).
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## What it detects
|
|
153
|
+
|
|
154
|
+
| Change type | Example | How it is reported |
|
|
155
|
+
|---|---|---|
|
|
156
|
+
| **Part added / removed** | a bracket dropped from the assembly | BOM-level: listed in `summary.bom_added` / `bom_removed` |
|
|
157
|
+
| **Instance count changed** | 2 screws became 4 | BOM-level: listed in `summary.bom_count_mismatch` |
|
|
158
|
+
| **`moved`** | same part, translated or rotated | displacement in mm/°, blue arrow on the image |
|
|
159
|
+
| **`shape_changed`** | material added or removed | boolean symmetric difference, magenta highlight, volume delta |
|
|
160
|
+
|
|
161
|
+
Parts that could **not** be compared (too many faces, boolean timeout, no solid shape) are
|
|
162
|
+
never silently dropped — they appear in `summary.skipped_parts` with a reason. "Not
|
|
163
|
+
mentioned" must never be readable as "no difference".
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## What you get
|
|
168
|
+
|
|
169
|
+
```
|
|
170
|
+
report/
|
|
171
|
+
├── diff_manifest.json machine-readable contract (start here in CI)
|
|
172
|
+
├── report.html human-readable report with the images inline
|
|
173
|
+
├── report.md same content as Markdown (good for PR comments)
|
|
174
|
+
├── images/*.png overview + old/new close-ups per change
|
|
175
|
+
├── compare.pptx only with --pptx
|
|
176
|
+
├── bom_diff.json intermediate
|
|
177
|
+
└── geom_diff.json intermediate
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Each change gets an **automatically chosen viewpoint**: `caddiff` scans 26 candidate
|
|
181
|
+
directions (6 faces + 12 edges + 8 corners), scores each on how much of the highlighted
|
|
182
|
+
geometry is visible and how readable the framing is, and picks the winner. When the change
|
|
183
|
+
is buried inside the assembly it says so on the image instead of pretending the shot is fine.
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## Exit codes — use it as a CI gate
|
|
188
|
+
|
|
189
|
+
| Code | Meaning |
|
|
190
|
+
|---|---|
|
|
191
|
+
| `0` | no differences |
|
|
192
|
+
| `1` | differences found |
|
|
193
|
+
| `2` | the run failed (bad input, timeout, crash) |
|
|
194
|
+
|
|
195
|
+
```yaml
|
|
196
|
+
- name: Check geometry changes
|
|
197
|
+
run: |
|
|
198
|
+
docker run --rm -v "$PWD:/data" ghcr.io/angel291592/caddiff:v0.3.4 \
|
|
199
|
+
diff /data/base.stp /data/pr.stp -o /data/report
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
The distinction between `1` and `2` matters: a crashed FreeCAD must never look like
|
|
203
|
+
"nothing changed".
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## How it compares
|
|
208
|
+
|
|
209
|
+
There are two different things people mean by "CAD diff", and they are not competitors —
|
|
210
|
+
they are the two halves of one loop. Here is where `caddiff` sits.
|
|
211
|
+
|
|
212
|
+
| | **caddiff** | text-to-CAD tools<br><sub>[text-to-cad](https://github.com/earthtojake/text-to-cad), [CADAM](https://github.com/Adam-CAD/CADAM)</sub> | SOLIDWORKS Compare<br><sub>commercial revision checkers</sub> |
|
|
213
|
+
|---|---|---|---|
|
|
214
|
+
| **What it is for** | verify what changed between two revisions | generate / edit a model from a prompt | verify revisions |
|
|
215
|
+
| Answers "did this model change, and how?" | ✅ deterministic geometry comparison | ❌ has no such notion | ✅ |
|
|
216
|
+
| Works on a file pair you already have | ✅ | ❌ needs a prompt and a regeneration | ✅ |
|
|
217
|
+
| Machine-readable change list | ✅ `diff_manifest.json` | ❌ | ❌ |
|
|
218
|
+
| Gates a pull request | ✅ exit codes `0/1/2` | ❌ | ❌ |
|
|
219
|
+
| Headless / runs in a container | ✅ | varies | ❌ |
|
|
220
|
+
| Needs a CAD licence | ❌ | ❌ | ✅ |
|
|
221
|
+
| Open source | ✅ Apache-2.0 | ✅ (varies) | ❌ |
|
|
222
|
+
|
|
223
|
+
**The complement, not the rival.** text-to-CAD tools are extremely good at *making*
|
|
224
|
+
changes and have nothing to say about *verifying* them. That gap widens as more edits are
|
|
225
|
+
produced by agents instead of hands:
|
|
226
|
+
|
|
227
|
+
```console
|
|
228
|
+
# an agent (or you) just rewrote the bracket
|
|
229
|
+
$ caddiff diff old.stp new.stp -o report
|
|
230
|
+
$ echo $?
|
|
231
|
+
1 # something changed — here is exactly what, and by how much
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
If you generate models with a text-to-CAD tool, `caddiff` is what you run **after** it.
|
|
235
|
+
|
|
236
|
+
**Versus the commercial revision checkers.** They solve the same problem well, and they
|
|
237
|
+
cost a licence per seat, need the CAD application installed, and cannot run in CI. That is
|
|
238
|
+
the entire reason this project exists — see [The problem](#the-problem).
|
|
239
|
+
|
|
240
|
+
> On the open-source side, a handful of projects in this space render a visual diff, and
|
|
241
|
+
> none of them ship BOM-level alignment, a machine-readable manifest, or CI exit codes.
|
|
242
|
+
> That is the gap `caddiff` fills.
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## Benchmarks (measured, not estimated)
|
|
247
|
+
|
|
248
|
+
All numbers below are wall-clock, software rendering, no GPU. Rendering dominates:
|
|
249
|
+
each change costs one 26-direction scan (≈0.85 s per direction) plus three images.
|
|
250
|
+
|
|
251
|
+
| Input | Where it ran | Changes found | Wall clock |
|
|
252
|
+
|---|---|---|---|
|
|
253
|
+
| 3-part synthetic assembly ([`examples/`](https://github.com/angel291592/caddiff/tree/main/examples)) | source checkout, Windows + FreeCAD 1.1.3 | 2 | **≈80 s** |
|
|
254
|
+
| 3-part synthetic assembly, same fixture | official image, Linux + FreeCAD 0.21.2 | 2 | **≈35 s** |
|
|
255
|
+
| 55-part production assembly | source checkout, Windows + FreeCAD 1.1.3 | 3 | **290–366 s** |
|
|
256
|
+
|
|
257
|
+
The image is faster on the small fixture because the container is a clean Linux
|
|
258
|
+
filesystem — no Windows Defender scanning of the intermediate STEP/BREP files. Do not
|
|
259
|
+
read that as 0.21 being faster than 1.1.3; the two rows differ in more than one way.
|
|
260
|
+
|
|
261
|
+
Reproduce the first row yourself:
|
|
262
|
+
|
|
263
|
+
```console
|
|
264
|
+
$ python caddiff/make_moved_fixture.py examples/fixtures
|
|
265
|
+
$ caddiff diff examples/fixtures/moved_old.stp examples/fixtures/moved_new.stp -o out
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
We are not claiming a speed record. If you need sub-second diffs on huge assemblies,
|
|
269
|
+
this is not the tool for you yet — see the roadmap.
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
## What this does **not** do
|
|
274
|
+
|
|
275
|
+
Being explicit about the boundaries, because a tool that over-promises is worse than no tool:
|
|
276
|
+
|
|
277
|
+
- **No tolerance analysis or GD&T.** `shape_changed` means "the boolean symmetric
|
|
278
|
+
difference is non-empty", not "this is out of tolerance".
|
|
279
|
+
- **No free-form surface deviation maps.** We compare solids, not point clouds.
|
|
280
|
+
- **No huge assemblies.** The render step is serial; a 55-part assembly already takes
|
|
281
|
+
minutes. There is no upper bound enforced, but the experience degrades.
|
|
282
|
+
- **Part pairing is heuristic.** Same-named parts are matched by bounding-box proximity
|
|
283
|
+
with a 50 % volume guard. This works well for the common "same assembly, edited in
|
|
284
|
+
place" case and is **known to be weak** when parts are renamed wholesale or the whole
|
|
285
|
+
assembly is moved. Unmatched parts are reported, never guessed. Measured on 24 pairs of
|
|
286
|
+
real public assemblies: every structural change was caught, but 7 of 15 structurally
|
|
287
|
+
unchanged pairs still report BOM add/remove pairs purely from **renames** (human renames,
|
|
288
|
+
exporter auto-names, even case-only changes) — the name really did change, and geometry
|
|
289
|
+
cannot pair across names, so read a symmetric added/removed list as "something was
|
|
290
|
+
renamed". A same-named part that changed beyond the 50 % pairing guard is reported as a
|
|
291
|
+
whole-part change (degraded, clearly labelled), never dropped.
|
|
292
|
+
- **No merge.** `caddiff` tells you what changed. It does not merge two STEP files, and it
|
|
293
|
+
will not try.
|
|
294
|
+
- **No hosted service.** Everything runs locally or in your own CI. Nothing is uploaded.
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
## How it works
|
|
299
|
+
|
|
300
|
+
```
|
|
301
|
+
old.stp ─┐
|
|
302
|
+
├─► [1] BOM alignment (pure Python — part names, instance counts)
|
|
303
|
+
new.stp ─┘ │
|
|
304
|
+
├─► [2] geometric diff (FreeCAD: classify identical/moved/shape_changed,
|
|
305
|
+
│ boolean symmetric difference in a killable subprocess)
|
|
306
|
+
├─► [3] render (FreeCAD GUI + 26-direction viewpoint search → PNG)
|
|
307
|
+
└─► [4] report (manifest JSON + HTML + Markdown; PPTX on demand)
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
Two design rules that are load-bearing:
|
|
311
|
+
|
|
312
|
+
- **Every expensive geometry operation runs in a subprocess with a hard timeout.** Face
|
|
313
|
+
count does not predict boolean cost — we measured a 912-face part whose single `cut`
|
|
314
|
+
ran past 840 s. A face-count gate alone cannot catch that; only a killable subprocess can.
|
|
315
|
+
- **FreeCAD is only ever talked to via subprocess + files.** No compiled extensions, no
|
|
316
|
+
`dlopen`, no shared memory. This keeps the LGPL/GPL boundary clean (see
|
|
317
|
+
[`THIRD_PARTY_LICENSES.md`](https://github.com/angel291592/caddiff/blob/main/THIRD_PARTY_LICENSES.md)) and keeps crashes contained.
|
|
318
|
+
|
|
319
|
+
Technical deep-dive: [`docs/pipeline.md`](https://github.com/angel291592/caddiff/blob/main/docs/pipeline.md).
|
|
320
|
+
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
## Roadmap
|
|
324
|
+
|
|
325
|
+
- **v0.1 – v0.3** (released) — `caddiff diff`: BOM alignment, geometric diff, rendering,
|
|
326
|
+
HTML/Markdown/JSON reports, Docker image, GitHub Action, CI exit codes.
|
|
327
|
+
- **next** — an MCP server so an agent that just edited a model can verify its own work
|
|
328
|
+
against the previous revision.
|
|
329
|
+
- **later** — `caddiff check` (FEA sanity checks) and `caddiff build` (sandboxed modeling).
|
|
330
|
+
The namespace is reserved; nothing is promised.
|
|
331
|
+
|
|
332
|
+
[](https://star-history.com/#angel291592/caddiff&Date)
|
|
333
|
+
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
## Contributing
|
|
337
|
+
|
|
338
|
+
Bug reports, fixture pairs, and pull requests are welcome — see
|
|
339
|
+
[`CONTRIBUTING.md`](https://github.com/angel291592/caddiff/blob/main/CONTRIBUTING.md). Please **never attach a real customer model** to an
|
|
340
|
+
issue: CAD files routinely contain trade secrets, and the derived PNG/JSON/HTML carry the
|
|
341
|
+
part names too. Use a minimal synthetic sample.
|
|
342
|
+
|
|
343
|
+
Security reports: [`SECURITY.md`](https://github.com/angel291592/caddiff/blob/main/SECURITY.md).
|
|
344
|
+
|
|
345
|
+
---
|
|
346
|
+
|
|
347
|
+
## License
|
|
348
|
+
|
|
349
|
+
Repository source code is **Apache-2.0** ([`LICENSE`](https://github.com/angel291592/caddiff/blob/main/LICENSE)).
|
|
350
|
+
|
|
351
|
+
The Docker image **bundles third-party components under their own licenses** — FreeCAD
|
|
352
|
+
(LGPL-2.1-or-later, and its distribution also contains GPL-licensed files), OpenCASCADE
|
|
353
|
+
(LGPL-2.1 with the OCCT exception), numpy, Pillow, python-pptx. Those are *not* covered by
|
|
354
|
+
the Apache-2.0 license of this repository. Full details, including how to obtain the
|
|
355
|
+
corresponding source, are in [`THIRD_PARTY_LICENSES.md`](https://github.com/angel291592/caddiff/blob/main/THIRD_PARTY_LICENSES.md).
|
|
356
|
+
|
|
357
|
+
This project is not affiliated with or endorsed by the FreeCAD project or the FreeCAD
|
|
358
|
+
Project Association. It uses Open CASCADE Technology.
|