Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
name: Docs

on:
push:
branches: [main]
paths:
- "docs/**"
- "mkdocs.yml"
- "gerberdiff/**"
- "CHANGELOG.md"
- "CONTRIBUTING.md"
- ".github/workflows/docs.yml"
pull_request:
branches: [main]
paths:
- "docs/**"
- "mkdocs.yml"
- "gerberdiff/**"
- "CHANGELOG.md"
- "CONTRIBUTING.md"
- ".github/workflows/docs.yml"

permissions:
contents: read

concurrency:
group: docs-${{ github.ref }}
cancel-in-progress: true

jobs:
build:
name: Build site
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: astral-sh/setup-uv@v7
with:
enable-cache: true
- run: uv sync --group docs
- run: uv run mkdocs build --strict
- uses: actions/upload-pages-artifact@v4
if: github.event_name == 'push'
with:
path: site/

deploy:
name: Deploy to GitHub Pages
if: github.event_name == 'push'
needs: build
runs-on: ubuntu-latest
permissions:
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- id: deployment
uses: actions/deploy-pages@v4
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- **Documentation site** at <https://cameronbrooks11.github.io/gerberdiff/>
-- MkDocs + Material with mkdocstrings API reference, MathJax for the
LaTeX notation already used in the docs, and Changelog/Contributing
included via snippets. Built strictly and deployed to GitHub Pages by
`.github/workflows/docs.yml` on every push to `main` that touches docs
or the package.

- Edge-case test suite for the geometry engine's guard paths: block
nesting depth limit, invalid layer indices, zero-dimension apertures,
degenerate regions and strokes, macro flash dispatch, the
Expand Down
3 changes: 2 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,4 +109,5 @@ EOF
## License

By contributing you agree that your contributions will be licensed under the
[Apache-2.0](LICENSE) licence.
[Apache-2.0](https://github.com/CameronBrooks11/gerberdiff/blob/main/LICENSE)
licence.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# gerberdiff

[![CI](https://github.com/CameronBrooks11/gerberdiff/actions/workflows/ci.yml/badge.svg)](https://github.com/CameronBrooks11/gerberdiff/actions/workflows/ci.yml)
[![Docs](https://github.com/CameronBrooks11/gerberdiff/actions/workflows/docs.yml/badge.svg)](https://cameronbrooks11.github.io/gerberdiff/)
[![PyPI](https://img.shields.io/pypi/v/gerberdiff)](https://pypi.org/project/gerberdiff/)
[![Python](https://img.shields.io/pypi/pyversions/gerberdiff)](https://pypi.org/project/gerberdiff/)
[![License: Apache-2.0](https://img.shields.io/badge/License-Apache--2.0-blue.svg)](LICENSE)
Expand Down Expand Up @@ -49,6 +50,8 @@ for layer in result.layers:

## Docs

Full documentation site: **<https://cameronbrooks11.github.io/gerberdiff/>**

| Topic | File |
| -------------------- | -------------------------------------------- |
| CLI reference | [docs/cli.md](docs/cli.md) |
Expand Down
1 change: 1 addition & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--8<-- "CHANGELOG.md"
1 change: 1 addition & 0 deletions docs/contributing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--8<-- "CONTRIBUTING.md"
78 changes: 78 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# gerberdiff

Diff tool for Gerber/Excellon PCB design files, with two complementary
engines:

- **Raster diff** (`diff`) -- renders both revisions with Cairo and XORs the
pixels; produces visual overlay PNGs of changed regions.
- **Geometry diff** (`geomdiff`) -- computes resolution-independent,
**attributed** changes on the parsed vector geometry: every change is
classified as `added`, `removed`, `moved` (with dx/dy displacement, down
to micrometres), or `resized`, with net names propagated from `%TO.N%`
attributes.

The raster engine answers "*where* did pixels change?"; the geometry engine
answers "*what* changed, and by how much?". A $0.14\,\text{mm}$ component
move that renders as an unreadable field of XOR crescents in a raster diff
is reported by the geometry engine as "46 objects moved by
$(-0.139, -0.054)\,\text{mm}$".

## Install

```sh
pip install gerberdiff
```

Requires Python >= 3.11. The raster engine needs the system Cairo library
(`libcairo2` on Debian/Ubuntu, `cairo` via Homebrew); the geometry engine
and the parsers are Cairo-free and work everywhere.

## Quick start

```sh
# Geometry diff: what moved, resized, was added or removed -- and by how much
gerberdiff geomdiff before/ after/ --out-json report.json --out-svg overlays/

# Raster diff: visual overlay PNGs
gerberdiff diff before/ after/ --out-json report.json --out-png diffs/

# Exit 1 if any changes detected (useful in CI)
gerberdiff geomdiff before/ after/ --fail-on-diff
```

```python
import gerberdiff
from pathlib import Path

result = gerberdiff.compute_geometry_diff(Path("before/"), Path("after/"))
for layer in result.layers:
for change in layer.changes:
print(f"{layer.name}: {change.kind} {change.op_kind} "
f"dx={change.dx_mm} dy={change.dy_mm}")
```

## Where to go next

| I want to... | Read |
| --- | --- |
| Use the command line | [CLI reference](cli.md) |
| Call it from Python | [Python API](api.md) |
| Parse the JSON reports | [JSON report schemas](schema.md) |
| Understand how it works | [Architecture](architecture.md) |
| Deep-dive the geometry engine | [Geometry diff engine](geometry-diff.md) |
| Browse the API surface | [API reference](reference/package.md) |
| Contribute | [Contributing](contributing.md) |

## Known limitations

- **Excellon rout mode:** only drill hits are processed; routing paths
produce a `Warning` diagnostic but no geometry.
- **Deprecated RS-274X commands (`%MI%`, `%OF%`, `%SF%`, `%AS%`):** ignored
with an `Info` diagnostic.
- **Rectangle/obround aperture strokes:** the raster engine strokes with
`max(width, height)`; the geometry engine computes the exact Minkowski sum
for linear strokes (see [Geometry diff engine](geometry-diff.md)).

## License

[Apache-2.0](https://github.com/CameronBrooks11/gerberdiff/blob/main/LICENSE).
20 changes: 20 additions & 0 deletions docs/javascripts/mathjax.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/* MathJax configuration for pymdownx.arithmatex (generic mode). */
window.MathJax = {
tex: {
inlineMath: [["\\(", "\\)"]],
displayMath: [["\\[", "\\]"]],
processEscapes: true,
processEnvironments: true,
},
options: {
ignoreHtmlClass: ".*|",
processHtmlClass: "arithmatex",
},
};

document$.subscribe(() => {
MathJax.startup.output.clearCache();
MathJax.typesetClear();
MathJax.texReset();
MathJax.typesetPromise();
});
24 changes: 24 additions & 0 deletions docs/reference/geometry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# API reference -- geometry result types

The result types returned by
[`compute_geometry_diff`][gerberdiff.compute_geometry_diff]. Unit
conventions: centroids in **inches**, areas in **mm^2**, displacements in
**mm** (see the [schema documentation](../schema.md)).

::: gerberdiff.geometry.types.GeometryChange

::: gerberdiff.geometry.types.LayerGeometryDiff

::: gerberdiff.geometry.types.GeometryDiffResult

## Core IR and shared result types

::: gerberdiff.types.ParsedImage

::: gerberdiff.types.DiffResult

::: gerberdiff.types.LayerDiffResult

::: gerberdiff.types.Region

::: gerberdiff.types.Diagnostic
32 changes: 32 additions & 0 deletions docs/reference/package.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# API reference -- top-level package

All public symbols are importable from the root `gerberdiff` package; see
the [Python API guide](../api.md) for usage examples.

## Parsing

::: gerberdiff.parse_gerber

::: gerberdiff.parse_excellon

## Geometry diff

::: gerberdiff.compute_geometry_diff

## Raster diff

::: gerberdiff.compute_diff

::: gerberdiff.compute_full_diff

## Rendering

::: gerberdiff.render_to_numpy

::: gerberdiff.render_to_surface

::: gerberdiff.compute_viewport

## Layer matching

::: gerberdiff.match_layers
9 changes: 9 additions & 0 deletions gerberdiff/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
"""Diff tool for Gerber/Excellon PCB design files.

Two complementary engines share one parse layer: the raster engine
(``compute_diff`` / ``compute_full_diff``) renders revisions with Cairo and
XORs pixels for visual overlays; the geometry engine
(``compute_geometry_diff``) computes resolution-independent, attributed
changes on the vector geometry and is Cairo-free.
"""

__version__ = "0.29.1"

from typing import TYPE_CHECKING, Any
Expand Down
87 changes: 87 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
site_name: gerberdiff
site_description: >-
Diff tool for Gerber/Excellon PCB files: visual raster overlays and
attributed vector-geometry change analysis.
site_url: https://cameronbrooks11.github.io/gerberdiff/
repo_url: https://github.com/CameronBrooks11/gerberdiff
repo_name: CameronBrooks11/gerberdiff
edit_uri: edit/main/docs/

theme:
name: material
palette:
- media: "(prefers-color-scheme: light)"
scheme: default
primary: teal
accent: deep orange
toggle:
icon: material/brightness-7
name: Switch to dark mode
- media: "(prefers-color-scheme: dark)"
scheme: slate
primary: teal
accent: deep orange
toggle:
icon: material/brightness-4
name: Switch to light mode
features:
- navigation.sections
- navigation.top
- navigation.footer
- content.code.copy
- content.action.edit
- search.suggest
- search.highlight
icon:
repo: fontawesome/brands/github

nav:
- Home: index.md
- Guide:
- CLI reference: cli.md
- Python API: api.md
- JSON report schemas: schema.md
- Internals:
- Architecture: architecture.md
- Geometry diff engine: geometry-diff.md
- API reference:
- Package: reference/package.md
- Geometry types: reference/geometry.md
- Project:
- Changelog: changelog.md
- Contributing: contributing.md

markdown_extensions:
- admonition
- attr_list
- pymdownx.arithmatex:
generic: true
- pymdownx.highlight:
anchor_linenums: true
- pymdownx.inlinehilite
- pymdownx.snippets:
base_path: ["."]
check_paths: true
- pymdownx.superfences
- tables
- toc:
permalink: true

extra_javascript:
- javascripts/mathjax.js
- https://unpkg.com/mathjax@3/es5/tex-mml-chtml.js

plugins:
- search
- mkdocstrings:
handlers:
python:
options:
docstring_style: numpy
show_source: false
members_order: source
separate_signature: true
show_signature_annotations: true

watch:
- gerberdiff
8 changes: 8 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@ dev = [
"scipy-stubs>=1.17.1.4",
"types-shapely>=2.1",
]
# Documentation site; built and deployed by .github/workflows/docs.yml.
# Material 9.x is pinned to MkDocs 1.x (MkDocs 2.0 is an incompatible
# rewrite); the maintainers' successor (Zensical) is the migration path
# once its plugin support matures.
docs = [
"mkdocs-material>=9.5,<10",
"mkdocstrings[python]>=0.26",
]

[project.scripts]
gerberdiff = "gerberdiff.cli:cli"
Expand Down
Loading
Loading