valetudo-map-parser 0.1.9b41__py3-none-any.whl → 0.1.9b42__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 +6 -3
- valetudo_map_parser/config/drawable.py +22 -2
- valetudo_map_parser/config/drawable_elements.py +312 -0
- valetudo_map_parser/config/enhanced_drawable.py +447 -0
- valetudo_map_parser/config/shared.py +27 -0
- valetudo_map_parser/config/types.py +2 -1
- valetudo_map_parser/config/utils.py +410 -1
- valetudo_map_parser/hypfer_draw.py +194 -60
- valetudo_map_parser/hypfer_handler.py +344 -40
- valetudo_map_parser/rand25_handler.py +223 -38
- valetudo_map_parser-0.1.9b42.dist-info/METADATA +92 -0
- valetudo_map_parser-0.1.9b42.dist-info/RECORD +23 -0
- {valetudo_map_parser-0.1.9b41.dist-info → valetudo_map_parser-0.1.9b42.dist-info}/WHEEL +1 -1
- valetudo_map_parser-0.1.9b41.dist-info/METADATA +0 -47
- valetudo_map_parser-0.1.9b41.dist-info/RECORD +0 -21
- {valetudo_map_parser-0.1.9b41.dist-info → valetudo_map_parser-0.1.9b42.dist-info}/LICENSE +0 -0
- {valetudo_map_parser-0.1.9b41.dist-info → valetudo_map_parser-0.1.9b42.dist-info}/NOTICE.txt +0 -0
@@ -8,6 +8,7 @@ from __future__ import annotations
|
|
8
8
|
|
9
9
|
import logging
|
10
10
|
|
11
|
+
from .config.drawable_elements import DrawableElement
|
11
12
|
from .config.types import Color, JsonType, NumpyArray, RobotPosition
|
12
13
|
|
13
14
|
|
@@ -44,8 +45,22 @@ class ImageDraw:
|
|
44
45
|
color_wall,
|
45
46
|
color_zone_clean,
|
46
47
|
pixel_size,
|
48
|
+
disabled_rooms=None,
|
47
49
|
):
|
48
|
-
"""Draw the base layer of the map.
|
50
|
+
"""Draw the base layer of the map.
|
51
|
+
|
52
|
+
Args:
|
53
|
+
img_np_array: The image array to draw on
|
54
|
+
compressed_pixels_list: The list of compressed pixels to draw
|
55
|
+
layer_type: The type of layer to draw (segment, floor, wall)
|
56
|
+
color_wall: The color to use for walls
|
57
|
+
color_zone_clean: The color to use for clean zones
|
58
|
+
pixel_size: The size of each pixel
|
59
|
+
disabled_rooms: A set of room IDs that are disabled
|
60
|
+
|
61
|
+
Returns:
|
62
|
+
A tuple of (room_id, img_np_array)
|
63
|
+
"""
|
49
64
|
room_id = 0
|
50
65
|
|
51
66
|
for compressed_pixels in compressed_pixels_list:
|
@@ -62,7 +77,7 @@ class ImageDraw:
|
|
62
77
|
)
|
63
78
|
elif layer_type == "wall":
|
64
79
|
img_np_array = await self._process_wall_layer(
|
65
|
-
img_np_array, pixels, pixel_size, color_wall
|
80
|
+
img_np_array, pixels, pixel_size, color_wall, disabled_rooms
|
66
81
|
)
|
67
82
|
|
68
83
|
return room_id, img_np_array
|
@@ -71,6 +86,25 @@ class ImageDraw:
|
|
71
86
|
self, img_np_array, pixels, layer_type, room_id, pixel_size, color_zone_clean
|
72
87
|
):
|
73
88
|
"""Process a room layer (segment or floor)."""
|
89
|
+
# Check if this room should be drawn
|
90
|
+
draw_room = True
|
91
|
+
if layer_type == "segment" and hasattr(self.img_h, "drawing_config"):
|
92
|
+
# The room_id is 0-based, but DrawableElement.ROOM_x is 1-based
|
93
|
+
current_room_id = room_id + 1
|
94
|
+
if 1 <= current_room_id <= 15:
|
95
|
+
# Use the DrawableElement imported at the top of the file
|
96
|
+
|
97
|
+
room_element = getattr(DrawableElement, f"ROOM_{current_room_id}", None)
|
98
|
+
if room_element and hasattr(self.img_h.drawing_config, "is_enabled"):
|
99
|
+
draw_room = self.img_h.drawing_config.is_enabled(room_element)
|
100
|
+
_LOGGER.debug(
|
101
|
+
"%s: Room %d is %s",
|
102
|
+
self.file_name,
|
103
|
+
current_room_id,
|
104
|
+
"enabled" if draw_room else "disabled",
|
105
|
+
)
|
106
|
+
|
107
|
+
# Get the room color
|
74
108
|
room_color = self.img_h.shared.rooms_colors[room_id]
|
75
109
|
|
76
110
|
try:
|
@@ -79,13 +113,18 @@ class ImageDraw:
|
|
79
113
|
room_id, room_color, color_zone_clean
|
80
114
|
)
|
81
115
|
|
82
|
-
|
83
|
-
|
84
|
-
|
116
|
+
# Only draw the room if it's enabled
|
117
|
+
if draw_room:
|
118
|
+
img_np_array = await self.img_h.draw.from_json_to_image(
|
119
|
+
img_np_array, pixels, pixel_size, room_color
|
120
|
+
)
|
121
|
+
|
122
|
+
# Always increment the room_id, even if the room is not drawn
|
85
123
|
room_id = (room_id + 1) % 16 # Cycle room_id back to 0 after 15
|
86
124
|
|
87
125
|
except IndexError as e:
|
88
126
|
_LOGGER.warning("%s: Image Draw Error: %s", self.file_name, str(e))
|
127
|
+
|
89
128
|
_LOGGER.debug(
|
90
129
|
"%s Active Zones: %s and Room ID: %s",
|
91
130
|
self.file_name,
|
@@ -104,12 +143,106 @@ class ImageDraw:
|
|
104
143
|
)
|
105
144
|
return room_color
|
106
145
|
|
107
|
-
async def _process_wall_layer(
|
108
|
-
|
109
|
-
|
110
|
-
|
146
|
+
async def _process_wall_layer(
|
147
|
+
self, img_np_array, pixels, pixel_size, color_wall, disabled_rooms=None
|
148
|
+
):
|
149
|
+
"""Process a wall layer.
|
150
|
+
|
151
|
+
Args:
|
152
|
+
img_np_array: The image array to draw on
|
153
|
+
pixels: The pixels to draw
|
154
|
+
pixel_size: The size of each pixel
|
155
|
+
color_wall: The color to use for the walls
|
156
|
+
disabled_rooms: A set of room IDs that are disabled
|
157
|
+
|
158
|
+
Returns:
|
159
|
+
The updated image array
|
160
|
+
"""
|
161
|
+
# Log the wall color to verify alpha is being passed correctly
|
162
|
+
_LOGGER.debug("%s: Drawing walls with color %s", self.file_name, color_wall)
|
163
|
+
|
164
|
+
# If there are no disabled rooms, draw all walls
|
165
|
+
if not disabled_rooms:
|
166
|
+
return await self.img_h.draw.from_json_to_image(
|
167
|
+
img_np_array, pixels, pixel_size, color_wall
|
168
|
+
)
|
169
|
+
|
170
|
+
# If there are disabled rooms, we need to check each wall pixel
|
171
|
+
# to see if it belongs to a disabled room
|
172
|
+
_LOGGER.debug(
|
173
|
+
"%s: Filtering walls for disabled rooms: %s", self.file_name, disabled_rooms
|
111
174
|
)
|
112
175
|
|
176
|
+
# Get the element map if available
|
177
|
+
element_map = getattr(self.img_h, "element_map", None)
|
178
|
+
if element_map is None:
|
179
|
+
_LOGGER.warning(
|
180
|
+
"%s: Element map not available, drawing all walls", self.file_name
|
181
|
+
)
|
182
|
+
return await self.img_h.draw.from_json_to_image(
|
183
|
+
img_np_array, pixels, pixel_size, color_wall
|
184
|
+
)
|
185
|
+
|
186
|
+
# Filter out walls that belong to disabled rooms
|
187
|
+
filtered_pixels = []
|
188
|
+
for x, y, z in pixels:
|
189
|
+
# Check if this wall pixel is adjacent to a disabled room
|
190
|
+
# by checking the surrounding pixels in the element map
|
191
|
+
is_disabled_room_wall = False
|
192
|
+
|
193
|
+
# Check the element map at this position and surrounding positions
|
194
|
+
# to see if this wall is adjacent to a disabled room
|
195
|
+
for dx in range(-1, 2):
|
196
|
+
for dy in range(-1, 2):
|
197
|
+
# Skip the center pixel
|
198
|
+
if dx == 0 and dy == 0:
|
199
|
+
continue
|
200
|
+
|
201
|
+
# Calculate the position to check
|
202
|
+
check_x = x + dx
|
203
|
+
check_y = y + dy
|
204
|
+
|
205
|
+
# Make sure the position is within bounds
|
206
|
+
if (
|
207
|
+
check_x < 0
|
208
|
+
or check_y < 0
|
209
|
+
or check_x >= element_map.shape[1]
|
210
|
+
or check_y >= element_map.shape[0]
|
211
|
+
):
|
212
|
+
continue
|
213
|
+
|
214
|
+
# Get the element at this position
|
215
|
+
element = element_map[check_y, check_x]
|
216
|
+
|
217
|
+
# Check if this element is a disabled room
|
218
|
+
# Room elements are in the range 101-115 (ROOM_1 to ROOM_15)
|
219
|
+
if 101 <= element <= 115:
|
220
|
+
room_id = element - 101 # Convert to 0-based index
|
221
|
+
if room_id in disabled_rooms:
|
222
|
+
is_disabled_room_wall = True
|
223
|
+
break
|
224
|
+
|
225
|
+
if is_disabled_room_wall:
|
226
|
+
break
|
227
|
+
|
228
|
+
# If this wall is not adjacent to a disabled room, add it to the filtered pixels
|
229
|
+
if not is_disabled_room_wall:
|
230
|
+
filtered_pixels.append((x, y, z))
|
231
|
+
|
232
|
+
# Draw the filtered walls
|
233
|
+
_LOGGER.debug(
|
234
|
+
"%s: Drawing %d of %d wall pixels after filtering",
|
235
|
+
self.file_name,
|
236
|
+
len(filtered_pixels),
|
237
|
+
len(pixels),
|
238
|
+
)
|
239
|
+
if filtered_pixels:
|
240
|
+
return await self.img_h.draw.from_json_to_image(
|
241
|
+
img_np_array, filtered_pixels, pixel_size, color_wall
|
242
|
+
)
|
243
|
+
|
244
|
+
return img_np_array
|
245
|
+
|
113
246
|
async def async_draw_obstacle(
|
114
247
|
self, np_array: NumpyArray, entity_dict: dict, color_no_go: Color
|
115
248
|
) -> NumpyArray:
|
@@ -118,6 +251,7 @@ class ImageDraw:
|
|
118
251
|
obstacle_data = entity_dict.get("obstacle")
|
119
252
|
except KeyError:
|
120
253
|
_LOGGER.info("%s No obstacle found.", self.file_name)
|
254
|
+
return np_array
|
121
255
|
else:
|
122
256
|
obstacle_positions = []
|
123
257
|
if obstacle_data:
|
@@ -151,6 +285,7 @@ class ImageDraw:
|
|
151
285
|
charger_pos = entity_dict.get("charger_location")
|
152
286
|
except KeyError:
|
153
287
|
_LOGGER.warning("%s: No charger position found.", self.file_name)
|
288
|
+
return np_array
|
154
289
|
else:
|
155
290
|
if charger_pos:
|
156
291
|
charger_pos = charger_pos[0]["points"]
|
@@ -311,58 +446,57 @@ class ImageDraw:
|
|
311
446
|
self.img_h.zooming = False
|
312
447
|
return temp
|
313
448
|
# else we need to search and use the async method.
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
"room": str(room["name"]),
|
328
|
-
}
|
329
|
-
room_count += 1
|
330
|
-
# Check if the robot coordinates are inside the room's corners
|
331
|
-
if (
|
332
|
-
(self.img_h.robot_in_room["right"] >= int(robot_x))
|
333
|
-
and (self.img_h.robot_in_room["left"] <= int(robot_x))
|
334
|
-
) and (
|
335
|
-
(self.img_h.robot_in_room["down"] >= int(robot_y))
|
336
|
-
and (self.img_h.robot_in_room["up"] <= int(robot_y))
|
337
|
-
):
|
338
|
-
temp = {
|
339
|
-
"x": robot_x,
|
340
|
-
"y": robot_y,
|
341
|
-
"angle": angle,
|
342
|
-
"in_room": self.img_h.robot_in_room["room"],
|
343
|
-
}
|
344
|
-
_LOGGER.debug(
|
345
|
-
"%s is in %s room.",
|
346
|
-
self.file_name,
|
347
|
-
self.img_h.robot_in_room["room"],
|
348
|
-
)
|
349
|
-
del room, corners, robot_x, robot_y # free memory.
|
350
|
-
return temp
|
351
|
-
del room, corners # free memory.
|
352
|
-
_LOGGER.debug(
|
353
|
-
"%s not located within Camera Rooms coordinates.",
|
354
|
-
self.file_name,
|
355
|
-
)
|
356
|
-
self.img_h.robot_in_room = last_room
|
357
|
-
self.img_h.zooming = False
|
358
|
-
temp = {
|
359
|
-
"x": robot_x,
|
360
|
-
"y": robot_y,
|
361
|
-
"angle": angle,
|
362
|
-
"in_room": last_room["room"] if last_room else None,
|
449
|
+
last_room = None
|
450
|
+
room_count = 0
|
451
|
+
if self.img_h.robot_in_room:
|
452
|
+
last_room = self.img_h.robot_in_room
|
453
|
+
for room in self.img_h.rooms_pos:
|
454
|
+
corners = room["corners"]
|
455
|
+
self.img_h.robot_in_room = {
|
456
|
+
"id": room_count,
|
457
|
+
"left": int(corners[0][0]),
|
458
|
+
"right": int(corners[2][0]),
|
459
|
+
"up": int(corners[0][1]),
|
460
|
+
"down": int(corners[2][1]),
|
461
|
+
"room": str(room["name"]),
|
363
462
|
}
|
364
|
-
|
365
|
-
|
463
|
+
room_count += 1
|
464
|
+
# Check if the robot coordinates are inside the room's corners
|
465
|
+
if (
|
466
|
+
(self.img_h.robot_in_room["right"] >= int(robot_x))
|
467
|
+
and (self.img_h.robot_in_room["left"] <= int(robot_x))
|
468
|
+
) and (
|
469
|
+
(self.img_h.robot_in_room["down"] >= int(robot_y))
|
470
|
+
and (self.img_h.robot_in_room["up"] <= int(robot_y))
|
471
|
+
):
|
472
|
+
temp = {
|
473
|
+
"x": robot_x,
|
474
|
+
"y": robot_y,
|
475
|
+
"angle": angle,
|
476
|
+
"in_room": self.img_h.robot_in_room["room"],
|
477
|
+
}
|
478
|
+
_LOGGER.debug(
|
479
|
+
"%s is in %s room.",
|
480
|
+
self.file_name,
|
481
|
+
self.img_h.robot_in_room["room"],
|
482
|
+
)
|
483
|
+
del room, corners, robot_x, robot_y # free memory.
|
484
|
+
return temp
|
485
|
+
del room, corners # free memory.
|
486
|
+
_LOGGER.debug(
|
487
|
+
"%s not located within Camera Rooms coordinates.",
|
488
|
+
self.file_name,
|
489
|
+
)
|
490
|
+
self.img_h.robot_in_room = last_room
|
491
|
+
self.img_h.zooming = False
|
492
|
+
temp = {
|
493
|
+
"x": robot_x,
|
494
|
+
"y": robot_y,
|
495
|
+
"angle": angle,
|
496
|
+
"in_room": last_room["room"] if last_room else None,
|
497
|
+
}
|
498
|
+
# If the robot is not inside any room, return a default value
|
499
|
+
return temp
|
366
500
|
|
367
501
|
async def async_get_robot_position(self, entity_dict: dict) -> tuple | None:
|
368
502
|
"""Get the robot position from the entity data."""
|