diff --git a/tools/lageplan.php b/tools/lageplan.php new file mode 100644 index 0000000..839d36e --- /dev/null +++ b/tools/lageplan.php @@ -0,0 +1,450 @@ +-Zeilen heraus. + * + * Warum nicht einfach am Bild abmessen: die Zeichenfläche ist 400 × 300 groß + * und hat mit Metern nichts zu tun. Wer das im Kopf umrechnet, verrechnet + * sich - und zwar in jeder Ecke anders. + * + * Das Luftbild kommt live vom WMS der Bayerischen Vermessungsverwaltung, es + * liegt also keine Kopie im Repository. Der Ausschnitt lässt sich über die + * Adresszeile verschieben, ohne diese Datei anzufassen: + * + * tools/lageplan.php?lat=47.5781&lon=10.2628&breite=120 + * + * "breite" ist die Kantenlänge des Ausschnitts in Metern; die Höhe ergibt + * sich aus dem Seitenverhältnis 4:3 der Zeichenfläche. + * + * Aufruf: http:///smart/tools/lageplan.php + * + * Bewusst eine eigene Seite und kein Eintrag im Menü: sie wird einmal + * gebraucht und danach nie wieder - genau wie kachelpositionen.php, mit der + * sie sich die Bauart teilt. + */ + +require_once(__DIR__ . "/../helper.php"); +require_once(__DIR__ . "/../restricted/rooms.php"); + +if (!checkLogin()) { + http_response_code(403); + exit; +} + +/** So groß ist die Zeichenfläche - siehe restricted/home.php. */ +const PLAN_BREIT = 400; +const PLAN_HOCH = 300; + +/** So groß ist eine Kachel, für die vorgeschlagene x/y-Zeile. */ +const KACHEL_BREIT = 24; +const KACHEL_HOCH = 19; + +/** Welche Etage hier vermessen wird. */ +const ETAGE = "AG"; + +/** + * Das Luftbild. CC BY 4.0 - die Namensnennung steht unten auf der Seite und + * gehört dort hin, auch wenn die Seite nur intern erreichbar ist. + */ +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 in + * restricted/gartenbewaesserung/auto_watering.py, 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"]) : 120.0; +$breite = max(20.0, min(400.0, $breite)); +$hoehe = $breite * PLAN_HOCH / PLAN_BREIT; + +/** + * 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_BREIT * WMS_SCHAERFE), + "HEIGHT" => (int) (PLAN_HOCH * WMS_SCHAERFE), + "FORMAT" => "image/jpeg", +]); + +/** + * Die Flächen, die abgeklickt werden. + * + * Sie kommen aus der Raumtabelle - ein neuer AG-Raum in rooms.php taucht hier + * von selbst auf. Das Haus steht davor, obwohl es kein Raum ist: es ist der + * Umriss, an dem sich beim Zeichnen alles andere ausrichtet. + */ +$flaechen = [["schluessel" => "haus", "name" => "Haus", "raum" => null]]; +foreach (allRooms() as $raum) { + if ($raum["floor"] !== ETAGE) { + continue; + } + $flaechen[] = ["schluessel" => $raum["id"], "name" => $raum["mqtt"], "raum" => $raum]; +} + +// Genug unterscheidbare Farben, danach wiederholen sie sich - bei sieben +// Flächen kommt es dazu nicht. +$farben = ["#ffbe3c", "#35b6cf", "#7ed957", "#ff7a7a", "#c58cff", "#ffe066", "#6ee7c8"]; +foreach ($flaechen as $i => $f) { + $flaechen[$i]["farbe"] = $farben[$i % count($farben)]; +} + +?> + + + + +Lageplan Außengelände + + + +
+ +

Lageplan Außengelände

+

+ Die Zeichenfläche ist × und zeigt hier + × + m – + eine Einheit sind m. + Wähle eine Fläche und klick ihre Ecken der Reihe nach ab; Backspace nimmt + den letzten Punkt zurück. Unten stehen die fertigen Zeilen für + restricted/home.php und restricted/rooms.php. + Passt der Ausschnitt nicht, verschieb ihn über ?lat=, + ?lon= und ?breite= in der Adresszeile. +

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+

Fläche wählen und die erste Ecke anklicken …

+
+ +

Für restricted/home.php – der Plan

+ + +

Für restricted/rooms.php – die Kacheln

+ + +

+ 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 in EPSG:25832. +

+ +
+ + + +