diff --git a/docs/Background/geography/loot_locations.md b/docs/Background/geography/loot_locations.md
index dc5fd14..844a990 100644
--- a/docs/Background/geography/loot_locations.md
+++ b/docs/Background/geography/loot_locations.md
@@ -13,104 +13,4 @@ included in the list solely to contain a geotag to be used on the auto-rendered
Super Markets are a great place to find food, medicine, and other useful items.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/mkdocs.yml b/mkdocs.yml
index aa68d30..7a0499b 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -114,11 +114,16 @@ plugins:
- search
hooks:
+ - render_map/auto_populate/auto_populate_hooks.py
- render_map/plugin_hooks.py
extra:
# GOOGLE_MAPS_API_KEY: !ENV GOOGLE_MAPS_API_KEY # ReadTheDocs doesn't support loading from env variables!
GOOGLE_MAPS_API_KEY: AIzaSyD6gTw8OwC-LyQi3wl_gr8P385pPBfa5tE
+ # Center and default zoom level for the Google Maps
global_map:
center: [29.7604, -95.3698]
- zoom: 9
\ No newline at end of file
+ zoom: 9
+ auto_populate:
+ center: [29.7604, -95.3698]
+ population_radius: 35000 # Radius around the center to auto-populate locations (in meters)
\ No newline at end of file
diff --git a/render_map/auto_populate/__init__.py b/render_map/auto_populate/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/render_map/auto_populate/auto_populate_hooks.py b/render_map/auto_populate/auto_populate_hooks.py
new file mode 100644
index 0000000..a947481
--- /dev/null
+++ b/render_map/auto_populate/auto_populate_hooks.py
@@ -0,0 +1,34 @@
+from __future__ import annotations
+
+import mkdocs.plugins
+
+from render_map.auto_populate import auto_populate_map
+
+@mkdocs.plugins.event_priority(100)
+def on_page_markdown(
+ markdown: str,
+ page: mkdocs.plugins.Page,
+ config: mkdocs.plugins.MkDocsConfig,
+ **kwargs,
+):
+ """Find all geotags in the markdown and process them into a list of GeoLink objects.
+
+ Args:
+ markdown: The markdown to search for geotags.
+ page: The page object.
+ config: The mkdocs config.
+
+ Returns:
+ A list of GeoLink objects.
+ """
+ # Skip, if page is excluded
+ if page.file.inclusion.is_excluded():
+ return
+
+ latitude, longitude = config.extra["auto_populate"]["center"]
+ radius = config.extra["auto_populate"]["population_radius"]
+
+ geolinks, markdown = auto_populate_map.find_auto_populate_geotags(markdown, latitude, longitude, radius)
+
+ return markdown
+
diff --git a/render_map/auto_populate_map.py b/render_map/auto_populate/auto_populate_map.py
similarity index 54%
rename from render_map/auto_populate_map.py
rename to render_map/auto_populate/auto_populate_map.py
index 8ba256c..6931751 100644
--- a/render_map/auto_populate_map.py
+++ b/render_map/auto_populate/auto_populate_map.py
@@ -1,7 +1,10 @@
"""Automatically populate the map with supermarkets and other landmarks using the Overpass (Open Street Map) API."""
from __future__ import annotations
+import bs4
import overpy
+import pydantic
+
from render_map import mapping
RADIUS=35000
@@ -21,6 +24,65 @@
API = overpy.Overpass()
+class AutoPopulateConfig(pydantic.BaseModel):
+ """The configuration for the auto-populate plugin."""
+
+ supermarket: bool = False
+
+ @staticmethod
+ def tag_name() -> str:
+ """The name of the tag to search for."""
+ return "populate_geotag"
+
+ @classmethod
+ def from_dict(cls, config_dict: dict[str, str|bool]) -> AutoPopulateConfig:
+ """Create a config object from a dictionary.
+
+ Args:
+ config_dict: The dictionary to create the config object from.
+
+ Returns:
+ A config object.
+ """
+ for key in cls.model_fields:
+ if key in config_dict:
+ config_dict[key] = True
+ return cls(**config_dict)
+
+def find_auto_populate_geotags(markdown: str, latitude:float, longitude:float, radius:float) -> tuple[list[AutoPopulateConfig], str]:
+ """Find all geotags in the markdown and process them into a list of GeoLink objects.
+
+ Args:
+ markdown: The markdown to search for geotags.
+ latitude: The latitude to search for supermarkets.
+ longitude: The longitude to search for supermarkets.
+ radius: The radius in meters to search for supermarkets.
+
+ Returns:
+ A list of GeoLink objects and the markdown with the geotags replaced.
+ """
+ soup = bs4.BeautifulSoup(markdown, "html.parser")
+ geo_tags = soup.find_all(AutoPopulateConfig.tag_name())
+
+ populate_geotags_configs = []
+ for geo_tag in geo_tags:
+ result = geo_tag.attrs
+
+ # Generate a GeoLink object from the result
+ geotag_config = AutoPopulateConfig.from_dict(result)
+ populate_geotags_configs.append(geotag_config)
+
+ # Replace the geotag with a span tag with the uuid as the id and the name as the text
+ new_tag = soup.new_tag("div")
+ if geotag_config.supermarket:
+ supermarkets_tags = populate_supermarkets(radius, latitude, longitude)
+ for tag in supermarkets_tags:
+ new_tag.append(tag)
+ new_tag.append(", ")
+ geo_tag.replace_with(new_tag)
+ return populate_geotags_configs, str(soup)
+
+
def choose_supermarket_name_zoom(node:overpy.Node) -> tuple[str|None, mapping.ZoomLevel]:
"""Choose the game name and map zoom level for a supermarket, based on the properties of the supermarket in the
real world.
@@ -43,7 +105,7 @@ def choose_supermarket_name_zoom(node:overpy.Node) -> tuple[str|None, mapping.Zo
return "Supermarket", mapping.ZoomLevel.TOWN
-def populate_supermarkets(radius:float, latitude:float, longitude:float) -> str:
+def populate_supermarkets(radius:float, latitude:float, longitude:float) -> list[bs4.Tag]:
"""Generate geotags for supermarkets in the game world, using the locations of supermarkets in the real world (using
the Overpass API).
@@ -67,4 +129,4 @@ def populate_supermarkets(radius:float, latitude:float, longitude:float) -> str:
)
)
- return "\n".join(geotag.get_tag() for geotag in geotags)
\ No newline at end of file
+ return [geotag.get_tag() for geotag in geotags]
diff --git a/render_map/mapping.py b/render_map/mapping.py
index b8c3fd7..dd9bac4 100644
--- a/render_map/mapping.py
+++ b/render_map/mapping.py
@@ -54,7 +54,7 @@ class GeoLink(pydantic.BaseModel):
zoom: ZoomLevel = pydantic.Field(default=ZoomLevel.WASTELAND, validate_default=True)
uuid: str = pydantic.Field(default_factory=lambda: str(uuid.uuid4()))
- def get_tag(self, include_uuid:bool=False) -> str:
+ def get_tag(self, include_uuid:bool=False) -> bs4.Tag:
"""Get the geotag as a string.
Args:
@@ -68,12 +68,12 @@ def get_tag(self, include_uuid:bool=False) -> str:
tag["name"] = self.name
tag["latitude"] = str(self.latitude)
tag["longitude"] = str(self.longitude)
- tag["icon"] = self.icon.name
- tag["zoom"] = str(self.zoom.name)
+ tag["icon"] = str(map_icons.MapIcon(self.icon).name)
+ tag["zoom"] = str(ZoomLevel(self.zoom).name)
if include_uuid:
tag["uuid"] = self.uuid
- return str(tag)
+ return tag
GEO_LINKS: list[GeoLink] = []