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"