EG/plugins/user/navigation_mesh/tools/navmesh_tools.py
2025-12-12 16:16:15 +08:00

531 lines
16 KiB
Python

"""
导航网格工具集
整合导航网格的各种工具功能
"""
from typing import Dict, Any, List, Optional
from panda3d.core import Point3
class NavMeshTools:
"""
导航网格工具集
整合导航网格的各种工具功能
"""
def __init__(self, plugin):
"""
初始化工具集
Args:
plugin: 导航网格插件实例
"""
self.plugin = plugin
self.tools = {}
# 初始化各个工具
self._initialize_tools()
def _initialize_tools(self):
"""初始化各个工具"""
try:
from .navmesh_analyzer import NavMeshAnalyzer
from .navmesh_optimizer import NavMeshOptimizer
from ..utils.navmesh_serializer import NavMeshSerializer
# 初始化分析器
self.tools['analyzer'] = NavMeshAnalyzer(self.plugin.navmesh_manager)
# 初始化优化器
self.tools['optimizer'] = NavMeshOptimizer(self.plugin.navmesh_manager)
# 初始化序列化器
self.tools['serializer'] = NavMeshSerializer()
except Exception as e:
print(f"初始化工具失败: {e}")
def analyze_mesh_quality(self) -> Dict:
"""
分析导航网格质量
Returns:
质量分析结果
"""
if 'analyzer' in self.tools:
return self.tools['analyzer'].analyze_mesh_quality()
return {}
def suggest_optimizations(self) -> List[Dict]:
"""
提供优化建议
Returns:
优化建议列表
"""
if 'analyzer' in self.tools:
return self.tools['analyzer'].suggest_optimizations()
return []
def analyze_pathfinding_performance(self, sample_count: int = 100) -> Dict:
"""
分析寻路性能
Args:
sample_count: 采样次数
Returns:
性能分析结果
"""
if 'analyzer' in self.tools:
return self.tools['analyzer'].analyze_pathfinding_performance(sample_count)
return {}
def detect_bottlenecks(self) -> List[Dict]:
"""
检测导航网格中的瓶颈区域
Returns:
瓶颈区域列表
"""
if 'analyzer' in self.tools:
return self.tools['analyzer'].detect_bottlenecks()
return []
def analyze_coverage(self) -> Dict:
"""
分析导航网格覆盖情况
Returns:
覆盖情况分析结果
"""
if 'analyzer' in self.tools:
return self.tools['analyzer'].analyze_coverage()
return {}
def generate_report(self) -> Dict:
"""
生成完整的分析报告
Returns:
分析报告
"""
if 'analyzer' in self.tools:
return self.tools['analyzer'].generate_report()
return {}
def export_report(self, filepath: str) -> bool:
"""
导出分析报告到文件
Args:
filepath: 导出文件路径
Returns:
是否导出成功
"""
if 'analyzer' in self.tools:
return self.tools['analyzer'].export_report(filepath)
return False
def get_complexity_score(self) -> float:
"""
计算导航网格复杂度评分
Returns:
复杂度评分 (0-100)
"""
if 'analyzer' in self.tools:
return self.tools['analyzer'].get_complexity_score()
return 0.0
def recommend_simplification(self) -> Dict:
"""
推荐网格简化策略
Returns:
简化策略建议
"""
if 'analyzer' in self.tools:
return self.tools['analyzer'].recommend_simplification()
return {}
def merge_adjacent_polygons(self) -> int:
"""
合并相邻的多边形
Returns:
合并的多边形数量
"""
if 'optimizer' in self.tools:
return self.tools['optimizer'].merge_adjacent_polygons()
return 0
def simplify_polygons(self) -> int:
"""
简化多边形(移除不必要的顶点)
Returns:
简化的顶点数量
"""
if 'optimizer' in self.tools:
return self.tools['optimizer'].simplify_polygons()
return 0
def remove_small_polygons(self) -> int:
"""
移除极小的多边形
Returns:
移除的多边形数量
"""
if 'optimizer' in self.tools:
return self.tools['optimizer'].remove_small_polygons()
return 0
def optimize_mesh(self, optimization_level: str = 'medium') -> Dict:
"""
执行完整的网格优化
Args:
optimization_level: 优化级别 ('light', 'medium', 'heavy')
Returns:
优化结果统计
"""
if 'optimizer' in self.tools:
return self.tools['optimizer'].optimize_mesh(optimization_level)
return {}
def set_optimization_settings(self, settings: Dict):
"""
设置优化参数
Args:
settings: 优化参数字典
"""
if 'optimizer' in self.tools:
self.tools['optimizer'].set_optimization_settings(settings)
def get_optimization_settings(self) -> Dict:
"""
获取优化参数
Returns:
优化参数字典
"""
if 'optimizer' in self.tools:
return self.tools['optimizer'].get_optimization_settings()
return {}
def fill_gaps(self) -> int:
"""
填补导航网格中的空隙
Returns:
填补的多边形数量
"""
if 'optimizer' in self.tools:
return self.tools['optimizer'].fill_gaps()
return 0
def smooth_boundaries(self) -> int:
"""
平滑多边形边界
Returns:
平滑处理的边数
"""
if 'optimizer' in self.tools:
return self.tools['optimizer'].smooth_boundaries()
return 0
def balance_polygon_sizes(self) -> int:
"""
平衡多边形大小
Returns:
调整的多边形数量
"""
if 'optimizer' in self.tools:
return self.tools['optimizer'].balance_polygon_sizes()
return 0
def serialize_navmesh(self) -> str:
"""
序列化导航网格为字符串
Returns:
序列化后的字符串
"""
if 'serializer' in self.tools and self.plugin.navmesh_manager:
return self.tools['serializer'].serialize_navmesh(self.plugin.navmesh_manager)
return ""
def deserialize_navmesh(self, data_str: str) -> bool:
"""
从字符串反序列化导航网格
Args:
data_str: 序列化数据字符串
Returns:
是否反序列化成功
"""
if 'serializer' in self.tools and self.plugin.navmesh_manager:
return self.tools['serializer'].deserialize_navmesh(data_str, self.plugin.navmesh_manager)
return False
def save_navmesh_to_file(self, filepath: str,
compress: bool = False, pretty_print: bool = False) -> bool:
"""
保存导航网格到文件
Args:
filepath: 文件路径
compress: 是否压缩
pretty_print: 是否美化输出
Returns:
是否保存成功
"""
if 'serializer' in self.tools and self.plugin.navmesh_manager:
return self.tools['serializer'].save_navmesh_to_file(
self.plugin.navmesh_manager, filepath, compress, pretty_print)
return False
def load_navmesh_from_file(self, filepath: str) -> bool:
"""
从文件加载导航网格
Args:
filepath: 文件路径
Returns:
是否加载成功
"""
if 'serializer' in self.tools and self.plugin.navmesh_manager:
return self.tools['serializer'].load_navmesh_from_file(filepath, self.plugin.navmesh_manager)
return False
def export_to_standard_format(self, filepath: str,
format_type: str = 'obj') -> bool:
"""
导出为标准格式
Args:
filepath: 导出文件路径
format_type: 导出格式 ('obj', 'ply')
Returns:
是否导出成功
"""
if 'serializer' in self.tools and self.plugin.navmesh_manager:
return self.tools['serializer'].export_to_standard_format(
self.plugin.navmesh_manager, filepath, format_type)
return False
def import_from_standard_format(self, filepath: str,
format_type: str = 'obj') -> bool:
"""
从标准格式导入
Args:
filepath: 导入文件路径
format_type: 导入格式 ('obj', 'ply')
Returns:
是否导入成功
"""
if 'serializer' in self.tools and self.plugin.navmesh_manager:
return self.tools['serializer'].import_from_standard_format(
filepath, self.plugin.navmesh_manager, format_type)
return False
def get_file_info(self, filepath: str) -> Dict[str, Any]:
"""
获取导航网格文件信息
Args:
filepath: 文件路径
Returns:
文件信息字典
"""
if 'serializer' in self.tools:
return self.tools['serializer'].get_file_info(filepath)
return {}
def batch_analyze(self, filepaths: List[str]) -> Dict[str, Dict]:
"""
批量分析多个导航网格文件
Args:
filepaths: 文件路径列表
Returns:
各文件的分析结果
"""
results = {}
for filepath in filepaths:
try:
info = self.get_file_info(filepath)
results[filepath] = info
except Exception as e:
results[filepath] = {'error': str(e)}
return results
def compare_navmeshes(self, navmesh1_path: str, navmesh2_path: str) -> Dict:
"""
比较两个导航网格
Args:
navmesh1_path: 第一个导航网格文件路径
navmesh2_path: 第二个导航网格文件路径
Returns:
比较结果
"""
try:
info1 = self.get_file_info(navmesh1_path)
info2 = self.get_file_info(navmesh2_path)
comparison = {
'file1': info1,
'file2': info2,
'differences': {}
}
# 比较关键指标
for key in ['polygon_count', 'obstacle_count', 'file_size']:
val1 = info1.get(key, 0)
val2 = info2.get(key, 0)
if val1 != val2:
comparison['differences'][key] = {
'file1': val1,
'file2': val2,
'difference': val2 - val1,
'percentage': ((val2 - val1) / val1 * 100) if val1 != 0 else float('inf')
}
return comparison
except Exception as e:
return {'error': str(e)}
def validate_navmesh_file(self, filepath: str) -> Dict:
"""
验证导航网格文件的有效性
Args:
filepath: 文件路径
Returns:
验证结果
"""
try:
info = self.get_file_info(filepath)
validation = {
'filepath': filepath,
'valid': True,
'issues': [],
'info': info
}
# 检查基本信息
if info.get('file_size', 0) == 0:
validation['valid'] = False
validation['issues'].append('文件为空')
if info.get('version') == 'unknown':
validation['issues'].append('无法识别文件版本')
# 检查多边形数量
polygon_count = info.get('polygon_count', 0)
if polygon_count == 0:
validation['issues'].append('导航网格不包含多边形')
elif polygon_count > 100000:
validation['issues'].append('多边形数量过多,可能影响性能')
return validation
except Exception as e:
return {
'filepath': filepath,
'valid': False,
'issues': [str(e)],
'error': True
}
def optimize_and_save(self, input_filepath: str, output_filepath: str,
optimization_level: str = 'medium') -> Dict:
"""
优化并保存导航网格
Args:
input_filepath: 输入文件路径
output_filepath: 输出文件路径
optimization_level: 优化级别
Returns:
操作结果
"""
try:
# 加载导航网格
if not self.load_navmesh_from_file(input_filepath):
return {'success': False, 'error': '无法加载输入文件'}
# 执行优化
optimization_result = self.optimize_mesh(optimization_level)
# 保存优化后的网格
if not self.save_navmesh_to_file(output_filepath):
return {'success': False, 'error': '无法保存优化后的文件'}
return {
'success': True,
'optimization_result': optimization_result,
'input_file': input_filepath,
'output_file': output_filepath
}
except Exception as e:
return {'success': False, 'error': str(e)}
def create_optimization_pipeline(self, steps: List[str]) -> Dict:
"""
创建优化流水线
Args:
steps: 优化步骤列表
Returns:
流水线执行结果
"""
results = {
'steps': steps,
'results': [],
'total_improvement': 0
}
for step in steps:
try:
if step == 'merge':
result = {'step': 'merge', 'polygons_merged': self.merge_adjacent_polygons()}
elif step == 'simplify':
result = {'step': 'simplify', 'vertices_simplified': self.simplify_polygons()}
elif step == 'remove_small':
result = {'step': 'remove_small', 'polygons_removed': self.remove_small_polygons()}
elif step == 'optimize':
result = {'step': 'optimize', 'optimization_result': self.optimize_mesh()}
else:
result = {'step': step, 'error': '未知的优化步骤'}
results['results'].append(result)
except Exception as e:
results['results'].append({'step': step, 'error': str(e)})
return results