maps4fs 1.8.172__py3-none-any.whl → 1.8.173__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -235,24 +235,16 @@ class Background(MeshComponent, ImageComponent):
235
235
  This setting is used for a Background Terrain, where the center part where the
236
236
  playable area is will be cut out.
237
237
  """
238
- resize_factor = 1 / self.map.background_settings.resize_factor
239
- dem_data = cv2.resize(dem_data, (0, 0), fx=resize_factor, fy=resize_factor)
240
- if remove_center:
241
- half_size = int(self.map_size // 2 * resize_factor)
242
- dem_data = self.cut_out_np(dem_data, half_size, set_zeros=True)
243
- self.logger.debug("Center removed from DEM data.")
244
- self.logger.debug(
245
- "DEM data resized to shape: %s with factor: %s", dem_data.shape, resize_factor
246
- )
247
-
248
238
  mesh = self.mesh_from_np(
249
239
  dem_data,
250
240
  include_zeros=include_zeros,
251
241
  z_scaling_factor=self.get_z_scaling_factor(),
252
- resize_factor=resize_factor,
242
+ resize_factor=self.map.background_settings.resize_factor,
253
243
  apply_decimation=self.map.background_settings.apply_decimation,
254
244
  decimation_percent=self.map.background_settings.decimation_percent,
255
245
  decimation_agression=self.map.background_settings.decimation_agression,
246
+ remove_center=remove_center,
247
+ remove_size=self.map_size,
256
248
  )
257
249
 
258
250
  mesh.export(save_path)
@@ -440,6 +432,12 @@ class Background(MeshComponent, ImageComponent):
440
432
 
441
433
  # Single channeled 8 bit image, where the water have values of 255, and the rest 0.
442
434
  plane_water = cv2.imread(self.water_resources_path, cv2.IMREAD_UNCHANGED)
435
+
436
+ # Check if the image contains non-zero values.
437
+ if not np.any(plane_water):
438
+ self.logger.warning("Water resources image is empty, skipping water generation.")
439
+ return
440
+
443
441
  dilated_plane_water = cv2.dilate(
444
442
  plane_water.astype(np.uint8), np.ones((5, 5), np.uint8), iterations=5
445
443
  ).astype(np.uint8)
@@ -53,10 +53,12 @@ class MeshComponent(Component):
53
53
  image: np.ndarray,
54
54
  include_zeros: bool,
55
55
  z_scaling_factor: float,
56
- resize_factor: float,
56
+ resize_factor: int,
57
57
  apply_decimation: bool,
58
58
  decimation_percent: int,
59
59
  decimation_agression: int,
60
+ remove_center: bool,
61
+ remove_size: int,
60
62
  ) -> trimesh.Trimesh:
61
63
  """Generates a mesh from the given numpy array.
62
64
 
@@ -64,16 +66,21 @@ class MeshComponent(Component):
64
66
  image (np.ndarray): The numpy array to generate the mesh from.
65
67
  include_zeros (bool): Whether to include zero values in the mesh.
66
68
  z_scaling_factor (float): The scaling factor for the Z-axis.
67
- resize_factor (float): The resizing factor.
69
+ resize_factor (int): The resizing factor.
68
70
  apply_decimation (bool): Whether to apply decimation to the mesh.
69
71
  decimation_percent (int): The percent of the decimation.
70
72
  decimation_agression (int): The agression of the decimation.
73
+ remove_center (bool): Whether to remove the center from the mesh.
74
+ remove_size (int): The size of the center to remove.
71
75
 
72
76
  Returns:
73
77
  trimesh.Trimesh: The generated mesh.
74
78
  """
79
+ output_x_size, _ = image.shape
75
80
  image = image.max() - image
76
81
 
82
+ image = image[::resize_factor, ::resize_factor]
83
+
77
84
  rows, cols = image.shape
78
85
  x = np.linspace(0, cols - 1, cols)
79
86
  y = np.linspace(0, rows - 1, rows)
@@ -106,15 +113,7 @@ class MeshComponent(Component):
106
113
 
107
114
  faces_np = np.array(faces)
108
115
  mesh = trimesh.Trimesh(vertices=vertices, faces=faces_np)
109
-
110
- # Apply rotation: 180 degrees around Y-axis and Z-axis
111
- rotation_matrix_y = trimesh.transformations.rotation_matrix(np.pi, [0, 1, 0])
112
- rotation_matrix_z = trimesh.transformations.rotation_matrix(np.pi, [0, 0, 1])
113
- mesh.apply_transform(rotation_matrix_y)
114
- mesh.apply_transform(rotation_matrix_z)
115
-
116
- # if not include_zeros:
117
- mesh.apply_scale([1 / resize_factor, 1 / resize_factor, z_scaling_factor])
116
+ mesh = MeshComponent.rotate_mesh(mesh)
118
117
 
119
118
  if apply_decimation:
120
119
  percent = decimation_percent / 100
@@ -122,4 +121,122 @@ class MeshComponent(Component):
122
121
  percent=percent, aggression=decimation_agression
123
122
  )
124
123
 
124
+ try:
125
+ if not mesh.is_watertight:
126
+ mesh = MeshComponent.fix_mesh(mesh)
127
+ except Exception:
128
+ pass
129
+
130
+ mesh = MeshComponent.mesh_to_output_size(
131
+ mesh,
132
+ resize_factor,
133
+ z_scaling_factor,
134
+ output_x_size,
135
+ skip_resize_to_expected_size=not include_zeros,
136
+ )
137
+
138
+ if remove_center:
139
+ mesh = MeshComponent.remove_center_from_mesh(mesh, remove_size)
140
+
125
141
  return mesh
142
+
143
+ @staticmethod
144
+ def rotate_mesh(mesh: trimesh.Trimesh) -> trimesh.Trimesh:
145
+ """Rotates the given mesh by 180 degrees around the Y-axis and Z-axis.
146
+
147
+ Arguments:
148
+ mesh (trimesh.Trimesh): The mesh to rotate.
149
+
150
+ Returns:
151
+ trimesh.Trimesh: The rotated mesh.
152
+ """
153
+ mesh_copy = mesh.copy()
154
+
155
+ rotation_matrices = [
156
+ trimesh.transformations.rotation_matrix(np.pi, [0, 1, 0]),
157
+ trimesh.transformations.rotation_matrix(np.pi, [0, 0, 1]),
158
+ ]
159
+
160
+ for rotation_matrix in tqdm(rotation_matrices, desc="Rotating mesh", unit="rotation"):
161
+ mesh_copy.apply_transform(rotation_matrix)
162
+
163
+ return mesh_copy
164
+
165
+ @staticmethod
166
+ def fix_mesh(mesh: trimesh.Trimesh) -> trimesh.Trimesh:
167
+ """Fixes the given mesh by filling holes, fixing normals, fixing winding, fixing inversion,
168
+ fixing broken faces, and stitching.
169
+
170
+ Arguments:
171
+ mesh (trimesh.Trimesh): The mesh to fix.
172
+
173
+ Returns:
174
+ trimesh.Trimesh: The fixed mesh.
175
+ """
176
+ mesh_copy = mesh.copy()
177
+
178
+ fix_methods = [
179
+ trimesh.repair.fill_holes,
180
+ trimesh.repair.fix_normals,
181
+ trimesh.repair.fix_winding,
182
+ trimesh.repair.fix_inversion,
183
+ trimesh.repair.broken_faces,
184
+ trimesh.repair.stitch,
185
+ ]
186
+
187
+ for method in tqdm(fix_methods, desc="Fixing mesh", unit="method"):
188
+ method(mesh_copy) # type: ignore
189
+
190
+ return mesh_copy
191
+
192
+ @staticmethod
193
+ def mesh_to_output_size(
194
+ mesh: trimesh.Trimesh,
195
+ resize_factor: int,
196
+ z_scaling_factor: float,
197
+ expected_size: int,
198
+ skip_resize_to_expected_size: bool = False,
199
+ ) -> trimesh.Trimesh:
200
+ """Resizes the given mesh to the expected size.
201
+
202
+ Arguments:
203
+ mesh (trimesh.Trimesh): The mesh to resize.
204
+ resize_factor (int): The resizing factor.
205
+ z_scaling_factor (float): The scaling factor for the Z-axis.
206
+ expected_size (int): The expected size.
207
+ skip_resize_to_expected_size (bool): Whether to skip resizing to the expected size.
208
+
209
+ Returns:
210
+ trimesh.Trimesh: The resized mesh.
211
+ """
212
+ mesh_copy = mesh.copy()
213
+
214
+ mesh_copy.apply_scale([resize_factor / 1, resize_factor / 1, z_scaling_factor])
215
+
216
+ if not skip_resize_to_expected_size:
217
+ x_size, y_size, _ = mesh_copy.extents
218
+ x_resize_factor = expected_size / x_size
219
+ y_resize_factor = expected_size / y_size
220
+
221
+ mesh_copy.apply_scale([x_resize_factor, y_resize_factor, 1])
222
+ return mesh_copy
223
+
224
+ @staticmethod
225
+ def remove_center_from_mesh(mesh: trimesh.Trimesh, remove_size: int) -> trimesh.Trimesh:
226
+ """Removes the center from the given mesh.
227
+
228
+ Arguments:
229
+ mesh (trimesh.Trimesh): The mesh to remove the center from.
230
+ remove_size (int): The size of the center to remove.
231
+
232
+ Returns:
233
+ trimesh.Trimesh: The mesh with the center removed.
234
+ """
235
+ mesh_copy = mesh.copy()
236
+
237
+ _, _, z_size = mesh_copy.extents
238
+
239
+ cube_mesh = trimesh.creation.box([remove_size, remove_size, z_size * 4])
240
+ cube_mesh.apply_translation(mesh_copy.centroid - cube_mesh.centroid)
241
+
242
+ return trimesh.boolean.difference([mesh_copy, cube_mesh], check_volume=False)
@@ -133,7 +133,7 @@ class BackgroundSettings(SettingsModel):
133
133
  generate_background: bool = False
134
134
  generate_water: bool = False
135
135
  resize_factor: int = 8
136
- remove_center: bool = False
136
+ remove_center: bool = True
137
137
  apply_decimation: bool = False
138
138
  decimation_percent: int = 25
139
139
  decimation_agression: int = 3
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: maps4fs
3
- Version: 1.8.172
3
+ Version: 1.8.173
4
4
  Summary: Generate map templates for Farming Simulator from real places.
5
5
  Author-email: iwatkot <iwatkot@gmail.com>
6
6
  License: MIT License
@@ -582,7 +582,7 @@ You can also apply some advanced settings to the map generation process.<br>
582
582
 
583
583
  - Resize factor - the factor by which the background terrain will be resized. It will be used as 1 / resize_factor while generating the models. Which means that the larger the value the more the terrain will be resized. The lowest value is 1, in this case background terrain will not be resized. Note, than low values will lead to long processing and enormous size of the obj files.
584
584
 
585
- - Remove center - if enabled, the playable region (map terrain) will be removed from the background terrain. Note, that it will require low resize factors, to avoid gaps between the map and the background terrain.
585
+ - Remove center - if enabled, the playable region (map terrain) will be removed from the background terrain. By default, it's set to True.
586
586
 
587
587
  - Apply decimation - if enabled, the mesh will be simplified to reduce the number of faces.
588
588
 
@@ -6,17 +6,17 @@ maps4fs/generator/game.py,sha256=YwtdzqwcBJm1FHtc1ehDd3WbfTTW_gBvxK-pzfU48zs,110
6
6
  maps4fs/generator/map.py,sha256=c5GMhr5iTRdXvTXoBKyVYa2V1tocR3ZCc7D_hpU21k8,11523
7
7
  maps4fs/generator/qgis.py,sha256=Es8hLuqN_KH8lDfnJE6He2rWYbAKJ3RGPn-o87S6CPI,6116
8
8
  maps4fs/generator/satellite.py,sha256=t33EfaxWTCjcKYnqoppSlFdQQSekiBe7UFmLgTVhFQI,3650
9
- maps4fs/generator/settings.py,sha256=sMyDY29fweF_Yo_buaUELFSYBYkOqf8VsZPL8lM8j1c,6271
9
+ maps4fs/generator/settings.py,sha256=cFlN-gK8QcySqyPtcGm-2fLnxQnlmC3Y9kQufJxwI3Y,6270
10
10
  maps4fs/generator/texture.py,sha256=_IfqIuxH4934VJXKtdABHa6ToPWk3T0xknvlu-rZ5Uc,36570
11
11
  maps4fs/generator/component/__init__.py,sha256=zZMLEkGzb4z0xql650gOtGSvcgX58DnJ2yN3vC2daRk,43
12
- maps4fs/generator/component/background.py,sha256=HWwQnZ5k-D4MdDSUdRvvNmWGUTtqps942DVGdpEQRoE,18947
12
+ maps4fs/generator/component/background.py,sha256=cBBp-ULrJzuNG9wfE_MaxzAn_mR24neqtL7WjxXEb3I,18749
13
13
  maps4fs/generator/component/config.py,sha256=RitKgFDZPzjA1fi8GcEi1na75qqaueUvpcITHjBvCXc,3674
14
14
  maps4fs/generator/component/grle.py,sha256=aKMjVJNuKHJJ2gsXaH00bz10kWaIbbZXU_JbP-ZAGw4,18990
15
15
  maps4fs/generator/component/i3d.py,sha256=3x38yL-kSJ8ylBwICBb6wPYzRSky4gVj8XCk2jzYSeo,19861
16
16
  maps4fs/generator/component/base/__init__.py,sha256=zZMLEkGzb4z0xql650gOtGSvcgX58DnJ2yN3vC2daRk,43
17
17
  maps4fs/generator/component/base/component.py,sha256=U3XJae0GUvHN08psv2j24Y4PBAAytSkSK3AmD-VjjXE,21404
18
18
  maps4fs/generator/component/base/component_image.py,sha256=vuiiJqsrKZgYsnK8Qa5yL2Pejqa6nJSTtXNAcBPL29c,3099
19
- maps4fs/generator/component/base/component_mesh.py,sha256=-9kmMX5KUULAIScygcrzmq8Cg643hiZ2IfSZOKiFfRs,4634
19
+ maps4fs/generator/component/base/component_mesh.py,sha256=jtsEQZkqiCkycYpueq1M1eqgxdShL_bHaJT6Upu8PLI,8412
20
20
  maps4fs/generator/component/base/component_xml.py,sha256=6OO1dKoceO1ACk7-k1oGtnkfNud8ZN3u3ZNjdNMpTqw,3967
21
21
  maps4fs/generator/dtm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
22
  maps4fs/generator/dtm/bavaria.py,sha256=7njrEvSCYAC8ZVyvS-_84iXHhWA0oHKrEqSzxdnZuGs,4293
@@ -42,8 +42,8 @@ maps4fs/toolbox/__init__.py,sha256=zZMLEkGzb4z0xql650gOtGSvcgX58DnJ2yN3vC2daRk,4
42
42
  maps4fs/toolbox/background.py,sha256=RclEqxEWLbMxuEkkegQP8jybzugwQ1_R3rdfDe0s21U,2104
43
43
  maps4fs/toolbox/custom_osm.py,sha256=X6ZlPqiOhNjkmdD_qVroIfdOl9Rb90cDwVSLDVYgx80,1892
44
44
  maps4fs/toolbox/dem.py,sha256=z9IPFNmYbjiigb3t02ZenI3Mo8odd19c5MZbjDEovTo,3525
45
- maps4fs-1.8.172.dist-info/LICENSE.md,sha256=pTKD_oUexcn-yccFCTrMeLkZy0ifLRa-VNcDLqLZaIw,10749
46
- maps4fs-1.8.172.dist-info/METADATA,sha256=E5nc98xim9woImXF8JqFv44PLOjeqiBHhqdFfB8H3WA,43012
47
- maps4fs-1.8.172.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
48
- maps4fs-1.8.172.dist-info/top_level.txt,sha256=Ue9DSRlejRQRCaJueB0uLcKrWwsEq9zezfv5dI5mV1M,8
49
- maps4fs-1.8.172.dist-info/RECORD,,
45
+ maps4fs-1.8.173.dist-info/LICENSE.md,sha256=pTKD_oUexcn-yccFCTrMeLkZy0ifLRa-VNcDLqLZaIw,10749
46
+ maps4fs-1.8.173.dist-info/METADATA,sha256=juPm5cwfn3XLlaUemJjP43yHQbW-9NYEljrHscMlGN4,42937
47
+ maps4fs-1.8.173.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
48
+ maps4fs-1.8.173.dist-info/top_level.txt,sha256=Ue9DSRlejRQRCaJueB0uLcKrWwsEq9zezfv5dI5mV1M,8
49
+ maps4fs-1.8.173.dist-info/RECORD,,