valetudo-map-parser 0.1.9b44__tar.gz → 0.1.9b45__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.9b44 → valetudo_map_parser-0.1.9b45}/PKG-INFO +1 -2
- {valetudo_map_parser-0.1.9b44 → valetudo_map_parser-0.1.9b45}/SCR/valetudo_map_parser/config/colors.py +28 -0
- {valetudo_map_parser-0.1.9b44 → valetudo_map_parser-0.1.9b45}/SCR/valetudo_map_parser/config/drawable.py +79 -5
- {valetudo_map_parser-0.1.9b44 → valetudo_map_parser-0.1.9b45}/SCR/valetudo_map_parser/hypfer_handler.py +1 -46
- {valetudo_map_parser-0.1.9b44 → valetudo_map_parser-0.1.9b45}/SCR/valetudo_map_parser/rand25_handler.py +4 -4
- {valetudo_map_parser-0.1.9b44 → valetudo_map_parser-0.1.9b45}/pyproject.toml +1 -2
- {valetudo_map_parser-0.1.9b44 → valetudo_map_parser-0.1.9b45}/LICENSE +0 -0
- {valetudo_map_parser-0.1.9b44 → valetudo_map_parser-0.1.9b45}/NOTICE.txt +0 -0
- {valetudo_map_parser-0.1.9b44 → valetudo_map_parser-0.1.9b45}/README.md +0 -0
- {valetudo_map_parser-0.1.9b44 → valetudo_map_parser-0.1.9b45}/SCR/valetudo_map_parser/__init__.py +0 -0
- {valetudo_map_parser-0.1.9b44 → valetudo_map_parser-0.1.9b45}/SCR/valetudo_map_parser/config/__init__.py +0 -0
- {valetudo_map_parser-0.1.9b44 → valetudo_map_parser-0.1.9b45}/SCR/valetudo_map_parser/config/auto_crop.py +0 -0
- {valetudo_map_parser-0.1.9b44 → valetudo_map_parser-0.1.9b45}/SCR/valetudo_map_parser/config/colors_man.py +0 -0
- {valetudo_map_parser-0.1.9b44 → valetudo_map_parser-0.1.9b45}/SCR/valetudo_map_parser/config/drawable_elements.py +0 -0
- {valetudo_map_parser-0.1.9b44 → valetudo_map_parser-0.1.9b45}/SCR/valetudo_map_parser/config/enhanced_drawable.py +0 -0
- {valetudo_map_parser-0.1.9b44 → valetudo_map_parser-0.1.9b45}/SCR/valetudo_map_parser/config/optimized_element_map.py +0 -0
- {valetudo_map_parser-0.1.9b44 → valetudo_map_parser-0.1.9b45}/SCR/valetudo_map_parser/config/rand25_parser.py +0 -0
- {valetudo_map_parser-0.1.9b44 → valetudo_map_parser-0.1.9b45}/SCR/valetudo_map_parser/config/room_outline.py +0 -0
- {valetudo_map_parser-0.1.9b44 → valetudo_map_parser-0.1.9b45}/SCR/valetudo_map_parser/config/shared.py +0 -0
- {valetudo_map_parser-0.1.9b44 → valetudo_map_parser-0.1.9b45}/SCR/valetudo_map_parser/config/types.py +0 -0
- {valetudo_map_parser-0.1.9b44 → valetudo_map_parser-0.1.9b45}/SCR/valetudo_map_parser/config/utils.py +0 -0
- {valetudo_map_parser-0.1.9b44 → valetudo_map_parser-0.1.9b45}/SCR/valetudo_map_parser/hypfer_draw.py +0 -0
- {valetudo_map_parser-0.1.9b44 → valetudo_map_parser-0.1.9b45}/SCR/valetudo_map_parser/map_data.py +0 -0
- {valetudo_map_parser-0.1.9b44 → valetudo_map_parser-0.1.9b45}/SCR/valetudo_map_parser/py.typed +0 -0
- {valetudo_map_parser-0.1.9b44 → valetudo_map_parser-0.1.9b45}/SCR/valetudo_map_parser/reimg_draw.py +0 -0
- {valetudo_map_parser-0.1.9b44 → valetudo_map_parser-0.1.9b45}/SCR/valetudo_map_parser/utils/__init__.py +0 -0
- {valetudo_map_parser-0.1.9b44 → valetudo_map_parser-0.1.9b45}/SCR/valetudo_map_parser/utils/color_utils.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: valetudo-map-parser
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.9b45
|
4
4
|
Summary: A Python library to parse Valetudo map data returning a PIL Image object.
|
5
5
|
License: Apache-2.0
|
6
6
|
Author: Sandro Cantarella
|
@@ -12,7 +12,6 @@ Classifier: Programming Language :: Python :: 3.12
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.13
|
13
13
|
Requires-Dist: Pillow (>=10.3.0)
|
14
14
|
Requires-Dist: numpy (>=1.26.4)
|
15
|
-
Requires-Dist: scikit-image (>=0.22.0)
|
16
15
|
Requires-Dist: scipy (>=1.12.0)
|
17
16
|
Project-URL: Bug Tracker, https://github.com/sca075/Python-package-valetudo-map-parser/issues
|
18
17
|
Project-URL: Changelog, https://github.com/sca075/Python-package-valetudo-map-parser/releases
|
@@ -194,6 +194,34 @@ class ColorsManagment:
|
|
194
194
|
|
195
195
|
return (out_r, out_g, out_b, out_a)
|
196
196
|
|
197
|
+
@staticmethod
|
198
|
+
def sample_and_blend_color(array, x: int, y: int, foreground: Color) -> Color:
|
199
|
+
"""
|
200
|
+
Sample the background color from the array at coordinates (x,y) and blend with foreground color.
|
201
|
+
|
202
|
+
Args:
|
203
|
+
array: The RGBA numpy array representing the image
|
204
|
+
x, y: Coordinates to sample the background color from
|
205
|
+
foreground: Foreground RGBA color (r,g,b,a) to blend on top
|
206
|
+
|
207
|
+
Returns:
|
208
|
+
Blended RGBA color
|
209
|
+
"""
|
210
|
+
# Ensure coordinates are within bounds
|
211
|
+
if array is None:
|
212
|
+
return foreground
|
213
|
+
|
214
|
+
height, width = array.shape[:2]
|
215
|
+
if not (0 <= y < height and 0 <= x < width):
|
216
|
+
return foreground # Return foreground if coordinates are out of bounds
|
217
|
+
|
218
|
+
# Sample background color from the array
|
219
|
+
# The array is in RGBA format with shape (height, width, 4)
|
220
|
+
background = tuple(array[y, x])
|
221
|
+
|
222
|
+
# Blend the colors
|
223
|
+
return ColorsManagment.blend_colors(background, foreground)
|
224
|
+
|
197
225
|
def get_user_colors(self) -> List[Color]:
|
198
226
|
"""Return the list of RGBA colors for user-defined map elements."""
|
199
227
|
return self.user_colors
|
@@ -174,11 +174,47 @@ class Drawable:
|
|
174
174
|
y2: int,
|
175
175
|
color: Color,
|
176
176
|
width: int = 3,
|
177
|
+
blend: bool = True,
|
177
178
|
) -> NumpyArray:
|
178
179
|
"""
|
179
180
|
Draw a line on a NumPy array (layer) from point A to B using Bresenham's algorithm.
|
181
|
+
|
182
|
+
Args:
|
183
|
+
layer: The numpy array to draw on
|
184
|
+
x1, y1: Start point coordinates
|
185
|
+
x2, y2: End point coordinates
|
186
|
+
color: Color to draw with
|
187
|
+
width: Width of the line
|
188
|
+
blend: Whether to blend the color with the background
|
180
189
|
"""
|
190
|
+
from .colors import ColorsManagment
|
191
|
+
|
181
192
|
x1, y1, x2, y2 = int(x1), int(y1), int(x2), int(y2)
|
193
|
+
|
194
|
+
# Sample background color at the endpoints and blend with foreground color if requested
|
195
|
+
if blend:
|
196
|
+
# Sample at start point
|
197
|
+
if 0 <= y1 < layer.shape[0] and 0 <= x1 < layer.shape[1]:
|
198
|
+
start_blended_color = ColorsManagment.sample_and_blend_color(layer, x1, y1, color)
|
199
|
+
else:
|
200
|
+
start_blended_color = color
|
201
|
+
|
202
|
+
# Sample at end point
|
203
|
+
if 0 <= y2 < layer.shape[0] and 0 <= x2 < layer.shape[1]:
|
204
|
+
end_blended_color = ColorsManagment.sample_and_blend_color(layer, x2, y2, color)
|
205
|
+
else:
|
206
|
+
end_blended_color = color
|
207
|
+
|
208
|
+
# Use the average of the two blended colors
|
209
|
+
blended_color = (
|
210
|
+
(start_blended_color[0] + end_blended_color[0]) // 2,
|
211
|
+
(start_blended_color[1] + end_blended_color[1]) // 2,
|
212
|
+
(start_blended_color[2] + end_blended_color[2]) // 2,
|
213
|
+
(start_blended_color[3] + end_blended_color[3]) // 2
|
214
|
+
)
|
215
|
+
else:
|
216
|
+
blended_color = color
|
217
|
+
|
182
218
|
dx = abs(x2 - x1)
|
183
219
|
dy = abs(y2 - y1)
|
184
220
|
sx = 1 if x1 < x2 else -1
|
@@ -189,7 +225,7 @@ class Drawable:
|
|
189
225
|
for i in range(-width // 2, (width + 1) // 2):
|
190
226
|
for j in range(-width // 2, (width + 1) // 2):
|
191
227
|
if 0 <= x1 + i < layer.shape[1] and 0 <= y1 + j < layer.shape[0]:
|
192
|
-
layer[y1 + j, x1 + i] =
|
228
|
+
layer[y1 + j, x1 + i] = blended_color
|
193
229
|
if x1 == x2 and y1 == y2:
|
194
230
|
break
|
195
231
|
e2 = 2 * err
|
@@ -221,6 +257,8 @@ class Drawable:
|
|
221
257
|
Join the coordinates creating a continuous line (path).
|
222
258
|
"""
|
223
259
|
import logging
|
260
|
+
from .colors import ColorsManagment
|
261
|
+
|
224
262
|
_LOGGER = logging.getLogger(__name__)
|
225
263
|
_LOGGER.debug("Drawing lines with %d coordinates, width %d, color %s", len(coords), width, color)
|
226
264
|
for coord in coords:
|
@@ -230,6 +268,27 @@ class Drawable:
|
|
230
268
|
except IndexError:
|
231
269
|
x1, y1 = x0, y0
|
232
270
|
_LOGGER.debug("Drawing line from (%d, %d) to (%d, %d)", x0, y0, x1, y1)
|
271
|
+
|
272
|
+
# Sample background color at the endpoints and blend with foreground color
|
273
|
+
# This is more efficient than sampling at every pixel
|
274
|
+
if 0 <= y0 < arr.shape[0] and 0 <= x0 < arr.shape[1]:
|
275
|
+
start_blended_color = ColorsManagment.sample_and_blend_color(arr, x0, y0, color)
|
276
|
+
else:
|
277
|
+
start_blended_color = color
|
278
|
+
|
279
|
+
if 0 <= y1 < arr.shape[0] and 0 <= x1 < arr.shape[1]:
|
280
|
+
end_blended_color = ColorsManagment.sample_and_blend_color(arr, x1, y1, color)
|
281
|
+
else:
|
282
|
+
end_blended_color = color
|
283
|
+
|
284
|
+
# Use the average of the two blended colors
|
285
|
+
blended_color = (
|
286
|
+
(start_blended_color[0] + end_blended_color[0]) // 2,
|
287
|
+
(start_blended_color[1] + end_blended_color[1]) // 2,
|
288
|
+
(start_blended_color[2] + end_blended_color[2]) // 2,
|
289
|
+
(start_blended_color[3] + end_blended_color[3]) // 2
|
290
|
+
)
|
291
|
+
|
233
292
|
dx = abs(x1 - x0)
|
234
293
|
dy = abs(y1 - y0)
|
235
294
|
sx = 1 if x0 < x1 else -1
|
@@ -252,8 +311,9 @@ class Drawable:
|
|
252
311
|
x, y = pixel
|
253
312
|
for i in range(width):
|
254
313
|
for j in range(width):
|
255
|
-
|
256
|
-
|
314
|
+
px, py = x + i, y + j
|
315
|
+
if 0 <= px < arr.shape[1] and 0 <= py < arr.shape[0]:
|
316
|
+
arr[py, px] = blended_color
|
257
317
|
return arr
|
258
318
|
|
259
319
|
@staticmethod
|
@@ -360,8 +420,10 @@ class Drawable:
|
|
360
420
|
@staticmethod
|
361
421
|
async def zones(layers: NumpyArray, coordinates, color: Color) -> NumpyArray:
|
362
422
|
"""
|
363
|
-
Draw the zones on the input layer.
|
423
|
+
Draw the zones on the input layer with color blending.
|
364
424
|
"""
|
425
|
+
from .colors import ColorsManagment
|
426
|
+
|
365
427
|
dot_radius = 1 # Number of pixels for the dot
|
366
428
|
dot_spacing = 4 # Space between dots
|
367
429
|
for zone in coordinates:
|
@@ -370,10 +432,22 @@ class Drawable:
|
|
370
432
|
max_x = max(points[::2])
|
371
433
|
min_y = min(points[1::2])
|
372
434
|
max_y = max(points[1::2])
|
435
|
+
|
436
|
+
# Sample a point from the zone to get the background color
|
437
|
+
# Use the center of the zone for sampling
|
438
|
+
sample_x = (min_x + max_x) // 2
|
439
|
+
sample_y = (min_y + max_y) // 2
|
440
|
+
|
441
|
+
# Blend the color with the background color at the sample point
|
442
|
+
if 0 <= sample_y < layers.shape[0] and 0 <= sample_x < layers.shape[1]:
|
443
|
+
blended_color = ColorsManagment.sample_and_blend_color(layers, sample_x, sample_y, color)
|
444
|
+
else:
|
445
|
+
blended_color = color
|
446
|
+
|
373
447
|
for y in range(min_y, max_y, dot_spacing):
|
374
448
|
for x in range(min_x, max_x, dot_spacing):
|
375
449
|
for _ in range(dot_radius):
|
376
|
-
layers = Drawable._ellipse(layers, (x, y), dot_radius,
|
450
|
+
layers = Drawable._ellipse(layers, (x, y), dot_radius, blended_color)
|
377
451
|
return layers
|
378
452
|
|
379
453
|
@staticmethod
|
@@ -26,11 +26,8 @@ from .config.types import (
|
|
26
26
|
)
|
27
27
|
from .config.utils import (
|
28
28
|
BaseHandler,
|
29
|
-
blend_colors,
|
30
|
-
blend_pixel,
|
31
29
|
get_element_at_position,
|
32
30
|
get_room_at_position,
|
33
|
-
handle_room_outline_error,
|
34
31
|
initialize_drawing_config,
|
35
32
|
manage_drawable_elements,
|
36
33
|
prepare_resize_params,
|
@@ -159,26 +156,7 @@ class HypferMapImageHandler(BaseHandler, AutoCrop):
|
|
159
156
|
x_max,
|
160
157
|
y_max,
|
161
158
|
) = await self.data.async_get_rooms_coordinates(pixels, pixel_size)
|
162
|
-
|
163
|
-
# Get rectangular corners as a fallback
|
164
159
|
corners = self.get_corners(x_max, x_min, y_max, y_min)
|
165
|
-
|
166
|
-
# Try to extract a more accurate room outline from the element map
|
167
|
-
try:
|
168
|
-
# Extract the room outline using the element map
|
169
|
-
outline = await self.extract_room_outline_from_map(
|
170
|
-
segment_id, pixels, pixel_size
|
171
|
-
)
|
172
|
-
LOGGER.debug(
|
173
|
-
"%s: Traced outline for room %s with %d points",
|
174
|
-
self.file_name,
|
175
|
-
segment_id,
|
176
|
-
len(outline),
|
177
|
-
)
|
178
|
-
except (ValueError, IndexError, TypeError, ArithmeticError) as e:
|
179
|
-
handle_room_outline_error(self.file_name, segment_id, e)
|
180
|
-
outline = corners
|
181
|
-
|
182
160
|
room_id = str(segment_id)
|
183
161
|
self.rooms_pos.append(
|
184
162
|
{
|
@@ -188,7 +166,7 @@ class HypferMapImageHandler(BaseHandler, AutoCrop):
|
|
188
166
|
)
|
189
167
|
room_properties[room_id] = {
|
190
168
|
"number": segment_id,
|
191
|
-
"outline":
|
169
|
+
"outline": corners,
|
192
170
|
"name": name,
|
193
171
|
"x": ((x_min + x_max) // 2),
|
194
172
|
"y": ((y_min + y_max) // 2),
|
@@ -597,29 +575,6 @@ class HypferMapImageHandler(BaseHandler, AutoCrop):
|
|
597
575
|
"""Get the room ID at a specific position, or None if not a room."""
|
598
576
|
return get_room_at_position(self.shared.element_map, x, y, DrawableElement.ROOM_1)
|
599
577
|
|
600
|
-
@staticmethod
|
601
|
-
def blend_colors(base_color, overlay_color):
|
602
|
-
"""
|
603
|
-
Blend two RGBA colors, considering alpha channels.
|
604
|
-
|
605
|
-
Args:
|
606
|
-
base_color: The base RGBA color
|
607
|
-
overlay_color: The overlay RGBA color to blend on top
|
608
|
-
|
609
|
-
Returns:
|
610
|
-
The blended RGBA color
|
611
|
-
"""
|
612
|
-
return blend_colors(base_color, overlay_color)
|
613
|
-
|
614
|
-
def blend_pixel(self, array, x, y, color, element):
|
615
|
-
"""
|
616
|
-
Blend a pixel color with the existing color at the specified position.
|
617
|
-
Also updates the element map if the new element has higher z-index.
|
618
|
-
"""
|
619
|
-
return blend_pixel(
|
620
|
-
array, x, y, color, element, self.shared.element_map, self.drawing_config
|
621
|
-
)
|
622
|
-
|
623
578
|
@staticmethod
|
624
579
|
async def async_copy_array(original_array):
|
625
580
|
"""Copy the array."""
|
@@ -130,7 +130,7 @@ class ReImageHandler(BaseHandler, AutoCrop):
|
|
130
130
|
|
131
131
|
async def extract_room_properties(
|
132
132
|
self, json_data: JsonType, destinations: JsonType
|
133
|
-
) -> RoomsProperties:
|
133
|
+
) -> tuple[RoomsProperties, Any, Any]:
|
134
134
|
"""Extract the room properties."""
|
135
135
|
unsorted_id = RandImageData.get_rrm_segments_ids(json_data)
|
136
136
|
size_x, size_y = RandImageData.get_rrm_image_size(json_data)
|
@@ -153,7 +153,7 @@ class ReImageHandler(BaseHandler, AutoCrop):
|
|
153
153
|
if not self.outlines:
|
154
154
|
# Return empty data if no outlines are available
|
155
155
|
_LOGGER.debug("%s: No outlines available", self.file_name)
|
156
|
-
return None, None, None
|
156
|
+
return None, None, None # Return empty data for all three return values
|
157
157
|
|
158
158
|
# If we have outlines, proceed with processing
|
159
159
|
for id_x, room_id in enumerate(unsorted_id):
|
@@ -231,7 +231,7 @@ class ReImageHandler(BaseHandler, AutoCrop):
|
|
231
231
|
e,
|
232
232
|
exc_info=True,
|
233
233
|
)
|
234
|
-
return None, None, None
|
234
|
+
return None, None, None # Return empty data in case of error
|
235
235
|
|
236
236
|
async def get_image_from_rrm(
|
237
237
|
self,
|
@@ -427,7 +427,7 @@ class ReImageHandler(BaseHandler, AutoCrop):
|
|
427
427
|
|
428
428
|
async def get_rooms_attributes(
|
429
429
|
self, destinations: JsonType = None
|
430
|
-
) -> RoomsProperties:
|
430
|
+
) -> tuple[RoomsProperties, Any, Any]:
|
431
431
|
"""Return the rooms attributes."""
|
432
432
|
if self.room_propriety:
|
433
433
|
return self.room_propriety
|
@@ -1,6 +1,6 @@
|
|
1
1
|
[tool.poetry]
|
2
2
|
name = "valetudo-map-parser"
|
3
|
-
version = "0.1.
|
3
|
+
version = "0.1.9b45"
|
4
4
|
description = "A Python library to parse Valetudo map data returning a PIL Image object."
|
5
5
|
authors = ["Sandro Cantarella <gsca075@gmail.com>"]
|
6
6
|
license = "Apache-2.0"
|
@@ -18,7 +18,6 @@ python = ">=3.12"
|
|
18
18
|
numpy = ">=1.26.4"
|
19
19
|
Pillow = ">=10.3.0"
|
20
20
|
scipy = ">=1.12.0"
|
21
|
-
scikit-image = ">=0.22.0"
|
22
21
|
|
23
22
|
[tool.poetry.group.dev.dependencies]
|
24
23
|
ruff = "*"
|
File without changes
|
File without changes
|
File without changes
|
{valetudo_map_parser-0.1.9b44 → valetudo_map_parser-0.1.9b45}/SCR/valetudo_map_parser/__init__.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{valetudo_map_parser-0.1.9b44 → valetudo_map_parser-0.1.9b45}/SCR/valetudo_map_parser/hypfer_draw.py
RENAMED
File without changes
|
{valetudo_map_parser-0.1.9b44 → valetudo_map_parser-0.1.9b45}/SCR/valetudo_map_parser/map_data.py
RENAMED
File without changes
|
{valetudo_map_parser-0.1.9b44 → valetudo_map_parser-0.1.9b45}/SCR/valetudo_map_parser/py.typed
RENAMED
File without changes
|
{valetudo_map_parser-0.1.9b44 → valetudo_map_parser-0.1.9b45}/SCR/valetudo_map_parser/reimg_draw.py
RENAMED
File without changes
|
File without changes
|
File without changes
|