Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Advanced settings: Added field padding #72

Merged
merged 5 commits into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -427,20 +427,26 @@ The tool supports the custom size of the map. To use this feature select `Custom

⛔️ 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 specific values for the map size.<br><br>

![Advanced settings](https://github.com/user-attachments/assets/e7406adf-6b82-41a0-838a-13dd8877bebf)
![Advanced settings](https://github.com/user-attachments/assets/9e8e178a-58d9-4aa6-aefd-4ed53408701d)

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.<br>

Here's the list of the advanced settings:
### DEM Advanced settings

- DEM multiplier: the height of the map is multiplied by this value. So the DEM map is just a 16-bit grayscale image, which means that the maximum available value there is 65535, while the actual difference between the deepest and the highest point on Earth is about 20 km. Just note that this setting mostly does not matter, because you can always adjust it in the Giants Editor, learn more about the DEM file and the heightScale parameter in [docs](docs/dem.md). By default, it's set to 1.
- Multiplier: the height of the map is multiplied by this value. So the DEM map is just a 16-bit grayscale image, which means that the maximum available value there is 65535, while the actual difference between the deepest and the highest point on Earth is about 20 km. Just note that this setting mostly does not matter, because you can always adjust it in the Giants Editor, learn more about the DEM file and the heightScale parameter in [docs](docs/dem.md). By default, it's set to 1.

- DEM Blur radius: the radius of the Gaussian blur filter applied to the DEM map. By default, it's set to 21. This filter just makes the DEM map smoother, so the height transitions will be more natural. You can set it to 1 to disable the filter, but it will result in a Minecraft-like map.
- Blur radius: the radius of the Gaussian blur filter applied to the DEM map. By default, it's set to 21. This filter just makes the DEM map smoother, so the height transitions will be more natural. You can set it to 1 to disable the filter, but it will result in a Minecraft-like map.

- DEM Plateau height: this value will be added to each pixel of the DEM image, making it "higher". It's useful when you want to add some negative heights on the map, that appear to be in a "low" place. By default, it's set to 0.
- Plateau height: this value will be added to each pixel of the DEM image, making it "higher". It's useful when you want to add some negative heights on the map, that appear to be in a "low" place. By default, it's set to 0.

### Background Terrain Advanced settings

- Background Terrain Generate only full tiles: if checked (by default) the small tiles (N, NE, E, and so on) will not be generated, only the full tile will be created. It's useful when you don't want to work with separate tiles, but with one big file. Since the new method of cutting the map from the background terrain added to the documentation, and now it's possible to perfectly align the map with the background terrain, this option will remain just as a legacy one.

### Texture Advanced settings

- Fields padding - this value (in meters) will be applied to each field, making it smaller. It's useful when the fields are too close to each other and you want to make them smaller. By default, it's set to 0.

## Resources
In this section, you'll find a list of the resources that you need to create a map for the Farming Simulator.<br>
To create a basic map, you only need the Giants Editor. But if you want to create a background terrain - the world around the map, so it won't look like it's floating in the void - you also need Blender and the Blender Exporter Plugins. To create realistic textures for the background terrain, the QGIS is required to obtain high-resolution satellite images.<br>
Expand Down
14 changes: 13 additions & 1 deletion docs/FAQ.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,21 @@ You can find the detailed tutorial [here](https://github.com/iwatkot/maps4fs/blo
You can find the detailed tutorial [here](https://github.com/iwatkot/maps4fs/blob/main/docs/import_to_giants_editor.md).


### I have some graphic glitches in Giants Editor: screen keeps blinking black, and the terrain become purple at some angles, what should I do?
### I have some graphic glitches in Giants Editor: the terrain become purple at some angles, what should I do?

To fix this issue, select the **terrain** object, open the **Terrain** tab in the **Attributes** window, scroll down to the end and press the **Reload material** button. It should help.

### I have some graphic glitches in Giants Editor: the screen keeps flickering black, what should I do?

To fix this issue, in the Giants Editor click on **Scripts** -> **Create new script**, give it a name and paste the code below:

```
setAudioCullingWorldProperties(-8192, -100, -8192, 8192, 500, 8192, 16, 0, 9000)
setLightCullingWorldProperties(-8192, -100, -8192, 8192, 500, 8192, 16, 0, 9000)
setShapeCullingWorldProperties(-8192, -100, -8192, 8192, 500, 8192, 16, 0, 9000)
```

Make sure that **Always loaded** checkbox is checked, then save it and execute. It should help.


If you think that some question should be added here, please, contact me in [Discord](https://discord.gg/Sj5QKKyE42) or open an issue on GitHub. Thank you!
33 changes: 27 additions & 6 deletions maps4fs/generator/background.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ def generate_obj_files(self) -> None:
dem_data = cv2.imread(tile.dem_path, cv2.IMREAD_UNCHANGED) # pylint: disable=no-member
self.plane_from_np(tile.code, dem_data, save_path) # type: ignore

# pylint: disable=too-many-locals
def cutout(self, dem_path: str) -> str:
"""Cuts out the center of the DEM (the actual map) and saves it as a separate file.

Expand All @@ -205,20 +206,40 @@ def cutout(self, dem_path: str) -> str:

output_size = self.map_height + 1

# pylint: disable=no-member
dem_data = cv2.resize(dem_data, (output_size, output_size), interpolation=cv2.INTER_LINEAR)

main_dem_path = self.game.dem_file_path(self.map_directory)
dem_directory = os.path.dirname(main_dem_path)

try:
os.remove(main_dem_path)
except FileNotFoundError:
pass

cv2.imwrite(main_dem_path, dem_data) # pylint: disable=no-member
self.logger.info("DEM cutout saved: %s", main_dem_path)
# pylint: disable=no-member
resized_dem_data = cv2.resize(
dem_data, (output_size, output_size), interpolation=cv2.INTER_LINEAR
)

# Giant Editor contains a bug for large maps, where the DEM should not match
# the UnitsPerPixel value. For example, for map 8192x8192, without bug
# the DEM image should be 8193x8193, but it does not work, so we need to
# resize the DEM to 4097x4097.
if self.map_height > 4096:
correct_dem_path = os.path.join(dem_directory, "correct_dem.png")
save_path = correct_dem_path

output_size = self.map_height // 2 + 1
bugged_dem_data = cv2.resize(
dem_data, (output_size, output_size), interpolation=cv2.INTER_LINEAR
)
# pylint: disable=no-member
cv2.imwrite(main_dem_path, bugged_dem_data)
else:
save_path = main_dem_path

cv2.imwrite(save_path, resized_dem_data) # pylint: disable=no-member
self.logger.info("DEM cutout saved: %s", save_path)

return main_dem_path
return save_path

# pylint: disable=too-many-locals
def plane_from_np(self, tile_code: str, dem_data: np.ndarray, save_path: str) -> None:
Expand Down
28 changes: 12 additions & 16 deletions maps4fs/generator/i3d.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ class I3d(Component):
def preprocess(self) -> None:
"""Gets the path to the map I3D file from the game instance and saves it to the instance
attribute. If the game does not support I3D files, the attribute is set to None."""
self.auto_process = self.kwargs.get("auto_process", False)

try:
self._map_i3d_path = self.game.i3d_file_path(self.map_directory)
self.logger.debug("Map I3D path: %s.", self._map_i3d_path)
Expand Down Expand Up @@ -69,22 +71,16 @@ def _update_i3d_file(self) -> None:
root = tree.getroot()
for map_elem in root.iter("Scene"):
for terrain_elem in map_elem.iter("TerrainTransformGroup"):
terrain_elem.set("heightScale", str(DEFAULT_HEIGHT_SCALE))
self.logger.debug(
"heightScale attribute set to %s in TerrainTransformGroup element.",
DEFAULT_HEIGHT_SCALE,
)
terrain_elem.set("maxLODDistance", str(DEFAULT_MAX_LOD_DISTANCE))
self.logger.debug(
"maxLODDistance attribute set to %s in TerrainTransformGroup element.",
DEFAULT_MAX_LOD_DISTANCE,
)

terrain_elem.set("occMaxLODDistance", str(DEFAULT_MAX_LOD_OCCLUDER_DISTANCE))
self.logger.debug(
"occMaxLODDistance attribute set to %s in TerrainTransformGroup element.",
DEFAULT_MAX_LOD_OCCLUDER_DISTANCE,
)
if self.auto_process:
terrain_elem.set("heightScale", str(DEFAULT_HEIGHT_SCALE))
self.logger.debug(
"heightScale attribute set to %s in TerrainTransformGroup element.",
DEFAULT_HEIGHT_SCALE,
)
else:
self.logger.debug(
"Auto process is disabled, skipping the heightScale attribute update."
)

self.logger.debug("TerrainTransformGroup element updated in I3D file.")

Expand Down
41 changes: 34 additions & 7 deletions maps4fs/generator/texture.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ def paths(self, weights_directory: str) -> list[str]:

def preprocess(self) -> None:
self.light_version = self.kwargs.get("light_version", False)
self.fields_padding = self.kwargs.get("fields_padding", 0)
self.logger.debug("Light version: %s.", self.light_version)

if not os.path.isfile(self.game.texture_schema):
Expand Down Expand Up @@ -476,15 +477,17 @@ def _to_np(self, geometry: shapely.geometry.polygon.Polygon, *args) -> np.ndarra
pairs = list(zip(xs, ys))
return np.array(pairs, dtype=np.int32).reshape((-1, 1, 2))

def _to_polygon(self, obj: pd.core.series.Series, width: int | None) -> np.ndarray | None:
def _to_polygon(
self, obj: pd.core.series.Series, width: int | None
) -> shapely.geometry.polygon.Polygon:
"""Converts OSM object to numpy array of polygon points.

Arguments:
obj (pd.core.series.Series): OSM object.
width (int | None): Width of the polygon in meters.

Returns:
np.ndarray | None: Numpy array of polygon points.
shapely.geometry.polygon.Polygon: Polygon geometry.
"""
geometry = obj["geometry"]
geometry_type = geometry.geom_type
Expand All @@ -498,7 +501,7 @@ def _sequence(
self,
geometry: shapely.geometry.linestring.LineString | shapely.geometry.point.Point,
width: int | None,
) -> np.ndarray:
) -> shapely.geometry.polygon.Polygon:
"""Converts LineString or Point geometry to numpy array of polygon points.

Arguments:
Expand All @@ -507,10 +510,23 @@ def _sequence(
width (int | None): Width of the polygon in meters.

Returns:
np.ndarray: Numpy array of polygon points.
shapely.geometry.polygon.Polygon: Polygon geometry.
"""
polygon = geometry.buffer(width)
return self._to_np(polygon)
return polygon

def _skip(
self, geometry: shapely.geometry.polygon.Polygon, *args, **kwargs
) -> shapely.geometry.polygon.Polygon:
"""Returns the same geometry.

Arguments:
geometry (shapely.geometry.polygon.Polygon): Polygon geometry.

Returns:
shapely.geometry.polygon.Polygon: Polygon geometry.
"""
return geometry

def _converters(
self, geom_type: str
Expand All @@ -523,7 +539,7 @@ def _converters(
Returns:
Callable[[shapely.geometry, int | None], np.ndarray]: Converter function.
"""
converters = {"Polygon": self._to_np, "LineString": self._sequence, "Point": self._sequence}
converters = {"Polygon": self._skip, "LineString": self._sequence, "Point": self._sequence}
return converters.get(geom_type) # type: ignore

def polygons(
Expand All @@ -538,6 +554,7 @@ def polygons(
Yields:
Generator[np.ndarray, None, None]: Numpy array of polygon points.
"""
is_fieds = "farmland" in tags.values()
try:
objects = ox.features_from_bbox(bbox=self.new_bbox, tags=tags)
except Exception as e: # pylint: disable=W0718
Expand All @@ -551,7 +568,17 @@ def polygons(
polygon = self._to_polygon(obj, width)
if polygon is None:
continue
yield polygon

if is_fieds and self.fields_padding > 0:
padded_polygon = polygon.buffer(-self.fields_padding)

if not isinstance(padded_polygon, shapely.geometry.polygon.Polygon):
self.logger.warning("The padding value is too high, field will not padded.")
else:
polygon = padded_polygon

polygon_np = self._to_np(polygon)
yield polygon_np

def previews(self) -> list[str]:
"""Invokes methods to generate previews. Returns list of paths to previews.
Expand Down
Loading
Loading