diff --git a/src/terrain_management/large_scale_terrain/crater_distribution.py b/src/terrain_management/large_scale_terrain/crater_distribution.py index a10d52b..ba19c1b 100644 --- a/src/terrain_management/large_scale_terrain/crater_distribution.py +++ b/src/terrain_management/large_scale_terrain/crater_distribution.py @@ -12,8 +12,12 @@ import dataclasses import numpy as np import colorsys +import logging import pickle +logger = logging.getLogger(__name__) +logging.basicConfig(format="%(asctime)s %(message)s", datefmt="%m/%d/%Y %I:%M:%S %p") + from src.terrain_management.large_scale_terrain.utils import BoundingBox, CraterMetadata from src.terrain_management.large_scale_terrain.crater_database import CraterDB @@ -344,7 +348,7 @@ def build(self) -> None: spline profiles are generated only once and cached inside the database. """ - print("Warming up crater generation...") + logger.debug("Warming up crater generation...") self.generate_deformation_profiles() self.generate_marking_profiles() self.load_profiles() @@ -384,7 +388,7 @@ def generate_deformation_profiles(self) -> None: Generates the deformation profiles for the craters. """ - print("Pre-generating crater deformation profiles") + logger.debug("Pre-generating crater deformation profiles") for i in range(self.settings.num_unique_profiles): deformation_profile = self._rng.uniform(0.95, 1, 9) deformation_profile = np.concatenate([deformation_profile, [deformation_profile[0]]], axis=0) @@ -396,7 +400,7 @@ def generate_marking_profiles(self) -> None: Generates the marking profiles for the craters. """ - print("Pre-generating crater marking profiles") + logger.debug("Pre-generating crater marking profiles") for i in range(self.settings.num_unique_profiles): # Generates a profile to add marks that converges toward the center of the crater marks_profile = self._rng.uniform(0.0, 0.01, 45) @@ -409,7 +413,7 @@ def load_profiles(self) -> None: Loads the half crater spline profiles from a pickle file. """ - print("Loading crater profiles") + logger.debug("Loading crater profiles") with open(self.settings.profiles_path, "rb") as handle: self.crater_profiles = pickle.load(handle) diff --git a/src/terrain_management/large_scale_terrain/geometry_clipmaps_numba.py b/src/terrain_management/large_scale_terrain/geometry_clipmaps_numba.py index d7edbc4..5680601 100644 --- a/src/terrain_management/large_scale_terrain/geometry_clipmaps_numba.py +++ b/src/terrain_management/large_scale_terrain/geometry_clipmaps_numba.py @@ -8,6 +8,10 @@ import numba as nb import numpy as np +import logging + +logger = logging.getLogger(__name__) +logging.basicConfig(format="%(asctime)s %(message)s", datefmt="%m/%d/%Y %I:%M:%S %p") point3 = nb.types.UniTuple(nb.types.float32, 3) point2 = nb.types.UniTuple(nb.types.float32, 2) @@ -143,7 +147,7 @@ def _build_mesh(start_level, num_levels, meshBaseLODExtentHeightfieldTexels): coordinates, and list of indices in the mesh backbone. """ - print("Building the mesh backbone, this may take time...") + logger.info("Building the mesh backbone, this may take time...") points = nb.typed.List.empty_list(point3) uvs = nb.typed.List.empty_list(point2) indices = nb.typed.List.empty_list(nb.types.int32) @@ -151,7 +155,7 @@ def _build_mesh(start_level, num_levels, meshBaseLODExtentHeightfieldTexels): new_indices = nb.typed.Dict.empty(key_type=point2, value_type=nb.types.int32) index_count = 0 for level in range(start_level, num_levels): - print("Generating level " + str(level + 1) + " out of " + str(num_levels) + "...") + logger.info("Generating level " + str(level + 1) + " out of " + str(num_levels) + "...") step = 1 << level if level == 0: prevStep = 0 diff --git a/src/terrain_management/large_scale_terrain/map_manager.py b/src/terrain_management/large_scale_terrain/map_manager.py index 2ac0c87..68f578a 100644 --- a/src/terrain_management/large_scale_terrain/map_manager.py +++ b/src/terrain_management/large_scale_terrain/map_manager.py @@ -9,12 +9,15 @@ from typing import Tuple import dataclasses import numpy as np -import warnings +import logging import math import yaml import time import os +logger = logging.getLogger(__name__) +logging.basicConfig(format="%(asctime)s %(message)s", datefmt="%m/%d/%Y %I:%M:%S %p") + from src.terrain_management.large_scale_terrain.high_resolution_DEM_generator import ( HighResDEMGen, ) @@ -61,15 +64,22 @@ class MapManager: interract with the DEMs. """ - def __init__(self, map_manager_settings: MapManagerConf, is_simulation_alive: callable = lambda: True) -> None: + def __init__( + self, + map_manager_settings: MapManagerConf, + is_simulation_alive: callable = lambda: True, + close_simulation: callable = lambda: None, + ) -> None: """ Args: map_manager_settings (MapManagerConf): settings for the map manager. is_simulation_alive (callable): function to check if the simulation is alive. + close_simulation (callable): function to close the simulation. """ self.hr_dem_settings = map_manager_settings.hrdem_settings self.is_simulation_alive = is_simulation_alive + self.close_simulation = close_simulation self.settings = map_manager_settings self.lr_dem = None @@ -112,18 +122,18 @@ def fetch_pregenerated_lr_dems(self) -> None: if os.path.exists(dem_path): self.dem_paths[folder] = dem_path else: - warnings.warn( + logger.warn( f"DEM {dem_path} does not exist. Expected to find dem.npy in the folder but could not find it." ) if os.path.exists(dem_info_path): with open(dem_info_path, "r") as file: self.dem_infos[folder] = DemInfo(**yaml.safe_load(file)) else: - warnings.warn( + logger.warn( f"DEM info {dem_info_path} does not exist. Expected to find dem.yaml in the folder but could not find it." ) else: - warnings.warn(f"Folder {folder} is not a directory.") + logger.warn(f"Folder {folder} is not a directory.") def load_lr_dem_by_name(self, name: str) -> None: """ @@ -140,13 +150,18 @@ def load_lr_dem_by_name(self, name: str) -> None: else: raise ValueError(f"DEM info {name} does not exist in the folder path {self.settings.folder_path}") else: - warnings.warn(f"DEM {name} does not exist in the folder path {self.settings.folder_path}") + logger.warn(f"DEM {name} does not exist in the folder path {self.settings.folder_path}") # Override the source resolution lr_dem_res = self.lr_dem_info.pixel_size[0] self.hr_dem_settings.high_res_dem_cfg.source_resolution = lr_dem_res self.hr_dem_settings.interpolator_cfg.source_resolution = lr_dem_res - self.hr_dem_gen = HighResDEMGen(self.lr_dem, self.hr_dem_settings) + self.hr_dem_gen = HighResDEMGen( + self.lr_dem, + self.hr_dem_settings, + is_simulation_alive=self.is_simulation_alive, + close_simulation=self.close_simulation, + ) def load_lr_dem_by_path(self, path: str) -> None: """ @@ -168,7 +183,12 @@ def load_lr_dem_by_path(self, path: str) -> None: lr_dem_res = self.lr_dem_info.pixel_size[0] self.hr_dem_settings.high_res_dem_cfg.source_resolution = lr_dem_res self.hr_dem_settings.interpolator_cfg.source_resolution = lr_dem_res - self.hr_dem_gen = HighResDEMGen(self.lr_dem, self.hr_dem_settings) + self.hr_dem_gen = HighResDEMGen( + self.lr_dem, + self.hr_dem_settings, + is_simulation_alive=self.is_simulation_alive, + close_simulation=self.close_simulation, + ) def load_lr_dem_by_id(self, id: int) -> None: """ @@ -179,7 +199,7 @@ def load_lr_dem_by_id(self, id: int) -> None: id (int): id of the DEM to load. """ - warnings.warn("load_lr_dem_by_id is a legacy method and should not be used. Use load_lr_dem_by_name instead.") + logger.warn("load_lr_dem_by_id is a legacy method and should not be used. Use load_lr_dem_by_name instead.") if id in list(range(len(self.dem_paths.keys()))): key = list(self.dem_paths.keys())[id] self.lr_dem = self.load(self.dem_paths[key]) @@ -193,7 +213,12 @@ def load_lr_dem_by_id(self, id: int) -> None: lr_dem_res = self.lr_dem_info.pixel_size[0] self.hr_dem_settings.high_res_dem_cfg.source_resolution = lr_dem_res self.hr_dem_settings.interpolator_cfg.source_resolution = lr_dem_res - self.hr_dem_gen = HighResDEMGen(self.lr_dem, self.hr_dem_settings) + self.hr_dem_gen = HighResDEMGen( + self.lr_dem, + self.hr_dem_settings, + is_simulation_alive=self.is_simulation_alive, + close_simulation=self.close_simulation, + ) def generate_procedural_lr_dem(self): """ @@ -374,13 +399,13 @@ def initialize_hr_dem(self, coordinates: Tuple[float, float]) -> None: coordinates (Tuple[float,float]): coordinates in meters. """ - print("Initializing HR DEM") + logger.info("Initializing HR DEM") start = time.time() self.update_hr_dem(coordinates) while not self.is_hr_dem_updated(): time.sleep(0.1) end = time.time() - print(f"HR DEM initialized in {end - start} seconds") + logger.info(f"HR DEM initialized in {end - start} seconds") def is_hr_dem_updated(self) -> bool: """ diff --git a/src/terrain_management/large_scale_terrain/rock_manager.py b/src/terrain_management/large_scale_terrain/rock_manager.py index c7c1c38..44c1fd5 100644 --- a/src/terrain_management/large_scale_terrain/rock_manager.py +++ b/src/terrain_management/large_scale_terrain/rock_manager.py @@ -10,7 +10,7 @@ import numpy as np import dataclasses import threading -import warnings +import logging import time import os @@ -30,6 +30,9 @@ from pxr import UsdGeom, Gf, Usd, Vt, Sdf +logger = logging.getLogger(__name__) +logging.basicConfig(format="%(asctime)s %(message)s", datefmt="%m/%d/%Y %I:%M:%S %p") + class Instancer: """ @@ -99,9 +102,9 @@ def load_material(self): self.material_path = load_material(self.texture_name, self.texture_path) self.apply_material = True elif (self.texture_name is not None) and (self.texture_path is None): - warnings.warn("Texture path not provided. Material will not be loaded.") + logger.warn("Texture path not provided. Material will not be loaded.") elif (self.texture_name is None) and (self.texture_path is not None): - warnings.warn("Texture name not provided. Material will not be loaded.") + logger.warn("Texture name not provided. Material will not be loaded.") def apply_semantic_label(self, prim_path: Usd.Prim): prim_sd = PrimSemanticData(self.stage.GetPrimAtPath(prim_path)) @@ -156,7 +159,7 @@ def set_instancer_parameters( try: self.update_extent() except Exception as e: - print("Error updating extent", e) + logger.warn("Error updating extent", e) def update_extent(self) -> None: """ @@ -244,9 +247,9 @@ def load_material(self): self.material_path = load_material(self.texture_name, self.texture_path) self.apply_material = True elif (self.texture_name is not None) and (self.texture_path is None): - warnings.warn("Texture path not provided. Material will not be loaded.") + logger.warn("Texture path not provided. Material will not be loaded.") elif (self.texture_name is None) and (self.texture_path is not None): - warnings.warn("Texture name not provided. Material will not be loaded.") + logger.warn("Texture name not provided. Material will not be loaded.") def apply_semantic_label(self, prim_path: Usd.Prim): prim_sd = PrimSemanticData(self.stage.GetPrimAtPath(prim_path)) @@ -424,9 +427,9 @@ def load_material(self): self.material_path = load_material(self.texture_name, self.texture_path) self.apply_material = True elif (self.texture_name is not None) and (self.texture_path is None): - warnings.warn("Texture path not provided. Material will not be loaded.") + logger.warn("Texture path not provided. Material will not be loaded.") elif (self.texture_name is None) and (self.texture_path is not None): - warnings.warn("Texture name not provided. Material will not be loaded.") + logger.warn("Texture name not provided. Material will not be loaded.") def apply_semantic_label(self, prim_path: Usd.Prim): prim_sd = PrimSemanticData(self.stage.GetPrimAtPath(prim_path)) diff --git a/src/terrain_management/large_scale_terrain/utils.py b/src/terrain_management/large_scale_terrain/utils.py index 195c761..4fd79ec 100644 --- a/src/terrain_management/large_scale_terrain/utils.py +++ b/src/terrain_management/large_scale_terrain/utils.py @@ -11,9 +11,13 @@ import dataclasses import numpy as np import threading +import logging import time import zfpy +logger = logging.getLogger(__name__) +logging.basicConfig(format="%(asctime)s %(message)s", datefmt="%m/%d/%Y %I:%M:%S %p") + @dataclasses.dataclass class BoundingBox: @@ -149,6 +153,6 @@ def __exit__(self, exc_type, exc_value, traceback): # If we are back to the outermost level, print all accumulated messages if self._thread_local_data.nesting_level == 0: for msg in self._thread_local_data.messages: - print(msg) + logger.info(msg) # Clear the message stack self._thread_local_data.messages.clear() diff --git a/src/terrain_management/large_scale_terrain_manager.py b/src/terrain_management/large_scale_terrain_manager.py index 0d2a673..1c7434d 100644 --- a/src/terrain_management/large_scale_terrain_manager.py +++ b/src/terrain_management/large_scale_terrain_manager.py @@ -33,9 +33,11 @@ def __init__( self, settings: LargeScaleTerrainConf, is_simulation_alive: callable = lambda: True, + close_simulation: callable = lambda: None, ): self.settings = settings self.is_simulation_alive = is_simulation_alive + self.close_simulation = close_simulation self.last_update_coordinates = None def build_configs(self): @@ -51,7 +53,9 @@ def build_managers(self): self.build_rock_manager() def build_map_manager(self): - self.map_manager = MapManager(self.mapmanager_cfg, is_simulation_alive = self.is_simulation_alive) + self.map_manager = MapManager( + self.mapmanager_cfg, is_simulation_alive=self.is_simulation_alive, close_simulation=self.close_simulation + ) self.map_manager.load_lr_dem_by_name(self.settings.lr_dem_name) self.map_manager.initialize_hr_dem(self.settings.starting_position)