diff --git a/restricted/aussenplan.php b/restricted/aussenplan.php
new file mode 100644
index 0000000..1c816bf
--- /dev/null
+++ b/restricted/aussenplan.php
@@ -0,0 +1,302 @@
+ "#c8cdd6",
+ "Hof" => "#57585a",
+ "Garten" => "#2e5c33",
+ "Garage" => "#8a9099",
+ "Carport EG" => "#3f4a63", // nur Fundament, mit PV darauf
+ "Carport OG" => "#6f7680",
+ "Veranda EG" => "#9a7b52",
+ "Veranda OG" => "#c9a978",
+ "Terrasse EG" => "#9a7b52",
+ "Terrasse OG" => "#c9a978",
+ "Pergola" => "#7a6a8f",
+ ];
+ return $farben[$name] ?? "#8a9099";
+}
+
+/** Blickrichtung: negativ heißt von Westen her. -35° ist Südwesten. */
+const PLAN_WINKEL = -35.0;
+
+/** Wie stark die Tiefe zusammengedrückt wird. 1 wäre die reine Draufsicht. */
+const PLAN_STAUCHUNG = 0.55;
+
+/**
+ * Wie hoch Höhen erscheinen. 1,4 heißt: ein Meter Höhe sieht aus wie 1,4 m
+ * Grundfläche. Überhöht, damit die drei Meter zwischen Terrasse EG und
+ * Terrasse OG deutlich werden - bei maßstäblicher Höhe klebten die beiden
+ * aufeinander, und genau das soll die Schrägsicht ja auflösen.
+ */
+const PLAN_UEBERHOEHUNG = 1.4;
+
+/** So groß ist die Zeichenfläche, in die alles hineinpassen muss. */
+const PLAN_BREITE = 400;
+const PLAN_HOEHE = 300;
+
+/** Luft zwischen Zeichnung und Rand, in Einheiten der Zeichenfläche. */
+const PLAN_RAND = 12;
+
+/**
+ * Die Flächen des Außengeländes, in Metern.
+ *
+ * Herkunft: tools/lageplan.php - dort werden sie am amtlichen Luftbild
+ * abgeklickt, die Seite gibt diese Zeilen fertig aus. Von Hand zu ändern
+ * lohnt nur für Kleinigkeiten; wer etwas verschiebt, misst besser neu.
+ *
+ * raum Raumname aus rooms.php, oder null für Flächen, die kein Raum sind
+ * (Haus, Hof, Garten - sie tragen keine Kachel)
+ * ecken Grundriss als [x, y] in Metern, x nach Osten, y nach Süden
+ * z Höhe der Fläche über Gelände (0 = ebenerdig, ~3 = OG-Ebene)
+ * hoehe Bauhöhe darüber (0 = flache Fläche, sonst ein Körper)
+ * dach Satteldach über der Bauhöhe, 0 = flach
+ * farbe Deckfläche; die Seiten werden daraus abgedunkelt
+ *
+ * Solange die Liste leer ist, hat AG keinen Grundriss - die Etage taucht dann
+ * im Menü nicht auf (siehe floorsWithPlan() in rooms.php), Zuordnung und
+ * Automatiken funktionieren trotzdem.
+ */
+function aussenFlaechen()
+{
+ return [
+ // Hier kommen die abgeklickten Flächen hinein.
+ ];
+}
+
+/**
+ * Die Projektion selbst. Liefert eine Funktion, die (x, y, z) in Metern auf
+ * (X, Y) in projizierten Metern abbildet - noch ohne Bezug zur Zeichenfläche.
+ */
+function aussenProjektor()
+{
+ $w = deg2rad(PLAN_WINKEL);
+ $c = cos($w);
+ $s = sin($w);
+ return function ($x, $y, $z) use ($c, $s) {
+ return [$x * $c - $y * $s,
+ ($x * $s + $y * $c) * PLAN_STAUCHUNG - $z * PLAN_UEBERHOEHUNG];
+ };
+}
+
+/**
+ * Alles Gezeichnete in die Zeichenfläche einpassen.
+ *
+ * Erst wird projiziert, dann ein Maßstab gesucht, in den die ganze Zeichnung
+ * passt - nicht umgekehrt. Die Zeichenfläche ist 400 × 300 und hat mit Metern
+ * nichts zu tun; wer den Maßstab vorher festlegt, schneidet entweder etwas ab
+ * oder lässt die Hälfte leer.
+ *
+ * Wichtig: Messseite und Anzeige müssen dieselbe Einpassung benutzen, sonst
+ * sitzen die Kacheln woanders als die Flächen, auf denen sie liegen sollen.
+ * Deshalb steht sie hier und nicht zweimal.
+ */
+function aussenEinpassung($flaechen)
+{
+ $P = aussenProjektor();
+ $xs = [];
+ $ys = [];
+ foreach ($flaechen as $f) {
+ $oben = ($f["z"] ?? 0) + ($f["hoehe"] ?? 0) + ($f["dach"] ?? 0);
+ foreach ($f["ecken"] as $e) {
+ foreach ([$f["z"] ?? 0, $oben] as $z) {
+ list($X, $Y) = $P($e[0], $e[1], $z);
+ $xs[] = $X;
+ $ys[] = $Y;
+ }
+ }
+ }
+ if (!$xs) {
+ return null;
+ }
+ $breite = max($xs) - min($xs);
+ $hoehe = max($ys) - min($ys);
+ // Der kleinere der beiden Maßstäbe passt in beide Richtungen.
+ $massstab = min(($breite > 0 ? (PLAN_BREITE - 2 * PLAN_RAND) / $breite : INF),
+ ($hoehe > 0 ? (PLAN_HOEHE - 2 * PLAN_RAND) / $hoehe : INF));
+ if (!is_finite($massstab)) {
+ $massstab = 1.0;
+ }
+ return [
+ "massstab" => $massstab,
+ // Zusätzlich zentrieren: was schmaler ist als die Fläche, soll nicht
+ // in der Ecke kleben.
+ "dx" => (PLAN_BREITE - $breite * $massstab) / 2 - min($xs) * $massstab,
+ "dy" => (PLAN_HOEHE - $hoehe * $massstab) / 2 - min($ys) * $massstab,
+ ];
+}
+
+/** Ein Punkt in Metern zu einem Punkt auf der Zeichenfläche. */
+function aussenPunkt($einpassung, $x, $y, $z)
+{
+ $P = aussenProjektor();
+ list($X, $Y) = $P($x, $y, $z);
+ return [$X * $einpassung["massstab"] + $einpassung["dx"],
+ $Y * $einpassung["massstab"] + $einpassung["dy"]];
+}
+
+/** Mittelwert einer Punktliste - gut genug als Ankerpunkt einer Fläche. */
+function aussenMitte($punkte)
+{
+ $sx = 0.0;
+ $sy = 0.0;
+ foreach ($punkte as $p) {
+ $sx += $p[0];
+ $sy += $p[1];
+ }
+ $n = max(1, count($punkte));
+ return [$sx / $n, $sy / $n];
+}
+
+/** Eine Farbe abdunkeln - die Seitenflächen liegen im Schatten. */
+function aussenSchatten($hex, $faktor)
+{
+ $n = hexdec(ltrim($hex, "#"));
+ return sprintf("#%02x%02x%02x",
+ (int) round(($n >> 16) * $faktor),
+ (int) round((($n >> 8) & 255) * $faktor),
+ (int) round(($n & 255) * $faktor));
+}
+
+/**
+ * Die Zeichnung als Liste von Polygonen, von hinten nach vorn sortiert.
+ *
+ * Sortiert wird nach dem hintersten Punkt der Grundfläche (Malerreihenfolge).
+ * Das reicht hier: die Körper stehen nebeneinander auf dem Boden und
+ * durchdringen sich nicht. Bei ineinander verschachtelten Körpern bräuchte es
+ * mehr, aber ein Grundstück ist keine Baugruppe.
+ *
+ * Returns:
+ * ["polygone" => [["punkte" => [[x,y],...], "farbe" => "#rrggbb"], ...],
+ * "anker" => [Raumname => [x, y], ...]] Mitte der Deckfläche
+ */
+function aussenZeichnung()
+{
+ $flaechen = aussenFlaechen();
+ $einpassung = aussenEinpassung($flaechen);
+ if (!$einpassung) {
+ return ["polygone" => [], "anker" => []];
+ }
+
+ $stuecke = [];
+ foreach ($flaechen as $f) {
+ $z = $f["z"] ?? 0;
+ $hoehe = $f["hoehe"] ?? 0;
+ $dach = $f["dach"] ?? 0;
+ $farbe = $f["farbe"] ?? "#8a9099";
+
+ $tiefe = INF;
+ foreach ($f["ecken"] as $e) {
+ $p = aussenPunkt($einpassung, $e[0], $e[1], 0);
+ $tiefe = min($tiefe, $p[1]);
+ }
+
+ $unten = [];
+ $oben = [];
+ foreach ($f["ecken"] as $e) {
+ $unten[] = aussenPunkt($einpassung, $e[0], $e[1], $z);
+ $oben[] = aussenPunkt($einpassung, $e[0], $e[1], $z + $hoehe);
+ }
+
+ $polygone = [];
+ if ($hoehe > 0) {
+ $anzahl = count($f["ecken"]);
+ for ($i = 0; $i < $anzahl; $i++) {
+ $j = ($i + 1) % $anzahl;
+ $polygone[] = ["punkte" => [$unten[$i], $unten[$j], $oben[$j], $oben[$i]],
+ "farbe" => aussenSchatten($farbe, 0.62)];
+ }
+ }
+ $polygone[] = ["punkte" => $oben, "farbe" => $farbe];
+
+ if ($dach > 0 && count($f["ecken"]) === 4) {
+ // Satteldach mit First über der Mitte der beiden Schmalseiten.
+ $e = $f["ecken"];
+ $first1 = aussenPunkt($einpassung, ($e[0][0] + $e[3][0]) / 2,
+ ($e[0][1] + $e[3][1]) / 2, $z + $hoehe + $dach);
+ $first2 = aussenPunkt($einpassung, ($e[1][0] + $e[2][0]) / 2,
+ ($e[1][1] + $e[2][1]) / 2, $z + $hoehe + $dach);
+ $polygone[] = ["punkte" => [$oben[0], $oben[1], $first2, $first1],
+ "farbe" => $f["dachfarbe"] ?? "#b5563a"];
+ $polygone[] = ["punkte" => [$oben[3], $oben[2], $first2, $first1],
+ "farbe" => aussenSchatten($f["dachfarbe"] ?? "#b5563a", 0.78)];
+ }
+
+ $stuecke[] = ["tiefe" => $tiefe, "polygone" => $polygone,
+ "raum" => $f["raum"] ?? null, "mitte" => aussenMitte($oben)];
+ }
+
+ usort($stuecke, function ($a, $b) {
+ return $a["tiefe"] <=> $b["tiefe"];
+ });
+
+ $polygone = [];
+ $anker = [];
+ foreach ($stuecke as $s) {
+ foreach ($s["polygone"] as $p) {
+ $polygone[] = $p;
+ }
+ if ($s["raum"] !== null) {
+ $anker[$s["raum"]] = $s["mitte"];
+ }
+ }
+ return ["polygone" => $polygone, "anker" => $anker];
+}
+
+/** Die Zeichnung als fertige SVG-Zeilen. */
+function aussenSvg()
+{
+ $zeichnung = aussenZeichnung();
+ $svg = "";
+ foreach ($zeichnung["polygone"] as $p) {
+ $punkte = [];
+ foreach ($p["punkte"] as $pt) {
+ $punkte[] = round($pt[0], 1) . "," . round($pt[1], 1);
+ }
+ $svg .= '' . "\n";
+ }
+ return $svg;
+}
diff --git a/restricted/rooms.php b/restricted/rooms.php
index 0aa7bd7..18c5fc5 100644
--- a/restricted/rooms.php
+++ b/restricted/rooms.php
@@ -97,9 +97,14 @@ $rooms = [
// restricted/config.php; am Carport OG haengt der go-e Charger.
["floor" => "AG", "mqtt" => "Carport EG", "id" => "carport_eg", "werte" => []],
["floor" => "AG", "mqtt" => "Carport OG", "id" => "carport_og", "werte" => []],
- ["floor" => "AG", "mqtt" => "Veranda", "id" => "veranda", "werte" => []],
+ // Veranda und Terrasse gibt es zweimal, je Wohnpartei eine. In der
+ // Draufsicht laege das obere Paar genau auf dem unteren - deshalb die
+ // Schraegsicht, siehe restricted/aussenplan.php.
+ ["floor" => "AG", "mqtt" => "Veranda EG", "id" => "veranda_eg", "werte" => []],
+ ["floor" => "AG", "mqtt" => "Veranda OG", "id" => "veranda_og", "werte" => []],
+ ["floor" => "AG", "mqtt" => "Terrasse EG", "id" => "terrasse_eg", "werte" => []],
+ ["floor" => "AG", "mqtt" => "Terrasse OG", "id" => "terrasse_og", "werte" => []],
["floor" => "AG", "mqtt" => "Pergola", "id" => "pergola", "werte" => []],
- ["floor" => "AG", "mqtt" => "Terrasse", "id" => "terrasse", "werte" => []],
["floor" => "AG", "mqtt" => "Garage", "id" => "garage", "werte" => []],
// Der Garten ist kein Bauteil wie die anderen, aber ein Ort: hier haengen
// der Regensensor und die beiden Ventilsteuerungen.
diff --git a/tools/lageplan.php b/tools/lageplan.php
index 839d36e..cc6c81c 100644
--- a/tools/lageplan.php
+++ b/tools/lageplan.php
@@ -2,16 +2,21 @@
/**
* Messblatt für den Lageplan des Außengeländes.
*
- * OG, EG und UG haben je ein Bild in assets/img - Renderings aus der
- * Planungssoftware, Puppenhausschnitt von schräg oben. Für das Außengelände
- * gibt es so ein Bild nicht: die Software kennt nur das einzelne Gebäude,
- * nicht das Grundstück. Der Plan für AG entsteht deshalb als Vektor direkt im
- * SVG von restricted/home.php - Haus, Carport, Garage, Pergola, Terrasse und
- * Garten als Flächen.
+ * OG, EG und UG haben je ein Rendering in assets/img - Puppenhausschnitt von
+ * schräg oben. Für das Außengelände gibt es so ein Bild nicht: die
+ * Planungssoftware kennt nur das einzelne Gebäude, nicht das Grundstück. Der
+ * Plan für AG entsteht deshalb als Vektor, gezeichnet aus der Geometrie in
+ * restricted/aussenplan.php - und die entsteht hier.
*
- * Diese Seite liefert die Koordinaten dafür. Als Hintergrund liegt das
- * amtliche Luftbild (DOP20, 20 cm Bodenauflösung), abgeklickt wird darauf
- * Fläche für Fläche; darunter fallen die fertigen -Zeilen heraus.
+ * Abgeklickt wird auf dem amtlichen Luftbild (DOP20, 20 cm Bodenauflösung).
+ * Daneben steht die Vorschau in derselben Schrägsicht von Südwesten, in der
+ * die Etage später gezeichnet wird: nur dort sieht man, ob Terrasse OG und
+ * Terrasse EG wirklich auseinandergehen.
+ *
+ * Warum das überhaupt geht: die Projektion in aussenplan.php ist eine
+ * Militärprojektion. Sie lässt den Grundriss maßhaltig, also reichen die
+ * Koordinaten aus der Draufsicht plus eine Höhe je Fläche. Eine echte
+ * Perspektive müsste man neu vermessen.
*
* 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
@@ -21,41 +26,31 @@
* 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
+ * tools/lageplan.php?lat=47.5781&lon=10.2628&breite=70
*
* "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.
+ * 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;
}
-/** 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.
- */
+/** 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";
@@ -70,9 +65,9 @@ const WMS_SCHAERFE = 3;
*/
$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 = isset($_GET["breite"]) ? floatval($_GET["breite"]) : 70.0;
$breite = max(20.0, min(400.0, $breite));
-$hoehe = $breite * PLAN_HOCH / PLAN_BREIT;
+$hoehe = $breite * PLAN_HOEHE / PLAN_BREITE;
/**
* WGS84 nach UTM Zone 32 Nord (EPSG:25832).
@@ -122,31 +117,56 @@ $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),
+ "WIDTH" => (int) (PLAN_BREITE * WMS_SCHAERFE),
+ "HEIGHT" => (int) (PLAN_HOEHE * 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.
+ * 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]];
+$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;
}
- $flaechen[] = ["schluessel" => $raum["id"], "name" => $raum["mqtt"], "raum" => $raum];
+ // 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, danach wiederholen sie sich - bei sieben
-// Flächen kommt es dazu nicht.
-$farben = ["#ffbe3c", "#35b6cf", "#7ed957", "#ff7a7a", "#c58cff", "#ffe066", "#6ee7c8"];
+// 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]["farbe"] = $farben[$i % count($farben)];
+ $flaechen[$i]["stift"] = $stifte[$i % count($stifte)];
+ $flaechen[$i]["farbe"] = aussenFarbe($f["name"]);
}
?>
@@ -171,7 +191,7 @@ foreach ($flaechen as $i => $f) {
background: var(--grund); color: var(--schrift);
font: 15px/1.55 -apple-system, "Segoe UI", Roboto, sans-serif;
}
- .huelle { max-width: 900px; margin: 0 auto; }
+ .huelle { max-width: 1000px; margin: 0 auto; }
h1 { font-size: 1.35rem; margin: 0 0 .3rem; }
.vorwort { color: var(--leise); margin: 0 0 1.2rem; max-width: 62ch; }
.vorwort code, .quelle code {
@@ -182,14 +202,21 @@ foreach ($flaechen as $i => $f) {
background: var(--karte); border: 1px solid var(--linie);
border-radius: .6rem; padding: .8rem; margin-bottom: 1.2rem;
}
+ .nebeneinander { display: grid; grid-template-columns: 1fr 1fr; gap: .8rem; }
+ @media (max-width: 720px) { .nebeneinander { grid-template-columns: 1fr; } }
+ .nebeneinander h3 {
+ font-size: .82rem; font-weight: 600; color: var(--leise);
+ margin: 0 0 .3rem; text-transform: uppercase; letter-spacing: .04em;
+ }
.plan {
display: block; width: 100%; height: auto; border-radius: .4rem;
- cursor: crosshair; touch-action: none; background: #0b0d10;
+ touch-action: none; background: #0b0d10;
}
+ #plan { cursor: crosshair; }
.achsen text { fill: #ffffffaa; font: 7px sans-serif; }
.stift { stroke: #ffbe3c; stroke-width: .4; stroke-dasharray: 3 3; }
- .name { font: 5px sans-serif; text-anchor: middle; paint-order: stroke;
- stroke: #000a; stroke-width: 1.4; }
+ .name { font: 6px sans-serif; text-anchor: middle; paint-order: stroke;
+ stroke: #000a; stroke-width: 1.8; }
.waehler { display: flex; flex-wrap: wrap; gap: .4rem; margin: .8rem 0 .2rem; }
.waehler button {
@@ -202,6 +229,13 @@ foreach ($flaechen as $i => $f) {
.waehler .tupfen { width: .7rem; height: .7rem; border-radius: 50%; }
.waehler .zahl { color: var(--leise); font-variant-numeric: tabular-nums; }
+ .hoehen { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem;
+ margin: .7rem 0 0; font-size: .88rem; color: var(--leise); }
+ .hoehen input {
+ font: inherit; width: 4.2rem; padding: .15rem .35rem; text-align: right;
+ background: var(--grund); color: var(--schrift);
+ border: 1px solid var(--linie); border-radius: .3rem;
+ }
.knoepfe { display: flex; flex-wrap: wrap; gap: .4rem; margin: .6rem 0 0; }
.knoepfe button {
font: inherit; font-size: .88rem; cursor: pointer; padding: .25rem .6rem;
@@ -213,7 +247,7 @@ foreach ($flaechen as $i => $f) {
h2 { font-size: .95rem; margin: 1.4rem 0 .4rem; font-weight: 600; }
textarea {
- width: 100%; box-sizing: border-box; min-height: 9rem; resize: vertical;
+ width: 100%; box-sizing: border-box; min-height: 11rem; resize: vertical;
background: var(--karte); color: var(--schrift);
border: 1px solid var(--linie); border-radius: .4rem; padding: .6rem;
font-family: ui-monospace, Consolas, monospace; font-size: .82rem; line-height: 1.5;
@@ -227,47 +261,59 @@ foreach ($flaechen as $i => $f) {
Lageplan Außengelände
- Die Zeichenfläche ist = PLAN_BREIT ?> × = PLAN_HOCH ?> und zeigt hier
+ 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_BREIT, 2, ",", "") ?> 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.
+ 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.