84 lines
2.4 KiB
Python
84 lines
2.4 KiB
Python
"""utility functions"""
|
|
|
|
from pathlib import Path
|
|
import re
|
|
from typing import Any, Callable, Tuple
|
|
|
|
import numpy as np
|
|
|
|
from timezonefinder.configs import (
|
|
DEFAULT_DATA_DIR,
|
|
OCEAN_TIMEZONE_PREFIX,
|
|
)
|
|
from timezonefinder import utils_numba, utils_clang
|
|
|
|
|
|
# make numba functions available via utils
|
|
using_numba = utils_numba.using_numba
|
|
clang_extension_loaded = utils_clang.clang_extension_loaded
|
|
is_valid_lat = utils_numba.is_valid_lat
|
|
is_valid_lng = utils_numba.is_valid_lng
|
|
coord2int = utils_numba.coord2int
|
|
int2coord = utils_numba.int2coord
|
|
convert2coords = utils_numba.convert2coords
|
|
convert2coord_pairs = utils_numba.convert2coord_pairs
|
|
get_last_change_idx = utils_numba.get_last_change_idx
|
|
|
|
|
|
inside_polygon: Callable[[int, int, np.ndarray], bool]
|
|
# at import time fix which "point-in-polygon" implementation will be used
|
|
if clang_extension_loaded and not using_numba:
|
|
# use the C implementation only if Numba is not present
|
|
inside_polygon = utils_clang.pt_in_poly_clang
|
|
else:
|
|
# use the (JIT compiled) python function if Numba is present or the C extension cannot be loaded
|
|
inside_polygon = utils_numba.pt_in_poly_python
|
|
|
|
|
|
def validate_lat(lat: float) -> None:
|
|
if not is_valid_lat(lat):
|
|
raise ValueError(f"The given latitude {lat} is out of bounds")
|
|
|
|
|
|
def validate_lng(lng: float) -> None:
|
|
if not is_valid_lng(lng):
|
|
raise ValueError(f"The given longitude {lng} is out of bounds")
|
|
|
|
|
|
def validate_coordinates(lng: float, lat: float) -> Tuple[float, float]:
|
|
lng, lat = float(lng), float(lat)
|
|
validate_lng(lng)
|
|
validate_lat(lat)
|
|
return lng, lat
|
|
|
|
|
|
def close_resource(obj: Any) -> None:
|
|
"""Safely close a resource, ignoring specific expected errors."""
|
|
if obj is None:
|
|
return
|
|
try:
|
|
obj.close()
|
|
except (AttributeError, OSError, ValueError):
|
|
pass
|
|
|
|
|
|
def is_ocean_timezone(timezone_name: str) -> bool:
|
|
if re.match(OCEAN_TIMEZONE_PREFIX, timezone_name) is None:
|
|
return False
|
|
return True
|
|
|
|
|
|
def get_boundaries_dir(data_dir: Path = DEFAULT_DATA_DIR) -> Path:
|
|
"""Return the path to the boundaries directory."""
|
|
return data_dir / "boundaries"
|
|
|
|
|
|
def get_holes_dir(data_dir: Path = DEFAULT_DATA_DIR) -> Path:
|
|
"""Return the path to the holes directory."""
|
|
return data_dir / "holes"
|
|
|
|
|
|
def get_hole_registry_path(data_dir: Path = DEFAULT_DATA_DIR) -> Path:
|
|
"""Return the path to the hole registry file."""
|
|
return data_dir / "hole_registry.json"
|