diff --git a/.dockerignore b/.dockerignore index a96804c1..c2eaaada 100644 --- a/.dockerignore +++ b/.dockerignore @@ -12,7 +12,6 @@ temp/ .gitignore LICENSE.md README.md -requirements.txt run.ps1 run.sh maps4fs.zip diff --git a/.github/workflows/build_docker.yml b/.github/workflows/build_docker.yml index 152f8b17..00d7996b 100644 --- a/.github/workflows/build_docker.yml +++ b/.github/workflows/build_docker.yml @@ -30,5 +30,7 @@ jobs: with: context: . push: true - tags: iwatkot/maps4fs:latest + tags: | + iwatkot/maps4fs:latest + iwatkot/maps4fs:${{ github.ref }} file: ./Dockerfile \ No newline at end of file diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index a1f7be8d..77a8ce92 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -20,7 +20,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install mypy pylint opencv-python tifffile pympler imageio "osmnx<2.0.0" "fast-simplification" geopy trimesh rasterio pandas-stubs types-requests pytest pytest-cov + pip install -r dev/requirements.txt - name: Run mypy to generate cache run: mypy maps4fs || true diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml index 7a29f6e4..02f6d0dc 100644 --- a/.github/workflows/pypi.yml +++ b/.github/workflows/pypi.yml @@ -7,17 +7,25 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 + - name: Set up Python uses: actions/setup-python@v2 with: python-version: '3.11' + - name: Install dependencies run: | python -m pip install --upgrade pip python -m pip install build twine + + - name: Update version in pyproject.toml + run: | + sed -i "s/^version = \".*\"/version = \"${{ github.ref_name }}\"/" pyproject.toml + - name: Build package run: | python -m build + - name: Publish package to PyPI uses: pypa/gh-action-pypi-publish@release/v1 with: diff --git a/Dockerfile b/Dockerfile index 24488756..366b4636 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,8 +10,10 @@ WORKDIR /usr/src/app COPY data /usr/src/app/data COPY docs /usr/src/app/docs COPY webui /usr/src/app/webui +COPY requirements.txt /usr/src/app/requirements.txt -RUN pip install "opencv-python" "pyproj" "folium" "geopy" "pympler" "streamlit-stl==0.0.2" "osmnx<2.0.0" "fast-simplification" "rasterio" "trimesh" "streamlit" "maps4fs" +# RUN pip install "opencv-python" "pyproj" "folium" "geopy" "pympler" "streamlit-stl==0.0.2" "osmnx>=2.0.0" "fast-simplification" "rasterio" "trimesh" "streamlit" "maps4fs" +RUN pip install -r requirements.txt EXPOSE 8501 diff --git a/dev/requirements.txt b/dev/requirements.txt index 2b05b17b..72762889 100644 --- a/dev/requirements.txt +++ b/dev/requirements.txt @@ -1,5 +1,5 @@ opencv-python -osmnx<2.0.0 +osmnx>=2.0.0 rasterio streamlit mypy diff --git a/maps4fs/generator/background.py b/maps4fs/generator/background.py index 613b14dd..3dc77363 100644 --- a/maps4fs/generator/background.py +++ b/maps4fs/generator/background.py @@ -15,7 +15,7 @@ DEFAULT_MULTIPLIER, DEFAULT_PLATEAU, ) -from maps4fs.generator.path_steps import DEFAULT_DISTANCE, PATH_FULL_NAME, get_steps +from maps4fs.generator.path_steps import PATH_FULL_NAME, get_steps from maps4fs.generator.tile import Tile RESIZE_FACTOR = 1 / 4 @@ -242,119 +242,21 @@ def mesh_to_stl(self, mesh: trimesh.Trimesh) -> None: self.stl_preview_path = preview_path # pylint: disable=attribute-defined-outside-init + # pylint: disable=no-member def previews(self) -> list[str]: - """Generates a preview by combining all tiles into one image. - NOTE: The map itself is not included in the preview, so it will be empty. + """Returns the path to the image of full tile and the path to the STL preview file. Returns: - list[str] -- A list of paths to the preview images.""" - - self.logger.info("Generating a preview image for the background DEM") - - image_height = self.map_height + DEFAULT_DISTANCE * 2 - image_width = self.map_width + DEFAULT_DISTANCE * 2 - self.logger.debug("Full size of the preview image: %s x %s", image_width, image_height) - - image = np.zeros((image_height, image_width), np.uint16) # pylint: disable=no-member - self.logger.debug("Empty image created: %s", image.shape) - - for tile in self.tiles: - # pylint: disable=no-member - if tile.code == PATH_FULL_NAME: - continue - tile_image = cv2.imread(tile.dem_path, cv2.IMREAD_UNCHANGED) - - self.logger.debug( - "Tile %s image shape: %s, dtype: %s, max: %s, min: %s", - tile.code, - tile_image.shape, - tile_image.dtype, - tile_image.max(), - tile_image.min(), - ) - - tile_height, tile_width = tile_image.shape - self.logger.debug("Tile %s size: %s x %s", tile.code, tile_width, tile_height) - - # Calculate the position based on the tile code - if tile.code == "N": - x = DEFAULT_DISTANCE - y = 0 - elif tile.code == "NE": - x = self.map_width + DEFAULT_DISTANCE - y = 0 - elif tile.code == "E": - x = self.map_width + DEFAULT_DISTANCE - y = DEFAULT_DISTANCE - elif tile.code == "SE": - x = self.map_width + DEFAULT_DISTANCE - y = self.map_height + DEFAULT_DISTANCE - elif tile.code == "S": - x = DEFAULT_DISTANCE - y = self.map_height + DEFAULT_DISTANCE - elif tile.code == "SW": - x = 0 - y = self.map_height + DEFAULT_DISTANCE - elif tile.code == "W": - x = 0 - y = DEFAULT_DISTANCE - elif tile.code == "NW": - x = 0 - y = 0 - - # pylint: disable=possibly-used-before-assignment - x2 = x + tile_width - y2 = y + tile_height - - self.logger.debug( - "Tile %s position. X from %s to %s, Y from %s to %s", tile.code, x, x2, y, y2 + list[str] -- A list of paths to the previews. + """ + full_tile = next((tile for tile in self.tiles if tile.code == PATH_FULL_NAME), None) + if full_tile: + preview_path = os.path.join(self.previews_directory, "background_dem.png") + full_tile_image = cv2.imread(full_tile.dem_path, cv2.IMREAD_UNCHANGED) + full_tile_image = cv2.normalize( # type: ignore + full_tile_image, None, 0, 255, cv2.NORM_MINMAX, cv2.CV_8U ) - - # pylint: disable=possibly-used-before-assignment - image[y:y2, x:x2] = tile_image - - # Save image to the map directory. - preview_path = os.path.join(self.previews_directory, "background_dem.png") - - # pylint: disable=no-member - image = cv2.normalize(image, None, 0, 255, cv2.NORM_MINMAX, cv2.CV_8U) # type: ignore - image = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR) # type: ignore - cv2.imwrite(preview_path, image) - - return [preview_path, self.stl_preview_path] - - -# Creates tiles around the map. -# The one on corners 2048x2048, on sides and in the middle map_size x 2048. -# So 2048 is a distance FROM the edge of the map, but the other size depends on the map size. -# But for corner tiles it's always 2048. - -# In the beginning we have coordinates of the central point of the map and it's size. -# We need to calculate the coordinates of central points all 8 tiles around the map. - -# Latitude is a vertical line, Longitude is a horizontal line. - -# 2048 -# | | -# ____________________|_________|___ -# | | | | -# | NW | N | NE | 2048 -# |_________|_________|_________|___ -# | | | | -# | W | C | E | -# |_________|_________|_________| -# | | | | -# | SW | S | SE | -# |_________|_________|_________| -# -# N = C map_height / 2 + 1024; N_width = map_width; N_height = 2048 -# NW = N - map_width / 2 - 1024; NW_width = 2048; NW_height = 2048 -# and so on... - -# lat, lon = 45.28565000315636, 20.237121355049904 -# dst = 1024 - -# # N -# destination = distance(meters=dst).destination((lat, lon), 0) -# lat, lon = destination.latitude, destination.longitude -# print(lat, lon) + full_tile_image = cv2.cvtColor(full_tile_image, cv2.COLOR_GRAY2BGR) + cv2.imwrite(preview_path, full_tile_image) + return [preview_path, self.stl_preview_path] + return [self.stl_preview_path] diff --git a/maps4fs/generator/component.py b/maps4fs/generator/component.py index 88954914..fb78c619 100644 --- a/maps4fs/generator/component.py +++ b/maps4fs/generator/component.py @@ -184,10 +184,10 @@ def get_bbox( height_distance = height_distance or int(self.map_height / 2) width_distance = width_distance or int(self.map_width / 2) - north, south, _, _ = ox.utils_geo.bbox_from_point( + west, south, _, _ = ox.utils_geo.bbox_from_point( # type: ignore coordinates, dist=height_distance, project_utm=project_utm ) - _, _, east, west = ox.utils_geo.bbox_from_point( + _, _, east, north = ox.utils_geo.bbox_from_point( # type: ignore coordinates, dist=width_distance, project_utm=project_utm ) bbox = north, south, east, west diff --git a/maps4fs/generator/dem.py b/maps4fs/generator/dem.py index 4a297b6b..2d0b42a5 100644 --- a/maps4fs/generator/dem.py +++ b/maps4fs/generator/dem.py @@ -319,7 +319,7 @@ def _srtm_tile(self) -> str | None: def _save_empty_dem(self, dem_output_resolution: tuple[int, int]) -> None: """Saves empty DEM file filled with zeros.""" dem_data = np.zeros(dem_output_resolution, dtype="uint16") - cv2.imwrite(self._dem_path, dem_data) # pylint: disable=no-member + cv2.imwrite(self._dem_path, dem_data) self.logger.warning("DEM data filled with zeros and saved to %s.", self._dem_path) def grayscale_preview(self) -> str: @@ -329,7 +329,6 @@ def grayscale_preview(self) -> str: Returns: str: Path to the preview image. """ - # rgb_dem_path = self._dem_path.replace(".png", "_grayscale.png") grayscale_dem_path = os.path.join(self.previews_directory, "dem_grayscale.png") self.logger.debug("Creating grayscale preview of DEM data in %s.", grayscale_dem_path) @@ -346,8 +345,6 @@ def colored_preview(self) -> str: Returns: list[str]: List with a single path to the DEM file """ - - # colored_dem_path = self._dem_path.replace(".png", "_colored.png") colored_dem_path = os.path.join(self.previews_directory, "dem_colored.png") self.logger.debug("Creating colored preview of DEM data in %s.", colored_dem_path) diff --git a/maps4fs/generator/texture.py b/maps4fs/generator/texture.py index f51314c8..694b87d1 100644 --- a/maps4fs/generator/texture.py +++ b/maps4fs/generator/texture.py @@ -4,7 +4,6 @@ import json import os -import warnings from collections import defaultdict from typing import Any, Callable, Generator, Optional @@ -540,14 +539,12 @@ def polygons( Generator[np.ndarray, None, None]: Numpy array of polygon points. """ try: - with warnings.catch_warnings(): - warnings.simplefilter("ignore", DeprecationWarning) - objects = ox.features_from_bbox(bbox=self.bbox, tags=tags) + objects = ox.features_from_bbox(bbox=self.new_bbox, tags=tags) except Exception as e: # pylint: disable=W0718 self.logger.warning("Error fetching objects for tags: %s.", tags) self.logger.warning(e) return - objects_utm = ox.project_gdf(objects, to_latlong=False) + objects_utm = ox.projection.project_gdf(objects, to_latlong=False) self.logger.debug("Fetched %s elements for tags: %s.", len(objects_utm), tags) for _, obj in objects_utm.iterrows(): @@ -610,6 +607,7 @@ def _osm_preview(self) -> str: merged.dtype, ) preview_path = os.path.join(self.previews_directory, "textures_osm.png") - cv2.imwrite(preview_path, merged) # pylint: disable=no-member + + cv2.imwrite(preview_path, merged) # type: ignore self.logger.info("Preview saved to %s.", preview_path) return preview_path diff --git a/pyproject.toml b/pyproject.toml index 14a16495..e2ec4c31 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,7 +18,7 @@ classifiers = [ ] dependencies = [ "opencv-python", - "osmnx<2.0.0", + "osmnx>=2.0.0", "rasterio", "folium", "geopy", diff --git a/requirements.txt b/requirements.txt index da7ae225..12ba31a3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ opencv-python -osmnx<2.0.0 +osmnx>=2.0.0 rasterio streamlit folium diff --git a/webui/osmp.py b/webui/osmp.py index 8bbaceed..221c425d 100644 --- a/webui/osmp.py +++ b/webui/osmp.py @@ -47,7 +47,7 @@ def get_center(bbox: tuple[float, float, float, float]) -> tuple[float, float]: def get_bbox(center: tuple[float, float], size_meters: int) -> tuple[float, float, float, float]: center_lat, center_lon = center - north, south, east, west = ox.utils_geo.bbox_from_point( + west, south, east, north = ox.utils_geo.bbox_from_point( (center_lat, center_lon), size_meters / 2, project_utm=False ) return north, south, east, west