valetudo-map-parser 0.1.9b44__py3-none-any.whl → 0.1.9b46__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/config/colors.py +621 -20
- valetudo_map_parser/config/drawable.py +148 -12
- valetudo_map_parser/config/drawable_elements.py +166 -70
- valetudo_map_parser/config/optimized_element_map.py +133 -90
- valetudo_map_parser/config/room_outline.py +27 -27
- valetudo_map_parser/hypfer_handler.py +34 -59
- valetudo_map_parser/map_data.py +1 -1
- valetudo_map_parser/rand25_handler.py +60 -84
- valetudo_map_parser/utils/color_utils.py +8 -8
- {valetudo_map_parser-0.1.9b44.dist-info → valetudo_map_parser-0.1.9b46.dist-info}/METADATA +1 -2
- valetudo_map_parser-0.1.9b46.dist-info/RECORD +26 -0
- valetudo_map_parser/config/colors_man.py +0 -249
- valetudo_map_parser-0.1.9b44.dist-info/RECORD +0 -27
- {valetudo_map_parser-0.1.9b44.dist-info → valetudo_map_parser-0.1.9b46.dist-info}/LICENSE +0 -0
- {valetudo_map_parser-0.1.9b44.dist-info → valetudo_map_parser-0.1.9b46.dist-info}/NOTICE.txt +0 -0
- {valetudo_map_parser-0.1.9b44.dist-info → valetudo_map_parser-0.1.9b46.dist-info}/WHEEL +0 -0
@@ -13,11 +13,11 @@ import asyncio
|
|
13
13
|
import logging
|
14
14
|
import math
|
15
15
|
|
16
|
-
# cv2 is imported but not used directly in this file
|
17
|
-
# It's needed for other modules that import from here
|
18
16
|
import numpy as np
|
19
17
|
from PIL import ImageDraw, ImageFont
|
18
|
+
from scipy import ndimage
|
20
19
|
|
20
|
+
from .colors import ColorsManagement
|
21
21
|
from .types import Color, NumpyArray, PilPNG, Point, Tuple, Union
|
22
22
|
|
23
23
|
|
@@ -174,11 +174,50 @@ 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
|
+
|
181
191
|
x1, y1, x2, y2 = int(x1), int(y1), int(x2), int(y2)
|
192
|
+
|
193
|
+
# Sample background color at the endpoints and blend with foreground color if requested
|
194
|
+
if blend:
|
195
|
+
# Sample at start point
|
196
|
+
if 0 <= y1 < layer.shape[0] and 0 <= x1 < layer.shape[1]:
|
197
|
+
start_blended_color = ColorsManagement.sample_and_blend_color(
|
198
|
+
layer, x1, y1, color
|
199
|
+
)
|
200
|
+
else:
|
201
|
+
start_blended_color = color
|
202
|
+
|
203
|
+
# Sample at end point
|
204
|
+
if 0 <= y2 < layer.shape[0] and 0 <= x2 < layer.shape[1]:
|
205
|
+
end_blended_color = ColorsManagement.sample_and_blend_color(
|
206
|
+
layer, x2, y2, color
|
207
|
+
)
|
208
|
+
else:
|
209
|
+
end_blended_color = color
|
210
|
+
|
211
|
+
# Use the average of the two blended colors
|
212
|
+
blended_color = (
|
213
|
+
(start_blended_color[0] + end_blended_color[0]) // 2,
|
214
|
+
(start_blended_color[1] + end_blended_color[1]) // 2,
|
215
|
+
(start_blended_color[2] + end_blended_color[2]) // 2,
|
216
|
+
(start_blended_color[3] + end_blended_color[3]) // 2,
|
217
|
+
)
|
218
|
+
else:
|
219
|
+
blended_color = color
|
220
|
+
|
182
221
|
dx = abs(x2 - x1)
|
183
222
|
dy = abs(y2 - y1)
|
184
223
|
sx = 1 if x1 < x2 else -1
|
@@ -189,7 +228,7 @@ class Drawable:
|
|
189
228
|
for i in range(-width // 2, (width + 1) // 2):
|
190
229
|
for j in range(-width // 2, (width + 1) // 2):
|
191
230
|
if 0 <= x1 + i < layer.shape[1] and 0 <= y1 + j < layer.shape[0]:
|
192
|
-
layer[y1 + j, x1 + i] =
|
231
|
+
layer[y1 + j, x1 + i] = blended_color
|
193
232
|
if x1 == x2 and y1 == y2:
|
194
233
|
break
|
195
234
|
e2 = 2 * err
|
@@ -220,16 +259,38 @@ class Drawable:
|
|
220
259
|
"""
|
221
260
|
Join the coordinates creating a continuous line (path).
|
222
261
|
"""
|
223
|
-
|
224
|
-
_LOGGER = logging.getLogger(__name__)
|
225
|
-
_LOGGER.debug("Drawing lines with %d coordinates, width %d, color %s", len(coords), width, color)
|
262
|
+
|
226
263
|
for coord in coords:
|
227
264
|
x0, y0 = coord[0]
|
228
265
|
try:
|
229
266
|
x1, y1 = coord[1]
|
230
267
|
except IndexError:
|
231
268
|
x1, y1 = x0, y0
|
232
|
-
|
269
|
+
|
270
|
+
# Sample background color at the endpoints and blend with foreground color
|
271
|
+
# This is more efficient than sampling at every pixel
|
272
|
+
if 0 <= y0 < arr.shape[0] and 0 <= x0 < arr.shape[1]:
|
273
|
+
start_blended_color = ColorsManagement.sample_and_blend_color(
|
274
|
+
arr, x0, y0, color
|
275
|
+
)
|
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 = ColorsManagement.sample_and_blend_color(
|
281
|
+
arr, x1, y1, color
|
282
|
+
)
|
283
|
+
else:
|
284
|
+
end_blended_color = color
|
285
|
+
|
286
|
+
# Use the average of the two blended colors
|
287
|
+
blended_color = (
|
288
|
+
(start_blended_color[0] + end_blended_color[0]) // 2,
|
289
|
+
(start_blended_color[1] + end_blended_color[1]) // 2,
|
290
|
+
(start_blended_color[2] + end_blended_color[2]) // 2,
|
291
|
+
(start_blended_color[3] + end_blended_color[3]) // 2,
|
292
|
+
)
|
293
|
+
|
233
294
|
dx = abs(x1 - x0)
|
234
295
|
dy = abs(y1 - y0)
|
235
296
|
sx = 1 if x0 < x1 else -1
|
@@ -252,8 +313,9 @@ class Drawable:
|
|
252
313
|
x, y = pixel
|
253
314
|
for i in range(width):
|
254
315
|
for j in range(width):
|
255
|
-
|
256
|
-
|
316
|
+
px, py = x + i, y + j
|
317
|
+
if 0 <= px < arr.shape[1] and 0 <= py < arr.shape[0]:
|
318
|
+
arr[py, px] = blended_color
|
257
319
|
return arr
|
258
320
|
|
259
321
|
@staticmethod
|
@@ -360,8 +422,9 @@ class Drawable:
|
|
360
422
|
@staticmethod
|
361
423
|
async def zones(layers: NumpyArray, coordinates, color: Color) -> NumpyArray:
|
362
424
|
"""
|
363
|
-
Draw the zones on the input layer.
|
425
|
+
Draw the zones on the input layer with color blending.
|
364
426
|
"""
|
427
|
+
|
365
428
|
dot_radius = 1 # Number of pixels for the dot
|
366
429
|
dot_spacing = 4 # Space between dots
|
367
430
|
for zone in coordinates:
|
@@ -370,10 +433,26 @@ class Drawable:
|
|
370
433
|
max_x = max(points[::2])
|
371
434
|
min_y = min(points[1::2])
|
372
435
|
max_y = max(points[1::2])
|
436
|
+
|
437
|
+
# Sample a point from the zone to get the background color
|
438
|
+
# Use the center of the zone for sampling
|
439
|
+
sample_x = (min_x + max_x) // 2
|
440
|
+
sample_y = (min_y + max_y) // 2
|
441
|
+
|
442
|
+
# Blend the color with the background color at the sample point
|
443
|
+
if 0 <= sample_y < layers.shape[0] and 0 <= sample_x < layers.shape[1]:
|
444
|
+
blended_color = ColorsManagement.sample_and_blend_color(
|
445
|
+
layers, sample_x, sample_y, color
|
446
|
+
)
|
447
|
+
else:
|
448
|
+
blended_color = color
|
449
|
+
|
373
450
|
for y in range(min_y, max_y, dot_spacing):
|
374
451
|
for x in range(min_x, max_x, dot_spacing):
|
375
452
|
for _ in range(dot_radius):
|
376
|
-
layers = Drawable._ellipse(
|
453
|
+
layers = Drawable._ellipse(
|
454
|
+
layers, (x, y), dot_radius, blended_color
|
455
|
+
)
|
377
456
|
return layers
|
378
457
|
|
379
458
|
@staticmethod
|
@@ -468,7 +547,7 @@ class Drawable:
|
|
468
547
|
|
469
548
|
@staticmethod
|
470
549
|
async def async_draw_obstacles(
|
471
|
-
image: np.ndarray, obstacle_info_list, color:
|
550
|
+
image: np.ndarray, obstacle_info_list, color: Color
|
472
551
|
) -> np.ndarray:
|
473
552
|
"""
|
474
553
|
Optimized async version of draw_obstacles using asyncio.gather().
|
@@ -518,3 +597,60 @@ class Drawable:
|
|
518
597
|
else:
|
519
598
|
draw.text((x, y), text, font=font, fill=color)
|
520
599
|
x += draw.textlength(text, font=default_font)
|
600
|
+
|
601
|
+
@staticmethod
|
602
|
+
def draw_filled_polygon(image_array, vertices, color):
|
603
|
+
"""
|
604
|
+
Draw a filled polygon on the image array using scipy.ndimage.
|
605
|
+
|
606
|
+
Args:
|
607
|
+
image_array: NumPy array of shape (height, width, 4) containing RGBA image data
|
608
|
+
vertices: List of (x,y) tuples defining the polygon vertices
|
609
|
+
color: RGBA color tuple to fill the polygon with
|
610
|
+
|
611
|
+
Returns:
|
612
|
+
Modified image array with the filled polygon
|
613
|
+
"""
|
614
|
+
if len(vertices) < 3:
|
615
|
+
return image_array # Need at least 3 points for a polygon
|
616
|
+
|
617
|
+
height, width = image_array.shape[:2]
|
618
|
+
|
619
|
+
# Create a mask for the polygon
|
620
|
+
polygon_mask = np.zeros((height, width), dtype=bool)
|
621
|
+
|
622
|
+
# Convert vertices to numpy arrays for processing
|
623
|
+
vertices_array = np.array(vertices)
|
624
|
+
x_coords = vertices_array[:, 0]
|
625
|
+
y_coords = vertices_array[:, 1]
|
626
|
+
|
627
|
+
# Clip coordinates to image boundaries
|
628
|
+
x_coords = np.clip(x_coords, 0, width - 1)
|
629
|
+
y_coords = np.clip(y_coords, 0, height - 1)
|
630
|
+
|
631
|
+
# Create a polygon using scipy.ndimage
|
632
|
+
# First create the boundary
|
633
|
+
for i in range(len(vertices)):
|
634
|
+
x1, y1 = int(x_coords[i]), int(y_coords[i])
|
635
|
+
x2, y2 = (
|
636
|
+
int(x_coords[(i + 1) % len(vertices)]),
|
637
|
+
int(y_coords[(i + 1) % len(vertices)]),
|
638
|
+
)
|
639
|
+
|
640
|
+
# Draw line between consecutive vertices
|
641
|
+
length = max(abs(x2 - x1), abs(y2 - y1)) * 2
|
642
|
+
if length == 0:
|
643
|
+
continue
|
644
|
+
|
645
|
+
t = np.linspace(0, 1, length)
|
646
|
+
x = np.round(x1 * (1 - t) + x2 * t).astype(int)
|
647
|
+
y = np.round(y1 * (1 - t) + y2 * t).astype(int)
|
648
|
+
|
649
|
+
# Add boundary points to mask
|
650
|
+
polygon_mask[y, x] = True
|
651
|
+
|
652
|
+
# Fill the polygon using scipy.ndimage.binary_fill_holes
|
653
|
+
filled_polygon = ndimage.binary_fill_holes(polygon_mask)
|
654
|
+
|
655
|
+
# Apply color to the filled polygon
|
656
|
+
return ColorsManagement.batch_blend_colors(image_array, filled_polygon, color)
|