0cfddd8930
Neuer GPU-Renderer fuer den Grundriss (src/plan/glPlan/): Earcut-Tessellierung (konkav-faehig), gehrte Linienzuege (Miter), echte Papier-mm-Strichbreiten im Massstab (repliziert den SVG-printStrokeVb-Pfad), Hybrid mit scharfem SVG-Text- Overlay. GPU ist der Standardpfad; der SVG-Renderer bleibt automatischer Fallback, falls WebGL2/Shader nicht verfuegbar sind. Imperativer Pan (rAF + CSS-transform) fuer fluessige Interaktion ohne React-Re-Render je Frame. Enthaelt zudem den bisher nicht committeten Arbeitsstand des Browser-BIM (Oeffnungen, Treppen, Raeume, Decken, DXF-Export, Materialbibliothek, Kontext- Import, Tauri-Compute-Boundary-PoC).
111 lines
3.7 KiB
TypeScript
111 lines
3.7 KiB
TypeScript
// Gemeinsame Typen + Helfer für den Standort-Import (swisstopo & OSM).
|
|
//
|
|
// Beide Quellen liefern am Ende dasselbe: geschlossene/offene Polylinien in
|
|
// LOKALEN Modell-Metern (bereits um die Origin verschoben, siehe lv95.ts),
|
|
// kategorisiert nach Art (Gebäude/Strasse/Wasser/Grün). Die UI wandelt diese in
|
|
// `ContourSet`-Kontext-Objekte pro Kategorie um und legt sie in `project.context`.
|
|
//
|
|
// Bezeichner englisch, Kommentare deutsch (CONVENTIONS.md).
|
|
|
|
import type { GeoOrigin } from "./lv95";
|
|
import type { ContextObject, Contour } from "../model/types";
|
|
|
|
/** Fachliche Kategorie einer importierten Kontext-Linie. */
|
|
export type GeoCategory = "building" | "road" | "water" | "green";
|
|
|
|
/** Ein importiertes Polygon/Polylinie in lokalen Modell-Metern. */
|
|
export interface GeoFeature {
|
|
category: GeoCategory;
|
|
/** Stützpunkte in lokalen Metern (x=Ost, y=Nord). */
|
|
pts: { x: number; y: number }[];
|
|
/** Geschlossener Ring (Gebäude/Wasser/Grün) vs. offene Linie (Strasse). */
|
|
closed: boolean;
|
|
}
|
|
|
|
/** Ergebnis eines Import-Laufs: Features + verwendete Origin. */
|
|
export interface GeoImportResult {
|
|
origin: GeoOrigin;
|
|
features: GeoFeature[];
|
|
}
|
|
|
|
/** Menschlicher Layer-/Objektname je Kategorie (deutsch, für die Kontext-Liste). */
|
|
const CATEGORY_LABEL: Record<GeoCategory, string> = {
|
|
building: "Gebäude",
|
|
road: "Strassen",
|
|
water: "Gewässer",
|
|
green: "Grünflächen",
|
|
};
|
|
|
|
/** Layer-Kennung (englischer Identifier) je Kategorie — für spätere Zuordnung. */
|
|
const CATEGORY_LAYER: Record<GeoCategory, string> = {
|
|
building: "context-buildings",
|
|
road: "context-roads",
|
|
water: "context-water",
|
|
green: "context-green",
|
|
};
|
|
|
|
/** Erzeugt eine (kollisionsarme) ID für ein neues Kontext-Objekt. */
|
|
function contextId(prefix: string): string {
|
|
return `${prefix}-${Date.now().toString(36)}-${Math.random()
|
|
.toString(36)
|
|
.slice(2, 8)}`;
|
|
}
|
|
|
|
/**
|
|
* Wandelt importierte Features in `ContextObject`s (je Kategorie EIN
|
|
* ContourSet). Die Konturen liegen auf z=0 (Grundriss-Kontext); geschlossene
|
|
* Ringe (Gebäude/Wasser/Grün) werden als geschlossene Konturen markiert,
|
|
* Strassen als offene Linienzüge. Der Aufrufer legt das Ergebnis über
|
|
* `onAddContextObjects` in `project.context` ab.
|
|
*/
|
|
export function featuresToContextObjects(
|
|
features: GeoFeature[],
|
|
sourceLabel: string,
|
|
): ContextObject[] {
|
|
const byCat = new Map<GeoCategory, Contour[]>();
|
|
for (const f of features) {
|
|
if (f.pts.length < 2) continue;
|
|
const list = byCat.get(f.category) ?? [];
|
|
list.push({
|
|
z: 0,
|
|
pts: f.pts.map((p) => ({ x: p.x, y: p.y })),
|
|
closed: f.closed,
|
|
layer: CATEGORY_LAYER[f.category],
|
|
});
|
|
byCat.set(f.category, list);
|
|
}
|
|
|
|
const objs: ContextObject[] = [];
|
|
for (const [cat, contours] of byCat) {
|
|
if (contours.length === 0) continue;
|
|
objs.push({
|
|
id: contextId(`geo-${cat}`),
|
|
type: "contourSet",
|
|
name: `${CATEGORY_LABEL[cat]} (${sourceLabel})`,
|
|
layer: CATEGORY_LAYER[cat],
|
|
contours,
|
|
});
|
|
}
|
|
return objs;
|
|
}
|
|
|
|
/**
|
|
* Basis-URL des optionalen Geo-Proxys (openbureau-core `/geoproxy`). Wird für
|
|
* Overpass zwingend benutzt (CORS unzuverlässig); für geo.admin nur als
|
|
* Fallback. Konfiguration über `VITE_GEO_PROXY` (z. B. "/geoproxy" bei
|
|
* gleichem Origin oder eine absolute URL auf den API-Server). Leer = kein Proxy.
|
|
*/
|
|
export function geoProxyBase(): string {
|
|
const env = (import.meta as unknown as { env?: Record<string, string> }).env;
|
|
return (env?.VITE_GEO_PROXY ?? "").replace(/\/$/, "");
|
|
}
|
|
|
|
/**
|
|
* Verpackt eine absolute Upstream-URL für den Geo-Proxy. Ohne konfigurierten
|
|
* Proxy wird die URL unverändert zurückgegeben (Direktabruf).
|
|
*/
|
|
export function viaProxy(url: string): string {
|
|
const base = geoProxyBase();
|
|
return base ? `${base}?u=${encodeURIComponent(url)}` : url;
|
|
}
|