gisc
A stateless civil/GIS compiler. Civil intent → IR → adapters → view + provenance.
pip install -e ".[dev]" && pytest && gisc compile corridor.conflicts \
--alignment fixtures/alignment.xml \
--utils fixtures/utilities.geojson \
--flood fixtures/flood.geojson \
--buffer-ft 15 --crs EPSG:3857 --out ./out/demo
gisc ir <same args> prints the plan and stops without executing any op.
Stateless means gisc has no database. It reads the files and services you already
own, in place, read-only, and writes exactly one folder: plan.json (the IR it
compiled), conflicts.geojson, flood.geojson, summary.md, and provenance.json
— source path, mtime, sha256, CRS in and out, filter, and feature counts for every
input. Every emitted feature carries the source it came from; if gisc cannot say
where a geometry came from, it does not emit it. A missing CRS is a non-zero exit,
never a guess. A run folder belongs to one run: gisc clears a previous run's
artifacts, records what it cleared, and refuses any folder it did not write. The
clearing is undone if anything goes wrong — the previous run is set aside, not
deleted, and put back on any failure — so a run either replaces the last one
completely or leaves it exactly as it was.
Tasks: corridor.conflicts — what is inside N feet of an alignment.
alignment.crossings — where something crosses the centreline, as the point the
intersection makes, with its station. Ops:
read, reproject, buffer, intersect, sample, write, and nothing else.
Exit codes: 0 ok, 2 usage, 3 missing CRS, 4 adapter failed, 5 adapter stubbed.
Feet are ground feet. A projected CRS measures grid distance, so gisc measures the local scale factor empirically (a geodesic walk on WGS 84) and converts. In EPSG:3857 near 35.6°N that is 1.230, so a naive 15 ft buffer would cover 12.2 ft of real ground. Two things quietly give that back, so gisc handles both: a buffer is a polygon inscribed in the true circle, and at the usual 8 segments per quadrant a 15 ft corridor is 14.93 ft at the ends, so gisc picks the segment count from the tolerance and records the arc error it bought; and the scale factor is a property of a point, so over a long alignment one buffer distance cannot be right everywhere — gisc measures the drift along the extent and says what it costs in feet.
A station is not a distance. Stationing is measured in the alignment's native
design CRS, because a station is a grid distance in the system the drawing was made
in. And if the alignment carries <StaEquation> the stationing jumps: gisc applies
the equations, numbers the regions, and puts the raw stations beside them. Ignoring
one is the quietest way this format can make a tool wrong — the geometry stays
perfect, the offsets stay right, and every station past the equation is off by the
size of the equation. A gap and an overlap are both called out, and a feature that
straddles an equation is labelled with both regions, because across one the
displayed stations are no longer a length.
LandXML reads two subjects: <Alignment> for the centre line, <PipeNetwork>
for the utility — so Civil 3D storm goes straight into --utils without converting
first. Pipes become lines, structures points. Pipe geometry lives on the structures
a pipe names, so a pipe whose structure is missing from the file is left out and
named in provenance, never straight-lined between guesses. Diameters are reported as
written: real files carry inches under linearUnit="USSurveyFoot".
Alignments understand Line, Curve and Spiral. The spiral is the clothoid,
which is what a roadway transition is: gisc integrates the heading — exact in closed
form — and quadratures its sine and cosine, so one expression covers an entry spiral,
an exit spiral and a compound spiral between two finite radii. It then checks the
result against the <End> the file declares and refuses a spiral that does not land
on it, naming the rotation as the likely cause when reversing it would close. A
non-clothoid transition, a discontinuity, or a missing <CoordinateSystem> fails
loudly and names the element.
Stubbed: postgis and fema (NFHL) — both parse their input and fail with the
exact SQL or HTTP request they would issue.
Tested: 363 tests, 100% line coverage, enforced in CI. Four guards no input can
reach are marked pragma: no cover with the reason, rather than mocked into a
number. Plus acceptance checks against real tools.
Two alignments built in Autodesk Civil 3D 2023 over COM:
| Civil 3D vs gisc | |
|---|---|
| tangent–arc–tangent, length | −0.0025 ft over 1035 ft |
| tangent–arc–tangent, XY over 21 stations | worst 0.0095 ft |
| spiral–curve–spiral, length | −0.0020 ft over 985 ft |
| spiral–curve–spiral, XY over 40 stations | worst 0.0091 ft |
clothoid TotalX / TotalY |
~7e-11 ft |
| offset, 8 probes | worst 0.0073 ft |
| station across a station equation, 8 probes | worst 0.0300 ft |
Both sit inside the 0.01 ft chord tolerance the parser advertises. The clothoid
figures are the ones that say something: Civil 3D carries the spiral analytically
and publishes its own TotalX/TotalY, gisc integrates it from nothing but the
length and the two radii, and they agree to a ten-billionth of a foot — so what
error remains is chording, not the maths. See validation/README.md; committed
artifacts mean pytest -m civil3d needs no Civil 3D. A genuine LANDXMLOUT sheet
export and real <PipeNetwork> storm exports both parse, the latter correctly
refusing two pipes whose structures the export omitted.
Not exercised: a genuine LANDXMLOUT file containing a spiral or a station
equation. Both are now checked against Civil 3D's own geometry and its own equated
station strings, but the LandXML in that check was written by gisc from what Civil
3D reported over COM, because Civil 3D's LandXML export is a modal dialog with no COM
entry point. Element ordering and attribute spelling in a real export are covered
only by the LANDXMLOUT sheet export in the suite, which contains neither. Spiral
types other than the clothoid — bloss, sinusoidal, cosine, the cubics — are refused
by name rather than approximated.
Python ≥3.11, tested in CI on Linux and Windows against 3.11 and 3.12.
Regenerate fixtures with python fixtures/make_fixtures.py.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file gisc-0.3.1.tar.gz.
File metadata
- Download URL: gisc-0.3.1.tar.gz
- Upload date:
- Size: 80.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8c505fd398347819388baf0a02ef04ab1c22be36907c1fc2709ee20a56056710
|
|
| MD5 |
2c39f3bccd57a84aefcc26917eb45211
|
|
| BLAKE2b-256 |
55c0101b1714534c7e8253e4ff071c67bcad29c55f02e69da86aeef2d783983a
|
Provenance
The following attestation bundles were made for gisc-0.3.1.tar.gz:
Publisher:
publish.yml on mf4633/gisc
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
gisc-0.3.1.tar.gz -
Subject digest:
8c505fd398347819388baf0a02ef04ab1c22be36907c1fc2709ee20a56056710 - Sigstore transparency entry: 2811033534
- Sigstore integration time:
-
Permalink:
mf4633/gisc@d12897a7687a16b1da76e1c8e96762052966e7e1 -
Branch / Tag:
refs/tags/v0.3.1 - Owner: https://github.com/mf4633
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@d12897a7687a16b1da76e1c8e96762052966e7e1 -
Trigger Event:
release
-
Statement type:
File details
Details for the file gisc-0.3.1-py3-none-any.whl.
File metadata
- Download URL: gisc-0.3.1-py3-none-any.whl
- Upload date:
- Size: 47.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b8a6e69f77ba9f153a0cdcb6c0e967db48c536e79c837550965fbe7b216a9f9f
|
|
| MD5 |
d41bb2a36c5ad58c467e6862ffaccf15
|
|
| BLAKE2b-256 |
11fbf81b5ba92fbb72fd28521c688246b73164a48fa9484927387aee88396c04
|
Provenance
The following attestation bundles were made for gisc-0.3.1-py3-none-any.whl:
Publisher:
publish.yml on mf4633/gisc
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
gisc-0.3.1-py3-none-any.whl -
Subject digest:
b8a6e69f77ba9f153a0cdcb6c0e967db48c536e79c837550965fbe7b216a9f9f - Sigstore transparency entry: 2811033542
- Sigstore integration time:
-
Permalink:
mf4633/gisc@d12897a7687a16b1da76e1c8e96762052966e7e1 -
Branch / Tag:
refs/tags/v0.3.1 - Owner: https://github.com/mf4633
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@d12897a7687a16b1da76e1c8e96762052966e7e1 -
Trigger Event:
release
-
Statement type: