From da5c21a61ae91c5f7fdc9a4ed027e50411b40559 Mon Sep 17 00:00:00 2001 From: Stan Soldatov <118521851+iwatkot@users.noreply.github.com> Date: Mon, 18 Nov 2024 12:41:23 +0100 Subject: [PATCH] Preview update and custom map size * Preview update and custom size. * Version update. * README update. * README update. --- README.md | 31 +++++++++++++++--------------- maps4fs/generator/component.py | 8 +++++--- maps4fs/generator/dem.py | 35 ++++++++++++++++++++++------------ maps4fs/generator/texture.py | 21 ++++++++++++++++++-- pyproject.toml | 2 +- requirements.txt | 1 - webui/webui.py | 7 ++++++- 7 files changed, 69 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index e6441c49..9acd3cb9 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,8 @@ Quick StartOverviewHow-To-Run • - FeaturesSupported objects • - Advanced Settings • + For advanced usersBugs and feature requests

@@ -24,10 +23,13 @@ -### Supported Games +🗺️ Supports 2x2, 4x4, 8x8, 16x16 and any custom size maps
+🌍 Based on real-world data from OpenStreetMap
+🏞️ Generates height using SRTM dataset
+📦 Provides a ready-to-use map template for the Giants Editor
+🚜 Supports Farming Simulator 22 and 25*
-✅ Farming Simulator 22
-🔃 Farming Simulator 25 (changes in the library are ready, waiting for the Giants to release the Giants Editor v10)
+\* changes in the library are ready, waiting for the Giants to release the Giants Editor v10. Meanwhile the option to generate a map for FS25 is disabled. ## Quick Start There are several ways to use the tool. You obviously need the **first one**, but you can choose any of the others depending on your needs.
@@ -80,7 +82,6 @@ You'll find detailed instructions on how to run the project below. But if you pr Video tutorial: How to generate a Farming Simulator 22 map from real-world data. ### Option 1: StreamLit -**🗺️ Supported map sizes:** 2x2, 4x4, 8x8, 16x16 km.
🟢 Recommended for all users, you don't need to install anything.
Using the [StreamLit](https://maps4fs.streamlit.app) version of the tool is the easiest way to generate a map template. Just open the link and follow the instructions. Note: due to CPU and RAM limitations of the hosting, the generation may take some time. If you need faster processing, use the [Docker version](#option-2-docker-version).
@@ -88,7 +89,6 @@ Note: due to CPU and RAM limitations of the hosting, the generation may take som Using it is easy and doesn't require any guides. Enjoy! ### Option 2: Docker version -**🗺️ Supported map sizes:** 2x2, 4x4, 8x8, 16x16 km.
🟠 Recommended for users who want faster processing, very simple installation.
You can launch the project with minimalistic UI in your browser using Docker. Follow these steps: @@ -101,10 +101,9 @@ docker run -d -p 8501:8501 iwatkot/maps4fs 4. Fill in the required fields and click on the `Generate` button. 5. When the map is generated click on the `Download` button to get the map. -![WebUI](https://github.com/user-attachments/assets/e3b48c9d-7b87-4ce7-8ad7-98332a558a88) +![WebUI](https://github.com/user-attachments/assets/581e1206-2abd-4b3c-ad31-80554ad92d99) ### Option 3: Python package -**🗺️ Supported map sizes:** 2x2, 4x4, 8x8, 16x16 km (and ANY other you may add).
🔴 Recommended for developers.
You can use the Python package to generate maps. Follow these steps: @@ -149,12 +148,6 @@ map.generate() The map will be saved in the `map_directory` directory. -## Features -- Allows to enter a location by lat and lon (e.g. from Google Maps). -- Allows to select a size of the map (2x2, 4x4, 8x8 km, 16x16 km). -- Generates a map template (check the list of supported objects in [this section](#supported-objects)). -- Generates a height map. - ## Supported objects The project is based on the [OpenStreetMap](https://www.openstreetmap.org/) data. So, refer to [this page](https://wiki.openstreetmap.org/wiki/Map_Features) to understand the list below. - "building": True @@ -187,7 +180,13 @@ The script will also generate the `generation_info.json` file in the `output` fo You can use this information to adjust some other sources of data to the map, e.g. textures, height maps, etc. -## Advanced Settings +## For advanced users +The tool supports the custom size of the map. To use this feature select `Custom` in the `Map size` dropdown and enter the desired size. The tool will generate a map with the size you entered.
+ +⛔️ Do not use this feature, if you don't know what you're doing. In most cases the Giants Editor will just crash on opening the file, because you need to enter a specific values for the map size.

+ +![Advanced settings and custom size](https://github.com/user-attachments/assets/327b6065-09ed-41d0-86a8-7d904025707c) + You can also apply some advanced settings to the map generation process. Note that they're ADVANCED, so you don't need to use them if you're not sure what they do.
Here's the list of the advanced settings: diff --git a/maps4fs/generator/component.py b/maps4fs/generator/component.py index 17976c68..26b59fba 100644 --- a/maps4fs/generator/component.py +++ b/maps4fs/generator/component.py @@ -86,8 +86,10 @@ def get_bbox(self, project_utm: bool = False) -> tuple[int, int, int, int]: ) bbox = north, south, east, west self.logger.debug( - f"Calculated bounding box for component: {self.__class__.__name__}: {bbox}, " - f"project_utm: {project_utm}" + "Calculated bounding box for component: %s: %s, project_utm: %s", + self.__class__.__name__, + bbox, + project_utm, ) return bbox @@ -96,4 +98,4 @@ def save_bbox(self) -> None: height and width of the map. """ self.bbox = self.get_bbox(project_utm=False) - self.logger.debug(f"Saved bounding box: {self.bbox}") + self.logger.debug("Saved bounding box: %s", self.bbox) diff --git a/maps4fs/generator/dem.py b/maps4fs/generator/dem.py index a640d9c5..c5193780 100644 --- a/maps4fs/generator/dem.py +++ b/maps4fs/generator/dem.py @@ -85,8 +85,11 @@ def process(self) -> None: return self.logger.debug( - f"DEM data was read from SRTM file. Shape: {data.shape}, dtype: {data.dtype}. " - f"Min: {data.min()}, max: {data.max()}." + "DEM data was read from SRTM file. Shape: %s, dtype: %s. Min: %s, max: %s.", + data.shape, + data.dtype, + data.min(), + data.max(), ) resampled_data = cv2.resize( @@ -94,26 +97,33 @@ def process(self) -> None: ).astype("uint16") self.logger.debug( - f"Maximum value in resampled data: {resampled_data.max()}, " - f"minimum value: {resampled_data.min()}." + "Maximum value in resampled data: %s, minimum value: %s.", + resampled_data.max(), + resampled_data.min(), ) resampled_data = resampled_data * self.multiplier self.logger.debug( - f"DEM data multiplied by {self.multiplier}. Shape: {resampled_data.shape}, " - f"dtype: {resampled_data.dtype}. " - f"Min: {resampled_data.min()}, max: {resampled_data.max()}." + "DEM data multiplied by %s. Shape: %s, dtype: %s. Min: %s, max: %s.", + self.multiplier, + resampled_data.shape, + resampled_data.dtype, + resampled_data.min(), + resampled_data.max(), ) self.logger.debug( - f"DEM data was resampled. Shape: {resampled_data.shape}, " - f"dtype: {resampled_data.dtype}. " - f"Min: {resampled_data.min()}, max: {resampled_data.max()}." + "DEM data was resampled. Shape: %s, dtype: %s. Min: %s, max: %s.", + resampled_data.shape, + resampled_data.dtype, + resampled_data.min(), + resampled_data.max(), ) resampled_data = cv2.GaussianBlur(resampled_data, (self.blur_radius, self.blur_radius), 0) self.logger.debug( - f"Gaussion blur applied to DEM data with kernel size {self.blur_radius}. " + "Gaussion blur applied to DEM data with kernel size %s.", + self.blur_radius, ) cv2.imwrite(self._dem_path, resampled_data) @@ -179,7 +189,8 @@ def _srtm_tile(self) -> str | None: decompressed_file_path = os.path.join(self.hgt_dir, f"{tile_name}.hgt") if os.path.isfile(decompressed_file_path): self.logger.info( - f"Decompressed tile already exists: {decompressed_file_path}, skipping download." + "Decompressed tile already exists: %s, skipping download.", + decompressed_file_path, ) return decompressed_file_path diff --git a/maps4fs/generator/texture.py b/maps4fs/generator/texture.py index 60ce005b..dff6c38d 100644 --- a/maps4fs/generator/texture.py +++ b/maps4fs/generator/texture.py @@ -16,6 +16,8 @@ from maps4fs.generator.component import Component +PREVIEW_MAXIMUM_SIZE = 2048 + # pylint: disable=R0902 class Texture(Component): @@ -387,7 +389,20 @@ def _osm_preview(self) -> str: Returns: str: Path to the preview. """ - preview_size = (2048, 2048) + scaling_factor = min( + PREVIEW_MAXIMUM_SIZE / self.map_width, PREVIEW_MAXIMUM_SIZE / self.map_height + ) + + preview_size = ( + int(self.map_width * scaling_factor), + int(self.map_height * scaling_factor), + ) + self.logger.debug( + "Scaling factor: %s. Preview size: %s.", + scaling_factor, + preview_size, + ) + images = [ cv2.resize( cv2.imread(layer.path(self._weights_dir), cv2.IMREAD_UNCHANGED), preview_size @@ -402,7 +417,9 @@ def _osm_preview(self) -> str: color_images.append(color_img) merged = np.sum(color_images, axis=0, dtype=np.uint8) self.logger.debug( - f"Merged layers into one image. Shape: {merged.shape}, dtype: {merged.dtype}." + "Merged layers into one image. Shape: %s, dtype: %s.", + merged.shape, + merged.dtype, ) preview_path = os.path.join(self.map_directory, "preview_osm.png") cv2.imwrite(preview_path, merged) # pylint: disable=no-member diff --git a/pyproject.toml b/pyproject.toml index 7c751ec8..000b3c08 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "maps4fs" -version = "0.7.2" +version = "0.7.3" description = "Generate map templates for Farming Simulator from real places." authors = [{name = "iwatkot", email = "iwatkot@gmail.com"}] license = {text = "MIT License"} diff --git a/requirements.txt b/requirements.txt index 15ec73ee..e39bea7b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,4 @@ opencv-python -opencv-python-headless osmnx<2.0.0 rasterio tqdm diff --git a/webui/webui.py b/webui/webui.py index 4beed8d8..5ef5267d 100644 --- a/webui/webui.py +++ b/webui/webui.py @@ -48,11 +48,16 @@ def add_widgets(self) -> None: st.write("Select size of the map:") self.map_size_input = st.selectbox( "Map Size (meters)", - options=["2048x2048", "4096x4096", "8192x8192", "16384x16384"], # , "Custom"], + options=["2048x2048", "4096x4096", "8192x8192", "16384x16384", "Custom"], label_visibility="collapsed", ) if self.map_size_input == "Custom": + st.warning( + "This feature is for advanced users only, you need to know exact correct values, " + "otherwise the Giants Editor will crash on opening the file. Do not use it, " + "if you are not sure what you are doing." + ) st.write("Enter map height (meters):") map_height_input = st.number_input( "Height (meters)", 1, 16384, 2048, key="map_height", label_visibility="collapsed"