valetudo-map-parser 0.1.9b5__tar.gz → 0.1.9b7__tar.gz
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-0.1.9b5 → valetudo_map_parser-0.1.9b7}/PKG-INFO +1 -1
- valetudo_map_parser-0.1.9b7/SCR/valetudo_map_parser/config/utils.py +448 -0
- {valetudo_map_parser-0.1.9b5 → valetudo_map_parser-0.1.9b7}/SCR/valetudo_map_parser/hypfer_draw.py +1 -1
- {valetudo_map_parser-0.1.9b5 → valetudo_map_parser-0.1.9b7}/SCR/valetudo_map_parser/hypfer_handler.py +4 -6
- {valetudo_map_parser-0.1.9b5 → valetudo_map_parser-0.1.9b7}/SCR/valetudo_map_parser/rand25_handler.py +3 -5
- {valetudo_map_parser-0.1.9b5 → valetudo_map_parser-0.1.9b7}/SCR/valetudo_map_parser/reimg_draw.py +0 -2
- {valetudo_map_parser-0.1.9b5 → valetudo_map_parser-0.1.9b7}/pyproject.toml +1 -1
- valetudo_map_parser-0.1.9b5/SCR/valetudo_map_parser/config/utils.py +0 -132
- valetudo_map_parser-0.1.9b5/SCR/valetudo_map_parser/images_utils.py +0 -335
- {valetudo_map_parser-0.1.9b5 → valetudo_map_parser-0.1.9b7}/LICENSE +0 -0
- {valetudo_map_parser-0.1.9b5 → valetudo_map_parser-0.1.9b7}/NOTICE.txt +0 -0
- {valetudo_map_parser-0.1.9b5 → valetudo_map_parser-0.1.9b7}/README.md +0 -0
- {valetudo_map_parser-0.1.9b5 → valetudo_map_parser-0.1.9b7}/SCR/valetudo_map_parser/__init__.py +0 -0
- {valetudo_map_parser-0.1.9b5 → valetudo_map_parser-0.1.9b7}/SCR/valetudo_map_parser/config/__init__.py +0 -0
- {valetudo_map_parser-0.1.9b5 → valetudo_map_parser-0.1.9b7}/SCR/valetudo_map_parser/config/auto_crop.py +0 -0
- {valetudo_map_parser-0.1.9b5 → valetudo_map_parser-0.1.9b7}/SCR/valetudo_map_parser/config/colors.py +0 -0
- {valetudo_map_parser-0.1.9b5 → valetudo_map_parser-0.1.9b7}/SCR/valetudo_map_parser/config/drawable.py +0 -0
- {valetudo_map_parser-0.1.9b5 → valetudo_map_parser-0.1.9b7}/SCR/valetudo_map_parser/config/rand25_parser.py +0 -0
- {valetudo_map_parser-0.1.9b5 → valetudo_map_parser-0.1.9b7}/SCR/valetudo_map_parser/config/shared.py +0 -0
- {valetudo_map_parser-0.1.9b5 → valetudo_map_parser-0.1.9b7}/SCR/valetudo_map_parser/config/types.py +0 -0
- {valetudo_map_parser-0.1.9b5 → valetudo_map_parser-0.1.9b7}/SCR/valetudo_map_parser/map_data.py +0 -0
- {valetudo_map_parser-0.1.9b5 → valetudo_map_parser-0.1.9b7}/SCR/valetudo_map_parser/py.typed +0 -0
@@ -0,0 +1,448 @@
|
|
1
|
+
"""Utility code for the valetudo map parser."""
|
2
|
+
|
3
|
+
import hashlib
|
4
|
+
import json
|
5
|
+
from logging import getLogger
|
6
|
+
|
7
|
+
from PIL import ImageOps
|
8
|
+
|
9
|
+
from .types import ChargerPosition, ImageSize, NumpyArray, RobotPosition
|
10
|
+
|
11
|
+
_LOGGER = getLogger(__name__)
|
12
|
+
|
13
|
+
|
14
|
+
class BaseHandler:
|
15
|
+
"""Avoid Code duplication"""
|
16
|
+
|
17
|
+
def __init__(self):
|
18
|
+
self.file_name = None
|
19
|
+
self.img_size = None
|
20
|
+
self.json_data = None
|
21
|
+
self.json_id = None
|
22
|
+
self.path_pixels = None
|
23
|
+
self.robot_in_room = None
|
24
|
+
self.robot_pos = None
|
25
|
+
self.room_propriety = None
|
26
|
+
self.rooms_pos = None
|
27
|
+
self.charger_pos = None
|
28
|
+
self.frame_number = 0
|
29
|
+
self.max_frames = 1024
|
30
|
+
self.crop_img_size = [0, 0]
|
31
|
+
self.offset_x = 0
|
32
|
+
self.offset_y = 0
|
33
|
+
self.shared = None
|
34
|
+
|
35
|
+
def get_frame_number(self) -> int:
|
36
|
+
"""Return the frame number of the image."""
|
37
|
+
return self.frame_number
|
38
|
+
|
39
|
+
def get_robot_position(self) -> RobotPosition | None:
|
40
|
+
"""Return the robot position."""
|
41
|
+
return self.robot_pos
|
42
|
+
|
43
|
+
def get_charger_position(self) -> ChargerPosition | None:
|
44
|
+
"""Return the charger position."""
|
45
|
+
return self.charger_pos
|
46
|
+
|
47
|
+
def get_img_size(self) -> ImageSize | None:
|
48
|
+
"""Return the size of the image."""
|
49
|
+
return self.img_size
|
50
|
+
|
51
|
+
def get_json_id(self) -> str | None:
|
52
|
+
"""Return the JSON ID from the image."""
|
53
|
+
return self.json_id
|
54
|
+
|
55
|
+
async def async_resize_image(
|
56
|
+
self, pil_img, width, height, aspect_ratio=None, is_rand=False
|
57
|
+
):
|
58
|
+
"""Resize the image to the given dimensions and aspect ratio."""
|
59
|
+
if aspect_ratio:
|
60
|
+
wsf, hsf = [int(x) for x in aspect_ratio.split(",")]
|
61
|
+
if wsf == 0 or hsf == 0:
|
62
|
+
return pil_img
|
63
|
+
new_aspect_ratio = wsf / hsf
|
64
|
+
if width / height > new_aspect_ratio:
|
65
|
+
new_width = int(pil_img.height * new_aspect_ratio)
|
66
|
+
new_height = pil_img.height
|
67
|
+
else:
|
68
|
+
new_width = pil_img.width
|
69
|
+
new_height = int(pil_img.width / new_aspect_ratio)
|
70
|
+
_LOGGER.debug(
|
71
|
+
"%s: Image Aspect Ratio: %s, %s",
|
72
|
+
self.file_name,
|
73
|
+
str(wsf),
|
74
|
+
str(hsf),
|
75
|
+
)
|
76
|
+
(
|
77
|
+
self.crop_img_size[0],
|
78
|
+
self.crop_img_size[1],
|
79
|
+
) = await self.async_map_coordinates_offset(
|
80
|
+
wsf, hsf, new_width, new_height, is_rand
|
81
|
+
)
|
82
|
+
return ImageOps.pad(pil_img, (new_width, new_height))
|
83
|
+
return ImageOps.pad(pil_img, (width, height))
|
84
|
+
|
85
|
+
async def async_map_coordinates_offset(
|
86
|
+
self, wsf: int, hsf: int, width: int, height: int, rand256: bool = False
|
87
|
+
) -> tuple[int, int]:
|
88
|
+
"""
|
89
|
+
Offset the coordinates to the map.
|
90
|
+
"""
|
91
|
+
|
92
|
+
if wsf == 1 and hsf == 1:
|
93
|
+
self.set_image_offset_ratio_1_1(width, height, rand256)
|
94
|
+
elif wsf == 2 and hsf == 1:
|
95
|
+
self.set_image_offset_ratio_2_1(width, height, rand256)
|
96
|
+
elif wsf == 3 and hsf == 2:
|
97
|
+
self.set_image_offset_ratio_3_2(width, height, rand256)
|
98
|
+
elif wsf == 5 and hsf == 4:
|
99
|
+
self.set_image_offset_ratio_5_4(width, height, rand256)
|
100
|
+
elif wsf == 9 and hsf == 16:
|
101
|
+
self.set_image_offset_ratio_9_16(width, height, rand256)
|
102
|
+
elif wsf == 16 and hsf == 9:
|
103
|
+
self.set_image_offset_ratio_16_9(width, height, rand256)
|
104
|
+
return width, height
|
105
|
+
|
106
|
+
@staticmethod
|
107
|
+
async def calculate_array_hash(layers: dict, active: list[int] = None) -> str:
|
108
|
+
"""Calculate the hash of the image based on layers and active zones."""
|
109
|
+
if layers and active:
|
110
|
+
data_to_hash = {
|
111
|
+
"layers": len(layers["wall"][0]),
|
112
|
+
"active_segments": tuple(active),
|
113
|
+
}
|
114
|
+
data_json = json.dumps(data_to_hash, sort_keys=True)
|
115
|
+
return hashlib.sha256(data_json.encode()).hexdigest()
|
116
|
+
return None
|
117
|
+
|
118
|
+
@staticmethod
|
119
|
+
async def async_copy_array(original_array: NumpyArray) -> NumpyArray:
|
120
|
+
"""Copy the array."""
|
121
|
+
return NumpyArray.copy(original_array)
|
122
|
+
|
123
|
+
def get_map_points(self) -> dict:
|
124
|
+
"""Return the map points."""
|
125
|
+
return [
|
126
|
+
{"x": 0, "y": 0}, # Top-left corner 0
|
127
|
+
{"x": self.crop_img_size[0], "y": 0}, # Top-right corner 1
|
128
|
+
{
|
129
|
+
"x": self.crop_img_size[0],
|
130
|
+
"y": self.crop_img_size[1],
|
131
|
+
}, # Bottom-right corner 2
|
132
|
+
{"x": 0, "y": self.crop_img_size[1]}, # Bottom-left corner (optional) 3
|
133
|
+
]
|
134
|
+
|
135
|
+
def set_image_offset_ratio_1_1(
|
136
|
+
self, width: int, height: int, rand256: bool = False
|
137
|
+
) -> None:
|
138
|
+
"""Set the image offset ratio to 1:1."""
|
139
|
+
|
140
|
+
rotation = self.shared.image_rotate
|
141
|
+
if not rand256:
|
142
|
+
if rotation in [0, 180]:
|
143
|
+
self.offset_y = self.crop_img_size[0] - width
|
144
|
+
self.offset_x = (height - self.crop_img_size[1]) // 2
|
145
|
+
elif rotation in [90, 270]:
|
146
|
+
self.offset_y = width - self.crop_img_size[0]
|
147
|
+
self.offset_x = (self.crop_img_size[1] - height) // 2
|
148
|
+
else:
|
149
|
+
if rotation in [0, 180]:
|
150
|
+
self.offset_x = (width - self.crop_img_size[0]) // 2
|
151
|
+
self.offset_y = height - self.crop_img_size[1]
|
152
|
+
elif rotation in [90, 270]:
|
153
|
+
self.offset_y = (self.crop_img_size[0] - width) // 2
|
154
|
+
self.offset_x = self.crop_img_size[1] - height
|
155
|
+
_LOGGER.debug(
|
156
|
+
"%s Image Coordinates Offsets (x,y): %s. %s",
|
157
|
+
self.file_name,
|
158
|
+
self.offset_x,
|
159
|
+
self.offset_y,
|
160
|
+
)
|
161
|
+
|
162
|
+
def set_image_offset_ratio_2_1(
|
163
|
+
self, width: int, height: int, rand256: bool = False
|
164
|
+
) -> None:
|
165
|
+
"""Set the image offset ratio to 2:1."""
|
166
|
+
|
167
|
+
rotation = self.shared.image_rotate
|
168
|
+
if not rand256:
|
169
|
+
if rotation in [0, 180]:
|
170
|
+
self.offset_y = width - self.crop_img_size[0]
|
171
|
+
self.offset_x = height - self.crop_img_size[1]
|
172
|
+
elif rotation in [90, 270]:
|
173
|
+
self.offset_x = width - self.crop_img_size[0]
|
174
|
+
self.offset_y = height - self.crop_img_size[1]
|
175
|
+
else:
|
176
|
+
if rotation in [0, 180]:
|
177
|
+
self.offset_y = width - self.crop_img_size[0]
|
178
|
+
self.offset_x = height - self.crop_img_size[1]
|
179
|
+
elif rotation in [90, 270]:
|
180
|
+
self.offset_x = width - self.crop_img_size[0]
|
181
|
+
self.offset_y = height - self.crop_img_size[1]
|
182
|
+
|
183
|
+
_LOGGER.debug(
|
184
|
+
"%s Image Coordinates Offsets (x,y): %s. %s",
|
185
|
+
self.file_name,
|
186
|
+
self.offset_x,
|
187
|
+
self.offset_y,
|
188
|
+
)
|
189
|
+
|
190
|
+
def set_image_offset_ratio_3_2(
|
191
|
+
self, width: int, height: int, rand256: bool = False
|
192
|
+
) -> None:
|
193
|
+
"""Set the image offset ratio to 3:2."""
|
194
|
+
|
195
|
+
rotation = self.shared.image_rotate
|
196
|
+
|
197
|
+
if not rand256:
|
198
|
+
if rotation in [0, 180]:
|
199
|
+
self.offset_y = width - self.crop_img_size[0]
|
200
|
+
self.offset_x = ((height - self.crop_img_size[1]) // 2) - (
|
201
|
+
self.crop_img_size[1] // 10
|
202
|
+
)
|
203
|
+
elif rotation in [90, 270]:
|
204
|
+
self.offset_y = (self.crop_img_size[0] - width) // 2
|
205
|
+
self.offset_x = (self.crop_img_size[1] - height) + (
|
206
|
+
(height // 10) // 2
|
207
|
+
)
|
208
|
+
else:
|
209
|
+
if rotation in [0, 180]:
|
210
|
+
self.offset_x = (width - self.crop_img_size[0]) // 2
|
211
|
+
self.offset_y = height - self.crop_img_size[1]
|
212
|
+
elif rotation in [90, 270]:
|
213
|
+
self.offset_y = (self.crop_img_size[0] - width) // 2
|
214
|
+
self.offset_x = self.crop_img_size[1] - height
|
215
|
+
|
216
|
+
_LOGGER.debug(
|
217
|
+
"%s Image Coordinates Offsets (x,y): %s. %s",
|
218
|
+
self.file_name,
|
219
|
+
self.offset_x,
|
220
|
+
self.offset_y,
|
221
|
+
)
|
222
|
+
|
223
|
+
def set_image_offset_ratio_5_4(
|
224
|
+
self, width: int, height: int, rand256: bool = False
|
225
|
+
) -> None:
|
226
|
+
"""Set the image offset ratio to 5:4."""
|
227
|
+
|
228
|
+
rotation = self.shared.image_rotate
|
229
|
+
if not rand256:
|
230
|
+
if rotation in [0, 180]:
|
231
|
+
self.offset_x = ((width - self.crop_img_size[0]) // 2) - (
|
232
|
+
self.crop_img_size[0] // 2
|
233
|
+
)
|
234
|
+
self.offset_y = (self.crop_img_size[1] - height) - (
|
235
|
+
self.crop_img_size[1] // 2
|
236
|
+
)
|
237
|
+
elif rotation in [90, 270]:
|
238
|
+
self.offset_y = ((self.crop_img_size[0] - width) // 2) - 10
|
239
|
+
self.offset_x = (self.crop_img_size[1] - height) + (
|
240
|
+
height // 10
|
241
|
+
)
|
242
|
+
else:
|
243
|
+
if rotation in [0, 180]:
|
244
|
+
self.offset_y = (width - self.crop_img_size[0]) // 2
|
245
|
+
self.offset_x = self.crop_img_size[1] - height
|
246
|
+
elif rotation in [90, 270]:
|
247
|
+
self.offset_y = (self.crop_img_size[0] - width) // 2
|
248
|
+
self.offset_x = self.crop_img_size[1] - height
|
249
|
+
|
250
|
+
_LOGGER.debug(
|
251
|
+
"%s Image Coordinates Offsets (x,y): %s. %s",
|
252
|
+
self.file_name,
|
253
|
+
self.offset_x,
|
254
|
+
self.offset_y,
|
255
|
+
)
|
256
|
+
|
257
|
+
def set_image_offset_ratio_9_16(
|
258
|
+
self, width: int, height: int, rand256: bool = False
|
259
|
+
) -> None:
|
260
|
+
"""Set the image offset ratio to 9:16."""
|
261
|
+
|
262
|
+
rotation = self.shared.image_rotate
|
263
|
+
if not rand256:
|
264
|
+
if rotation in [0, 180]:
|
265
|
+
self.offset_y = width - self.crop_img_size[0]
|
266
|
+
self.offset_x = height - self.crop_img_size[1]
|
267
|
+
elif rotation in [90, 270]:
|
268
|
+
self.offset_x = (width - self.crop_img_size[0]) + (height // 10)
|
269
|
+
self.offset_y = height - self.crop_img_size[1]
|
270
|
+
else:
|
271
|
+
if rotation in [0, 180]:
|
272
|
+
self.offset_y = width - self.crop_img_size[0]
|
273
|
+
self.offset_x = height - self.crop_img_size[1]
|
274
|
+
elif rotation in [90, 270]:
|
275
|
+
self.offset_x = width - self.crop_img_size[0]
|
276
|
+
self.offset_y = height - self.crop_img_size[1]
|
277
|
+
|
278
|
+
_LOGGER.debug(
|
279
|
+
"%s Image Coordinates Offsets (x,y): %s. %s",
|
280
|
+
self.file_name,
|
281
|
+
self.offset_x,
|
282
|
+
self.offset_y,
|
283
|
+
)
|
284
|
+
|
285
|
+
def set_image_offset_ratio_16_9(
|
286
|
+
self, width: int, height: int, rand256: bool = False
|
287
|
+
) -> None:
|
288
|
+
"""Set the image offset ratio to 16:9."""
|
289
|
+
|
290
|
+
rotation = self.shared.image_rotate
|
291
|
+
if not rand256:
|
292
|
+
if rotation in [0, 180]:
|
293
|
+
self.offset_y = width - self.crop_img_size[0]
|
294
|
+
self.offset_x = height - self.crop_img_size[1]
|
295
|
+
elif rotation in [90, 270]:
|
296
|
+
self.offset_x = width - self.crop_img_size[0]
|
297
|
+
self.offset_y = height - self.crop_img_size[1]
|
298
|
+
else:
|
299
|
+
if rotation in [0, 180]:
|
300
|
+
self.offset_y = width - self.crop_img_size[0]
|
301
|
+
self.offset_x = height - self.crop_img_size[1]
|
302
|
+
elif rotation in [90, 270]:
|
303
|
+
self.offset_x = width - self.crop_img_size[0]
|
304
|
+
self.offset_y = height - self.crop_img_size[1]
|
305
|
+
|
306
|
+
_LOGGER.debug(
|
307
|
+
"%s Image Coordinates Offsets (x,y): %s. %s",
|
308
|
+
self.file_name,
|
309
|
+
self.offset_x,
|
310
|
+
self.offset_y,
|
311
|
+
)
|
312
|
+
|
313
|
+
def get_vacuum_points(self, rotation_angle: int) -> list[dict[str, int]]:
|
314
|
+
"""Calculate the calibration points based on the rotation angle."""
|
315
|
+
|
316
|
+
# get_calibration_data
|
317
|
+
vacuum_points = [
|
318
|
+
{
|
319
|
+
"x": self.img.crop_area[0] + self.img.offset_x,
|
320
|
+
"y": self.img.crop_area[1] + self.img.offset_y,
|
321
|
+
}, # Top-left corner 0
|
322
|
+
{
|
323
|
+
"x": self.img.crop_area[2] - self.img.offset_x,
|
324
|
+
"y": self.img.crop_area[1] + self.img.offset_y,
|
325
|
+
}, # Top-right corner 1
|
326
|
+
{
|
327
|
+
"x": self.img.crop_area[2] - self.img.offset_x,
|
328
|
+
"y": self.img.crop_area[3] - self.img.offset_y,
|
329
|
+
}, # Bottom-right corner 2
|
330
|
+
{
|
331
|
+
"x": self.img.crop_area[0] + self.img.offset_x,
|
332
|
+
"y": self.img.crop_area[3] - self.img.offset_y,
|
333
|
+
}, # Bottom-left corner (optional)3
|
334
|
+
]
|
335
|
+
|
336
|
+
# Rotate the vacuum points based on the rotation angle
|
337
|
+
if rotation_angle == 90:
|
338
|
+
vacuum_points = [
|
339
|
+
vacuum_points[1],
|
340
|
+
vacuum_points[2],
|
341
|
+
vacuum_points[3],
|
342
|
+
vacuum_points[0],
|
343
|
+
]
|
344
|
+
elif rotation_angle == 180:
|
345
|
+
vacuum_points = [
|
346
|
+
vacuum_points[2],
|
347
|
+
vacuum_points[3],
|
348
|
+
vacuum_points[0],
|
349
|
+
vacuum_points[1],
|
350
|
+
]
|
351
|
+
elif rotation_angle == 270:
|
352
|
+
vacuum_points = [
|
353
|
+
vacuum_points[3],
|
354
|
+
vacuum_points[0],
|
355
|
+
vacuum_points[1],
|
356
|
+
vacuum_points[2],
|
357
|
+
]
|
358
|
+
|
359
|
+
return vacuum_points
|
360
|
+
|
361
|
+
def re_get_vacuum_points(self, rotation_angle: int) -> list[dict[str, int]]:
|
362
|
+
"""Recalculate the calibration points based on the rotation angle.
|
363
|
+
RAND256 Vacuums Calibration Points are in 10th of a mm."""
|
364
|
+
vacuum_points = [
|
365
|
+
{
|
366
|
+
"x": ((self.img.crop_area[0] + self.img.offset_x) * 10),
|
367
|
+
"y": ((self.img.crop_area[1] + self.img.offset_y) * 10),
|
368
|
+
}, # Top-left corner 0
|
369
|
+
{
|
370
|
+
"x": ((self.img.crop_area[2] - self.img.offset_x) * 10),
|
371
|
+
"y": ((self.img.crop_area[1] + self.img.offset_y) * 10),
|
372
|
+
}, # Top-right corner 1
|
373
|
+
{
|
374
|
+
"x": ((self.img.crop_area[2] - self.img.offset_x) * 10),
|
375
|
+
"y": ((self.img.crop_area[3] - self.img.offset_y) * 10),
|
376
|
+
}, # Bottom-right corner 2
|
377
|
+
{
|
378
|
+
"x": ((self.img.crop_area[0] + self.img.offset_x) * 10),
|
379
|
+
"y": ((self.img.crop_area[3] - self.img.offset_y) * 10),
|
380
|
+
}, # Bottom-left corner (optional)3
|
381
|
+
]
|
382
|
+
|
383
|
+
# Rotate the vacuum points based on the rotation angle
|
384
|
+
if rotation_angle == 90:
|
385
|
+
vacuum_points = [
|
386
|
+
vacuum_points[1],
|
387
|
+
vacuum_points[2],
|
388
|
+
vacuum_points[3],
|
389
|
+
vacuum_points[0],
|
390
|
+
]
|
391
|
+
elif rotation_angle == 180:
|
392
|
+
vacuum_points = [
|
393
|
+
vacuum_points[2],
|
394
|
+
vacuum_points[3],
|
395
|
+
vacuum_points[0],
|
396
|
+
vacuum_points[1],
|
397
|
+
]
|
398
|
+
elif rotation_angle == 270:
|
399
|
+
vacuum_points = [
|
400
|
+
vacuum_points[3],
|
401
|
+
vacuum_points[0],
|
402
|
+
vacuum_points[1],
|
403
|
+
vacuum_points[2],
|
404
|
+
]
|
405
|
+
|
406
|
+
return vacuum_points
|
407
|
+
|
408
|
+
async def async_zone_propriety(self, zones_data) -> dict:
|
409
|
+
"""Get the zone propriety"""
|
410
|
+
zone_properties = {}
|
411
|
+
id_count = 1
|
412
|
+
for zone in zones_data:
|
413
|
+
zone_name = zone.get("name")
|
414
|
+
coordinates = zone.get("coordinates")
|
415
|
+
if coordinates and len(coordinates) > 0:
|
416
|
+
coordinates[0].pop()
|
417
|
+
x1, y1, x2, y2 = coordinates[0]
|
418
|
+
zone_properties[zone_name] = {
|
419
|
+
"zones": coordinates,
|
420
|
+
"name": zone_name,
|
421
|
+
"x": ((x1 + x2) // 2),
|
422
|
+
"y": ((y1 + y2) // 2),
|
423
|
+
}
|
424
|
+
id_count += 1
|
425
|
+
if id_count > 1:
|
426
|
+
_LOGGER.debug("%s: Zones Properties updated.", self.file_name)
|
427
|
+
return zone_properties
|
428
|
+
|
429
|
+
async def async_points_propriety(self, points_data) -> dict:
|
430
|
+
"""Get the point propriety"""
|
431
|
+
point_properties = {}
|
432
|
+
id_count = 1
|
433
|
+
for point in points_data:
|
434
|
+
point_name = point.get("name")
|
435
|
+
coordinates = point.get("coordinates")
|
436
|
+
if coordinates and len(coordinates) > 0:
|
437
|
+
coordinates = point.get("coordinates")
|
438
|
+
x1, y1 = coordinates
|
439
|
+
point_properties[id_count] = {
|
440
|
+
"position": coordinates,
|
441
|
+
"name": point_name,
|
442
|
+
"x": x1,
|
443
|
+
"y": y1,
|
444
|
+
}
|
445
|
+
id_count += 1
|
446
|
+
if id_count > 1:
|
447
|
+
_LOGGER.debug("%s: Point Properties updated.", self.file_name)
|
448
|
+
return point_properties
|
{valetudo_map_parser-0.1.9b5 → valetudo_map_parser-0.1.9b7}/SCR/valetudo_map_parser/hypfer_draw.py
RENAMED
@@ -70,7 +70,7 @@ class ImageDraw:
|
|
70
70
|
self, img_np_array, pixels, layer_type, room_id, pixel_size, color_zone_clean
|
71
71
|
):
|
72
72
|
"""Process a room layer (segment or floor)."""
|
73
|
-
room_color = self.img_h.rooms_colors[room_id]
|
73
|
+
room_color = self.img_h.shared.rooms_colors[room_id]
|
74
74
|
|
75
75
|
try:
|
76
76
|
if layer_type == "segment":
|
@@ -51,8 +51,6 @@ class HypferMapImageHandler(BaseHandler):
|
|
51
51
|
self.offset_bottom = self.shared.offset_down # offset bottom
|
52
52
|
self.offset_left = self.shared.offset_left # offset left
|
53
53
|
self.offset_right = self.shared.offset_right # offset right
|
54
|
-
self.offset_x = 0 # offset x for the aspect ratio.
|
55
|
-
self.offset_y = 0 # offset y for the aspect ratio.
|
56
54
|
self.imd = ImDraw(self)
|
57
55
|
self.ac = AutoCrop(self)
|
58
56
|
self.color_grey = (128, 128, 128, 255)
|
@@ -221,7 +219,7 @@ class HypferMapImageHandler(BaseHandler):
|
|
221
219
|
)
|
222
220
|
# Draw path prediction and paths.
|
223
221
|
img_np_array = await self.imd.async_draw_paths(
|
224
|
-
img_np_array, m_json, colors["
|
222
|
+
img_np_array, m_json, colors["move"], self.color_grey
|
225
223
|
)
|
226
224
|
# Check if the robot is docked.
|
227
225
|
if self.shared.vacuum_state == "docked":
|
@@ -235,13 +233,13 @@ class HypferMapImageHandler(BaseHandler):
|
|
235
233
|
x=robot_position[0],
|
236
234
|
y=robot_position[1],
|
237
235
|
angle=robot_position_angle,
|
238
|
-
fill=colors["
|
236
|
+
fill=colors["robot"],
|
239
237
|
robot_state=self.shared.vacuum_state,
|
240
238
|
)
|
241
239
|
# Resize the image
|
242
240
|
img_np_array = await self.ac.async_auto_trim_and_zoom_image(
|
243
241
|
img_np_array,
|
244
|
-
colors["
|
242
|
+
colors["background"],
|
245
243
|
int(self.shared.margins),
|
246
244
|
int(self.shared.image_rotate),
|
247
245
|
self.zooming,
|
@@ -303,7 +301,7 @@ class HypferMapImageHandler(BaseHandler):
|
|
303
301
|
# Define the map points (fixed)
|
304
302
|
map_points = self.get_map_points()
|
305
303
|
# Calculate the calibration points in the vacuum coordinate system
|
306
|
-
vacuum_points = self.
|
304
|
+
vacuum_points = self.get_vacuum_points(rotation_angle)
|
307
305
|
|
308
306
|
# Create the calibration data for each point
|
309
307
|
for vacuum_point, map_point in zip(vacuum_points, map_points):
|
@@ -57,8 +57,6 @@ class ReImageHandler(BaseHandler):
|
|
57
57
|
self.trim_up = None # Trim up
|
58
58
|
self.zooming = False # Zooming flag
|
59
59
|
self.file_name = self.shared.file_name # File name
|
60
|
-
self.offset_x = 0 # offset x for the aspect ratio.
|
61
|
-
self.offset_y = 0 # offset y for the aspect ratio.
|
62
60
|
self.offset_top = self.shared.offset_top # offset top
|
63
61
|
self.offset_bottom = self.shared.offset_down # offset bottom
|
64
62
|
self.offset_left = self.shared.offset_left # offset left
|
@@ -121,9 +119,9 @@ class ReImageHandler(BaseHandler):
|
|
121
119
|
"y": (y_min + y_max) // 2,
|
122
120
|
}
|
123
121
|
# get the zones and points data
|
124
|
-
zone_properties = await self.
|
122
|
+
zone_properties = await self.async_zone_propriety(zones_data)
|
125
123
|
# get the points data
|
126
|
-
point_properties = await self.
|
124
|
+
point_properties = await self.async_points_propriety(points_data)
|
127
125
|
if room_properties or zone_properties:
|
128
126
|
extracted_data = [
|
129
127
|
f"{len(room_properties)} Rooms" if room_properties else None,
|
@@ -381,7 +379,7 @@ class ReImageHandler(BaseHandler):
|
|
381
379
|
map_points = self.get_map_points()
|
382
380
|
|
383
381
|
# Valetudo Re version need corrections of the coordinates and are implemented with *10
|
384
|
-
vacuum_points = self.
|
382
|
+
vacuum_points = self.re_get_vacuum_points(rotation_angle)
|
385
383
|
|
386
384
|
# Create the calibration data for each point
|
387
385
|
for vacuum_point, map_point in zip(vacuum_points, map_points):
|
@@ -1,132 +0,0 @@
|
|
1
|
-
"""Utility code for the valetudo map parser."""
|
2
|
-
|
3
|
-
import hashlib
|
4
|
-
import json
|
5
|
-
from logging import getLogger
|
6
|
-
|
7
|
-
from PIL import ImageOps
|
8
|
-
|
9
|
-
from ..images_utils import ImageUtils as ImUtils
|
10
|
-
from .types import ChargerPosition, ImageSize, NumpyArray, RobotPosition
|
11
|
-
|
12
|
-
_LOGGER = getLogger(__name__)
|
13
|
-
|
14
|
-
|
15
|
-
class BaseHandler:
|
16
|
-
"""Avoid Code duplication"""
|
17
|
-
|
18
|
-
def __init__(self):
|
19
|
-
self.file_name = None
|
20
|
-
self.img_size = None
|
21
|
-
self.json_data = None
|
22
|
-
self.json_id = None
|
23
|
-
self.path_pixels = None
|
24
|
-
self.robot_in_room = None
|
25
|
-
self.robot_pos = None
|
26
|
-
self.room_propriety = None
|
27
|
-
self.rooms_pos = None
|
28
|
-
self.charger_pos = None
|
29
|
-
self.frame_number = 0
|
30
|
-
self.max_frames = 1024
|
31
|
-
self.crop_img_size = [0, 0]
|
32
|
-
self.imu = ImUtils(self) # Image Utils
|
33
|
-
|
34
|
-
def get_frame_number(self) -> int:
|
35
|
-
"""Return the frame number of the image."""
|
36
|
-
return self.frame_number
|
37
|
-
|
38
|
-
def get_robot_position(self) -> RobotPosition | None:
|
39
|
-
"""Return the robot position."""
|
40
|
-
return self.robot_pos
|
41
|
-
|
42
|
-
def get_charger_position(self) -> ChargerPosition | None:
|
43
|
-
"""Return the charger position."""
|
44
|
-
return self.charger_pos
|
45
|
-
|
46
|
-
def get_img_size(self) -> ImageSize | None:
|
47
|
-
"""Return the size of the image."""
|
48
|
-
return self.img_size
|
49
|
-
|
50
|
-
def get_json_id(self) -> str | None:
|
51
|
-
"""Return the JSON ID from the image."""
|
52
|
-
return self.json_id
|
53
|
-
|
54
|
-
async def async_resize_image(
|
55
|
-
self, pil_img, width, height, aspect_ratio=None, is_rand=False
|
56
|
-
):
|
57
|
-
"""Resize the image to the given dimensions and aspect ratio."""
|
58
|
-
if aspect_ratio:
|
59
|
-
wsf, hsf = [int(x) for x in aspect_ratio.split(",")]
|
60
|
-
if wsf == 0 or hsf == 0:
|
61
|
-
return pil_img
|
62
|
-
new_aspect_ratio = wsf / hsf
|
63
|
-
if width / height > new_aspect_ratio:
|
64
|
-
new_width = int(pil_img.height * new_aspect_ratio)
|
65
|
-
new_height = pil_img.height
|
66
|
-
else:
|
67
|
-
new_width = pil_img.width
|
68
|
-
new_height = int(pil_img.width / new_aspect_ratio)
|
69
|
-
_LOGGER.debug(
|
70
|
-
"%s: Image Aspect Ratio: %s, %s",
|
71
|
-
self.file_name,
|
72
|
-
str(wsf),
|
73
|
-
str(hsf),
|
74
|
-
)
|
75
|
-
(
|
76
|
-
self.crop_img_size[0],
|
77
|
-
self.crop_img_size[1],
|
78
|
-
) = await self.async_map_coordinates_offset(
|
79
|
-
wsf, hsf, new_width, new_height, is_rand
|
80
|
-
)
|
81
|
-
return ImageOps.pad(pil_img, (new_width, new_height))
|
82
|
-
return ImageOps.pad(pil_img, (width, height))
|
83
|
-
|
84
|
-
async def async_map_coordinates_offset(
|
85
|
-
self, wsf: int, hsf: int, width: int, height: int, rand256: bool = False
|
86
|
-
) -> tuple[int, int]:
|
87
|
-
"""
|
88
|
-
Offset the coordinates to the map.
|
89
|
-
"""
|
90
|
-
|
91
|
-
if wsf == 1 and hsf == 1:
|
92
|
-
self.imu.set_image_offset_ratio_1_1(width, height, rand256)
|
93
|
-
elif wsf == 2 and hsf == 1:
|
94
|
-
self.imu.set_image_offset_ratio_2_1(width, height, rand256)
|
95
|
-
elif wsf == 3 and hsf == 2:
|
96
|
-
self.imu.set_image_offset_ratio_3_2(width, height, rand256)
|
97
|
-
elif wsf == 5 and hsf == 4:
|
98
|
-
self.imu.set_image_offset_ratio_5_4(width, height, rand256)
|
99
|
-
elif wsf == 9 and hsf == 16:
|
100
|
-
self.imu.set_image_offset_ratio_9_16(width, height, rand256=True)
|
101
|
-
elif wsf == 16 and hsf == 9:
|
102
|
-
self.imu.set_image_offset_ratio_16_9(width, height, rand256=True)
|
103
|
-
return width, height
|
104
|
-
|
105
|
-
@staticmethod
|
106
|
-
async def calculate_array_hash(layers: dict, active: list[int] = None) -> str:
|
107
|
-
"""Calculate the hash of the image based on layers and active zones."""
|
108
|
-
if layers and active:
|
109
|
-
data_to_hash = {
|
110
|
-
"layers": len(layers["wall"][0]),
|
111
|
-
"active_segments": tuple(active),
|
112
|
-
}
|
113
|
-
data_json = json.dumps(data_to_hash, sort_keys=True)
|
114
|
-
return hashlib.sha256(data_json.encode()).hexdigest()
|
115
|
-
return None
|
116
|
-
|
117
|
-
@staticmethod
|
118
|
-
async def async_copy_array(original_array: NumpyArray) -> NumpyArray:
|
119
|
-
"""Copy the array."""
|
120
|
-
return NumpyArray.copy(original_array)
|
121
|
-
|
122
|
-
def get_map_points(self) -> dict:
|
123
|
-
"""Return the map points."""
|
124
|
-
return [
|
125
|
-
{"x": 0, "y": 0}, # Top-left corner 0
|
126
|
-
{"x": self.crop_img_size[0], "y": 0}, # Top-right corner 1
|
127
|
-
{
|
128
|
-
"x": self.crop_img_size[0],
|
129
|
-
"y": self.crop_img_size[1],
|
130
|
-
}, # Bottom-right corner 2
|
131
|
-
{"x": 0, "y": self.crop_img_size[1]}, # Bottom-left corner (optional) 3
|
132
|
-
]
|
@@ -1,335 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Image Utils Class for Valetudo Hypfer Image Handling.
|
3
|
-
This class is used to simplify the ImageHandler class.
|
4
|
-
Version: 0.1.6
|
5
|
-
"""
|
6
|
-
|
7
|
-
from __future__ import annotations
|
8
|
-
|
9
|
-
import logging
|
10
|
-
|
11
|
-
_LOGGER = logging.getLogger(__name__)
|
12
|
-
|
13
|
-
|
14
|
-
class ImageUtils:
|
15
|
-
"""Image Utils Class for Valetudo Hypfer Image Handler.
|
16
|
-
It is used to simplify the ImageHandler class."""
|
17
|
-
|
18
|
-
def __init__(self, image_handler):
|
19
|
-
self.img = image_handler
|
20
|
-
self.file_name = self.img.shared.file_name
|
21
|
-
|
22
|
-
def get_vacuum_points(self, rotation_angle: int) -> list[dict[str, int]]:
|
23
|
-
"""Calculate the calibration points based on the rotation angle."""
|
24
|
-
|
25
|
-
# get_calibration_data
|
26
|
-
vacuum_points = [
|
27
|
-
{
|
28
|
-
"x": self.img.crop_area[0] + self.img.offset_x,
|
29
|
-
"y": self.img.crop_area[1] + self.img.offset_y,
|
30
|
-
}, # Top-left corner 0
|
31
|
-
{
|
32
|
-
"x": self.img.crop_area[2] - self.img.offset_x,
|
33
|
-
"y": self.img.crop_area[1] + self.img.offset_y,
|
34
|
-
}, # Top-right corner 1
|
35
|
-
{
|
36
|
-
"x": self.img.crop_area[2] - self.img.offset_x,
|
37
|
-
"y": self.img.crop_area[3] - self.img.offset_y,
|
38
|
-
}, # Bottom-right corner 2
|
39
|
-
{
|
40
|
-
"x": self.img.crop_area[0] + self.img.offset_x,
|
41
|
-
"y": self.img.crop_area[3] - self.img.offset_y,
|
42
|
-
}, # Bottom-left corner (optional)3
|
43
|
-
]
|
44
|
-
|
45
|
-
# Rotate the vacuum points based on the rotation angle
|
46
|
-
if rotation_angle == 90:
|
47
|
-
vacuum_points = [
|
48
|
-
vacuum_points[1],
|
49
|
-
vacuum_points[2],
|
50
|
-
vacuum_points[3],
|
51
|
-
vacuum_points[0],
|
52
|
-
]
|
53
|
-
elif rotation_angle == 180:
|
54
|
-
vacuum_points = [
|
55
|
-
vacuum_points[2],
|
56
|
-
vacuum_points[3],
|
57
|
-
vacuum_points[0],
|
58
|
-
vacuum_points[1],
|
59
|
-
]
|
60
|
-
elif rotation_angle == 270:
|
61
|
-
vacuum_points = [
|
62
|
-
vacuum_points[3],
|
63
|
-
vacuum_points[0],
|
64
|
-
vacuum_points[1],
|
65
|
-
vacuum_points[2],
|
66
|
-
]
|
67
|
-
|
68
|
-
return vacuum_points
|
69
|
-
|
70
|
-
def re_get_vacuum_points(self, rotation_angle: int) -> list[dict[str, int]]:
|
71
|
-
"""Recalculate the calibration points based on the rotation angle.
|
72
|
-
RAND256 Vacuums Calibration Points are in 10th of a mm."""
|
73
|
-
vacuum_points = [
|
74
|
-
{
|
75
|
-
"x": ((self.img.crop_area[0] + self.img.offset_x) * 10),
|
76
|
-
"y": ((self.img.crop_area[1] + self.img.offset_y) * 10),
|
77
|
-
}, # Top-left corner 0
|
78
|
-
{
|
79
|
-
"x": ((self.img.crop_area[2] - self.img.offset_x) * 10),
|
80
|
-
"y": ((self.img.crop_area[1] + self.img.offset_y) * 10),
|
81
|
-
}, # Top-right corner 1
|
82
|
-
{
|
83
|
-
"x": ((self.img.crop_area[2] - self.img.offset_x) * 10),
|
84
|
-
"y": ((self.img.crop_area[3] - self.img.offset_y) * 10),
|
85
|
-
}, # Bottom-right corner 2
|
86
|
-
{
|
87
|
-
"x": ((self.img.crop_area[0] + self.img.offset_x) * 10),
|
88
|
-
"y": ((self.img.crop_area[3] - self.img.offset_y) * 10),
|
89
|
-
}, # Bottom-left corner (optional)3
|
90
|
-
]
|
91
|
-
|
92
|
-
# Rotate the vacuum points based on the rotation angle
|
93
|
-
if rotation_angle == 90:
|
94
|
-
vacuum_points = [
|
95
|
-
vacuum_points[1],
|
96
|
-
vacuum_points[2],
|
97
|
-
vacuum_points[3],
|
98
|
-
vacuum_points[0],
|
99
|
-
]
|
100
|
-
elif rotation_angle == 180:
|
101
|
-
vacuum_points = [
|
102
|
-
vacuum_points[2],
|
103
|
-
vacuum_points[3],
|
104
|
-
vacuum_points[0],
|
105
|
-
vacuum_points[1],
|
106
|
-
]
|
107
|
-
elif rotation_angle == 270:
|
108
|
-
vacuum_points = [
|
109
|
-
vacuum_points[3],
|
110
|
-
vacuum_points[0],
|
111
|
-
vacuum_points[1],
|
112
|
-
vacuum_points[2],
|
113
|
-
]
|
114
|
-
|
115
|
-
return vacuum_points
|
116
|
-
|
117
|
-
def set_image_offset_ratio_1_1(
|
118
|
-
self, width: int, height: int, rand256: bool = False
|
119
|
-
) -> None:
|
120
|
-
"""Set the image offset ratio to 1:1."""
|
121
|
-
|
122
|
-
rotation = self.img.shared.image_rotate
|
123
|
-
if not rand256:
|
124
|
-
if rotation in [0, 180]:
|
125
|
-
self.img.offset_y = self.img.crop_img_size[0] - width
|
126
|
-
self.img.offset_x = (height - self.img.crop_img_size[1]) // 2
|
127
|
-
elif rotation in [90, 270]:
|
128
|
-
self.img.offset_y = width - self.img.crop_img_size[0]
|
129
|
-
self.img.offset_x = (self.img.crop_img_size[1] - height) // 2
|
130
|
-
else:
|
131
|
-
if rotation in [0, 180]:
|
132
|
-
self.img.offset_x = (width - self.img.crop_img_size[0]) // 2
|
133
|
-
self.img.offset_y = height - self.img.crop_img_size[1]
|
134
|
-
elif rotation in [90, 270]:
|
135
|
-
self.img.offset_y = (self.img.crop_img_size[0] - width) // 2
|
136
|
-
self.img.offset_x = self.img.crop_img_size[1] - height
|
137
|
-
_LOGGER.debug(
|
138
|
-
"%s Image Coordinates Offsets (x,y): %s. %s",
|
139
|
-
self.file_name,
|
140
|
-
self.img.offset_x,
|
141
|
-
self.img.offset_y,
|
142
|
-
)
|
143
|
-
|
144
|
-
def set_image_offset_ratio_2_1(
|
145
|
-
self, width: int, height: int, rand256: bool = False
|
146
|
-
) -> None:
|
147
|
-
"""Set the image offset ratio to 2:1."""
|
148
|
-
|
149
|
-
rotation = self.img.shared.image_rotate
|
150
|
-
if not rand256:
|
151
|
-
if rotation in [0, 180]:
|
152
|
-
self.img.offset_y = width - self.img.crop_img_size[0]
|
153
|
-
self.img.offset_x = height - self.img.crop_img_size[1]
|
154
|
-
elif rotation in [90, 270]:
|
155
|
-
self.img.offset_x = width - self.img.crop_img_size[0]
|
156
|
-
self.img.offset_y = height - self.img.crop_img_size[1]
|
157
|
-
else:
|
158
|
-
if rotation in [0, 180]:
|
159
|
-
self.img.offset_y = width - self.img.crop_img_size[0]
|
160
|
-
self.img.offset_x = height - self.img.crop_img_size[1]
|
161
|
-
elif rotation in [90, 270]:
|
162
|
-
self.img.offset_x = width - self.img.crop_img_size[0]
|
163
|
-
self.img.offset_y = height - self.img.crop_img_size[1]
|
164
|
-
|
165
|
-
_LOGGER.debug(
|
166
|
-
"%s Image Coordinates Offsets (x,y): %s. %s",
|
167
|
-
self.file_name,
|
168
|
-
self.img.offset_x,
|
169
|
-
self.img.offset_y,
|
170
|
-
)
|
171
|
-
|
172
|
-
def set_image_offset_ratio_3_2(
|
173
|
-
self, width: int, height: int, rand256: bool = False
|
174
|
-
) -> None:
|
175
|
-
"""Set the image offset ratio to 3:2."""
|
176
|
-
|
177
|
-
rotation = self.img.shared.image_rotate
|
178
|
-
|
179
|
-
if not rand256:
|
180
|
-
if rotation in [0, 180]:
|
181
|
-
self.img.offset_y = width - self.img.crop_img_size[0]
|
182
|
-
self.img.offset_x = ((height - self.img.crop_img_size[1]) // 2) - (
|
183
|
-
self.img.crop_img_size[1] // 10
|
184
|
-
)
|
185
|
-
elif rotation in [90, 270]:
|
186
|
-
self.img.offset_y = (self.img.crop_img_size[0] - width) // 2
|
187
|
-
self.img.offset_x = (self.img.crop_img_size[1] - height) + (
|
188
|
-
(height // 10) // 2
|
189
|
-
)
|
190
|
-
else:
|
191
|
-
if rotation in [0, 180]:
|
192
|
-
self.img.offset_x = (width - self.img.crop_img_size[0]) // 2
|
193
|
-
self.img.offset_y = height - self.img.crop_img_size[1]
|
194
|
-
elif rotation in [90, 270]:
|
195
|
-
self.img.offset_y = (self.img.crop_img_size[0] - width) // 2
|
196
|
-
self.img.offset_x = self.img.crop_img_size[1] - height
|
197
|
-
|
198
|
-
_LOGGER.debug(
|
199
|
-
"%s Image Coordinates Offsets (x,y): %s. %s",
|
200
|
-
self.file_name,
|
201
|
-
self.img.offset_x,
|
202
|
-
self.img.offset_y,
|
203
|
-
)
|
204
|
-
|
205
|
-
def set_image_offset_ratio_5_4(
|
206
|
-
self, width: int, height: int, rand256: bool = False
|
207
|
-
) -> None:
|
208
|
-
"""Set the image offset ratio to 5:4."""
|
209
|
-
|
210
|
-
rotation = self.img.shared.image_rotate
|
211
|
-
if not rand256:
|
212
|
-
if rotation in [0, 180]:
|
213
|
-
self.img.offset_x = ((width - self.img.crop_img_size[0]) // 2) - (
|
214
|
-
self.img.crop_img_size[0] // 2
|
215
|
-
)
|
216
|
-
self.img.offset_y = (self.img.crop_img_size[1] - height) - (
|
217
|
-
self.img.crop_img_size[1] // 2
|
218
|
-
)
|
219
|
-
elif rotation in [90, 270]:
|
220
|
-
self.img.offset_y = ((self.img.crop_img_size[0] - width) // 2) - 10
|
221
|
-
self.img.offset_x = (self.img.crop_img_size[1] - height) + (
|
222
|
-
height // 10
|
223
|
-
)
|
224
|
-
else:
|
225
|
-
if rotation in [0, 180]:
|
226
|
-
self.img.offset_y = (width - self.img.crop_img_size[0]) // 2
|
227
|
-
self.img.offset_x = self.img.crop_img_size[1] - height
|
228
|
-
elif rotation in [90, 270]:
|
229
|
-
self.img.offset_y = (self.img.crop_img_size[0] - width) // 2
|
230
|
-
self.img.offset_x = self.img.crop_img_size[1] - height
|
231
|
-
|
232
|
-
_LOGGER.debug(
|
233
|
-
"%s Image Coordinates Offsets (x,y): %s. %s",
|
234
|
-
self.file_name,
|
235
|
-
self.img.offset_x,
|
236
|
-
self.img.offset_y,
|
237
|
-
)
|
238
|
-
|
239
|
-
def set_image_offset_ratio_9_16(
|
240
|
-
self, width: int, height: int, rand256: bool = False
|
241
|
-
) -> None:
|
242
|
-
"""Set the image offset ratio to 9:16."""
|
243
|
-
|
244
|
-
rotation = self.img.shared.image_rotate
|
245
|
-
if not rand256:
|
246
|
-
if rotation in [0, 180]:
|
247
|
-
self.img.offset_y = width - self.img.crop_img_size[0]
|
248
|
-
self.img.offset_x = height - self.img.crop_img_size[1]
|
249
|
-
elif rotation in [90, 270]:
|
250
|
-
self.img.offset_x = (width - self.img.crop_img_size[0]) + (height // 10)
|
251
|
-
self.img.offset_y = height - self.img.crop_img_size[1]
|
252
|
-
else:
|
253
|
-
if rotation in [0, 180]:
|
254
|
-
self.img.offset_y = width - self.img.crop_img_size[0]
|
255
|
-
self.img.offset_x = height - self.img.crop_img_size[1]
|
256
|
-
elif rotation in [90, 270]:
|
257
|
-
self.img.offset_x = width - self.img.crop_img_size[0]
|
258
|
-
self.img.offset_y = height - self.img.crop_img_size[1]
|
259
|
-
|
260
|
-
_LOGGER.debug(
|
261
|
-
"%s Image Coordinates Offsets (x,y): %s. %s",
|
262
|
-
self.file_name,
|
263
|
-
self.img.offset_x,
|
264
|
-
self.img.offset_y,
|
265
|
-
)
|
266
|
-
|
267
|
-
def set_image_offset_ratio_16_9(
|
268
|
-
self, width: int, height: int, rand256: bool = False
|
269
|
-
) -> None:
|
270
|
-
"""Set the image offset ratio to 16:9."""
|
271
|
-
|
272
|
-
rotation = self.img.shared.image_rotate
|
273
|
-
if not rand256:
|
274
|
-
if rotation in [0, 180]:
|
275
|
-
self.img.offset_y = width - self.img.crop_img_size[0]
|
276
|
-
self.img.offset_x = height - self.img.crop_img_size[1]
|
277
|
-
elif rotation in [90, 270]:
|
278
|
-
self.img.offset_x = width - self.img.crop_img_size[0]
|
279
|
-
self.img.offset_y = height - self.img.crop_img_size[1]
|
280
|
-
else:
|
281
|
-
if rotation in [0, 180]:
|
282
|
-
self.img.offset_y = width - self.img.crop_img_size[0]
|
283
|
-
self.img.offset_x = height - self.img.crop_img_size[1]
|
284
|
-
elif rotation in [90, 270]:
|
285
|
-
self.img.offset_x = width - self.img.crop_img_size[0]
|
286
|
-
self.img.offset_y = height - self.img.crop_img_size[1]
|
287
|
-
|
288
|
-
_LOGGER.debug(
|
289
|
-
"%s Image Coordinates Offsets (x,y): %s. %s",
|
290
|
-
self.file_name,
|
291
|
-
self.img.offset_x,
|
292
|
-
self.img.offset_y,
|
293
|
-
)
|
294
|
-
|
295
|
-
async def async_zone_propriety(self, zones_data) -> dict:
|
296
|
-
"""Get the zone propriety"""
|
297
|
-
zone_properties = {}
|
298
|
-
id_count = 1
|
299
|
-
for zone in zones_data:
|
300
|
-
zone_name = zone.get("name")
|
301
|
-
coordinates = zone.get("coordinates")
|
302
|
-
if coordinates and len(coordinates) > 0:
|
303
|
-
coordinates[0].pop()
|
304
|
-
x1, y1, x2, y2 = coordinates[0]
|
305
|
-
zone_properties[zone_name] = {
|
306
|
-
"zones": coordinates,
|
307
|
-
"name": zone_name,
|
308
|
-
"x": ((x1 + x2) // 2),
|
309
|
-
"y": ((y1 + y2) // 2),
|
310
|
-
}
|
311
|
-
id_count += 1
|
312
|
-
if id_count > 1:
|
313
|
-
_LOGGER.debug("%s: Zones Properties updated.", self.file_name)
|
314
|
-
return zone_properties
|
315
|
-
|
316
|
-
async def async_points_propriety(self, points_data) -> dict:
|
317
|
-
"""Get the point propriety"""
|
318
|
-
point_properties = {}
|
319
|
-
id_count = 1
|
320
|
-
for point in points_data:
|
321
|
-
point_name = point.get("name")
|
322
|
-
coordinates = point.get("coordinates")
|
323
|
-
if coordinates and len(coordinates) > 0:
|
324
|
-
coordinates = point.get("coordinates")
|
325
|
-
x1, y1 = coordinates
|
326
|
-
point_properties[id_count] = {
|
327
|
-
"position": coordinates,
|
328
|
-
"name": point_name,
|
329
|
-
"x": x1,
|
330
|
-
"y": y1,
|
331
|
-
}
|
332
|
-
id_count += 1
|
333
|
-
if id_count > 1:
|
334
|
-
_LOGGER.debug("%s: Point Properties updated.", self.file_name)
|
335
|
-
return point_properties
|
File without changes
|
File without changes
|
File without changes
|
{valetudo_map_parser-0.1.9b5 → valetudo_map_parser-0.1.9b7}/SCR/valetudo_map_parser/__init__.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
{valetudo_map_parser-0.1.9b5 → valetudo_map_parser-0.1.9b7}/SCR/valetudo_map_parser/config/colors.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
{valetudo_map_parser-0.1.9b5 → valetudo_map_parser-0.1.9b7}/SCR/valetudo_map_parser/config/shared.py
RENAMED
File without changes
|
{valetudo_map_parser-0.1.9b5 → valetudo_map_parser-0.1.9b7}/SCR/valetudo_map_parser/config/types.py
RENAMED
File without changes
|
{valetudo_map_parser-0.1.9b5 → valetudo_map_parser-0.1.9b7}/SCR/valetudo_map_parser/map_data.py
RENAMED
File without changes
|
{valetudo_map_parser-0.1.9b5 → valetudo_map_parser-0.1.9b7}/SCR/valetudo_map_parser/py.typed
RENAMED
File without changes
|