Begehbare 3D-Visualisierung des Gartens Egglihaldenstrasse 9a

Geometrie massstaeblich aus dem Gartenplan-PDF (1:100) extrahiert: Belaege,
Mauern, Pflanzenstandorte und 46 Hoehenkoten. Wohnhaus nach Gartenplan und
den Fassadenplaenen von EHLE Architekten.

- tools/: Pipeline PDF -> Szenenmodell (MuPDF, Node)
- src/: three.js-Szene mit prozeduralen Texturen, Rundgang und Uebersicht
- Docker/Traefik fuer garten.aicds.ch, Gitea-Workflow auf main

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-08 22:59:37 +02:00
co-authored by Claude Opus 5
commit 70d239fe9c
43 changed files with 5614 additions and 0 deletions
+165
View File
@@ -0,0 +1,165 @@
# Gartenvisualisierung Egglihaldenstrasse 9a
Begehbare 3D-Visualisierung des geplanten Gartens von Jasmin und Damian
Kellenberger, Egglihaldenstrasse 9a, 9030 Abtwil SG.
Live: **https://garten.aicds.ch**
Die gesamte Geometrie ist **massstäblich aus dem Gartenplan** abgeleitet – nicht
nachmodelliert. Ein Node-Werkzeug liest die Vektordaten direkt aus dem Plan-PDF,
rechnet sie in Meter um und erzeugt daraus das Szenenmodell.
---
## Grundlagen
| Quelle | Inhalt |
|---|---|
| `Info Dateien/Gartenplan 1 …pdf` | Garten Design AG, 14.08.2026, Massstab 1:100, A1 |
| `Info Dateien/20210427 - Projektpläne Haus 9a.pdf` | EHLE Architekten AG, Grundrisse, Fassaden, Umgebung |
| `Info Dateien/WhatsApp Image …jpeg` | Fotos des Ist-Zustands (Fassade, Beläge, Nachbarschaft) |
Die DWG wird nicht benötigt – das PDF enthält dieselbe Vektorgeometrie.
### Koordinatensystem
Alles rechnet im **Site-Frame**, in Metern:
- **X** – Hausachse ENE, Peilung 61.1615° gegen Nord
- **Z** – senkrecht dazu, SSE, Peilung 151.1615°
- **Y** – Höhe über dem Fixpunkt `0.00` = **651.17 m ü. M.** (OK Fertigboden EG)
Der Nordpfeil des Plans zeigt exakt zur Blattoberkante, das Zeichnungsraster
liegt um −28.8385° gedreht dazu. Der Massstab ist über das Plattenraster
verifiziert: die Keramikplatten messen sich auf 0.600 m genau.
### Höhen
| Bezug | relativ | absolut |
|---|---|---|
| Feuerwehrzufahrt, Nordwestecke | −2.08 | 648.09 m |
| Nachbargarten Zollet (Haus 9, OK FB EG) | −1.70 | 649.47 m |
| Hauptsitzplatz Travertin | −0.30 … −0.02 | 650.87 … 651.15 m |
| Fixpunkt Hauseingang | 0.00 | 651.17 m |
| Ostseite beim Apfelbaum | +0.63 | 651.80 m |
| OK Fertigboden Obergeschoss | +2.90 | 654.07 m |
| OK Attika Haus 9a | +6.15 | 657.32 m |
---
## Datenpipeline
```bash
npm run data # extract-plan + build-site
```
1. **`tools/extract-plan.mjs`** – öffnet das Plan-PDF mit MuPDF (WASM) und
protokolliert alle Zeichenoperationen mit. Ergebnis: rund 5400 Polygone,
234 Pflanzenkreise, 229 Beschriftungen und 46 Höhenkoten, transformiert in
den Site-Frame. → `tools/out/plan-raw.json`
2. **`tools/authoring.mjs`** – handgepflegte Ergänzungen: Zuordnung der
Planfarben zu Belagsarten, Mauerachsen und -höhen, Gebäudekubatur,
Geländezonen, Standorte. Alles kommentiert und auf Plan oder
Architekturpläne zurückgeführt.
3. **`tools/build-site.mjs`** – klassiert die Flächen, leitet Pflanzen und
Leuchten ab, interpoliert das Geländeraster (0.25 m) aus den Höhenkoten je
Zone und schreibt `public/data/site.json` (rund 110 kB).
Zur Kontrolle: `node tools/debug-svg.mjs` zeichnet die extrahierte Geometrie als
SVG-Draufsicht, `node tools/inspect-colors.mjs` listet die Planfarben mit den
nächstgelegenen Beschriftungen.
### Warum Zonen statt eines einzigen Geländes
Das Grundstück fällt über rund 3.5 m ab, die Sprünge liegen aber nicht im
Gelände, sondern in den Stützbauten: Travertinmauer zum Nachbargrundstück,
Winkelelemente aus Beton entlang der Feuerwehrzufahrt, Betonmauer im Süden.
Deshalb wird je Zone getrennt interpoliert – über die Zonengrenze hinweg nie.
Die Mauern erhalten ihr Kronen- und Fussprofil aus dem Gelände beider Seiten.
---
## Anwendung
```bash
npm install
npm run dev # http://localhost:5173
npm run build # dist/, rund 640 kB
```
Stack: Vite + TypeScript + three.js. **Keine externen Assets** – sämtliche
Texturen (Travertin, Keramik, Tegula, Rasen, Kies, Beton, Holzschalung,
Scheiterwand) werden zur Laufzeit prozedural auf ein Canvas gezeichnet. Die UVs
sind weltbezogen, damit die Plattenraster über Flächengrenzen hinweg durchlaufen
– so wie auf dem Plan.
### Bedienung
| | |
|---|---|
| Rundgang | Klicken, dann `W` `A` `S` `D`, `Shift` zum Rennen, `Esc` gibt die Maus frei |
| Handy | links Joystick, rechts wischen zum Umsehen |
| Übersicht | ziehen zum Drehen, Mausrad zum Zoomen |
| Tageszeit | Regler oben rechts, Sonnenstand astronomisch für Abtwil SG gerechnet |
Der Rundgang folgt dem Gelände, steigt Stufen bis 45 cm und wird von Mauern,
Gebäuden, Hecken und Objekten aufgehalten. Ab Dämmerung schalten die 17 Leuchten
des Plans automatisch ein.
### Aufbau
```
src/
site.ts Datenmodell und Höhen-Sampler
scene/textures.ts prozedurale Beläge und Materialien
scene/geometry.ts Polygone auf das Gelände legen, Mauern extrudieren
scene/terrain.ts Geländeraster und Umland
scene/surfaces.ts Beläge
scene/structures.ts Mauern, Stelen, Objekte, Leuchten
scene/vegetation.ts Gehölze, Hecken, Gräser, Stauden
scene/building.ts Wohnhaus 9a und Nachbargebäude
scene/environment.ts Himmel, Sonnenstand, Licht
controls/walker.ts Begehen mit Kollision und Geländeführung
ui/hud.ts Bedienoberfläche
```
---
## Deployment
Push auf `main` löst den Gitea-Workflow aus; die App landet unter
`/opt/aicds/apps/Gartenvisualisierung/` und wird per `docker compose` gebaut.
Traefik-Router `garten`, Host `garten.aicds.ch`, Netzwerk `agent-net`.
```bash
docker compose config # Prüfung vor dem Push
docker compose up -d --build
```
Das Image enthält nur `dist/` hinter nginx – die Planunterlagen und Fotos aus
`Info Dateien/` werden über `.dockerignore` ausgeschlossen und gelangen nie in
den Webcontainer.
---
## Was bewusst interpretiert ist
Der Plan ist ein Situationsplan; einiges steht nur als Beschriftung darin. Diese
Annahmen stecken in `tools/authoring.mjs` und sind dort einzeln kommentiert:
- **Mauerhöhen** aus den Höhenkoten beidseits abgeleitet; die gelbe Kote `25`
bei der Sitzmauer als 25 cm Aufkantung gelesen, `35` bei den Heidelbeeren
analog.
- **Lamellenwand zum Sitzen** als senkrechte Holzlamellen im Planrhythmus
(10 cm breit, 35 cm tief, rund 90 cm Achsabstand), passend zum Foto des
Ist-Zustands.
- **Wohnhaus** in Kubatur und Öffnungen nach Gartenplan und Fassadenplänen,
Materialisierung nach den Fotos: vertikale Holzschalung graubraun, heller
Betonsockel, Flachdach mit extensiver Begrünung.
- **Nachbarhaus Zollet** als einfaches Kontextvolumen, 1.70 m tiefer liegend.
- **Solitärgehölze** mit den Kronenradien des Plans; Wuchshöhen als
Erfahrungswerte.
- **Gartenhaus, Spielhaus, Flammengrill, Bänkli** in Lage und Grundfläche nach
Plan, in der Ausformulierung frei.