valetudo-map-parser 0.1.7__py3-none-any.whl → 0.1.9a1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. valetudo_map_parser/__init__.py +19 -12
  2. valetudo_map_parser/config/auto_crop.py +174 -116
  3. valetudo_map_parser/config/color_utils.py +105 -0
  4. valetudo_map_parser/config/colors.py +662 -13
  5. valetudo_map_parser/config/drawable.py +624 -279
  6. valetudo_map_parser/config/drawable_elements.py +292 -0
  7. valetudo_map_parser/config/enhanced_drawable.py +324 -0
  8. valetudo_map_parser/config/optimized_element_map.py +406 -0
  9. valetudo_map_parser/config/rand25_parser.py +42 -28
  10. valetudo_map_parser/config/room_outline.py +148 -0
  11. valetudo_map_parser/config/shared.py +29 -5
  12. valetudo_map_parser/config/types.py +102 -51
  13. valetudo_map_parser/config/utils.py +841 -0
  14. valetudo_map_parser/hypfer_draw.py +398 -132
  15. valetudo_map_parser/hypfer_handler.py +259 -241
  16. valetudo_map_parser/hypfer_rooms_handler.py +599 -0
  17. valetudo_map_parser/map_data.py +45 -64
  18. valetudo_map_parser/rand25_handler.py +429 -310
  19. valetudo_map_parser/reimg_draw.py +55 -74
  20. valetudo_map_parser/rooms_handler.py +470 -0
  21. valetudo_map_parser-0.1.9a1.dist-info/METADATA +93 -0
  22. valetudo_map_parser-0.1.9a1.dist-info/RECORD +27 -0
  23. {valetudo_map_parser-0.1.7.dist-info → valetudo_map_parser-0.1.9a1.dist-info}/WHEEL +1 -1
  24. valetudo_map_parser/images_utils.py +0 -398
  25. valetudo_map_parser-0.1.7.dist-info/METADATA +0 -23
  26. valetudo_map_parser-0.1.7.dist-info/RECORD +0 -20
  27. {valetudo_map_parser-0.1.7.dist-info → valetudo_map_parser-0.1.9a1.dist-info}/LICENSE +0 -0
  28. {valetudo_map_parser-0.1.7.dist-info → valetudo_map_parser-0.1.9a1.dist-info}/NOTICE.txt +0 -0
@@ -0,0 +1,292 @@
1
+ """
2
+ Drawable Elements Configuration.
3
+ Defines the elements that can be drawn on the map and their properties.
4
+ Version: 0.1.9
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from enum import IntEnum
10
+ from typing import Dict, List, Tuple, Union
11
+
12
+ import numpy as np
13
+
14
+ from .colors import DefaultColors, SupportedColor
15
+ from .types import LOGGER
16
+
17
+
18
+ # Type aliases
19
+ Color = Tuple[int, int, int, int] # RGBA color
20
+ PropertyDict = Dict[str, Union[Color, float, int]]
21
+
22
+
23
+ class DrawableElement(IntEnum):
24
+ """Enumeration of drawable map elements with unique integer codes."""
25
+
26
+ # Base elements
27
+ FLOOR = 1
28
+ WALL = 2
29
+ ROBOT = 3
30
+ CHARGER = 4
31
+ VIRTUAL_WALL = 5
32
+ RESTRICTED_AREA = 6
33
+ NO_MOP_AREA = 7
34
+ OBSTACLE = 8
35
+ PATH = 9
36
+ PREDICTED_PATH = 10
37
+ GO_TO_TARGET = 11
38
+
39
+ # Rooms (101-115 for up to 15 rooms)
40
+ ROOM_1 = 101
41
+ ROOM_2 = 102
42
+ ROOM_3 = 103
43
+ ROOM_4 = 104
44
+ ROOM_5 = 105
45
+ ROOM_6 = 106
46
+ ROOM_7 = 107
47
+ ROOM_8 = 108
48
+ ROOM_9 = 109
49
+ ROOM_10 = 110
50
+ ROOM_11 = 111
51
+ ROOM_12 = 112
52
+ ROOM_13 = 113
53
+ ROOM_14 = 114
54
+ ROOM_15 = 115
55
+
56
+
57
+ class DrawingConfig:
58
+ """Configuration for which elements to draw and their properties."""
59
+
60
+ def __init__(self):
61
+ """Initialize with all elements enabled by default."""
62
+ # Dictionary of element_code -> enabled status
63
+ self._enabled_elements = {element: True for element in DrawableElement}
64
+
65
+ # Dictionary of element_code -> drawing properties (color, opacity, etc.)
66
+ self._element_properties: Dict[DrawableElement, PropertyDict] = {}
67
+
68
+ # Initialize default properties
69
+ self._set_default_properties()
70
+
71
+ def _set_default_properties(self):
72
+ """Set default drawing properties for each element."""
73
+ # Set properties for rooms using DefaultColors
74
+ for room_id in range(1, 16):
75
+ room_element = getattr(DrawableElement, f"ROOM_{room_id}")
76
+ room_key = SupportedColor.room_key(room_id - 1)
77
+ rgb = DefaultColors.DEFAULT_ROOM_COLORS.get(room_key, (135, 206, 250))
78
+ alpha = DefaultColors.DEFAULT_ALPHA.get(f"alpha_room_{room_id - 1}", 255.0)
79
+
80
+ self._element_properties[room_element] = {
81
+ "color": (*rgb, int(alpha)),
82
+ "opacity": alpha / 255.0,
83
+ "z_index": 10, # Drawing order
84
+ }
85
+
86
+ # Map DrawableElement to SupportedColor
87
+ element_color_mapping = {
88
+ DrawableElement.FLOOR: SupportedColor.MAP_BACKGROUND,
89
+ DrawableElement.WALL: SupportedColor.WALLS,
90
+ DrawableElement.ROBOT: SupportedColor.ROBOT,
91
+ DrawableElement.CHARGER: SupportedColor.CHARGER,
92
+ DrawableElement.VIRTUAL_WALL: SupportedColor.NO_GO,
93
+ DrawableElement.RESTRICTED_AREA: SupportedColor.NO_GO,
94
+ DrawableElement.PATH: SupportedColor.PATH,
95
+ DrawableElement.PREDICTED_PATH: SupportedColor.PREDICTED_PATH,
96
+ DrawableElement.GO_TO_TARGET: SupportedColor.GO_TO,
97
+ DrawableElement.NO_MOP_AREA: SupportedColor.NO_GO, # Using NO_GO for no-mop areas
98
+ DrawableElement.OBSTACLE: SupportedColor.NO_GO, # Using NO_GO for obstacles
99
+ }
100
+
101
+ # Set z-index for each element type
102
+ z_indices = {
103
+ DrawableElement.FLOOR: 0,
104
+ DrawableElement.WALL: 20,
105
+ DrawableElement.ROBOT: 50,
106
+ DrawableElement.CHARGER: 40,
107
+ DrawableElement.VIRTUAL_WALL: 30,
108
+ DrawableElement.RESTRICTED_AREA: 25,
109
+ DrawableElement.NO_MOP_AREA: 25,
110
+ DrawableElement.OBSTACLE: 15,
111
+ DrawableElement.PATH: 35,
112
+ DrawableElement.PREDICTED_PATH: 34,
113
+ DrawableElement.GO_TO_TARGET: 45,
114
+ }
115
+
116
+ # Set properties for other elements using DefaultColors
117
+ for element, color_key in element_color_mapping.items():
118
+ rgb = DefaultColors.COLORS_RGB.get(color_key, (0, 0, 0))
119
+ alpha_key = f"alpha_{color_key}"
120
+ alpha = DefaultColors.DEFAULT_ALPHA.get(alpha_key, 255.0)
121
+
122
+ # Special case for semi-transparent elements
123
+ if element in [
124
+ DrawableElement.RESTRICTED_AREA,
125
+ DrawableElement.NO_MOP_AREA,
126
+ DrawableElement.PREDICTED_PATH,
127
+ ]:
128
+ alpha = 125.0 # Semi-transparent by default
129
+
130
+ self._element_properties[element] = {
131
+ "color": (*rgb, int(alpha)),
132
+ "opacity": alpha / 255.0,
133
+ "z_index": z_indices.get(element, 0),
134
+ }
135
+
136
+ def enable_element(self, element_code: DrawableElement) -> None:
137
+ """Enable drawing of a specific element."""
138
+ if element_code in self._enabled_elements:
139
+ self._enabled_elements[element_code] = True
140
+ LOGGER.info(
141
+ "Enabled element %s (%s)", element_code.name, element_code.value
142
+ )
143
+ LOGGER.info(
144
+ "Element %s is now enabled: %s",
145
+ element_code.name,
146
+ self._enabled_elements[element_code],
147
+ )
148
+
149
+ def disable_element(self, element_code: DrawableElement) -> None:
150
+ """Disable drawing of a specific element."""
151
+ if element_code in self._enabled_elements:
152
+ self._enabled_elements[element_code] = False
153
+ LOGGER.info(
154
+ "Disabled element %s (%s)", element_code.name, element_code.value
155
+ )
156
+ LOGGER.info(
157
+ "Element %s is now enabled: %s",
158
+ element_code.name,
159
+ self._enabled_elements[element_code],
160
+ )
161
+
162
+ def set_elements(self, element_codes: List[DrawableElement]) -> None:
163
+ """Enable only the specified elements, disable all others."""
164
+ # First disable all
165
+ for element in self._enabled_elements:
166
+ self._enabled_elements[element] = False
167
+
168
+ # Then enable specified ones
169
+ for element in element_codes:
170
+ if element in self._enabled_elements:
171
+ self._enabled_elements[element] = True
172
+
173
+ def is_enabled(self, element_code: DrawableElement) -> bool:
174
+ """Check if an element is enabled for drawing."""
175
+ return self._enabled_elements.get(element_code, False)
176
+
177
+ def set_property(
178
+ self, element_code: DrawableElement, property_name: str, value
179
+ ) -> None:
180
+ """Set a drawing property for an element."""
181
+ if element_code in self._element_properties:
182
+ self._element_properties[element_code][property_name] = value
183
+
184
+ def get_property(
185
+ self, element_code: DrawableElement, property_name: str, default=None
186
+ ):
187
+ """Get a drawing property for an element."""
188
+ if element_code in self._element_properties:
189
+ return self._element_properties[element_code].get(property_name, default)
190
+ return default
191
+
192
+ def get_enabled_elements(self) -> List[DrawableElement]:
193
+ """Get list of enabled element codes."""
194
+ return [
195
+ element for element, enabled in self._enabled_elements.items() if enabled
196
+ ]
197
+
198
+ def get_drawing_order(self) -> List[DrawableElement]:
199
+ """Get list of enabled elements in drawing order (by z_index)."""
200
+ enabled = self.get_enabled_elements()
201
+ return sorted(enabled, key=lambda e: self.get_property(e, "z_index", 0))
202
+
203
+ def update_from_device_info(self, device_info: dict) -> None:
204
+ """Update configuration based on device info dictionary."""
205
+ # Map DrawableElement to SupportedColor
206
+ element_color_mapping = {
207
+ DrawableElement.FLOOR: SupportedColor.MAP_BACKGROUND,
208
+ DrawableElement.WALL: SupportedColor.WALLS,
209
+ DrawableElement.ROBOT: SupportedColor.ROBOT,
210
+ DrawableElement.CHARGER: SupportedColor.CHARGER,
211
+ DrawableElement.VIRTUAL_WALL: SupportedColor.NO_GO,
212
+ DrawableElement.RESTRICTED_AREA: SupportedColor.NO_GO,
213
+ DrawableElement.PATH: SupportedColor.PATH,
214
+ DrawableElement.PREDICTED_PATH: SupportedColor.PREDICTED_PATH,
215
+ DrawableElement.GO_TO_TARGET: SupportedColor.GO_TO,
216
+ DrawableElement.NO_MOP_AREA: SupportedColor.NO_GO,
217
+ DrawableElement.OBSTACLE: SupportedColor.NO_GO,
218
+ }
219
+
220
+ # Update room colors from device info
221
+ for room_id in range(1, 16):
222
+ room_element = getattr(DrawableElement, f"ROOM_{room_id}")
223
+ color_key = SupportedColor.room_key(room_id - 1)
224
+ alpha_key = f"alpha_room_{room_id - 1}"
225
+
226
+ if color_key in device_info:
227
+ rgb = device_info[color_key]
228
+ alpha = device_info.get(alpha_key, 255.0)
229
+
230
+ # Create RGBA color
231
+ rgba = (*rgb, int(alpha))
232
+
233
+ # Update color and opacity
234
+ self.set_property(room_element, "color", rgba)
235
+ self.set_property(room_element, "opacity", alpha / 255.0)
236
+
237
+ # Update other element colors
238
+ for element, color_key in element_color_mapping.items():
239
+ if color_key in device_info:
240
+ rgb = device_info[color_key]
241
+ alpha_key = f"alpha_{color_key}"
242
+ alpha = device_info.get(alpha_key, 255.0)
243
+
244
+ # Special case for semi-transparent elements
245
+ if element in [
246
+ DrawableElement.RESTRICTED_AREA,
247
+ DrawableElement.NO_MOP_AREA,
248
+ DrawableElement.PREDICTED_PATH,
249
+ ]:
250
+ if alpha > 200: # If alpha is too high for these elements
251
+ alpha = 125.0 # Use a more appropriate default
252
+
253
+ # Create RGBA color
254
+ rgba = (*rgb, int(alpha))
255
+
256
+ # Update color and opacity
257
+ self.set_property(element, "color", rgba)
258
+ self.set_property(element, "opacity", alpha / 255.0)
259
+
260
+ # Check for disabled elements using specific boolean flags
261
+ # Map element disable flags to DrawableElement enum values
262
+ element_disable_mapping = {
263
+ "disable_floor": DrawableElement.FLOOR,
264
+ "disable_wall": DrawableElement.WALL,
265
+ "disable_robot": DrawableElement.ROBOT,
266
+ "disable_charger": DrawableElement.CHARGER,
267
+ "disable_virtual_walls": DrawableElement.VIRTUAL_WALL,
268
+ "disable_restricted_areas": DrawableElement.RESTRICTED_AREA,
269
+ "disable_no_mop_areas": DrawableElement.NO_MOP_AREA,
270
+ "disable_obstacles": DrawableElement.OBSTACLE,
271
+ "disable_path": DrawableElement.PATH,
272
+ "disable_predicted_path": DrawableElement.PREDICTED_PATH,
273
+ "disable_go_to_target": DrawableElement.GO_TO_TARGET,
274
+ }
275
+
276
+ # Process base element disable flags
277
+ for disable_key, element in element_disable_mapping.items():
278
+ if device_info.get(disable_key, False):
279
+ self.disable_element(element)
280
+ LOGGER.info(
281
+ "Disabled %s element from device_info setting", element.name
282
+ )
283
+
284
+ # Process room disable flags (1-15)
285
+ for room_id in range(1, 16):
286
+ disable_key = f"disable_room_{room_id}"
287
+ if device_info.get(disable_key, False):
288
+ room_element = getattr(DrawableElement, f"ROOM_{room_id}")
289
+ self.disable_element(room_element)
290
+ LOGGER.info(
291
+ "Disabled ROOM_%d element from device_info setting", room_id
292
+ )
@@ -0,0 +1,324 @@
1
+ """
2
+ Enhanced Drawable Class.
3
+ Provides drawing utilities with element selection support.
4
+ Version: 0.1.9
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import logging
10
+
11
+ # math is not used in this file
12
+ from typing import Optional, Tuple
13
+
14
+ import numpy as np
15
+
16
+ from .colors import ColorsManagement
17
+ from .drawable import Drawable
18
+ from .drawable_elements import (
19
+ DrawableElement,
20
+ DrawingConfig,
21
+ )
22
+
23
+
24
+ # Type aliases
25
+ NumpyArray = np.ndarray
26
+ Color = Tuple[int, int, int, int]
27
+
28
+ _LOGGER = logging.getLogger(__name__)
29
+
30
+
31
+ class EnhancedDrawable(Drawable):
32
+ """Enhanced drawing utilities with element selection support."""
33
+
34
+ def __init__(self, drawing_config: Optional[DrawingConfig] = None):
35
+ """Initialize with optional drawing configuration."""
36
+ super().__init__()
37
+ self.drawing_config = drawing_config or DrawingConfig()
38
+
39
+ # Color blending methods have been moved to ColorsManagement class in colors.py
40
+
41
+ # Pixel blending methods have been moved to ColorsManagement class in colors.py
42
+
43
+ async def draw_map(
44
+ self, map_data: dict, base_array: Optional[NumpyArray] = None
45
+ ) -> NumpyArray:
46
+ """
47
+ Draw the map with selected elements.
48
+
49
+ Args:
50
+ map_data: The map data dictionary
51
+ base_array: Optional base array to draw on
52
+
53
+ Returns:
54
+ The image array with all elements drawn
55
+ """
56
+ # Get map dimensions
57
+ size_x = map_data.get("size", {}).get("x", 1024)
58
+ size_y = map_data.get("size", {}).get("y", 1024)
59
+
60
+ # Create empty image if none provided
61
+ if base_array is None:
62
+ background_color = self.drawing_config.get_property(
63
+ DrawableElement.FLOOR, "color", (200, 200, 200, 255)
64
+ )
65
+ base_array = await self.create_empty_image(size_x, size_y, background_color)
66
+
67
+ # Draw elements in order of z-index
68
+ for element in self.drawing_config.get_drawing_order():
69
+ if element == DrawableElement.FLOOR:
70
+ base_array = await self._draw_floor(map_data, base_array)
71
+ elif element == DrawableElement.WALL:
72
+ base_array = await self._draw_walls(map_data, base_array)
73
+ elif element == DrawableElement.ROBOT:
74
+ base_array = await self._draw_robot(map_data, base_array)
75
+ elif element == DrawableElement.CHARGER:
76
+ base_array = await self._draw_charger(map_data, base_array)
77
+ elif element == DrawableElement.VIRTUAL_WALL:
78
+ base_array = await self._draw_virtual_walls(map_data, base_array)
79
+ elif element == DrawableElement.RESTRICTED_AREA:
80
+ base_array = await self._draw_restricted_areas(map_data, base_array)
81
+ elif element == DrawableElement.NO_MOP_AREA:
82
+ base_array = await self._draw_no_mop_areas(map_data, base_array)
83
+ elif element == DrawableElement.PATH:
84
+ base_array = await self._draw_path(map_data, base_array)
85
+ elif element == DrawableElement.PREDICTED_PATH:
86
+ base_array = await self._draw_predicted_path(map_data, base_array)
87
+ elif element == DrawableElement.GO_TO_TARGET:
88
+ base_array = await self._draw_go_to_target(map_data, base_array)
89
+ elif DrawableElement.ROOM_1 <= element <= DrawableElement.ROOM_15:
90
+ room_id = element - DrawableElement.ROOM_1 + 1
91
+ base_array = await self._draw_room(map_data, room_id, base_array)
92
+
93
+ return base_array
94
+
95
+ async def _draw_floor(self, map_data: dict, array: NumpyArray) -> NumpyArray:
96
+ """Draw the floor layer."""
97
+ if not self.drawing_config.is_enabled(DrawableElement.FLOOR):
98
+ return array
99
+
100
+ # Implementation depends on the map data format
101
+ # This is a placeholder - actual implementation would use map_data to draw floor
102
+
103
+ return array
104
+
105
+ async def _draw_walls(self, map_data: dict, array: NumpyArray) -> NumpyArray:
106
+ """Draw the walls."""
107
+ if not self.drawing_config.is_enabled(DrawableElement.WALL):
108
+ return array
109
+
110
+ # Get wall color from drawing config
111
+ wall_color = self.drawing_config.get_property(
112
+ DrawableElement.WALL, "color", (255, 255, 0, 255)
113
+ )
114
+
115
+ # Implementation depends on the map data format
116
+ # For Valetudo maps, we would look at the layers with type "wall"
117
+ # This is a simplified example - in a real implementation, we would extract the actual wall pixels
118
+
119
+ # Find wall data in map_data
120
+ wall_pixels = []
121
+ for layer in map_data.get("layers", []):
122
+ if layer.get("type") == "wall":
123
+ # Extract wall pixels from the layer
124
+ # This is a placeholder - actual implementation would depend on the map data format
125
+ wall_pixels = layer.get("pixels", [])
126
+ break
127
+
128
+ # Draw wall pixels with color blending
129
+ for x, y in wall_pixels:
130
+ # Use sample_and_blend_color from ColorsManagement
131
+ blended_color = ColorsManagement.sample_and_blend_color(
132
+ array, x, y, wall_color
133
+ )
134
+ if 0 <= y < array.shape[0] and 0 <= x < array.shape[1]:
135
+ array[y, x] = blended_color
136
+
137
+ return array
138
+
139
+ async def _draw_robot(self, map_data: dict, array: NumpyArray) -> NumpyArray:
140
+ """Draw the robot."""
141
+ if not self.drawing_config.is_enabled(DrawableElement.ROBOT):
142
+ return array
143
+
144
+ # Get robot color from drawing config
145
+ robot_color = self.drawing_config.get_property(
146
+ DrawableElement.ROBOT, "color", (255, 255, 204, 255)
147
+ )
148
+
149
+ # Extract robot position and angle from map_data
150
+ robot_position = map_data.get("robot", {}).get("position", None)
151
+ robot_angle = map_data.get("robot", {}).get("angle", 0)
152
+
153
+ if robot_position:
154
+ x, y = robot_position.get("x", 0), robot_position.get("y", 0)
155
+
156
+ # Draw robot with color blending
157
+ # Create a circle around the robot position
158
+ radius = 25 # Same as in the robot drawing method
159
+ for dy in range(-radius, radius + 1):
160
+ for dx in range(-radius, radius + 1):
161
+ if dx * dx + dy * dy <= radius * radius:
162
+ map_x, map_y = int(x + dx), int(y + dy)
163
+ # Use sample_and_blend_color from ColorsManagement
164
+ blended_color = ColorsManagement.sample_and_blend_color(
165
+ array, map_x, map_y, robot_color
166
+ )
167
+ if 0 <= map_y < array.shape[0] and 0 <= map_x < array.shape[1]:
168
+ array[map_y, map_x] = blended_color
169
+ return array
170
+
171
+ async def _draw_charger(self, map_data: dict, array: NumpyArray) -> NumpyArray:
172
+ """Draw the charger."""
173
+ if not self.drawing_config.is_enabled(DrawableElement.CHARGER):
174
+ return array
175
+
176
+ # Get charger color from drawing config
177
+ charger_color = self.drawing_config.get_property(
178
+ DrawableElement.CHARGER, "color", (255, 128, 0, 255)
179
+ )
180
+
181
+ # Implementation depends on the map data format
182
+ # This would extract charger data from map_data and draw it
183
+
184
+ return array
185
+
186
+ async def _draw_virtual_walls(
187
+ self, map_data: dict, array: NumpyArray
188
+ ) -> NumpyArray:
189
+ """Draw virtual walls."""
190
+ if not self.drawing_config.is_enabled(DrawableElement.VIRTUAL_WALL):
191
+ return array
192
+
193
+ # Get virtual wall color from drawing config
194
+ wall_color = self.drawing_config.get_property(
195
+ DrawableElement.VIRTUAL_WALL, "color", (255, 0, 0, 255)
196
+ )
197
+
198
+ # Implementation depends on the map data format
199
+ # This would extract virtual wall data from map_data and draw it
200
+
201
+ return array
202
+
203
+ async def _draw_restricted_areas(
204
+ self, map_data: dict, array: NumpyArray
205
+ ) -> NumpyArray:
206
+ """Draw restricted areas."""
207
+ if not self.drawing_config.is_enabled(DrawableElement.RESTRICTED_AREA):
208
+ return array
209
+
210
+ # Get restricted area color from drawing config
211
+ area_color = self.drawing_config.get_property(
212
+ DrawableElement.RESTRICTED_AREA, "color", (255, 0, 0, 125)
213
+ )
214
+
215
+ # Implementation depends on the map data format
216
+ # This would extract restricted area data from map_data and draw it
217
+
218
+ return array
219
+
220
+ async def _draw_no_mop_areas(self, map_data: dict, array: NumpyArray) -> NumpyArray:
221
+ """Draw no-mop areas."""
222
+ if not self.drawing_config.is_enabled(DrawableElement.NO_MOP_AREA):
223
+ return array
224
+
225
+ # Get no-mop area color from drawing config
226
+ area_color = self.drawing_config.get_property(
227
+ DrawableElement.NO_MOP_AREA, "color", (0, 0, 255, 125)
228
+ )
229
+
230
+ # Implementation depends on the map data format
231
+ # This would extract no-mop area data from map_data and draw it
232
+
233
+ return array
234
+
235
+ async def _draw_path(self, map_data: dict, array: NumpyArray) -> NumpyArray:
236
+ """Draw the robot's path."""
237
+ if not self.drawing_config.is_enabled(DrawableElement.PATH):
238
+ return array
239
+
240
+ # Get path color from drawing config
241
+ path_color = self.drawing_config.get_property(
242
+ DrawableElement.PATH, "color", (238, 247, 255, 255)
243
+ )
244
+
245
+ # Implementation depends on the map data format
246
+ # This would extract path data from map_data and draw it
247
+
248
+ return array
249
+
250
+ async def _draw_predicted_path(
251
+ self, map_data: dict, array: NumpyArray
252
+ ) -> NumpyArray:
253
+ """Draw the predicted path."""
254
+ if not self.drawing_config.is_enabled(DrawableElement.PREDICTED_PATH):
255
+ return array
256
+
257
+ # Get predicted path color from drawing config
258
+ path_color = self.drawing_config.get_property(
259
+ DrawableElement.PREDICTED_PATH, "color", (238, 247, 255, 125)
260
+ )
261
+
262
+ # Implementation depends on the map data format
263
+ # This would extract predicted path data from map_data and draw it
264
+
265
+ return array
266
+
267
+ async def _draw_go_to_target(self, map_data: dict, array: NumpyArray) -> NumpyArray:
268
+ """Draw the go-to target."""
269
+ if not self.drawing_config.is_enabled(DrawableElement.GO_TO_TARGET):
270
+ return array
271
+
272
+ # Get go-to target color from drawing config
273
+ target_color = self.drawing_config.get_property(
274
+ DrawableElement.GO_TO_TARGET, "color", (0, 255, 0, 255)
275
+ )
276
+
277
+ # Implementation depends on the map data format
278
+ # This would extract go-to target data from map_data and draw it
279
+
280
+ return array
281
+
282
+ async def _draw_room(
283
+ self, map_data: dict, room_id: int, array: NumpyArray
284
+ ) -> NumpyArray:
285
+ """Draw a specific room."""
286
+ element = getattr(DrawableElement, f"ROOM_{room_id}")
287
+ if not self.drawing_config.is_enabled(element):
288
+ return array
289
+
290
+ # Get room color from drawing config
291
+ room_color = self.drawing_config.get_property(
292
+ element,
293
+ "color",
294
+ (135, 206, 250, 255), # Default light blue
295
+ )
296
+
297
+ # Implementation depends on the map data format
298
+ # For Valetudo maps, we would look at the layers with type "segment"
299
+ # This is a simplified example - in a real implementation, we would extract the actual room pixels
300
+
301
+ # Find room data in map_data
302
+ room_pixels = []
303
+ for layer in map_data.get("layers", []):
304
+ if layer.get("type") == "segment" and str(
305
+ layer.get("metaData", {}).get("segmentId")
306
+ ) == str(room_id):
307
+ # Extract room pixels from the layer
308
+ # This is a placeholder - actual implementation would depend on the map data format
309
+ # For example, it might use compressed pixels or other data structures
310
+
311
+ # For demonstration, let's assume we have a list of (x, y) coordinates
312
+ room_pixels = layer.get("pixels", [])
313
+ break
314
+
315
+ # Draw room pixels with color blending
316
+ for x, y in room_pixels:
317
+ # Use sample_and_blend_color from ColorsManagement
318
+ blended_color = ColorsManagement.sample_and_blend_color(
319
+ array, x, y, room_color
320
+ )
321
+ if 0 <= y < array.shape[0] and 0 <= x < array.shape[1]:
322
+ array[y, x] = blended_color
323
+
324
+ return array