From 42b7ab86d9dfe42f984f31b0870c318f21738706 Mon Sep 17 00:00:00 2001 From: MaxNumerique Date: Fri, 27 Mar 2026 16:54:25 +0100 Subject: [PATCH 1/3] feat(components_color): adds new rpc for model_components color --- .../rpc/model/model_protocols.py | 9 +++ .../rpc/model/schemas/__init__.py | 1 + .../rpc/model/schemas/components_color.json | 55 +++++++++++++++++++ .../rpc/model/schemas/components_color.py | 17 ++++++ .../surfaces/model_surfaces_protocols.py | 2 +- 5 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 src/opengeodeweb_viewer/rpc/model/schemas/components_color.json create mode 100644 src/opengeodeweb_viewer/rpc/model/schemas/components_color.py diff --git a/src/opengeodeweb_viewer/rpc/model/model_protocols.py b/src/opengeodeweb_viewer/rpc/model/model_protocols.py index 6ca47947..9998424a 100644 --- a/src/opengeodeweb_viewer/rpc/model/model_protocols.py +++ b/src/opengeodeweb_viewer/rpc/model/model_protocols.py @@ -81,3 +81,12 @@ def setModelVisibility(self, rpc_params: RpcParams) -> None: ) params = schemas.Visibility.from_dict(rpc_params) self.SetVisibility(params.id, params.visibility) + + @exportRpc(model_prefix + model_schemas_dict["components_color"]["rpc"]) + def setModelComponentsColor(self, rpc_params: RpcParams) -> None: + validate_schema( + rpc_params, self.model_schemas_dict["components_color"], self.model_prefix + ) + params = schemas.ComponentsColor.from_dict(rpc_params) + color = params.color + self.SetBlocksColor(params.id, params.block_ids, color.r, color.g, color.b) diff --git a/src/opengeodeweb_viewer/rpc/model/schemas/__init__.py b/src/opengeodeweb_viewer/rpc/model/schemas/__init__.py index a974c1d6..b2eb2b9f 100644 --- a/src/opengeodeweb_viewer/rpc/model/schemas/__init__.py +++ b/src/opengeodeweb_viewer/rpc/model/schemas/__init__.py @@ -1,3 +1,4 @@ from .visibility import * from .register import * from .deregister import * +from .components_color import * diff --git a/src/opengeodeweb_viewer/rpc/model/schemas/components_color.json b/src/opengeodeweb_viewer/rpc/model/schemas/components_color.json new file mode 100644 index 00000000..08afcb6f --- /dev/null +++ b/src/opengeodeweb_viewer/rpc/model/schemas/components_color.json @@ -0,0 +1,55 @@ +{ + "rpc": "components_color", + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1 + }, + "block_ids": { + "type": "array", + "items": { + "type": "integer" + }, + "minItems": 1 + }, + "color": { + "type": "object", + "properties": { + "r": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "g": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "b": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "a": { + "type": "number", + "minimum": 0, + "maximum": 1, + "default": 1 + } + }, + "required": [ + "r", + "g", + "b" + ], + "additionalProperties": false + } + }, + "required": [ + "id", + "block_ids", + "color" + ], + "additionalProperties": false +} diff --git a/src/opengeodeweb_viewer/rpc/model/schemas/components_color.py b/src/opengeodeweb_viewer/rpc/model/schemas/components_color.py new file mode 100644 index 00000000..c3c1fa3b --- /dev/null +++ b/src/opengeodeweb_viewer/rpc/model/schemas/components_color.py @@ -0,0 +1,17 @@ +from dataclasses import dataclass +from opengeodeweb_microservice.schemas import Color + + +@dataclass +class ComponentsColor: + id: str + block_ids: list[int] + color: Color + + @classmethod + def from_dict(cls, data: dict) -> "ComponentsColor": + return cls( + id=data["id"], + block_ids=data["block_ids"], + color=Color(**data["color"]), + ) diff --git a/src/opengeodeweb_viewer/rpc/model/surfaces/model_surfaces_protocols.py b/src/opengeodeweb_viewer/rpc/model/surfaces/model_surfaces_protocols.py index aaa3a818..12b0c9af 100644 --- a/src/opengeodeweb_viewer/rpc/model/surfaces/model_surfaces_protocols.py +++ b/src/opengeodeweb_viewer/rpc/model/surfaces/model_surfaces_protocols.py @@ -34,7 +34,7 @@ def setModelSurfacesPolygonsVisibility(self, rpc_params: RpcParams) -> None: self.SetBlocksVisibility(params.id, params.block_ids, params.visibility) @exportRpc(model_surfaces_prefix + model_surfaces_schemas_dict["color"]["rpc"]) - def setModelSurfacesPolygonsCOlor(self, rpc_params: RpcParams) -> None: + def setModelSurfacesPolygonsColor(self, rpc_params: RpcParams) -> None: validate_schema( rpc_params, self.model_surfaces_schemas_dict["color"], From 5a47786ce8dcd76506a06a44cef0e519e7b39236 Mon Sep 17 00:00:00 2001 From: MaxNumerique Date: Fri, 27 Mar 2026 17:31:28 +0100 Subject: [PATCH 2/3] test and adds a visibility_component rpc --- .../rpc/model/model_protocols.py | 10 ++++++ .../rpc/model/schemas/__init__.py | 1 + .../rpc/model/schemas/components_color.py | 25 +++++++------- .../model/schemas/components_visibility.json | 26 +++++++++++++++ .../model/schemas/components_visibility.py | 10 ++++++ tests/data/images/model/components_color.jpeg | Bin 0 -> 4082 bytes .../model/components_visibility_color.jpeg | Bin 0 -> 4208 bytes tests/model/test_model_protocols.py | 31 ++++++++++++++++++ 8 files changed, 91 insertions(+), 12 deletions(-) create mode 100644 src/opengeodeweb_viewer/rpc/model/schemas/components_visibility.json create mode 100644 src/opengeodeweb_viewer/rpc/model/schemas/components_visibility.py create mode 100644 tests/data/images/model/components_color.jpeg create mode 100644 tests/data/images/model/components_visibility_color.jpeg diff --git a/src/opengeodeweb_viewer/rpc/model/model_protocols.py b/src/opengeodeweb_viewer/rpc/model/model_protocols.py index 9998424a..564e4ff5 100644 --- a/src/opengeodeweb_viewer/rpc/model/model_protocols.py +++ b/src/opengeodeweb_viewer/rpc/model/model_protocols.py @@ -90,3 +90,13 @@ def setModelComponentsColor(self, rpc_params: RpcParams) -> None: params = schemas.ComponentsColor.from_dict(rpc_params) color = params.color self.SetBlocksColor(params.id, params.block_ids, color.r, color.g, color.b) + + @exportRpc(model_prefix + model_schemas_dict["components_visibility"]["rpc"]) + def setModelComponentsVisibility(self, rpc_params: RpcParams) -> None: + validate_schema( + rpc_params, + self.model_schemas_dict["components_visibility"], + self.model_prefix, + ) + params = schemas.ComponentsVisibility.from_dict(rpc_params) + self.SetBlocksVisibility(params.id, params.block_ids, params.visibility) diff --git a/src/opengeodeweb_viewer/rpc/model/schemas/__init__.py b/src/opengeodeweb_viewer/rpc/model/schemas/__init__.py index b2eb2b9f..6a23cff8 100644 --- a/src/opengeodeweb_viewer/rpc/model/schemas/__init__.py +++ b/src/opengeodeweb_viewer/rpc/model/schemas/__init__.py @@ -2,3 +2,4 @@ from .register import * from .deregister import * from .components_color import * +from .components_visibility import * diff --git a/src/opengeodeweb_viewer/rpc/model/schemas/components_color.py b/src/opengeodeweb_viewer/rpc/model/schemas/components_color.py index c3c1fa3b..1acd570a 100644 --- a/src/opengeodeweb_viewer/rpc/model/schemas/components_color.py +++ b/src/opengeodeweb_viewer/rpc/model/schemas/components_color.py @@ -1,17 +1,18 @@ +from dataclasses_json import DataClassJsonMixin from dataclasses import dataclass -from opengeodeweb_microservice.schemas import Color +from typing import Optional, List @dataclass -class ComponentsColor: - id: str - block_ids: list[int] - color: Color +class ColorClass(DataClassJsonMixin): + b: int + g: int + r: int + a: Optional[float] = None + - @classmethod - def from_dict(cls, data: dict) -> "ComponentsColor": - return cls( - id=data["id"], - block_ids=data["block_ids"], - color=Color(**data["color"]), - ) +@dataclass +class ComponentsColor(DataClassJsonMixin): + block_ids: List[int] + color: ColorClass + id: str diff --git a/src/opengeodeweb_viewer/rpc/model/schemas/components_visibility.json b/src/opengeodeweb_viewer/rpc/model/schemas/components_visibility.json new file mode 100644 index 00000000..548f1d2e --- /dev/null +++ b/src/opengeodeweb_viewer/rpc/model/schemas/components_visibility.json @@ -0,0 +1,26 @@ +{ + "rpc": "components_visibility", + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1 + }, + "block_ids": { + "type": "array", + "items": { + "type": "integer" + }, + "minItems": 1 + }, + "visibility": { + "type": "boolean" + } + }, + "required": [ + "id", + "block_ids", + "visibility" + ], + "additionalProperties": false +} diff --git a/src/opengeodeweb_viewer/rpc/model/schemas/components_visibility.py b/src/opengeodeweb_viewer/rpc/model/schemas/components_visibility.py new file mode 100644 index 00000000..dde8e19d --- /dev/null +++ b/src/opengeodeweb_viewer/rpc/model/schemas/components_visibility.py @@ -0,0 +1,10 @@ +from dataclasses_json import DataClassJsonMixin +from dataclasses import dataclass +from typing import List + + +@dataclass +class ComponentsVisibility(DataClassJsonMixin): + block_ids: List[int] + id: str + visibility: bool diff --git a/tests/data/images/model/components_color.jpeg b/tests/data/images/model/components_color.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..24d6342b8349cc393dde634c50f9fca4f76de523 GIT binary patch literal 4082 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 G|0V!Pc!K=^ literal 0 HcmV?d00001 diff --git a/tests/model/test_model_protocols.py b/tests/model/test_model_protocols.py index 4f363f28..0b4257fd 100644 --- a/tests/model/test_model_protocols.py +++ b/tests/model/test_model_protocols.py @@ -53,3 +53,34 @@ def test_deregister_model( [{"id": "123456789"}], ) assert server.compare_image("model/deregister.jpeg") == True + + +def test_components_color_model( + server: ServerMonitor, dataset_factory: Callable[..., str] +) -> None: + + test_register_model_cube(server, dataset_factory) + + server.call( + VtkModelView.model_prefix + + VtkModelView.model_schemas_dict["components_color"]["rpc"], + [{"id": "123456789", "block_ids": [48, 49], "color": {"r": 255, "g": 0, "b": 0}}], + ) + assert server.compare_image("model/components_color.jpeg") == True + + +def test_components_visibility_color_model( + server: ServerMonitor, dataset_factory: Callable[..., str] +) -> None: + test_register_model_cube(server, dataset_factory) + + server.call( + VtkModelView.model_prefix + "components_visibility", + [{"id": "123456789", "block_ids": [48, 49], "visibility": False}], + ) + + server.call( + VtkModelView.model_prefix + "components_color", + [{"id": "123456789", "block_ids": list(range(36, 47)), "color": {"r": 0, "g": 255, "b": 0}}], + ) + assert server.compare_image("model/components_visibility_color.jpeg") == True From 8d62e754e0e226c160a4e206edf91e2c24f6e864 Mon Sep 17 00:00:00 2001 From: MaxNumerique <144453705+MaxNumerique@users.noreply.github.com> Date: Fri, 27 Mar 2026 16:32:55 +0000 Subject: [PATCH 3/3] Apply prepare changes --- opengeodeweb_viewer_schemas.json | 83 +++++++++++++++++++ requirements.txt | 1 - .../rpc/model/schemas/__init__.py | 2 +- .../rpc/model/schemas/components_color.py | 10 ++- .../model/schemas/components_visibility.py | 3 + tests/model/test_model_protocols.py | 18 +++- 6 files changed, 110 insertions(+), 7 deletions(-) diff --git a/opengeodeweb_viewer_schemas.json b/opengeodeweb_viewer_schemas.json index 47ffb9db..5ee65fe2 100644 --- a/opengeodeweb_viewer_schemas.json +++ b/opengeodeweb_viewer_schemas.json @@ -1504,6 +1504,89 @@ ], "additionalProperties": false }, + "components_visibility": { + "$id": "opengeodeweb_viewer.model.components_visibility", + "rpc": "components_visibility", + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1 + }, + "block_ids": { + "type": "array", + "items": { + "type": "integer" + }, + "minItems": 1 + }, + "visibility": { + "type": "boolean" + } + }, + "required": [ + "id", + "block_ids", + "visibility" + ], + "additionalProperties": false + }, + "components_color": { + "$id": "opengeodeweb_viewer.model.components_color", + "rpc": "components_color", + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1 + }, + "block_ids": { + "type": "array", + "items": { + "type": "integer" + }, + "minItems": 1 + }, + "color": { + "type": "object", + "properties": { + "r": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "g": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "b": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "a": { + "type": "number", + "minimum": 0, + "maximum": 1, + "default": 1 + } + }, + "required": [ + "r", + "g", + "b" + ], + "additionalProperties": false + } + }, + "required": [ + "id", + "block_ids", + "color" + ], + "additionalProperties": false + }, "surfaces": { "visibility": { "$id": "opengeodeweb_viewer.model.surfaces.visibility", diff --git a/requirements.txt b/requirements.txt index 5750c624..13efd779 100644 --- a/requirements.txt +++ b/requirements.txt @@ -61,4 +61,3 @@ wslink==1.12.4 yarl>=1 # via aiohttp -opengeodeweb-microservice==1.*,>=1.1.1 diff --git a/src/opengeodeweb_viewer/rpc/model/schemas/__init__.py b/src/opengeodeweb_viewer/rpc/model/schemas/__init__.py index 6a23cff8..4316d90e 100644 --- a/src/opengeodeweb_viewer/rpc/model/schemas/__init__.py +++ b/src/opengeodeweb_viewer/rpc/model/schemas/__init__.py @@ -1,5 +1,5 @@ from .visibility import * from .register import * from .deregister import * -from .components_color import * from .components_visibility import * +from .components_color import * diff --git a/src/opengeodeweb_viewer/rpc/model/schemas/components_color.py b/src/opengeodeweb_viewer/rpc/model/schemas/components_color.py index 1acd570a..71474acb 100644 --- a/src/opengeodeweb_viewer/rpc/model/schemas/components_color.py +++ b/src/opengeodeweb_viewer/rpc/model/schemas/components_color.py @@ -4,7 +4,10 @@ @dataclass -class ColorClass(DataClassJsonMixin): +class Color(DataClassJsonMixin): + def __post_init__(self) -> None: + print(self, flush=True) + b: int g: int r: int @@ -13,6 +16,9 @@ class ColorClass(DataClassJsonMixin): @dataclass class ComponentsColor(DataClassJsonMixin): + def __post_init__(self) -> None: + print(self, flush=True) + block_ids: List[int] - color: ColorClass + color: Color id: str diff --git a/src/opengeodeweb_viewer/rpc/model/schemas/components_visibility.py b/src/opengeodeweb_viewer/rpc/model/schemas/components_visibility.py index dde8e19d..db72d3ff 100644 --- a/src/opengeodeweb_viewer/rpc/model/schemas/components_visibility.py +++ b/src/opengeodeweb_viewer/rpc/model/schemas/components_visibility.py @@ -5,6 +5,9 @@ @dataclass class ComponentsVisibility(DataClassJsonMixin): + def __post_init__(self) -> None: + print(self, flush=True) + block_ids: List[int] id: str visibility: bool diff --git a/tests/model/test_model_protocols.py b/tests/model/test_model_protocols.py index 0b4257fd..9a0d5980 100644 --- a/tests/model/test_model_protocols.py +++ b/tests/model/test_model_protocols.py @@ -64,7 +64,13 @@ def test_components_color_model( server.call( VtkModelView.model_prefix + VtkModelView.model_schemas_dict["components_color"]["rpc"], - [{"id": "123456789", "block_ids": [48, 49], "color": {"r": 255, "g": 0, "b": 0}}], + [ + { + "id": "123456789", + "block_ids": [48, 49], + "color": {"r": 255, "g": 0, "b": 0}, + } + ], ) assert server.compare_image("model/components_color.jpeg") == True @@ -78,9 +84,15 @@ def test_components_visibility_color_model( VtkModelView.model_prefix + "components_visibility", [{"id": "123456789", "block_ids": [48, 49], "visibility": False}], ) - + server.call( VtkModelView.model_prefix + "components_color", - [{"id": "123456789", "block_ids": list(range(36, 47)), "color": {"r": 0, "g": 255, "b": 0}}], + [ + { + "id": "123456789", + "block_ids": list(range(36, 47)), + "color": {"r": 0, "g": 255, "b": 0}, + } + ], ) assert server.compare_image("model/components_visibility_color.jpeg") == True