valetudo-map-parser 0.1.8__py3-none-any.whl → 0.1.9a2__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.
- valetudo_map_parser/__init__.py +19 -12
- valetudo_map_parser/config/auto_crop.py +174 -116
- valetudo_map_parser/config/color_utils.py +105 -0
- valetudo_map_parser/config/colors.py +662 -13
- valetudo_map_parser/config/drawable.py +624 -279
- valetudo_map_parser/config/drawable_elements.py +292 -0
- valetudo_map_parser/config/enhanced_drawable.py +324 -0
- valetudo_map_parser/config/optimized_element_map.py +406 -0
- valetudo_map_parser/config/rand25_parser.py +42 -28
- valetudo_map_parser/config/room_outline.py +148 -0
- valetudo_map_parser/config/shared.py +73 -6
- valetudo_map_parser/config/types.py +102 -51
- valetudo_map_parser/config/utils.py +841 -0
- valetudo_map_parser/hypfer_draw.py +398 -132
- valetudo_map_parser/hypfer_handler.py +259 -241
- valetudo_map_parser/hypfer_rooms_handler.py +599 -0
- valetudo_map_parser/map_data.py +45 -64
- valetudo_map_parser/rand25_handler.py +429 -310
- valetudo_map_parser/reimg_draw.py +55 -74
- valetudo_map_parser/rooms_handler.py +470 -0
- valetudo_map_parser-0.1.9a2.dist-info/METADATA +93 -0
- valetudo_map_parser-0.1.9a2.dist-info/RECORD +27 -0
- {valetudo_map_parser-0.1.8.dist-info → valetudo_map_parser-0.1.9a2.dist-info}/WHEEL +1 -1
- valetudo_map_parser/images_utils.py +0 -398
- valetudo_map_parser-0.1.8.dist-info/METADATA +0 -23
- valetudo_map_parser-0.1.8.dist-info/RECORD +0 -20
- {valetudo_map_parser-0.1.8.dist-info → valetudo_map_parser-0.1.9a2.dist-info}/LICENSE +0 -0
- {valetudo_map_parser-0.1.8.dist-info → valetudo_map_parser-0.1.9a2.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
|