How to Define Topology Rules for Cadastral Maps
Cadastral parcel data underpins land registration, taxation, and boundary adjudication. Even minor geometry errors — a 2 mm overlap, a missing shared edge — can invalidate a legal transaction or trigger costly re-surveys. This guide walks through the full process of selecting, configuring, and running topology rules against cadastral datasets, drawing on the OGC topology rule framework that formalises spatial predicates for automated validation.
The workflow applies to any team ingesting cadastral submissions into a PostGIS or GeoPackage environment and needing to enforce spatial integrity before publication.
Prerequisites
Before defining rules, confirm the following conditions so the predicates produce deterministic results:
- PostGIS 3.2+ or GDAL 3.4+ installed and accessible. Earlier PostGIS versions lack reliable
ST_Snapbehaviour andST_IsValidDetailoutput. - Single projected Coordinate Reference System (CRS). All parcel layers must share one metric CRS — a national grid or UTM zone. Coordinate Reference System precision standards explains how to choose and enforce the correct projection before validation begins.
- Pre-validated single-part geometries. Run geometry validity checks to eliminate self-intersections and unclosed rings before topology evaluation. Topology predicates applied to already-invalid geometries produce misleading results.
- Consistent attribute schema. Parcel identifiers (
parcel_id,tax_lot) must be populated and typed correctly. Review attribute schema mapping for spatial datasets if incoming submissions use inconsistent field naming. - Agreed-upon tolerance values. Obtain these from the survey authority or project specification before writing any SQL — they cannot be changed post-hoc without re-running the entire validation job.
Core Cadastral Topology Rules
Cadastral systems require planar enforcement: geographic coordinate topology breaks down because angular distortion changes apparent distances and areas. The standard rule set covers five constraint classes:
Step-by-Step Procedure
1. Standardize Input Data
Convert all source files to a single format and CRS before writing any topology logic. Legacy CAD, Shapefile, and DWG sources routinely carry mixed or undefined projections:
-- Verify all parcels share the same SRID
SELECT DISTINCT ST_SRID(geom), COUNT(*) AS cnt
FROM parcels
GROUP BY ST_SRID(geom);
-- Expected: one row, your agreed metric SRID (e.g. 32633)
If multiple SRIDs are present, reproject before proceeding:
-- Reproject to EPSG:32633 (UTM zone 33N) in place
ALTER TABLE parcels
ALTER COLUMN geom TYPE geometry(Polygon, 32633)
USING ST_Transform(geom, 32633);
Verification: Re-run the SRID query — it must return exactly one row.
2. Configure Tolerance and Pre-snap Vertices
Snap tolerance must be set before validation, not used as a filter afterwards. Apply ST_Snap to collapse micro-gaps introduced by digitising or coordinate conversion:
-- Snap vertices within 0.003 m to eliminate digitising drift
UPDATE parcels
SET geom = ST_Snap(geom, ST_Union(geom) OVER (), 0.003)
WHERE block_id = 'BLK_04';
Use these thresholds as a starting point and adjust to your survey specification:
| Survey Method | Snap Tolerance | Validation Tolerance |
|---|---|---|
| GPS RTK / Total Station | 0.001 m | 0.005 m |
| Aerial photogrammetry | 0.003 m | 0.01 m |
| Digitised from paper maps | 0.005 m | 0.02 m |
Verification: Run SELECT MAX(ST_Distance(ST_Boundary(a.geom), ST_Boundary(b.geom))) FROM parcels a JOIN parcels b ON ST_DWithin(a.geom, b.geom, 0.05) AND a.parcel_id <> b.parcel_id — the result must be below your validation tolerance.
3. Create the Audit Table
Route all violations to a dedicated audit table rather than modifying source data. This preserves the original geometry for manual review and supports audit trails required by land-registry compliance frameworks:
CREATE TABLE IF NOT EXISTS cadastral_violations (
violation_id SERIAL PRIMARY KEY,
rule_name TEXT NOT NULL,
parcel_id_a TEXT,
parcel_id_b TEXT,
violation_geom GEOMETRY,
severity TEXT DEFAULT 'critical',
logged_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX ON cadastral_violations USING GIST (violation_geom);
4. Run Overlap and Gap Detection
These two queries implement the highest-priority rules. Wrap them in a transaction so both succeed or neither is committed:
BEGIN;
-- Rule: Must Not Overlap
INSERT INTO cadastral_violations (rule_name, parcel_id_a, parcel_id_b, violation_geom, severity)
SELECT
'MUST_NOT_OVERLAP',
a.parcel_id,
b.parcel_id,
ST_Intersection(a.geom, b.geom),
'critical'
FROM parcels a
JOIN parcels b
ON ST_Intersects(a.geom, b.geom)
AND a.parcel_id < b.parcel_id -- avoid symmetric duplicates
AND ST_Area(ST_Intersection(a.geom, b.geom)) > 0.0001; -- ε = 1 cm²
-- Rule: Must Not Have Gaps (within a cadastral block)
WITH block_union AS (
SELECT block_id, ST_Union(geom) AS merged FROM parcels GROUP BY block_id
),
block_hull AS (
SELECT block_id, ST_ConvexHull(merged) AS hull, merged FROM block_union
)
INSERT INTO cadastral_violations (rule_name, parcel_id_a, violation_geom, severity)
SELECT
'MUST_NOT_HAVE_GAPS',
bh.block_id,
ST_Difference(bh.hull, bh.merged),
'warning'
FROM block_hull bh
WHERE ST_Area(ST_Difference(bh.hull, bh.merged)) > 0.01; -- gaps > 10 cm²
COMMIT;
Verification: SELECT rule_name, COUNT(*) FROM cadastral_violations GROUP BY rule_name; — a clean dataset returns 0 rows for both rules.
5. Enforce Boundary Coincidence and Attribute Integrity
Shared edges must align within tolerance, and every parcel must carry a unique, non-null identifier:
-- Boundary coincidence check: flag pairs whose shared boundary deviates beyond tolerance
INSERT INTO cadastral_violations (rule_name, parcel_id_a, parcel_id_b, violation_geom, severity)
SELECT
'BOUNDARY_NOT_COINCIDENT',
a.parcel_id,
b.parcel_id,
ST_ClosestPoint(ST_Boundary(a.geom), ST_Boundary(b.geom)),
'critical'
FROM parcels a
JOIN parcels b
ON ST_DWithin(a.geom, b.geom, 0.05)
AND a.parcel_id < b.parcel_id
WHERE ST_Distance(ST_Boundary(a.geom), ST_Boundary(b.geom)) BETWEEN 0.005 AND 0.05;
-- Attribute integrity: duplicate or null parcel IDs
INSERT INTO cadastral_violations (rule_name, parcel_id_a, severity)
SELECT 'DUPLICATE_OR_NULL_ID', parcel_id, 'critical'
FROM parcels
WHERE parcel_id IS NULL
OR parcel_id IN (
SELECT parcel_id FROM parcels GROUP BY parcel_id HAVING COUNT(*) > 1
);
Verification: Both inserts should affect 0 rows on a compliant dataset.
Interpreting Results
Query the audit table to triage the violation set before remediation:
SELECT
rule_name,
severity,
COUNT(*) AS violation_count,
ROUND(SUM(ST_Area(violation_geom))::numeric, 4) AS total_area_m2
FROM cadastral_violations
GROUP BY rule_name, severity
ORDER BY severity, violation_count DESC;
Use this output to decide remediation priority. Critical violations (MUST_NOT_OVERLAP, DUPLICATE_OR_NULL_ID) must be resolved before the dataset can be published. Warning violations (MUST_NOT_HAVE_GAPS) can be triaged against known block boundaries — some may be intentional public rights-of-way rather than data errors.
For teams who need to classify violations beyond overlap/gap, the categorizing and prioritizing spatial errors workflow provides a composable severity model that integrates with this audit table pattern.
Gotchas and Edge Cases
- ConvexHull gap detection produces false positives for irregular blocks. Replace
ST_ConvexHullwith a surveyed block boundary polygon from a reference layer when one is available. The convex hull approach over-estimates expected coverage for L-shaped or re-entrant block geometries. - ST_Snap changes geometry permanently. Always operate on a staging copy of the parcel table, never the production dataset. Snap drift compounds across iterations if applied repeatedly without resetting to the authoritative source.
- Symmetric duplicate suppression (
a.parcel_id < b.parcel_id) fails on null IDs. Null identifiers compare as unequal under SQL three-valued logic, so the filter does not exclude null-vs-null pairs. Handle nulls in a separate pass (see Step 5 above). - WGS 84 (EPSG:4326) area thresholds are in degrees-squared, not square metres. Every area constant in the queries above (
0.0001,0.01) assumes metric units. The ISO 19107 Spatial Schema and the OGC Simple Features specification both define area operations on a planar (projected) coordinate system. - Sliver polygons survive gap detection. A parcel narrower than your snap tolerance but longer than your minimum area threshold passes all checks. Add an explicit aspect-ratio or minimum-width check (
ST_MinimumClearance(geom) < 0.05) to catch needle-like slivers from misaligned boundary edits.
When to Escalate
This PostGIS-based procedure handles datasets up to roughly 500 000 parcels on a single node before query times exceed practical batch windows. Escalate to a different approach when:
- Feature count exceeds 500 k: Move overlap detection to a distributed spatial engine such as Apache Sedona on Spark, which can partition the parcel layer by block or grid cell and run pairwise checks in parallel.
- Submissions arrive continuously: Replace the batch SQL pattern with an asynchronous validation workflow using Celery or a message queue. Each new submission triggers a scoped validation job rather than a full-table scan.
- Multiple jurisdictions share one schema: The building rule engines with GeoPandas approach lets you declare per-jurisdiction tolerance profiles in a configuration file and apply them dynamically, avoiding hard-coded threshold constants in SQL.
- Audit trail must survive schema migrations: Embed topology validation into your data governance framework — defining spatial data quality policies covers how to version rule catalogs and link violation records to policy documents for regulatory review.
Frequently Asked Questions
What snap tolerance should I use for cadastral topology?
Use 0.001 m–0.005 m for GPS RTK or total station surveys, and 0.005 m–0.01 m for older digitised boundaries. Apply ST_Snap before running topology predicates; tolerance is a pre-processing step, not a filter applied after the fact.
Can I run cadastral topology checks on WGS 84 coordinates?
No. Geographic coordinates introduce angular distortion that breaks metric predicates such as ST_Area and ST_Distance. Always project to a local metric CRS before validation.
When should I block publication versus flag for manual review?
Block publication for overlaps and missing parcel identifiers — these prevent legal registration. Flag for manual review when gap area is below your validation tolerance, or when only metadata attributes are inconsistent.
Related
- Understanding OGC Topology Rules — the spatial predicate framework underlying every rule in this guide
- Geometry Validity Checks for Vector Data — run these before topology validation to ensure clean inputs
- Coordinate Reference System Precision Standards — projection and tolerance guidance for metric enforcement
- Categorizing and Prioritizing Spatial Errors — integrate the audit table output into a broader severity classification model
Back to Understanding OGC Topology Rules