2026-03-19 16:32:01 +01:00
|
|
|
|
"""
|
|
|
|
|
|
sn_plan41/ui/tab_b_logic.py – Fachlogik für Tab B (Druck)
|
|
|
|
|
|
"""
|
|
|
|
|
|
from __future__ import annotations
|
2026-03-20 12:43:01 +01:00
|
|
|
|
import math
|
|
|
|
|
|
from sn_basis.functions.variable_wrapper import set_variable, get_variable
|
2026-03-20 14:02:15 +01:00
|
|
|
|
from sn_basis.functions.qgiscore_wrapper import get_layer_extent
|
2026-03-19 16:32:01 +01:00
|
|
|
|
from sn_basis.modules.Pruefmanager import Pruefmanager
|
2026-03-20 12:43:01 +01:00
|
|
|
|
from sn_basis.modules.layerpruefer import Layerpruefer
|
2026-03-20 14:02:15 +01:00
|
|
|
|
from sn_plan41.ui.layout import Layout
|
2026-03-19 16:32:01 +01:00
|
|
|
|
|
2026-03-20 10:11:42 +01:00
|
|
|
|
|
|
|
|
|
|
KARTENNAME_VAR = "sn_kartenname"
|
|
|
|
|
|
PLOTMASSSTAB_VAR = "sn_plotmassstab"
|
2026-03-20 10:37:08 +01:00
|
|
|
|
VIEW_VAR = "sn_view"
|
2026-03-20 12:01:44 +01:00
|
|
|
|
ZIELGROESSE_VAR = "sn_zielgroesse"
|
|
|
|
|
|
FORMFAKTOR_VAR = "sn_formfaktor"
|
2026-03-20 11:45:36 +01:00
|
|
|
|
KARTENNAME_38 = "§38"
|
|
|
|
|
|
KARTENNAME_41 = "§41"
|
2026-03-20 10:11:42 +01:00
|
|
|
|
MASSSTAB_WIE_KARTENFENSTER = "Wie Kartenfenster"
|
2026-03-20 11:45:36 +01:00
|
|
|
|
THEMA_WIE_KARTENFENSTER = "wie kartenfenster"
|
2026-03-20 10:11:42 +01:00
|
|
|
|
|
2026-03-20 11:45:36 +01:00
|
|
|
|
KARTENNAME_BY_AUSWAHL = {
|
|
|
|
|
|
KARTENNAME_38: "Planungsübersicht §38 FlurbG",
|
|
|
|
|
|
KARTENNAME_41: "Karte zum Plan über die gemeinschaftlichen und öffentlichen Anlagen (§ 41 FlurbG)",
|
2026-03-20 10:11:42 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
PLOTMASSSTAB_BY_AUSWAHL = {
|
|
|
|
|
|
"1:5.000": "5000",
|
|
|
|
|
|
"1:10.000": "10000",
|
|
|
|
|
|
"1:15.000": "15000",
|
|
|
|
|
|
"1:20.000": "20000",
|
|
|
|
|
|
"1:25.000": "25000",
|
|
|
|
|
|
"1:50.000": "50000",
|
|
|
|
|
|
"1:100.000": "100000",
|
|
|
|
|
|
}
|
2026-03-19 16:32:01 +01:00
|
|
|
|
|
2026-03-20 12:01:44 +01:00
|
|
|
|
# Breite x Höhe in mm (Hochformat, DIN-Standard)
|
|
|
|
|
|
DIN_GROESSEN: dict[str, tuple[int, int]] = {
|
|
|
|
|
|
"DIN A0": (841, 1189),
|
|
|
|
|
|
"DIN A1": (594, 841),
|
|
|
|
|
|
"DIN A2": (420, 594),
|
|
|
|
|
|
"DIN A3": (297, 420),
|
|
|
|
|
|
"DIN A4": (210, 297),
|
|
|
|
|
|
}
|
|
|
|
|
|
DIN_STANDARD = "DIN A0"
|
|
|
|
|
|
|
2026-03-19 16:32:01 +01:00
|
|
|
|
class TabBLogic:
|
|
|
|
|
|
"""
|
|
|
|
|
|
Kapselt die Fachlogik von Tab B.
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, pruefmanager: Pruefmanager) -> None:
|
|
|
|
|
|
self.pruefmanager = pruefmanager
|
2026-03-20 10:11:42 +01:00
|
|
|
|
|
2026-03-20 11:45:36 +01:00
|
|
|
|
def set_kartenname_for_auswahl(self, auswahl: str) -> None:
|
|
|
|
|
|
"""Setzt die Projektvariable ``sn_kartenname`` anhand der Kartennamen-Auswahl."""
|
|
|
|
|
|
kartenname = KARTENNAME_BY_AUSWAHL.get(auswahl, "")
|
2026-03-20 10:11:42 +01:00
|
|
|
|
set_variable(KARTENNAME_VAR, kartenname, scope="project")
|
|
|
|
|
|
|
|
|
|
|
|
def set_plotmassstab_for_auswahl(self, auswahl: str, aktueller_massstab: float | None = None) -> None:
|
|
|
|
|
|
"""Setzt die Projektvariable ``sn_plotmassstab`` anhand der Maßstabsauswahl."""
|
|
|
|
|
|
if auswahl == MASSSTAB_WIE_KARTENFENSTER:
|
|
|
|
|
|
if aktueller_massstab and aktueller_massstab > 0:
|
|
|
|
|
|
set_variable(PLOTMASSSTAB_VAR, str(int(round(aktueller_massstab))), scope="project")
|
|
|
|
|
|
else:
|
|
|
|
|
|
set_variable(PLOTMASSSTAB_VAR, "", scope="project")
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
value = PLOTMASSSTAB_BY_AUSWAHL.get(auswahl, "")
|
|
|
|
|
|
set_variable(PLOTMASSSTAB_VAR, value, scope="project")
|
2026-03-20 10:37:08 +01:00
|
|
|
|
|
|
|
|
|
|
def set_view_for_auswahl(self, auswahl: str) -> None:
|
2026-03-20 11:45:36 +01:00
|
|
|
|
"""Setzt ``sn_view`` auf ``aktuell`` oder den Namen des gewählten Layerthemas."""
|
|
|
|
|
|
if auswahl == THEMA_WIE_KARTENFENSTER:
|
2026-03-20 10:37:08 +01:00
|
|
|
|
set_variable(VIEW_VAR, "aktuell", scope="project")
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
set_variable(VIEW_VAR, auswahl or "", scope="project")
|
2026-03-20 12:01:44 +01:00
|
|
|
|
|
|
|
|
|
|
def set_zielgroesse_for_auswahl(self, auswahl: str) -> None:
|
|
|
|
|
|
"""Setzt ``sn_zielgroesse`` auf den gewählten DIN-Namen."""
|
|
|
|
|
|
set_variable(ZIELGROESSE_VAR, auswahl if auswahl in DIN_GROESSEN else DIN_STANDARD, scope="project")
|
|
|
|
|
|
|
|
|
|
|
|
def set_formfaktor(self, endlosrolle: bool) -> None:
|
|
|
|
|
|
"""Setzt ``sn_formfaktor`` auf ``Endlosrolle`` oder ``Blatt``."""
|
|
|
|
|
|
set_variable(FORMFAKTOR_VAR, "Endlosrolle" if endlosrolle else "Blatt", scope="project")
|
2026-03-20 12:43:01 +01:00
|
|
|
|
|
|
|
|
|
|
# ─────────────────────────────────────────────────────────────────────────
|
|
|
|
|
|
# Pipeline: Druckvorlage_anlegen
|
|
|
|
|
|
# ─────────────────────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
|
|
def druckvorlage_anlegen(
|
|
|
|
|
|
self,
|
2026-03-20 14:02:15 +01:00
|
|
|
|
layer: object,
|
2026-03-20 12:43:01 +01:00
|
|
|
|
kartenname_auswahl: str,
|
|
|
|
|
|
massstab_auswahl: str,
|
|
|
|
|
|
zielgroesse: str,
|
|
|
|
|
|
formfaktor: bool,
|
|
|
|
|
|
) -> dict:
|
|
|
|
|
|
"""Pipeline 'Druckvorlage_anlegen'.
|
|
|
|
|
|
|
|
|
|
|
|
Prüft Parameter, berechnet Plotgröße und stellt bei Bedarf Atlas-Rückfrage.
|
|
|
|
|
|
|
2026-03-20 14:02:15 +01:00
|
|
|
|
Parameters
|
|
|
|
|
|
----------
|
|
|
|
|
|
layer:
|
|
|
|
|
|
Aktuell gewählter Verfahrensgebiet-Layer aus Tab A.
|
|
|
|
|
|
|
2026-03-20 12:43:01 +01:00
|
|
|
|
Returns
|
|
|
|
|
|
-------
|
|
|
|
|
|
dict
|
|
|
|
|
|
``ok`` (bool): Ob die Pipeline erfolgreich durchlaufen werden soll.
|
|
|
|
|
|
``switch_to_tab_a`` (bool): Ob Tab A aktiviert werden soll.
|
|
|
|
|
|
``atlas_seiten`` (int): Anzahl benötigter Seiten (1 = kein Atlas).
|
|
|
|
|
|
"""
|
|
|
|
|
|
# ─── 1. Verfahrensgebiet-Layer prüfen ─────────────────────────────
|
|
|
|
|
|
lp = Layerpruefer(layer=layer)
|
|
|
|
|
|
ergebnis = lp.pruefe()
|
|
|
|
|
|
if not ergebnis.ok:
|
|
|
|
|
|
self.pruefmanager.zeige_hinweis(
|
|
|
|
|
|
"Verfahrensgebiets-Layer angeben",
|
|
|
|
|
|
"Verfahrensgebiets-Layer angeben",
|
|
|
|
|
|
)
|
|
|
|
|
|
return {"ok": False, "switch_to_tab_a": True, "atlas_seiten": 0}
|
|
|
|
|
|
|
2026-03-20 14:02:15 +01:00
|
|
|
|
layer_id = getattr(layer, "id", lambda: "")() or ""
|
2026-03-20 12:43:01 +01:00
|
|
|
|
set_variable("sn_verfahrensgebietslayer", layer_id, scope="project")
|
|
|
|
|
|
|
|
|
|
|
|
# ─── 2. Kartenname prüfen ─────────────────────────────────────────
|
|
|
|
|
|
if kartenname_auswahl not in (KARTENNAME_38, KARTENNAME_41):
|
|
|
|
|
|
self.pruefmanager.zeige_hinweis(
|
|
|
|
|
|
"Kartennamen wählen",
|
|
|
|
|
|
"Kartennamen wählen",
|
|
|
|
|
|
)
|
|
|
|
|
|
return {"ok": False, "switch_to_tab_a": False, "atlas_seiten": 0}
|
|
|
|
|
|
|
|
|
|
|
|
# ─── 3. Maßstab ermitteln ─────────────────────────────────────────
|
|
|
|
|
|
if massstab_auswahl == MASSSTAB_WIE_KARTENFENSTER:
|
|
|
|
|
|
massstab_str = get_variable(PLOTMASSSTAB_VAR, scope="project") or ""
|
|
|
|
|
|
try:
|
|
|
|
|
|
massstab_zahl = float(massstab_str)
|
|
|
|
|
|
except (ValueError, TypeError):
|
|
|
|
|
|
massstab_zahl = 0.0
|
|
|
|
|
|
else:
|
|
|
|
|
|
massstab_zahl = float(PLOTMASSSTAB_BY_AUSWAHL.get(massstab_auswahl, 0))
|
|
|
|
|
|
|
|
|
|
|
|
if massstab_zahl <= 0:
|
|
|
|
|
|
self.pruefmanager.zeige_hinweis(
|
|
|
|
|
|
"Maßstab fehlt",
|
|
|
|
|
|
"Kein gültiger Maßstab angegeben.",
|
|
|
|
|
|
)
|
|
|
|
|
|
return {"ok": False, "switch_to_tab_a": False, "atlas_seiten": 0}
|
|
|
|
|
|
|
|
|
|
|
|
# ─── 4. Kartenbild berechnen ──────────────────────────────────────
|
|
|
|
|
|
# Der Layer wird als metrisch projiziert (Einheit: m) vorausgesetzt,
|
|
|
|
|
|
# wie es für deutsche Planungslagen (z.B. EPSG:25832) üblich ist.
|
|
|
|
|
|
extent = get_layer_extent(layer)
|
|
|
|
|
|
if extent is None:
|
|
|
|
|
|
self.pruefmanager.zeige_hinweis(
|
|
|
|
|
|
"Fehler",
|
|
|
|
|
|
"Layer-Ausdehnung konnte nicht ermittelt werden.",
|
|
|
|
|
|
)
|
|
|
|
|
|
return {"ok": False, "switch_to_tab_a": False, "atlas_seiten": 0}
|
|
|
|
|
|
|
|
|
|
|
|
# Naturgröße (m) → Papiergröße (mm): mm = m * 1000 / massstab
|
|
|
|
|
|
kartenbild_w = extent.width() * 1000.0 / massstab_zahl
|
|
|
|
|
|
kartenbild_h = extent.height() * 1000.0 / massstab_zahl
|
|
|
|
|
|
|
|
|
|
|
|
# ─── 5. Plotgröße = Kartenbild + Randabstand (x+210 mm, y+20 mm) ──
|
|
|
|
|
|
plotgroesse_w = kartenbild_w + 210.0
|
|
|
|
|
|
plotgroesse_h = kartenbild_h + 20.0
|
|
|
|
|
|
|
|
|
|
|
|
# ─── 6. Zielgröße bestimmen ───────────────────────────────────────
|
|
|
|
|
|
din_dims = DIN_GROESSEN.get(zielgroesse, DIN_GROESSEN[DIN_STANDARD])
|
2026-03-20 14:02:15 +01:00
|
|
|
|
if formfaktor: # Endlosrolle: X-Richtung entspricht der Plotgröße
|
|
|
|
|
|
ziel_w, ziel_h = plotgroesse_w, float(min(din_dims))
|
2026-03-20 12:43:01 +01:00
|
|
|
|
else:
|
|
|
|
|
|
ziel_w, ziel_h = float(din_dims[0]), float(din_dims[1])
|
|
|
|
|
|
|
2026-03-20 14:02:15 +01:00
|
|
|
|
# ─── 7. Passt auf ein Blatt? -> Layout erzeugen ───────────────────
|
|
|
|
|
|
print(f"[TabBLogic] plotgroesse=({plotgroesse_w:.1f}x{plotgroesse_h:.1f}), "
|
|
|
|
|
|
f"zielgroesse=({ziel_w:.1f}x{ziel_h:.1f}), passt={plotgroesse_w <= ziel_w and plotgroesse_h <= ziel_h}")
|
2026-03-20 12:43:01 +01:00
|
|
|
|
if plotgroesse_w <= ziel_w and plotgroesse_h <= ziel_h:
|
2026-03-20 14:02:15 +01:00
|
|
|
|
kartenname = get_variable(KARTENNAME_VAR, scope="project") or KARTENNAME_BY_AUSWAHL.get(
|
|
|
|
|
|
kartenname_auswahl, "Vorlage"
|
|
|
|
|
|
)
|
|
|
|
|
|
thema = get_variable(VIEW_VAR, scope="project") or ""
|
|
|
|
|
|
print(f"[TabBLogic] frage_text aufrufen, default='{kartenname}', thema='{thema}'")
|
|
|
|
|
|
vorlage_name, bestaetigt = self.pruefmanager.frage_text(
|
|
|
|
|
|
"Neue Vorlage anlegen",
|
|
|
|
|
|
"Bezeichnung der Vorlage:",
|
|
|
|
|
|
default_text=kartenname,
|
|
|
|
|
|
)
|
|
|
|
|
|
print(f"[TabBLogic] frage_text Ergebnis: name='{vorlage_name}', bestaetigt={bestaetigt}")
|
|
|
|
|
|
if not bestaetigt:
|
|
|
|
|
|
return {"ok": False, "switch_to_tab_a": False, "atlas_seiten": 0}
|
|
|
|
|
|
|
|
|
|
|
|
vorlage_name = (vorlage_name or "").strip() or kartenname
|
|
|
|
|
|
|
|
|
|
|
|
print(f"[TabBLogic] Rufe Layout().create_single_page_layout auf: name='{vorlage_name}', "
|
|
|
|
|
|
f"page=({ziel_w}x{ziel_h}), map=({kartenbild_w:.1f}x{kartenbild_h:.1f}), "
|
|
|
|
|
|
f"massstab={massstab_zahl}, thema='{thema}'")
|
|
|
|
|
|
try:
|
|
|
|
|
|
Layout().create_single_page_layout(
|
|
|
|
|
|
name=vorlage_name,
|
|
|
|
|
|
page_width_mm=ziel_w,
|
|
|
|
|
|
page_height_mm=ziel_h,
|
|
|
|
|
|
map_width_mm=kartenbild_w,
|
|
|
|
|
|
map_height_mm=kartenbild_h,
|
|
|
|
|
|
extent=extent,
|
|
|
|
|
|
plotmassstab=massstab_zahl,
|
|
|
|
|
|
thema=thema,
|
|
|
|
|
|
)
|
|
|
|
|
|
print("[TabBLogic] create_single_page_layout erfolgreich abgeschlossen")
|
|
|
|
|
|
except ValueError as exc:
|
|
|
|
|
|
print(f"[TabBLogic] ValueError: {exc}")
|
|
|
|
|
|
self.pruefmanager.zeige_hinweis("Vorlage anlegen", str(exc))
|
|
|
|
|
|
return {"ok": False, "switch_to_tab_a": False, "atlas_seiten": 0}
|
|
|
|
|
|
except Exception as exc:
|
|
|
|
|
|
print(f"[TabBLogic] Exception: {exc!r}")
|
|
|
|
|
|
self.pruefmanager.zeige_hinweis("Vorlage anlegen", f"Die Vorlage konnte nicht angelegt werden: {exc}")
|
|
|
|
|
|
return {"ok": False, "switch_to_tab_a": False, "atlas_seiten": 0}
|
|
|
|
|
|
|
2026-03-20 12:43:01 +01:00
|
|
|
|
return {"ok": True, "switch_to_tab_a": False, "atlas_seiten": 1}
|
|
|
|
|
|
|
|
|
|
|
|
# ─── 8. Atlas: Anzahl Seiten berechnen ────────────────────────────
|
|
|
|
|
|
# Nutzbarer Kartenbereich pro Atlasseite (abzüglich gleichem Randabstand)
|
|
|
|
|
|
seite_karte_w = ziel_w - 210.0
|
|
|
|
|
|
seite_karte_h = ziel_h - 20.0
|
|
|
|
|
|
|
|
|
|
|
|
if seite_karte_w <= 0 or seite_karte_h <= 0:
|
|
|
|
|
|
self.pruefmanager.zeige_hinweis(
|
|
|
|
|
|
"Blattgröße zu klein",
|
|
|
|
|
|
"Die gewählte Zielgröße ist kleiner als der Mindest-Randabstand. "
|
|
|
|
|
|
"Bitte eine größere Blattgröße wählen.",
|
|
|
|
|
|
)
|
|
|
|
|
|
return {"ok": False, "switch_to_tab_a": False, "atlas_seiten": 0}
|
|
|
|
|
|
|
|
|
|
|
|
pages_x = math.ceil(kartenbild_w / seite_karte_w)
|
|
|
|
|
|
pages_y = math.ceil(kartenbild_h / seite_karte_h)
|
|
|
|
|
|
anzahl_seiten = pages_x * pages_y
|
|
|
|
|
|
|
|
|
|
|
|
ja = self.pruefmanager.frage_ja_nein(
|
|
|
|
|
|
"Ausdruck als Atlas anlegen?",
|
|
|
|
|
|
f"Für die ausgewählten Parameter sind {anzahl_seiten} Einzelseiten erforderlich.\n"
|
|
|
|
|
|
"Ausdruck als Atlas anlegen?",
|
|
|
|
|
|
default=True,
|
|
|
|
|
|
)
|
|
|
|
|
|
if not ja:
|
|
|
|
|
|
return {"ok": False, "switch_to_tab_a": False, "atlas_seiten": anzahl_seiten}
|
|
|
|
|
|
|
|
|
|
|
|
return {"ok": True, "switch_to_tab_a": False, "atlas_seiten": anzahl_seiten}
|