diff --git a/arho_feature_template/core/plan_regulation_config.py b/arho_feature_template/core/plan_regulation_config.py
index 0221cf3..dd00842 100644
--- a/arho_feature_template/core/plan_regulation_config.py
+++ b/arho_feature_template/core/plan_regulation_config.py
@@ -2,7 +2,7 @@
import logging
import os
-from dataclasses import dataclass
+from dataclasses import dataclass, field
from enum import Enum
from pathlib import Path
from typing import TYPE_CHECKING, cast
@@ -14,6 +14,7 @@
from arho_feature_template.qgis_plugin_tools.tools.resources import resources_path
if TYPE_CHECKING:
+ from numbers import Number
from typing import Literal
from qgis.core import QgsMapLayer
@@ -34,10 +35,11 @@ def __init__(self, message: str):
class UninitializedError(Exception):
def __init__(self):
- super().__init__("PlanRegulationsSet is not initialized. Call 'load_config' first")
+ super().__init__("PlanRegulationsSet is not initialized. Call 'initialize' first")
class ValueType(Enum):
+ DECIMAL = "desimaali"
POSITIVE_DECIMAL = "positiivinen desimaali"
POSITIVE_INTEGER = "positiivinen kokonaisluku"
POSITIVE_INTEGER_RANGE = "positiivinen kokonaisluku arvoväli"
@@ -50,6 +52,8 @@ class Unit(Enum):
EFFICIENCY_RATIO = "k-m2/m2"
PERCENTAGE = "prosentti"
AREA_RATIO = "m2/k-m2"
+ DEGREES = "°"
+ DECIBEL = "dB"
# TODO: Same as in PlanManager, should refactor
@@ -75,6 +79,7 @@ class PlanRegulationsSet:
version: str
regulations: list[PlanRegulationConfig]
+ regulations_dict: dict[str, PlanRegulationConfig] = field(default_factory=dict)
_instance: PlanRegulationsSet | None = None
@@ -87,9 +92,18 @@ def get_instance(cls) -> PlanRegulationsSet:
@classmethod
def get_regulations(cls) -> list[PlanRegulationConfig]:
- """Get the list of regulation configs, if instance is initialized."""
- instance = cls.get_instance()
- return instance.regulations
+ """Get the list of top-level regulation configs, if instance is initialized."""
+ return cls.get_instance().regulations
+
+ @classmethod
+ def get_regulations_dict(cls) -> dict[str, PlanRegulationConfig]:
+ """Get all regulations in a dictionary where keys are regulations codes and values PlanRegulationConfigs."""
+ return cls.get_instance().regulations_dict
+
+ @classmethod
+ def get_regulation_by_code(cls, regulation_code: str) -> PlanRegulationConfig | None:
+ """Get a regulation by it's regulation code (if exists)."""
+ return cls.get_instance().regulations_dict.get(regulation_code)
@classmethod
def initialize(
@@ -103,12 +117,17 @@ def initialize(
data = yaml.safe_load(f)
cls._instance = cls.from_dict(data)
- # Add names from plan regulation layer
+ regulations = cls.get_regulations()
+ regulations_dict: dict[str, PlanRegulationConfig] = {}
mapping = get_name_mapping_for_plan_regulations(type_of_plan_regulations_layer_name)
- if mapping:
- for regulation in cls.get_regulations():
+
+ # Add names to dictionary, add names to regulations
+ for regulation in regulations:
+ regulation.add_to_dictionary(regulations_dict)
+ if mapping:
regulation.add_name(mapping, language)
+ cls._instance.regulations_dict = regulations_dict
logger.info("PlanRegulationsSet initialized successfully.")
return cls._instance
@@ -156,3 +175,29 @@ def add_name(self, code_to_name_mapping: dict[str, dict[str, str]], language: Li
self.name = language_to_name_dict[language] if language_to_name_dict else self.regulation_code
for regulation in self.child_regulations:
regulation.add_name(code_to_name_mapping, language)
+
+ def add_to_dictionary(self, dictionary: dict[str, PlanRegulationConfig]):
+ dictionary[self.regulation_code] = self
+ for regulation in self.child_regulations:
+ regulation.add_to_dictionary(dictionary)
+
+
+@dataclass
+class PlanRegulationDefinition:
+ """Associates a PlanRegulationConfig with an optional default value and additional data."""
+
+ regulation_config: PlanRegulationConfig
+ default_value: str | Number | None
+ additional_info: dict[str, str | Number | None] # NOTE: Correct typing for additional information values?
+ regulation_number: int | None
+ attached_files: list[Path]
+
+ @classmethod
+ def from_dict(cls, data: dict) -> PlanRegulationDefinition:
+ return cls(
+ regulation_config=data["config"],
+ default_value=data.get("default_value"),
+ additional_info=data.get("additional_info", {}),
+ regulation_number=data.get("regulation_number"),
+ attached_files=data.get("attached_files", []),
+ )
diff --git a/arho_feature_template/core/plan_regulation_group_config.py b/arho_feature_template/core/plan_regulation_group_config.py
new file mode 100644
index 0000000..0d455eb
--- /dev/null
+++ b/arho_feature_template/core/plan_regulation_group_config.py
@@ -0,0 +1,118 @@
+from __future__ import annotations
+
+import logging
+from dataclasses import dataclass
+from typing import TYPE_CHECKING, cast
+
+import yaml
+from qgis.utils import iface
+
+from arho_feature_template.core.plan_regulation_config import PlanRegulationDefinition, PlanRegulationsSet
+
+if TYPE_CHECKING:
+ from pathlib import Path
+
+ from qgis.gui import QgisInterface
+
+ iface: QgisInterface = cast("QgisInterface", iface) # type: ignore[no-redef]
+
+logger = logging.getLogger(__name__)
+
+
+class ConfigSyntaxError(Exception):
+ def __init__(self, message: str):
+ super().__init__(f"Invalid config syntax: {message}")
+
+
+@dataclass
+class PlanRegulationGroupLibrary:
+ """Describes the configuration of a plan regulation group library"""
+
+ meta: PlanRegulationGroupLibraryMeta
+ plan_regulation_group_categories: list[PlanRegulationGroupCategory]
+
+ @classmethod
+ def from_dict(cls, data: dict) -> PlanRegulationGroupLibrary:
+ try:
+ return cls(
+ meta=PlanRegulationGroupLibraryMeta.from_dict(data["meta"]),
+ plan_regulation_group_categories=[
+ PlanRegulationGroupCategory.from_dict(category) for category in data["categories"]
+ ],
+ )
+ except KeyError as e:
+ raise ConfigSyntaxError(str(e)) from e
+
+ @classmethod
+ def new_from_file(cls, fp: Path) -> PlanRegulationGroupLibrary:
+ with fp.open(encoding="utf-8") as f:
+ data = yaml.safe_load(f)
+ return PlanRegulationGroupLibrary.from_dict(data)
+
+
+@dataclass
+class PlanRegulationGroupLibraryMeta:
+ """Describes the metadata of a plan regulation group library"""
+
+ name: str
+ version: int | None
+ group: str | None
+ sub_group: str | None
+ description: str | None
+
+ @classmethod
+ def from_dict(cls, data: dict) -> PlanRegulationGroupLibraryMeta:
+ return cls(
+ name=data["name"],
+ version=data.get("version"),
+ group=data.get("group"),
+ sub_group=data.get("sub_group"),
+ description=data.get("description"),
+ )
+
+
+@dataclass
+class PlanRegulationGroupCategory:
+ category_code: str
+ name: str | None
+ plan_regulation_groups: list[PlanRegulationGroupDefinition]
+
+ @classmethod
+ def from_dict(cls, data: dict) -> PlanRegulationGroupCategory:
+ return cls(
+ category_code=data["category_code"],
+ name=data.get("name"),
+ plan_regulation_groups=[
+ PlanRegulationGroupDefinition.from_dict(group) for group in data["plan_regulation_groups"]
+ ],
+ )
+
+
+@dataclass
+class PlanRegulationGroupDefinition:
+ """Describes a plan regulation group"""
+
+ name: str
+ geometry: str
+ color_code: str | None
+ letter_code: str | None
+ plan_regulations: list[PlanRegulationDefinition]
+
+ @classmethod
+ def from_dict(cls, data: dict) -> PlanRegulationGroupDefinition:
+ regulations = []
+ for reg_data in data["plan_regulations"]:
+ reg_code = reg_data["regulation_code"]
+ config = PlanRegulationsSet.get_regulation_by_code(reg_code)
+ if config:
+ reg_data["config"] = config
+ regulations.append(PlanRegulationDefinition.from_dict(reg_data))
+ else:
+ iface.messageBar().pushWarning("", f"Could not find config for {reg_code} plan regulation!")
+ return cls(
+ name=data["name"],
+ geometry=data["geometry"],
+ color_code=data.get("color_code"),
+ letter_code=data.get("letter_code"),
+ plan_regulations=regulations,
+ )
diff --git a/arho_feature_template/gui/new_plan_regulation_group_form.py b/arho_feature_template/gui/new_plan_regulation_group_form.py
index e60516d..8d7c232 100644
--- a/arho_feature_template/gui/new_plan_regulation_group_form.py
+++ b/arho_feature_template/gui/new_plan_regulation_group_form.py
@@ -8,7 +8,7 @@
from qgis.PyQt.QtWidgets import QDialog, QTreeWidget, QTreeWidgetItem
from arho_feature_template.core.plan_regulation_config import PlanRegulationConfig, PlanRegulationsSet
-from arho_feature_template.gui.new_plan_regulation_widget import NewPlanRegulationWidget
+from arho_feature_template.gui.plan_regulation_widget import PlanRegulationWidget
if TYPE_CHECKING:
from qgis.PyQt.QtWidgets import QBoxLayout, QWidget
@@ -57,11 +57,11 @@ def add_selected_plan_regulation(self, item: QTreeWidgetItem, column: int):
self.add_plan_regulation(config)
def add_plan_regulation(self, config: PlanRegulationConfig):
- widget = NewPlanRegulationWidget(config=config, parent=self.plan_regulations_scroll_area_contents)
+ widget = PlanRegulationWidget(config=config, parent=self.plan_regulations_scroll_area_contents)
widget.delete_signal.connect(self.delete_plan_regulation)
index = self.plan_regulations_layout.count() - 1
self.plan_regulations_layout.insertWidget(index, widget)
- def delete_plan_regulation(self, plan_regulation_widget: NewPlanRegulationWidget):
+ def delete_plan_regulation(self, plan_regulation_widget: PlanRegulationWidget):
self.plan_regulations_layout.removeWidget(plan_regulation_widget)
plan_regulation_widget.deleteLater()
diff --git a/arho_feature_template/gui/new_plan_regulation_widget.py b/arho_feature_template/gui/new_plan_regulation_widget.py
deleted file mode 100644
index 383eda5..0000000
--- a/arho_feature_template/gui/new_plan_regulation_widget.py
+++ /dev/null
@@ -1,192 +0,0 @@
-from __future__ import annotations
-
-from collections import defaultdict
-from importlib import resources
-from typing import TYPE_CHECKING
-
-from qgis.core import QgsApplication
-from qgis.gui import QgsDoubleSpinBox, QgsFileWidget, QgsSpinBox
-from qgis.PyQt import uic
-from qgis.PyQt.QtCore import Qt, pyqtSignal
-from qgis.PyQt.QtWidgets import (
- QFormLayout,
- QHBoxLayout,
- QLabel,
- QLineEdit,
- QMenu,
- QSizePolicy,
- QTextEdit,
- QWidget,
-)
-
-from arho_feature_template.core.plan_regulation_config import PlanRegulationConfig, Unit, ValueType
-
-if TYPE_CHECKING:
- from numbers import Number
-
- from qgis.PyQt.QtWidgets import QPushButton
-
-ui_path = resources.files(__package__) / "new_plan_regulation_widget.ui"
-FormClass, _ = uic.loadUiType(ui_path)
-
-
-# Related layer and field names to save information later on
-LAYER_NAME = "Kaavamääräys"
-TYPE_OF_PLAN_REGULATION_KIND_FIELD = "type_of_plan_regulation_kind"
-NUMERIC_VALUE_FIELD = "numeric_value"
-TYPE_OF_VERBAL_PLAN_REGULATION_FIELD = "type_of_verbal_plan_regulation"
-UNIT_FIELD = "unit"
-TEXT_VALUE_FIELD = "text_value"
-REGULATION_TYPE_ADDITIONAL_INFORMATION_ID = "regulation_type_additional_information_id"
-
-
-class NewPlanRegulationWidget(QWidget, FormClass): # type: ignore
- """A widget representation of a plan regulation."""
-
- delete_signal = pyqtSignal(QWidget)
-
- def __init__(self, config: PlanRegulationConfig, parent=None):
- super().__init__(parent)
- self.setupUi(self)
-
- # TYPES
- self.plan_regulation_name: QLineEdit
- self.form_layout: QFormLayout
-
- self.add_additional_information_btn: QPushButton
- self.add_regulation_number_btn: QPushButton
- self.add_file_btn: QPushButton
- self.del_btn: QPushButton
-
- # INIT
- self.config = config
- self.regulation_number_added = False
- # Key is related field name, value is 1) widget, 2) tuple of widget and default value
- # NOTE: Maybe this is not something needed? Instead, when user clicks Ok, write into a YAML
- # in a separate script?
- self.attribute_widgets: dict[str, QWidget | tuple[QWidget, str | Number]] = defaultdict(dict)
- self.plan_regulation_name.setText(config.name)
- self.plan_regulation_name.setReadOnly(True)
- self.init_value_fields()
- self.init_buttons()
-
- def init_value_fields(self):
- layout = QHBoxLayout()
- value_type = self.config.value_type
- if value_type:
- self._add_value_input(value_type, layout)
-
- unit = self.config.unit
- if unit:
- self._add_value_unit(unit, layout)
-
- def _add_value_input(self, value_type: ValueType, layout: QHBoxLayout):
- if value_type == ValueType.POSITIVE_DECIMAL:
- self.add_positive_decimal_input(layout)
- elif value_type == ValueType.POSITIVE_INTEGER:
- self.add_positive_integer_input(layout)
- elif value_type == ValueType.POSITIVE_INTEGER_RANGE:
- self.add_positive_integer_range_input(layout)
- elif value_type == ValueType.VERSIONED_TEXT:
- self.add_versioned_text_input(layout)
- else:
- msg = f"Invalid input value type for plan regulation: {value_type}"
- raise ValueError(msg)
-
- def _add_value_unit(self, unit: Unit, layout: QHBoxLayout):
- # NOTE: Unit could also be suffix in the QgsSpinBox, could be clearer?
- unit_label = QLabel(unit.value)
- layout.addWidget(unit_label)
-
- def init_buttons(self):
- # DEL
- self.del_btn.setIcon(QgsApplication.getThemeIcon("mActionDeleteSelected.svg"))
- self.del_btn.clicked.connect(lambda: self.delete_signal.emit(self))
-
- # ADDITIONAL INFORMATION
- type_menu = QMenu("Tyyppi", self)
- type_menu_items = [
- "Pääkäyttötarkoitus",
- "Osa-alue",
- "Poisluettava käyttötarkoitus",
- "Väliaikainen määräys",
- "Vaihtoehtoinen",
- "Ohjeellinen sijainti",
- "Yhteystarve",
- ]
-
- for item in type_menu_items:
- action = type_menu.addAction(item)
- action.triggered.connect(lambda _, item=item: self.add_additional_info(item))
-
- signifigance_menu = QMenu("Merkittävyys", self)
- signifigance_menu_items = [
- "Kansainvälinen",
- "Valtakunnallinen",
- "Maakunnallinen",
- "Seudullinen",
- "Alueellinen",
- "Paikallinen",
- ]
-
- for item in signifigance_menu_items:
- action = signifigance_menu.addAction(item)
- action.triggered.connect(lambda _, item=item: self.add_additional_info(item))
-
- type_main_menu = QMenu(self)
- type_main_menu.addMenu(type_menu)
- type_main_menu.addMenu(signifigance_menu)
- self.add_additional_information_btn.setMenu(type_main_menu)
-
- # REGULATION NUMBER
- self.add_regulation_number_btn.clicked.connect(self.add_regulation_number)
-
- # ADD FILE
- self.add_file_btn.clicked.connect(self.add_file)
-
- def add_positive_decimal_input(self, layout: QHBoxLayout):
- value_widget = QgsDoubleSpinBox()
- value_widget.setMinimum(0.0)
- value_widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
- layout.addWidget(value_widget)
- self.form_layout.addRow("Desimaali (positiivinen)", layout)
-
- def add_positive_integer_input(self, layout: QHBoxLayout):
- value_widget = QgsSpinBox()
- value_widget.setMinimum(0)
- value_widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
- layout.addWidget(value_widget)
- self.form_layout.addRow("Kokonaisluku (positiivinen)", layout)
-
- def add_positive_integer_range_input(self, layout: QHBoxLayout):
- min_widget = QgsSpinBox()
- min_widget.setMinimum(0)
- max_widget = QgsSpinBox()
- max_widget.setMinimum(0)
- layout.addWidget(min_widget)
- dash_label = QLabel(" — ")
- dash_label.setAlignment(Qt.AlignCenter)
- dash_label.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed)
- layout.addWidget(dash_label)
- layout.addWidget(max_widget)
- self.form_layout.addRow("Kokonaisluku arvoväli (positiivinen)", layout)
-
- def add_versioned_text_input(self, layout: QHBoxLayout):
- text_widget = QTextEdit()
- layout.addWidget(text_widget)
- self.form_layout.addRow("Kieliversioitu teksti", layout)
-
- def add_additional_info(self, info_type):
- info_type_label = QLineEdit(info_type)
- info_type_label.setReadOnly(True)
- self.form_layout.addRow("Lisätiedonlaji", info_type_label)
-
- def add_regulation_number(self):
- if not self.regulation_number_added:
- number_widget = QgsSpinBox()
- self.form_layout.addRow("Määräysnumero", number_widget)
- self.regulation_number_added = True
-
- def add_file(self):
- file_input = QgsFileWidget()
- self.form_layout.addRow("Liiteasiakirja", file_input)
diff --git a/arho_feature_template/gui/new_plan_regulation_widget.ui b/arho_feature_template/gui/new_plan_regulation_widget.ui
deleted file mode 100644
index e6f5225..0000000
--- a/arho_feature_template/gui/new_plan_regulation_widget.ui
+++ /dev/null
@@ -1,145 +0,0 @@
-
-
- Form
-
-
-
- 0
- 0
- 694
- 108
-
-
-
- Form
-
-
- -
-
-
-
-
-
- Kaavamääräyslaji
-
-
-
- -
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 30
- 16777215
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- Lisätieto
-
-
-
- -
-
-
- Määräysnumero
-
-
-
- -
-
-
- Liiteasiakirja
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
-
- -
-
-
-
-
-
- Qt::Horizontal
-
-
- QSizePolicy::Fixed
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
-
- 0
- 20
-
-
-
- Qt::Horizontal
-
-
-
- -
-
-
- Qt::Horizontal
-
-
- QSizePolicy::Fixed
-
-
-
- 40
- 20
-
-
-
-
-
-
-
-
-
-
-
diff --git a/arho_feature_template/gui/plan_regulation_group_widget.py b/arho_feature_template/gui/plan_regulation_group_widget.py
index 5717327..850f210 100644
--- a/arho_feature_template/gui/plan_regulation_group_widget.py
+++ b/arho_feature_template/gui/plan_regulation_group_widget.py
@@ -13,7 +13,8 @@
if TYPE_CHECKING:
from qgis.PyQt.QtWidgets import QFrame, QLineEdit, QPushButton
- from arho_feature_template.core.template_library_config import Feature
+ from arho_feature_template.core.plan_regulation_config import PlanRegulationConfig
+ from arho_feature_template.core.plan_regulation_group_config import PlanRegulationGroupDefinition
ui_path = resources.files(__package__) / "plan_regulation_group_widget.ui"
FormClass, _ = uic.loadUiType(ui_path)
@@ -24,7 +25,7 @@ class PlanRegulationGroupWidget(QWidget, FormClass): # type: ignore
delete_signal = pyqtSignal(QWidget)
- def __init__(self, feature: Feature):
+ def __init__(self, group_definition: PlanRegulationGroupDefinition):
super().__init__()
self.setupUi(self)
@@ -34,31 +35,26 @@ def __init__(self, feature: Feature):
self.del_btn: QPushButton
# INIT
- self.feature = feature
- self.layer = self.feature.layer # Should be plan_regulation_group layer
+ self.group_definition = group_definition
+ self.layer = "plan_regulation_group"
+ self.heading.setText(self.group_definition.name)
self.init_buttons()
- self.set_group_heading()
- self.add_plan_regulation_widgets()
-
- def request_delete(self):
- self.delete_signal.emit(self)
+ for plan_regulation_definition in self.group_definition.plan_regulations:
+ config = plan_regulation_definition.regulation_config
+ widget = self.add_plan_regulation_widget(config)
+ widget.populate_from_definition(plan_regulation_definition)
def init_buttons(self):
self.del_btn.setIcon(QgsApplication.getThemeIcon("mActionDeleteSelected.svg"))
- self.del_btn.clicked.connect(self.request_delete)
-
- def set_group_heading(self):
- for attribute_config in self.feature.attributes:
- if attribute_config.attribute == "name":
- self.heading.setText(attribute_config.display())
-
- def add_plan_regulation_widgets(self):
- if self.feature.child_features is not None:
- for child in self.feature.child_features:
- if child.layer == "plan_requlation":
- self.add_plan_regulation_widget(child)
-
- def add_plan_regulation_widget(self, plan_regulation_feature: Feature):
- plan_regulation_widget = PlanRegulationWidget(plan_regulation_feature)
- self.frame.layout().addWidget(plan_regulation_widget)
+ self.del_btn.clicked.connect(lambda: self.delete_signal.emit(self))
+
+ def add_plan_regulation_widget(self, config: PlanRegulationConfig) -> PlanRegulationWidget:
+ widget = PlanRegulationWidget(config=config, parent=self.frame)
+ widget.delete_signal.connect(self.delete_plan_regulation_widget)
+ self.frame.layout().addWidget(widget)
+ return widget
+
+ def delete_plan_regulation_widget(self, plan_regulation_widget: PlanRegulationWidget):
+ self.frame.layout().removeWidget(plan_regulation_widget)
+ plan_regulation_widget.deleteLater()
diff --git a/arho_feature_template/gui/plan_regulation_widget.py b/arho_feature_template/gui/plan_regulation_widget.py
index 4f113d0..36a23c7 100644
--- a/arho_feature_template/gui/plan_regulation_widget.py
+++ b/arho_feature_template/gui/plan_regulation_widget.py
@@ -1,105 +1,202 @@
from __future__ import annotations
+from collections import defaultdict
from importlib import resources
from typing import TYPE_CHECKING
+from qgis.core import QgsApplication
+from qgis.gui import QgsDoubleSpinBox, QgsFileWidget, QgsSpinBox
from qgis.PyQt import uic
-from qgis.PyQt.QtGui import QIcon
+from qgis.PyQt.QtCore import Qt, pyqtSignal
from qgis.PyQt.QtWidgets import (
- QComboBox,
+ QFormLayout,
QHBoxLayout,
QLabel,
QLineEdit,
- QPlainTextEdit,
- QPushButton,
+ QMenu,
QSizePolicy,
- QToolButton,
+ QTextEdit,
QWidget,
)
-from arho_feature_template.qgis_plugin_tools.tools.resources import plugin_path
+from arho_feature_template.core.plan_regulation_config import PlanRegulationConfig, Unit, ValueType
if TYPE_CHECKING:
- from qgis.PyQt.QtWidgets import QFormLayout
+ from numbers import Number
- from arho_feature_template.core.template_library_config import Feature
+ from qgis.PyQt.QtWidgets import QPushButton
-ui_path = resources.files(__package__) / "plan_regulation_widget.ui"
+ from arho_feature_template.core.plan_regulation_group_config import PlanRegulationDefinition
+
+ui_path = resources.files(__package__) / "new_plan_regulation_widget.ui"
FormClass, _ = uic.loadUiType(ui_path)
+# Related layer and field names to save information later on
+LAYER_NAME = "Kaavamääräys"
+TYPE_OF_PLAN_REGULATION_KIND_FIELD = "type_of_plan_regulation_kind"
+NUMERIC_VALUE_FIELD = "numeric_value"
+TYPE_OF_VERBAL_PLAN_REGULATION_FIELD = "type_of_verbal_plan_regulation"
+UNIT_FIELD = "unit"
+TEXT_VALUE_FIELD = "text_value"
+REGULATION_TYPE_ADDITIONAL_INFORMATION_ID = "regulation_type_additional_information_id"
+
+
class PlanRegulationWidget(QWidget, FormClass): # type: ignore
- """A widget representation of a plan regulation group."""
+ """A widget representation of a plan regulation."""
- def __init__(self, feature: Feature):
- super().__init__()
+ delete_signal = pyqtSignal(QWidget)
+
+ def __init__(self, config: PlanRegulationConfig, parent=None):
+ super().__init__(parent)
self.setupUi(self)
# TYPES
- self.regulation_kind: QLineEdit
- self.form_layout: QFormLayout = self.layout()
-
- # INITI
- self.feature = feature
- self.initialize_fields()
-
- def initialize_fields(self):
- for plan_regulation_config in self.feature.attributes:
- # Set regulation type / kind
- if plan_regulation_config.attribute == "type_of_plan_regulation_id":
- self.regulation_kind.setText(plan_regulation_config.display())
-
- elif plan_regulation_config.attribute == "numeric_default":
- self.add_quantity_input()
-
- # elif plan_regulation_config.attribute == "text???":
- # self.add_text_input()
-
- if self.feature.child_features is None:
- return
-
- for child in self.feature.child_features:
- # Additional information here, what else?
- # Assume attribute is "additional_information_of_plan_regulation"
- # NOTE: Could additional information be attribute of plan regulation instead of child feature?
-
- # TBD: Multiple additional feature per plan regulation
- for attribute in child.attributes:
- # Assume "type_of_additional_information_id"
- self.add_additional_information_field(attribute.display())
-
- def add_additional_information_field(self, default_value: str | None = None):
- label = QLabel("Lisätieto", self)
- horizontal_layout = QHBoxLayout(self)
- line_edit = QLineEdit(self)
- if default_value:
- line_edit.setText(default_value)
- conf_btn = QPushButton(self)
- conf_btn.setIcon(QIcon(plugin_path("resources", "icons", "settings.svg")))
- horizontal_layout.addWidget(line_edit)
- horizontal_layout.addWidget(conf_btn)
- self.form_layout.addRow(label, horizontal_layout)
-
- def add_quantity_input(self, quantity_types: list[str] | None = None):
- label = QLabel("Arvo", self)
- line_edit = QLineEdit(self)
- if quantity_types:
- quantity_types_selection = QComboBox(self)
- quantity_types_selection.addItems(quantity_types)
- horizontal_layout = QHBoxLayout(self)
- horizontal_layout.addItem(line_edit)
- horizontal_layout.addItem(quantity_types_selection)
- self.form_layout.addRow(label, horizontal_layout)
+ self.plan_regulation_name: QLineEdit
+ self.form_layout: QFormLayout
+
+ self.add_additional_information_btn: QPushButton
+ self.add_regulation_number_btn: QPushButton
+ self.add_file_btn: QPushButton
+ self.del_btn: QPushButton
+
+ # INIT
+ self.config = config
+ self.regulation_number_added = False
+ # Key is related field name, value is 1) widget, 2) tuple of widget and default value
+ # NOTE: Maybe this is not something needed? Instead, when user clicks Ok, write into a YAML
+ # in a separate script?
+ self.attribute_widgets: dict[str, QWidget | tuple[QWidget, str | Number]] = defaultdict(dict)
+ self.plan_regulation_name.setText(config.name)
+ self.plan_regulation_name.setReadOnly(True)
+ self.init_value_fields()
+ self.init_buttons()
+
+ def populate_from_definition(self, definition: PlanRegulationDefinition):
+ pass
+
+ def init_value_fields(self):
+ layout = QHBoxLayout()
+ value_type = self.config.value_type
+ if value_type:
+ self._add_value_input(value_type, layout)
+
+ unit = self.config.unit
+ if unit:
+ self._add_value_unit(unit, layout)
+
+ def _add_value_input(self, value_type: ValueType, layout: QHBoxLayout):
+ if value_type in [ValueType.DECIMAL, ValueType.POSITIVE_DECIMAL]:
+ self.add_decimal_input(layout, value_type)
+ elif value_type == ValueType.POSITIVE_INTEGER:
+ self.add_positive_integer_input(layout)
+ elif value_type == ValueType.POSITIVE_INTEGER_RANGE:
+ self.add_positive_integer_range_input(layout)
+ elif value_type == ValueType.VERSIONED_TEXT:
+ self.add_versioned_text_input(layout)
+ else:
+ msg = f"Invalid input value type for plan regulation: {value_type}"
+ raise ValueError(msg)
+
+ def _add_value_unit(self, unit: Unit, layout: QHBoxLayout):
+ # NOTE: Unit could also be suffix in the QgsSpinBox, could be clearer?
+ unit_label = QLabel(unit.value)
+ layout.addWidget(unit_label)
+
+ def init_buttons(self):
+ # DEL
+ self.del_btn.setIcon(QgsApplication.getThemeIcon("mActionDeleteSelected.svg"))
+ self.del_btn.clicked.connect(lambda: self.delete_signal.emit(self))
+
+ # ADDITIONAL INFORMATION
+ type_menu = QMenu("Tyyppi", self)
+ type_menu_items = [
+ "Pääkäyttötarkoitus",
+ "Osa-alue",
+ "Poisluettava käyttötarkoitus",
+ "Väliaikainen määräys",
+ "Vaihtoehtoinen",
+ "Ohjeellinen sijainti",
+ "Yhteystarve",
+ ]
+
+ for item in type_menu_items:
+ action = type_menu.addAction(item)
+ action.triggered.connect(lambda _, item=item: self.add_additional_info(item))
+
+ signifigance_menu = QMenu("Merkittävyys", self)
+ signifigance_menu_items = [
+ "Kansainvälinen",
+ "Valtakunnallinen",
+ "Maakunnallinen",
+ "Seudullinen",
+ "Alueellinen",
+ "Paikallinen",
+ ]
+
+ for item in signifigance_menu_items:
+ action = signifigance_menu.addAction(item)
+ action.triggered.connect(lambda _, item=item: self.add_additional_info(item))
+
+ type_main_menu = QMenu(self)
+ type_main_menu.addMenu(type_menu)
+ type_main_menu.addMenu(signifigance_menu)
+ self.add_additional_information_btn.setMenu(type_main_menu)
+
+ # REGULATION NUMBER
+ self.add_regulation_number_btn.clicked.connect(self.add_regulation_number)
+
+ # ADD FILE
+ self.add_file_btn.clicked.connect(self.add_file)
+
+ def add_decimal_input(self, layout: QHBoxLayout, value_type: ValueType):
+ value_widget = QgsDoubleSpinBox()
+ label_text = "Desimaali"
+ if value_type == ValueType.POSITIVE_DECIMAL:
+ value_widget.setMinimum(0.0)
+ label_text += " (positiivinen)"
else:
- self.form_layout.addRow(label, line_edit)
- # TODO: Input validation
-
- def add_text_input(self):
- label = QLabel("Arvo", self)
- horizontal_layout = QHBoxLayout(self)
- text_edit = QPlainTextEdit(self)
- text_edit.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Preferred)
- open_btn = QToolButton(self)
- horizontal_layout.addWidget(text_edit)
- horizontal_layout.addWidget(open_btn)
- self.form_layout.addRow(label, horizontal_layout)
+ value_widget.setMinimum(-9999.9)
+ value_widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
+ layout.addWidget(value_widget)
+ self.form_layout.addRow(label_text, layout)
+
+ def add_positive_integer_input(self, layout: QHBoxLayout):
+ value_widget = QgsSpinBox()
+ value_widget.setMinimum(0)
+ value_widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
+ layout.addWidget(value_widget)
+ self.form_layout.addRow("Kokonaisluku (positiivinen)", layout)
+
+ def add_positive_integer_range_input(self, layout: QHBoxLayout):
+ min_widget = QgsSpinBox()
+ min_widget.setMinimum(0)
+ max_widget = QgsSpinBox()
+ max_widget.setMinimum(0)
+ layout.addWidget(min_widget)
+ dash_label = QLabel(" — ")
+ dash_label.setAlignment(Qt.AlignCenter)
+ dash_label.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed)
+ layout.addWidget(dash_label)
+ layout.addWidget(max_widget)
+ self.form_layout.addRow("Kokonaisluku arvoväli (positiivinen)", layout)
+
+ def add_versioned_text_input(self, layout: QHBoxLayout):
+ text_widget = QTextEdit()
+ layout.addWidget(text_widget)
+ self.form_layout.addRow("Kieliversioitu teksti", layout)
+
+ def add_additional_info(self, info_type):
+ info_type_label = QLineEdit(info_type)
+ info_type_label.setReadOnly(True)
+ self.form_layout.addRow("Lisätiedonlaji", info_type_label)
+
+ def add_regulation_number(self):
+ if not self.regulation_number_added:
+ number_widget = QgsSpinBox()
+ self.form_layout.addRow("Määräysnumero", number_widget)
+ self.regulation_number_added = True
+
+ def add_file(self):
+ file_input = QgsFileWidget()
+ self.form_layout.addRow("Liiteasiakirja", file_input)
diff --git a/arho_feature_template/gui/plan_regulation_widget.ui b/arho_feature_template/gui/plan_regulation_widget.ui
index f9ec55f..e6f5225 100644
--- a/arho_feature_template/gui/plan_regulation_widget.ui
+++ b/arho_feature_template/gui/plan_regulation_widget.ui
@@ -6,33 +6,137 @@
0
0
- 349
- 43
+ 694
+ 108
-
-
- 0
- 0
-
-
Form
-
- -
-
-
- Kaavamääräyslaji
-
-
+
+
-
+
+
-
+
+
+ Kaavamääräyslaji
+
+
+
+ -
+
+
-
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 30
+ 16777215
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
-
+
+
+ Lisätieto
+
+
+
+ -
+
+
+ Määräysnumero
+
+
+
+ -
+
+
+ Liiteasiakirja
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
- -
-
-
-
-
-
+
-
+
+
-
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Fixed
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+
+ 0
+ 20
+
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Fixed
+
+
+
+ 40
+ 20
+
+
+
+
+
diff --git a/arho_feature_template/gui/template_attribute_form.py b/arho_feature_template/gui/template_attribute_form.py
index 3d8a28b..2508cd8 100644
--- a/arho_feature_template/gui/template_attribute_form.py
+++ b/arho_feature_template/gui/template_attribute_form.py
@@ -1,11 +1,14 @@
from __future__ import annotations
+import os
from importlib import resources
+from pathlib import Path
from typing import TYPE_CHECKING
-from qgis.gui import QgsSpinBox
from qgis.PyQt import uic
+from qgis.PyQt.QtCore import Qt
from qgis.PyQt.QtWidgets import (
+ QComboBox,
QDialog,
QDialogButtonBox,
QLineEdit,
@@ -16,13 +19,17 @@
QTreeWidgetItem,
)
+from arho_feature_template.core.plan_regulation_group_config import (
+ PlanRegulationGroupDefinition,
+ PlanRegulationGroupLibrary,
+)
from arho_feature_template.gui.plan_regulation_group_widget import PlanRegulationGroupWidget
+from arho_feature_template.qgis_plugin_tools.tools.resources import resources_path
if TYPE_CHECKING:
- from qgis.core import QgsFeature
from qgis.PyQt.QtWidgets import QWidget
- from arho_feature_template.core.template_library_config import Feature, FeatureTemplate
+ from arho_feature_template.core.template_library_config import FeatureTemplate
ui_path = resources.files(__package__) / "template_attribute_form.ui"
FormClass, _ = uic.loadUiType(ui_path)
@@ -41,29 +48,17 @@ def __init__(self, feature_template_config: FeatureTemplate):
self.feature_underground: QLineEdit
self.plan_regulation_group_scrollarea: QScrollArea
self.plan_regulation_group_scrollarea_contents: QWidget
+ self.plan_regulation_group_libraries_combobox: QComboBox
self.plan_regulation_groups_tree: QTreeWidget
self.button_box: QDialogButtonBox
- # SIGNALS
- self.button_box.accepted.connect(self._on_ok_clicked)
- self.plan_regulation_groups_tree.itemDoubleClicked.connect(self.add_selected_plan_regulation_group)
-
# INIT
- self.attribute_widgets = {
- "name": self.feature_name,
- "description": self.feature_description,
- "type_of_underground_id": self.feature_underground,
- }
- # TODO: The 'configs' could be a mapping where keys are plan regulation group names and
- # values are the related configurations
- self.configs: dict[str, Feature] = {}
self.scroll_area_spacer = None
- self.available_plan_regulation_group_configs: list[Feature] = []
-
self.setWindowTitle(feature_template_config.name)
- self.init_feature_attributes_from_template(feature_template_config)
- self.init_plan_regulation_groups_from_template(feature_template_config)
- self.init_plan_regulation_group_library()
+ self.init_plan_regulation_group_libraries()
+ # self.init_plan_regulation_groups_from_template(feature_template_config)
+ self.button_box.accepted.connect(self._on_ok_clicked)
+ self.plan_regulation_groups_tree.itemDoubleClicked.connect(self.add_selected_plan_regulation_group)
def _add_spacer(self):
self.scroll_area_spacer = QSpacerItem(0, 0, QSizePolicy.Expanding, QSizePolicy.Expanding)
@@ -77,14 +72,11 @@ def _remove_spacer(self):
def add_selected_plan_regulation_group(self, item: QTreeWidgetItem, column: int):
if not item.parent():
return
- config = self.configs.get(item.text(column))
- if not config:
- print(f"Could not find plan regulation group configuration for {item.text(column)}") # noqa: T201
- return
- self.add_plan_regulation_group(config)
+ definition: PlanRegulationGroupDefinition = item.data(column, Qt.UserRole)
+ self.add_plan_regulation_group(definition)
- def add_plan_regulation_group(self, feature_config: Feature):
- new_plan_regulation_group = PlanRegulationGroupWidget(feature_config)
+ def add_plan_regulation_group(self, definition: PlanRegulationGroupDefinition):
+ new_plan_regulation_group = PlanRegulationGroupWidget(definition)
new_plan_regulation_group.delete_signal.connect(self.remove_plan_regulation_group)
self._remove_spacer()
self.plan_regulation_group_scrollarea_contents.layout().addWidget(new_plan_regulation_group)
@@ -94,42 +86,22 @@ def remove_plan_regulation_group(self, plan_regulation_group_widget: PlanRegulat
self.plan_regulation_group_scrollarea_contents.layout().removeWidget(plan_regulation_group_widget)
plan_regulation_group_widget.deleteLater()
- def init_plan_regulation_group_library(self):
- # Now plan regulation group tree widget/view is just static placeholder for demo
- pass
-
- def init_feature_attributes_from_template(self, feature_template_config: FeatureTemplate):
- if feature_template_config.feature.attributes is None:
- return
- for _attribute in feature_template_config.feature.attributes:
- # TODO: TO be implemented
- pass
-
- def init_plan_regulation_groups_from_template(self, feature_template_config: FeatureTemplate):
- if feature_template_config.feature.child_features is None:
- return
- for child_feature in feature_template_config.feature.child_features:
- if child_feature.layer == "plan_requlation_group":
- # Collect encountered plan regulation groups in init
- # This does not need to be done if Katja config file is read beforehand and
- # that handles available plan regulation groups
- self.available_plan_regulation_group_configs.append(child_feature)
- self.add_plan_regulation_group(child_feature)
- else:
- # TODO: Implement
- print(f"Encountered child feature with unrecognized layer: {child_feature.layer}") # noqa: T201
+ def init_plan_regulation_group_libraries(self):
+ katja_asemakaava_path = Path(os.path.join(resources_path(), "katja_asemakaava.yaml"))
+ libraries = [PlanRegulationGroupLibrary.new_from_file(katja_asemakaava_path)]
+ for library in libraries:
+ self.init_plan_regulation_group_library(library)
+
+ def init_plan_regulation_group_library(self, library: PlanRegulationGroupLibrary):
+ self.plan_regulation_group_libraries_combobox.addItem(library.meta.name)
+ for category in library.plan_regulation_group_categories:
+ category_item = QTreeWidgetItem()
+ category_item.setText(0, category.name)
+ self.plan_regulation_groups_tree.addTopLevelItem(category_item)
+ for group_definition in category.plan_regulation_groups:
+ regulation_group_item = QTreeWidgetItem(category_item)
+ regulation_group_item.setText(0, group_definition.name)
+ regulation_group_item.setData(0, Qt.UserRole, group_definition)
def _on_ok_clicked(self):
self.accept()
-
- def set_feature_attributes(self, feature: QgsFeature):
- for attribute, widget in self.attribute_widgets.items():
- feature.setAttribute(attribute, self._get_widget_value(widget))
-
- def _get_widget_value(self, widget: QWidget) -> str | int | None:
- if isinstance(widget, QLineEdit):
- return widget.text()
- if isinstance(widget, QgsSpinBox):
- return widget.value()
- return None
- # TODO: Implement
diff --git a/arho_feature_template/gui/template_attribute_form.ui b/arho_feature_template/gui/template_attribute_form.ui
index 0e16853..0016881 100644
--- a/arho_feature_template/gui/template_attribute_form.ui
+++ b/arho_feature_template/gui/template_attribute_form.ui
@@ -6,7 +6,7 @@
0
0
- 757
+ 906
749
@@ -78,18 +78,7 @@
-
-
-
-
-
- Katja
-
-
- -
-
- Omat
-
-
-
+
-
@@ -116,7 +105,7 @@
-
-
+
0
0
@@ -141,104 +130,9 @@
- 1
+
-
-
-
- Aluevaraukset
-
-
-
-
- Asuinrakennusten alue
-
-
- -
-
- Asuinkerrostalojen alue
-
-
- -
-
- Asuinpientalojen alue
-
-
- -
-
- Rivitalojen ja muiden kytkettyjen asuinrakennusten alue
-
-
- -
-
- Erillispientalojen alue
-
-
-
- -
-
- Rakennusalat
-
-
-
-
- Kunnan tai kaupunginosas raja
-
-
- -
-
- Korttelialue tai korttelialueen osa
-
-
- -
-
- Sitovan tonttijaon mukainen tontti
-
-
- -
-
- Ohjeellinen tontti / rakennusala
-
-
- -
-
- Rakennusala
-
-
-
- -
-
- Numeeriset ja tekstimuotoiset määräykset
-
-
-
-
- Kaupungin- tai kunnanosan numero
-
-
- -
-
- Kaupungin- tai kunnanosan nimi
-
-
- -
-
- Korttelin numero
-
-
- -
-
- Tontin tai rakennuspaikan numero
-
-
- -
-
- Ohjeellisen tontin tai rakennuspaikan numero
-
-
- -
-
- Kadun tai tien nimi
-
-
-
@@ -262,7 +156,7 @@
0
0
- 449
+ 598
624
diff --git a/arho_feature_template/resources/kaavamaaraykset.yaml b/arho_feature_template/resources/kaavamaaraykset.yaml
index 7f80472..40e43b4 100644
--- a/arho_feature_template/resources/kaavamaaraykset.yaml
+++ b/arho_feature_template/resources/kaavamaaraykset.yaml
@@ -4,7 +4,7 @@ plan_regulations:
- regulation_code: asumisenAlue
child_regulations:
- - regulation_code: asuinPientaloAlue
+ - regulation_code: asuinpientaloalue
child_regulations:
- regulation_code: erillistenAsuinpientalojenAlue
@@ -19,12 +19,97 @@ plan_regulations:
- regulation_code: kylaAlue
+# TYÖPAIKKOJEN ALUE (valmis?)
+ - regulation_code: tyopaikkojenAlue
+ child_regulations:
+
+ - regulation_code: toimitilojenAlue
+ child_regulations:
+
+ - regulation_code: toimistorakennustenAlue
+
+ - regulation_code: palvelujenAlue
+ child_regulations:
+
+ - regulation_code: liikerakennustenAlue
+ child_regulations:
+
+ - regulation_code: myymalarakennustenAlue
+ child_regulations:
+
+ - regulation_code: vahittaiskaupanSuuryksikkö
+
+ - regulation_code: vahittaiskaupanMyymalakeskittyma
+
+ - regulation_code: huviJaViihdeRakennustenAlue
+
+ - regulation_code: yleistenRakennustenAlue
+ child_regulations:
+
+ - regulation_code: hoitoalanRakennustenAlue
+
+ - regulation_code: museorakennustenAlue
+
+ - regulation_code: urheiluJaLiikuntaRakennustenAlue
+
+ - regulation_code: kulttuurirakennustenAlue
+
+ - regulation_code: uskonnollistenYhteisojenRakennustenAlue
+
+ - regulation_code: opetusrakennustenAlue
+
+ - regulation_code: teollisuusalue
+
+ - regulation_code: varastoalue
+
+# VAPAA-AJAN ASUMISEN JA MATKAILUN ALUE (valmis?)
+
+ - regulation_code: vapaaAjanAsumisenJaMatkailunAlue
+ child_regulatons:
+
+ - regulation_code: vapaaAjanAsumisenJaMatkailunAlue
+
+ - regulation_code: matkailupalvelujenAlue
+
+ - regulation_code: leirintaAlue
+
+ - regulation_code: asuntovaunualue
+
+ - regulation_code: siirtolapuutarhaAlue
+
+ - regulation_code: palstaviljelyalue
+
+# TAAJAMATOIMIEN ALUE (valmis?)
+ - regulation_code: taajamatoimintojenAlue
+ child_regulations:
+
+ - regulation_code: keskustatoimintojenAlue
+ child_regulations:
+
+ - regulation_code: keskustatoimintojenAlakeskus
+
# VIHERALUE (kesken)
- regulation_code: viheralue
category_only: true
child_regulations:
- regulation_code: virkistysalue
+ child_regulations:
+
+ - regulation_code: uimaranta
+
+ - regulation_code: puisto
+
+ - regulation_code: leikkipuisto
+
+# MAATALOUSALUE (kesken)
+ - regulation_code: maaJaMetsatalousAlue
+ child_regulations:
+
+ - regulation_code: maatalousalue
+ child_regulations:
+
+ - regulation_code: pelto
# VESIALUE (valmis?)
- regulation_code: vesialue
@@ -32,6 +117,24 @@ plan_regulations:
- regulation_code: pohjavesialue
+# YMPÄRISTÖARVOJEN ALUE (kesken)
+ - regulation_code: ymparistoarvojenAlue
+ category_only: true
+ child_regulations:
+
+ - regulation_code: kulttuuriymparistoarvojenAlue
+ child_regulations:
+
+ - regulation_code: merkittavaRakennettuKulttuuriymparisto
+
+ - regulation_code: maisemallisestiArvokasAlue
+
+# RAKENNUSALA (kesken)
+ - regulation_code: rakennusala
+ child_regulations:
+
+ - regulation_code: rakennusalaJolleSaaSijoittaaSaunan
+
# RAKENTAMISEN MÄÄRÄ (valmis?)
- regulation_code: rakentamisenMaara
category_only: true
@@ -87,6 +190,19 @@ plan_regulations:
- regulation_code: tuulivoimaloidenMaara
value_type: positiivinen kokonaisluku
+# RAKENTAMISEN TAPA
+ - regulation_code: rakentamisenTapa
+ category_only: true
+ child_regulations:
+
+ - regulation_code: kattokaltevuus
+ value_type: desimaali
+ unit: °
+
+ - regulation_code: aaneneristavyys
+ value_type: positiivinen desimaali
+ unit: dB
+
# SANALLINEN MÄÄRÄYS (valmis?)
- regulation_code: sanallinenMaarays
value_type: kieliversioitu teksti
diff --git a/arho_feature_template/resources/katja.yaml b/arho_feature_template/resources/katja.yaml
deleted file mode 100644
index da0ceb1..0000000
--- a/arho_feature_template/resources/katja.yaml
+++ /dev/null
@@ -1,74 +0,0 @@
-aluevaraukset:
- - geometria: Alue
- värikoodi: #000000
- kirjaintunnus: A
- kaavamääräyksen_otsikko: Asuinrakennusten alue
- kaavamääräykset:
- - nimi: Asumisen alue
- lisätiedot:
- - laji: Pääkäyttötarkoitus
-
- - geometria: Alue
- värikoodi: #000000
- kirjaintunnus: AK
- kaavamääräyksen_otsikko: Asuinkerrostalojen alue
- kaavamääräykset:
- - nimi: Asuinkerrostaloalue
- lisätiedot:
- - laji: Pääkäyttötarkoitus
-
- - geometria: Alue
- värikoodi: "#A9D08E"
- kirjaintunnus: AP
- kaavamääräyksen_otsikko: Asuinpientalojen alue
- kaavamääräykset:
- - nimi: Asuinpientaloalue
- lisätiedot:
- - laji: Pääkäyttötarkoitus
-
- - geometria: Alue
- värikoodi: "#FFD966"
- kirjaintunnus: AR
- kaavamääräyksen_otsikko: Rivitalojen ja muiden kytkettyjen asuinrakennusten alue
- kaavamääräykset:
- - nimi: Rivitalojen ja muiden kytkettyjen asuinpientalojen alue
- lisätiedot:
- - laji: Pääkäyttötarkoitus
-
- - geometria: Alue
- värikoodi: "#E06666"
- kirjaintunnus: AO
- kaavamääräyksen_otsikko: Erillispientalojen alue
- kaavamääräykset:
- - nimi: Erillisten asuinpientalojen alue
- lisätiedot:
- - laji: Pääkäyttötarkoitus
-
- - geometria: Alue
- värikoodi: "#5B9BD5"
- kirjaintunnus: AL
- kaavamääräyksen_otsikko: Asuin-, liike- ja toimistorakennusten alue
- kaavamääräykset:
- - nimi: Asumisen alue
- - nimi: Liikerakennusten alue
- - nimi: Toimistorakennusten alue
- lisätiedot:
- - laji: Pääkäyttötarkoitus
-
- - geometria: Alue
- värikoodi: "#9BC2E6"
- kirjaintunnus: AH
- kaavamääräyksen_otsikko: Asumista palveleva yhteiskäyttöinen alue
- kaavamääräykset:
- - nimi: Asumista palveleva yhteiskäyttöinen alue
- lisätiedot:
- - laji: Pääkäyttötarkoitus
-
- - geometria: Alue
- värikoodi: "#FFD966"
- kirjaintunnus: AM
- kaavamääräyksen_otsikko: Maatilojen talouskeskusten alue
- kaavamääräykset:
- - nimi: Maatilan talouskeskuksen alue
- lisätiedot:
- - laji: Pääkäyttötarkoitus
diff --git a/arho_feature_template/resources/katja_asemakaava.yaml b/arho_feature_template/resources/katja_asemakaava.yaml
new file mode 100644
index 0000000..63910c9
--- /dev/null
+++ b/arho_feature_template/resources/katja_asemakaava.yaml
@@ -0,0 +1,277 @@
+meta:
+ name: Asemakaavan kaavamääräysryhmät (Katja)
+ version: 1
+categories:
+
+ - category_code: aluevaraukset
+ name: Aluevaraukset
+ plan_regulation_groups:
+
+ - name: Asuinrakennusten alue
+ geometry: Alue
+ color_code: #000000
+ letter_code: A
+ plan_regulations:
+ - regulation_code: asumisenAlue
+ additional_information:
+ - type: paakayttotarkoitus
+
+ - name: Asuinkerrostalojen alue
+ geometry: Alue
+ color_code: #000000
+ letter_code: AK
+ plan_regulations:
+ - regulation_code: asuinkerrostaloalue
+ additional_information:
+ - type: paakayttotarkoitus
+
+ - name: Asuinpientalojen alue
+ geometry: Alue
+ color_code: #A9D08E
+ letter_code: AP
+ plan_regulations:
+ - regulation_code: asuinpientaloalue
+ additional_information:
+ - type: paakayttotarkoitus
+
+ - name: Rivitalojen ja muiden kytkettyjen asuinrakennusten alue
+ geometry: Alue
+ color_code: #FFD966
+ letter_code: AR
+ plan_regulations:
+ - regulation_code: rivitalojenJaMuidenKytkettyjenAsuinpientalojenAlue
+ additional_information:
+ - type: paakayttotarkoitus
+
+ - name: Erillispientalojen alue
+ geometry: Alue
+ color_code: #E06666
+ letter_code: AO
+ plan_regulations:
+ - regulation_code: erillistenAsuinpientalojenAlue
+ additional_information:
+ - type: paakayttotarkoitus
+
+ - name: Asuin-, liike- ja toimistorakennusten alue
+ geometry: Alue
+ color_code: #5B9BD5
+ letter_code: AL
+ plan_regulations:
+ - regulation_code: asumisenAlue
+ additional_information:
+ - type: paakayttotarkoitus
+ - regulation_code: liikerakennustenAlue
+ additional_information:
+ - type: paakayttotarkoitus
+ - regulation_code: toimistorakennustenAlue
+ additional_information:
+ - type: paakayttotarkoitus
+
+ - name: Asumista palveleva yhteiskäyttöinen alue
+ geometry: Alue
+ color_code: #9BC2E6
+ letter_code: AH
+ plan_regulations:
+ - regulation_code: asumistaPalvelevaYhteiskayttoinenAlue
+ additional_information:
+ - type: paakayttotarkoitus
+
+ - name: Maatilojen talouskeskusten alue
+ geometry: Alue
+ color_code: #FFD966
+ letter_code: AM
+ plan_regulations:
+ - regulation_code: maatilanTalouskeskuksenAlue
+ additional_information:
+ - type: paakayttotarkoitus
+
+ - name: Keskustatoimintojen alue
+ geometry: Alue
+ color_code: #D9D9D9
+ letter_code: C
+ plan_regulations:
+ - regulation_code: keskustatoimintojenAlue
+ additional_information:
+ - type: paakayttotarkoitus
+
+ - name: Yleisten rakennusten alue
+ geometry: Alue
+ color_code: #C6E0B4
+ letter_code: Y
+ plan_regulations:
+ - regulation_code: yleistenRakennustenAlue
+ additional_information:
+ - type: paakayttotarkoitus
+ - type: varattuYleiseenKayttoon
+
+ - name: Palvelurakennusten alue
+ geometry: Alue
+ color_code: #FFC000
+ letter_code: P
+ plan_regulations:
+ - regulation_code: palvelujenAlue
+ additional_information:
+ - type: paakayttotarkoitus
+
+ - name: Teollisuus- ja varastorakennusten alue
+ geometry: Alue
+ color_code: #70AD47
+ letter_code: T
+ plan_regulations:
+ - regulation_code: teollisuusalue
+ additional_information:
+ - type: paakayttotarkoitus
+ - regulation_code: varastoalue
+ additional_information:
+ - type: paakayttotarkoitus
+
+ - name: Teollisuusrakennusten alue, jolla ympäristö asettaa toiminnan laadulle erityisiä vaatimuksia
+ geometry: Alue
+ color_code: #5B9BD5
+ letter_code: TY
+ plan_regulations:
+ - regulation_code: teollisuusalue
+ additional_information:
+ - type: paakayttotarkoitus
+ - type: ymparistoAsettaaToiminnanLaadulleErityisiaVaatimuksia
+
+ - name: Puisto
+ geometry: Alue
+ color_code: #4472C4
+ letter_code: VP
+ plan_regulations:
+ - regulation_code: puisto
+ additional_information:
+ - type: paakayttotarkoitus
+
+ - name: Leikkipuisto
+ geometry: Alue
+ color_code: #A9D08E
+ letter_code: VK
+ plan_regulations:
+ - regulation_code: leikkipuisto
+ additional_information:
+ - type: paakayttotarkoitus
+
+ - name: Uimaranta-alue
+ geometry: Alue
+ color_code: #E06666
+ letter_code: VV
+ plan_regulations:
+ - regulation_code: uimaranta
+ additional_information:
+ - type: paakayttotarkoitus
+
+ - name: Vapaa-ajan asumisen ja matkailun alue
+ geometry: Alue
+ color_code: #70AD47
+ letter_code: R
+ plan_regulations:
+ - regulation_code: vapaaAjanAsumisenJaMatkailunAlue
+ additional_information:
+ - type: paakayttotarkoitus
+
+ - name: Maisemallisesti arvokas peltoalue
+ geometry: Alue
+ color_code: #abcdef
+ letter_code: MA
+ plan_regulations:
+ - regulation_code: pelto
+ additional_information:
+ - type: paakayttotarkoitus
+ - regulation_code: maisemallisestiArvokasAlue
+ # Lisätieto: Pääkäyttötarkoitus ???
+
+ - name: Virkistysalue
+ geometry: Alue
+ color_code: #FFC000
+ letter_code: V
+ plan_regulations:
+ - regulation_code: virkistysalue
+ additional_information:
+ - type: paakayttotarkoitus
+
+ - category_code: rakennusala
+ name: Rakennusala
+ plan_regulation_groups:
+
+ - name: Auton säilytyspaikan rakennusala
+ geometry: Alue
+ letter_code: a
+ plan_regulations:
+ - regulation_code: rakennusala
+ additional_information:
+ - type: osaAlue
+ - type: kayttotarkoituskohdistus
+ value: Pysäköinnin alue
+
+ - name: Rakennusala, jolle saa sijoittaa lasten päiväkodin
+ geometry: Alue
+ letter_code: pk
+ plan_regulations:
+ - regulation_code: rakennusala
+ additional_information:
+ - type: osaAlue
+ - type: kayttotarkoituskohdistus
+ value: Opetusrakennusten alue
+
+ - name: Rakennusala, jolle saa sijoittaa saunan
+ geometry: Alue
+ letter_code: sa
+ plan_regulations:
+ - regulation_code: rakennusalaJolleSaaSijoittaaSaunan
+ additional_information:
+ - type: osaAlue
+
+ - name: Rakennetun kulttuuriympäristön ja maiseman vaalimisen kannalta tärkeä alue
+ geometry: Alue
+ letter_code: kyma
+ plan_regulations:
+ - regulation_code: maisemallisestiArvokasAlue
+ additional_information:
+ - type: osaAlue
+ - regulation_code: merkittavaRakennettuKulttuuriymparisto
+ additional_information:
+ - type: osaAlue
+
+ - name: Maisemallisesti arvokas alue
+ geometry: Alue
+ letter_code: ma
+ plan_regulations:
+ - regulation_code: maisemallisestiArvokasAlue
+ additional_information:
+ - type: osaAlue
+
+ - name: Kansainvälisesti arvokas maisema-alue
+ geometry: Alue
+ letter_code: kvma
+ plan_regulations:
+ - regulation_code: maisemallisestiArvokasAlue
+ additional_information:
+ - type: osaAlue
+ - type: kansainvalinen
+
+
+ - category_code: numeerisetJaTekstimuotoiset
+ name: Numeeriset ja tekstimuotoiset
+ plan_regulation_groups:
+
+ - name: Rakennusoikeus kuutiometreinä
+ geometry: Alue
+ plan_regulations:
+ - regulation_code: sallittuRakennustilavuus
+
+ - name: Luku osoittaa, kuinka suuri osa alueesta tai rakennusalasta tulee jättää rakentamatta
+ geometry: Alue
+ plan_regulations:
+ - regulation_code: valjyysluku
+
+ - name: Roomalaisin numeroin ilmaistu arvoväli osoittaa rakennusten, rakennuksen tai sen osan kerrosluvun vähimmäis- ja enimmäismäärän
+ geometry: Alue
+ plan_regulations:
+ - regulation_code: maanpaallinenKerroslukuArvovali
+
+ - name: Kattokaltevuus
+ geometry: Alue
+ plan_regulations:
+ - regulation_code: kattokaltevuus
diff --git a/arho_feature_template/resources/omat_kaavamaaraysryhmat_placeholder.yaml b/arho_feature_template/resources/omat_kaavamaaraysryhmat_placeholder.yaml
new file mode 100644
index 0000000..1e14210
--- /dev/null
+++ b/arho_feature_template/resources/omat_kaavamaaraysryhmat_placeholder.yaml
@@ -0,0 +1,4 @@
+version: 1
+meta:
+ name: Asemakaavan kaavamääräysryhmät (Katja)
+ version: "1.0"