Skip to content

Commit 099f123

Browse files
authored
Merge pull request #10 from DPIRD-DMA/chore/ci-and-release-setup
Chore/ci and release setup
2 parents 76cf03c + 9c3c4db commit 099f123

18 files changed

Lines changed: 729 additions & 2389 deletions

.github/workflows/ci.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
pull_request:
6+
7+
jobs:
8+
check:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- uses: actions/checkout@v6
12+
13+
- uses: actions/setup-python@v6
14+
with:
15+
python-version: "3.11"
16+
17+
- uses: astral-sh/setup-uv@v8.0.0
18+
19+
- run: uv sync --all-extras --dev
20+
21+
- name: Lint
22+
run: uv run ruff check .
23+
24+
- name: Type check
25+
run: uv run mypy buildingregulariser/ tests/
26+
27+
- name: Test
28+
run: uv run pytest tests/ -x -q

.github/workflows/publish.yml

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
name: Publish to PyPI
2+
3+
on:
4+
push:
5+
tags:
6+
- "v*"
7+
8+
jobs:
9+
build:
10+
runs-on: ubuntu-latest
11+
steps:
12+
- uses: actions/checkout@v6
13+
with:
14+
fetch-depth: 0
15+
fetch-tags: true
16+
17+
- uses: actions/setup-python@v6
18+
with:
19+
python-version: "3.11"
20+
21+
- uses: astral-sh/setup-uv@v8.0.0
22+
23+
- name: Build sdist and wheel
24+
run: uv build
25+
26+
- uses: actions/upload-artifact@v6
27+
with:
28+
name: dist
29+
path: dist/
30+
31+
publish:
32+
needs: build
33+
runs-on: ubuntu-latest
34+
environment: pypi
35+
permissions:
36+
id-token: write
37+
steps:
38+
- uses: actions/download-artifact@v8
39+
with:
40+
name: dist
41+
path: dist/
42+
43+
- uses: pypa/gh-action-pypi-publish@release/v1

.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ ipython_config.py
9898
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
9999
# This is especially recommended for binary packages to ensure reproducibility, and is more
100100
# commonly ignored for libraries.
101-
#uv.lock
101+
uv.lock
102102

103103
# poetry
104104
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
@@ -179,4 +179,4 @@ private test data/*
179179
buildingregulariser.egg-info/*
180180
.DS_Store
181181
test data/input/old/*
182-
test data/output/*
182+
tests/output/

.pre-commit-config.yaml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
repos:
2+
- repo: https://github.com/astral-sh/ruff-pre-commit
3+
rev: v0.15.8
4+
hooks:
5+
- id: ruff-check
6+
- id: ruff-format
7+
- repo: local
8+
hooks:
9+
- id: pytest
10+
name: pytest
11+
entry: uv run pytest tests/ -x -q
12+
language: system
13+
pass_filenames: false
14+
always_run: true
15+
stages: [pre-push]

.vscode/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"geodataframe",
88
"linalg",
99
"ndarray",
10+
"pyproj",
1011
"neighbour",
1112
"neighbourhood",
1213
"neighbouring",

CHANGELOG.md

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
# Changelog
2+
3+
All notable changes to Building-Regulariser are documented here.
4+
5+
## [Unreleased]
6+
7+
## [0.2.5] - 2026-05-04
8+
9+
### Added
10+
- Pre-commit configuration (`ruff-check`, `ruff-format`, and a pre-push
11+
`pytest` hook).
12+
- GitHub Actions CI workflow running ruff lint, mypy, and pytest on
13+
every push and pull request.
14+
- GitHub Actions publish workflow that builds the package and pushes to
15+
PyPI via OIDC trusted publishing on `v*` tag pushes.
16+
- `py.typed` marker so downstream type checkers pick up the package's
17+
type hints.
18+
- Multipolygon regression tests covering self-intersecting and
19+
vertex-touching inputs.
20+
21+
### Changed
22+
- Versioning is now derived from git tags via `setuptools-scm`. The
23+
hardcoded `__version__.py` has been removed; `__version__` is now
24+
read at runtime from package metadata via `importlib.metadata`.
25+
- `regularize_single_polygon` signature widened to
26+
`Polygon | MultiPolygon` to match its actual runtime behaviour.
27+
- `uv.lock` is no longer tracked in version control.
28+
29+
### Fixed
30+
- Type errors in `geometry_utils.rotate_edge` where the no-rotation
31+
branch returned `ndarray` instead of the expected coordinate tuple.
32+
33+
## [0.2.4] - 2025-07-24
34+
35+
### Added
36+
- Project metadata: license, keywords, project URL.
37+
- Ruff to the dev dependency group.
38+
39+
### Fixed
40+
- Improved robustness when input geometries are invalid
41+
(self-intersecting or otherwise malformed polygons).
42+
- Handling of invalid inputs reported in issue #5.
43+
44+
### Changed
45+
- Layer order in the regularization pipeline.
46+
- Updated example parameters and dataset.
47+
48+
## [0.2.2] - 2025-05-22
49+
50+
### Added
51+
- Neighbour alignment: edges of nearby buildings can be aligned to a
52+
shared direction.
53+
- End-to-end tests for geometry quality and parameterized regularization.
54+
- Example notebook and data.
55+
56+
### Changed
57+
- Throughput optimisations.
58+
- Improved spatial-index handling and data preparation in neighbour
59+
alignment.
60+
- Internal consolidation and refactoring; `rotate_edge` and other line
61+
operations consolidated into `geometry_utils`.
62+
- Type-hint and argument-name cleanup across the codebase.
63+
64+
## [0.1.12] - 2025-04-12
65+
66+
### Added
67+
- `include_metadata` option to return per-feature regularization
68+
metadata alongside the output geometries.
69+
- Conda-forge install instructions.
70+
71+
### Changed
72+
- Improved main-edge finding with mirroring and smoothing.
73+
- Relaxed dependency version requirements.
74+
75+
## [0.1.11] - 2025-04-10
76+
77+
### Changed
78+
- Reordered filter operations in the regularization pipeline.
79+
80+
## [0.1.10] - 2025-04-09
81+
82+
### Added
83+
- Coarse and fine bins when finding the main direction of a polygon.
84+
85+
## [0.1.9] - 2025-04-09
86+
87+
### Added
88+
- Per-feature metadata output.
89+
- Inputs are now exploded so multipart geometries are handled.
90+
- Increased histogram bin size for direction estimation.
91+
92+
## [0.1.8] - 2025-04-04
93+
94+
### Added
95+
- Additional histogram bins for finer direction estimation.
96+
97+
## [0.1.7] - 2025-04-03
98+
99+
### Added
100+
- Exposed the diagonal threshold reduction parameter.
101+
102+
## [0.1.6] - 2025-04-03
103+
104+
### Fixed
105+
- Handling of unusually large buildings.
106+
107+
## [0.1.4] - 2025-04-02
108+
109+
### Added
110+
- Optional circle output for round-shaped buildings.
111+
112+
### Changed
113+
- Throughput improvements.
114+
115+
## [0.1.3] - 2025-04-01
116+
117+
### Added
118+
- MIT license file and project README.
119+
120+
### Fixed
121+
- Cleaning logic refinements following the initial release.
122+
123+
## [0.1.0] - 2025-04-01
124+
125+
### Added
126+
- Initial public release with the core `regularize_geodataframe` API
127+
for aligning building polygon edges to principal directions.
128+
129+
[Unreleased]: https://github.com/DPIRD-DMA/Building-Regulariser/compare/v0.2.5...HEAD
130+
[0.2.5]: https://github.com/DPIRD-DMA/Building-Regulariser/compare/v0.2.4...v0.2.5
131+
[0.2.4]: https://github.com/DPIRD-DMA/Building-Regulariser/compare/v0.2.2...v0.2.4
132+
[0.2.2]: https://github.com/DPIRD-DMA/Building-Regulariser/compare/v0.1.12...v0.2.2
133+
[0.1.12]: https://github.com/DPIRD-DMA/Building-Regulariser/compare/v0.1.11...v0.1.12
134+
[0.1.11]: https://github.com/DPIRD-DMA/Building-Regulariser/compare/v0.1.10...v0.1.11
135+
[0.1.10]: https://github.com/DPIRD-DMA/Building-Regulariser/compare/v0.1.9...v0.1.10
136+
[0.1.9]: https://github.com/DPIRD-DMA/Building-Regulariser/compare/v0.1.8...v0.1.9
137+
[0.1.8]: https://github.com/DPIRD-DMA/Building-Regulariser/compare/v0.1.7...v0.1.8
138+
[0.1.7]: https://github.com/DPIRD-DMA/Building-Regulariser/compare/v0.1.6...v0.1.7
139+
[0.1.6]: https://github.com/DPIRD-DMA/Building-Regulariser/compare/v0.1.4...v0.1.6
140+
[0.1.4]: https://github.com/DPIRD-DMA/Building-Regulariser/compare/v0.1.3...v0.1.4
141+
[0.1.3]: https://github.com/DPIRD-DMA/Building-Regulariser/compare/v0.1.0...v0.1.3
142+
[0.1.0]: https://github.com/DPIRD-DMA/Building-Regulariser/releases/tag/v0.1.0

README.md

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@
22

33
A Python library for regularizing building footprints in geospatial data. This library helps clean up and standardize building polygon geometries by aligning edges to principal directions. Built as an open source alternative to the [ArcGIS Regularize Building Footprint (3D Analyst) tool](https://pro.arcgis.com/en/pro-app/latest/tool-reference/3d-analyst/regularize-building-footprint.htm).
44

5-
[![Python](https://img.shields.io/badge/Python-3.9%2B-blue)]()
6-
[![License](https://img.shields.io/badge/License-MIT-green)]()
5+
[![PyPI](https://img.shields.io/pypi/v/buildingregulariser)](https://pypi.org/project/buildingregulariser/)
6+
[![conda-forge](https://img.shields.io/conda/vn/conda-forge/buildingregulariser)](https://anaconda.org/conda-forge/buildingregulariser)
7+
[![Downloads](https://static.pepy.tech/badge/buildingregulariser)](https://pepy.tech/project/buildingregulariser)
8+
[![Python](https://img.shields.io/pypi/pyversions/buildingregulariser)](https://pypi.org/project/buildingregulariser/)
9+
[![CI](https://github.com/DPIRD-DMA/Building-Regulariser/actions/workflows/ci.yml/badge.svg)](https://github.com/DPIRD-DMA/Building-Regulariser/actions/workflows/ci.yml)
10+
[![License](https://img.shields.io/badge/License-MIT-green)](LICENSE)
711

812
## Example Results
913

@@ -93,31 +97,32 @@ regularized = regularize_geodataframe(buildings)
9397
```python
9498
regularized = regularize_geodataframe(
9599
buildings,
96-
parallel_threshold=2.0, # Higher values allow less edge alignment
97-
simplify_tolerance=0.5, # Controls simplification level, should be 2-3 x the raster pixel size
98-
allow_45_degree=True, # Enable 45-degree angles
99-
allow_circles=True, # Enable circle detection
100-
circle_threshold=0.9 # IOU threshold for circle detection
101-
neighbor_alignment=True, # After regularization try to align each building with neighboring buildings
102-
neighbor_search_distance: float = 100.0, # The search distance around each building to find neighbors
103-
neighbor_max_rotation: float = 10, # The maximum rotation allowed to align with neighbors
100+
parallel_threshold=2.0, # Higher values allow less edge alignment
101+
simplify_tolerance=0.5, # Controls simplification level, should be 2-3 x the raster pixel size
102+
allow_45_degree=True, # Enable 45-degree angles
103+
allow_circles=True, # Enable circle detection
104+
circle_threshold=0.9, # IOU threshold for circle detection
105+
neighbor_alignment=True, # After regularization try to align each building with neighboring buildings
106+
neighbor_search_distance=100, # Search distance around each building when looking for neighbors
107+
neighbor_max_rotation=10, # Maximum rotation allowed to align with neighbors
104108
)
105109
```
106110

107111
## Parameters
108112

109113
- **geodataframe**: Input GeoDataFrame with polygon geometries
110114
- **parallel_threshold**: Distance threshold for handling parallel lines (default: 1.0)
115+
- **target_crs**: Optional CRS (string or `pyproj.CRS`) to reproject the input to before regularization (default: None)
111116
- **simplify**: If True, applies simplification to the geometry (default: True)
112117
- **simplify_tolerance**: Tolerance for simplification (default: 0.5)
113118
- **allow_45_degree**: If True, allows edges to be oriented at 45-degree angles (default: True)
114119
- **diagonal_threshold_reduction**: Used to reduce the chance of diagonal edges being generated, can be from 0 to 22.5 (default: 15.0)
115120
- **allow_circles**: If True, detects and converts near-circular shapes to perfect circles (default: True)
116121
- **circle_threshold**: Intersection over Union (IoU) threshold for circle detection (default: 0.9)
117-
- **num_cores**: Number of CPU cores to use for parallel processing (default: 1)
118-
- **include_metadata**: Include the main direction, IOU, perimeter and aligned_direction (if used) in output gdf
122+
- **num_cores**: Number of CPU cores to use for parallel processing; 0 uses all available cores (default: 0)
123+
- **include_metadata**: Include the main direction, IOU, perimeter and aligned_direction (if used) in output gdf (default: False)
119124
- **neighbor_alignment**: If True, try to align each building with neighboring buildings (default: False)
120-
- **neighbor_search_distance**: The distance to find neighboring buildings (default: 350.0)
125+
- **neighbor_search_distance**: The distance to find neighboring buildings (default: 100.0)
121126
- **neighbor_max_rotation**: The maximum allowable rotation to align with neighbors (default: 10)
122127

123128

RELEASING.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Releasing Building-Regulariser
2+
3+
How to cut a new release to PyPI. The whole flow is driven from a single
4+
`v*` git tag — `setuptools-scm` reads the version from the tag and
5+
`pypa/gh-action-pypi-publish` ships the wheel.
6+
7+
## Cutting a release
8+
9+
1. **Update [`CHANGELOG.md`](CHANGELOG.md).**
10+
Promote the `[Unreleased]` section to `[X.Y.Z] - YYYY-MM-DD` and add
11+
a fresh empty `[Unreleased]` heading on top. Update the comparison
12+
links at the bottom of the file to add the new version.
13+
14+
2. **Merge to `main`.**
15+
Make sure the merge commit is the one you intend to release —
16+
the tag will be cut from it.
17+
18+
3. **Tag and push.**
19+
```bash
20+
git checkout main
21+
git pull
22+
git tag vX.Y.Z # e.g. v0.3.0
23+
git push origin vX.Y.Z
24+
```
25+
26+
4. **Approve the deployment.**
27+
The push triggers the [`Publish to PyPI`](.github/workflows/publish.yml)
28+
workflow. Open *Actions* on GitHub and click *Review pending
29+
deployments → Approve and deploy* on the `pypi` environment when
30+
prompted.
31+
32+
5. **Verify on PyPI.**
33+
Within a minute or two `pip install buildingregulariser==X.Y.Z` should
34+
work and the project page on
35+
<https://pypi.org/project/buildingregulariser/> should show the new
36+
version.
37+
38+
## Notes
39+
40+
- **Versions come from tags.** `buildingregulariser.__version__` and the
41+
wheel filename both come from `setuptools-scm` reading the latest `v*`
42+
tag. Don't hand-edit a version anywhere — bumping a tag is the entire
43+
bump.
44+
- **Pre-releases** (e.g. `v0.3.0rc1`) work the same way; PEP 440 markers
45+
in the tag carry through.
46+
- **Yanking a bad release** is done from the PyPI web UI, not from this
47+
repo. The tag and CHANGELOG entry stay.
48+
- **Hotfix on an older line** (e.g. `v0.2.5` while `main` is on `0.3.x`):
49+
branch from the older tag, fix, tag `v0.2.5` on that branch, push the
50+
tag. The same workflow handles it.

buildingregulariser/__init__.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,15 @@
44
A package for regularizing polygons by aligning edges to principal directions.
55
"""
66

7-
from .__version__ import __version__
7+
from importlib.metadata import PackageNotFoundError, version
8+
89
from .coordinator import regularize_geodataframe
910

11+
try:
12+
__version__ = version("buildingregulariser")
13+
except PackageNotFoundError:
14+
__version__ = "0.0.0+unknown"
15+
1016
# Package-wide exports
1117
__all__ = [
1218
"regularize_geodataframe",

buildingregulariser/__version__.py

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)