EG/plugins/user/weather_season_system/utils/weather_utils.py
2025-12-12 16:16:15 +08:00

743 lines
22 KiB
Python

"""
天气和季节系统工具类
提供各种实用工具函数和辅助方法
"""
import time
import random
from typing import Dict, Any, List, Optional, Tuple
import math
import json
import os
class WeatherUtils:
"""
天气和季节系统工具类
提供各种实用工具函数和辅助方法
"""
def __init__(self, plugin):
"""
初始化工具类
Args:
plugin: 天气和季节系统插件实例
"""
self.plugin = plugin
self.enabled = False
self.initialized = False
# 配置文件路径
self.config_directory = "config/weather"
self.preset_directory = "presets/weather"
# 数据缓存
self.data_cache = {}
self.cache_expiry = 300 # 缓存过期时间(秒)
# 日志配置
self.log_enabled = True
self.log_level = "INFO"
self.log_file = "weather_system.log"
# 性能监控
self.performance_stats = {
'function_calls': {},
'execution_times': {},
'memory_usage': 0.0
}
print("✓ 天气和季节系统工具类已创建")
def initialize(self) -> bool:
"""
初始化工具类
Returns:
是否初始化成功
"""
try:
# 创建必要的目录
directories = [self.config_directory, self.preset_directory]
for directory in directories:
if not os.path.exists(directory):
os.makedirs(directory)
self.initialized = True
print("✓ 天气和季节系统工具类初始化完成")
return True
except Exception as e:
print(f"✗ 天气和季节系统工具类初始化失败: {e}")
import traceback
traceback.print_exc()
return False
def enable(self) -> bool:
"""
启用工具类
Returns:
是否启用成功
"""
try:
if not self.initialized:
print("✗ 工具类未初始化")
return False
self.enabled = True
print("✓ 天气和季节系统工具类已启用")
return True
except Exception as e:
print(f"✗ 天气和季节系统工具类启用失败: {e}")
import traceback
traceback.print_exc()
return False
def disable(self):
"""禁用工具类"""
try:
self.enabled = False
print("✓ 天气和季节系统工具类已禁用")
except Exception as e:
print(f"✗ 天气和季节系统工具类禁用失败: {e}")
import traceback
traceback.print_exc()
def finalize(self):
"""清理工具类资源"""
try:
self.disable()
self._save_cache()
self.initialized = False
print("✓ 天气和季节系统工具类资源已清理")
except Exception as e:
print(f"✗ 天气和季节系统工具类资源清理失败: {e}")
import traceback
traceback.print_exc()
def update(self, dt: float):
"""
更新工具类状态
Args:
dt: 时间增量
"""
try:
if not self.enabled:
return
# 清理过期缓存
self._cleanup_expired_cache()
except Exception as e:
print(f"✗ 天气和季节系统工具类更新失败: {e}")
import traceback
traceback.print_exc()
def _cleanup_expired_cache(self):
"""清理过期缓存"""
try:
current_time = time.time()
expired_keys = []
for key, (timestamp, _) in self.data_cache.items():
if current_time - timestamp > self.cache_expiry:
expired_keys.append(key)
for key in expired_keys:
del self.data_cache[key]
except Exception as e:
if self.log_enabled and self.log_level == "DEBUG":
print(f"✗ 缓存清理失败: {e}")
def _save_cache(self):
"""保存缓存到文件"""
try:
cache_file = os.path.join(self.config_directory, "cache.json")
cache_data = {}
# 只保存可序列化的数据
for key, (timestamp, value) in self.data_cache.items():
try:
json.dumps(value) # 测试是否可序列化
cache_data[key] = (timestamp, value)
except (TypeError, ValueError):
continue # 跳过不可序列化的数据
with open(cache_file, 'w', encoding='utf-8') as f:
json.dump(cache_data, f, ensure_ascii=False, indent=2)
except Exception as e:
if self.log_enabled and self.log_level == "DEBUG":
print(f"✗ 缓存保存失败: {e}")
def load_cache(self):
"""从文件加载缓存"""
try:
cache_file = os.path.join(self.config_directory, "cache.json")
if os.path.exists(cache_file):
with open(cache_file, 'r', encoding='utf-8') as f:
cache_data = json.load(f)
self.data_cache.update(cache_data)
except Exception as e:
if self.log_enabled and self.log_level == "DEBUG":
print(f"✗ 缓存加载失败: {e}")
def log_message(self, level: str, message: str):
"""
记录日志消息
Args:
level: 日志级别
message: 日志消息
"""
try:
if not self.log_enabled:
return
levels = ["DEBUG", "INFO", "WARNING", "ERROR"]
if levels.index(level) < levels.index(self.log_level):
return
timestamp = time.strftime("%Y-%m-%d %H:%M:%S")
log_entry = f"[{timestamp}] {level}: {message}\n"
print(log_entry.strip())
# 写入日志文件
try:
with open(self.log_file, 'a', encoding='utf-8') as f:
f.write(log_entry)
except Exception:
pass # 忽略文件写入错误
except Exception as e:
pass # 忽略日志记录错误
def performance_monitor(self, func_name: str):
"""
性能监控装饰器
Args:
func_name: 函数名称
"""
def decorator(func):
def wrapper(*args, **kwargs):
start_time = time.time()
try:
result = func(*args, **kwargs)
end_time = time.time()
# 记录执行时间
execution_time = end_time - start_time
if func_name not in self.performance_stats['function_calls']:
self.performance_stats['function_calls'][func_name] = 0
self.performance_stats['execution_times'][func_name] = 0.0
self.performance_stats['function_calls'][func_name] += 1
self.performance_stats['execution_times'][func_name] += execution_time
return result
except Exception as e:
end_time = time.time()
execution_time = end_time - start_time
self.log_message("ERROR", f"函数 {func_name} 执行失败: {e}")
raise
return wrapper
return decorator
def get_weather_icon(self, weather_type: str) -> str:
"""
获取天气图标
Args:
weather_type: 天气类型
Returns:
天气图标字符
"""
icons = {
'clear': '☀️',
'cloudy': '☁️',
'rain': '🌧️',
'storm': '⛈️',
'snow': '❄️',
'fog': '🌫️',
'windy': '💨',
'hail': '🌨️'
}
return icons.get(weather_type, '🌈')
def get_season_icon(self, season: str) -> str:
"""
获取季节图标
Args:
season: 季节名称
Returns:
季节图标字符
"""
icons = {
'spring': '🌸',
'summer': '☀️',
'autumn': '🍂',
'winter': '❄️'
}
return icons.get(season, '🌍')
def temperature_to_string(self, temperature: float) -> str:
"""
将温度转换为字符串
Args:
temperature: 温度值(摄氏度)
Returns:
温度字符串
"""
return f"{temperature:.1f}°C"
def wind_speed_to_string(self, wind_speed: float) -> str:
"""
将风速转换为字符串
Args:
wind_speed: 风速(m/s)
Returns:
风速字符串
"""
return f"{wind_speed:.1f} m/s"
def precipitation_to_string(self, precipitation: float) -> str:
"""
将降水强度转换为字符串
Args:
precipitation: 降水强度(0-1)
Returns:
降水强度字符串
"""
if precipitation <= 0:
return "无降水"
elif precipitation < 0.3:
return "小雨"
elif precipitation < 0.6:
return "中雨"
elif precipitation < 0.9:
return "大雨"
else:
return "暴雨"
def visibility_to_string(self, visibility: float) -> str:
"""
将能见度转换为字符串
Args:
visibility: 能见度(米)
Returns:
能见度字符串
"""
if visibility >= 5000:
return "良好"
elif visibility >= 1000:
return "一般"
elif visibility >= 500:
return "较差"
else:
return "极差"
def humidity_to_string(self, humidity: float) -> str:
"""
将湿度转换为字符串
Args:
humidity: 湿度(%)
Returns:
湿度字符串
"""
return f"{humidity:.0f}%"
def pressure_to_string(self, pressure: float) -> str:
"""
将气压转换为字符串
Args:
pressure: 气压(hPa)
Returns:
气压字符串
"""
return f"{pressure:.1f} hPa"
def uv_index_to_string(self, uv_index: float) -> str:
"""
将UV指数转换为字符串
Args:
uv_index: UV指数
Returns:
UV指数字符串
"""
if uv_index <= 2:
return ""
elif uv_index <= 5:
return "中等"
elif uv_index <= 7:
return ""
elif uv_index <= 10:
return "很高"
else:
return "极高"
def get_weather_description(self, weather_type: str) -> str:
"""
获取天气描述
Args:
weather_type: 天气类型
Returns:
天气描述
"""
descriptions = {
'clear': '晴朗无云',
'cloudy': '多云天气',
'rain': '正在下雨',
'storm': '雷暴天气',
'snow': '正在下雪',
'fog': '大雾天气',
'windy': '风力强劲',
'hail': '正在下冰雹'
}
return descriptions.get(weather_type, '未知天气')
def get_season_description(self, season: str) -> str:
"""
获取季节描述
Args:
season: 季节名称
Returns:
季节描述
"""
descriptions = {
'spring': '万物复苏的春季',
'summer': '炎热的夏季',
'autumn': '收获的秋季',
'winter': '寒冷的冬季'
}
return descriptions.get(season, '未知季节')
def calculate_weather_severity(self, conditions: Dict[str, Any]) -> float:
"""
计算天气严重程度
Args:
conditions: 天气条件字典
Returns:
严重程度(0-1)
"""
try:
severity = 0.0
# 降水影响
precipitation = conditions.get('precipitation', 0.0)
severity += precipitation * 0.3
# 风速影响
wind_speed = conditions.get('wind_speed', 0.0)
severity += min(1.0, wind_speed / 20.0) * 0.2
# 温度影响(极端温度)
temperature = conditions.get('temperature', 20.0)
if temperature > 35 or temperature < 0:
severity += 0.2
# 能见度影响
visibility = conditions.get('visibility', 10000.0)
severity += (1.0 - min(1.0, visibility / 10000.0)) * 0.3
return min(1.0, severity)
except Exception as e:
self.log_message("ERROR", f"天气严重程度计算失败: {e}")
return 0.0
def interpolate_values(self, start_value: float, end_value: float, progress: float) -> float:
"""
插值计算
Args:
start_value: 起始值
end_value: 结束值
progress: 进度(0-1)
Returns:
插值结果
"""
return start_value + (end_value - start_value) * progress
def clamp_value(self, value: float, min_value: float, max_value: float) -> float:
"""
限制值范围
Args:
value: 值
min_value: 最小值
max_value: 最大值
Returns:
限制后的值
"""
return max(min_value, min(max_value, value))
def random_range(self, min_value: float, max_value: float) -> float:
"""
生成随机范围值
Args:
min_value: 最小值
max_value: 最大值
Returns:
随机值
"""
return random.uniform(min_value, max_value)
def normalize_vector(self, vector: List[float]) -> List[float]:
"""
归一化向量
Args:
vector: 向量
Returns:
归一化后的向量
"""
try:
magnitude = math.sqrt(sum(x * x for x in vector))
if magnitude > 0:
return [x / magnitude for x in vector]
return [0.0] * len(vector)
except Exception as e:
self.log_message("ERROR", f"向量归一化失败: {e}")
return vector
def distance_3d(self, pos1: Tuple[float, float, float], pos2: Tuple[float, float, float]) -> float:
"""
计算3D空间距离
Args:
pos1: 位置1
pos2: 位置2
Returns:
距离
"""
try:
dx = pos1[0] - pos2[0]
dy = pos1[1] - pos2[1]
dz = pos1[2] - pos2[2]
return math.sqrt(dx * dx + dy * dy + dz * dz)
except Exception as e:
self.log_message("ERROR", f"距离计算失败: {e}")
return 0.0
def angle_between_vectors(self, v1: List[float], v2: List[float]) -> float:
"""
计算两个向量之间的夹角
Args:
v1: 向量1
v2: 向量2
Returns:
夹角(弧度)
"""
try:
dot_product = sum(a * b for a, b in zip(v1, v2))
magnitude1 = math.sqrt(sum(a * a for a in v1))
magnitude2 = math.sqrt(sum(b * b for b in v2))
if magnitude1 > 0 and magnitude2 > 0:
cos_angle = dot_product / (magnitude1 * magnitude2)
cos_angle = max(-1.0, min(1.0, cos_angle)) # 限制在[-1, 1]范围内
return math.acos(cos_angle)
return 0.0
except Exception as e:
self.log_message("ERROR", f"向量夹角计算失败: {e}")
return 0.0
def save_to_json(self, data: Dict[str, Any], filename: str) -> bool:
"""
保存数据到JSON文件
Args:
data: 数据字典
filename: 文件名
Returns:
是否保存成功
"""
try:
with open(filename, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
return True
except Exception as e:
self.log_message("ERROR", f"数据保存失败: {e}")
return False
def load_from_json(self, filename: str) -> Optional[Dict[str, Any]]:
"""
从JSON文件加载数据
Args:
filename: 文件名
Returns:
数据字典或None
"""
try:
if os.path.exists(filename):
with open(filename, 'r', encoding='utf-8') as f:
return json.load(f)
return None
except Exception as e:
self.log_message("ERROR", f"数据加载失败: {e}")
return None
def get_cache(self, key: str) -> Any:
"""
获取缓存数据
Args:
key: 缓存键
Returns:
缓存数据或None
"""
try:
if key in self.data_cache:
timestamp, value = self.data_cache[key]
if time.time() - timestamp <= self.cache_expiry:
return value
else:
del self.data_cache[key]
return None
except Exception as e:
self.log_message("ERROR", f"缓存获取失败: {e}")
return None
def set_cache(self, key: str, value: Any):
"""
设置缓存数据
Args:
key: 缓存键
value: 缓存值
"""
try:
self.data_cache[key] = (time.time(), value)
except Exception as e:
self.log_message("ERROR", f"缓存设置失败: {e}")
def clear_cache(self):
"""清空缓存"""
try:
self.data_cache.clear()
except Exception as e:
self.log_message("ERROR", f"缓存清空失败: {e}")
def get_performance_stats(self) -> Dict[str, Any]:
"""
获取性能统计信息
Returns:
性能统计信息字典
"""
try:
stats = self.performance_stats.copy()
# 计算平均执行时间
average_times = {}
for func_name, total_time in stats['execution_times'].items():
calls = stats['function_calls'][func_name]
if calls > 0:
average_times[func_name] = total_time / calls
stats['average_times'] = average_times
return stats
except Exception as e:
self.log_message("ERROR", f"性能统计获取失败: {e}")
return {}
def reset_performance_stats(self):
"""重置性能统计信息"""
try:
self.performance_stats = {
'function_calls': {},
'execution_times': {},
'memory_usage': 0.0
}
except Exception as e:
self.log_message("ERROR", f"性能统计重置失败: {e}")
def format_time(self, seconds: float) -> str:
"""
格式化时间
Args:
seconds: 秒数
Returns:
格式化的时间字符串
"""
try:
if seconds < 60:
return f"{seconds:.1f}"
elif seconds < 3600:
minutes = seconds / 60
return f"{minutes:.1f}分钟"
else:
hours = seconds / 3600
return f"{hours:.1f}小时"
except Exception as e:
self.log_message("ERROR", f"时间格式化失败: {e}")
return f"{seconds:.1f}"
def generate_unique_id(self) -> str:
"""
生成唯一ID
Returns:
唯一ID字符串
"""
try:
timestamp = int(time.time() * 1000000) # 微秒时间戳
random_part = random.randint(1000, 9999)
return f"{timestamp}_{random_part}"
except Exception as e:
self.log_message("ERROR", f"唯一ID生成失败: {e}")
return str(random.randint(10000000, 99999999))