Skip to content

Commit

Permalink
Migration to OSMNX2.0
Browse files Browse the repository at this point in the history
* osmnx 2.0 migration.

* Actions update.

* mypy updates.

* Tests and previews.

* Tests and previews.

* Docker build release tag version.

* pypi version action update.

* pypi dependencies update.
  • Loading branch information
iwatkot authored Dec 13, 2024
1 parent 4c1610a commit d2931f9
Show file tree
Hide file tree
Showing 13 changed files with 41 additions and 133 deletions.
1 change: 0 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ temp/
.gitignore
LICENSE.md
README.md
requirements.txt
run.ps1
run.sh
maps4fs.zip
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/build_docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,7 @@ jobs:
with:
context: .
push: true
tags: iwatkot/maps4fs:latest
tags: |
iwatkot/maps4fs:latest
iwatkot/maps4fs:${{ github.ref }}
file: ./Dockerfile
2 changes: 1 addition & 1 deletion .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions .github/workflows/pypi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
4 changes: 3 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion dev/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
opencv-python
osmnx<2.0.0
osmnx>=2.0.0
rasterio
streamlit
mypy
Expand Down
128 changes: 15 additions & 113 deletions maps4fs/generator/background.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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]
4 changes: 2 additions & 2 deletions maps4fs/generator/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 1 addition & 4 deletions maps4fs/generator/dem.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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)
Expand All @@ -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)
Expand Down
10 changes: 4 additions & 6 deletions maps4fs/generator/texture.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

import json
import os
import warnings
from collections import defaultdict
from typing import Any, Callable, Generator, Optional

Expand Down Expand Up @@ -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():
Expand Down Expand Up @@ -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
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ classifiers = [
]
dependencies = [
"opencv-python",
"osmnx<2.0.0",
"osmnx>=2.0.0",
"rasterio",
"folium",
"geopy",
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
opencv-python
osmnx<2.0.0
osmnx>=2.0.0
rasterio
streamlit
folium
Expand Down
2 changes: 1 addition & 1 deletion webui/osmp.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit d2931f9

Please sign in to comment.