valetudo-map-parser 0.1.9b47__py3-none-any.whl → 0.1.9b48__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/color_utils.py +51 -0
- valetudo_map_parser/config/drawable.py +458 -222
- {valetudo_map_parser-0.1.9b47.dist-info → valetudo_map_parser-0.1.9b48.dist-info}/METADATA +1 -1
- {valetudo_map_parser-0.1.9b47.dist-info → valetudo_map_parser-0.1.9b48.dist-info}/RECORD +7 -7
- {valetudo_map_parser-0.1.9b47.dist-info → valetudo_map_parser-0.1.9b48.dist-info}/WHEEL +1 -1
- valetudo_map_parser/utils/color_utils.py +0 -62
- {valetudo_map_parser-0.1.9b47.dist-info → valetudo_map_parser-0.1.9b48.dist-info}/LICENSE +0 -0
- {valetudo_map_parser-0.1.9b47.dist-info → valetudo_map_parser-0.1.9b48.dist-info}/NOTICE.txt +0 -0
@@ -0,0 +1,51 @@
|
|
1
|
+
"""Utility functions for color operations in the map parser."""
|
2
|
+
|
3
|
+
from typing import Tuple, Optional
|
4
|
+
|
5
|
+
from SCR.valetudo_map_parser.config.colors import ColorsManagement
|
6
|
+
from SCR.valetudo_map_parser.config.types import NumpyArray, Color
|
7
|
+
|
8
|
+
|
9
|
+
def get_blended_color(
|
10
|
+
x0: int,
|
11
|
+
y0: int,
|
12
|
+
x1: int,
|
13
|
+
y1: int,
|
14
|
+
arr: Optional[NumpyArray],
|
15
|
+
color: Color,
|
16
|
+
) -> Color:
|
17
|
+
"""
|
18
|
+
Get a blended color for a pixel based on the current element map and the new element to draw.
|
19
|
+
|
20
|
+
This function:
|
21
|
+
1. Gets the current element at position (x,y) from the element map
|
22
|
+
2. Gets the color for that element from the colors manager
|
23
|
+
3. Blends the new color with the existing color based on alpha values
|
24
|
+
|
25
|
+
Returns:
|
26
|
+
Blended RGBA color to use for drawing
|
27
|
+
"""
|
28
|
+
# Sample background color at the endpoints and blend with foreground color
|
29
|
+
# This is more efficient than sampling at every pixel
|
30
|
+
if 0 <= y0 < arr.shape[0] and 0 <= x0 < arr.shape[1]:
|
31
|
+
start_blended_color = ColorsManagement.sample_and_blend_color(
|
32
|
+
arr, x0, y0, color
|
33
|
+
)
|
34
|
+
else:
|
35
|
+
start_blended_color = color
|
36
|
+
|
37
|
+
if 0 <= y1 < arr.shape[0] and 0 <= x1 < arr.shape[1]:
|
38
|
+
end_blended_color = ColorsManagement.sample_and_blend_color(
|
39
|
+
arr, x1, y1, color
|
40
|
+
)
|
41
|
+
else:
|
42
|
+
end_blended_color = color
|
43
|
+
|
44
|
+
# Use the average of the two blended colors
|
45
|
+
blended_color = (
|
46
|
+
(start_blended_color[0] + end_blended_color[0]) // 2,
|
47
|
+
(start_blended_color[1] + end_blended_color[1]) // 2,
|
48
|
+
(start_blended_color[2] + end_blended_color[2]) // 2,
|
49
|
+
(start_blended_color[3] + end_blended_color[3]) // 2,
|
50
|
+
)
|
51
|
+
return blended_color
|
@@ -3,21 +3,22 @@ Collections of Drawing Utility
|
|
3
3
|
Drawable is part of the Image_Handler
|
4
4
|
used functions to draw the elements on the Numpy Array
|
5
5
|
that is actually our camera frame.
|
6
|
-
Version:
|
6
|
+
Version: v0.1.10
|
7
7
|
Refactored for clarity, consistency, and optimized parameter usage.
|
8
|
+
Optimized with NumPy and SciPy for better performance.
|
8
9
|
"""
|
9
10
|
|
10
11
|
from __future__ import annotations
|
11
12
|
|
12
|
-
|
13
|
+
|
13
14
|
import logging
|
14
15
|
import math
|
15
16
|
|
16
17
|
import numpy as np
|
17
18
|
from PIL import ImageDraw, ImageFont
|
18
|
-
from scipy import ndimage
|
19
19
|
|
20
20
|
from .colors import ColorsManagement
|
21
|
+
from .color_utils import get_blended_color
|
21
22
|
from .types import Color, NumpyArray, PilPNG, Point, Tuple, Union
|
22
23
|
|
23
24
|
|
@@ -62,6 +63,9 @@ class Drawable:
|
|
62
63
|
# Create the full color with alpha
|
63
64
|
full_color = color if len(color) == 4 else (*color, 255)
|
64
65
|
|
66
|
+
# Check if we need to blend colors (alpha < 255)
|
67
|
+
need_blending = alpha < 255
|
68
|
+
|
65
69
|
# Loop through pixels to find min and max coordinates
|
66
70
|
for x, y, z in pixels:
|
67
71
|
col = x * pixel_size
|
@@ -69,13 +73,31 @@ class Drawable:
|
|
69
73
|
# Draw pixels as blocks
|
70
74
|
for i in range(z):
|
71
75
|
# Get the region to update
|
72
|
-
|
73
|
-
row
|
74
|
-
col + i * pixel_size
|
75
|
-
|
76
|
+
region_slice = (
|
77
|
+
slice(row, row + pixel_size),
|
78
|
+
slice(col + i * pixel_size, col + (i + 1) * pixel_size)
|
79
|
+
)
|
76
80
|
|
77
|
-
|
78
|
-
|
81
|
+
if need_blending:
|
82
|
+
# Sample the center of the region for blending
|
83
|
+
center_y = row + pixel_size // 2
|
84
|
+
center_x = col + i * pixel_size + pixel_size // 2
|
85
|
+
|
86
|
+
# Only blend if coordinates are valid
|
87
|
+
if (0 <= center_y < image_array.shape[0] and
|
88
|
+
0 <= center_x < image_array.shape[1]):
|
89
|
+
# Get blended color
|
90
|
+
blended_color = ColorsManagement.sample_and_blend_color(
|
91
|
+
image_array, center_x, center_y, full_color
|
92
|
+
)
|
93
|
+
# Apply blended color to the region
|
94
|
+
image_array[region_slice] = blended_color
|
95
|
+
else:
|
96
|
+
# Use original color if out of bounds
|
97
|
+
image_array[region_slice] = full_color
|
98
|
+
else:
|
99
|
+
# No blending needed, use direct assignment
|
100
|
+
image_array[region_slice] = full_color
|
79
101
|
|
80
102
|
return image_array
|
81
103
|
|
@@ -83,14 +105,44 @@ class Drawable:
|
|
83
105
|
async def battery_charger(
|
84
106
|
layers: NumpyArray, x: int, y: int, color: Color
|
85
107
|
) -> NumpyArray:
|
86
|
-
"""Draw the battery charger on the input layer."""
|
108
|
+
"""Draw the battery charger on the input layer with color blending."""
|
109
|
+
# Check if coordinates are within bounds
|
110
|
+
height, width = layers.shape[:2]
|
111
|
+
if not (0 <= x < width and 0 <= y < height):
|
112
|
+
return layers
|
113
|
+
|
114
|
+
# Calculate charger dimensions
|
87
115
|
charger_width = 10
|
88
116
|
charger_height = 20
|
89
|
-
start_row = y - charger_height // 2
|
90
|
-
end_row = start_row + charger_height
|
91
|
-
start_col = x - charger_width // 2
|
92
|
-
end_col = start_col + charger_width
|
93
|
-
|
117
|
+
start_row = max(0, y - charger_height // 2)
|
118
|
+
end_row = min(height, start_row + charger_height)
|
119
|
+
start_col = max(0, x - charger_width // 2)
|
120
|
+
end_col = min(width, start_col + charger_width)
|
121
|
+
|
122
|
+
# Skip if charger is completely outside the image
|
123
|
+
if start_row >= end_row or start_col >= end_col:
|
124
|
+
return layers
|
125
|
+
|
126
|
+
# Extract alpha from color
|
127
|
+
alpha = color[3] if len(color) == 4 else 255
|
128
|
+
|
129
|
+
# Check if we need to blend colors (alpha < 255)
|
130
|
+
if alpha < 255:
|
131
|
+
# Sample the center of the charger for blending
|
132
|
+
center_y = (start_row + end_row) // 2
|
133
|
+
center_x = (start_col + end_col) // 2
|
134
|
+
|
135
|
+
# Get blended color
|
136
|
+
blended_color = ColorsManagement.sample_and_blend_color(
|
137
|
+
layers, center_x, center_y, color
|
138
|
+
)
|
139
|
+
|
140
|
+
# Apply blended color
|
141
|
+
layers[start_row:end_row, start_col:end_col] = blended_color
|
142
|
+
else:
|
143
|
+
# No blending needed, use direct assignment
|
144
|
+
layers[start_row:end_row, start_col:end_col] = color
|
145
|
+
|
94
146
|
return layers
|
95
147
|
|
96
148
|
@staticmethod
|
@@ -100,8 +152,34 @@ class Drawable:
|
|
100
152
|
"""
|
101
153
|
Draw a flag centered at specified coordinates on the input layer.
|
102
154
|
It uses the rotation angle of the image to orient the flag.
|
155
|
+
Includes color blending for better visual integration.
|
103
156
|
"""
|
104
|
-
|
157
|
+
# Check if coordinates are within bounds
|
158
|
+
height, width = layer.shape[:2]
|
159
|
+
x, y = center
|
160
|
+
if not (0 <= x < width and 0 <= y < height):
|
161
|
+
return layer
|
162
|
+
|
163
|
+
# Get blended colors for flag and pole
|
164
|
+
flag_alpha = flag_color[3] if len(flag_color) == 4 else 255
|
165
|
+
pole_color_base = (0, 0, 255) # Blue for the pole
|
166
|
+
pole_alpha = 255
|
167
|
+
|
168
|
+
# Blend flag color if needed
|
169
|
+
if flag_alpha < 255:
|
170
|
+
flag_color = ColorsManagement.sample_and_blend_color(
|
171
|
+
layer, x, y, flag_color
|
172
|
+
)
|
173
|
+
|
174
|
+
# Create pole color with alpha
|
175
|
+
pole_color: Color = (*pole_color_base, pole_alpha)
|
176
|
+
|
177
|
+
# Blend pole color if needed
|
178
|
+
if pole_alpha < 255:
|
179
|
+
pole_color = ColorsManagement.sample_and_blend_color(
|
180
|
+
layer, x, y, pole_color
|
181
|
+
)
|
182
|
+
|
105
183
|
flag_size = 50
|
106
184
|
pole_width = 6
|
107
185
|
# Adjust flag coordinates based on rotation angle
|
@@ -174,10 +252,9 @@ class Drawable:
|
|
174
252
|
y2: int,
|
175
253
|
color: Color,
|
176
254
|
width: int = 3,
|
177
|
-
blend: bool = True,
|
178
255
|
) -> NumpyArray:
|
179
256
|
"""
|
180
|
-
Draw a line on a NumPy array (layer) from point A to B using
|
257
|
+
Draw a line on a NumPy array (layer) from point A to B using vectorized operations.
|
181
258
|
|
182
259
|
Args:
|
183
260
|
layer: The numpy array to draw on
|
@@ -185,59 +262,45 @@ class Drawable:
|
|
185
262
|
x2, y2: End point coordinates
|
186
263
|
color: Color to draw with
|
187
264
|
width: Width of the line
|
188
|
-
blend: Whether to blend the color with the background
|
189
265
|
"""
|
190
|
-
|
266
|
+
# Ensure coordinates are integers
|
191
267
|
x1, y1, x2, y2 = int(x1), int(y1), int(x2), int(y2)
|
192
268
|
|
193
|
-
#
|
194
|
-
|
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
|
269
|
+
# Get blended color for the line
|
270
|
+
blended_color = get_blended_color(x1, y1, x2, y2, layer, color)
|
202
271
|
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
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
|
-
|
221
|
-
dx = abs(x2 - x1)
|
222
|
-
dy = abs(y2 - y1)
|
223
|
-
sx = 1 if x1 < x2 else -1
|
224
|
-
sy = 1 if y1 < y2 else -1
|
225
|
-
err = dx - dy
|
226
|
-
while True:
|
227
|
-
# Draw a rectangle at the current coordinates with the specified width
|
272
|
+
# Calculate line length
|
273
|
+
length = max(abs(x2 - x1), abs(y2 - y1))
|
274
|
+
if length == 0: # Handle case of a single point
|
275
|
+
# Draw a dot with the specified width
|
228
276
|
for i in range(-width // 2, (width + 1) // 2):
|
229
277
|
for j in range(-width // 2, (width + 1) // 2):
|
230
278
|
if 0 <= x1 + i < layer.shape[1] and 0 <= y1 + j < layer.shape[0]:
|
231
279
|
layer[y1 + j, x1 + i] = blended_color
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
280
|
+
return layer
|
281
|
+
|
282
|
+
# Create parametric points along the line
|
283
|
+
t = np.linspace(0, 1, length * 2) # Double the points for smoother lines
|
284
|
+
x_coords = np.round(x1 * (1 - t) + x2 * t).astype(int)
|
285
|
+
y_coords = np.round(y1 * (1 - t) + y2 * t).astype(int)
|
286
|
+
|
287
|
+
# Draw the line with the specified width
|
288
|
+
if width == 1:
|
289
|
+
# Fast path for width=1
|
290
|
+
for x, y in zip(x_coords, y_coords):
|
291
|
+
if 0 <= x < layer.shape[1] and 0 <= y < layer.shape[0]:
|
292
|
+
layer[y, x] = blended_color
|
293
|
+
else:
|
294
|
+
# For thicker lines, draw a rectangle at each point
|
295
|
+
half_width = width // 2
|
296
|
+
for x, y in zip(x_coords, y_coords):
|
297
|
+
for i in range(-half_width, half_width + 1):
|
298
|
+
for j in range(-half_width, half_width + 1):
|
299
|
+
if (i*i + j*j <= half_width*half_width and # Make it round
|
300
|
+
0 <= x + i < layer.shape[1] and
|
301
|
+
0 <= y + j < layer.shape[0]):
|
302
|
+
layer[y + j, x + i] = blended_color
|
303
|
+
|
241
304
|
return layer
|
242
305
|
|
243
306
|
@staticmethod
|
@@ -258,8 +321,8 @@ class Drawable:
|
|
258
321
|
async def lines(arr: NumpyArray, coords, width: int, color: Color) -> NumpyArray:
|
259
322
|
"""
|
260
323
|
Join the coordinates creating a continuous line (path).
|
324
|
+
Optimized with vectorized operations for better performance.
|
261
325
|
"""
|
262
|
-
|
263
326
|
for coord in coords:
|
264
327
|
x0, y0 = coord[0]
|
265
328
|
try:
|
@@ -267,55 +330,16 @@ class Drawable:
|
|
267
330
|
except IndexError:
|
268
331
|
x1, y1 = x0, y0
|
269
332
|
|
270
|
-
#
|
271
|
-
|
272
|
-
|
273
|
-
start_blended_color = ColorsManagement.sample_and_blend_color(
|
274
|
-
arr, x0, y0, color
|
275
|
-
)
|
276
|
-
else:
|
277
|
-
start_blended_color = color
|
333
|
+
# Skip if coordinates are the same
|
334
|
+
if x0 == x1 and y0 == y1:
|
335
|
+
continue
|
278
336
|
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
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
|
-
)
|
337
|
+
# Get blended color for this line segment
|
338
|
+
blended_color = get_blended_color(x0, y0, x1, y1, arr, color)
|
339
|
+
|
340
|
+
# Use the optimized line drawing method
|
341
|
+
arr = Drawable._line(arr, x0, y0, x1, y1, blended_color, width)
|
293
342
|
|
294
|
-
dx = abs(x1 - x0)
|
295
|
-
dy = abs(y1 - y0)
|
296
|
-
sx = 1 if x0 < x1 else -1
|
297
|
-
sy = 1 if y0 < y1 else -1
|
298
|
-
err = dx - dy
|
299
|
-
line_pixels: list[Tuple[int, int]] = []
|
300
|
-
while True:
|
301
|
-
line_pixels.append((x0, y0))
|
302
|
-
if x0 == x1 and y0 == y1:
|
303
|
-
break
|
304
|
-
e2 = 2 * err
|
305
|
-
if e2 > -dy:
|
306
|
-
err -= dy
|
307
|
-
x0 += sx
|
308
|
-
if e2 < dx:
|
309
|
-
err += dx
|
310
|
-
y0 += sy
|
311
|
-
# Draw filled rectangles for each pixel in the line
|
312
|
-
for pixel in line_pixels:
|
313
|
-
x, y = pixel
|
314
|
-
for i in range(width):
|
315
|
-
for j in range(width):
|
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
|
319
343
|
return arr
|
320
344
|
|
321
345
|
@staticmethod
|
@@ -329,17 +353,35 @@ class Drawable:
|
|
329
353
|
) -> NumpyArray:
|
330
354
|
"""
|
331
355
|
Draw a filled circle on the image using NumPy.
|
356
|
+
Optimized to only process the bounding box of the circle.
|
332
357
|
"""
|
333
358
|
y, x = center
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
359
|
+
height, width = image.shape[:2]
|
360
|
+
|
361
|
+
# Calculate the bounding box of the circle
|
362
|
+
min_y = max(0, y - radius - outline_width)
|
363
|
+
max_y = min(height, y + radius + outline_width + 1)
|
364
|
+
min_x = max(0, x - radius - outline_width)
|
365
|
+
max_x = min(width, x + radius + outline_width + 1)
|
366
|
+
|
367
|
+
# Create coordinate arrays for the bounding box
|
368
|
+
y_indices, x_indices = np.ogrid[min_y:max_y, min_x:max_x]
|
369
|
+
|
370
|
+
# Calculate distances from center
|
371
|
+
dist_sq = (y_indices - y) ** 2 + (x_indices - x) ** 2
|
372
|
+
|
373
|
+
# Create masks for the circle and outline
|
374
|
+
circle_mask = dist_sq <= radius ** 2
|
375
|
+
|
376
|
+
# Apply the fill color
|
377
|
+
image[min_y:max_y, min_x:max_x][circle_mask] = color
|
378
|
+
|
379
|
+
# Draw the outline if needed
|
380
|
+
if outline_width > 0 and outline_color is not None:
|
381
|
+
outer_mask = dist_sq <= (radius + outline_width) ** 2
|
382
|
+
outline_mask = outer_mask & ~circle_mask
|
383
|
+
image[min_y:max_y, min_x:max_x][outline_mask] = outline_color
|
384
|
+
|
343
385
|
return image
|
344
386
|
|
345
387
|
@staticmethod
|
@@ -395,7 +437,9 @@ class Drawable:
|
|
395
437
|
) -> NumpyArray:
|
396
438
|
"""
|
397
439
|
Draw the outline of a polygon on the array using _line, and optionally fill it.
|
440
|
+
Uses NumPy vectorized operations for improved performance.
|
398
441
|
"""
|
442
|
+
# Draw the outline
|
399
443
|
for i, _ in enumerate(points):
|
400
444
|
current_point = points[i]
|
401
445
|
next_point = points[(i + 1) % len(points)]
|
@@ -408,31 +452,53 @@ class Drawable:
|
|
408
452
|
outline_color,
|
409
453
|
width,
|
410
454
|
)
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
455
|
+
|
456
|
+
# Fill the polygon if a fill color is provided
|
457
|
+
if fill_color is not None:
|
458
|
+
# Get the bounding box of the polygon
|
459
|
+
min_x = max(0, min(p[0] for p in points))
|
460
|
+
max_x = min(arr.shape[1] - 1, max(p[0] for p in points))
|
461
|
+
min_y = max(0, min(p[1] for p in points))
|
462
|
+
max_y = min(arr.shape[0] - 1, max(p[1] for p in points))
|
463
|
+
|
464
|
+
# Create a mask for the polygon region
|
465
|
+
mask = np.zeros((max_y - min_y + 1, max_x - min_x + 1), dtype=bool)
|
466
|
+
|
467
|
+
# Adjust points to the mask's coordinate system
|
468
|
+
adjusted_points = [(p[0] - min_x, p[1] - min_y) for p in points]
|
469
|
+
|
470
|
+
# Create a grid of coordinates and use it to test all points at once
|
471
|
+
y_indices, x_indices = np.mgrid[0:mask.shape[0], 0:mask.shape[1]]
|
472
|
+
|
473
|
+
# Test each point in the grid
|
474
|
+
for i in range(mask.shape[0]):
|
475
|
+
for j in range(mask.shape[1]):
|
476
|
+
mask[i, j] = Drawable.point_inside(j, i, adjusted_points)
|
477
|
+
|
478
|
+
# Apply the fill color to the masked region
|
479
|
+
arr[min_y:max_y+1, min_x:max_x+1][mask] = fill_color
|
480
|
+
|
420
481
|
return arr
|
421
482
|
|
422
483
|
@staticmethod
|
423
484
|
async def zones(layers: NumpyArray, coordinates, color: Color) -> NumpyArray:
|
424
485
|
"""
|
425
486
|
Draw the zones on the input layer with color blending.
|
487
|
+
Optimized with NumPy vectorized operations for better performance.
|
426
488
|
"""
|
427
|
-
|
428
489
|
dot_radius = 1 # Number of pixels for the dot
|
429
490
|
dot_spacing = 4 # Space between dots
|
491
|
+
|
430
492
|
for zone in coordinates:
|
431
493
|
points = zone["points"]
|
432
|
-
min_x = min(points[::2])
|
433
|
-
max_x = max(points[::2])
|
434
|
-
min_y = min(points[1::2])
|
435
|
-
max_y = max(points[1::2])
|
494
|
+
min_x = max(0, min(points[::2]))
|
495
|
+
max_x = min(layers.shape[1] - 1, max(points[::2]))
|
496
|
+
min_y = max(0, min(points[1::2]))
|
497
|
+
max_y = min(layers.shape[0] - 1, max(points[1::2]))
|
498
|
+
|
499
|
+
# Skip if zone is outside the image
|
500
|
+
if min_x >= max_x or min_y >= max_y:
|
501
|
+
continue
|
436
502
|
|
437
503
|
# Sample a point from the zone to get the background color
|
438
504
|
# Use the center of the zone for sampling
|
@@ -447,12 +513,28 @@ class Drawable:
|
|
447
513
|
else:
|
448
514
|
blended_color = color
|
449
515
|
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
516
|
+
# Create a grid of dot centers
|
517
|
+
x_centers = np.arange(min_x, max_x, dot_spacing)
|
518
|
+
y_centers = np.arange(min_y, max_y, dot_spacing)
|
519
|
+
|
520
|
+
# Draw dots at each grid point
|
521
|
+
for y in y_centers:
|
522
|
+
for x in x_centers:
|
523
|
+
# Create a small mask for the dot
|
524
|
+
y_min = max(0, y - dot_radius)
|
525
|
+
y_max = min(layers.shape[0], y + dot_radius + 1)
|
526
|
+
x_min = max(0, x - dot_radius)
|
527
|
+
x_max = min(layers.shape[1], x + dot_radius + 1)
|
528
|
+
|
529
|
+
# Create coordinate arrays for the dot
|
530
|
+
y_indices, x_indices = np.ogrid[y_min:y_max, x_min:x_max]
|
531
|
+
|
532
|
+
# Create a circular mask
|
533
|
+
mask = (y_indices - y)**2 + (x_indices - x)**2 <= dot_radius**2
|
534
|
+
|
535
|
+
# Apply the color to the masked region
|
536
|
+
layers[y_min:y_max, x_min:x_max][mask] = blended_color
|
537
|
+
|
456
538
|
return layers
|
457
539
|
|
458
540
|
@staticmethod
|
@@ -466,27 +548,56 @@ class Drawable:
|
|
466
548
|
) -> NumpyArray:
|
467
549
|
"""
|
468
550
|
Draw the robot on a smaller array to reduce memory cost.
|
551
|
+
Optimized with NumPy vectorized operations for better performance.
|
469
552
|
"""
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
553
|
+
# Ensure coordinates are within bounds
|
554
|
+
height, width = layers.shape[:2]
|
555
|
+
if not (0 <= x < width and 0 <= y < height):
|
556
|
+
return layers
|
557
|
+
|
558
|
+
# Calculate the bounding box for the robot
|
476
559
|
radius = 25
|
560
|
+
box_size = radius * 2 + 2 # Add a small margin
|
561
|
+
|
562
|
+
# Calculate the region to draw on
|
563
|
+
top_left_x = max(0, x - radius - 1)
|
564
|
+
top_left_y = max(0, y - radius - 1)
|
565
|
+
bottom_right_x = min(width, x + radius + 1)
|
566
|
+
bottom_right_y = min(height, y + radius + 1)
|
567
|
+
|
568
|
+
# Skip if the robot is completely outside the image
|
569
|
+
if top_left_x >= bottom_right_x or top_left_y >= bottom_right_y:
|
570
|
+
return layers
|
571
|
+
|
572
|
+
# Create a temporary layer for the robot
|
573
|
+
tmp_width = bottom_right_x - top_left_x
|
574
|
+
tmp_height = bottom_right_y - top_left_y
|
575
|
+
tmp_layer = layers[top_left_y:bottom_right_y, top_left_x:bottom_right_x].copy()
|
576
|
+
|
577
|
+
# Calculate the robot center in the temporary layer
|
578
|
+
tmp_x = x - top_left_x
|
579
|
+
tmp_y = y - top_left_y
|
580
|
+
|
581
|
+
# Calculate robot parameters
|
477
582
|
r_scaled = radius // 11
|
478
583
|
r_cover = r_scaled * 12
|
479
584
|
lidar_angle = np.deg2rad(angle + 90)
|
480
585
|
r_lidar = r_scaled * 3
|
481
586
|
r_button = r_scaled * 1
|
587
|
+
|
588
|
+
# Set colors based on robot state
|
482
589
|
if robot_state == "error":
|
483
590
|
outline = Drawable.ERROR_OUTLINE
|
484
591
|
fill = Drawable.ERROR_COLOR
|
485
592
|
else:
|
486
593
|
outline = (fill[0] // 2, fill[1] // 2, fill[2] // 2, fill[3])
|
594
|
+
|
595
|
+
# Draw the main robot body
|
487
596
|
tmp_layer = Drawable._filled_circle(
|
488
|
-
tmp_layer, (
|
597
|
+
tmp_layer, (tmp_y, tmp_x), radius, fill, outline, 1
|
489
598
|
)
|
599
|
+
|
600
|
+
# Draw the robot direction indicator
|
490
601
|
angle -= 90
|
491
602
|
a1 = ((angle + 90) - 80) / 180 * math.pi
|
492
603
|
a2 = ((angle + 90) + 80) / 180 * math.pi
|
@@ -494,18 +605,31 @@ class Drawable:
|
|
494
605
|
y1 = int(tmp_y + r_cover * math.cos(a1))
|
495
606
|
x2 = int(tmp_x - r_cover * math.sin(a2))
|
496
607
|
y2 = int(tmp_y + r_cover * math.cos(a2))
|
497
|
-
|
608
|
+
|
609
|
+
# Draw the direction line
|
610
|
+
if (0 <= x1 < tmp_width and 0 <= y1 < tmp_height and
|
611
|
+
0 <= x2 < tmp_width and 0 <= y2 < tmp_height):
|
612
|
+
tmp_layer = Drawable._line(tmp_layer, x1, y1, x2, y2, outline, width=1)
|
613
|
+
|
614
|
+
# Draw the lidar indicator
|
498
615
|
lidar_x = int(tmp_x + 15 * np.cos(lidar_angle))
|
499
616
|
lidar_y = int(tmp_y + 15 * np.sin(lidar_angle))
|
500
|
-
|
501
|
-
tmp_layer
|
502
|
-
|
617
|
+
if 0 <= lidar_x < tmp_width and 0 <= lidar_y < tmp_height:
|
618
|
+
tmp_layer = Drawable._filled_circle(
|
619
|
+
tmp_layer, (lidar_y, lidar_x), r_lidar, outline
|
620
|
+
)
|
621
|
+
|
622
|
+
# Draw the button indicator
|
503
623
|
butt_x = int(tmp_x - 20 * np.cos(lidar_angle))
|
504
624
|
butt_y = int(tmp_y - 20 * np.sin(lidar_angle))
|
505
|
-
|
506
|
-
tmp_layer
|
507
|
-
|
508
|
-
|
625
|
+
if 0 <= butt_x < tmp_width and 0 <= butt_y < tmp_height:
|
626
|
+
tmp_layer = Drawable._filled_circle(
|
627
|
+
tmp_layer, (butt_y, butt_x), r_button, outline
|
628
|
+
)
|
629
|
+
|
630
|
+
# Copy the robot layer back to the main layer
|
631
|
+
layers[top_left_y:bottom_right_y, top_left_x:bottom_right_x] = tmp_layer
|
632
|
+
|
509
633
|
return layers
|
510
634
|
|
511
635
|
@staticmethod
|
@@ -545,24 +669,193 @@ class Drawable:
|
|
545
669
|
image[mask] = color
|
546
670
|
return image
|
547
671
|
|
672
|
+
@staticmethod
|
673
|
+
def batch_draw_elements(
|
674
|
+
image: np.ndarray,
|
675
|
+
elements: list,
|
676
|
+
element_type: str,
|
677
|
+
color: Color,
|
678
|
+
) -> np.ndarray:
|
679
|
+
"""
|
680
|
+
Efficiently draw multiple elements of the same type at once.
|
681
|
+
|
682
|
+
Args:
|
683
|
+
image: The image array to draw on
|
684
|
+
elements: List of element data (coordinates, etc.)
|
685
|
+
element_type: Type of element to draw ('circle', 'line', etc.)
|
686
|
+
color: Color to use for drawing
|
687
|
+
|
688
|
+
Returns:
|
689
|
+
Modified image array
|
690
|
+
"""
|
691
|
+
if not elements or len(elements) == 0:
|
692
|
+
return image
|
693
|
+
|
694
|
+
# Get image dimensions
|
695
|
+
height, width = image.shape[:2]
|
696
|
+
|
697
|
+
if element_type == 'circle':
|
698
|
+
# Extract circle centers and radii
|
699
|
+
centers = []
|
700
|
+
radii = []
|
701
|
+
for elem in elements:
|
702
|
+
if isinstance(elem, dict) and 'center' in elem and 'radius' in elem:
|
703
|
+
centers.append(elem['center'])
|
704
|
+
radii.append(elem['radius'])
|
705
|
+
elif isinstance(elem, (list, tuple)) and len(elem) >= 3:
|
706
|
+
# Format: (x, y, radius)
|
707
|
+
centers.append((elem[0], elem[1]))
|
708
|
+
radii.append(elem[2])
|
709
|
+
|
710
|
+
# Process circles with the same radius together
|
711
|
+
for radius in set(radii):
|
712
|
+
same_radius_centers = [centers[i] for i in range(len(centers)) if radii[i] == radius]
|
713
|
+
if same_radius_centers:
|
714
|
+
# Create a combined mask for all circles with this radius
|
715
|
+
mask = np.zeros((height, width), dtype=bool)
|
716
|
+
for cx, cy in same_radius_centers:
|
717
|
+
if 0 <= cx < width and 0 <= cy < height:
|
718
|
+
# Calculate circle bounds
|
719
|
+
min_y = max(0, cy - radius)
|
720
|
+
max_y = min(height, cy + radius + 1)
|
721
|
+
min_x = max(0, cx - radius)
|
722
|
+
max_x = min(width, cx + radius + 1)
|
723
|
+
|
724
|
+
# Create coordinate arrays for the circle
|
725
|
+
y_indices, x_indices = np.ogrid[min_y:max_y, min_x:max_x]
|
726
|
+
|
727
|
+
# Add this circle to the mask
|
728
|
+
circle_mask = (y_indices - cy)**2 + (x_indices - cx)**2 <= radius**2
|
729
|
+
mask[min_y:max_y, min_x:max_x] |= circle_mask
|
730
|
+
|
731
|
+
# Apply color to all circles at once
|
732
|
+
image[mask] = color
|
733
|
+
|
734
|
+
elif element_type == 'line':
|
735
|
+
# Extract line endpoints
|
736
|
+
lines = []
|
737
|
+
widths = []
|
738
|
+
for elem in elements:
|
739
|
+
if isinstance(elem, dict) and 'start' in elem and 'end' in elem:
|
740
|
+
lines.append((elem['start'], elem['end']))
|
741
|
+
widths.append(elem.get('width', 1))
|
742
|
+
elif isinstance(elem, (list, tuple)) and len(elem) >= 4:
|
743
|
+
# Format: (x1, y1, x2, y2, [width])
|
744
|
+
lines.append(((elem[0], elem[1]), (elem[2], elem[3])))
|
745
|
+
widths.append(elem[4] if len(elem) > 4 else 1)
|
746
|
+
|
747
|
+
# Process lines with the same width together
|
748
|
+
for width in set(widths):
|
749
|
+
same_width_lines = [lines[i] for i in range(len(lines)) if widths[i] == width]
|
750
|
+
if same_width_lines:
|
751
|
+
# Create a combined mask for all lines with this width
|
752
|
+
mask = np.zeros((height, width), dtype=bool)
|
753
|
+
|
754
|
+
# Draw all lines into the mask
|
755
|
+
for (start, end) in same_width_lines:
|
756
|
+
x1, y1 = start
|
757
|
+
x2, y2 = end
|
758
|
+
|
759
|
+
# Skip invalid lines
|
760
|
+
if not (0 <= x1 < width and 0 <= y1 < height and
|
761
|
+
0 <= x2 < width and 0 <= y2 < height):
|
762
|
+
continue
|
763
|
+
|
764
|
+
# Use Bresenham's algorithm to get line points
|
765
|
+
length = max(abs(x2 - x1), abs(y2 - y1))
|
766
|
+
if length == 0:
|
767
|
+
continue
|
768
|
+
|
769
|
+
t = np.linspace(0, 1, length * 2)
|
770
|
+
x_coords = np.round(x1 * (1 - t) + x2 * t).astype(int)
|
771
|
+
y_coords = np.round(y1 * (1 - t) + y2 * t).astype(int)
|
772
|
+
|
773
|
+
# Add line points to mask
|
774
|
+
for x, y in zip(x_coords, y_coords):
|
775
|
+
if width == 1:
|
776
|
+
mask[y, x] = True
|
777
|
+
else:
|
778
|
+
# For thicker lines
|
779
|
+
half_width = width // 2
|
780
|
+
min_y = max(0, y - half_width)
|
781
|
+
max_y = min(height, y + half_width + 1)
|
782
|
+
min_x = max(0, x - half_width)
|
783
|
+
max_x = min(width, x + half_width + 1)
|
784
|
+
|
785
|
+
# Create a circular brush
|
786
|
+
y_indices, x_indices = np.ogrid[min_y:max_y, min_x:max_x]
|
787
|
+
brush = (y_indices - y)**2 + (x_indices - x)**2 <= half_width**2
|
788
|
+
mask[min_y:max_y, min_x:max_x] |= brush
|
789
|
+
|
790
|
+
# Apply color to all lines at once
|
791
|
+
image[mask] = color
|
792
|
+
|
793
|
+
return image
|
794
|
+
|
548
795
|
@staticmethod
|
549
796
|
async def async_draw_obstacles(
|
550
797
|
image: np.ndarray, obstacle_info_list, color: Color
|
551
798
|
) -> np.ndarray:
|
552
799
|
"""
|
553
|
-
Optimized async version of draw_obstacles using
|
800
|
+
Optimized async version of draw_obstacles using batch processing.
|
801
|
+
Includes color blending for better visual integration.
|
554
802
|
"""
|
803
|
+
if not obstacle_info_list:
|
804
|
+
return image
|
555
805
|
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
806
|
+
# Extract alpha from color
|
807
|
+
alpha = color[3] if len(color) == 4 else 255
|
808
|
+
need_blending = alpha < 255
|
809
|
+
|
810
|
+
# Extract obstacle centers and prepare for batch processing
|
811
|
+
centers = []
|
812
|
+
for obs in obstacle_info_list:
|
813
|
+
try:
|
814
|
+
x = obs["points"]["x"]
|
815
|
+
y = obs["points"]["y"]
|
816
|
+
|
817
|
+
# Skip if coordinates are out of bounds
|
818
|
+
if not (0 <= x < image.shape[1] and 0 <= y < image.shape[0]):
|
819
|
+
continue
|
820
|
+
|
821
|
+
# Apply color blending if needed
|
822
|
+
obstacle_color = color
|
823
|
+
if need_blending:
|
824
|
+
obstacle_color = ColorsManagement.sample_and_blend_color(
|
825
|
+
image, x, y, color
|
826
|
+
)
|
827
|
+
|
828
|
+
# Add to centers list with radius
|
829
|
+
centers.append({
|
830
|
+
'center': (x, y),
|
831
|
+
'radius': 6,
|
832
|
+
'color': obstacle_color
|
833
|
+
})
|
834
|
+
except (KeyError, TypeError):
|
835
|
+
continue
|
836
|
+
|
837
|
+
# Draw each obstacle with its blended color
|
838
|
+
if centers:
|
839
|
+
for obstacle in centers:
|
840
|
+
cx, cy = obstacle['center']
|
841
|
+
radius = obstacle['radius']
|
842
|
+
obs_color = obstacle['color']
|
843
|
+
|
844
|
+
# Create a small mask for the obstacle
|
845
|
+
min_y = max(0, cy - radius)
|
846
|
+
max_y = min(image.shape[0], cy + radius + 1)
|
847
|
+
min_x = max(0, cx - radius)
|
848
|
+
max_x = min(image.shape[1], cx + radius + 1)
|
849
|
+
|
850
|
+
# Create coordinate arrays for the circle
|
851
|
+
y_indices, x_indices = np.ogrid[min_y:max_y, min_x:max_x]
|
852
|
+
|
853
|
+
# Create a circular mask
|
854
|
+
mask = (y_indices - cy)**2 + (x_indices - cx)**2 <= radius**2
|
855
|
+
|
856
|
+
# Apply the color to the masked region
|
857
|
+
image[min_y:max_y, min_x:max_x][mask] = obs_color
|
561
858
|
|
562
|
-
centers = await asyncio.get_running_loop().run_in_executor(
|
563
|
-
None, extract_centers, obstacle_info_list
|
564
|
-
)
|
565
|
-
Drawable.draw_filled_circle(image, centers, 6, color)
|
566
859
|
return image
|
567
860
|
|
568
861
|
@staticmethod
|
@@ -597,60 +890,3 @@ class Drawable:
|
|
597
890
|
else:
|
598
891
|
draw.text((x, y), text, font=font, fill=color)
|
599
892
|
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)
|
@@ -1,8 +1,9 @@
|
|
1
1
|
valetudo_map_parser/__init__.py,sha256=SOxmq7LkS7eMa2N4atW7ZBbqhGEL7fpj6MsyXZpCMsk,958
|
2
2
|
valetudo_map_parser/config/__init__.py,sha256=DQ9plV3ZF_K25Dp5ZQHPDoG-40dQoJNdNi-dfNeR3Zc,48
|
3
3
|
valetudo_map_parser/config/auto_crop.py,sha256=6OvRsWzXMXBaSEvgwpaaisNdozDKiDyTmPjknFxoUMc,12624
|
4
|
+
valetudo_map_parser/config/color_utils.py,sha256=pJ9Frx5aZ1W2XPJxNToBLIwSYNTIm4Tw_NMMfFrZSaM,1691
|
4
5
|
valetudo_map_parser/config/colors.py,sha256=zF-6CGe6XA9wtnrWY8hBmqsMNOcL1x5tZY1G6evniQ0,30278
|
5
|
-
valetudo_map_parser/config/drawable.py,sha256=
|
6
|
+
valetudo_map_parser/config/drawable.py,sha256=9-7FBlzWDfr7d_yIeRWXlAxlRxRfKflxi4fTnC3hqjk,33785
|
6
7
|
valetudo_map_parser/config/drawable_elements.py,sha256=Ulfgf8B4LuLCfx-FfmC7LrP8o9ll_Sncg9mR774_3KE,43140
|
7
8
|
valetudo_map_parser/config/enhanced_drawable.py,sha256=xNgFUNccstP245VgLFEA9gjB3-VvlSAJSjRgSZ3YFL0,16641
|
8
9
|
valetudo_map_parser/config/optimized_element_map.py,sha256=52BCnkvVv9bre52LeVIfT8nhnEIpc0TuWTv1xcNu0Rk,15744
|
@@ -18,9 +19,8 @@ valetudo_map_parser/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,
|
|
18
19
|
valetudo_map_parser/rand25_handler.py,sha256=F9o1J6JZRV3CZTS4CG3AHNHZweKRM0nzd4HLmdPZe4w,23617
|
19
20
|
valetudo_map_parser/reimg_draw.py,sha256=1q8LkNTPHEA9Tsapc_JnVw51kpPYNhaBU-KmHkefCQY,12507
|
20
21
|
valetudo_map_parser/utils/__init__.py,sha256=r-GKKSPqBkMDd2K-vWe7kAix8OBrGN5HXC1RS2tbDwo,130
|
21
|
-
valetudo_map_parser/
|
22
|
-
valetudo_map_parser-0.1.
|
23
|
-
valetudo_map_parser-0.1.
|
24
|
-
valetudo_map_parser-0.1.
|
25
|
-
valetudo_map_parser-0.1.
|
26
|
-
valetudo_map_parser-0.1.9b47.dist-info/RECORD,,
|
22
|
+
valetudo_map_parser-0.1.9b48.dist-info/LICENSE,sha256=Lh-qBbuRV0-jiCIBhfV7NgdwFxQFOXH3BKOzK865hRs,10480
|
23
|
+
valetudo_map_parser-0.1.9b48.dist-info/METADATA,sha256=5lDbj_xHkH3jIyKf1GKrXLLMVUXLRLuOavw04HkqvMs,3321
|
24
|
+
valetudo_map_parser-0.1.9b48.dist-info/NOTICE.txt,sha256=5lTOuWiU9aiEnJ2go8sc7lTJ7ntMBx0g0GFnNrswCY4,2533
|
25
|
+
valetudo_map_parser-0.1.9b48.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
26
|
+
valetudo_map_parser-0.1.9b48.dist-info/RECORD,,
|
@@ -1,62 +0,0 @@
|
|
1
|
-
"""Utility functions for color operations in the map parser."""
|
2
|
-
|
3
|
-
from typing import Tuple, Optional
|
4
|
-
|
5
|
-
from ..config.colors import ColorsManagment
|
6
|
-
from ..config.drawable_elements import ElementMapGenerator, DrawableElement
|
7
|
-
|
8
|
-
|
9
|
-
def get_blended_color(
|
10
|
-
element_map_generator: ElementMapGenerator,
|
11
|
-
colors_manager: ColorsManagment,
|
12
|
-
x: int,
|
13
|
-
y: int,
|
14
|
-
new_element: DrawableElement,
|
15
|
-
new_color: Tuple[int, int, int, int],
|
16
|
-
) -> Tuple[int, int, int, int]:
|
17
|
-
"""
|
18
|
-
Get a blended color for a pixel based on the current element map and the new element to draw.
|
19
|
-
|
20
|
-
This function:
|
21
|
-
1. Gets the current element at position (x,y) from the element map
|
22
|
-
2. Gets the color for that element from the colors manager
|
23
|
-
3. Blends the new color with the existing color based on alpha values
|
24
|
-
|
25
|
-
Args:
|
26
|
-
element_map_generator: The element map generator containing the current element map
|
27
|
-
colors_manager: The colors manager to get colors for elements
|
28
|
-
x: X coordinate in the element map
|
29
|
-
y: Y coordinate in the element map
|
30
|
-
new_element: The new element to draw at this position
|
31
|
-
new_color: The RGBA color of the new element
|
32
|
-
|
33
|
-
Returns:
|
34
|
-
Blended RGBA color to use for drawing
|
35
|
-
"""
|
36
|
-
# Get current element at this position
|
37
|
-
current_element = element_map_generator.get_element_at_position(x, y)
|
38
|
-
|
39
|
-
# If no current element or it's the same as the new element, just return the new color
|
40
|
-
if current_element is None or current_element == new_element:
|
41
|
-
return new_color
|
42
|
-
|
43
|
-
# Get color for the current element
|
44
|
-
current_color = None
|
45
|
-
|
46
|
-
# Handle different element types
|
47
|
-
if current_element == DrawableElement.FLOOR:
|
48
|
-
# Floor is the background color
|
49
|
-
current_color = colors_manager.get_colour("color_background")
|
50
|
-
elif current_element == DrawableElement.WALL:
|
51
|
-
# Wall color
|
52
|
-
current_color = colors_manager.get_colour("color_wall")
|
53
|
-
elif DrawableElement.ROOM_1 <= current_element <= DrawableElement.ROOM_15:
|
54
|
-
# Room colors (ROOM_1 = 16, ROOM_2 = 17, etc.)
|
55
|
-
room_index = current_element - DrawableElement.ROOM_1
|
56
|
-
current_color = colors_manager.get_colour(f"color_room_{room_index}")
|
57
|
-
else:
|
58
|
-
# Default for unknown elements
|
59
|
-
current_color = (100, 100, 100, 255)
|
60
|
-
|
61
|
-
# Blend the colors
|
62
|
-
return colors_manager.blend_colors(current_color, new_color)
|
File without changes
|
{valetudo_map_parser-0.1.9b47.dist-info → valetudo_map_parser-0.1.9b48.dist-info}/NOTICE.txt
RENAMED
File without changes
|