ParcelToolv4/README.md
2026-03-03 11:33:31 +03:00

227 lines
5.9 KiB
Markdown

# 🗺 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
```bash
# Clone / extract project
cd parcel-tool
# Build and start all services
docker compose up --build
# Access at:
http://localhost:8080
```
### Stop
```bash
docker compose down
```
---
## Usage Guide
### Step 1 — Draw Boundary
1. Click **Draw Boundary** in the toolbar
2. Click on the map to add polygon vertices
3. **Double-click** to finish the polygon
4. Press **Escape** to cancel
### Step 2 — (Optional) Draw Roads
1. Click **Draw Road**
2. Click to add road centerline vertices
3. Double-click to finish
4. 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`
```json
{
"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:**
```json
{
"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)
```bash
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