diff --git a/SCR/valetudo_map_parser/config/colors.py b/SCR/valetudo_map_parser/config/colors.py index 904da4d..f37fd46 100644 --- a/SCR/valetudo_map_parser/config/colors.py +++ b/SCR/valetudo_map_parser/config/colors.py @@ -12,6 +12,8 @@ ALPHA_CHARGER, ALPHA_CARPET, ALPHA_GO_TO, + ALPHA_MATERIAL_TILE, + ALPHA_MATERIAL_WOOD, ALPHA_MOVE, ALPHA_NO_GO, ALPHA_ROBOT, @@ -38,6 +40,8 @@ COLOR_CHARGER, COLOR_CARPET, COLOR_GO_TO, + COLOR_MATERIAL_TILE, + COLOR_MATERIAL_WOOD, COLOR_MOVE, COLOR_NO_GO, COLOR_ROBOT, @@ -77,6 +81,8 @@ color_text = (255, 255, 255, 255) color_grey = (125, 125, 125, 255) color_black = (0, 0, 0, 255) +color_material_wood = (40, 40, 40, 38) +color_material_tile = (40, 40, 40, 45) color_room_0 = (135, 206, 250, 255) color_room_1 = (176, 226, 255, 255) color_room_2 = (164, 211, 238, 255) @@ -114,15 +120,18 @@ ] base_colors_array = [ - color_wall, - color_zone_clean, - color_robot, - color_background, - color_move, - color_charger, - color_no_go, - color_go_to, - color_text, + color_wall, # [0] + color_zone_clean, # [1] + color_robot, # [2] + color_background, # [3] + color_move, # [4] + color_charger, # [5] + color_no_go, # [6] + color_go_to, # [7] + color_text, # [8] + color_carpet, # [9] + color_material_wood, # [10] + color_material_tile, # [11] ] color_array = [ @@ -153,6 +162,9 @@ class SupportedColor(StrEnum): NO_GO = "color_no_go" ZONE_CLEAN = "color_zone_clean" CARPET = "color_carpet" + OBSTACLE = "color_obstacle" + TILE = "color_material_tile" + WOOD = "color_material_wood" MAP_BACKGROUND = "color_background" TEXT = "color_text" TRANSPARENT = "color_transparent" @@ -175,7 +187,10 @@ class DefaultColors: SupportedColor.GO_TO: (0, 255, 0), SupportedColor.NO_GO: (255, 0, 0), SupportedColor.ZONE_CLEAN: (255, 255, 255), - SupportedColor.CARPET: (67, 103, 125), # 50% of room_0 default color (135, 206, 250) + SupportedColor.CARPET: (67, 103, 125), + SupportedColor.OBSTACLE: (255, 0, 0), + SupportedColor.TILE: (40, 40, 40), + SupportedColor.WOOD: (40, 40, 40), SupportedColor.MAP_BACKGROUND: (0, 125, 255), SupportedColor.TEXT: (0, 0, 0), SupportedColor.TRANSPARENT: (0, 0, 0), @@ -310,6 +325,8 @@ def set_initial_colours(self, device_info: dict) -> None: (COLOR_NO_GO, color_no_go, ALPHA_NO_GO), (COLOR_GO_TO, color_go_to, ALPHA_GO_TO), (COLOR_TEXT, color_text, ALPHA_TEXT), + (COLOR_MATERIAL_WOOD, color_material_wood, ALPHA_MATERIAL_WOOD), + (COLOR_MATERIAL_TILE, color_material_tile, ALPHA_MATERIAL_TILE), ] room_color_keys = [ diff --git a/SCR/valetudo_map_parser/config/drawable_elements.py b/SCR/valetudo_map_parser/config/drawable_elements.py index 8982654..dd7cea9 100644 --- a/SCR/valetudo_map_parser/config/drawable_elements.py +++ b/SCR/valetudo_map_parser/config/drawable_elements.py @@ -34,6 +34,7 @@ class DrawableElement(IntEnum): PREDICTED_PATH = 10 GO_TO_TARGET = 11 CARPET = 12 + MATERIAL_OVERLAY = 13 # Rooms (101-115 for up to 15 rooms) ROOM_1 = 101 @@ -98,6 +99,15 @@ def _set_default_properties(self): DrawableElement.CARPET: SupportedColor.CARPET, } + # Set default properties for material overlay + self._element_properties[DrawableElement.MATERIAL_OVERLAY] = { + "wood_color": (40, 40, 40), # RGB for wood lines + "wood_alpha": 38, # Alpha for wood lines + "tile_color": (40, 40, 40), # RGB for tile lines + "tile_alpha": 45, # Alpha for tile lines + "z_index": 11, # Draw materials above rooms but below walls + } + # Set z-index for each element type z_indices = { DrawableElement.FLOOR: 0, @@ -219,6 +229,32 @@ def update_from_device_info(self, device_info: dict) -> None: DrawableElement.CARPET: SupportedColor.CARPET, } + # Update material overlay properties if present + if "color_material_wood" in device_info: + self.set_property( + DrawableElement.MATERIAL_OVERLAY, + "wood_color", + device_info["color_material_wood"], + ) + if "alpha_material_wood" in device_info: + self.set_property( + DrawableElement.MATERIAL_OVERLAY, + "wood_alpha", + device_info["alpha_material_wood"], + ) + if "color_material_tile" in device_info: + self.set_property( + DrawableElement.MATERIAL_OVERLAY, + "tile_color", + device_info["color_material_tile"], + ) + if "alpha_material_tile" in device_info: + self.set_property( + DrawableElement.MATERIAL_OVERLAY, + "tile_alpha", + device_info["alpha_material_tile"], + ) + # Update room colors from device info for room_id in range(1, 16): room_element = getattr(DrawableElement, f"ROOM_{room_id}") @@ -274,6 +310,7 @@ def update_from_device_info(self, device_info: dict) -> None: "disable_path": DrawableElement.PATH, "disable_predicted_path": DrawableElement.PREDICTED_PATH, "disable_go_to_target": DrawableElement.GO_TO_TARGET, + "disable_material_overlay": DrawableElement.MATERIAL_OVERLAY, } # Process base element disable flags diff --git a/SCR/valetudo_map_parser/config/material.py b/SCR/valetudo_map_parser/config/material.py new file mode 100644 index 0000000..1f10f7d --- /dev/null +++ b/SCR/valetudo_map_parser/config/material.py @@ -0,0 +1,223 @@ +from __future__ import annotations + +from dataclasses import dataclass +from functools import lru_cache +from typing import Final, Optional + +import numpy as np +from mvcrender.draw import line_u8 + +from .colors import color_material_tile, color_material_wood +from .types import Color, NumpyArray + + +@dataclass(frozen=True, slots=True) +class _MaterialSpec: + cells: int + kind: str # "wood_h", "wood_v", "tile" + + +@dataclass(frozen=True, slots=True) +class MaterialColors: + """Material colors for rendering.""" + + wood_rgba: Color = color_material_wood + tile_rgba: Color = color_material_tile + + +# Create a singleton instance for easy access +_material_colors = MaterialColors() + + +class MaterialTileRenderer: + """ + Material patterns rendered as small RGBA tiles. + + Wood is drawn as staggered rectangular planks (brick-like) with ONLY thin seams + (no extra inner grain line). + """ + + _SPECS: Final[dict[str, _MaterialSpec]] = { + "wood_horizontal": _MaterialSpec(cells=36, kind="wood_h"), + "wood_vertical": _MaterialSpec(cells=36, kind="wood_v"), + "tile": _MaterialSpec(cells=4, kind="tile"), + } + + @staticmethod + def _empty_rgba(h: int, w: int) -> NumpyArray: + return np.zeros((h, w, 4), dtype=np.uint8) + + @staticmethod + def _thin_px(pixel_size: int) -> int: + """Thin seam thickness in pixels (for pixel_size 5/7 -> 1 px).""" + return 1 if pixel_size <= 7 else 2 + + @staticmethod + def _draw_rect_outline( + tile: NumpyArray, + x0: int, + y0: int, + x1: int, + y1: int, + thickness: int, + rgba: Color, + ) -> None: + """Draw rectangle outline using mvcrender.line_u8.""" + if x1 <= x0 or y1 <= y0: + return + + # Draw four lines to form rectangle outline + # Top line + line_u8(tile, x0, y0, x1 - 1, y0, rgba, thickness) + # Bottom line + line_u8(tile, x0, y1 - 1, x1 - 1, y1 - 1, rgba, thickness) + # Left line + line_u8(tile, x0, y0, x0, y1 - 1, rgba, thickness) + # Right line + line_u8(tile, x1 - 1, y0, x1 - 1, y1 - 1, rgba, thickness) + + @staticmethod + def _wood_planks_horizontal( + tile_px: int, pixel_size: int, color: Color + ) -> NumpyArray: + """ + Horizontal wood planks as staggered rectangles. + ONLY thin seams (no inner lines). + """ + t = MaterialTileRenderer._empty_rgba(tile_px, tile_px) + seam = MaterialTileRenderer._thin_px(pixel_size) + + # Plank size in CELLS (tweak here) + plank_h_cells = 3 + plank_w_cells = 24 # longer planks -> looks less like tiles + + plank_h = plank_h_cells * pixel_size + plank_w = plank_w_cells * pixel_size + + rows = max(1, tile_px // plank_h) + cols = max(1, (tile_px + plank_w - 1) // plank_w) + + for r in range(rows + 1): + y0 = r * plank_h + y1 = y0 + plank_h + offset = (plank_w // 2) if (r % 2 == 1) else 0 + + for c in range(cols + 1): + x0 = c * plank_w - offset + x1 = x0 + plank_w + + cx0 = max(0, x0) + cy0 = max(0, y0) + cx1 = min(tile_px, x1) + cy1 = min(tile_px, y1) + + MaterialTileRenderer._draw_rect_outline( + t, cx0, cy0, cx1, cy1, seam, color + ) + + return t + + @staticmethod + def _wood_planks_vertical( + tile_px: int, pixel_size: int, color: Color + ) -> NumpyArray: + """Vertical wood planks as staggered rectangles, ONLY thin seams.""" + t = MaterialTileRenderer._empty_rgba(tile_px, tile_px) + seam = MaterialTileRenderer._thin_px(pixel_size) + + plank_w_cells = 3 + plank_h_cells = 24 + + plank_w = plank_w_cells * pixel_size + plank_h = plank_h_cells * pixel_size + + cols = max(1, tile_px // plank_w) + rows = max(1, (tile_px + plank_h - 1) // plank_h) + + for c in range(cols + 1): + x0 = c * plank_w + x1 = x0 + plank_w + offset = (plank_h // 2) if (c % 2 == 1) else 0 + + for r in range(rows + 1): + y0 = r * plank_h - offset + y1 = y0 + plank_h + + cx0 = max(0, x0) + cy0 = max(0, y0) + cx1 = min(tile_px, x1) + cy1 = min(tile_px, y1) + + MaterialTileRenderer._draw_rect_outline( + t, cx0, cy0, cx1, cy1, seam, color + ) + + return t + + @staticmethod + def _tile_pixels(cells: int, pixel_size: int, tile_rgba: Color) -> NumpyArray: + """Draw tile grid using mvcrender.line_u8.""" + size = cells * pixel_size + t = MaterialTileRenderer._empty_rgba(size, size) + th = MaterialTileRenderer._thin_px(pixel_size) + rgba = tile_rgba + + # Draw horizontal line at top + line_u8(t, 0, 0, size - 1, 0, rgba, th) + # Draw vertical line at left + line_u8(t, 0, 0, 0, size - 1, rgba, th) + + return t + + @staticmethod + @lru_cache(maxsize=64) + def get_tile( + material: str, pixel_size: int, colors: MaterialColors = None + ) -> Optional[NumpyArray]: + spec = MaterialTileRenderer._SPECS.get(material) + if spec is None or pixel_size <= 0: + return None + + # Use provided colors or fall back to defaults + if colors is None: + colors = _material_colors + + wood_color = colors.wood_rgba + tile_color = colors.tile_rgba + + if spec.kind == "tile": + return MaterialTileRenderer._tile_pixels(spec.cells, pixel_size, tile_color) + + tile_px = spec.cells * pixel_size + if spec.kind == "wood_h": + return MaterialTileRenderer._wood_planks_horizontal( + tile_px, pixel_size, wood_color + ) + if spec.kind == "wood_v": + return MaterialTileRenderer._wood_planks_vertical( + tile_px, pixel_size, wood_color + ) + + return None + + @staticmethod + def tile_block(tile: NumpyArray, r0: int, r1: int, c0: int, c1: int) -> NumpyArray: + th, tw, _ = tile.shape + rows = (np.arange(r0, r1) % th).astype(np.intp, copy=False) + cols = (np.arange(c0, c1) % tw).astype(np.intp, copy=False) + return tile[rows[:, None], cols[None, :], :] + + @staticmethod + def apply_overlay_on_region( + image: NumpyArray, + tile: NumpyArray, + r0: int, + r1: int, + c0: int, + c1: int, + ) -> None: + region = image[r0:r1, c0:c1] + overlay = MaterialTileRenderer.tile_block(tile, r0, r1, c0, c1) + mask = overlay[..., 3] > 0 + if np.any(mask): + region[mask] = overlay[mask] diff --git a/SCR/valetudo_map_parser/config/shared.py b/SCR/valetudo_map_parser/config/shared.py index b106bb2..aa62f07 100755 --- a/SCR/valetudo_map_parser/config/shared.py +++ b/SCR/valetudo_map_parser/config/shared.py @@ -312,11 +312,15 @@ def update_shared_data(self, device_info): ) # Check for new floors_data first floors_data = device_info.get("floors_data", None) - current_floor = device_info.get("current_floor", "floor_0") # Default fallback + current_floor = device_info.get( + "current_floor", "floor_0" + ) # Default fallback if floors_data: # NEW: Use floors_data - floor_trims = floors_data.get(current_floor, DEFAULT_VALUES["trims_data"]) + floor_trims = floors_data.get( + current_floor, DEFAULT_VALUES["trims_data"] + ) instance.trims = TrimsData.from_dict(floor_trims) instance.current_floor = current_floor else: diff --git a/SCR/valetudo_map_parser/config/types.py b/SCR/valetudo_map_parser/config/types.py index 1501a66..72f7456 100644 --- a/SCR/valetudo_map_parser/config/types.py +++ b/SCR/valetudo_map_parser/config/types.py @@ -63,7 +63,7 @@ class RoomProperty(TypedDict): @dataclass class TrimCropData: """Dataclass for trim and crop data.""" - + floor: str trim_left: int trim_up: int diff --git a/SCR/valetudo_map_parser/const.py b/SCR/valetudo_map_parser/const.py index 6c6508d..a6514d1 100644 --- a/SCR/valetudo_map_parser/const.py +++ b/SCR/valetudo_map_parser/const.py @@ -85,7 +85,13 @@ "vac_status_position": True, "get_svg_file": False, "save_trims": True, - "trims_data": {"floor": "floor_0", "trim_left": 0, "trim_up": 0, "trim_right": 0, "trim_down": 0}, + "trims_data": { + "floor": "floor_0", + "trim_left": 0, + "trim_up": 0, + "trim_right": 0, + "trim_down": 0, + }, "enable_www_snapshots": False, "color_charger": [255, 128, 0], "color_move": [238, 247, 255], @@ -97,6 +103,8 @@ "color_carpet": [67, 103, 125], "color_background": [0, 125, 255], "color_text": [255, 255, 255], + "color_material_wood": [40, 40, 40], + "color_material_tile": [40, 40, 40], "alpha_charger": 255.0, "alpha_move": 255.0, "alpha_wall": 255.0, @@ -107,6 +115,8 @@ "alpha_carpet": 255.0, "alpha_background": 255.0, "alpha_text": 255.0, + "alpha_material_wood": 38.0, + "alpha_material_tile": 45.0, "color_room_0": [135, 206, 250], "color_room_1": [176, 226, 255], "color_room_2": [165, 105, 18], @@ -235,6 +245,8 @@ COLOR_CHARGER = "color_charger" COLOR_CARPET = "color_carpet" COLOR_MOVE = "color_move" +COLOR_MATERIAL_WOOD = "color_material_wood" +COLOR_MATERIAL_TILE = "color_material_tile" COLOR_ROBOT = "color_robot" COLOR_NO_GO = "color_no_go" COLOR_GO_TO = "color_go_to" @@ -269,6 +281,8 @@ ALPHA_NO_GO = "alpha_no_go" ALPHA_GO_TO = "alpha_go_to" ALPHA_BACKGROUND = "alpha_background" +ALPHA_MATERIAL_WOOD = "alpha_material_wood" +ALPHA_MATERIAL_TILE = "alpha_material_tile" ALPHA_ZONE_CLEAN = "alpha_zone_clean" ALPHA_WALL = "alpha_wall" ALPHA_TEXT = "alpha_text" diff --git a/SCR/valetudo_map_parser/hypfer_draw.py b/SCR/valetudo_map_parser/hypfer_draw.py index fcba079..18f7562 100755 --- a/SCR/valetudo_map_parser/hypfer_draw.py +++ b/SCR/valetudo_map_parser/hypfer_draw.py @@ -9,6 +9,7 @@ import logging from .config.drawable_elements import DrawableElement +from .config.material import MaterialColors, MaterialTileRenderer from .config.types import Color, JsonType, NumpyArray, RobotPosition, RoomStore from .config.utils import point_in_polygon @@ -117,6 +118,32 @@ async def _process_room_layer( img_np_array, pixels, pixel_size, room_color ) + # Apply material overlay if present for this segment and enabled + if ( + layer_type == "segment" + and hasattr(self.img_h, "json_data") + and self.img_h.drawing_config.is_enabled( + DrawableElement.MATERIAL_OVERLAY + ) + ): + segment_id = str(room_id + 1) + materials = getattr(self.img_h.json_data, "materials", {}) + material = materials.get(segment_id) + if material and material != "generic": + # Get material colors from shared.user_colors + # Index 10 = wood, Index 11 = tile + material_colors = MaterialColors( + wood_rgba=self.img_h.shared.user_colors[10], + tile_rgba=self.img_h.shared.user_colors[11] + ) + img_np_array = self._apply_material_overlay( + img_np_array, + pixels, + pixel_size, + material, + material_colors, + ) + # Increment room_id only for segment layers, not for floor layers if layer_type == "segment": room_id = (room_id + 1) % 16 # Cycle room_id back to 0 after 15 @@ -126,6 +153,39 @@ async def _process_room_layer( return img_np_array, room_id + def _apply_material_overlay( + self, img_np_array, pixels, pixel_size, material, material_colors + ): + """Apply material texture overlay to a room segment.""" + try: + tile = MaterialTileRenderer.get_tile( + material, pixel_size, material_colors + ) + if tile is None: + return img_np_array + + if not pixels: + return img_np_array + + # Apply overlay directly to each pixel block + for x, y, count in pixels: + row = y * pixel_size + col = x * pixel_size + for i in range(count): + c_start = col + i * pixel_size + c_end = c_start + pixel_size + overlay = MaterialTileRenderer.tile_block( + tile, row, row + pixel_size, c_start, c_end + ) + region = img_np_array[row : row + pixel_size, c_start:c_end] + alpha = overlay[..., 3:4] / 255.0 + region[:] = (1 - alpha) * region + alpha * overlay + + except Exception as e: + _LOGGER.warning("%s: Material overlay error: %s", self.file_name, str(e)) + + return img_np_array + def _get_active_room_color(self, room_id, room_color, color_zone_clean): """Adjust the room color if the room is active.""" if self.img_h.active_zones and room_id < len(self.img_h.active_zones): diff --git a/SCR/valetudo_map_parser/hypfer_handler.py b/SCR/valetudo_map_parser/hypfer_handler.py index 04d9a67..3df4f76 100644 --- a/SCR/valetudo_map_parser/hypfer_handler.py +++ b/SCR/valetudo_map_parser/hypfer_handler.py @@ -231,7 +231,11 @@ async def _draw_dynamic_elements( """Draw dynamic elements like zones, paths, and go-to targets.""" if self.drawing_config.is_enabled(DrawableElement.RESTRICTED_AREA): img_np_array = await self.imd.async_draw_zones( - m_json, img_np_array, colors["zone_clean"], colors["no_go"], colors.get("carpet") + m_json, + img_np_array, + colors["zone_clean"], + colors["no_go"], + colors.get("carpet"), ) if self.drawing_config.is_enabled(DrawableElement.GO_TO_TARGET): diff --git a/SCR/valetudo_map_parser/map_data.py b/SCR/valetudo_map_parser/map_data.py index 9722482..1f6121c 100755 --- a/SCR/valetudo_map_parser/map_data.py +++ b/SCR/valetudo_map_parser/map_data.py @@ -62,6 +62,7 @@ class SegmentMeta(TypedDict, total=False): active: bool source: str area: int + material: str class MapLayerBase(TypedDict): @@ -251,7 +252,8 @@ def find_layers( json_obj: JsonType, layer_dict: dict[str, list[Any]] | None, active_list: list[int] | None, - ) -> tuple[dict[str, list[Any]], list[int]]: + materials_dict: dict[str, str] | None = None, + ) -> tuple[dict[str, list[Any]], list[int], dict[str, str]]: """ Recursively traverse a JSON-like structure to find MapLayer entries. @@ -259,15 +261,21 @@ def find_layers( json_obj: The JSON-like object (dicts/lists) to search. layer_dict: Optional mapping of layer_type to a list of compressed pixel data. active_list: Optional list of active segment flags. + materials_dict: Optional mapping of segment_id to material type. Returns: A tuple: - dict mapping layer types to their compressed pixel arrays. - list of integers marking active segment layers. + - dict mapping segment IDs to material types. """ if layer_dict is None: layer_dict = {} active_list = [] + materials_dict = {} + + if materials_dict is None: + materials_dict = {} if isinstance(json_obj, dict): if json_obj.get("__class") == "MapLayer": @@ -286,28 +294,36 @@ def find_layers( compressed_pixels = [] for i in range(0, len(pixels), 2): if i + 1 < len(pixels): - compressed_pixels.extend([pixels[i], pixels[i + 1], 1]) + compressed_pixels.extend( + [pixels[i], pixels[i + 1], 1] + ) else: compressed_pixels = [] layer_dict.setdefault(layer_type, []).append(compressed_pixels) - # Safely extract "active" flag if present and convertible to int + # Safely extract "active" flag and material if present if layer_type == "segment": try: active_list.append(int(meta_data.get("active", 0))) except (ValueError, TypeError): pass # skip invalid/missing 'active' values + # Extract material if present + segment_id = meta_data.get("segmentId") + material = meta_data.get("material") + if segment_id and material: + materials_dict[segment_id] = material + # json_obj.items() yields (key, value), so we only want the values for _, value in json_obj.items(): - ImageData.find_layers(value, layer_dict, active_list) + ImageData.find_layers(value, layer_dict, active_list, materials_dict) elif isinstance(json_obj, list): for item in json_obj: - ImageData.find_layers(item, layer_dict, active_list) + ImageData.find_layers(item, layer_dict, active_list, materials_dict) - return layer_dict, active_list + return layer_dict, active_list, materials_dict @staticmethod def find_points_entities( @@ -786,6 +802,7 @@ class HyperMapData: layers: dict[str, list[Any]] = field(default_factory=dict) active_zones: list[int] = field(default_factory=list) virtual_walls: list[list[tuple[float, float]]] = field(default_factory=list) + materials: dict[str, str] = field(default_factory=dict) @classmethod async def async_from_valetudo_json(cls, json_data: Any) -> "HyperMapData": @@ -801,14 +818,15 @@ async def async_from_valetudo_json(cls, json_data: Any) -> "HyperMapData": areas = ImageData.find_zone_entities(json_data) layers = {} active_zones = [] + materials = {} # Hypothetical obstacles finder, if you have one obstacles = getattr(ImageData, "find_obstacles_entities", lambda *_: {})( json_data ) virtual_walls = ImageData.find_virtual_walls(json_data) pixel_size = int(json_data["pixelSize"]) - layers, active_zones = ImageData.find_layers( - json_data["layers"], layers, active_zones + layers, active_zones, materials = ImageData.find_layers( + json_data["layers"], layers, active_zones, materials ) entity_dict = ImageData.find_points_entities(json_data) @@ -824,6 +842,7 @@ async def async_from_valetudo_json(cls, json_data: Any) -> "HyperMapData": pixel_size=pixel_size, layers=layers, active_zones=active_zones, + materials=materials, ) def to_dict(self) -> dict[str, Any]: @@ -847,6 +866,7 @@ def from_dict(cls, data: dict[str, Any]) -> "HyperMapData": layers=data.get("layers", {}), active_zones=data.get("active_zones", []), virtual_walls=data.get("virtual_walls", []), + materials=data.get("materials", {}), ) def update_from_dict(self, updates: dict[str, Any]) -> None: diff --git a/SCR/valetudo_map_parser/rand256_handler.py b/SCR/valetudo_map_parser/rand256_handler.py index 8a68f09..8e150e8 100644 --- a/SCR/valetudo_map_parser/rand256_handler.py +++ b/SCR/valetudo_map_parser/rand256_handler.py @@ -15,7 +15,6 @@ from .config.async_utils import AsyncPIL from .config.drawable_elements import DrawableElement -from .const import COLORS, DEFAULT_IMAGE_SIZE, DEFAULT_PIXEL_SIZE from .config.types import ( LOGGER, Colors, @@ -31,6 +30,7 @@ initialize_drawing_config, point_in_polygon, ) +from .const import COLORS, DEFAULT_IMAGE_SIZE, DEFAULT_PIXEL_SIZE from .map_data import RandImageData from .reimg_draw import ImageDraw from .rooms_handler import RandRoomsHandler @@ -543,4 +543,4 @@ def get_calibration_data(self, rotation_angle: int = 0) -> Any: calibration_point = {"vacuum": vacuum_point, "map": map_point} self.calibration_data.append(calibration_point) - return self.calibration_data \ No newline at end of file + return self.calibration_data diff --git a/pyproject.toml b/pyproject.toml index 428cf97..6122fda 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "valetudo-map-parser" -version = "0.1.16" +version = "0.1.17" description = "A Python library to parse Valetudo map data returning a PIL Image object." authors = ["Sandro Cantarella "] license = "Apache-2.0"