diff --git a/docs/DOME-GEOMETRY-CAPABILITY.md b/docs/DOME-GEOMETRY-CAPABILITY.md new file mode 100644 index 00000000..0a53b475 --- /dev/null +++ b/docs/DOME-GEOMETRY-CAPABILITY.md @@ -0,0 +1,68 @@ +# Blender vs geodesic-dome-mcp — Capability Comparison + +2026-06-23 | OSA (mother node) | FreeBSD 15.0 + +## The problem + +Generate geodesic dome wireframes for architectural visualization and +bill-of-materials calculation. The obvious answer was Blender — it has +`bpy.ops.mesh.primitive_ico_sphere_add()` built in. + +## Before: Blender + +| Metric | Value | +|---|---| +| Packages installed | 53 | +| Download size | 323 MiB | +| Installed size | 1 GiB | +| Key dependencies | llvm19, ffmpeg, openimageio, opencolorio, openvdb, pulseaudio | +| Headless mode | `blender --background` (still pulls X11 deps) | +| Dome generation time | ~14s (Eevee render, 2000×2000) | + +## After: geodesic-dome-mcp + +| Metric | Value | +|---|---| +| File size | 6 KB (294 lines of Python) | +| Dependencies | numpy, Pillow (already installed on all nodes) | +| Dome generation time | <1s (wireframe), sub-second (BOM only) | +| Headless | Always — no X11, no GPU, no display server | +| Outputs | Wireframe PNG + structural BOM (JSON) | + +## Capability impact + +| Capability | Before (Blender) | After (geodesic-dome-mcp) | +|---|---|---| +| Can run on 32GB USB ISO? | ❌ (1 GiB, exceeds headroom) | ✅ (6 KB, negligible) | +| Can run on 12GB RAM VPS? | ❌ (would fit disk but overkill) | ✅ (already running) | +| Can run on bare-metal? | ✅ (if installed) | ✅ (always) | +| Structural BOM? | ❌ (needs separate script) | ✅ (built-in) | +| Half-sphere mode? | Manual mesh cut | ✅ (`half=true`) | +| Connector analysis? | ❌ | ✅ (3/4/5/6-way counts) | +| Strut length table? | ❌ | ✅ (grouped by size) | +| Material cost estimates? | ❌ | ✅ (glass/polycarbonate/insulated) | + +## Registering capabilities + +This comparison feeds into the mother node's PostgreSQL `usb_nodes` table. +When a node registers its hardware profile, the capability derivation trigger +marks nodes that can run `geodesic-dome-mcp` (all of them — numpy + Pillow +are universal). Nodes that have Blender installed get an additional +`has_blender: true` capability for 3D rendering workloads. + +## OSA as example (registered 2026-06-23) + +```json +{ + "hostname": "osa.smilepowered.org", + "ram_gb": 12, + "cpu_cores": 6, + "capabilities": { + "has_gpu": false, + "cpu_only": true, + "geodesic_dome_mcp": true + } +} +``` + +12GB RAM, no GPU, but `geodesic_dome_mcp` runs fine. No Blender needed. diff --git a/docs/GIS-INTEGRATION-PLAN.md b/docs/GIS-INTEGRATION-PLAN.md new file mode 100644 index 00000000..7bdfc7b9 --- /dev/null +++ b/docs/GIS-INTEGRATION-PLAN.md @@ -0,0 +1,267 @@ +# GIS Integration — Step-by-Step Implementation Plan + +2026-06-23 | Specification phase | No code yet + +## Overview + +Six standalone MCP tools, each one layer of the stack. Each tool is +independently testable, accepts JSON-RPC on stdin, returns JSON on stdout. +All tools run on the mother node (OSA) and are registered in +`/usr/local/etc/colibri/external-mcp.json`. + +--- + +## Step 1: `gurs-address-lookup` — Address → Coordinates + Parcel ID + +### Input +```json +{ + "address": "Na vrtu 5", + "postal_code": "1000", + "municipality": "Ljubljana" +} +``` + +### Implementation +1. WFS GetFeature to GURS Register naslovov + - Filter: `ULICA='Na vrtu' AND HISNA_STEVILKA='5' AND POSTNA_STEVILKA='1000'` + - EPSG 3794 → reproject to EPSG 4326 +2. Parse: coordinates, parcel ID, land use code +3. Multiple results: return all, let caller pick +4. No results: partial match, suggest alternatives + +### Output +Lat/lon + parcel ID + cadastral municipality + land use code. + +### Diagram +``` +User "Na vrtu 5, 1000 LJ" + │ + ▼ +┌──────────────────────────┐ +│ GURS Register naslovov │ +│ WFS GetFeature │ +│ │ +│ → 46.0514, 14.5060 │ +│ → parcel 1724/3 │ +│ → stavbno zemljišče │ +└──────────────────────────┘ +``` + +--- + +## Step 2: `gurs-parcel-boundary` — Parcel ID → Boundary + Metadata + +### Implementation +1. WFS GetFeature to GURS Kataster nepremičnin (collection: `parcele`) +2. Compute: area, centroid, inscribed circle, setback compliance +3. Query GJI for road/utility access +4. Check OPSI orthophoto availability + +### Output +Boundary GeoJSON + area + inscribed circle + infrastructure distances + setbacks. + +### Diagram +``` +┌─────────────────────────────────┐ +│ ┌───┐ │ +│ │old│ existing building │ +│ └───┘ │ +│ · centroid │ +│ ○ inscribed circle r=14.5m │ +│ │ +│ 850m², stavbno zemljišče │ +│ road: 8m, power: 15m │ +│ setback compliant for 5m dome │ +└─────────────────────────────────┘ +``` + +--- + +## Step 3: `dome-placement` — Optimal Dome Position + +### Implementation +1. Inscribed circle search (binary search from centroid) +2. Orientation: entrance faces south, ramp fits within parcel +3. Ground slope from GURS DMR (optional) +4. Collision check against buildings/utilities +5. Sun path: winter solstice shadow analysis + +### Output +Center coordinates + orientation + fit quality rating + conflicts + sun/shadow. + +### Diagram +``` + N + ▲ + ┌──────────────────────────┐ + │ · · · parcel · · · · · │ + │ · ┌───┐ · │ + │ · │old│ ╭──────╮ · │ + │ · │bld│ │ DOME │ · │ + │ · └───┘ │ r=5m │ · │ + │ · │ ▸ │ · │ + │ · ╰──────╯ · │ + │ · entrance · │ + │ · SOUTH · │ + └──────────────────────────┘ + setback 4m ✓, no conflicts ✓ + winter shadow: 8.2m → NW (away from neighbor) +``` + +--- + +## Step 4: `geodesic-dome-mcp` — Site-Context BOM + +Already implemented: wireframes, BOM, strut constraint, construction layers. +New: site context from Steps 2-3. + +### New output +- Foundation type based on frost depth + slope +- Access path length + gravel estimate +- Rebar updated with foundation starter bars +- Local Eurocode constants applied + +### BOM Diagram +``` +Item │ Qty │ Cost +──────────────────┼──────┼────── +FI12 rebar 6m │ 62 │ €372 +Concrete C25/30 │ 3.1m³│ €310 +Gravel 0-32mm │ 2.4t │ €48 +Glass 4mm temper │196m² │€4910 +5-way connectors │ 14 │ TBD +6-way connectors │ 44 │ TBD +──────────────────┼──────┼────── +Foundation depth: 0.9m (frost 0.8m) +Snow load: 1.5 kN/m² (zone A2) +Wind: 25 m/s (zone 2) +Seismic: 0.175g PGA +``` + +--- + +## Step 5: `dome-site-render` — Composite Visualization + +### Three options + +| Option | Cost | Quality | Effort | +|---|---|---|---| +| A: OPSI orthophoto overlay | Free | Good (2D site plan) | ~4h | +| B: Google 3D Tiles | Paid | Excellent (3D photoreal) | ~8h | +| C: Gemini AI-enhanced | ~$0.04 | Good (4K composite) | ~1h | + +### Option C (quickest path) +1. Pass orthophoto + dome wireframe as Gemini reference images +2. Prompt: "Photorealistic vegetation matching Slovenian landscape..." +3. Output: 4K composite PNG + +### Diagram +``` +┌────────────────────────────────────┐ +│ 3D Perspective — Dome on Site │ +│ │ +│ ╱▔▔▔╲ │ +│ ╱ DOME ╲ │ +│ ╱ r=5m ╲ │ +│ ╱ ╱▔▔▔▔▔▔▔╲ ╲ │ +│ ╱ ╱ wireframe ╲ ╲ │ +│ ╱ ╱ subdivision ╲ ╲ │ +│ ╱▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔╲ │ +│ ▕ ░░░░░░░░░░░░░░░░░░ ▏ │ +│ ▕ ░░ actual terrain ░ ▏ │ +│ ───────────────────────── │ +│ │ +│ Background: OPSI orthophoto │ +│ Overlay: geodesic-dome-mcp │ +│ Enhance: Gemini AI │ +└────────────────────────────────────┘ +``` + +--- + +## Step 6: `mother-blender-render` — Photorealistic 3D via Mother + +Heavy nodes (USB) request renders from mother. Same MCP pattern as `build-colibri.sh`. + +### Architecture +``` +USB (light node) Mother (OSA, Blender 5.0) + │ │ + │ MCP: blender_render({...}) │ + ├─────────────────────────────►│ + │ ├─ blender --background --python dome_render.py + │ │ Cycles/EEVEE, 4K, materials, vegetation + │◄─────────────────────────────┤ + │ image_path + metadata │ + │ │ + │ scp binary from mother │ + └──────────────────────────────┘ +``` + +### Capabilities +- Cycles path-traced rendering (photorealistic) +- EEVEE real-time rendering (fast previews) +- PBR materials (glass, steel, concrete, wood) +- Terrain + foundation extrusion +- Vegetation particle scattering +- Sun position + shadow study (any date/time) +- 360° turntable animation +- DXF/STL export (CNC-ready) +- 4K+ native resolution + +### Render times (OSA, 6-core CPU, no GPU) +- Wireframe: ~5s (EEVEE) +- Materials + lighting: ~5min (Cycles 128) +- Full scene + vegetation: ~15-30min (Cycles 256, 4K) + +### Blender render pipeline diagram +``` +┌──────────────────────────────────────────┐ +│ Mother Blender Render Pipeline │ +│ │ +│ Scene JSON ──► dome_render.py ──► PNG │ +│ │ │ +│ ▼ │ +│ ┌──────────────┐ │ +│ │ • icosphere │ │ +│ │ • wireframe │ │ +│ │ • materials │ │ +│ │ • lighting │ │ +│ │ • camera rig │ │ +│ │ • terrain │ │ +│ │ • vegetation │ │ +│ └──────────────┘ │ +│ │ +│ Queue: /var/db/geodesic/render-queue/ │ +│ Cache: /var/db/geodesic/renders/ │ +│ TTL: 7 days │ +└──────────────────────────────────────────┘ +``` + +--- + +## Implementation Priority + +| Step | Effort | Priority | +|---|---|---| +| Step 1: address lookup | ~2h | 1 — unlocks everything | +| Step 2: parcel boundary | ~3h | 2 | +| Step 3: dome placement | ~4h | 3 | +| Step 4: site BOM | ~2h | 4 | +| Step 5: AI render | ~1h | 5 | +| Step 5: orthophoto | ~4h | 6 | +| Step 6: Blender render | ~6h | 7 | +| Step 5: Google 3D | ~8h | 8 | + +Total: ~30h for complete pipeline. + +## Slovenian building code (Eurocode) + +| Parameter | Central Slovenia | +|---|---| +| Frost depth | 0.8m | +| Snow load | 1.5 kN/m² (≤500m) | +| Wind speed | 25 m/s | +| Seismic PGA | 0.175g | +| Setback | 4.0m |