polyforge 0.1.0a1__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.
- polyforge-0.1.0a1/LICENSE +21 -0
- polyforge-0.1.0a1/PKG-INFO +153 -0
- polyforge-0.1.0a1/README.md +121 -0
- polyforge-0.1.0a1/polyforge/__init__.py +154 -0
- polyforge-0.1.0a1/polyforge/clearance/__init__.py +62 -0
- polyforge-0.1.0a1/polyforge/clearance/fix_clearance.py +474 -0
- polyforge-0.1.0a1/polyforge/core/__init__.py +69 -0
- polyforge-0.1.0a1/polyforge/core/cleanup.py +20 -0
- polyforge-0.1.0a1/polyforge/core/constraints.py +297 -0
- polyforge-0.1.0a1/polyforge/core/errors.py +259 -0
- polyforge-0.1.0a1/polyforge/core/geometry_utils.py +395 -0
- polyforge-0.1.0a1/polyforge/core/iterative_utils.py +134 -0
- polyforge-0.1.0a1/polyforge/core/spatial_utils.py +334 -0
- polyforge-0.1.0a1/polyforge/core/types.py +165 -0
- polyforge-0.1.0a1/polyforge/merge/__init__.py +10 -0
- polyforge-0.1.0a1/polyforge/merge/core.py +252 -0
- polyforge-0.1.0a1/polyforge/metrics.py +133 -0
- polyforge-0.1.0a1/polyforge/ops/__init__.py +10 -0
- polyforge-0.1.0a1/polyforge/ops/cleanup_ops.py +129 -0
- polyforge-0.1.0a1/polyforge/ops/clearance/__init__.py +36 -0
- polyforge-0.1.0a1/polyforge/ops/clearance/holes.py +177 -0
- polyforge-0.1.0a1/polyforge/ops/clearance/passages.py +760 -0
- polyforge-0.1.0a1/polyforge/ops/clearance/protrusions.py +283 -0
- polyforge-0.1.0a1/polyforge/ops/clearance/remove_protrusions.py +177 -0
- polyforge-0.1.0a1/polyforge/ops/clearance/utils.py +251 -0
- polyforge-0.1.0a1/polyforge/ops/merge/__init__.py +33 -0
- polyforge-0.1.0a1/polyforge/ops/merge_boundary_extension.py +270 -0
- polyforge-0.1.0a1/polyforge/ops/merge_common.py +101 -0
- polyforge-0.1.0a1/polyforge/ops/merge_convex_bridges.py +124 -0
- polyforge-0.1.0a1/polyforge/ops/merge_edge_detection.py +156 -0
- polyforge-0.1.0a1/polyforge/ops/merge_ops.py +174 -0
- polyforge-0.1.0a1/polyforge/ops/merge_selective_buffer.py +86 -0
- polyforge-0.1.0a1/polyforge/ops/merge_simple_buffer.py +52 -0
- polyforge-0.1.0a1/polyforge/ops/merge_vertex_movement.py +83 -0
- polyforge-0.1.0a1/polyforge/ops/simplify_ops.py +143 -0
- polyforge-0.1.0a1/polyforge/overlap.py +412 -0
- polyforge-0.1.0a1/polyforge/pipeline.py +133 -0
- polyforge-0.1.0a1/polyforge/process.py +140 -0
- polyforge-0.1.0a1/polyforge/repair/__init__.py +10 -0
- polyforge-0.1.0a1/polyforge/repair/analysis.py +84 -0
- polyforge-0.1.0a1/polyforge/repair/core.py +149 -0
- polyforge-0.1.0a1/polyforge/repair/robust.py +735 -0
- polyforge-0.1.0a1/polyforge/repair/strategies/__init__.py +15 -0
- polyforge-0.1.0a1/polyforge/repair/strategies/auto.py +87 -0
- polyforge-0.1.0a1/polyforge/repair/strategies/buffer.py +29 -0
- polyforge-0.1.0a1/polyforge/repair/strategies/reconstruct.py +46 -0
- polyforge-0.1.0a1/polyforge/repair/strategies/simplify.py +39 -0
- polyforge-0.1.0a1/polyforge/repair/strategies/strict.py +28 -0
- polyforge-0.1.0a1/polyforge/repair/utils.py +99 -0
- polyforge-0.1.0a1/polyforge/simplify.py +203 -0
- polyforge-0.1.0a1/polyforge/tile.py +89 -0
- polyforge-0.1.0a1/polyforge/topology.py +274 -0
- polyforge-0.1.0a1/polyforge.egg-info/PKG-INFO +153 -0
- polyforge-0.1.0a1/polyforge.egg-info/SOURCES.txt +75 -0
- polyforge-0.1.0a1/polyforge.egg-info/dependency_links.txt +1 -0
- polyforge-0.1.0a1/polyforge.egg-info/requires.txt +4 -0
- polyforge-0.1.0a1/polyforge.egg-info/top_level.txt +1 -0
- polyforge-0.1.0a1/pyproject.toml +54 -0
- polyforge-0.1.0a1/setup.cfg +4 -0
- polyforge-0.1.0a1/tests/test_cleanup.py +56 -0
- polyforge-0.1.0a1/tests/test_clearance.py +769 -0
- polyforge-0.1.0a1/tests/test_clearance_utils.py +231 -0
- polyforge-0.1.0a1/tests/test_errors.py +278 -0
- polyforge-0.1.0a1/tests/test_fix.py +372 -0
- polyforge-0.1.0a1/tests/test_fix_clearance.py +321 -0
- polyforge-0.1.0a1/tests/test_merge.py +607 -0
- polyforge-0.1.0a1/tests/test_merge_convex_bridges.py +174 -0
- polyforge-0.1.0a1/tests/test_merge_vertex_insertion.py +270 -0
- polyforge-0.1.0a1/tests/test_overlap.py +364 -0
- polyforge-0.1.0a1/tests/test_pipeline.py +134 -0
- polyforge-0.1.0a1/tests/test_process_geometry.py +777 -0
- polyforge-0.1.0a1/tests/test_remove_protrusions.py +264 -0
- polyforge-0.1.0a1/tests/test_robust_fix.py +680 -0
- polyforge-0.1.0a1/tests/test_simplify.py +500 -0
- polyforge-0.1.0a1/tests/test_split.py +410 -0
- polyforge-0.1.0a1/tests/test_tile.py +371 -0
- polyforge-0.1.0a1/tests/test_topology.py +332 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Dag Wastberg
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: polyforge
|
|
3
|
+
Version: 0.1.0a1
|
|
4
|
+
Summary: polygon processing and manipulation library built on Shapely - simplification, repair, merging, overlap resolution, and clearance fixing
|
|
5
|
+
Author-email: Dag Wastberg <dwastberg@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/dwastberg/polyforge
|
|
8
|
+
Project-URL: Repository, https://github.com/dwastberg/polyforge
|
|
9
|
+
Project-URL: Issues, https://github.com/dwastberg/polyforge/issues
|
|
10
|
+
Project-URL: Changelog, https://github.com/dwastberg/polyforge/releases
|
|
11
|
+
Keywords: geometry,polygon,shapely,gis,spatial,simplification,repair,merge,overlap
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: Topic :: Scientific/Engineering :: GIS
|
|
15
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Operating System :: OS Independent
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Requires-Dist: numpy>=2.0.1
|
|
28
|
+
Requires-Dist: scipy>=1.15.3
|
|
29
|
+
Requires-Dist: shapely>=2.1.0
|
|
30
|
+
Requires-Dist: simplification>=0.7.14
|
|
31
|
+
Dynamic: license-file
|
|
32
|
+
|
|
33
|
+
# Polyforge
|
|
34
|
+
|
|
35
|
+
Polyforge is a focused toolkit for cleaning, simplifying, repairing, and merging planar geometries built on top of Shapely. It exposes a small set of high-level functions that combine fast NumPy-based vertex processing with STRtree-powered spatial indexing, so you can run the same code on a handful of polygons or on thousands of building footprints.
|
|
36
|
+
|
|
37
|
+
## Installation
|
|
38
|
+
```bash
|
|
39
|
+
pip install polyforge
|
|
40
|
+
```
|
|
41
|
+
Python 3.10+ with Shapely ≥ 2.1 is required.
|
|
42
|
+
|
|
43
|
+
## What You Get
|
|
44
|
+
| Area | Highlights |
|
|
45
|
+
| --- | --- |
|
|
46
|
+
| **Simplify & Clean** | `simplify_rdp`, `simplify_vw`, `collapse_short_edges`, `remove_small_holes`, `remove_narrow_holes` |
|
|
47
|
+
| **Clearance Fixing** | `fix_clearance` auto-detects issues (holes too close, spikes, passages) and routes to ops helpers. Individual functions (`fix_hole_too_close`, `fix_narrow_passage`, …) now accept either enums or plain strings (e.g. `strategy="split"`). |
|
|
48
|
+
| **Overlap & Merge** | `split_overlap` for pairs, `remove_overlaps` for batches, `merge_close_polygons` with ops-based strategies (`"simple_buffer"`, `"selective_buffer"`, `"vertex_movement"`, `"boundary_extension"`, `"convex_bridges"`). |
|
|
49
|
+
| **Repair & QA** | `repair_geometry`, `analyze_geometry`, plus the pipeline-driven `robust_fix_geometry` / `robust_fix_batch` that iterate validity → clearance → merge → cleanup steps. |
|
|
50
|
+
| **Core Types** | Strategy enums (MergeStrategy, RepairStrategy, OverlapStrategy, …) remain available, but everything also accepts literal strings; `GeometryConstraints` + shared ops utilities live in `polyforge.ops.*`. |
|
|
51
|
+
|
|
52
|
+
## Quick Examples
|
|
53
|
+
|
|
54
|
+
### Simplify & Clean
|
|
55
|
+
```python
|
|
56
|
+
from shapely.geometry import Polygon
|
|
57
|
+
from polyforge import simplify_vwp, remove_small_holes
|
|
58
|
+
|
|
59
|
+
poly = Polygon([(0, 0), (5, 0.1), (10, 0), (10, 10), (0, 10)])
|
|
60
|
+
poly = simplify_vwp(poly, threshold=0.2)
|
|
61
|
+
poly = remove_small_holes(poly, min_area=1.0)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Fix Narrow Passages Automatically
|
|
65
|
+
```python
|
|
66
|
+
from polyforge import fix_clearance
|
|
67
|
+
|
|
68
|
+
improved, info = fix_clearance(complex_poly, min_clearance=1.5, return_diagnosis=True)
|
|
69
|
+
print(info.issue, info.fixed)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Merge Buildings into Blocks
|
|
73
|
+
```python
|
|
74
|
+
from polyforge import merge_close_polygons
|
|
75
|
+
|
|
76
|
+
merged = merge_close_polygons(
|
|
77
|
+
buildings,
|
|
78
|
+
margin=2.0,
|
|
79
|
+
merge_strategy="boundary_extension",
|
|
80
|
+
insert_vertices=True,
|
|
81
|
+
)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Remove Overlaps at Scale
|
|
85
|
+
```python
|
|
86
|
+
from polyforge import remove_overlaps
|
|
87
|
+
clean = remove_overlaps(parcel_list, overlap_strategy='split')
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Constrain Repairs
|
|
91
|
+
```python
|
|
92
|
+
from polyforge import robust_fix_geometry
|
|
93
|
+
from polyforge.core import GeometryConstraints
|
|
94
|
+
|
|
95
|
+
constraints = GeometryConstraints(min_clearance=1.0, min_area_ratio=0.9)
|
|
96
|
+
fixed, warn = robust_fix_geometry(polygon, constraints)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Design Notes
|
|
100
|
+
- **Ops-first architecture** – low-level helpers live in `polyforge/ops/…` (simplify, cleanup, clearance, merge). Public modules are thin wrappers that call these ops so behaviour stays consistent across the library.
|
|
101
|
+
- **Literal-friendly configuration** – strategy parameters accept enums or plain strings (`"selective_buffer"`, `"smooth"`, etc.), making it easy to drive Polyforge from config files or CLI flags.
|
|
102
|
+
- **Pipeline-driven repair** – `robust_fix_geometry` now runs a simple step list (validity → clearance → merge → cleanup) via `polyforge.pipeline.run_steps`, replacing the old transactional stage system.
|
|
103
|
+
- **process_geometry() everywhere** – every simplification/cleanup call is just a NumPy function applied to each vertex array, so Z values are preserved automatically.
|
|
104
|
+
- **STRtree first** – overlap removal, merges, and vertex insertion all walk spatial indexes, keeping runtime roughly O(n log n) even for thousands of polygons.
|
|
105
|
+
|
|
106
|
+
## Project Layout (high level)
|
|
107
|
+
```
|
|
108
|
+
polyforge/
|
|
109
|
+
ops/
|
|
110
|
+
simplify_ops.py # coordinate-level simplify helpers
|
|
111
|
+
cleanup_ops.py # hole removal, sliver cleanup
|
|
112
|
+
clearance/ # clearance fix primitives
|
|
113
|
+
merge/ + merge_* # merge strategies & utilities
|
|
114
|
+
simplify.py # thin wrappers over ops.simplify
|
|
115
|
+
clearance/ # fix_clearance + public wrappers
|
|
116
|
+
overlap.py # overlap engine + batch helpers
|
|
117
|
+
merge/ # merge orchestrator (calls ops)
|
|
118
|
+
repair/ # classic repair + pipeline-based robust fixes
|
|
119
|
+
core/ # enums, constraints, geometry/spatial utils
|
|
120
|
+
pipeline.py # FixConfig + run_steps helper
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Advanced: Using the ops layer directly
|
|
124
|
+
Most users should stick to the high-level API (`polyforge.simplify`, `polyforge.clearance`, `polyforge.merge`, `polyforge.repair`). If you need to compose Polyforge primitives yourself (custom pipelines, batch transforms, etc.), import the ops helpers:
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
from shapely.geometry import Polygon
|
|
128
|
+
from polyforge.process import process_geometry
|
|
129
|
+
from polyforge.ops.simplify_ops import snap_short_edges
|
|
130
|
+
from polyforge.ops.clearance import fix_hole_too_close
|
|
131
|
+
from polyforge.ops.merge import merge_selective_buffer
|
|
132
|
+
|
|
133
|
+
poly = Polygon([(0, 0), (1, 0.01), (2, 0), (2, 2), (0, 2)])
|
|
134
|
+
|
|
135
|
+
# Run a raw NumPy transform via process_geometry
|
|
136
|
+
collapsed = process_geometry(poly, snap_short_edges, min_length=0.1, snap_mode="midpoint")
|
|
137
|
+
|
|
138
|
+
# Call clearance helpers directly (accept enums or strings)
|
|
139
|
+
fixed = fix_hole_too_close(collapsed, min_clearance=1.0, strategy="shrink")
|
|
140
|
+
|
|
141
|
+
# Use merge strategies without going through merge_close_polygons
|
|
142
|
+
merged = merge_selective_buffer([fixed, fixed.translate(1.5, 0)], margin=0.5, preserve_holes=True)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
These ops modules expose the same functions the public API uses internally, so they're ideal for custom workflows or experimentation.
|
|
146
|
+
|
|
147
|
+
## Running Tests
|
|
148
|
+
```bash
|
|
149
|
+
python -m pytest -q
|
|
150
|
+
```
|
|
151
|
+
The suite asserts all expected warnings, so any output indicates a regression.
|
|
152
|
+
|
|
153
|
+
That’s it—import what you need from `polyforge` and combine the high-level functions to build your own geometry pipelines.
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# Polyforge
|
|
2
|
+
|
|
3
|
+
Polyforge is a focused toolkit for cleaning, simplifying, repairing, and merging planar geometries built on top of Shapely. It exposes a small set of high-level functions that combine fast NumPy-based vertex processing with STRtree-powered spatial indexing, so you can run the same code on a handful of polygons or on thousands of building footprints.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
```bash
|
|
7
|
+
pip install polyforge
|
|
8
|
+
```
|
|
9
|
+
Python 3.10+ with Shapely ≥ 2.1 is required.
|
|
10
|
+
|
|
11
|
+
## What You Get
|
|
12
|
+
| Area | Highlights |
|
|
13
|
+
| --- | --- |
|
|
14
|
+
| **Simplify & Clean** | `simplify_rdp`, `simplify_vw`, `collapse_short_edges`, `remove_small_holes`, `remove_narrow_holes` |
|
|
15
|
+
| **Clearance Fixing** | `fix_clearance` auto-detects issues (holes too close, spikes, passages) and routes to ops helpers. Individual functions (`fix_hole_too_close`, `fix_narrow_passage`, …) now accept either enums or plain strings (e.g. `strategy="split"`). |
|
|
16
|
+
| **Overlap & Merge** | `split_overlap` for pairs, `remove_overlaps` for batches, `merge_close_polygons` with ops-based strategies (`"simple_buffer"`, `"selective_buffer"`, `"vertex_movement"`, `"boundary_extension"`, `"convex_bridges"`). |
|
|
17
|
+
| **Repair & QA** | `repair_geometry`, `analyze_geometry`, plus the pipeline-driven `robust_fix_geometry` / `robust_fix_batch` that iterate validity → clearance → merge → cleanup steps. |
|
|
18
|
+
| **Core Types** | Strategy enums (MergeStrategy, RepairStrategy, OverlapStrategy, …) remain available, but everything also accepts literal strings; `GeometryConstraints` + shared ops utilities live in `polyforge.ops.*`. |
|
|
19
|
+
|
|
20
|
+
## Quick Examples
|
|
21
|
+
|
|
22
|
+
### Simplify & Clean
|
|
23
|
+
```python
|
|
24
|
+
from shapely.geometry import Polygon
|
|
25
|
+
from polyforge import simplify_vwp, remove_small_holes
|
|
26
|
+
|
|
27
|
+
poly = Polygon([(0, 0), (5, 0.1), (10, 0), (10, 10), (0, 10)])
|
|
28
|
+
poly = simplify_vwp(poly, threshold=0.2)
|
|
29
|
+
poly = remove_small_holes(poly, min_area=1.0)
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Fix Narrow Passages Automatically
|
|
33
|
+
```python
|
|
34
|
+
from polyforge import fix_clearance
|
|
35
|
+
|
|
36
|
+
improved, info = fix_clearance(complex_poly, min_clearance=1.5, return_diagnosis=True)
|
|
37
|
+
print(info.issue, info.fixed)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Merge Buildings into Blocks
|
|
41
|
+
```python
|
|
42
|
+
from polyforge import merge_close_polygons
|
|
43
|
+
|
|
44
|
+
merged = merge_close_polygons(
|
|
45
|
+
buildings,
|
|
46
|
+
margin=2.0,
|
|
47
|
+
merge_strategy="boundary_extension",
|
|
48
|
+
insert_vertices=True,
|
|
49
|
+
)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Remove Overlaps at Scale
|
|
53
|
+
```python
|
|
54
|
+
from polyforge import remove_overlaps
|
|
55
|
+
clean = remove_overlaps(parcel_list, overlap_strategy='split')
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Constrain Repairs
|
|
59
|
+
```python
|
|
60
|
+
from polyforge import robust_fix_geometry
|
|
61
|
+
from polyforge.core import GeometryConstraints
|
|
62
|
+
|
|
63
|
+
constraints = GeometryConstraints(min_clearance=1.0, min_area_ratio=0.9)
|
|
64
|
+
fixed, warn = robust_fix_geometry(polygon, constraints)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Design Notes
|
|
68
|
+
- **Ops-first architecture** – low-level helpers live in `polyforge/ops/…` (simplify, cleanup, clearance, merge). Public modules are thin wrappers that call these ops so behaviour stays consistent across the library.
|
|
69
|
+
- **Literal-friendly configuration** – strategy parameters accept enums or plain strings (`"selective_buffer"`, `"smooth"`, etc.), making it easy to drive Polyforge from config files or CLI flags.
|
|
70
|
+
- **Pipeline-driven repair** – `robust_fix_geometry` now runs a simple step list (validity → clearance → merge → cleanup) via `polyforge.pipeline.run_steps`, replacing the old transactional stage system.
|
|
71
|
+
- **process_geometry() everywhere** – every simplification/cleanup call is just a NumPy function applied to each vertex array, so Z values are preserved automatically.
|
|
72
|
+
- **STRtree first** – overlap removal, merges, and vertex insertion all walk spatial indexes, keeping runtime roughly O(n log n) even for thousands of polygons.
|
|
73
|
+
|
|
74
|
+
## Project Layout (high level)
|
|
75
|
+
```
|
|
76
|
+
polyforge/
|
|
77
|
+
ops/
|
|
78
|
+
simplify_ops.py # coordinate-level simplify helpers
|
|
79
|
+
cleanup_ops.py # hole removal, sliver cleanup
|
|
80
|
+
clearance/ # clearance fix primitives
|
|
81
|
+
merge/ + merge_* # merge strategies & utilities
|
|
82
|
+
simplify.py # thin wrappers over ops.simplify
|
|
83
|
+
clearance/ # fix_clearance + public wrappers
|
|
84
|
+
overlap.py # overlap engine + batch helpers
|
|
85
|
+
merge/ # merge orchestrator (calls ops)
|
|
86
|
+
repair/ # classic repair + pipeline-based robust fixes
|
|
87
|
+
core/ # enums, constraints, geometry/spatial utils
|
|
88
|
+
pipeline.py # FixConfig + run_steps helper
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Advanced: Using the ops layer directly
|
|
92
|
+
Most users should stick to the high-level API (`polyforge.simplify`, `polyforge.clearance`, `polyforge.merge`, `polyforge.repair`). If you need to compose Polyforge primitives yourself (custom pipelines, batch transforms, etc.), import the ops helpers:
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
from shapely.geometry import Polygon
|
|
96
|
+
from polyforge.process import process_geometry
|
|
97
|
+
from polyforge.ops.simplify_ops import snap_short_edges
|
|
98
|
+
from polyforge.ops.clearance import fix_hole_too_close
|
|
99
|
+
from polyforge.ops.merge import merge_selective_buffer
|
|
100
|
+
|
|
101
|
+
poly = Polygon([(0, 0), (1, 0.01), (2, 0), (2, 2), (0, 2)])
|
|
102
|
+
|
|
103
|
+
# Run a raw NumPy transform via process_geometry
|
|
104
|
+
collapsed = process_geometry(poly, snap_short_edges, min_length=0.1, snap_mode="midpoint")
|
|
105
|
+
|
|
106
|
+
# Call clearance helpers directly (accept enums or strings)
|
|
107
|
+
fixed = fix_hole_too_close(collapsed, min_clearance=1.0, strategy="shrink")
|
|
108
|
+
|
|
109
|
+
# Use merge strategies without going through merge_close_polygons
|
|
110
|
+
merged = merge_selective_buffer([fixed, fixed.translate(1.5, 0)], margin=0.5, preserve_holes=True)
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
These ops modules expose the same functions the public API uses internally, so they're ideal for custom workflows or experimentation.
|
|
114
|
+
|
|
115
|
+
## Running Tests
|
|
116
|
+
```bash
|
|
117
|
+
python -m pytest -q
|
|
118
|
+
```
|
|
119
|
+
The suite asserts all expected warnings, so any output indicates a regression.
|
|
120
|
+
|
|
121
|
+
That’s it—import what you need from `polyforge` and combine the high-level functions to build your own geometry pipelines.
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"""Polyforge - Polygon processing and manipulation library.
|
|
2
|
+
|
|
3
|
+
This library provides utilities for processing, simplifying, and manipulating
|
|
4
|
+
polygon geometries using Shapely.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
__version__ = "0.1.0a1"
|
|
8
|
+
|
|
9
|
+
# Simplification functions
|
|
10
|
+
from .simplify import (
|
|
11
|
+
simplify_rdp,
|
|
12
|
+
simplify_vw,
|
|
13
|
+
simplify_vwp,
|
|
14
|
+
collapse_short_edges,
|
|
15
|
+
deduplicate_vertices,
|
|
16
|
+
remove_small_holes,
|
|
17
|
+
remove_narrow_holes,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
# Clearance fixing functions
|
|
21
|
+
from .clearance import (
|
|
22
|
+
fix_clearance,
|
|
23
|
+
fix_hole_too_close,
|
|
24
|
+
fix_narrow_protrusion,
|
|
25
|
+
remove_narrow_protrusions,
|
|
26
|
+
fix_sharp_intrusion,
|
|
27
|
+
fix_narrow_passage,
|
|
28
|
+
fix_near_self_intersection,
|
|
29
|
+
fix_parallel_close_edges,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
# Overlap handling functions
|
|
33
|
+
from .overlap import (
|
|
34
|
+
split_overlap,
|
|
35
|
+
remove_overlaps,
|
|
36
|
+
count_overlaps,
|
|
37
|
+
find_overlapping_groups,
|
|
38
|
+
resolve_overlap_pair,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
# Merge functions
|
|
42
|
+
from .merge import merge_close_polygons
|
|
43
|
+
|
|
44
|
+
# Topology functions
|
|
45
|
+
from .topology import align_boundaries
|
|
46
|
+
|
|
47
|
+
# Geometry repair functions
|
|
48
|
+
from .repair import (
|
|
49
|
+
repair_geometry,
|
|
50
|
+
analyze_geometry,
|
|
51
|
+
batch_repair_geometries,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
# Robust constraint-aware repair
|
|
55
|
+
from .repair.robust import (
|
|
56
|
+
robust_fix_geometry,
|
|
57
|
+
robust_fix_batch,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
# Core types (enums)
|
|
61
|
+
from .core import (
|
|
62
|
+
OverlapStrategy,
|
|
63
|
+
MergeStrategy,
|
|
64
|
+
RepairStrategy,
|
|
65
|
+
CollapseMode,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
# Core exceptions
|
|
69
|
+
from .core import (
|
|
70
|
+
PolyforgeError,
|
|
71
|
+
ValidationError,
|
|
72
|
+
RepairError,
|
|
73
|
+
OverlapResolutionError,
|
|
74
|
+
MergeError,
|
|
75
|
+
ClearanceError,
|
|
76
|
+
ConfigurationError,
|
|
77
|
+
FixWarning,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
# Constraint framework
|
|
81
|
+
from .core import (
|
|
82
|
+
GeometryConstraints,
|
|
83
|
+
ConstraintStatus,
|
|
84
|
+
ConstraintViolation,
|
|
85
|
+
ConstraintType,
|
|
86
|
+
MergeConstraints,
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
__all__ = [
|
|
90
|
+
|
|
91
|
+
# Simplification
|
|
92
|
+
'simplify_rdp',
|
|
93
|
+
'simplify_vw',
|
|
94
|
+
'simplify_vwp',
|
|
95
|
+
'collapse_short_edges',
|
|
96
|
+
'deduplicate_vertices',
|
|
97
|
+
'remove_small_holes',
|
|
98
|
+
'remove_narrow_holes',
|
|
99
|
+
|
|
100
|
+
# Clearance fixing
|
|
101
|
+
'fix_clearance',
|
|
102
|
+
'fix_hole_too_close',
|
|
103
|
+
'fix_narrow_protrusion',
|
|
104
|
+
'remove_narrow_protrusions',
|
|
105
|
+
'fix_sharp_intrusion',
|
|
106
|
+
'fix_narrow_passage',
|
|
107
|
+
'fix_near_self_intersection',
|
|
108
|
+
'fix_parallel_close_edges',
|
|
109
|
+
|
|
110
|
+
# Overlap handling
|
|
111
|
+
'split_overlap',
|
|
112
|
+
'remove_overlaps',
|
|
113
|
+
'count_overlaps',
|
|
114
|
+
'find_overlapping_groups',
|
|
115
|
+
'resolve_overlap_pair',
|
|
116
|
+
|
|
117
|
+
# Merge
|
|
118
|
+
'merge_close_polygons',
|
|
119
|
+
|
|
120
|
+
# Topology
|
|
121
|
+
'align_boundaries',
|
|
122
|
+
|
|
123
|
+
# Geometry repair
|
|
124
|
+
'repair_geometry',
|
|
125
|
+
'analyze_geometry',
|
|
126
|
+
'batch_repair_geometries',
|
|
127
|
+
|
|
128
|
+
# Robust constraint-aware repair
|
|
129
|
+
'robust_fix_geometry',
|
|
130
|
+
'robust_fix_batch',
|
|
131
|
+
|
|
132
|
+
# Core types (enums)
|
|
133
|
+
'OverlapStrategy',
|
|
134
|
+
'MergeStrategy',
|
|
135
|
+
'RepairStrategy',
|
|
136
|
+
'CollapseMode',
|
|
137
|
+
|
|
138
|
+
# Core exceptions
|
|
139
|
+
'PolyforgeError',
|
|
140
|
+
'ValidationError',
|
|
141
|
+
'RepairError',
|
|
142
|
+
'OverlapResolutionError',
|
|
143
|
+
'MergeError',
|
|
144
|
+
'ClearanceError',
|
|
145
|
+
'ConfigurationError',
|
|
146
|
+
'FixWarning',
|
|
147
|
+
|
|
148
|
+
# Constraint framework
|
|
149
|
+
'GeometryConstraints',
|
|
150
|
+
'ConstraintStatus',
|
|
151
|
+
'ConstraintViolation',
|
|
152
|
+
'ConstraintType',
|
|
153
|
+
'MergeConstraints',
|
|
154
|
+
]
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""Geometry clearance fixing functions.
|
|
2
|
+
|
|
3
|
+
This module provides functions for fixing geometries with low minimum clearance
|
|
4
|
+
by applying minimal geometric modifications. Each function targets a specific
|
|
5
|
+
type of clearance issue.
|
|
6
|
+
|
|
7
|
+
The minimum_clearance (from Shapely) represents the smallest distance by which
|
|
8
|
+
a vertex could be moved to create an invalid geometry. Higher values indicate
|
|
9
|
+
more robust, stable geometries.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
# Import public API functions from the ops layer
|
|
13
|
+
from polyforge.ops.clearance import (
|
|
14
|
+
fix_hole_too_close,
|
|
15
|
+
fix_narrow_protrusion,
|
|
16
|
+
fix_sharp_intrusion,
|
|
17
|
+
remove_narrow_protrusions,
|
|
18
|
+
fix_narrow_passage,
|
|
19
|
+
fix_near_self_intersection,
|
|
20
|
+
fix_parallel_close_edges,
|
|
21
|
+
)
|
|
22
|
+
from .fix_clearance import (
|
|
23
|
+
fix_clearance,
|
|
24
|
+
diagnose_clearance,
|
|
25
|
+
ClearanceIssue,
|
|
26
|
+
ClearanceDiagnosis,
|
|
27
|
+
ClearanceFixSummary,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
# Import utility functions from ops
|
|
31
|
+
from polyforge.ops.clearance import (
|
|
32
|
+
_find_nearest_vertex_index,
|
|
33
|
+
_find_nearest_edge_index,
|
|
34
|
+
_point_to_segment_distance,
|
|
35
|
+
_point_to_line_perpendicular_distance,
|
|
36
|
+
_get_vertex_neighborhood,
|
|
37
|
+
_calculate_curvature_at_vertex,
|
|
38
|
+
_remove_vertices_between,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
__all__ = [
|
|
42
|
+
# Main public API
|
|
43
|
+
'fix_clearance', # Auto-detection and fixing
|
|
44
|
+
'diagnose_clearance', # Diagnosis without fixing
|
|
45
|
+
'ClearanceIssue',
|
|
46
|
+
'ClearanceDiagnosis',
|
|
47
|
+
'ClearanceFixSummary',
|
|
48
|
+
'fix_hole_too_close',
|
|
49
|
+
'fix_narrow_protrusion',
|
|
50
|
+
'remove_narrow_protrusions',
|
|
51
|
+
'fix_sharp_intrusion',
|
|
52
|
+
'fix_narrow_passage',
|
|
53
|
+
'fix_near_self_intersection',
|
|
54
|
+
'fix_parallel_close_edges',
|
|
55
|
+
# Utility functions (for advanced users and tests)
|
|
56
|
+
# '_find_nearest_vertex_index',
|
|
57
|
+
# '_find_nearest_edge_index',
|
|
58
|
+
# '_point_to_segment_distance',
|
|
59
|
+
# '_get_vertex_neighborhood',
|
|
60
|
+
# '_calculate_curvature_at_vertex',
|
|
61
|
+
# '_remove_vertices_between',
|
|
62
|
+
]
|