"""
地形工具类
提供各种地形处理和分析工具
"""

import numpy as np
import math
from typing import Dict, Any, List, Tuple, Optional
import json
import time

class TerrainUtils:
    """
    地形工具类
    提供各种地形处理和分析工具，包括地形分析、过滤、转换等功能
    """
    
    def __init__(self, plugin):
        """
        初始化地形工具类
        
        Args:
            plugin: 程序化地形生成插件实例
        """
        self.plugin = plugin
        self.enabled = False
        self.initialized = False
        
        # 工具配置
        self.tool_params = {
            'analysis_resolution': 64,
            'filter_radius': 3,
            'erosion_iterations': 10,
            'smoothing_iterations': 5,
            'slope_threshold': 0.3,
            'curvature_threshold': 0.1
        }
        
        # 分析结果缓存
        self.analysis_cache = {}
        
        # 统计信息
        self.stats = {
            'tools_used': 0,
            'total_processing_time': 0.0,
            'average_processing_time': 0.0,
            'cache_hits': 0,
            'cache_misses': 0
        }
        
        print("✓ 地形工具类已创建")
        
    def initialize(self) -> bool:
        """
        初始化地形工具类
        
        Returns:
            是否初始化成功
        """
        try:
            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.initialized = False
            print("✓ 地形工具类资源已清理")
            
        except Exception as e:
            print(f"✗ 地形工具类资源清理失败: {e}")
            import traceback
            traceback.print_exc()
            
    def update(self, dt: float):
        """
        更新地形工具类状态
        
        Args:
            dt: 时间增量
        """
        # 处理更新逻辑
        pass
        
    def analyze_terrain_slope(self, heightmap: np.ndarray) -> np.ndarray:
        """
        分析地形坡度
        
        Args:
            heightmap: 高度图数据
            
        Returns:
            坡度图数据 (弧度)
        """
        try:
            processing_start_time = time.time()
            
            if not self.enabled:
                print("✗ 地形工具类未启用")
                return np.zeros_like(heightmap, dtype=np.float32)
                
            print("✓ 开始分析地形坡度...")
            
            height, width = heightmap.shape
            slope_map = np.zeros((height, width), dtype=np.float32)
            
            # 计算每个点的坡度
            for y in range(height):
                for x in range(width):
                    # 计算梯度
                    slope = self._calculate_slope_at_point(heightmap, x, y)
                    slope_map[y, x] = slope
                    
            # 更新统计信息
            processing_time = time.time() - processing_start_time
            self._update_stats(processing_time)
            
            print(f"✓ 地形坡度分析完成，耗时: {processing_time:.3f}秒")
            return slope_map
            
        except Exception as e:
            print(f"✗ 地形坡度分析失败: {e}")
            import traceback
            traceback.print_exc()
            return np.zeros_like(heightmap, dtype=np.float32)
            
    def _calculate_slope_at_point(self, heightmap: np.ndarray, x: int, y: int) -> float:
        """
        计算指定点的坡度
        
        Args:
            heightmap: 高度图数据
            x: X坐标
            y: Y坐标
            
        Returns:
            坡度值 (弧度)
        """
        try:
            height, width = heightmap.shape
            
            # 计算梯度
            dx = 0.0
            dy = 0.0
            
            # X方向梯度
            if x > 0 and x < width - 1:
                dx = (heightmap[y, x + 1] - heightmap[y, x - 1]) / 2.0
            elif x == 0:
                dx = heightmap[y, x + 1] - heightmap[y, x]
            else:
                dx = heightmap[y, x] - heightmap[y, x - 1]
                
            # Y方向梯度
            if y > 0 and y < height - 1:
                dy = (heightmap[y + 1, x] - heightmap[y - 1, x]) / 2.0
            elif y == 0:
                dy = heightmap[y + 1, x] - heightmap[y, x]
            else:
                dy = heightmap[y, x] - heightmap[y - 1, x]
                
            # 计算坡度（梯度的模）
            gradient_magnitude = math.sqrt(dx * dx + dy * dy)
            slope = math.atan(gradient_magnitude)
            
            return slope
            
        except Exception as e:
            print(f"✗ 点坡度计算失败: {e}")
            return 0.0
            
    def analyze_terrain_curvature(self, heightmap: np.ndarray) -> np.ndarray:
        """
        分析地形曲率
        
        Args:
            heightmap: 高度图数据
            
        Returns:
            曲率图数据
        """
        try:
            processing_start_time = time.time()
            
            if not self.enabled:
                print("✗ 地形工具类未启用")
                return np.zeros_like(heightmap, dtype=np.float32)
                
            print("✓ 开始分析地形曲率...")
            
            height, width = heightmap.shape
            curvature_map = np.zeros((height, width), dtype=np.float32)
            
            # 计算每个点的曲率
            for y in range(1, height - 1):
                for x in range(1, width - 1):
                    # 使用拉普拉斯算子计算曲率
                    center = heightmap[y, x]
                    laplacian = (
                        heightmap[y-1, x] + heightmap[y+1, x] +
                        heightmap[y, x-1] + heightmap[y, x+1] - 4 * center
                    )
                    curvature_map[y, x] = laplacian
                    
            # 更新统计信息
            processing_time = time.time() - processing_start_time
            self._update_stats(processing_time)
            
            print(f"✓ 地形曲率分析完成，耗时: {processing_time:.3f}秒")
            return curvature_map
            
        except Exception as e:
            print(f"✗ 地形曲率分析失败: {e}")
            import traceback
            traceback.print_exc()
            return np.zeros_like(heightmap, dtype=np.float32)
            
    def analyze_terrain_aspect(self, heightmap: np.ndarray) -> np.ndarray:
        """
        分析地形坡向
        
        Args:
            heightmap: 高度图数据
            
        Returns:
            坡向图数据 (弧度)
        """
        try:
            processing_start_time = time.time()
            
            if not self.enabled:
                print("✗ 地形工具类未启用")
                return np.zeros_like(heightmap, dtype=np.float32)
                
            print("✓ 开始分析地形坡向...")
            
            height, width = heightmap.shape
            aspect_map = np.zeros((height, width), dtype=np.float32)
            
            # 计算每个点的坡向
            for y in range(1, height - 1):
                for x in range(1, width - 1):
                    # 计算梯度
                    dx = (heightmap[y, x + 1] - heightmap[y, x - 1]) / 2.0
                    dy = (heightmap[y + 1, x] - heightmap[y - 1, x]) / 2.0
                    
                    # 计算坡向
                    if dx == 0 and dy == 0:
                        aspect = 0.0
                    else:
                        aspect = math.atan2(dy, dx)
                        # 转换为0-2π范围
                        if aspect < 0:
                            aspect += 2 * math.pi
                            
                    aspect_map[y, x] = aspect
                    
            # 更新统计信息
            processing_time = time.time() - processing_start_time
            self._update_stats(processing_time)
            
            print(f"✓ 地形坡向分析完成，耗时: {processing_time:.3f}秒")
            return aspect_map
            
        except Exception as e:
            print(f"✗ 地形坡向分析失败: {e}")
            import traceback
            traceback.print_exc()
            return np.zeros_like(heightmap, dtype=np.float32)
            
    def analyze_terrain_rugosity(self, heightmap: np.ndarray, window_size: int = 3) -> np.ndarray:
        """
        分析地形粗糙度
        
        Args:
            heightmap: 高度图数据
            window_size: 窗口大小
            
        Returns:
            粗糙度图数据
        """
        try:
            processing_start_time = time.time()
            
            if not self.enabled:
                print("✗ 地形工具类未启用")
                return np.zeros_like(heightmap, dtype=np.float32)
                
            print("✓ 开始分析地形粗糙度...")
            
            height, width = heightmap.shape
            rugosity_map = np.zeros((height, width), dtype=np.float32)
            
            half_window = window_size // 2
            
            # 计算每个点的粗糙度
            for y in range(half_window, height - half_window):
                for x in range(half_window, width - half_window):
                    # 计算局部窗口内的标准差
                    window = heightmap[y-half_window:y+half_window+1, x-half_window:x+half_window+1]
                    rugosity = np.std(window)
                    rugosity_map[y, x] = rugosity
                    
            # 更新统计信息
            processing_time = time.time() - processing_start_time
            self._update_stats(processing_time)
            
            print(f"✓ 地形粗糙度分析完成，耗时: {processing_time:.3f}秒")
            return rugosity_map
            
        except Exception as e:
            print(f"✗ 地形粗糙度分析失败: {e}")
            import traceback
            traceback.print_exc()
            return np.zeros_like(heightmap, dtype=np.float32)
            
    def smooth_terrain(self, heightmap: np.ndarray, iterations: int = None) -> np.ndarray:
        """
        平滑地形
        
        Args:
            heightmap: 高度图数据
            iterations: 平滑迭代次数
            
        Returns:
            平滑后的高度图数据
        """
        try:
            processing_start_time = time.time()
            
            if not self.enabled:
                print("✗ 地形工具类未启用")
                return heightmap
                
            if iterations is None:
                iterations = self.tool_params['smoothing_iterations']
                
            print(f"✓ 开始平滑地形 ({iterations} 次迭代)...")
            
            smoothed = heightmap.copy()
            height, width = smoothed.shape
            
            # 多次平滑迭代
            for iteration in range(iterations):
                new_heightmap = smoothed.copy()
                
                # 应用3x3平均滤波器
                for y in range(1, height - 1):
                    for x in range(1, width - 1):
                        # 计算3x3邻域的平均值
                        avg_value = (
                            smoothed[y-1, x-1] + smoothed[y-1, x] + smoothed[y-1, x+1] +
                            smoothed[y, x-1] + smoothed[y, x] + smoothed[y, x+1] +
                            smoothed[y+1, x-1] + smoothed[y+1, x] + smoothed[y+1, x+1]
                        ) / 9.0
                        
                        new_heightmap[y, x] = avg_value
                        
                smoothed = new_heightmap
                
            # 更新统计信息
            processing_time = time.time() - processing_start_time
            self._update_stats(processing_time)
            
            print(f"✓ 地形平滑完成，耗时: {processing_time:.3f}秒")
            return smoothed
            
        except Exception as e:
            print(f"✗ 地形平滑失败: {e}")
            import traceback
            traceback.print_exc()
            return heightmap
            
    def filter_terrain(self, heightmap: np.ndarray, filter_type: str = 'gaussian', 
                      radius: int = None) -> np.ndarray:
        """
        过滤地形
        
        Args:
            heightmap: 高度图数据
            filter_type: 滤波器类型 ('gaussian', 'median', 'bilateral')
            radius: 滤波器半径
            
        Returns:
            过滤后的高度图数据
        """
        try:
            processing_start_time = time.time()
            
            if not self.enabled:
                print("✗ 地形工具类未启用")
                return heightmap
                
            if radius is None:
                radius = self.tool_params['filter_radius']
                
            print(f"✓ 开始{filter_type}滤波地形 (半径: {radius})...")
            
            filtered = heightmap.copy()
            height, width = filtered.shape
            kernel_size = radius * 2 + 1
            
            if filter_type == 'gaussian':
                filtered = self._apply_gaussian_filter(filtered, radius)
            elif filter_type == 'median':
                filtered = self._apply_median_filter(filtered, radius)
            elif filter_type == 'bilateral':
                filtered = self._apply_bilateral_filter(filtered, radius)
            else:
                print(f"✗ 不支持的滤波器类型: {filter_type}")
                return heightmap
                
            # 更新统计信息
            processing_time = time.time() - processing_start_time
            self._update_stats(processing_time)
            
            print(f"✓ 地形{filter_type}滤波完成，耗时: {processing_time:.3f}秒")
            return filtered
            
        except Exception as e:
            print(f"✗ 地形滤波失败: {e}")
            import traceback
            traceback.print_exc()
            return heightmap
            
    def _apply_gaussian_filter(self, heightmap: np.ndarray, radius: int) -> np.ndarray:
        """应用高斯滤波"""
        try:
            filtered = heightmap.copy()
            height, width = filtered.shape
            kernel_size = radius * 2 + 1
            
            # 创建高斯核
            kernel = np.zeros((kernel_size, kernel_size), dtype=np.float32)
            sigma = radius / 3.0
            for y in range(kernel_size):
                for x in range(kernel_size):
                    dx = x - radius
                    dy = y - radius
                    kernel[y, x] = math.exp(-(dx*dx + dy*dy) / (2 * sigma * sigma))
            kernel = kernel / np.sum(kernel)
            
            # 应用滤波
            for y in range(radius, height - radius):
                for x in range(radius, width - radius):
                    value = 0.0
                    for ky in range(kernel_size):
                        for kx in range(kernel_size):
                            ny = y + ky - radius
                            nx = x + kx - radius
                            value += heightmap[ny, nx] * kernel[ky, kx]
                    filtered[y, x] = value
                    
            return filtered
            
        except Exception as e:
            print(f"✗ 高斯滤波应用失败: {e}")
            return heightmap
            
    def _apply_median_filter(self, heightmap: np.ndarray, radius: int) -> np.ndarray:
        """应用中值滤波"""
        try:
            filtered = heightmap.copy()
            height, width = filtered.shape
            kernel_size = radius * 2 + 1
            
            # 应用滤波
            for y in range(radius, height - radius):
                for x in range(radius, width - radius):
                    values = []
                    for ky in range(kernel_size):
                        for kx in range(kernel_size):
                            ny = y + ky - radius
                            nx = x + kx - radius
                            values.append(heightmap[ny, nx])
                    filtered[y, x] = np.median(values)
                    
            return filtered
            
        except Exception as e:
            print(f"✗ 中值滤波应用失败: {e}")
            return heightmap
            
    def _apply_bilateral_filter(self, heightmap: np.ndarray, radius: int) -> np.ndarray:
        """应用双边滤波"""
        try:
            filtered = heightmap.copy()
            height, width = filtered.shape
            kernel_size = radius * 2 + 1
            
            # 双边滤波参数
            spatial_sigma = radius / 3.0
            intensity_sigma = 0.1
            
            # 应用滤波
            for y in range(radius, height - radius):
                for x in range(radius, width - radius):
                    weighted_sum = 0.0
                    weight_sum = 0.0
                    center_value = heightmap[y, x]
                    
                    for ky in range(kernel_size):
                        for kx in range(kernel_size):
                            ny = y + ky - radius
                            nx = x + kx - radius
                            neighbor_value = heightmap[ny, nx]
                            
                            # 空间权重
                            dx = kx - radius
                            dy = ky - radius
                            spatial_weight = math.exp(-(dx*dx + dy*dy) / (2 * spatial_sigma * spatial_sigma))
                            
                            # 强度权重
                            intensity_diff = abs(neighbor_value - center_value)
                            intensity_weight = math.exp(-(intensity_diff * intensity_diff) / (2 * intensity_sigma * intensity_sigma))
                            
                            # 总权重
                            weight = spatial_weight * intensity_weight
                            weighted_sum += neighbor_value * weight
                            weight_sum += weight
                            
                    if weight_sum > 0:
                        filtered[y, x] = weighted_sum / weight_sum
                        
            return filtered
            
        except Exception as e:
            print(f"✗ 双边滤波应用失败: {e}")
            return heightmap
            
    def normalize_heightmap(self, heightmap: np.ndarray, min_value: float = 0.0, 
                           max_value: float = 1.0) -> np.ndarray:
        """
        归一化高度图
        
        Args:
            heightmap: 高度图数据
            min_value: 最小值
            max_value: 最大值
            
        Returns:
            归一化后的高度图数据
        """
        try:
            processing_start_time = time.time()
            
            if not self.enabled:
                print("✗ 地形工具类未启用")
                return heightmap
                
            print("✓ 开始归一化高度图...")
            
            # 计算当前范围
            current_min = np.min(heightmap)
            current_max = np.max(heightmap)
            
            if current_max == current_min:
                # 如果所有值相同，返回常量图
                normalized = np.full_like(heightmap, (min_value + max_value) / 2.0)
            else:
                # 归一化到0-1范围
                normalized_01 = (heightmap - current_min) / (current_max - current_min)
                # 缩放到指定范围
                normalized = normalized_01 * (max_value - min_value) + min_value
                
            # 更新统计信息
            processing_time = time.time() - processing_start_time
            self._update_stats(processing_time)
            
            print(f"✓ 高度图归一化完成，耗时: {processing_time:.3f}秒")
            return normalized
            
        except Exception as e:
            print(f"✗ 高度图归一化失败: {e}")
            import traceback
            traceback.print_exc()
            return heightmap
            
    def invert_heightmap(self, heightmap: np.ndarray) -> np.ndarray:
        """
        反转高度图
        
        Args:
            heightmap: 高度图数据
            
        Returns:
            反转后的高度图数据
        """
        try:
            processing_start_time = time.time()
            
            if not self.enabled:
                print("✗ 地形工具类未启用")
                return heightmap
                
            print("✓ 开始反转高度图...")
            
            # 反转高度图
            inverted = 1.0 - heightmap
            
            # 更新统计信息
            processing_time = time.time() - processing_start_time
            self._update_stats(processing_time)
            
            print(f"✓ 高度图反转完成，耗时: {processing_time:.3f}秒")
            return inverted
            
        except Exception as e:
            print(f"✗ 高度图反转失败: {e}")
            import traceback
            traceback.print_exc()
            return heightmap
            
    def blend_heightmaps(self, heightmaps: List[np.ndarray], weights: List[float] = None) -> np.ndarray:
        """
        混合多个高度图
        
        Args:
            heightmaps: 高度图列表
            weights: 权重列表（如果为None，则平均分配权重）
            
        Returns:
            混合后的高度图数据
        """
        try:
            processing_start_time = time.time()
            
            if not self.enabled:
                print("✗ 地形工具类未启用")
                return np.array([])
                
            if not heightmaps:
                print("✗ 高度图列表为空")
                return np.array([])
                
            if len(heightmaps) == 1:
                return heightmaps[0].copy()
                
            print(f"✓ 开始混合 {len(heightmaps)} 个高度图...")
            
            # 确保所有高度图尺寸相同
            base_shape = heightmaps[0].shape
            for hm in heightmaps:
                if hm.shape != base_shape:
                    print("✗ 所有高度图必须具有相同的尺寸")
                    return heightmaps[0].copy()
                    
            # 处理权重
            if weights is None:
                weights = [1.0 / len(heightmaps)] * len(heightmaps)
            elif len(weights) != len(heightmaps):
                print("✗ 权重数量必须与高度图数量相同")
                return heightmaps[0].copy()
                
            # 归一化权重
            total_weight = sum(weights)
            if total_weight > 0:
                weights = [w / total_weight for w in weights]
                
            # 混合高度图
            blended = np.zeros(base_shape, dtype=np.float32)
            for i, (hm, weight) in enumerate(zip(heightmaps, weights)):
                blended += hm * weight
                
            # 更新统计信息
            processing_time = time.time() - processing_start_time
            self._update_stats(processing_time)
            
            print(f"✓ 高度图混合完成，耗时: {processing_time:.3f}秒")
            return blended
            
        except Exception as e:
            print(f"✗ 高度图混合失败: {e}")
            import traceback
            traceback.print_exc()
            # 返回第一个高度图的副本
            return heightmaps[0].copy() if heightmaps else np.array([])
            
    def generate_terrain_mask(self, heightmap: np.ndarray, condition: str, 
                             threshold: float = 0.5) -> np.ndarray:
        """
        生成地形掩码
        
        Args:
            heightmap: 高度图数据
            condition: 条件 ('above', 'below', 'equal', 'between')
            threshold: 阈值
            
        Returns:
            掩码数据 (0-1范围)
        """
        try:
            processing_start_time = time.time()
            
            if not self.enabled:
                print("✗ 地形工具类未启用")
                return np.zeros_like(heightmap, dtype=np.float32)
                
            print(f"✓ 开始生成地形掩码 (条件: {condition}, 阈值: {threshold})...")
            
            mask = np.zeros_like(heightmap, dtype=np.float32)
            
            if condition == 'above':
                mask = np.where(heightmap > threshold, 1.0, 0.0)
            elif condition == 'below':
                mask = np.where(heightmap < threshold, 1.0, 0.0)
            elif condition == 'equal':
                mask = np.where(np.abs(heightmap - threshold) < 0.01, 1.0, 0.0)
            elif condition == 'between':
                # 假设阈值是一个范围 [min, max]
                if isinstance(threshold, (list, tuple)) and len(threshold) == 2:
                    min_val, max_val = threshold
                    mask = np.where((heightmap >= min_val) & (heightmap <= max_val), 1.0, 0.0)
                else:
                    mask = np.where(np.abs(heightmap - threshold) < 0.1, 1.0, 0.0)
            else:
                print(f"✗ 不支持的条件: {condition}")
                return mask
                
            # 更新统计信息
            processing_time = time.time() - processing_start_time
            self._update_stats(processing_time)
            
            print(f"✓ 地形掩码生成完成，耗时: {processing_time:.3f}秒")
            return mask
            
        except Exception as e:
            print(f"✗ 地形掩码生成失败: {e}")
            import traceback
            traceback.print_exc()
            return np.zeros_like(heightmap, dtype=np.float32)
            
    def apply_terrain_mask(self, heightmap: np.ndarray, mask: np.ndarray, 
                          operation: str = 'multiply') -> np.ndarray:
        """
        应用地形掩码
        
        Args:
            heightmap: 高度图数据
            mask: 掩码数据
            operation: 操作 ('multiply', 'add', 'subtract', 'replace')
            
        Returns:
            处理后的高度图数据
        """
        try:
            processing_start_time = time.time()
            
            if not self.enabled:
                print("✗ 地形工具类未启用")
                return heightmap
                
            # 确保掩码尺寸匹配
            if mask.shape != heightmap.shape:
                print("✗ 掩码尺寸与高度图不匹配")
                return heightmap
                
            print(f"✓ 开始应用地形掩码 (操作: {operation})...")
            
            result = heightmap.copy()
            
            if operation == 'multiply':
                result = heightmap * mask
            elif operation == 'add':
                result = heightmap + mask
            elif operation == 'subtract':
                result = heightmap - mask
            elif operation == 'replace':
                # 只在掩码为1的地方替换
                result = np.where(mask > 0.5, mask, heightmap)
            else:
                print(f"✗ 不支持的操作: {operation}")
                return heightmap
                
            # 更新统计信息
            processing_time = time.time() - processing_start_time
            self._update_stats(processing_time)
            
            print(f"✓ 地形掩码应用完成，耗时: {processing_time:.3f}秒")
            return result
            
        except Exception as e:
            print(f"✗ 地形掩码应用失败: {e}")
            import traceback
            traceback.print_exc()
            return heightmap
            
    def calculate_terrain_statistics(self, heightmap: np.ndarray) -> Dict[str, float]:
        """
        计算地形统计信息
        
        Args:
            heightmap: 高度图数据
            
        Returns:
            统计信息字典
        """
        try:
            processing_start_time = time.time()
            
            if not self.enabled:
                print("✗ 地形工具类未启用")
                return {}
                
            print("✓ 开始计算地形统计信息...")
            
            # 计算基本统计信息
            stats = {
                'min_height': float(np.min(heightmap)),
                'max_height': float(np.max(heightmap)),
                'mean_height': float(np.mean(heightmap)),
                'std_height': float(np.std(heightmap)),
                'median_height': float(np.median(heightmap)),
                'total_area': float(heightmap.size),
                'width': heightmap.shape[1],
                'height': heightmap.shape[0]
            }
            
            # 计算坡度统计
            slope_map = self.analyze_terrain_slope(heightmap)
            stats['mean_slope'] = float(np.mean(slope_map))
            stats['max_slope'] = float(np.max(slope_map))
            stats['std_slope'] = float(np.std(slope_map))
            
            # 计算曲率统计
            curvature_map = self.analyze_terrain_curvature(heightmap)
            stats['mean_curvature'] = float(np.mean(curvature_map))
            stats['max_curvature'] = float(np.max(curvature_map))
            stats['std_curvature'] = float(np.std(curvature_map))
            
            # 计算粗糙度统计
            rugosity_map = self.analyze_terrain_rugosity(heightmap)
            stats['mean_rugosity'] = float(np.mean(rugosity_map))
            stats['max_rugosity'] = float(np.max(rugosity_map))
            stats['std_rugosity'] = float(np.std(rugosity_map))
            
            # 更新统计信息
            processing_time = time.time() - processing_start_time
            self._update_stats(processing_time)
            
            print(f"✓ 地形统计信息计算完成，耗时: {processing_time:.3f}秒")
            return stats
            
        except Exception as e:
            print(f"✗ 地形统计信息计算失败: {e}")
            import traceback
            traceback.print_exc()
            return {}
            
    def _update_stats(self, processing_time: float):
        """更新统计信息"""
        self.stats['tools_used'] += 1
        self.stats['total_processing_time'] += processing_time
        if self.stats['tools_used'] > 0:
            self.stats['average_processing_time'] = (
                self.stats['total_processing_time'] / self.stats['tools_used']
            )
            
    def get_stats(self) -> Dict[str, Any]:
        """
        获取统计信息
        
        Returns:
            统计信息字典
        """
        return self.stats.copy()
        
    def reset_stats(self):
        """重置统计信息"""
        self.stats = {
            'tools_used': 0,
            'total_processing_time': 0.0,
            'average_processing_time': 0.0,
            'cache_hits': 0,
            'cache_misses': 0
        }
        print("✓ 地形工具类统计信息已重置")
        
    def set_tool_parameters(self, params: Dict[str, Any]):
        """
        设置工具参数
        
        Args:
            params: 参数字典
        """
        self.tool_params.update(params)
        print(f"✓ 地形工具参数已更新: {self.tool_params}")
        
    def export_terrain_data(self, heightmap: np.ndarray, filename: str, 
                           metadata: Dict[str, Any] = None) -> bool:
        """
        导出地形数据
        
        Args:
            heightmap: 高度图数据
            filename: 文件名
            metadata: 元数据
            
        Returns:
            是否导出成功
        """
        try:
            print(f"✓ 开始导出地形数据到: {filename}")
            
            # 创建导出数据
            export_data = {
                'heightmap': heightmap.tolist(),
                'shape': heightmap.shape,
                'dtype': str(heightmap.dtype),
                'metadata': metadata or {},
                'export_time': time.time()
            }
            
            # 保存为JSON文件
            with open(filename, 'w', encoding='utf-8') as f:
                json.dump(export_data, f, ensure_ascii=False, indent=2)
                
            print(f"✓ 地形数据导出完成")
            return True
            
        except Exception as e:
            print(f"✗ 地形数据导出失败: {e}")
            import traceback
            traceback.print_exc()
            return False
            
    def import_terrain_data(self, filename: str) -> Optional[np.ndarray]:
        """
        导入地形数据
        
        Args:
            filename: 文件名
            
        Returns:
            高度图数据或None
        """
        try:
            print(f"✓ 开始导入地形数据从: {filename}")
            
            # 读取JSON文件
            with open(filename, 'r', encoding='utf-8') as f:
                import_data = json.load(f)
                
            # 恢复高度图数据
            heightmap_data = import_data['heightmap']
            heightmap = np.array(heightmap_data, dtype=np.float32)
            
            print(f"✓ 地形数据导入完成，尺寸: {heightmap.shape}")
            return heightmap
            
        except Exception as e:
            print(f"✗ 地形数据导入失败: {e}")
            import traceback
            traceback.print_exc()
            return None
            
    def resample_heightmap(self, heightmap: np.ndarray, new_width: int, new_height: int) -> np.ndarray:
        """
        重采样高度图
        
        Args:
            heightmap: 原始高度图数据
            new_width: 新宽度
            new_height: 新高度
            
        Returns:
            重采样后的高度图数据
        """
        try:
            processing_start_time = time.time()
            
            if not self.enabled:
                print("✗ 地形工具类未启用")
                return heightmap
                
            print(f"✓ 开始重采样高度图到 {new_width}x{new_height}...")
            
            old_height, old_width = heightmap.shape
            
            # 创建新的高度图
            resampled = np.zeros((new_height, new_width), dtype=np.float32)
            
            # 双线性插值重采样
            for y in range(new_height):
                for x in range(new_width):
                    # 计算在原图中的对应位置
                    old_x = x * (old_width - 1) / (new_width - 1)
                    old_y = y * (old_height - 1) / (new_height - 1)
                    
                    # 双线性插值
                    resampled[y, x] = self._bilinear_interpolate(heightmap, old_x, old_y)
                    
            # 更新统计信息
            processing_time = time.time() - processing_start_time
            self._update_stats(processing_time)
            
            print(f"✓ 高度图重采样完成，耗时: {processing_time:.3f}秒")
            return resampled
            
        except Exception as e:
            print(f"✗ 高度图重采样失败: {e}")
            import traceback
            traceback.print_exc()
            return heightmap
            
    def _bilinear_interpolate(self, heightmap: np.ndarray, x: float, y: float) -> float:
        """
        双线性插值
        
        Args:
            heightmap: 高度图数据
            x: X坐标
            y: Y坐标
            
        Returns:
            插值结果
        """
        try:
            height, width = heightmap.shape
            
            # 获取整数部分
            x0 = int(math.floor(x))
            y0 = int(math.floor(y))
            x1 = min(x0 + 1, width - 1)
            y1 = min(y0 + 1, height - 1)
            
            # 获取小数部分
            fx = x - x0
            fy = y - y0
            
            # 双线性插值
            top = heightmap[y0, x0] * (1 - fx) + heightmap[y0, x1] * fx
            bottom = heightmap[y1, x0] * (1 - fx) + heightmap[y1, x1] * fx
            result = top * (1 - fy) + bottom * fy
            
            return result
            
        except Exception as e:
            print(f"✗ 双线性插值失败: {e}")
            return 0.0
            
    def generate_terrain_preview(self, heightmap: np.ndarray, width: int = 256, height: int = 256) -> np.ndarray:
        """
        生成地形预览图
        
        Args:
            heightmap: 高度图数据
            width: 预览图宽度
            height: 预览图高度
            
        Returns:
            预览图数据 (RGB格式)
        """
        try:
            processing_start_time = time.time()
            
            if not self.enabled:
                print("✗ 地形工具类未启用")
                return np.zeros((height, width, 3), dtype=np.uint8)
                
            print("✓ 开始生成地形预览图...")
            
            # 重采样到预览尺寸
            preview_heightmap = self.resample_heightmap(heightmap, width, height)
            
            # 创建RGB预览图
            preview = np.zeros((height, width, 3), dtype=np.uint8)
            
            # 根据高度生成颜色
            for y in range(height):
                for x in range(width):
                    height_value = preview_heightmap[y, x]
                    
                    # 根据高度选择颜色
                    if height_value < 0.2:
                        # 水域 - 蓝色
                        r, g, b = 0, 0, int(128 + height_value * 127)
                    elif height_value < 0.3:
                        # 浅水/海滩 - 浅蓝色
                        r, g, b = int(height_value * 255), int(height_value * 255), 255
                    elif height_value < 0.5:
                        # 平原 - 绿色
                        r, g, b = 0, int(100 + height_value * 155), 0
                    elif height_value < 0.7:
                        # 丘陵 - 棕色
                        r, g, b = int(139 * height_value), int(69 * height_value), int(19 * height_value)
                    elif height_value < 0.9:
                        # 山地 - 灰色
                        r, g, b = int(100 + height_value * 155), int(100 + height_value * 155), int(100 + height_value * 155)
                    else:
                        # 雪山 - 白色
                        r, g, b = 255, 255, 255
                        
                    preview[y, x] = [r, g, b]
                    
            # 更新统计信息
            processing_time = time.time() - processing_start_time
            self._update_stats(processing_time)
            
            print(f"✓ 地形预览图生成完成，耗时: {processing_time:.3f}秒")
            return preview
            
        except Exception as e:
            print(f"✗ 地形预览图生成失败: {e}")
            import traceback
            traceback.print_exc()
            return np.zeros((height, width, 3), dtype=np.uint8)
            
    def calculate_terrain_volume(self, heightmap: np.ndarray, cell_size: float = 1.0) -> float:
        """
        计算地形体积
        
        Args:
            heightmap: 高度图数据
            cell_size: 网格单元大小
            
        Returns:
            体积值
        """
        try:
            processing_start_time = time.time()
            
            if not self.enabled:
                print("✗ 地形工具类未启用")
                return 0.0
                
            print("✓ 开始计算地形体积...")
            
            # 计算总体积（假设每个网格单元是柱体）
            volume = np.sum(heightmap) * cell_size * cell_size
            
            # 更新统计信息
            processing_time = time.time() - processing_start_time
            self._update_stats(processing_time)
            
            print(f"✓ 地形体积计算完成，耗时: {processing_time:.3f}秒")
            return float(volume)
            
        except Exception as e:
            print(f"✗ 地形体积计算失败: {e}")
            import traceback
            traceback.print_exc()
            return 0.0
            
    def calculate_terrain_area(self, heightmap: np.ndarray, cell_size: float = 1.0) -> float:
        """
        计算地形表面积
        
        Args:
            heightmap: 高度图数据
            cell_size: 网格单元大小
            
        Returns:
            表面积值
        """
        try:
            processing_start_time = time.time()
            
            if not self.enabled:
                print("✗ 地形工具类未启用")
                return 0.0
                
            print("✓ 开始计算地形表面积...")
            
            height, width = heightmap.shape
            total_area = 0.0
            
            # 计算每个网格单元的表面积
            for y in range(height - 1):
                for x in range(width - 1):
                    # 获取四个角点的高度
                    h00 = heightmap[y, x]
                    h01 = heightmap[y, x + 1]
                    h10 = heightmap[y + 1, x]
                    h11 = heightmap[y + 1, x + 1]
                    
                    # 计算两个三角形的面积
                    # 三角形1: (0,0,h00), (0,1,h01), (1,0,h10)
                    dx1 = cell_size
                    dy1 = 0.0
                    dz1 = h01 - h00
                    dv1 = np.array([dx1, dy1, dz1])
                    
                    dx2 = 0.0
                    dy2 = cell_size
                    dz2 = h10 - h00
                    dv2 = np.array([dx2, dy2, dz2])
                    
                    cross1 = np.cross(dv1, dv2)
                    area1 = 0.5 * np.linalg.norm(cross1)
                    
                    # 三角形2: (1,1,h11), (0,1,h01), (1,0,h10)
                    dx3 = 0.0
                    dy3 = -cell_size
                    dz3 = h11 - h01
                    dv3 = np.array([dx3, dy3, dz3])
                    
                    dx4 = -cell_size
                    dy4 = 0.0
                    dz4 = h11 - h10
                    dv4 = np.array([dx4, dy4, dz4])
                    
                    cross2 = np.cross(dv3, dv4)
                    area2 = 0.5 * np.linalg.norm(cross2)
                    
                    total_area += area1 + area2
                    
            # 更新统计信息
            processing_time = time.time() - processing_start_time
            self._update_stats(processing_time)
            
            print(f"✓ 地形表面积计算完成，耗时: {processing_time:.3f}秒")
            return total_area
            
        except Exception as e:
            print(f"✗ 地形表面积计算失败: {e}")
            import traceback
            traceback.print_exc()
            return 0.0
            
    def detect_terrain_features(self, heightmap: np.ndarray) -> Dict[str, np.ndarray]:
        """
        检测地形特征
        
        Args:
            heightmap: 高度图数据
            
        Returns:
            特征检测结果字典
        """
        try:
            processing_start_time = time.time()
            
            if not self.enabled:
                print("✗ 地形工具类未启用")
                return {}
                
            print("✓ 开始检测地形特征...")
            
            # 检测山峰
            peaks = self._detect_peaks(heightmap)
            
            # 检测山谷
            valleys = self._detect_valleys(heightmap)
            
            # 检测山脊
            ridges = self._detect_ridges(heightmap)
            
            # 检测河道
            rivers = self._detect_rivers(heightmap)
            
            # 更新统计信息
            processing_time = time.time() - processing_start_time
            self._update_stats(processing_time)
            
            print(f"✓ 地形特征检测完成，耗时: {processing_time:.3f}秒")
            return {
                'peaks': peaks,
                'valleys': valleys,
                'ridges': ridges,
                'rivers': rivers
            }
            
        except Exception as e:
            print(f"✗ 地形特征检测失败: {e}")
            import traceback
            traceback.print_exc()
            return {}
            
    def _detect_peaks(self, heightmap: np.ndarray) -> np.ndarray:
        """检测山峰"""
        try:
            height, width = heightmap.shape
            peaks = np.zeros_like(heightmap, dtype=np.float32)
            
            # 简化的山峰检测
            for y in range(1, height - 1):
                for x in range(1, width - 1):
                    center = heightmap[y, x]
                    is_peak = True
                    
                    # 检查是否比所有邻居都高
                    for dy in [-1, 0, 1]:
                        for dx in [-1, 0, 1]:
                            if dy == 0 and dx == 0:
                                continue
                            if heightmap[y + dy, x + dx] >= center:
                                is_peak = False
                                break
                        if not is_peak:
                            break
                            
                    if is_peak and center > 0.7:  # 高度阈值
                        peaks[y, x] = center
                        
            return peaks
            
        except Exception as e:
            print(f"✗ 山峰检测失败: {e}")
            return np.zeros_like(heightmap, dtype=np.float32)
            
    def _detect_valleys(self, heightmap: np.ndarray) -> np.ndarray:
        """检测山谷"""
        try:
            height, width = heightmap.shape
            valleys = np.zeros_like(heightmap, dtype=np.float32)
            
            # 简化的山谷检测
            for y in range(1, height - 1):
                for x in range(1, width - 1):
                    center = heightmap[y, x]
                    is_valley = True
                    
                    # 检查是否比所有邻居都低
                    for dy in [-1, 0, 1]:
                        for dx in [-1, 0, 1]:
                            if dy == 0 and dx == 0:
                                continue
                            if heightmap[y + dy, x + dx] <= center:
                                is_valley = False
                                break
                        if not is_valley:
                            break
                            
                    if is_valley and center < 0.3:  # 高度阈值
                        valleys[y, x] = 1.0 - center
                        
            return valleys
            
        except Exception as e:
            print(f"✗ 山谷检测失败: {e}")
            return np.zeros_like(heightmap, dtype=np.float32)
            
    def _detect_ridges(self, heightmap: np.ndarray) -> np.ndarray:
        """检测山脊"""
        try:
            # 简化的山脊检测
            slope_map = self.analyze_terrain_slope(heightmap)
            ridge_map = np.zeros_like(heightmap, dtype=np.float32)
            
            # 山脊通常是坡度变化较大的地方
            ridge_map = np.where(slope_map > self.tool_params['slope_threshold'], slope_map, 0)
            
            return ridge_map
            
        except Exception as e:
            print(f"✗ 山脊检测失败: {e}")
            return np.zeros_like(heightmap, dtype=np.float32)
            
    def _detect_rivers(self, heightmap: np.ndarray) -> np.ndarray:
        """检测河道"""
        try:
            # 简化的河道检测
            curvature_map = self.analyze_terrain_curvature(heightmap)
            river_map = np.zeros_like(heightmap, dtype=np.float32)
            
            # 河道通常在负曲率区域（凹陷处）
            river_map = np.where(curvature_map < -self.tool_params['curvature_threshold'], 
                               np.abs(curvature_map), 0)
            
            return river_map
            
        except Exception as e:
            print(f"✗ 河道检测失败: {e}")
            return np.zeros_like(heightmap, dtype=np.float32)
            
    def fill_terrain_holes(self, heightmap: np.ndarray, hole_threshold: float = 0.01) -> np.ndarray:
        """
        填补地形空洞
        
        Args:
            heightmap: 高度图数据
            hole_threshold: 空洞阈值
            
        Returns:
            处理后的高度图数据
        """
        try:
            processing_start_time = time.time()
            
            if not self.enabled:
                print("✗ 地形工具类未启用")
                return heightmap
                
            print("✓ 开始填补地形空洞...")
            
            filled = heightmap.copy()
            height, width = filled.shape
            
            # 简化的空洞填补算法
            for y in range(1, height - 1):
                for x in range(1, width - 1):
                    center = filled[y, x]
                    
                    # 如果中心点是空洞
                    if center < hole_threshold:
                        # 计算邻居的平均值
                        neighbors = []
                        for dy in [-1, 0, 1]:
                            for dx in [-1, 0, 1]:
                                if dy == 0 and dx == 0:
                                    continue
                                neighbor_value = filled[y + dy, x + dx]
                                if neighbor_value >= hole_threshold:  # 只考虑非空洞邻居
                                    neighbors.append(neighbor_value)
                                    
                        if neighbors:
                            filled[y, x] = np.mean(neighbors)
                            
            # 更新统计信息
            processing_time = time.time() - processing_start_time
            self._update_stats(processing_time)
            
            print(f"✓ 地形空洞填补完成，耗时: {processing_time:.3f}秒")
            return filled
            
        except Exception as e:
            print(f"✗ 地形空洞填补失败: {e}")
            import traceback
            traceback.print_exc()
            return heightmap
            
    def clamp_heightmap(self, heightmap: np.ndarray, min_value: float = 0.0, 
                       max_value: float = 1.0) -> np.ndarray:
        """
        限制高度图范围
        
        Args:
            heightmap: 高度图数据
            min_value: 最小值
            max_value: 最大值
            
        Returns:
            处理后的高度图数据
        """
        try:
            processing_start_time = time.time()
            
            if not self.enabled:
                print("✗ 地形工具类未启用")
                return heightmap
                
            print("✓ 开始限制高度图范围...")
            
            # 限制范围
            clamped = np.clip(heightmap, min_value, max_value)
            
            # 更新统计信息
            processing_time = time.time() - processing_start_time
            self._update_stats(processing_time)
            
            print(f"✓ 高度图范围限制完成，耗时: {processing_time:.3f}秒")
            return clamped
            
        except Exception as e:
            print(f"✗ 高度图范围限制失败: {e}")
            import traceback
            traceback.print_exc()
            return heightmap
            
    def add_terrain_noise(self, heightmap: np.ndarray, noise_amount: float = 0.01, 
                         seed: int = None) -> np.ndarray:
        """
        添加噪声到地形
        
        Args:
            heightmap: 高度图数据
            noise_amount: 噪声强度
            seed: 随机种子
            
        Returns:
            处理后的高度图数据
        """
        try:
            processing_start_time = time.time()
            
            if not self.enabled:
                print("✗ 地形工具类未启用")
                return heightmap
                
            print("✓ 开始添加噪声到地形...")
            
            # 设置随机种子
            if seed is not None:
                np.random.seed(seed)
                
            # 生成噪声
            noise = np.random.normal(0, noise_amount, heightmap.shape).astype(np.float32)
            
            # 添加噪声
            noisy = heightmap + noise
            
            # 更新统计信息
            processing_time = time.time() - processing_start_time
            self._update_stats(processing_time)
            
            print(f"✓ 地形噪声添加完成，耗时: {processing_time:.3f}秒")
            return noisy
            
        except Exception as e:
            print(f"✗ 地形噪声添加失败: {e}")
            import traceback
            traceback.print_exc()
            return heightmap
            
    def create_terrain_from_function(self, width: int, height: int, 
                                   function: callable) -> np.ndarray:
        """
        根据函数创建地形
        
        Args:
            width: 宽度
            height: 高度
            function: 生成函数 (x, y) -> height
            
        Returns:
            生成的高度图数据
        """
        try:
            processing_start_time = time.time()
            
            if not self.enabled:
                print("✗ 地形工具类未启用")
                return np.zeros((height, width), dtype=np.float32)
                
            print("✓ 开始根据函数创建地形...")
            
            # 创建高度图
            heightmap = np.zeros((height, width), dtype=np.float32)
            
            # 应用函数
            for y in range(height):
                for x in range(width):
                    # 将坐标标准化到[-1, 1]范围
                    norm_x = (x / (width - 1)) * 2.0 - 1.0
                    norm_y = (y / (height - 1)) * 2.0 - 1.0
                    heightmap[y, x] = function(norm_x, norm_y)
                    
            # 更新统计信息
            processing_time = time.time() - processing_start_time
            self._update_stats(processing_time)
            
            print(f"✓ 函数地形创建完成，耗时: {processing_time:.3f}秒")
            return heightmap
            
        except Exception as e:
            print(f"✗ 函数地形创建失败: {e}")
            import traceback
            traceback.print_exc()
            return np.zeros((height, width), dtype=np.float32)
            
    def cache_analysis_result(self, key: str, result: Any):
        """
        缓存分析结果
        
        Args:
            key: 缓存键
            result: 分析结果
        """
        try:
            self.analysis_cache[key] = {
                'result': result,
                'timestamp': time.time()
            }
            print(f"✓ 分析结果已缓存: {key}")
        except Exception as e:
            print(f"✗ 分析结果缓存失败: {e}")
            
    def get_cached_analysis_result(self, key: str) -> Optional[Any]:
        """
        获取缓存的分析结果
        
        Args:
            key: 缓存键
            
        Returns:
            缓存的分析结果或None
        """
        try:
            if key in self.analysis_cache:
                self.stats['cache_hits'] += 1
                return self.analysis_cache[key]['result']
            else:
                self.stats['cache_misses'] += 1
                return None
        except Exception as e:
            print(f"✗ 缓存分析结果获取失败: {e}")
            return None
            
    def clear_analysis_cache(self):
        """清空分析缓存"""
        try:
            self.analysis_cache.clear()
            print("✓ 分析缓存已清空")
        except Exception as e:
            print(f"✗ 分析缓存清空失败: {e}")
            
    def get_cache_stats(self) -> Dict[str, int]:
        """
        获取缓存统计信息
        
        Returns:
            缓存统计信息
        """
        return {
            'cache_size': len(self.analysis_cache),
            'cache_hits': self.stats['cache_hits'],
            'cache_misses': self.stats['cache_misses'],
            'hit_rate': self.stats['cache_hits'] / max(1, self.stats['cache_hits'] + self.stats['cache_misses'])
        }