135 lines
3.4 KiB
Python
135 lines
3.4 KiB
Python
"""
|
|
PlantPlan FastAPI Backend
|
|
- Symbolbibliothek ausliefern
|
|
- Koordinaten normalisieren
|
|
- JSON/SVG Export
|
|
- Shape-Änderungen empfangen (Puffer + Kreisel)
|
|
"""
|
|
|
|
import json
|
|
from pathlib import Path
|
|
from fastapi import FastAPI
|
|
from fastapi.middleware.cors import CORSMiddleware
|
|
from pydantic import BaseModel
|
|
|
|
app = FastAPI(title="PlantPlan API")
|
|
|
|
# CORS: Erlaubt Zugriff vom lokalen Frontend Dev-Server
|
|
app.add_middleware(
|
|
CORSMiddleware,
|
|
allow_origins=["http://localhost:5173"],
|
|
allow_methods=["*"],
|
|
allow_headers=["*"],
|
|
)
|
|
|
|
CATALOG_DIR = Path(__file__).parent / "catalog"
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Pydantic Models
|
|
# ---------------------------------------------------------------------------
|
|
|
|
class SketchPayload(BaseModel):
|
|
shapes: list[dict]
|
|
grid_size: int = 10
|
|
|
|
|
|
class PufferUpdate(BaseModel):
|
|
"""Puffer-Symbol: Rechteck mit Breite und Höhe."""
|
|
id: str
|
|
x: float
|
|
y: float
|
|
w: float # Breite
|
|
h: float # Höhe
|
|
|
|
|
|
class KreiselUpdate(BaseModel):
|
|
"""Kreisel-Symbol: Zwei Kreise mit Abstand und Radius."""
|
|
id: str
|
|
x: float
|
|
y: float
|
|
abstand: float # Abstand zwischen den Kreismittelpunkten
|
|
radius: float # Radius beider Kreise
|
|
|
|
|
|
class ShapeUpdatePayload(BaseModel):
|
|
"""Payload für Shape-Änderungen vom Client."""
|
|
puffer: list[PufferUpdate] = []
|
|
kreisel: list[KreiselUpdate] = []
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Endpoints
|
|
# ---------------------------------------------------------------------------
|
|
|
|
@app.get("/symbols")
|
|
async def get_symbols():
|
|
"""Symbolbibliothek als JSON ausliefern."""
|
|
catalog_file = CATALOG_DIR / "symbols.json"
|
|
with open(catalog_file, encoding="utf-8") as f:
|
|
return json.load(f)
|
|
|
|
|
|
@app.post("/normalize")
|
|
async def normalize(payload: SketchPayload):
|
|
"""Koordinaten auf Grid snappen und SVG-Pfade normalisieren."""
|
|
cleaned = []
|
|
for shape in payload.shapes:
|
|
s = dict(shape)
|
|
if "x" in s:
|
|
s["x"] = round(s["x"] / payload.grid_size) * payload.grid_size
|
|
if "y" in s:
|
|
s["y"] = round(s["y"] / payload.grid_size) * payload.grid_size
|
|
cleaned.append(s)
|
|
return {"shapes": cleaned}
|
|
|
|
|
|
@app.post("/export")
|
|
async def export_sketch(payload: SketchPayload):
|
|
"""Finales Projektfile als JSON exportieren."""
|
|
return {
|
|
"json": {
|
|
"version": "1.0",
|
|
"shapes": payload.shapes,
|
|
}
|
|
}
|
|
|
|
|
|
@app.post("/shapes/update")
|
|
async def update_shapes(payload: ShapeUpdatePayload):
|
|
"""
|
|
Shape-Änderungen vom Client empfangen.
|
|
|
|
Gibt für jeden Puffer Breite/Höhe und für jeden Kreisel
|
|
Abstand/Radius + berechnete Gesamtlänge zurück.
|
|
"""
|
|
result = {
|
|
"received": {
|
|
"puffer_count": len(payload.puffer),
|
|
"kreisel_count": len(payload.kreisel),
|
|
},
|
|
"puffer": [],
|
|
"kreisel": [],
|
|
}
|
|
|
|
for p in payload.puffer:
|
|
result["puffer"].append({
|
|
"id": p.id,
|
|
"x": p.x,
|
|
"y": p.y,
|
|
"breite": p.w,
|
|
"hoehe": p.h,
|
|
})
|
|
|
|
for k in payload.kreisel:
|
|
result["kreisel"].append({
|
|
"id": k.id,
|
|
"x": k.x,
|
|
"y": k.y,
|
|
"abstand": k.abstand,
|
|
"radius": k.radius,
|
|
"gesamtlaenge": 2 * k.radius + k.abstand,
|
|
})
|
|
|
|
return result
|