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,406 @@
|
|
1
|
+
"""
|
2
|
+
Optimized Element Map Generator.
|
3
|
+
Uses scipy for efficient element map generation and processing.
|
4
|
+
Version: 0.1.9
|
5
|
+
"""
|
6
|
+
|
7
|
+
from __future__ import annotations
|
8
|
+
|
9
|
+
import logging
|
10
|
+
import numpy as np
|
11
|
+
from scipy import ndimage
|
12
|
+
|
13
|
+
from .drawable_elements import DrawableElement, DrawingConfig
|
14
|
+
from .types import LOGGER
|
15
|
+
|
16
|
+
|
17
|
+
class OptimizedElementMapGenerator:
|
18
|
+
"""Class for generating 2D element maps from JSON data with optimized performance.
|
19
|
+
|
20
|
+
This class creates a 2D array where each cell contains an integer code
|
21
|
+
representing the element at that position (floor, wall, room, etc.).
|
22
|
+
It uses scipy for efficient processing and supports sparse matrices for memory efficiency.
|
23
|
+
"""
|
24
|
+
|
25
|
+
def __init__(self, drawing_config: DrawingConfig = None, shared_data=None):
|
26
|
+
"""Initialize the optimized element map generator.
|
27
|
+
|
28
|
+
Args:
|
29
|
+
drawing_config: Optional drawing configuration for element properties
|
30
|
+
shared_data: Shared data object for accessing common resources
|
31
|
+
"""
|
32
|
+
self.drawing_config = drawing_config or DrawingConfig()
|
33
|
+
self.shared = shared_data
|
34
|
+
self.element_map = None
|
35
|
+
self.element_map_shape = None
|
36
|
+
self.scale_info = None
|
37
|
+
self.file_name = (
|
38
|
+
getattr(shared_data, "file_name", "ElementMap")
|
39
|
+
if shared_data
|
40
|
+
else "ElementMap"
|
41
|
+
)
|
42
|
+
|
43
|
+
async def async_generate_from_json(self, json_data, existing_element_map=None):
|
44
|
+
"""Generate a 2D element map from JSON data with optimized performance.
|
45
|
+
|
46
|
+
Args:
|
47
|
+
json_data: The JSON data from the vacuum
|
48
|
+
existing_element_map: Optional pre-created element map to populate
|
49
|
+
|
50
|
+
Returns:
|
51
|
+
numpy.ndarray: The 2D element map
|
52
|
+
"""
|
53
|
+
if not self.shared:
|
54
|
+
LOGGER.warning("Shared data not provided, some features may not work.")
|
55
|
+
return None
|
56
|
+
|
57
|
+
# Use existing element map if provided
|
58
|
+
if existing_element_map is not None:
|
59
|
+
self.element_map = existing_element_map
|
60
|
+
return existing_element_map
|
61
|
+
|
62
|
+
# Detect JSON format
|
63
|
+
is_valetudo = "layers" in json_data and "pixelSize" in json_data
|
64
|
+
is_rand256 = "map_data" in json_data
|
65
|
+
|
66
|
+
if not (is_valetudo or is_rand256):
|
67
|
+
LOGGER.error("Unknown JSON format, cannot generate element map")
|
68
|
+
return None
|
69
|
+
|
70
|
+
if is_valetudo:
|
71
|
+
return await self._generate_valetudo_element_map(json_data)
|
72
|
+
elif is_rand256:
|
73
|
+
return await self._generate_rand256_element_map(json_data)
|
74
|
+
|
75
|
+
async def _generate_valetudo_element_map(self, json_data):
|
76
|
+
"""Generate an element map from Valetudo format JSON data."""
|
77
|
+
# Get map dimensions from the JSON data
|
78
|
+
size_x = json_data["size"]["x"]
|
79
|
+
size_y = json_data["size"]["y"]
|
80
|
+
pixel_size = json_data["pixelSize"]
|
81
|
+
|
82
|
+
# Calculate downscale factor based on pixel size
|
83
|
+
# Standard pixel size is 5mm, so adjust accordingly
|
84
|
+
downscale_factor = max(1, pixel_size // 5 * 2) # More aggressive downscaling
|
85
|
+
|
86
|
+
# Calculate dimensions for the downscaled map
|
87
|
+
map_width = max(100, size_x // (pixel_size * downscale_factor))
|
88
|
+
map_height = max(100, size_y // (pixel_size * downscale_factor))
|
89
|
+
|
90
|
+
LOGGER.info(
|
91
|
+
"%s: Creating optimized element map with dimensions: %dx%d (downscale factor: %d)",
|
92
|
+
self.file_name,
|
93
|
+
map_width,
|
94
|
+
map_height,
|
95
|
+
downscale_factor,
|
96
|
+
)
|
97
|
+
|
98
|
+
# Create the element map at the reduced size
|
99
|
+
element_map = np.zeros((map_height, map_width), dtype=np.int32)
|
100
|
+
element_map[:] = DrawableElement.FLOOR
|
101
|
+
|
102
|
+
# Store scaling information for coordinate conversion
|
103
|
+
self.scale_info = {
|
104
|
+
"original_size": (size_x, size_y),
|
105
|
+
"map_size": (map_width, map_height),
|
106
|
+
"scale_factor": downscale_factor * pixel_size,
|
107
|
+
"pixel_size": pixel_size,
|
108
|
+
}
|
109
|
+
|
110
|
+
# Process layers at the reduced resolution
|
111
|
+
for layer in json_data.get("layers", []):
|
112
|
+
layer_type = layer.get("type")
|
113
|
+
|
114
|
+
# Process rooms (segments)
|
115
|
+
if layer_type == "segment":
|
116
|
+
# Get room ID
|
117
|
+
meta_data = layer.get("metaData", {})
|
118
|
+
segment_id = meta_data.get("segmentId")
|
119
|
+
|
120
|
+
if segment_id is not None:
|
121
|
+
# Convert segment_id to int if it's a string
|
122
|
+
segment_id_int = (
|
123
|
+
int(segment_id) if isinstance(segment_id, str) else segment_id
|
124
|
+
)
|
125
|
+
if 1 <= segment_id_int <= 15:
|
126
|
+
room_element = getattr(
|
127
|
+
DrawableElement, f"ROOM_{segment_id_int}", None
|
128
|
+
)
|
129
|
+
|
130
|
+
# Skip if room is disabled
|
131
|
+
if room_element is None or not self.drawing_config.is_enabled(
|
132
|
+
room_element
|
133
|
+
):
|
134
|
+
continue
|
135
|
+
|
136
|
+
# Create a temporary high-resolution mask for this room
|
137
|
+
temp_mask = np.zeros(
|
138
|
+
(size_y // pixel_size, size_x // pixel_size), dtype=np.uint8
|
139
|
+
)
|
140
|
+
|
141
|
+
# Process pixels for this room
|
142
|
+
compressed_pixels = layer.get("compressedPixels", [])
|
143
|
+
if compressed_pixels:
|
144
|
+
# Process in chunks of 3 (x, y, count)
|
145
|
+
for i in range(0, len(compressed_pixels), 3):
|
146
|
+
if i + 2 < len(compressed_pixels):
|
147
|
+
x = compressed_pixels[i]
|
148
|
+
y = compressed_pixels[i + 1]
|
149
|
+
count = compressed_pixels[i + 2]
|
150
|
+
|
151
|
+
# Set pixels in the high-resolution mask
|
152
|
+
for j in range(count):
|
153
|
+
px = x + j
|
154
|
+
if (
|
155
|
+
0 <= y < temp_mask.shape[0]
|
156
|
+
and 0 <= px < temp_mask.shape[1]
|
157
|
+
):
|
158
|
+
temp_mask[y, px] = 1
|
159
|
+
|
160
|
+
# Use scipy to downsample the mask efficiently
|
161
|
+
# This preserves the room shape better than simple decimation
|
162
|
+
downsampled_mask = ndimage.zoom(
|
163
|
+
temp_mask,
|
164
|
+
(
|
165
|
+
map_height / temp_mask.shape[0],
|
166
|
+
map_width / temp_mask.shape[1],
|
167
|
+
),
|
168
|
+
order=0, # Nearest neighbor interpolation
|
169
|
+
)
|
170
|
+
|
171
|
+
# Apply the downsampled mask to the element map
|
172
|
+
element_map[downsampled_mask > 0] = room_element
|
173
|
+
|
174
|
+
# Clean up
|
175
|
+
del temp_mask, downsampled_mask
|
176
|
+
|
177
|
+
# Process walls similarly
|
178
|
+
elif layer_type == "wall" and self.drawing_config.is_enabled(
|
179
|
+
DrawableElement.WALL
|
180
|
+
):
|
181
|
+
# Create a temporary high-resolution mask for walls
|
182
|
+
temp_mask = np.zeros(
|
183
|
+
(size_y // pixel_size, size_x // pixel_size), dtype=np.uint8
|
184
|
+
)
|
185
|
+
|
186
|
+
# Process compressed pixels for walls
|
187
|
+
compressed_pixels = layer.get("compressedPixels", [])
|
188
|
+
if compressed_pixels:
|
189
|
+
# Process in chunks of 3 (x, y, count)
|
190
|
+
for i in range(0, len(compressed_pixels), 3):
|
191
|
+
if i + 2 < len(compressed_pixels):
|
192
|
+
x = compressed_pixels[i]
|
193
|
+
y = compressed_pixels[i + 1]
|
194
|
+
count = compressed_pixels[i + 2]
|
195
|
+
|
196
|
+
# Set pixels in the high-resolution mask
|
197
|
+
for j in range(count):
|
198
|
+
px = x + j
|
199
|
+
if (
|
200
|
+
0 <= y < temp_mask.shape[0]
|
201
|
+
and 0 <= px < temp_mask.shape[1]
|
202
|
+
):
|
203
|
+
temp_mask[y, px] = 1
|
204
|
+
|
205
|
+
# Use scipy to downsample the mask efficiently
|
206
|
+
downsampled_mask = ndimage.zoom(
|
207
|
+
temp_mask,
|
208
|
+
(map_height / temp_mask.shape[0], map_width / temp_mask.shape[1]),
|
209
|
+
order=0,
|
210
|
+
)
|
211
|
+
|
212
|
+
# Apply the downsampled mask to the element map
|
213
|
+
# Only overwrite floor pixels, not room pixels
|
214
|
+
wall_mask = (downsampled_mask > 0) & (
|
215
|
+
element_map == DrawableElement.FLOOR
|
216
|
+
)
|
217
|
+
element_map[wall_mask] = DrawableElement.WALL
|
218
|
+
|
219
|
+
# Clean up
|
220
|
+
del temp_mask, downsampled_mask
|
221
|
+
|
222
|
+
# Store the element map
|
223
|
+
self.element_map = element_map
|
224
|
+
self.element_map_shape = element_map.shape
|
225
|
+
|
226
|
+
LOGGER.info(
|
227
|
+
"%s: Element map generation complete with shape: %s",
|
228
|
+
self.file_name,
|
229
|
+
element_map.shape,
|
230
|
+
)
|
231
|
+
return element_map
|
232
|
+
|
233
|
+
async def _generate_rand256_element_map(self, json_data):
|
234
|
+
"""Generate an element map from Rand256 format JSON data."""
|
235
|
+
# Get map dimensions from the Rand256 JSON data
|
236
|
+
map_data = json_data["map_data"]
|
237
|
+
size_x = map_data["dimensions"]["width"]
|
238
|
+
size_y = map_data["dimensions"]["height"]
|
239
|
+
|
240
|
+
# Calculate downscale factor
|
241
|
+
downscale_factor = max(
|
242
|
+
1, min(size_x, size_y) // 500
|
243
|
+
) # Target ~500px in smallest dimension
|
244
|
+
|
245
|
+
# Calculate dimensions for the downscaled map
|
246
|
+
map_width = max(100, size_x // downscale_factor)
|
247
|
+
map_height = max(100, size_y // downscale_factor)
|
248
|
+
|
249
|
+
LOGGER.info(
|
250
|
+
"%s: Creating optimized Rand256 element map with dimensions: %dx%d (downscale factor: %d)",
|
251
|
+
self.file_name,
|
252
|
+
map_width,
|
253
|
+
map_height,
|
254
|
+
downscale_factor,
|
255
|
+
)
|
256
|
+
|
257
|
+
# Create the element map at the reduced size
|
258
|
+
element_map = np.zeros((map_height, map_width), dtype=np.int32)
|
259
|
+
element_map[:] = DrawableElement.FLOOR
|
260
|
+
|
261
|
+
# Store scaling information for coordinate conversion
|
262
|
+
self.scale_info = {
|
263
|
+
"original_size": (size_x, size_y),
|
264
|
+
"map_size": (map_width, map_height),
|
265
|
+
"scale_factor": downscale_factor,
|
266
|
+
"pixel_size": 1, # Rand256 uses 1:1 pixel mapping
|
267
|
+
}
|
268
|
+
|
269
|
+
# Process rooms
|
270
|
+
if "rooms" in map_data and map_data["rooms"]:
|
271
|
+
for room in map_data["rooms"]:
|
272
|
+
# Get room ID and check if it's enabled
|
273
|
+
room_id_int = room["id"]
|
274
|
+
|
275
|
+
# Get room element code (ROOM_1, ROOM_2, etc.)
|
276
|
+
room_element = None
|
277
|
+
if 0 < room_id_int <= 15:
|
278
|
+
room_element = getattr(DrawableElement, f"ROOM_{room_id_int}", None)
|
279
|
+
|
280
|
+
# Skip if room is disabled
|
281
|
+
if room_element is None or not self.drawing_config.is_enabled(
|
282
|
+
room_element
|
283
|
+
):
|
284
|
+
continue
|
285
|
+
|
286
|
+
if "coordinates" in room:
|
287
|
+
# Create a high-resolution mask for this room
|
288
|
+
temp_mask = np.zeros((size_y, size_x), dtype=np.uint8)
|
289
|
+
|
290
|
+
# Fill the mask with room coordinates
|
291
|
+
for coord in room["coordinates"]:
|
292
|
+
x, y = coord
|
293
|
+
if 0 <= y < size_y and 0 <= x < size_x:
|
294
|
+
temp_mask[y, x] = 1
|
295
|
+
|
296
|
+
# Use scipy to downsample the mask efficiently
|
297
|
+
downsampled_mask = ndimage.zoom(
|
298
|
+
temp_mask,
|
299
|
+
(map_height / size_y, map_width / size_x),
|
300
|
+
order=0, # Nearest neighbor interpolation
|
301
|
+
)
|
302
|
+
|
303
|
+
# Apply the downsampled mask to the element map
|
304
|
+
element_map[downsampled_mask > 0] = room_element
|
305
|
+
|
306
|
+
# Clean up
|
307
|
+
del temp_mask, downsampled_mask
|
308
|
+
|
309
|
+
# Process walls
|
310
|
+
if (
|
311
|
+
"walls" in map_data
|
312
|
+
and map_data["walls"]
|
313
|
+
and self.drawing_config.is_enabled(DrawableElement.WALL)
|
314
|
+
):
|
315
|
+
# Create a high-resolution mask for walls
|
316
|
+
temp_mask = np.zeros((size_y, size_x), dtype=np.uint8)
|
317
|
+
|
318
|
+
# Fill the mask with wall coordinates
|
319
|
+
for coord in map_data["walls"]:
|
320
|
+
x, y = coord
|
321
|
+
if 0 <= y < size_y and 0 <= x < size_x:
|
322
|
+
temp_mask[y, x] = 1
|
323
|
+
|
324
|
+
# Use scipy to downsample the mask efficiently
|
325
|
+
downsampled_mask = ndimage.zoom(
|
326
|
+
temp_mask, (map_height / size_y, map_width / size_x), order=0
|
327
|
+
)
|
328
|
+
|
329
|
+
# Apply the downsampled mask to the element map
|
330
|
+
# Only overwrite floor pixels, not room pixels
|
331
|
+
wall_mask = (downsampled_mask > 0) & (element_map == DrawableElement.FLOOR)
|
332
|
+
element_map[wall_mask] = DrawableElement.WALL
|
333
|
+
|
334
|
+
# Clean up
|
335
|
+
del temp_mask, downsampled_mask
|
336
|
+
|
337
|
+
# Store the element map
|
338
|
+
self.element_map = element_map
|
339
|
+
self.element_map_shape = element_map.shape
|
340
|
+
|
341
|
+
LOGGER.info(
|
342
|
+
"%s: Rand256 element map generation complete with shape: %s",
|
343
|
+
self.file_name,
|
344
|
+
element_map.shape,
|
345
|
+
)
|
346
|
+
return element_map
|
347
|
+
|
348
|
+
def map_to_element_coordinates(self, x, y):
|
349
|
+
"""Convert map coordinates to element map coordinates."""
|
350
|
+
if not hasattr(self, "scale_info"):
|
351
|
+
return x, y
|
352
|
+
|
353
|
+
scale = self.scale_info["scale_factor"]
|
354
|
+
return int(x / scale), int(y / scale)
|
355
|
+
|
356
|
+
def element_to_map_coordinates(self, x, y):
|
357
|
+
"""Convert element map coordinates to map coordinates."""
|
358
|
+
if not hasattr(self, "scale_info"):
|
359
|
+
return x, y
|
360
|
+
|
361
|
+
scale = self.scale_info["scale_factor"]
|
362
|
+
return int(x * scale), int(y * scale)
|
363
|
+
|
364
|
+
def get_element_at_position(self, x, y):
|
365
|
+
"""Get the element at the specified position."""
|
366
|
+
if not hasattr(self, "element_map") or self.element_map is None:
|
367
|
+
return None
|
368
|
+
|
369
|
+
if not (
|
370
|
+
0 <= y < self.element_map.shape[0] and 0 <= x < self.element_map.shape[1]
|
371
|
+
):
|
372
|
+
return None
|
373
|
+
|
374
|
+
return self.element_map[y, x]
|
375
|
+
|
376
|
+
def get_room_at_position(self, x, y):
|
377
|
+
"""Get the room ID at a specific position, or None if not a room."""
|
378
|
+
element_code = self.get_element_at_position(x, y)
|
379
|
+
if element_code is None:
|
380
|
+
return None
|
381
|
+
|
382
|
+
# Check if it's a room (codes 101-115)
|
383
|
+
if 101 <= element_code <= 115:
|
384
|
+
return element_code
|
385
|
+
return None
|
386
|
+
|
387
|
+
def get_element_name(self, element_code):
|
388
|
+
"""Get the name of the element from its code."""
|
389
|
+
if element_code is None:
|
390
|
+
return "NONE"
|
391
|
+
|
392
|
+
# Check if it's a room
|
393
|
+
if element_code >= 100:
|
394
|
+
room_number = element_code - 100
|
395
|
+
return f"ROOM_{room_number}"
|
396
|
+
|
397
|
+
# Check standard elements
|
398
|
+
for name, code in vars(DrawableElement).items():
|
399
|
+
if (
|
400
|
+
not name.startswith("_")
|
401
|
+
and isinstance(code, int)
|
402
|
+
and code == element_code
|
403
|
+
):
|
404
|
+
return name
|
405
|
+
|
406
|
+
return f"UNKNOWN_{element_code}"
|
@@ -5,10 +5,11 @@ Version: v2024.08.2
|
|
5
5
|
- Additional functions are to get in our image_handler the images datas.
|
6
6
|
"""
|
7
7
|
|
8
|
-
from enum import Enum
|
9
8
|
import math
|
10
9
|
import struct
|
11
|
-
from
|
10
|
+
from enum import Enum
|
11
|
+
from typing import Any, Callable, Dict, List, Optional, TypeVar
|
12
|
+
|
12
13
|
|
13
14
|
_CallableT = TypeVar("_CallableT", bound=Callable[..., Any])
|
14
15
|
|
@@ -162,7 +163,7 @@ class RRMapParser:
|
|
162
163
|
)
|
163
164
|
if segment_type == 0:
|
164
165
|
continue
|
165
|
-
|
166
|
+
if segment_type == 1 and pixels:
|
166
167
|
parameters["pixels"]["walls"].append(i)
|
167
168
|
else:
|
168
169
|
s = (
|
@@ -266,6 +267,18 @@ class RRMapParser:
|
|
266
267
|
parsed_map_data = {}
|
267
268
|
blocks = self.parse_block(map_buf, 0x14, None, pixels)
|
268
269
|
|
270
|
+
self._parse_image_data(parsed_map_data, blocks)
|
271
|
+
self._parse_charger_data(parsed_map_data, blocks)
|
272
|
+
self._parse_robot_data(parsed_map_data, blocks)
|
273
|
+
self._parse_zones_data(parsed_map_data, blocks)
|
274
|
+
self._parse_virtual_walls_data(parsed_map_data, blocks)
|
275
|
+
self._parse_misc_data(parsed_map_data, blocks)
|
276
|
+
|
277
|
+
return parsed_map_data
|
278
|
+
|
279
|
+
@staticmethod
|
280
|
+
def _parse_image_data(parsed_map_data: Dict[str, Any], blocks: Dict[int, Any]):
|
281
|
+
"""Parse image-related data."""
|
269
282
|
if RRMapParser.Types.IMAGE.value in blocks:
|
270
283
|
parsed_map_data["image"] = blocks[RRMapParser.Types.IMAGE.value]
|
271
284
|
for item in [
|
@@ -290,28 +303,27 @@ class RRMapParser:
|
|
290
303
|
- parsed_map_data[item["path"]]["points"][-2][0],
|
291
304
|
)
|
292
305
|
)
|
306
|
+
|
307
|
+
@staticmethod
|
308
|
+
def _parse_charger_data(parsed_map_data: Dict[str, Any], blocks: Dict[int, Any]):
|
309
|
+
"""Parse charger location data."""
|
293
310
|
if RRMapParser.Types.CHARGER_LOCATION.value in blocks:
|
294
311
|
charger = blocks[RRMapParser.Types.CHARGER_LOCATION.value]["position"]
|
295
|
-
# Assume no transformation needed here
|
296
312
|
parsed_map_data["charger"] = charger
|
297
313
|
|
314
|
+
@staticmethod
|
315
|
+
def _parse_robot_data(parsed_map_data: Dict[str, Any], blocks: Dict[int, Any]):
|
316
|
+
"""Parse robot position data."""
|
298
317
|
if RRMapParser.Types.ROBOT_POSITION.value in blocks:
|
299
318
|
robot = blocks[RRMapParser.Types.ROBOT_POSITION.value]["position"]
|
300
319
|
rob_angle = blocks[RRMapParser.Types.ROBOT_POSITION.value]["angle"]
|
301
|
-
# Assume no transformation needed here
|
302
320
|
parsed_map_data["robot"] = robot
|
303
321
|
parsed_map_data["robot_angle"] = rob_angle
|
304
322
|
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
]["position"]
|
309
|
-
# Assume no transformation needed here
|
310
|
-
|
323
|
+
@staticmethod
|
324
|
+
def _parse_zones_data(parsed_map_data: Dict[str, Any], blocks: Dict[int, Any]):
|
325
|
+
"""Parse zones and forbidden zones data."""
|
311
326
|
if RRMapParser.Types.CURRENTLY_CLEANED_ZONES.value in blocks:
|
312
|
-
parsed_map_data["currently_cleaned_zones"] = blocks[
|
313
|
-
RRMapParser.Types.CURRENTLY_CLEANED_ZONES.value
|
314
|
-
]
|
315
327
|
parsed_map_data["currently_cleaned_zones"] = [
|
316
328
|
[
|
317
329
|
zone[0],
|
@@ -319,13 +331,10 @@ class RRMapParser:
|
|
319
331
|
zone[2],
|
320
332
|
RRMapParser.Tools.DIMENSION_MM - zone[3],
|
321
333
|
]
|
322
|
-
for zone in
|
334
|
+
for zone in blocks[RRMapParser.Types.CURRENTLY_CLEANED_ZONES.value]
|
323
335
|
]
|
324
336
|
|
325
337
|
if RRMapParser.Types.FORBIDDEN_ZONES.value in blocks:
|
326
|
-
parsed_map_data["forbidden_zones"] = blocks[
|
327
|
-
RRMapParser.Types.FORBIDDEN_ZONES.value
|
328
|
-
]
|
329
338
|
parsed_map_data["forbidden_zones"] = [
|
330
339
|
[
|
331
340
|
zone[0],
|
@@ -337,13 +346,15 @@ class RRMapParser:
|
|
337
346
|
zone[6],
|
338
347
|
RRMapParser.Tools.DIMENSION_MM - zone[7],
|
339
348
|
]
|
340
|
-
for zone in
|
349
|
+
for zone in blocks[RRMapParser.Types.FORBIDDEN_ZONES.value]
|
341
350
|
]
|
342
351
|
|
352
|
+
@staticmethod
|
353
|
+
def _parse_virtual_walls_data(
|
354
|
+
parsed_map_data: Dict[str, Any], blocks: Dict[int, Any]
|
355
|
+
):
|
356
|
+
"""Parse virtual walls data."""
|
343
357
|
if RRMapParser.Types.VIRTUAL_WALLS.value in blocks:
|
344
|
-
parsed_map_data["virtual_walls"] = blocks[
|
345
|
-
RRMapParser.Types.VIRTUAL_WALLS.value
|
346
|
-
]
|
347
358
|
parsed_map_data["virtual_walls"] = [
|
348
359
|
[
|
349
360
|
wall[0],
|
@@ -351,18 +362,18 @@ class RRMapParser:
|
|
351
362
|
wall[2],
|
352
363
|
RRMapParser.Tools.DIMENSION_MM - wall[3],
|
353
364
|
]
|
354
|
-
for wall in
|
365
|
+
for wall in blocks[RRMapParser.Types.VIRTUAL_WALLS.value]
|
355
366
|
]
|
356
367
|
|
368
|
+
@staticmethod
|
369
|
+
def _parse_misc_data(parsed_map_data: Dict[str, Any], blocks: Dict[int, Any]):
|
370
|
+
"""Parse miscellaneous data like cleaned blocks and mop zones."""
|
357
371
|
if RRMapParser.Types.CURRENTLY_CLEANED_BLOCKS.value in blocks:
|
358
372
|
parsed_map_data["currently_cleaned_blocks"] = blocks[
|
359
373
|
RRMapParser.Types.CURRENTLY_CLEANED_BLOCKS.value
|
360
374
|
]
|
361
375
|
|
362
376
|
if RRMapParser.Types.FORBIDDEN_MOP_ZONES.value in blocks:
|
363
|
-
parsed_map_data["forbidden_mop_zones"] = blocks[
|
364
|
-
RRMapParser.Types.FORBIDDEN_MOP_ZONES.value
|
365
|
-
]
|
366
377
|
parsed_map_data["forbidden_mop_zones"] = [
|
367
378
|
[
|
368
379
|
zone[0],
|
@@ -374,10 +385,13 @@ class RRMapParser:
|
|
374
385
|
zone[6],
|
375
386
|
RRMapParser.Tools.DIMENSION_MM - zone[7],
|
376
387
|
]
|
377
|
-
for zone in
|
388
|
+
for zone in blocks[RRMapParser.Types.FORBIDDEN_MOP_ZONES.value]
|
378
389
|
]
|
379
390
|
|
380
|
-
|
391
|
+
if RRMapParser.Types.GOTO_TARGET.value in blocks:
|
392
|
+
parsed_map_data["goto_target"] = blocks[
|
393
|
+
RRMapParser.Types.GOTO_TARGET.value
|
394
|
+
]["position"]
|
381
395
|
|
382
396
|
def parse_data(
|
383
397
|
self, payload: Optional[bytes] = None, pixels: bool = False
|