Druckbereich und Layoutkarte im KBS des Verfahrensgebiets (#99) #107

Merged
Daniel merged 1 commits from bugfix/99-druck-kbs into unstable 2026-10-05 20:23:45 +00:00
7 changed files with 363 additions and 8 deletions
+2
View File
@@ -1,3 +1,5 @@
- Bugfix: War ein anderes Projekt-KBS als das des Verfahrensgebiets eingestellt (z. B. EPSG:3857 statt 25833), wurde das Drucklayout mit leerer Karte und falschen Koordinaten erstellt. Die Layoutkarte steht jetzt immer im KBS des Verfahrensgebiet-Layers (ohne Verfahrensgebiet im Projekt-KBS); alle Druckbereiche (Verfahrensgebiet, Auswahl, Rechteck, wie Kartenfenster) werden dorthin umgerechnet. Auch das gezeichnete Druckrechteck wird in das KBS seines Layers umgerechnet (#99)
- Neue allgemeine Funktionen `qgiscore_wrapper.transformiere_rechteck` (Rechteck zwischen zwei KBS umrechnen) und `qgisui_wrapper.zoom_auf_layer` (Kartenansicht auf einen Layer zoomen, mit Umrechnung ins KBS der Kartenansicht) (#99)
- Bugfix: Ein langer Tab (z. B. der Druck-Tab mit aufgeklapptem Basemap-Bereich) schob den unteren Rand des QGIS-Fensters über den Bildschirm hinaus, statt einen Scrollbalken zu zeigen. Jeder Tab der LNO-Docks liegt jetzt in einem Scroll-Bereich; das gilt auch für Fachplugins, die ihre Tabs selbst aufbauen (Plan41, Verfahrensgebiet), ohne dass sie geändert werden mussten (#104)
- Basemap-Bereich im Druck-Tab: neuer Abschnitt „Basemap-Layer“ mit Knopf „Basemap hinzufügen“ und Auswahl „Thema“ (Farbe, Grau; Standard Farbe). Liegt schon ein Layer mit derselben Quell-URL im Projekt, nennt eine Rückfrage ihn und bietet „Zusätzlich laden“, „Ersetzen“ (vorhandenen Layer im gewählten Thema neu laden, Position und Bezüge in Layouts bleiben) und „Abbrechen“. Die Themenauswahl stellt den im Layerbaum ausgewählten Basemap-Layer um (sonst den ersten). Vor dem Überschreiben der Darstellung wird geprüft, ob sie seit dem Laden des Themas oder Stils verändert wurde (Prüfwert als Layer-Eigenschaft); dann „Als Stil speichern …“, „Verwerfen“ oder „Abbrechen“ (#100)
- Stilvorlagen des Basemap-Layers vermerken ihr Thema; Laden, Speichern und „Punktlinien korrigieren“ wirken auf den im Layerbaum ausgewählten Basemap-Layer, sonst wie bisher auf den ersten (#100)
+46
View File
@@ -373,12 +373,21 @@ except Exception:
self.follow_visibility_preset_name = ""
self.keep_layer_set = False
self._grids = _MockQgsLayoutItemMapGridStack(self)
self._crs = None
self.crs_vor_extent = None # war das KBS gesetzt, als die Ausdehnung kam?
def setId(self, item_id: str) -> None:
self.item_id = item_id
def setCrs(self, crs: Any) -> None:
self._crs = crs
def crs(self) -> Any:
return self._crs
def setExtent(self, extent: Any) -> None:
self.extent = extent
self.crs_vor_extent = self._crs is not None
def setScale(self, scale: float) -> None:
self.scale = scale
@@ -1247,6 +1256,43 @@ def get_layer_extent(layer: Any) -> Any:
return None
def _crs_kennung(crs: Any) -> str:
authid = getattr(crs, "authid", None)
try:
return str(authid() or "") if callable(authid) else ""
except Exception:
return ""
def _crs_gueltig(crs: Any) -> bool:
if crs is None:
return False
is_valid = getattr(crs, "isValid", None)
try:
return bool(is_valid()) if callable(is_valid) else bool(_crs_kennung(crs))
except Exception:
return False
def transformiere_rechteck(rechteck: Any, quell_crs: Any, ziel_crs: Any, project: Any = None) -> Any:
"""Rechnet ein Rechteck (z. B. eine Layer-Ausdehnung) von ``quell_crs`` nach ``ziel_crs`` um (Basis #99).
Ausdehnungen von Layern stehen im KBS des Layers, Kartenansicht und Layoutkarte rechnen im
eigenen KBS. Unverändert zurück kommt das Rechteck, wenn es fehlt, eines der KBS fehlt oder
ungültig ist, beide gleich sind oder die Umrechnung scheitert.
"""
if rechteck is None or not _crs_gueltig(quell_crs) or not _crs_gueltig(ziel_crs):
return rechteck
quelle, ziel = _crs_kennung(quell_crs), _crs_kennung(ziel_crs)
if quelle and quelle == ziel:
return rechteck
try:
if project is None:
project = QgsProject.instance()
return QgsCoordinateTransform(quell_crs, ziel_crs, project).transformBoundingBox(rechteck)
except Exception:
return rechteck
# ---------------------------------------------------------
# Buffer-Layer erzeugen
# ---------------------------------------------------------
+22 -1
View File
@@ -8,7 +8,7 @@ from typing import Any, List, Type
from sn_basis.functions.qt_wrapper import QDockWidget
from sn_basis.functions.qgiscore_wrapper import QgsProject, QGIS_AVAILABLE
from sn_basis.functions.qgiscore_wrapper import QgsProject, QGIS_AVAILABLE, transformiere_rechteck
iface: Any
@@ -219,6 +219,27 @@ def remove_toolbar(toolbar: Any) -> None:
# Layer zum Projekt hinzufügen
# ---------------------------------------------------------
def zoom_auf_layer(layer: Any, canvas: Any = None) -> bool:
"""Zoomt die Kartenansicht auf den Layer; die Ausdehnung wird in das KBS der Kartenansicht umgerechnet.
``layer.extent()`` steht im KBS des Layers. Direkt an ``setExtent`` übergeben, landet der
Sprung an der falschen Stelle, sobald das Projekt-KBS ein anderes ist (Basis #99).
Gibt ``False`` zurück, wenn Layer oder Kartenansicht fehlen oder das Zoomen scheitert.
"""
if canvas is None:
map_canvas = getattr(iface, "mapCanvas", None)
canvas = map_canvas() if callable(map_canvas) else None
if layer is None or canvas is None:
return False
try:
ziel_crs = canvas.mapSettings().destinationCrs()
canvas.setExtent(transformiere_rechteck(layer.extent(), layer.crs(), ziel_crs))
canvas.refresh()
return True
except Exception:
return False
def get_active_layer() -> Any:
"""Im Layerbaum ausgewählter Layer oder ``None`` (Mock-Modus, kein Layer gewählt)."""
try:
+10
View File
@@ -982,6 +982,7 @@ class PrintLayout:
thema: str = "",
fit_extent_to_map: bool = True,
basemap_legende: bool = False,
crs: Any = None,
) -> Any:
layout_manager = self.project.layoutManager()
existing_layout = layout_manager.layoutByName(name)
@@ -1011,6 +1012,15 @@ class PrintLayout:
map_height_mm,
)
if crs is not None:
# Vor setExtent: die Ausdehnung steht im Druck-KBS, nicht im Projekt-KBS (Basis #99)
set_crs = getattr(hauptkarte, "setCrs", None)
if callable(set_crs):
try:
set_crs(crs)
except Exception:
pass
fitted_extent = extent
if fit_extent_to_map:
fitted_extent = self._fit_extent_to_map_item(extent, map_width_mm, map_height_mm)
+10
View File
@@ -98,6 +98,7 @@ class PrintLayoutBaufreigabe(PrintLayout):
thema: str = "",
fit_extent_to_map: bool = True,
atlas_driven: bool = True,
crs: Any = None,
) -> Any:
"""Erstellt ein Baufreigabe-Layout mit fester DIN A3/A4 Querformat-Größe.
@@ -155,6 +156,15 @@ class PrintLayoutBaufreigabe(PrintLayout):
map_height_mm,
)
if crs is not None:
# Vor setExtent: die Ausdehnung steht im Druck-KBS, nicht im Projekt-KBS (Basis #99)
set_crs = getattr(hauptkarte, "setCrs", None)
if callable(set_crs):
try:
set_crs(crs)
except Exception:
pass
fitted_extent = extent
if fit_extent_to_map:
fitted_extent = self._fit_extent_to_map_item(extent, map_width_mm, map_height_mm)
+66 -7
View File
@@ -6,7 +6,7 @@ from __future__ import annotations
import importlib
from typing import Any, cast, TypedDict
from sn_basis.functions.qgiscore_wrapper import QgsProject, get_layer_extent
from sn_basis.functions.qgiscore_wrapper import QgsProject, get_layer_extent, transformiere_rechteck
from sn_basis.functions.qgisui_wrapper import iface
from sn_basis.functions.variable_wrapper import get_variable, set_variable
from sn_basis.modules.layerpruefer import Layerpruefer
@@ -630,8 +630,12 @@ class PrintLogic:
)
return False
def _store_druckrechteck(self, layer: object, rectangle: Any) -> bool:
"""Test ausgesetzt, zunächst Refactor"""
def _store_druckrechteck(self, layer: object, rectangle: Any, quell_crs: Any = None) -> bool:
"""Test ausgesetzt, zunächst Refactor
``quell_crs``: KBS, in dem das Rechteck gezeichnet wurde (Kartenansicht); es wird in das
KBS des Druckrechteck-Layers umgerechnet (Basis #99).
"""
qgs_feature = self._import_qgis_symbol("qgis.core", "QgsFeature")
qgs_geometry = self._import_qgis_symbol("qgis.core", "QgsGeometry")
if qgs_feature is None or qgs_geometry is None:
@@ -640,6 +644,9 @@ class PrintLogic:
if layer is None or rectangle is None:
return False
if quell_crs is not None:
rectangle = transformiere_rechteck(rectangle, quell_crs, self._layer_crs(layer))
data_provider = getattr(layer, "dataProvider", lambda: None)()
if data_provider is None:
return False
@@ -760,7 +767,7 @@ class PrintLogic:
"Das gezeichnete Rechteck ist ungültig.",
)
else:
if logic._store_druckrechteck(layer, rectangle):
if logic._store_druckrechteck(layer, rectangle, logic._canvas_crs()):
logic.pruefmanager.zeige_hinweis(
"Druckrechteck",
"Das Druckrechteck wurde übernommen.",
@@ -932,12 +939,56 @@ class PrintLogic:
return extent
@staticmethod
def _layer_crs(layer: object | None) -> Any | None:
crs_fn = getattr(layer, "crs", None)
if not callable(crs_fn):
return None
try:
return crs_fn()
except Exception:
return None
def _canvas_crs(self) -> Any | None:
"""KBS der Kartenansicht, sonst das Projekt-KBS."""
try:
return iface.mapCanvas().mapSettings().destinationCrs()
except Exception:
pass
try:
return QgsProject.instance().crs()
except Exception:
return None
def _druck_crs(self, resolved_layer: object | None) -> Any | None:
"""KBS der Layoutkarte: das des Verfahrensgebiet-Layers, ohne diesen das Projekt-KBS (Basis #99).
Unabhängig vom Projekt-KBS stehen Koordinaten am Kartenrand, Gitter und Maßstab damit
im amtlichen KBS des Verfahrens (in Sachsen EPSG:25833).
"""
crs = self._layer_crs(resolved_layer)
is_valid = getattr(crs, "isValid", None)
if crs is not None and (not callable(is_valid) or is_valid()):
return crs
try:
return QgsProject.instance().crs()
except Exception:
return None
def _resolve_extent(
self,
resolved_layer: object | None,
druckbereich_auswahl: str,
plotmassstab: float,
druck_crs: Any = None,
) -> tuple[Any | None, object | None]:
"""Ausdehnung des Druckbereichs; mit ``druck_crs`` in dieses KBS umgerechnet (Basis #99)."""
def _in_druck_crs(extent: Any, quell_crs: Any) -> Any:
if druck_crs is None:
return extent
return transformiere_rechteck(extent, quell_crs, druck_crs)
if druckbereich_auswahl == DRUCKBEREICH_WIE_KARTENFENSTER:
extent = self._get_canvas_extent()
if extent is None:
@@ -946,7 +997,7 @@ class PrintLogic:
"Das aktuelle Kartenfenster liefert keine gültige Ausdehnung.",
)
return None, None
return extent, None
return _in_druck_crs(extent, self._canvas_crs()), None
if druckbereich_auswahl == DRUCKBEREICH_AKTUELLE_AUSWAHL:
selection_layer = self._resolve_selection_layer(resolved_layer)
@@ -957,6 +1008,7 @@ class PrintLogic:
"Auf dem aktuellen Layer sind keine gültigen Objekte ausgewählt.",
)
return None, None
extent = _in_druck_crs(extent, self._layer_crs(selection_layer))
return self._buffer_extent(extent, plotmassstab), None
if druckbereich_auswahl == DRUCKBEREICH_RECHTECK:
@@ -964,7 +1016,8 @@ class PrintLogic:
if extent is None:
self.activate_druckrechteck_capture(resolved_layer)
return None, None
return extent, None
rechteck_layer = self._get_existing_layer_by_name(DRUCKRECHTECK_LAYER_NAME)
return _in_druck_crs(extent, self._layer_crs(rechteck_layer) or druck_crs), None
lp = Layerpruefer(layer=resolved_layer)
ergebnis = lp.pruefe()
@@ -979,6 +1032,7 @@ class PrintLogic:
if extent is None:
self.pruefmanager.zeige_hinweis("Fehler", "Layer-Ausdehnung konnte nicht ermittelt werden.")
return None, None
extent = _in_druck_crs(extent, self._layer_crs(resolved_layer))
return self._buffer_extent(extent, plotmassstab), resolved_layer
def set_kartenname_for_auswahl(self, auswahl: str) -> None:
@@ -1233,7 +1287,10 @@ class PrintLogic:
self.pruefmanager.zeige_hinweis("Maßstab fehlt", "Kein gültiger Maßstab angegeben.")
return self._failed_result()
extent, layer_for_extent = self._resolve_extent(resolved_layer, druckbereich_auswahl, massstab_zahl)
druck_crs = self._druck_crs(resolved_layer)
extent, layer_for_extent = self._resolve_extent(
resolved_layer, druckbereich_auswahl, massstab_zahl, druck_crs=druck_crs
)
if extent is None:
return self._failed_result()
@@ -1320,6 +1377,7 @@ class PrintLogic:
thema=thema,
fit_extent_to_map=True,
atlas_driven=atlas_erzeugen_bf,
crs=druck_crs,
)
else:
# Standard-Layout: dynamische Größenanpassung
@@ -1335,6 +1393,7 @@ class PrintLogic:
thema=thema,
fit_extent_to_map=(druckbereich_auswahl != DRUCKBEREICH_VERFAHRENSGEBIET) or force_fit_extent_for_min_a4,
basemap_legende=self._basemap_legende_erzeugen(kartenname_auswahl),
crs=druck_crs,
)
except ValueError as exc:
self.pruefmanager.zeige_hinweis("Vorlage anlegen", str(exc))
+207
View File
@@ -0,0 +1,207 @@
"""
Tests zu Basis #99: Ist das Projekt-KBS ein anderes als das KBS des Verfahrensgebiets, müssen
Ausdehnungen umgerechnet werden – beim Zoom auf einen Layer, beim Druckbereich und beim
gezeichneten Druckrechteck. Die Layoutkarte steht im KBS des Verfahrensgebiets.
Die Umrechnung selbst (QgsCoordinateTransform) ist im Mock-Modus ein Ersatz; geprüft wird,
dass zwischen den richtigen KBS umgerechnet wird.
"""
import unittest
from unittest.mock import MagicMock, patch
from sn_basis.functions import qgiscore_wrapper as core
from sn_basis.functions.qgiscore_wrapper import QgsLayoutItemMap, QgsProject, transformiere_rechteck
from sn_basis.functions.qgisui_wrapper import zoom_auf_layer
from sn_basis.modules.print_layout import PrintLayout
from sn_basis.modules.print_logic import (
DRUCKBEREICH_AKTUELLE_AUSWAHL,
DRUCKBEREICH_WIE_KARTENFENSTER,
PrintLogic,
)
class _Crs:
def __init__(self, authid, gueltig=True):
self._authid, self._gueltig = authid, gueltig
def authid(self): return self._authid
def isValid(self): return self._gueltig
def __repr__(self): return self._authid
class _Rechteck:
def __init__(self, name="R", breite=1000.0, hoehe=800.0):
self.name, self._b, self._h = name, breite, hoehe
def width(self): return self._b
def height(self): return self._h
def isNull(self): return False
def xMinimum(self): return 0.0
def yMinimum(self): return 0.0
def xMaximum(self): return self._b
def yMaximum(self): return self._h
def buffered(self, d): return self
def __repr__(self): return self.name
UTM33 = _Crs("EPSG:25833")
WGS84 = _Crs("EPSG:4326")
PSEUDO_MERCATOR = _Crs("EPSG:3857")
def _umrechnung(protokoll):
"""Ersatz für transformiere_rechteck, der jede Umrechnung protokolliert und ein neues Rechteck liefert."""
def umrechnen(rechteck, quelle, ziel, project=None):
protokoll.append((rechteck, quelle, ziel))
return _Rechteck(f"{rechteck}->{ziel}")
return umrechnen
class TestTransformiereRechteck(unittest.TestCase):
"""Umrechnung eines Rechtecks zwischen zwei KBS."""
def test_verschiedene_kbs_werden_umgerechnet(self):
"""Prüft, dass ein Rechteck bei verschiedenen KBS mit QgsCoordinateTransform von Quell- nach Ziel-KBS umgerechnet wird."""
projekt = object()
with patch.object(core, "QgsCoordinateTransform") as transform:
transform.return_value.transformBoundingBox.return_value = "umgerechnet"
ergebnis = transformiere_rechteck("rechteck", UTM33, WGS84, projekt)
transform.assert_called_once_with(UTM33, WGS84, projekt)
transform.return_value.transformBoundingBox.assert_called_once_with("rechteck")
self.assertEqual(ergebnis, "umgerechnet")
def test_gleiches_fehlendes_oder_ungueltiges_kbs_laesst_rechteck_unveraendert(self):
"""Prüft, dass bei gleichem, fehlendem oder ungültigem KBS nicht umgerechnet und das Rechteck unverändert geliefert wird."""
rechteck = _Rechteck()
with patch.object(core, "QgsCoordinateTransform") as transform:
self.assertIs(transformiere_rechteck(rechteck, UTM33, _Crs("EPSG:25833")), rechteck)
self.assertIs(transformiere_rechteck(rechteck, None, UTM33), rechteck)
self.assertIs(transformiere_rechteck(rechteck, UTM33, _Crs("", gueltig=False)), rechteck)
self.assertIsNone(transformiere_rechteck(None, UTM33, WGS84))
transform.assert_not_called()
def test_fehler_bei_der_umrechnung_liefert_das_rechteck(self):
"""Prüft, dass ein Fehler bei der Umrechnung nicht durchschlägt, sondern das ursprüngliche Rechteck zurückkommt."""
rechteck = _Rechteck()
with patch.object(core, "QgsCoordinateTransform", side_effect=RuntimeError("kaputt")):
self.assertIs(transformiere_rechteck(rechteck, UTM33, WGS84, object()), rechteck)
class TestZoomAufLayer(unittest.TestCase):
"""Zoom der Kartenansicht auf einen Layer in einem anderen KBS."""
def test_ausdehnung_wird_ins_kbs_der_kartenansicht_umgerechnet(self):
"""Prüft, dass zoom_auf_layer die Layer-Ausdehnung vom Layer-KBS in das KBS der Kartenansicht umrechnet, bevor gezoomt wird."""
layer = MagicMock()
layer.extent.return_value = _Rechteck("VG")
layer.crs.return_value = UTM33
canvas = MagicMock()
canvas.mapSettings.return_value.destinationCrs.return_value = PSEUDO_MERCATOR
protokoll = []
with patch("sn_basis.functions.qgisui_wrapper.transformiere_rechteck", side_effect=_umrechnung(protokoll)):
self.assertTrue(zoom_auf_layer(layer, canvas))
self.assertEqual([(r.name, q, z) for r, q, z in protokoll], [("VG", UTM33, PSEUDO_MERCATOR)])
self.assertEqual(canvas.setExtent.call_args[0][0].name, "VG->EPSG:3857")
canvas.refresh.assert_called_once()
def test_ohne_layer_oder_kartenansicht_kein_zoom(self):
"""Prüft, dass zoom_auf_layer ohne Layer oder ohne Kartenansicht nichts tut und False liefert."""
canvas = MagicMock()
self.assertFalse(zoom_auf_layer(None, canvas))
canvas.setExtent.assert_not_called()
self.assertFalse(zoom_auf_layer(MagicMock(), None)) # Mock-iface hat keine Kartenansicht
class TestDruckKbs(unittest.TestCase):
"""KBS der Layoutkarte und Umrechnung der Druckbereiche."""
def setUp(self):
self.logic = PrintLogic(pruefmanager=MagicMock())
self.vg = MagicMock()
self.vg.crs.return_value = UTM33
def test_druck_kbs_ist_das_kbs_des_verfahrensgebiets(self):
"""Prüft, dass die Layoutkarte im KBS des Verfahrensgebiet-Layers steht und ohne Verfahrensgebiet das Projekt-KBS gilt."""
self.assertIs(self.logic._druck_crs(self.vg), UTM33)
with patch("sn_basis.modules.print_logic.QgsProject") as projekt:
projekt.instance.return_value.crs.return_value = WGS84
self.assertIs(self.logic._druck_crs(None), WGS84)
ungueltig = MagicMock()
ungueltig.crs.return_value = _Crs("", gueltig=False)
self.assertIs(self.logic._druck_crs(ungueltig), WGS84)
def test_kartenfenster_wird_vom_kbs_der_kartenansicht_umgerechnet(self):
"""Prüft, dass der Druckbereich „wie Kartenfenster“ vom KBS der Kartenansicht in das Druck-KBS umgerechnet wird."""
protokoll = []
with patch.object(PrintLogic, "_get_canvas_extent", return_value=_Rechteck("Fenster")), \
patch.object(PrintLogic, "_canvas_crs", return_value=PSEUDO_MERCATOR), \
patch("sn_basis.modules.print_logic.transformiere_rechteck", side_effect=_umrechnung(protokoll)):
extent, _ = self.logic._resolve_extent(self.vg, DRUCKBEREICH_WIE_KARTENFENSTER, 5000.0, druck_crs=UTM33)
self.assertEqual([(r.name, q, z) for r, q, z in protokoll], [("Fenster", PSEUDO_MERCATOR, UTM33)])
self.assertEqual(extent.name, "Fenster->EPSG:25833")
def test_auswahl_wird_vor_dem_puffern_vom_layer_kbs_umgerechnet(self):
"""Prüft, dass der Druckbereich „Auswahl“ aus dem KBS des Auswahl-Layers umgerechnet und erst danach gepuffert wird."""
auswahl_layer = MagicMock()
auswahl_layer.crs.return_value = WGS84
protokoll = []
with patch.object(PrintLogic, "_resolve_selection_layer", return_value=auswahl_layer), \
patch.object(PrintLogic, "_get_selected_extent", return_value=_Rechteck("Auswahl")), \
patch.object(PrintLogic, "_buffer_extent", side_effect=lambda e, m: e) as puffer, \
patch("sn_basis.modules.print_logic.transformiere_rechteck", side_effect=_umrechnung(protokoll)):
extent, _ = self.logic._resolve_extent(self.vg, DRUCKBEREICH_AKTUELLE_AUSWAHL, 5000.0, druck_crs=UTM33)
self.assertEqual([(r.name, q, z) for r, q, z in protokoll], [("Auswahl", WGS84, UTM33)])
self.assertEqual(puffer.call_args[0][0].name, "Auswahl->EPSG:25833")
self.assertEqual(extent.name, "Auswahl->EPSG:25833")
def test_ohne_druck_kbs_wird_nicht_umgerechnet(self):
"""Prüft, dass _resolve_extent ohne Druck-KBS wie bisher nicht umrechnet (Aufrufe ohne den neuen Parameter)."""
fenster = _Rechteck("Fenster")
with patch.object(PrintLogic, "_get_canvas_extent", return_value=fenster), \
patch("sn_basis.modules.print_logic.transformiere_rechteck") as umrechnen:
extent, _ = self.logic._resolve_extent(None, DRUCKBEREICH_WIE_KARTENFENSTER, 5000.0)
umrechnen.assert_not_called()
self.assertIs(extent, fenster)
def test_druckrechteck_wird_ins_kbs_seines_layers_umgerechnet(self):
"""Prüft, dass ein in der Kartenansicht gezeichnetes Druckrechteck vor dem Speichern in das KBS des Druckrechteck-Layers umgerechnet wird."""
layer = MagicMock()
layer.crs.return_value = UTM33
geometrie = MagicMock()
protokoll = []
def symbol(modul, name):
return {"QgsFeature": MagicMock, "QgsGeometry": geometrie}.get(name)
with patch.object(PrintLogic, "_import_qgis_symbol", side_effect=symbol), \
patch.object(PrintLogic, "_clear_layer_features"), \
patch("sn_basis.modules.print_logic.set_variable"), \
patch("sn_basis.modules.print_logic.transformiere_rechteck", side_effect=_umrechnung(protokoll)):
self.assertTrue(self.logic._store_druckrechteck(layer, _Rechteck("Gezeichnet"), PSEUDO_MERCATOR))
self.assertEqual([(r.name, q, z) for r, q, z in protokoll], [("Gezeichnet", PSEUDO_MERCATOR, UTM33)])
self.assertEqual(geometrie.fromRect.call_args[0][0].name, "Gezeichnet->EPSG:25833")
class TestLayoutkarteImDruckKbs(unittest.TestCase):
"""Die Layoutkarte bekommt das Druck-KBS, bevor die Ausdehnung gesetzt wird."""
@patch("sn_basis.modules.print_layout.open_layout_designer")
def test_hauptkarte_bekommt_das_kbs_vor_der_ausdehnung(self, _designer):
"""Prüft, dass die Hauptkarte eines neuen Layouts das Druck-KBS erhält, bevor ihre Ausdehnung gesetzt wird."""
layout = PrintLayout(project=QgsProject.instance()).create_single_page_layout(
name="KBS-Test",
page_width_mm=420.0,
page_height_mm=297.0,
map_width_mm=200.0,
map_height_mm=150.0,
extent=_Rechteck(),
plotmassstab=5000.0,
crs=UTM33,
)
hauptkarte = next(item for item in layout.items if isinstance(item, QgsLayoutItemMap))
self.assertIs(hauptkarte.crs(), UTM33)
self.assertTrue(hauptkarte.crs_vor_extent)
if __name__ == "__main__":
unittest.main()