maps4fs 1.3.6__py3-none-any.whl → 1.3.8__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.
maps4fs/generator/map.py CHANGED
@@ -79,7 +79,7 @@ class TextureSettings(NamedTuple):
79
79
  skip_drains: bool = False
80
80
 
81
81
 
82
- # pylint: disable=R0913, R0902
82
+ # pylint: disable=R0913, R0902, R0914
83
83
  class Map:
84
84
  """Class used to generate map using all components.
85
85
 
@@ -99,6 +99,7 @@ class Map:
99
99
  rotation: int,
100
100
  map_directory: str,
101
101
  logger: Any = None,
102
+ custom_osm: str | None = None,
102
103
  dem_settings: DEMSettings = DEMSettings(),
103
104
  background_settings: BackgroundSettings = BackgroundSettings(),
104
105
  grle_settings: GRLESettings = GRLESettings(),
@@ -126,6 +127,9 @@ class Map:
126
127
 
127
128
  self.logger.info("Game was set to %s", game.code)
128
129
 
130
+ self.custom_osm = custom_osm
131
+ self.logger.info("Custom OSM file: %s", custom_osm)
132
+
129
133
  self.dem_settings = dem_settings
130
134
  self.logger.info("DEM settings: %s", dem_settings)
131
135
  self.background_settings = background_settings
@@ -372,7 +372,7 @@ class Texture(Component):
372
372
  ),
373
373
  )
374
374
 
375
- # pylint: disable=no-member
375
+ # pylint: disable=no-member, R0912
376
376
  def draw(self) -> None:
377
377
  """Iterates over layers and fills them with polygons from OSM data."""
378
378
  layers = self.layers_by_priority()
@@ -409,11 +409,23 @@ class Texture(Component):
409
409
 
410
410
  mask = cv2.bitwise_not(cumulative_image)
411
411
 
412
- for polygon in self.polygons(layer.tags, layer.width, layer.info_layer): # type: ignore
412
+ for polygon in self.objects_generator( # type: ignore
413
+ layer.tags, layer.width, layer.info_layer
414
+ ):
413
415
  if layer.info_layer:
414
- info_layer_data[layer.info_layer].append(self.np_to_polygon_points(polygon))
416
+ info_layer_data[layer.info_layer].append(
417
+ self.np_to_polygon_points(polygon) # type: ignore
418
+ )
415
419
  cv2.fillPoly(layer_image, [polygon], color=255) # type: ignore
416
420
 
421
+ if layer.info_layer == "roads":
422
+ for linestring in self.objects_generator(
423
+ layer.tags, layer.width, layer.info_layer, yield_linestrings=True
424
+ ):
425
+ info_layer_data[f"{layer.info_layer}_polylines"].append(
426
+ linestring # type: ignore
427
+ )
428
+
417
429
  output_image = cv2.bitwise_and(layer_image, mask)
418
430
 
419
431
  cumulative_image = cv2.bitwise_or(cumulative_image, output_image)
@@ -422,8 +434,16 @@ class Texture(Component):
422
434
  self.logger.debug("Texture %s saved.", layer_path)
423
435
 
424
436
  # Save info layer data.
437
+ if os.path.isfile(self.info_layer_path):
438
+ self.logger.debug(
439
+ "File %s already exists, will update to avoid overwriting.", self.info_layer_path
440
+ )
441
+ with open(self.info_layer_path, "r", encoding="utf-8") as f:
442
+ info_layer_data.update(json.load(f))
443
+
425
444
  with open(self.info_layer_path, "w", encoding="utf-8") as f:
426
445
  json.dump(info_layer_data, f, ensure_ascii=False, indent=4)
446
+ self.logger.debug("Info layer data saved to %s.", self.info_layer_path)
427
447
 
428
448
  if cumulative_image is not None:
429
449
  self.draw_base_layer(cumulative_image)
@@ -617,31 +637,73 @@ class Texture(Component):
617
637
  converters = {"Polygon": self._skip, "LineString": self._sequence, "Point": self._sequence}
618
638
  return converters.get(geom_type) # type: ignore
619
639
 
620
- def polygons(
640
+ def objects_generator(
621
641
  self,
622
642
  tags: dict[str, str | list[str] | bool],
623
643
  width: int | None,
624
644
  info_layer: str | None = None,
625
- ) -> Generator[np.ndarray, None, None]:
645
+ yield_linestrings: bool = False,
646
+ ) -> Generator[np.ndarray, None, None] | Generator[list[tuple[int, int]], None, None]:
626
647
  """Generator which yields numpy arrays of polygons from OSM data.
627
648
 
628
649
  Arguments:
629
650
  tags (dict[str, str | list[str]]): Dictionary of tags to search for.
630
651
  width (int | None): Width of the polygon in meters (only for LineString).
631
652
  info_layer (str | None): Name of the corresponding info layer.
653
+ yield_linestrings (bool): Flag to determine if the LineStrings should be yielded.
632
654
 
633
655
  Yields:
634
- Generator[np.ndarray, None, None]: Numpy array of polygon points.
656
+ Generator[np.ndarray, None, None] | Generator[list[tuple[int, int]], None, None]:
657
+ Numpy array of polygon points or list of point coordinates.
635
658
  """
636
659
  is_fieds = info_layer == "fields"
637
660
  try:
638
- objects = ox.features_from_bbox(bbox=self.new_bbox, tags=tags)
661
+ if self.map.custom_osm is not None:
662
+ objects = ox.features_from_xml(self.map.custom_osm, tags=tags)
663
+ else:
664
+ objects = ox.features_from_bbox(bbox=self.new_bbox, tags=tags)
639
665
  except Exception: # pylint: disable=W0718
640
666
  self.logger.debug("Error fetching objects for tags: %s.", tags)
641
667
  return
642
668
  objects_utm = ox.projection.project_gdf(objects, to_latlong=False)
643
669
  self.logger.debug("Fetched %s elements for tags: %s.", len(objects_utm), tags)
644
670
 
671
+ method = self.linestrings_generator if yield_linestrings else self.polygons_generator
672
+
673
+ yield from method(objects_utm, width, is_fieds)
674
+
675
+ def linestrings_generator(
676
+ self, objects_utm: pd.core.frame.DataFrame, *args, **kwargs
677
+ ) -> Generator[list[tuple[int, int]], None, None]:
678
+ """Generator which yields lists of point coordinates which represent LineStrings from OSM.
679
+
680
+ Arguments:
681
+ objects_utm (pd.core.frame.DataFrame): Dataframe with OSM objects in UTM format.
682
+
683
+ Yields:
684
+ Generator[list[tuple[int, int]], None, None]: List of point coordinates.
685
+ """
686
+ for _, obj in objects_utm.iterrows():
687
+ geometry = obj["geometry"]
688
+ if isinstance(geometry, shapely.geometry.linestring.LineString):
689
+ points = [
690
+ (self.get_relative_x(x), self.get_relative_y(y)) for x, y in geometry.coords
691
+ ]
692
+ yield points
693
+
694
+ def polygons_generator(
695
+ self, objects_utm: pd.core.frame.DataFrame, width: int | None, is_fieds: bool
696
+ ) -> Generator[np.ndarray, None, None]:
697
+ """Generator which yields numpy arrays of polygons from OSM data.
698
+
699
+ Arguments:
700
+ objects_utm (pd.core.frame.DataFrame): Dataframe with OSM objects in UTM format.
701
+ width (int | None): Width of the polygon in meters (only for LineString).
702
+ is_fieds (bool): Flag to determine if the fields should be padded.
703
+
704
+ Yields:
705
+ Generator[np.ndarray, None, None]: Numpy array of polygon points.
706
+ """
645
707
  for _, obj in objects_utm.iterrows():
646
708
  polygon = self._to_polygon(obj, width)
647
709
  if polygon is None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: maps4fs
3
- Version: 1.3.6
3
+ Version: 1.3.8
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
@@ -72,6 +72,7 @@ Requires-Dist: pympler
72
72
  🌲 Automatically generates forests 🆕<br>
73
73
  🌊 Automatically generates water planes 🆕<br>
74
74
  🌍 Based on real-world data from OpenStreetMap<br>
75
+ 🗺️ Supports [custom OSM maps](/docs/custom_osm.md)<br>
75
76
  🏞️ Generates height map using SRTM dataset<br>
76
77
  📦 Provides a ready-to-use map template for the Giants Editor<br>
77
78
  🚜 Supports Farming Simulator 22 and 25<br>
@@ -528,3 +529,4 @@ But also, I want to thank the people who helped me with the project in some way,
528
529
  - [BFernaesds](https://github.com/BFernaesds) - for the manual tests of the app.
529
530
  - [gamerdesigns](https://github.com/gamerdesigns) - for the manual tests of the app.
530
531
  - [Tox3](https://github.com/Tox3) - for the manual tests of the app.
532
+ - [Lucandia](https://github.com/Lucandia) - for the awesome StreamLit [widget to preview STL files](https://github.com/Lucandia/streamlit_stl).
@@ -8,14 +8,14 @@ maps4fs/generator/dem.py,sha256=MZf3ZjawJ977TxqB1q9nNpvPZUNwfmm2EaJDtVU-eCU,1593
8
8
  maps4fs/generator/game.py,sha256=ZQeYzPzPB3CG41avdhNCyTZpHEeedqNBuAbNevTZuXg,7931
9
9
  maps4fs/generator/grle.py,sha256=xKIpyhYsZol-IXcBULbX7wWZ1n83BWTZqaf8FLodchE,17499
10
10
  maps4fs/generator/i3d.py,sha256=bW7FLAISFKCPUmad7ANz1loWI07oEZlEQOEL_tv0YmQ,18483
11
- maps4fs/generator/map.py,sha256=a-nwDsKq6u9RLB2htueXtJtdDZbocpj_KxGhBw5AoEI,8776
11
+ maps4fs/generator/map.py,sha256=VEcsh-nvJ8kF1NevBwNS0tW5oiLP8gIF61ttz6XrOHc,8920
12
12
  maps4fs/generator/qgis.py,sha256=Es8hLuqN_KH8lDfnJE6He2rWYbAKJ3RGPn-o87S6CPI,6116
13
- maps4fs/generator/texture.py,sha256=tNhv-_AOrv4Wf7knbrN9LZBkvApgsrGffGPAzZScr7g,27745
13
+ maps4fs/generator/texture.py,sha256=xfZejaAOrd0wmi_f2a4uLqJgEIPDJj9UHw0kwLZsGL0,30629
14
14
  maps4fs/toolbox/__init__.py,sha256=zZMLEkGzb4z0xql650gOtGSvcgX58DnJ2yN3vC2daRk,43
15
15
  maps4fs/toolbox/background.py,sha256=9BXWNqs_n3HgqDiPztWylgYk_QM4YgBpe6_ZNQAWtSc,2154
16
16
  maps4fs/toolbox/dem.py,sha256=z9IPFNmYbjiigb3t02ZenI3Mo8odd19c5MZbjDEovTo,3525
17
- maps4fs-1.3.6.dist-info/LICENSE.md,sha256=pTKD_oUexcn-yccFCTrMeLkZy0ifLRa-VNcDLqLZaIw,10749
18
- maps4fs-1.3.6.dist-info/METADATA,sha256=pczjM5FWcRCAJiNtW3JRwl0SeNYEAlQUwc1V2UWyjtY,31082
19
- maps4fs-1.3.6.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
20
- maps4fs-1.3.6.dist-info/top_level.txt,sha256=Ue9DSRlejRQRCaJueB0uLcKrWwsEq9zezfv5dI5mV1M,8
21
- maps4fs-1.3.6.dist-info/RECORD,,
17
+ maps4fs-1.3.8.dist-info/LICENSE.md,sha256=pTKD_oUexcn-yccFCTrMeLkZy0ifLRa-VNcDLqLZaIw,10749
18
+ maps4fs-1.3.8.dist-info/METADATA,sha256=IBhWOyO8IfX1f32hNSpTzkRFpTkx9YKlUZU0ctGUQHE,31286
19
+ maps4fs-1.3.8.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
20
+ maps4fs-1.3.8.dist-info/top_level.txt,sha256=Ue9DSRlejRQRCaJueB0uLcKrWwsEq9zezfv5dI5mV1M,8
21
+ maps4fs-1.3.8.dist-info/RECORD,,