5.9 KiB
5.9 KiB
🗺 Parcel Subdivision Tool
A full-stack GIS application for automatic land parcel generation from user-drawn site boundaries and road networks.
Architecture
┌──────────────────────────────────────────────────┐
│ Docker Network │
│ │
│ ┌─────────────┐ ┌──────────────────────┐ │
│ │ Nginx │────▶│ FastAPI Backend │ │
│ │ (port 80) │ │ (port 8000) │ │
│ │ + Frontend │ │ Shapely/GIS engine │ │
│ └─────────────┘ └──────────────────────┘ │
└──────────────────────────────────────────────────┘
▲
│ :8080
Browser
(OpenLayers UI)
Features
| Feature | Description |
|---|---|
| Draw Boundary | Freehand polygon drawing on map |
| Draw Roads | Road centerline drawing (buffered to configured width) |
| Auto Road Grid | Automatic internal road generation if no roads drawn |
| Block Detection | Remaining buildable areas become blocks |
| Cul-de-sacs | Auto-generated for blocks exceeding max length |
| Parcel Subdivision | Rectangular parcel generation respecting min frontage/depth |
| Shape Optimization | Bad/small parcels absorbed by neighbors |
| Addressing | Auto address assignment per block/plot |
| GeoJSON Export | Download all results |
| Layer Controls | Toggle parcels, roads, blocks, cul-de-sacs |
| Hover Tooltips | Area, frontage, depth, address per parcel |
Default Parameters
min_frontage = 12 m
min_depth = 25 m
road_width = 9 m
max_block_length = 120 m
allow_culdesac = true
corner_radius = 3 m
Quick Start
Prerequisites
- Docker & Docker Compose installed
Run
# Clone / extract project
cd parcel-tool
# Build and start all services
docker compose up --build
# Access at:
http://localhost:8080
Stop
docker compose down
Usage Guide
Step 1 — Draw Boundary
- Click Draw Boundary in the toolbar
- Click on the map to add polygon vertices
- Double-click to finish the polygon
- Press Escape to cancel
Step 2 — (Optional) Draw Roads
- Click Draw Road
- Click to add road centerline vertices
- Double-click to finish
- Repeat for additional roads
If no roads are drawn, the engine auto-generates an internal road grid based on
max_block_length.
Step 3 — Configure Parameters
Adjust the configuration panel:
- Min Frontage — minimum plot road frontage
- Min Depth — minimum plot depth
- Road Width — road right-of-way width
- Max Block Length — triggers cul-de-sac or cross-road insertion
- Corner Radius — road intersection corner rounding
- Allow Cul-de-sacs — toggle cul-de-sac generation
Step 4 — Generate
Click ⚡ Generate Subdivision
Results appear color-coded:
- 🔵 Blue — parcels
- ⚫ Dark grey — roads
- 🟢 Green dashed — block boundaries
- 🟡 Yellow — cul-de-sacs
Step 5 — Inspect & Export
- Hover over parcels to see attributes
- Click parcels to highlight/select
- Export all data as GeoJSON
API Reference
POST /api/subdivide
{
"boundary": { /* GeoJSON Polygon */ },
"roads": [ /* GeoJSON LineStrings */ ],
"config": {
"min_frontage": 12,
"min_depth": 25,
"road_width": 9,
"max_block_length": 120,
"allow_culdesac": true,
"corner_radius": 3
}
}
Response:
{
"parcels": [ /* GeoJSON Features with properties */ ],
"roads": [ /* GeoJSON Features */ ],
"blocks": [ /* GeoJSON Features */ ],
"culdesacs": [ /* GeoJSON Features */ ],
"stats": {
"total_parcels": 42,
"total_blocks": 4,
"avg_parcel_area_m2": 340.5,
"culdesacs": 2
}
}
GET /api/health
Returns {"status": "ok"}
GET /api/config/defaults
Returns default configuration values.
Subdivision Algorithm
1. Parse boundary polygon (EPSG:4326 → WGS84)
2. Buffer user roads → road polygons
└─ If no roads: auto-generate grid roads at max_block_length intervals
3. Subtract roads from boundary → buildable blocks
4. For each oversized block (> max_block_length):
└─ Insert cul-de-sac if allow_culdesac=true
5. For each block:
a. Detect dominant orientation via OBB
b. Determine double/single frontage layout
c. Calculate parcel columns and rows
d. Clip each parcel cell to block boundary
6. Shape QC:
- Compactness check (reject triangular/complex shapes)
- Minimum area check
- Absorb rejected parcels into neighboring plots
7. Assign addresses: "Plot N, Block B Road"
8. Return GeoJSON FeatureCollection
Development
Backend (Python/FastAPI)
cd backend
pip install -r requirements.txt
uvicorn main:app --reload --port 8000
Frontend
Pure HTML/JS — just open frontend/index.html in a browser (update API_BASE to http://localhost:8000).
File Structure
parcel-tool/
├── docker-compose.yml
├── README.md
├── backend/
│ ├── Dockerfile
│ ├── requirements.txt
│ └── main.py ← Subdivision engine
├── frontend/
│ └── index.html ← OpenLayers UI
└── nginx/
└── nginx.conf ← Reverse proxy config
Notes
- The map uses CartoDB Dark Matter basemap (no API key needed)
- Coordinate system: EPSG:4326 (WGS84) for I/O, EPSG:3857 for display
- Geometry engine: Shapely 2.x with GEOS backend
- For large sites (>100ha), processing may take a few seconds