/smart/tools/lageplan.php * * Bewusst eine eigene Seite und kein Eintrag im Menü: sie wird gebraucht, * wenn sich draußen etwas ändert, und das ist selten - genau wie * kachelpositionen.php, mit der sie sich die Bauart teilt. */ require_once(__DIR__ . "/../helper.php"); require_once(__DIR__ . "/../restricted/rooms.php"); require_once(__DIR__ . "/../restricted/aussenplan.php"); if (!checkLogin()) { http_response_code(403); exit; } /** Welche Etage hier vermessen wird. */ const ETAGE = "AG"; /** Das Luftbild. CC BY 4.0 - die Namensnennung steht unten auf der Seite. */ const WMS_URL = "https://geoservices.bayern.de/od/wms/dop/v1/dop20"; const WMS_LAYER = "by_dop20c"; // Wie viele Bildpunkte je Einheit der Zeichenfläche geholt werden. Drei ist // scharf genug zum Abklicken und bleibt weit unter der Grenze des Dienstes. const WMS_SCHAERFE = 3; /** * Mittelpunkt des Ausschnitts. Dieselben Koordinaten stehen als Vorgabe in * gatherRainData.py im SolarManager, von wo die Regendaten geholt werden - * es ist derselbe Ort. */ $lat = isset($_GET["lat"]) ? floatval($_GET["lat"]) : 47.5781; $lon = isset($_GET["lon"]) ? floatval($_GET["lon"]) : 10.2628; $breite = isset($_GET["breite"]) ? floatval($_GET["breite"]) : 70.0; $breite = max(20.0, min(400.0, $breite)); $hoehe = $breite * PLAN_HOEHE / PLAN_BREITE; /** * WGS84 nach UTM Zone 32 Nord (EPSG:25832). * * Der WMS kann auch mit Längen- und Breitengraden umgehen, aber dann ist ein * quadratischer Ausschnitt keiner mehr: ein Grad Länge ist auf dieser Breite * nur zwei Drittel so lang wie ein Grad Breite. In UTM ist ein Meter ein * Meter, und der Maßstab der Seite stimmt ohne Umrechnung. */ function nachUtm32($lonGrad, $latGrad) { $a = 6378137.0; $f = 1 / 298.257223563; $k0 = 0.9996; $e2 = $f * (2 - $f); $ep2 = $e2 / (1 - $e2); $lon0 = deg2rad(32 * 6 - 183); $lat = deg2rad($latGrad); $lon = deg2rad($lonGrad); $N = $a / sqrt(1 - $e2 * pow(sin($lat), 2)); $T = pow(tan($lat), 2); $C = $ep2 * pow(cos($lat), 2); $A = cos($lat) * ($lon - $lon0); $M = $a * ((1 - $e2 / 4 - 3 * $e2 ** 2 / 64 - 5 * $e2 ** 3 / 256) * $lat - (3 * $e2 / 8 + 3 * $e2 ** 2 / 32 + 45 * $e2 ** 3 / 1024) * sin(2 * $lat) + (15 * $e2 ** 2 / 256 + 45 * $e2 ** 3 / 1024) * sin(4 * $lat) - (35 * $e2 ** 3 / 3072) * sin(6 * $lat)); $x = $k0 * $N * ($A + (1 - $T + $C) * $A ** 3 / 6 + (5 - 18 * $T + $T ** 2 + 72 * $C - 58 * $ep2) * $A ** 5 / 120) + 500000.0; $y = $k0 * ($M + $N * tan($lat) * ($A ** 2 / 2 + (5 - $T + 9 * $C + 4 * $C ** 2) * $A ** 4 / 24 + (61 - 58 * $T + $T ** 2 + 600 * $C - 330 * $ep2) * $A ** 6 / 720)); return [$x, $y]; } list($mx, $my) = nachUtm32($lon, $lat); $bbox = sprintf("%.1f,%.1f,%.1f,%.1f", $mx - $breite / 2, $my - $hoehe / 2, $mx + $breite / 2, $my + $hoehe / 2); $luftbild = WMS_URL . "?" . http_build_query([ "SERVICE" => "WMS", "VERSION" => "1.3.0", "REQUEST" => "GetMap", "LAYERS" => WMS_LAYER, "STYLES" => "", "CRS" => "EPSG:25832", "BBOX" => $bbox, "WIDTH" => (int) (PLAN_BREITE * WMS_SCHAERFE), "HEIGHT" => (int) (PLAN_HOEHE * WMS_SCHAERFE), "FORMAT" => "image/jpeg", ]); /** * Die Flächen, die abgeklickt werden. * * Die Räume kommen aus der Raumtabelle - ein neuer AG-Raum in rooms.php * taucht hier von selbst auf. Davor stehen Haus und Hof: sie sind keine Räume * und tragen keine Kachel, aber ohne sie wäre der Plan ein paar Flecken im * Nichts. Das Haus ist zusätzlich der Umriss, an dem sich beim Zeichnen alles * andere ausrichtet, deshalb steht es ganz vorn. * * "z" ist die Höhe über Gelände, "hoehe" die Bauhöhe darüber. Die Vorgaben * sind das, was am häufigsten stimmt: eine ebenerdige, flache Fläche. */ $flaechen = [ ["schluessel" => "haus", "name" => "Haus", "raum" => null, "z" => 0, "hoehe" => 6, "dach" => 3], ["schluessel" => "hof", "name" => "Hof", "raum" => null, "z" => 0, "hoehe" => 0, "dach" => 0], ]; foreach (allRooms() as $raum) { if ($raum["floor"] !== ETAGE) { continue; } // Was auf der OG-Ebene liegt, steht drei Meter höher - die Traufe liegt // auf sechs Metern, bei zwei Geschossen ist das die halbe Höhe. Der // Carport OG heisst zwar OG, steht aber auf dem Boden; deshalb entscheidet // die Bauart und nicht der Name. $obenAuf = in_array($raum["mqtt"], ["Veranda OG", "Terrasse OG"], true); $mitDach = in_array($raum["mqtt"], ["Carport OG", "Garage"], true); $flaechen[] = [ "schluessel" => $raum["id"], "name" => $raum["mqtt"], "raum" => $raum, "z" => $obenAuf ? 3.0 : 0.0, "hoehe" => $mitDach ? 2.5 : 0.0, "dach" => 0, ]; } // Genug unterscheidbare Farben für die Bedienung; gezeichnet wird später mit // den Farben aus aussenFarbe(). $stifte = ["#ffbe3c", "#35b6cf", "#7ed957", "#ff7a7a", "#c58cff", "#ffe066", "#6ee7c8", "#ff9f5c", "#9ec5ff", "#f78fd0", "#b5e48c"]; foreach ($flaechen as $i => $f) { $flaechen[$i]["stift"] = $stifte[$i % count($stifte)]; $flaechen[$i]["farbe"] = aussenFarbe($f["name"]); } ?>
Links das Luftbild von oben, rechts die Vorschau in der Schrägsicht von
Südwesten, in der die Etage später gezeichnet wird. Der Ausschnitt zeigt
= rtrim(rtrim(number_format($breite, 1, ",", ""), "0"), ",") ?> ×
= rtrim(rtrim(number_format($hoehe, 1, ",", ""), "0"), ",") ?> m –
eine Einheit sind = number_format($breite / PLAN_BREITE, 2, ",", "") ?> m.
Wähle eine Fläche, klick ihre Ecken der Reihe nach ab und stell darunter ihre
Höhe ein; Backspace nimmt den letzten Punkt zurück. Unten stehen die
fertigen Zeilen für restricted/aussenplan.php.
Passt der Ausschnitt nicht, verschieb ihn über ?lat=,
?lon= und ?breite= in der Adresszeile.
Fläche wählen und die erste Ecke anklicken …
restricted/aussenplan.php – in aussenFlaechen()
Luftbild: Datenquelle Bayerische Vermessungsverwaltung –
www.geodaten.bayern.de,
DOP20 (20 cm), CC BY 4.0. Live vom WMS geholt, es liegt keine
Kopie im Repository. Ausschnitt = htmlspecialchars($bbox) ?> in EPSG:25832.