Skip to content

Commit

Permalink
Coordinates and rotation randomization.
Browse files Browse the repository at this point in the history
  • Loading branch information
iwatkot committed Dec 22, 2024
1 parent 116428f commit c2dc103
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 13 deletions.
2 changes: 1 addition & 1 deletion maps4fs/generator/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class Component:
def __init__(
self,
game: Game,
map: Map,
map: Map, # pylint: disable=W0622
coordinates: tuple[float, float],
map_size: int,
map_rotated_size: int,
Expand Down
11 changes: 6 additions & 5 deletions maps4fs/generator/grle.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import cv2
import numpy as np
from shapely.geometry import Polygon
from shapely.geometry import Polygon # type: ignore

from maps4fs.generator.component import Component
from maps4fs.generator.texture import Texture
Expand Down Expand Up @@ -199,12 +199,13 @@ def _add_farmlands(self) -> None:
"Farmlands added to the InfoLayer PNG file: %s.", info_layer_farmlands_path
)

# pylint: disable=R0915
def _add_plants(self) -> None:
"""Adds plants to the InfoLayer PNG file."""
# 1. Get the path to the densityMap_fruits.png.
# 2. Get the path to the base layer (grass).
# 3. Detect non-zero areas in the base layer (it's where the plants will be placed).
texture_component: Texture | None = self.map.get_component("Texture")
texture_component: Texture | None = self.map.get_component("Texture") # type: ignore
if not texture_component:
self.logger.warning("Texture component not found in the map.")
return
Expand Down Expand Up @@ -235,9 +236,9 @@ def _add_plants(self) -> None:
return

# Single channeled 8-bit image, where non-zero values (255) are where the grass is.
grass_image = cv2.imread(
grass_image_path, cv2.IMREAD_UNCHANGED
) # pylint: disable=no-member
grass_image = cv2.imread( # pylint: disable=no-member
grass_image_path, cv2.IMREAD_UNCHANGED # pylint: disable=no-member
)

# Density map of the fruits is 2X size of the base image, so we need to resize it.
# We'll resize the base image to make it bigger, so we can compare the values.
Expand Down
42 changes: 35 additions & 7 deletions maps4fs/generator/i3d.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import json
import os
from random import choice
from random import choice, randint, uniform
from typing import Generator
from xml.etree import ElementTree as ET

Expand Down Expand Up @@ -325,7 +325,9 @@ def create_attribute_node(name: str, attr_type: str, value: str) -> ET.Element:
attribute_node.set("value", value)
return attribute_node

# pylint: disable=R0911
def _add_forests(self) -> None:
"""Adds forests to the map I3D file."""
try:
tree_schema_path = self.game.tree_schema
except ValueError:
Expand All @@ -345,7 +347,7 @@ def _add_forests(self) -> None:
)
return

texture_component: Texture | None = self.map.get_component("Texture")
texture_component: Texture | None = self.map.get_component("Texture") # type: ignore
if not texture_component:
self.logger.warning("Texture component not found.")
return
Expand Down Expand Up @@ -385,24 +387,27 @@ def _add_forests(self) -> None:
trees_node.set("nodeId", str(node_id))
node_id += 1

# pylint: disable=no-member
forest_image = cv2.imread(forest_image_path, cv2.IMREAD_UNCHANGED)

forest_density = 10 # TODO: Obtain as a setting from UI.

tree_count = 0
for x, y in self.non_empty_pixels(forest_image, step=2):
for x, y in self.non_empty_pixels(forest_image, step=forest_density):
xcs, ycs = self.top_left_coordinates_to_center((x, y))
node_id += 1

# TODO: Randomize coordinates.
rotation = randint(-180, 180)
xcs, ycs = self.randomize_coordinates((xcs, ycs), forest_density) # type: ignore

random_tree = choice(tree_schema)
tree_name = random_tree["name"]
tree_id = random_tree["reference_id"]

# <ReferenceNode name="oak_stage02" translation="{x} 0 {y}" rotation="0 -0 0" referenceId="658" nodeId="{node_id}"/>
reference_node = ET.Element("ReferenceNode")
reference_node.set("name", tree_name)
reference_node.set("name", tree_name) # type: ignore
reference_node.set("translation", f"{xcs} 0 {ycs}")
reference_node.set("rotation", "0 -0 0")
reference_node.set("rotation", f"0 {rotation} 0")
reference_node.set("referenceId", str(tree_id))
reference_node.set("nodeId", str(node_id))

Expand All @@ -415,6 +420,29 @@ def _add_forests(self) -> None:
tree.write(self._map_i3d_path) # type: ignore
self.logger.info("Map I3D file saved to: %s.", self._map_i3d_path)

@staticmethod
def randomize_coordinates(coordinates: tuple[int, int], density: int) -> tuple[float, float]:
"""Randomizes the coordinates of the point with the given density.
Arguments:
coordinates (tuple[int, int]): The coordinates of the point.
density (int): The density of the randomization.
Returns:
tuple[float, float]: The randomized coordinates of the point.
"""
MAXIMUM_RELATIVE_SHIFT = 0.2 # pylint: disable=C0103
shift_range = density * MAXIMUM_RELATIVE_SHIFT

x_shift = uniform(-shift_range, shift_range)
y_shift = uniform(-shift_range, shift_range)

x, y = coordinates
x += x_shift # type: ignore
y += y_shift # type: ignore

return x, y

@staticmethod
def non_empty_pixels(
image: np.ndarray, step: int = 1
Expand Down

0 comments on commit c2dc103

Please sign in to comment.