Skip to main content

concavewrap-geo

CI PyPI Python License

Build auditable concave hulls that cover complete polygon areas.

Many concave-hull implementations guarantee that the output contains the input vertices. For areal data that is not enough: a hull edge can cut through a source polygon. concavewrap repairs or rejects invalid input, constructs the hull, and then enforces and verifies coverage of every source polygon.

Polygon patches become a polygon-safe concave hull

Quick start

python -m pip install concavewrap-geo
concavewrap build areas.gpkg \
  --layer areas \
  --ratio 0.25 \
  --output hulls.gpkg \
  --diagnostics hulls.json

The output is a GeoPackage layer named hulls. The JSON report records input and output areas, added fill area, the convex-hull area, coverage checks, repaired features, and any convex fallback.

Reproducible example

Generate and process four synthetic polygon arrangements, including the failure modes that commonly make a single concave-hull setting misleading:

python examples/run_examples.py
scenario question answered expected result
forest-patches can irregular areal patches be wrapped without cutting them? one hull that covers every complete polygon
large-gap should disconnected patches be bridged? global gives one hull; component gives two
narrow-neck does a thin connecting polygon remain covered? one valid hull covering the neck and both ends
ring-with-hole should a semantic hole remain open? allow_holes=True keeps it; the default fills it

Generated inputs, outputs, and JSON reports are placed under examples/generated/. To run the standard case through the CLI:

concavewrap build examples/generated/forest-patches.gpkg \
  --layer areas \
  --ratio 0.25 \
  --output examples/generated/forest-hull-cli.gpkg \
  --diagnostics examples/generated/forest-hull-cli.json

Expected audit values are printed and asserted by the script, then saved in summary.json. No external or real-world data is used.

Ratio and policies

--ratio follows GEOS/Shapely semantics:

value behavior
0 most concave result available from the input vertices
0.25 useful starting point for irregular polygon collections
1 convex hull

The ratio is dimensionless. It is not an alpha radius or a distance threshold, so values from alpha-shape tools cannot be copied directly.

option choices meaning
--scope global, component bridge all polygons in a group, or keep disconnected dissolved components separate
--group-by FIELD any scalar field build an independent result for each attribute value
--allow-holes flag retain source holes and permit hull holes; without it all holes are filled
--invalid repair, error repair invalid polygonal geometry with GEOS or stop
--fallback convex, error use and report the convex hull if the concave operation fails, or stop

Guarantees

For every output record, concavewrap verifies that:

  • the result is valid polygonal geometry;
  • the result covers the complete input polygon area, not only its vertices;
  • the result does not extend beyond the convex hull, within floating-point tolerance;
  • the chosen hole, grouping, component, repair, and fallback policies are recorded;
  • input ordering determines stable group and component ordering.

Output fields

field meaning
hull_id stable one-based output identifier
group_value text representation of the grouping value, or null
source_features number of input features contributing to the hull
repaired_features number of invalid contributors repaired
input_area dissolved source area in CRS square units
hull_area output hull area
fill_area area added around or between source polygons
convex_area area of the corresponding convex hull
hull_to_convex_ratio output area divided by convex-hull area
fallback_used whether the convex fallback was used
fallback_reason captured failure message, if any
ratio, allow_holes, scope effective construction settings
covers_input final invariant check

Python API

import geopandas as gpd
from concavewrap import HullOptions, HullResult, build_hulls

areas = gpd.read_file("areas.gpkg", layer="areas")
result: HullResult = build_hulls(
    areas,
    HullOptions(ratio=0.25, scope="global", allow_holes=False),
)
result.hulls.to_file("hulls.gpkg", layer="hulls", driver="GPKG")
print(result.report())

The stable public interface is build_hulls(...), HullOptions, HullResult, and HullDiagnostic.

Limits

  • Input geometries must be Polygon or MultiPolygon.
  • A projected CRS with horizontal units in metres is required so that area audit values are meaningful and comparable.
  • component scope dissolves touching and overlapping polygons before identifying disconnected components.
  • Concave hulls are not unique across algorithms. This package uses the GEOS algorithm exposed by Shapely and records its ratio explicitly.
  • A hull is a generalization. Always inspect results for sparse samples, narrow necks, very large gaps, and geometries whose holes have semantic meaning.

Run concavewrap --help for all options. Exit code 0 means success and 2 means invalid input or a processing failure.

The pre-release and launch checks are listed in docs/release-checklist.md.

Development

python -m pip install -e ".[test]"
python -m ruff check .
python -m ruff format --check .
python -m pytest

Copyright 2026 Alena Nikitina. Licensed under the Apache License 2.0.

Metadata

Release files for concavewrap-geo 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for concavewrap-geo 0.1.0
File Size Uploaded
concavewrap_geo-0.1.0.tar.gz 20.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for concavewrap-geo 0.1.0
File Interpreter ABI Platform
concavewrap_geo-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 33.7 kB

Release files / concavewrap_geo-0.1.0.tar.gz

Download URL concavewrap_geo-0.1.0.tar.gz
Size 20.3 kB
Tags Source
SHA-256 checksum
How to use checksums
d270b8093589db673426bad076d29edd4cea592645d5762ea5e0c613127ef6bf
BLAKE2b-256 checksum
How to use checksums
8e9c791054367c5b34933138d81c6773b28998aa7e922e4f6ed921f9b553f801
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 1, 2026.

Transparency log

Release files / concavewrap_geo-0.1.0-py3-none-any.whl

Download URL concavewrap_geo-0.1.0-py3-none-any.whl
Size 13.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
fee03b694271ff0a64cc521974735d2f94bcfacaad8706e33ac98758cb9824da
BLAKE2b-256 checksum
How to use checksums
89356863fc97b9182197531ba0f3bc14277db4914c75a51443f6a0134f4e82a1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 1, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page