valetudo-map-parser 0.1.4__py3-none-any.whl → 0.1.6__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 +4 -2
- valetudo_map_parser/config/auto_crop.py +12 -12
- valetudo_map_parser/config/rand25_parser.py +398 -0
- valetudo_map_parser/hypfer_handler.py +4 -4
- valetudo_map_parser/map_data.py +3 -4
- valetudo_map_parser/rand25_handler.py +455 -0
- valetudo_map_parser/reimg_draw.py +372 -0
- {valetudo_map_parser-0.1.4.dist-info → valetudo_map_parser-0.1.6.dist-info}/METADATA +1 -1
- valetudo_map_parser-0.1.6.dist-info/RECORD +20 -0
- valetudo_map_parser-0.1.4.dist-info/RECORD +0 -17
- {valetudo_map_parser-0.1.4.dist-info → valetudo_map_parser-0.1.6.dist-info}/LICENSE +0 -0
- {valetudo_map_parser-0.1.4.dist-info → valetudo_map_parser-0.1.6.dist-info}/NOTICE.txt +0 -0
- {valetudo_map_parser-0.1.4.dist-info → valetudo_map_parser-0.1.6.dist-info}/WHEEL +0 -0
valetudo_map_parser/__init__.py
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
"""Valetudo map parser.
|
2
|
-
|
3
|
-
|
2
|
+
Version: 0.1.6"""
|
4
3
|
|
5
4
|
from .hypfer_handler import HypferMapImageHandler
|
5
|
+
from .rand25_handler import ReImageHandler
|
6
|
+
from .config.rand25_parser import RRMapParser
|
6
7
|
from .config.shared import CameraShared, CameraSharedManager
|
7
8
|
from .config.colors import ColorsManagment
|
8
9
|
from .config.drawable import Drawable
|
@@ -17,6 +18,7 @@ from .config.types import (
|
|
17
18
|
|
18
19
|
__all__ = [
|
19
20
|
"HypferMapImageHandler",
|
21
|
+
"ReImageHandler",
|
20
22
|
"CameraShared",
|
21
23
|
"CameraSharedManager",
|
22
24
|
"ColorsManagment",
|
@@ -71,18 +71,18 @@ class AutoCrop:
|
|
71
71
|
return trimmed_width, trimmed_height
|
72
72
|
|
73
73
|
async def _async_auto_crop_data(self, tdata=None):
|
74
|
-
"""Load the auto crop data from the
|
75
|
-
|
76
|
-
if not self.imh.auto_crop:
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
74
|
+
"""Load the auto crop data from the Camera config."""
|
75
|
+
# todo: implement this method but from config data
|
76
|
+
# if not self.imh.auto_crop:
|
77
|
+
# trims_data = TrimCropData.from_dict(dict(tdata)).to_list()
|
78
|
+
# (
|
79
|
+
# self.imh.trim_left,
|
80
|
+
# self.imh.trim_up,
|
81
|
+
# self.imh.trim_right,
|
82
|
+
# self.imh.trim_down,
|
83
|
+
# ) = trims_data
|
84
|
+
# self._calculate_trimmed_dimensions()
|
85
|
+
# return trims_data
|
86
86
|
return None
|
87
87
|
|
88
88
|
def auto_crop_offset(self):
|
@@ -0,0 +1,398 @@
|
|
1
|
+
"""
|
2
|
+
Version: v2024.08.2
|
3
|
+
- This parser is the python version of @rand256 valetudo_mapper.
|
4
|
+
- This class is extracting the vacuum binary map_data.
|
5
|
+
- Additional functions are to get in our image_handler the images datas.
|
6
|
+
"""
|
7
|
+
|
8
|
+
from enum import Enum
|
9
|
+
import math
|
10
|
+
import struct
|
11
|
+
from typing import Dict, List, Optional, Callable, TypeVar, Any
|
12
|
+
|
13
|
+
_CallableT = TypeVar("_CallableT", bound=Callable[..., Any])
|
14
|
+
|
15
|
+
|
16
|
+
def callback(func: _CallableT) -> _CallableT:
|
17
|
+
"""Annotation to mark method as safe to call from within the event loop."""
|
18
|
+
setattr(func, "_hass_callback", True) # Attach a custom attribute to the function
|
19
|
+
return func # Return the function without modifying its behavior
|
20
|
+
|
21
|
+
|
22
|
+
# noinspection PyTypeChecker
|
23
|
+
class RRMapParser:
|
24
|
+
"""Parse the map data from the Rand256 vacuum."""
|
25
|
+
|
26
|
+
def __init__(self):
|
27
|
+
self.map_data = None
|
28
|
+
|
29
|
+
class Tools:
|
30
|
+
"""Tools for the RRMapParser."""
|
31
|
+
|
32
|
+
DIMENSION_PIXELS = 1024
|
33
|
+
DIMENSION_MM = 50 * 1024
|
34
|
+
|
35
|
+
class Types(Enum):
|
36
|
+
"""Types of blocks in the RRMapParser."""
|
37
|
+
|
38
|
+
CHARGER_LOCATION = 1
|
39
|
+
IMAGE = 2
|
40
|
+
PATH = 3
|
41
|
+
GOTO_PATH = 4
|
42
|
+
GOTO_PREDICTED_PATH = 5
|
43
|
+
CURRENTLY_CLEANED_ZONES = 6
|
44
|
+
GOTO_TARGET = 7
|
45
|
+
ROBOT_POSITION = 8
|
46
|
+
FORBIDDEN_ZONES = 9
|
47
|
+
VIRTUAL_WALLS = 10
|
48
|
+
CURRENTLY_CLEANED_BLOCKS = 11
|
49
|
+
FORBIDDEN_MOP_ZONES = 12
|
50
|
+
DIGEST = 1024
|
51
|
+
|
52
|
+
@staticmethod
|
53
|
+
def parse_block(
|
54
|
+
buf: bytes,
|
55
|
+
offset: int,
|
56
|
+
result: Optional[Dict[int, Any]] = None,
|
57
|
+
pixels: bool = False,
|
58
|
+
) -> Dict[int, Any]:
|
59
|
+
"""Parse a block of data from the map data."""
|
60
|
+
result = result or {}
|
61
|
+
if len(buf) <= offset:
|
62
|
+
return result
|
63
|
+
|
64
|
+
type_ = struct.unpack("<H", buf[offset : offset + 2])[0]
|
65
|
+
hlength = struct.unpack("<H", buf[offset + 2 : offset + 4])[0]
|
66
|
+
length = struct.unpack("<I", buf[offset + 4 : offset + 8])[0]
|
67
|
+
|
68
|
+
if type_ in (
|
69
|
+
RRMapParser.Types.ROBOT_POSITION.value,
|
70
|
+
RRMapParser.Types.CHARGER_LOCATION.value,
|
71
|
+
):
|
72
|
+
result[type_] = {
|
73
|
+
"position": [
|
74
|
+
int.from_bytes(buf[offset + 8 : offset + 10], byteorder="little"),
|
75
|
+
int.from_bytes(buf[offset + 12 : offset + 14], byteorder="little"),
|
76
|
+
],
|
77
|
+
"angle": (
|
78
|
+
struct.unpack("<i", buf[offset + 16 : offset + 20])[0]
|
79
|
+
if length >= 12
|
80
|
+
else 0
|
81
|
+
),
|
82
|
+
}
|
83
|
+
elif type_ == RRMapParser.Types.IMAGE.value:
|
84
|
+
RRMapParser._parse_image_block(buf, offset, length, hlength, result, pixels)
|
85
|
+
elif type_ in (
|
86
|
+
RRMapParser.Types.PATH.value,
|
87
|
+
RRMapParser.Types.GOTO_PATH.value,
|
88
|
+
RRMapParser.Types.GOTO_PREDICTED_PATH.value,
|
89
|
+
):
|
90
|
+
result[type_] = RRMapParser._parse_path_block(buf, offset, length)
|
91
|
+
elif type_ == RRMapParser.Types.GOTO_TARGET.value:
|
92
|
+
result[type_] = {
|
93
|
+
"position": [
|
94
|
+
struct.unpack("<H", buf[offset + 8 : offset + 10])[0],
|
95
|
+
struct.unpack("<H", buf[offset + 10 : offset + 12])[0],
|
96
|
+
]
|
97
|
+
}
|
98
|
+
elif type_ == RRMapParser.Types.CURRENTLY_CLEANED_ZONES.value:
|
99
|
+
result[type_] = RRMapParser._parse_cleaned_zones(buf, offset, length)
|
100
|
+
elif type_ in (
|
101
|
+
RRMapParser.Types.FORBIDDEN_ZONES.value,
|
102
|
+
RRMapParser.Types.FORBIDDEN_MOP_ZONES.value,
|
103
|
+
RRMapParser.Types.VIRTUAL_WALLS.value,
|
104
|
+
):
|
105
|
+
result[type_] = RRMapParser._parse_forbidden_zones(buf, offset, length)
|
106
|
+
return RRMapParser.parse_block(buf, offset + length + hlength, result, pixels)
|
107
|
+
|
108
|
+
@staticmethod
|
109
|
+
def _parse_image_block(
|
110
|
+
buf: bytes,
|
111
|
+
offset: int,
|
112
|
+
length: int,
|
113
|
+
hlength: int,
|
114
|
+
result: Dict[int, Any],
|
115
|
+
pixels: bool,
|
116
|
+
) -> None:
|
117
|
+
"""Parse the image block of the map data."""
|
118
|
+
g3offset = 4 if hlength > 24 else 0
|
119
|
+
parameters = {
|
120
|
+
"segments": {
|
121
|
+
"count": (
|
122
|
+
struct.unpack("<i", buf[offset + 8 : offset + 12])[0]
|
123
|
+
if g3offset
|
124
|
+
else 0
|
125
|
+
),
|
126
|
+
"id": [],
|
127
|
+
},
|
128
|
+
"position": {
|
129
|
+
"top": struct.unpack(
|
130
|
+
"<i", buf[offset + 8 + g3offset : offset + 12 + g3offset]
|
131
|
+
)[0],
|
132
|
+
"left": struct.unpack(
|
133
|
+
"<i", buf[offset + 12 + g3offset : offset + 16 + g3offset]
|
134
|
+
)[0],
|
135
|
+
},
|
136
|
+
"dimensions": {
|
137
|
+
"height": struct.unpack(
|
138
|
+
"<i", buf[offset + 16 + g3offset : offset + 20 + g3offset]
|
139
|
+
)[0],
|
140
|
+
"width": struct.unpack(
|
141
|
+
"<i", buf[offset + 20 + g3offset : offset + 24 + g3offset]
|
142
|
+
)[0],
|
143
|
+
},
|
144
|
+
"pixels": {"floor": [], "walls": [], "segments": {}},
|
145
|
+
}
|
146
|
+
parameters["position"]["top"] = (
|
147
|
+
RRMapParser.Tools.DIMENSION_PIXELS
|
148
|
+
- parameters["position"]["top"]
|
149
|
+
- parameters["dimensions"]["height"]
|
150
|
+
)
|
151
|
+
if (
|
152
|
+
parameters["dimensions"]["height"] > 0
|
153
|
+
and parameters["dimensions"]["width"] > 0
|
154
|
+
):
|
155
|
+
for i in range(length):
|
156
|
+
segment_type = (
|
157
|
+
struct.unpack(
|
158
|
+
"<B",
|
159
|
+
buf[offset + 24 + g3offset + i : offset + 25 + g3offset + i],
|
160
|
+
)[0]
|
161
|
+
& 0x07
|
162
|
+
)
|
163
|
+
if segment_type == 0:
|
164
|
+
continue
|
165
|
+
elif segment_type == 1 and pixels:
|
166
|
+
parameters["pixels"]["walls"].append(i)
|
167
|
+
else:
|
168
|
+
s = (
|
169
|
+
struct.unpack(
|
170
|
+
"<B",
|
171
|
+
buf[
|
172
|
+
offset + 24 + g3offset + i : offset + 25 + g3offset + i
|
173
|
+
],
|
174
|
+
)[0]
|
175
|
+
>> 3
|
176
|
+
)
|
177
|
+
if s == 0 and pixels:
|
178
|
+
parameters["pixels"]["floor"].append(i)
|
179
|
+
elif s != 0:
|
180
|
+
if s not in parameters["segments"]["id"]:
|
181
|
+
parameters["segments"]["id"].append(s)
|
182
|
+
parameters["segments"]["pixels_seg_" + str(s)] = []
|
183
|
+
if pixels:
|
184
|
+
parameters["segments"]["pixels_seg_" + str(s)].append(i)
|
185
|
+
result[RRMapParser.Types.IMAGE.value] = parameters
|
186
|
+
|
187
|
+
@staticmethod
|
188
|
+
def _parse_path_block(buf: bytes, offset: int, length: int) -> Dict[str, Any]:
|
189
|
+
"""Parse a path block of the map data."""
|
190
|
+
points = [
|
191
|
+
[
|
192
|
+
struct.unpack("<H", buf[offset + 20 + i : offset + 22 + i])[0],
|
193
|
+
struct.unpack("<H", buf[offset + 22 + i : offset + 24 + i])[0],
|
194
|
+
]
|
195
|
+
for i in range(0, length, 4)
|
196
|
+
]
|
197
|
+
return {
|
198
|
+
"current_angle": struct.unpack("<I", buf[offset + 16 : offset + 20])[0],
|
199
|
+
"points": points,
|
200
|
+
}
|
201
|
+
|
202
|
+
@staticmethod
|
203
|
+
def _parse_cleaned_zones(buf: bytes, offset: int, length: int) -> List[List[int]]:
|
204
|
+
"""Parse the cleaned zones block of the map data."""
|
205
|
+
zone_count = struct.unpack("<I", buf[offset + 8 : offset + 12])[0]
|
206
|
+
return (
|
207
|
+
[
|
208
|
+
[
|
209
|
+
struct.unpack("<H", buf[offset + 12 + i : offset + 14 + i])[0],
|
210
|
+
struct.unpack("<H", buf[offset + 14 + i : offset + 16 + i])[0],
|
211
|
+
struct.unpack("<H", buf[offset + 16 + i : offset + 18 + i])[0],
|
212
|
+
struct.unpack("<H", buf[offset + 18 + i : offset + 20 + i])[0],
|
213
|
+
]
|
214
|
+
for i in range(0, length, 8)
|
215
|
+
]
|
216
|
+
if zone_count > 0
|
217
|
+
else []
|
218
|
+
)
|
219
|
+
|
220
|
+
@staticmethod
|
221
|
+
def _parse_forbidden_zones(buf: bytes, offset: int, length: int) -> List[List[int]]:
|
222
|
+
"""Parse the forbidden zones block of the map data."""
|
223
|
+
zone_count = struct.unpack("<I", buf[offset + 8 : offset + 12])[0]
|
224
|
+
return (
|
225
|
+
[
|
226
|
+
[
|
227
|
+
struct.unpack("<H", buf[offset + 12 + i : offset + 14 + i])[0],
|
228
|
+
struct.unpack("<H", buf[offset + 14 + i : offset + 16 + i])[0],
|
229
|
+
struct.unpack("<H", buf[offset + 16 + i : offset + 18 + i])[0],
|
230
|
+
struct.unpack("<H", buf[offset + 18 + i : offset + 20 + i])[0],
|
231
|
+
struct.unpack("<H", buf[offset + 20 + i : offset + 22 + i])[0],
|
232
|
+
struct.unpack("<H", buf[offset + 22 + i : offset + 24 + i])[0],
|
233
|
+
struct.unpack("<H", buf[offset + 24 + i : offset + 26 + i])[0],
|
234
|
+
struct.unpack("<H", buf[offset + 26 + i : offset + 28 + i])[0],
|
235
|
+
]
|
236
|
+
for i in range(0, length, 16)
|
237
|
+
]
|
238
|
+
if zone_count > 0
|
239
|
+
else []
|
240
|
+
)
|
241
|
+
|
242
|
+
@callback
|
243
|
+
def parse(self, map_buf: bytes) -> Dict[str, Any]:
|
244
|
+
"""Parse the map data."""
|
245
|
+
if map_buf[0:2] == b"rr":
|
246
|
+
return {
|
247
|
+
"header_length": struct.unpack("<H", map_buf[2:4])[0],
|
248
|
+
"data_length": struct.unpack("<H", map_buf[4:6])[0],
|
249
|
+
"version": {
|
250
|
+
"major": struct.unpack("<H", map_buf[8:10])[0],
|
251
|
+
"minor": struct.unpack("<H", map_buf[10:12])[0],
|
252
|
+
},
|
253
|
+
"map_index": struct.unpack("<H", map_buf[12:14])[0],
|
254
|
+
"map_sequence": struct.unpack("<H", map_buf[16:18])[0],
|
255
|
+
}
|
256
|
+
return {}
|
257
|
+
|
258
|
+
@callback
|
259
|
+
def parse_rrm_data(
|
260
|
+
self, map_buf: bytes, pixels: bool = False
|
261
|
+
) -> Optional[Dict[str, Any]]:
|
262
|
+
"""Parse the complete map data."""
|
263
|
+
if not self.parse(map_buf).get("map_index"):
|
264
|
+
return None
|
265
|
+
|
266
|
+
parsed_map_data = {}
|
267
|
+
blocks = self.parse_block(map_buf, 0x14, None, pixels)
|
268
|
+
|
269
|
+
if RRMapParser.Types.IMAGE.value in blocks:
|
270
|
+
parsed_map_data["image"] = blocks[RRMapParser.Types.IMAGE.value]
|
271
|
+
for item in [
|
272
|
+
{"type": RRMapParser.Types.PATH.value, "path": "path"},
|
273
|
+
{
|
274
|
+
"type": RRMapParser.Types.GOTO_PREDICTED_PATH.value,
|
275
|
+
"path": "goto_predicted_path",
|
276
|
+
},
|
277
|
+
]:
|
278
|
+
if item["type"] in blocks:
|
279
|
+
parsed_map_data[item["path"]] = blocks[item["type"]]
|
280
|
+
parsed_map_data[item["path"]]["points"] = [
|
281
|
+
[point[0], RRMapParser.Tools.DIMENSION_MM - point[1]]
|
282
|
+
for point in parsed_map_data[item["path"]]["points"]
|
283
|
+
]
|
284
|
+
if len(parsed_map_data[item["path"]]["points"]) >= 2:
|
285
|
+
parsed_map_data[item["path"]]["current_angle"] = math.degrees(
|
286
|
+
math.atan2(
|
287
|
+
parsed_map_data[item["path"]]["points"][-1][1]
|
288
|
+
- parsed_map_data[item["path"]]["points"][-2][1],
|
289
|
+
parsed_map_data[item["path"]]["points"][-1][0]
|
290
|
+
- parsed_map_data[item["path"]]["points"][-2][0],
|
291
|
+
)
|
292
|
+
)
|
293
|
+
if RRMapParser.Types.CHARGER_LOCATION.value in blocks:
|
294
|
+
charger = blocks[RRMapParser.Types.CHARGER_LOCATION.value]["position"]
|
295
|
+
# Assume no transformation needed here
|
296
|
+
parsed_map_data["charger"] = charger
|
297
|
+
|
298
|
+
if RRMapParser.Types.ROBOT_POSITION.value in blocks:
|
299
|
+
robot = blocks[RRMapParser.Types.ROBOT_POSITION.value]["position"]
|
300
|
+
rob_angle = blocks[RRMapParser.Types.ROBOT_POSITION.value]["angle"]
|
301
|
+
# Assume no transformation needed here
|
302
|
+
parsed_map_data["robot"] = robot
|
303
|
+
parsed_map_data["robot_angle"] = rob_angle
|
304
|
+
|
305
|
+
if RRMapParser.Types.GOTO_TARGET.value in blocks:
|
306
|
+
parsed_map_data["goto_target"] = blocks[
|
307
|
+
RRMapParser.Types.GOTO_TARGET.value
|
308
|
+
]["position"]
|
309
|
+
# Assume no transformation needed here
|
310
|
+
|
311
|
+
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
|
+
parsed_map_data["currently_cleaned_zones"] = [
|
316
|
+
[
|
317
|
+
zone[0],
|
318
|
+
RRMapParser.Tools.DIMENSION_MM - zone[1],
|
319
|
+
zone[2],
|
320
|
+
RRMapParser.Tools.DIMENSION_MM - zone[3],
|
321
|
+
]
|
322
|
+
for zone in parsed_map_data["currently_cleaned_zones"]
|
323
|
+
]
|
324
|
+
|
325
|
+
if RRMapParser.Types.FORBIDDEN_ZONES.value in blocks:
|
326
|
+
parsed_map_data["forbidden_zones"] = blocks[
|
327
|
+
RRMapParser.Types.FORBIDDEN_ZONES.value
|
328
|
+
]
|
329
|
+
parsed_map_data["forbidden_zones"] = [
|
330
|
+
[
|
331
|
+
zone[0],
|
332
|
+
RRMapParser.Tools.DIMENSION_MM - zone[1],
|
333
|
+
zone[2],
|
334
|
+
RRMapParser.Tools.DIMENSION_MM - zone[3],
|
335
|
+
zone[4],
|
336
|
+
RRMapParser.Tools.DIMENSION_MM - zone[5],
|
337
|
+
zone[6],
|
338
|
+
RRMapParser.Tools.DIMENSION_MM - zone[7],
|
339
|
+
]
|
340
|
+
for zone in parsed_map_data["forbidden_zones"]
|
341
|
+
]
|
342
|
+
|
343
|
+
if RRMapParser.Types.VIRTUAL_WALLS.value in blocks:
|
344
|
+
parsed_map_data["virtual_walls"] = blocks[
|
345
|
+
RRMapParser.Types.VIRTUAL_WALLS.value
|
346
|
+
]
|
347
|
+
parsed_map_data["virtual_walls"] = [
|
348
|
+
[
|
349
|
+
wall[0],
|
350
|
+
RRMapParser.Tools.DIMENSION_MM - wall[1],
|
351
|
+
wall[2],
|
352
|
+
RRMapParser.Tools.DIMENSION_MM - wall[3],
|
353
|
+
]
|
354
|
+
for wall in parsed_map_data["virtual_walls"]
|
355
|
+
]
|
356
|
+
|
357
|
+
if RRMapParser.Types.CURRENTLY_CLEANED_BLOCKS.value in blocks:
|
358
|
+
parsed_map_data["currently_cleaned_blocks"] = blocks[
|
359
|
+
RRMapParser.Types.CURRENTLY_CLEANED_BLOCKS.value
|
360
|
+
]
|
361
|
+
|
362
|
+
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
|
+
parsed_map_data["forbidden_mop_zones"] = [
|
367
|
+
[
|
368
|
+
zone[0],
|
369
|
+
RRMapParser.Tools.DIMENSION_MM - zone[1],
|
370
|
+
zone[2],
|
371
|
+
RRMapParser.Tools.DIMENSION_MM - zone[3],
|
372
|
+
zone[4],
|
373
|
+
RRMapParser.Tools.DIMENSION_MM - zone[5],
|
374
|
+
zone[6],
|
375
|
+
RRMapParser.Tools.DIMENSION_MM - zone[7],
|
376
|
+
]
|
377
|
+
for zone in parsed_map_data["forbidden_mop_zones"]
|
378
|
+
]
|
379
|
+
|
380
|
+
return parsed_map_data
|
381
|
+
|
382
|
+
def parse_data(
|
383
|
+
self, payload: Optional[bytes] = None, pixels: bool = False
|
384
|
+
) -> Optional[Dict[str, Any]]:
|
385
|
+
"""Get the map data from MQTT and return the json."""
|
386
|
+
if payload:
|
387
|
+
self.map_data = self.parse(payload)
|
388
|
+
self.map_data.update(self.parse_rrm_data(payload, pixels) or {})
|
389
|
+
return self.map_data
|
390
|
+
|
391
|
+
def get_image(self) -> Dict[str, Any]:
|
392
|
+
"""Get the image data from the map data."""
|
393
|
+
return self.map_data.get("image", {})
|
394
|
+
|
395
|
+
@staticmethod
|
396
|
+
def get_int32(data: bytes, address: int) -> int:
|
397
|
+
"""Get a 32-bit integer from the data."""
|
398
|
+
return struct.unpack_from("<i", data, address)[0]
|
@@ -66,10 +66,10 @@ class HypferMapImageHandler:
|
|
66
66
|
self.max_frames = 1024
|
67
67
|
self.zooming = False # zooming the image.
|
68
68
|
self.svg_wait = False # SVG image creation wait.
|
69
|
-
self.trim_down =
|
70
|
-
self.trim_left =
|
71
|
-
self.trim_right =
|
72
|
-
self.trim_up =
|
69
|
+
self.trim_down = 0 # memory stored trims calculated once.
|
70
|
+
self.trim_left = 0 # memory stored trims calculated once.
|
71
|
+
self.trim_right = 0 # memory stored trims calculated once.
|
72
|
+
self.trim_up = 0 # memory stored trims calculated once.
|
73
73
|
self.offset_top = self.shared.offset_top # offset top
|
74
74
|
self.offset_bottom = self.shared.offset_down # offset bottom
|
75
75
|
self.offset_left = self.shared.offset_left # offset left
|
valetudo_map_parser/map_data.py
CHANGED
@@ -3,12 +3,11 @@ Collections of Json and List routines
|
|
3
3
|
ImageData is part of the Image_Handler
|
4
4
|
used functions to search data in the json
|
5
5
|
provided for the creation of the new camera frame
|
6
|
-
Version:
|
6
|
+
Version: v0.1.6
|
7
7
|
"""
|
8
8
|
|
9
9
|
from __future__ import annotations
|
10
10
|
|
11
|
-
from typing import Any
|
12
11
|
import numpy as np
|
13
12
|
|
14
13
|
from .config.types import (
|
@@ -186,7 +185,7 @@ class ImageData:
|
|
186
185
|
if rand:
|
187
186
|
x, y, _ = entry # Extract x and y coordinates
|
188
187
|
max_x = max(max_x, x) # Update max x coordinate
|
189
|
-
max_y = max(max_y, y) # Update max y coordinate
|
188
|
+
max_y = max(max_y, y + pixel_size) # Update max y coordinate
|
190
189
|
min_x = min(min_x, x) # Update min x coordinate
|
191
190
|
min_y = min(min_y, y) # Update min y coordinate
|
192
191
|
else:
|
@@ -227,7 +226,7 @@ class ImageData:
|
|
227
226
|
compressed_pixels = []
|
228
227
|
|
229
228
|
tot_pixels = 0
|
230
|
-
current_x, current_y, count = None, None, 0
|
229
|
+
current_x, current_y, count = None, None, 0
|
231
230
|
for index in pixel_data:
|
232
231
|
x = (index % image_width) + image_left
|
233
232
|
y = ((image_height - 1) - (index // image_width)) + image_top
|