# πŸ—Ί 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