|  | @@ -1,245 +1,133 @@
 | 
											
												
													
														|  |  import * as THREE from 'three';
 |  |  import * as THREE from 'three';
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  export class PltDataRenderer {
 |  |  export class PltDataRenderer {
 | 
											
												
													
														|  | -  constructor(updateProgress, onComplete) {
 |  | 
 | 
											
												
													
														|  | -    this.updateProgress = updateProgress || (() => {});
 |  | 
 | 
											
												
													
														|  | -    this.onComplete = onComplete || (() => {});
 |  | 
 | 
											
												
													
														|  | -    this.chunkSize = 5000; // 每个区域的最大三角面片数(用于分块加载)
 |  | 
 | 
											
												
													
														|  | -    this.defaultMaterial = new THREE.MeshPhongMaterial({
 |  | 
 | 
											
												
													
														|  | -      color: 0x4477ff,
 |  | 
 | 
											
												
													
														|  | -      specular: 0x111111,
 |  | 
 | 
											
												
													
														|  | -      shininess: 30,
 |  | 
 | 
											
												
													
														|  | -      side: THREE.DoubleSide, // 关键修改:双面渲染
 |  | 
 | 
											
												
													
														|  | -      flatShading: false,     // 平滑着色
 |  | 
 | 
											
												
													
														|  | -      transparent: true,
 |  | 
 | 
											
												
													
														|  | -      opacity: 0.95
 |  | 
 | 
											
												
													
														|  | -    });
 |  | 
 | 
											
												
													
														|  | -    this.wireframeMaterial = new THREE.MeshBasicMaterial({
 |  | 
 | 
											
												
													
														|  | -      color: 0x00ff00,
 |  | 
 | 
											
												
													
														|  | -      wireframe: true
 |  | 
 | 
											
												
													
														|  | -    });
 |  | 
 | 
											
												
													
														|  | -  }
 |  | 
 | 
											
												
													
														|  | -  
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -  async render(pltData, scene, specificZoneIndex = null) {
 |  | 
 | 
											
												
													
														|  | -    console.log("原始PLT数据结构诊断:", {
 |  | 
 | 
											
												
													
														|  | -      zones: pltData.zones.map(zone => ({
 |  | 
 | 
											
												
													
														|  | -        name: zone.name,
 |  | 
 | 
											
												
													
														|  | -        verticesType: zone.vertices?.constructor?.name,
 |  | 
 | 
											
												
													
														|  | -        verticesLength: zone.vertices?.length,
 |  | 
 | 
											
												
													
														|  | -        verticesSample: zone.vertices?.slice(0, 3),
 |  | 
 | 
											
												
													
														|  | -        indicesType: zone.indices?.constructor?.name,
 |  | 
 | 
											
												
													
														|  | -        indicesLength: zone.indices?.length,
 |  | 
 | 
											
												
													
														|  | -        indicesSample: zone.indices?.slice(0, 3)
 |  | 
 | 
											
												
													
														|  | -      }))
 |  | 
 | 
											
												
													
														|  | -    });
 |  | 
 | 
											
												
													
														|  | -    if (!pltData?.zones?.length) {
 |  | 
 | 
											
												
													
														|  | -      console.error('Invalid PLT data');
 |  | 
 | 
											
												
													
														|  | -      return;
 |  | 
 | 
											
												
													
														|  | -    }
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -    // 清空现有PLT相关对象
 |  | 
 | 
											
												
													
														|  | -    this._cleanupPreviousRender(scene);
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -    // 如果指定了具体区域索引,则只渲染该区域
 |  | 
 | 
											
												
													
														|  | -    if (specificZoneIndex !== null) {
 |  | 
 | 
											
												
													
														|  | -      if (specificZoneIndex < 0 || specificZoneIndex >= pltData.zones.length) {
 |  | 
 | 
											
												
													
														|  | -        console.error(`Invalid zone index: ${specificZoneIndex} (total zones: ${pltData.zones.length})`);
 |  | 
 | 
											
												
													
														|  | -        return;
 |  | 
 | 
											
												
													
														|  | -      }
 |  | 
 | 
											
												
													
														|  | -      
 |  | 
 | 
											
												
													
														|  | -      const zone = pltData.zones[specificZoneIndex];
 |  | 
 | 
											
												
													
														|  | -      await this._renderZone(zone, scene, specificZoneIndex, pltData.zones.length);
 |  | 
 | 
											
												
													
														|  | -      console.log(`[DEBUG] 仅渲染了区域 ${specificZoneIndex}: ${zone.name}`);
 |  | 
 | 
											
												
													
														|  | -      return;
 |  | 
 | 
											
												
													
														|  | 
 |  | +    constructor(updateProgress, onComplete) {
 | 
											
												
													
														|  | 
 |  | +        this.updateProgress = updateProgress;
 | 
											
												
													
														|  | 
 |  | +        this.onComplete = onComplete;
 | 
											
												
													
														|  | 
 |  | +        this.meshGroup = new THREE.Group();
 | 
											
												
													
														|  | 
 |  | +        
 | 
											
												
													
														|  | 
 |  | +        this.defaultMaterial = new THREE.MeshPhongMaterial({
 | 
											
												
													
														|  | 
 |  | +            color: 0xffffff, // 改为白色基础色
 | 
											
												
													
														|  | 
 |  | +            specular: 0x111111, // 适当的高光
 | 
											
												
													
														|  | 
 |  | +            shininess: 30,
 | 
											
												
													
														|  | 
 |  | +            side: THREE.DoubleSide,
 | 
											
												
													
														|  | 
 |  | +            flatShading: false, // 改为false获得更平滑的 shading
 | 
											
												
													
														|  | 
 |  | +            vertexColors: true,
 | 
											
												
													
														|  | 
 |  | +            transparent: true,
 | 
											
												
													
														|  | 
 |  | +            opacity: 1.0 // 不透明度设为1
 | 
											
												
													
														|  | 
 |  | +        });
 | 
											
												
													
														|  | 
 |  | +        this.defaultLights = [
 | 
											
												
													
														|  | 
 |  | +            new THREE.AmbientLight(0xffffff, 1.0), // 环境光(强度增强)
 | 
											
												
													
														|  | 
 |  | +            new THREE.DirectionalLight(0xffffff, 1.5), // 平行光(强度增强)
 | 
											
												
													
														|  | 
 |  | +            new THREE.HemisphereLight(0xffffbb, 0x080820, 0.8) // 天光
 | 
											
												
													
														|  | 
 |  | +        ];
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -    // 否则渲染所有区域(原有逻辑)
 |  | 
 | 
											
												
													
														|  | -    const totalZones = pltData.zones.length;
 |  | 
 | 
											
												
													
														|  | -    for (const [index, zone] of pltData.zones.entries()) {
 |  | 
 | 
											
												
													
														|  | -      try {
 |  | 
 | 
											
												
													
														|  | -        await this._renderZone(zone, scene, index, totalZones);
 |  | 
 | 
											
												
													
														|  | -        this.updateProgress((index + 1) / totalZones);
 |  | 
 | 
											
												
													
														|  | -      } catch (error) {
 |  | 
 | 
											
												
													
														|  | -        console.error(`Failed to render zone ${zone.name}:`, error);
 |  | 
 | 
											
												
													
														|  | -      }
 |  | 
 | 
											
												
													
														|  | -      await new Promise(resolve => setTimeout(resolve, 0));
 |  | 
 | 
											
												
													
														|  | 
 |  | +    async render(pltData, scene) {
 | 
											
												
													
														|  | 
 |  | +      // 清除旧光照
 | 
											
												
													
														|  | 
 |  | +        scene.traverse(obj => {
 | 
											
												
													
														|  | 
 |  | +            if (obj.isLight) scene.remove(obj);
 | 
											
												
													
														|  | 
 |  | +        });
 | 
											
												
													
														|  | 
 |  | +        
 | 
											
												
													
														|  | 
 |  | +        // 添加新光照
 | 
											
												
													
														|  | 
 |  | +        this.defaultLights.forEach(light => {
 | 
											
												
													
														|  | 
 |  | +            if (light.isDirectionalLight) {
 | 
											
												
													
														|  | 
 |  | +                light.position.set(1, 1, 1).normalize();
 | 
											
												
													
														|  | 
 |  | +            }
 | 
											
												
													
														|  | 
 |  | +            scene.add(light);
 | 
											
												
													
														|  | 
 |  | +        });
 | 
											
												
													
														|  | 
 |  | +        this.clearScene(scene);
 | 
											
												
													
														|  | 
 |  | +        scene.add(this.meshGroup);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +        try {
 | 
											
												
													
														|  | 
 |  | +            await this.updateProgressAsync('开始渲染PLT模型...');
 | 
											
												
													
														|  | 
 |  | +            
 | 
											
												
													
														|  | 
 |  | +            // 处理每个zone
 | 
											
												
													
														|  | 
 |  | +            for (const zone of pltData.zones) {
 | 
											
												
													
														|  | 
 |  | +                await this.updateProgressAsync(`正在处理区域: ${zone.name}...`);
 | 
											
												
													
														|  | 
 |  | +                
 | 
											
												
													
														|  | 
 |  | +                // 创建几何体
 | 
											
												
													
														|  | 
 |  | +                const geometry = new THREE.BufferGeometry();
 | 
											
												
													
														|  | 
 |  | +                
 | 
											
												
													
														|  | 
 |  | +                // 设置顶点属性
 | 
											
												
													
														|  | 
 |  | +                geometry.setAttribute(
 | 
											
												
													
														|  | 
 |  | +                    'position',
 | 
											
												
													
														|  | 
 |  | +                    new THREE.BufferAttribute(new Float32Array(zone.vertices), 3)
 | 
											
												
													
														|  | 
 |  | +                );
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +                // 设置索引
 | 
											
												
													
														|  | 
 |  | +                if (zone.indices && zone.indices.length > 0) {
 | 
											
												
													
														|  | 
 |  | +                    geometry.setIndex(
 | 
											
												
													
														|  | 
 |  | +                        new THREE.BufferAttribute(new Uint32Array(zone.indices), 1)
 | 
											
												
													
														|  | 
 |  | +                    );
 | 
											
												
													
														|  | 
 |  | +                }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +                // 设置顶点颜色(使用CoefPressure变量)
 | 
											
												
													
														|  | 
 |  | +                if (zone.variables && zone.variables.CoefPressure) {
 | 
											
												
													
														|  | 
 |  | +                    const colors = this.generateVertexColors(zone.variables.CoefPressure);
 | 
											
												
													
														|  | 
 |  | +                    geometry.setAttribute(
 | 
											
												
													
														|  | 
 |  | +                        'color',
 | 
											
												
													
														|  | 
 |  | +                        new THREE.BufferAttribute(new Float32Array(colors), 3)
 | 
											
												
													
														|  | 
 |  | +                    );
 | 
											
												
													
														|  | 
 |  | +                }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +                await this.updateProgressAsync('优化几何体...');
 | 
											
												
													
														|  | 
 |  | +                geometry.computeVertexNormals();
 | 
											
												
													
														|  | 
 |  | +                geometry.computeBoundingSphere();
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +                await this.updateProgressAsync('创建网格...');
 | 
											
												
													
														|  | 
 |  | +                const mesh = new THREE.Mesh(geometry, this.defaultMaterial);
 | 
											
												
													
														|  | 
 |  | +                mesh.name = zone.name;
 | 
											
												
													
														|  | 
 |  | +                this.meshGroup.add(mesh);
 | 
											
												
													
														|  | 
 |  | +            }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +            if (this.onComplete) this.onComplete();
 | 
											
												
													
														|  | 
 |  | +        } catch (error) {
 | 
											
												
													
														|  | 
 |  | +            console.error('PLT渲染错误:', error);
 | 
											
												
													
														|  | 
 |  | +            if (this.onComplete) this.onComplete(error);
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -    this.onComplete();
 |  | 
 | 
											
												
													
														|  | -  }
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -  async _renderZone(zone, scene, zoneIndex, totalZones) {
 |  | 
 | 
											
												
													
														|  | -    return new Promise((resolve) => {
 |  | 
 | 
											
												
													
														|  | -      // 使用requestAnimationFrame避免阻塞UI
 |  | 
 | 
											
												
													
														|  | -      requestAnimationFrame(() => {
 |  | 
 | 
											
												
													
														|  | -        if (!zone.vertices || !zone.indices) {
 |  | 
 | 
											
												
													
														|  | -          console.warn(`Zone ${zone.name} has no geometry data`);
 |  | 
 | 
											
												
													
														|  | -          return resolve();
 |  | 
 | 
											
												
													
														|  | 
 |  | +    generateVertexColors(data) {
 | 
											
												
													
														|  | 
 |  | +        // 添加数据验证
 | 
											
												
													
														|  | 
 |  | +        if (!data || !Array.isArray(data) || data.length === 0) {
 | 
											
												
													
														|  | 
 |  | +            console.warn('无效的顶点颜色数据,使用默认颜色');
 | 
											
												
													
														|  | 
 |  | +            return new Array(data.length * 3).fill(0.5); // 返回灰色
 | 
											
												
													
														|  |          }
 |  |          }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -        // 创建几何体
 |  | 
 | 
											
												
													
														|  | -        const geometry = this._createZoneGeometry(zone);
 |  | 
 | 
											
												
													
														|  | 
 |  | +        const min = Math.min(...data);
 | 
											
												
													
														|  | 
 |  | +        const max = Math.max(...data);
 | 
											
												
													
														|  | 
 |  | +        const range = max - min || 1; // 避免除以0
 | 
											
												
													
														|  |          
 |  |          
 | 
											
												
													
														|  | -        // 分配材质(交替使用实体和线框材质)
 |  | 
 | 
											
												
													
														|  | -        const material = zoneIndex % 2 === 0 
 |  | 
 | 
											
												
													
														|  | -          ? this.defaultMaterial.clone()
 |  | 
 | 
											
												
													
														|  | -          : this.wireframeMaterial.clone();
 |  | 
 | 
											
												
													
														|  | -        
 |  | 
 | 
											
												
													
														|  | -        // 设置区域特定颜色
 |  | 
 | 
											
												
													
														|  | -        if (zoneIndex % 2 === 0) {
 |  | 
 | 
											
												
													
														|  | -          material.color.setHSL(zoneIndex / totalZones, 0.7, 0.5);
 |  | 
 | 
											
												
													
														|  | -        } else {
 |  | 
 | 
											
												
													
														|  | -          material.color.setHSL(zoneIndex / totalZones, 0.7, 0.7);
 |  | 
 | 
											
												
													
														|  | -        }
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -        // 创建网格
 |  | 
 | 
											
												
													
														|  | -        const mesh = new THREE.Mesh(geometry, material);
 |  | 
 | 
											
												
													
														|  | -        mesh.name = `plt_zone_${zoneIndex}`;
 |  | 
 | 
											
												
													
														|  | -        mesh.userData = {
 |  | 
 | 
											
												
													
														|  | -          zoneName: zone.name,
 |  | 
 | 
											
												
													
														|  | -          zoneType: zone.type,
 |  | 
 | 
											
												
													
														|  | -          isPLT: true
 |  | 
 | 
											
												
													
														|  | -        };
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -        // 添加到场景
 |  | 
 | 
											
												
													
														|  | -        scene.add(mesh);
 |  | 
 | 
											
												
													
														|  | 
 |  | +        const colors = new Array(data.length * 3);
 | 
											
												
													
														|  |          
 |  |          
 | 
											
												
													
														|  | -        // 添加区域标签(可选)
 |  | 
 | 
											
												
													
														|  | -        this._addZoneLabel(zone, mesh, zoneIndex);
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -        console.log(`Rendered zone ${zone.name} with ${geometry.index.count / 3} triangles`);
 |  | 
 | 
											
												
													
														|  | -        resolve();
 |  | 
 | 
											
												
													
														|  | -      });
 |  | 
 | 
											
												
													
														|  | -    });
 |  | 
 | 
											
												
													
														|  | -  }
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -  _createZoneGeometry(zone) {
 |  | 
 | 
											
												
													
														|  | -    const geometry = new THREE.BufferGeometry();
 |  | 
 | 
											
												
													
														|  | -    
 |  | 
 | 
											
												
													
														|  | -    // 顶点数据
 |  | 
 | 
											
												
													
														|  | -    geometry.setAttribute(
 |  | 
 | 
											
												
													
														|  | -      'position',
 |  | 
 | 
											
												
													
														|  | -      new THREE.BufferAttribute(zone.vertices, 3)
 |  | 
 | 
											
												
													
														|  | -    );
 |  | 
 | 
											
												
													
														|  | -  
 |  | 
 | 
											
												
													
														|  | -    // 安全极值计算函数
 |  | 
 | 
											
												
													
														|  | -    const getArrayExtremes = (arr) => {
 |  | 
 | 
											
												
													
														|  | -      let min = Infinity, max = -Infinity;
 |  | 
 | 
											
												
													
														|  | -      for (let i = 0; i < arr.length; i++) {
 |  | 
 | 
											
												
													
														|  | -        if (arr[i] < min) min = arr[i];
 |  | 
 | 
											
												
													
														|  | -        if (arr[i] > max) max = arr[i];
 |  | 
 | 
											
												
													
														|  | -      }
 |  | 
 | 
											
												
													
														|  | -      return { min, max };
 |  | 
 | 
											
												
													
														|  | -    };
 |  | 
 | 
											
												
													
														|  | -  
 |  | 
 | 
											
												
													
														|  | -    // 索引处理
 |  | 
 | 
											
												
													
														|  | -    let indicesArray = zone.indices || new Uint32Array(0);
 |  | 
 | 
											
												
													
														|  | -    if (indicesArray.length > 0) {
 |  | 
 | 
											
												
													
														|  | -      // 计算极值
 |  | 
 | 
											
												
													
														|  | -      const { min: minIndex, max: maxIndex } = getArrayExtremes(indicesArray);
 |  | 
 | 
											
												
													
														|  | -      const vertexCount = zone.vertices.length / 3;
 |  | 
 | 
											
												
													
														|  | -  
 |  | 
 | 
											
												
													
														|  | -      // 索引验证
 |  | 
 | 
											
												
													
														|  | -      if (maxIndex >= vertexCount) {
 |  | 
 | 
											
												
													
														|  | -        console.warn(`修正${maxIndex - vertexCount + 1}个超出范围的索引`);
 |  | 
 | 
											
												
													
														|  | -        const validIndices = new Uint32Array(indicesArray.length);
 |  | 
 | 
											
												
													
														|  | -        for (let i = 0; i < indicesArray.length; i++) {
 |  | 
 | 
											
												
													
														|  | -          validIndices[i] = indicesArray[i] >= vertexCount ? 0 : indicesArray[i];
 |  | 
 | 
											
												
													
														|  | 
 |  | +        for (let i = 0; i < data.length; i++) {
 | 
											
												
													
														|  | 
 |  | +            const normalized = (data[i] - min) / range;
 | 
											
												
													
														|  | 
 |  | +            
 | 
											
												
													
														|  | 
 |  | +            // 热力图颜色映射
 | 
											
												
													
														|  | 
 |  | +            colors[i * 3] = normalized;         // R
 | 
											
												
													
														|  | 
 |  | +            colors[i * 3 + 1] = 0;              // G
 | 
											
												
													
														|  | 
 |  | +            colors[i * 3 + 2] = 1 - normalized; // B
 | 
											
												
													
														|  |          }
 |  |          }
 | 
											
												
													
														|  | -        indicesArray = validIndices;
 |  | 
 | 
											
												
													
														|  | -      }
 |  | 
 | 
											
												
													
														|  | -  
 |  | 
 | 
											
												
													
														|  | -      // 四边形转换
 |  | 
 | 
											
												
													
														|  | -      if (indicesArray.length % 4 === 0) {
 |  | 
 | 
											
												
													
														|  | -        console.log('四边形->三角形转换');
 |  | 
 | 
											
												
													
														|  | -        const triCount = indicesArray.length / 4 * 6;
 |  | 
 | 
											
												
													
														|  | -        const triangles = new Uint32Array(triCount);
 |  | 
 | 
											
												
													
														|  |          
 |  |          
 | 
											
												
													
														|  | -        for (let i = 0; i < indicesArray.length / 4; i++) {
 |  | 
 | 
											
												
													
														|  | -          const base = i * 4;
 |  | 
 | 
											
												
													
														|  | -          triangles[i*6]   = indicesArray[base];
 |  | 
 | 
											
												
													
														|  | -          triangles[i*6+1] = indicesArray[base+1];
 |  | 
 | 
											
												
													
														|  | -          triangles[i*6+2] = indicesArray[base+2];
 |  | 
 | 
											
												
													
														|  | -          triangles[i*6+3] = indicesArray[base];
 |  | 
 | 
											
												
													
														|  | -          triangles[i*6+4] = indicesArray[base+2];
 |  | 
 | 
											
												
													
														|  | -          triangles[i*6+5] = indicesArray[base+3];
 |  | 
 | 
											
												
													
														|  | -        }
 |  | 
 | 
											
												
													
														|  | -        indicesArray = triangles;
 |  | 
 | 
											
												
													
														|  | -      }
 |  | 
 | 
											
												
													
														|  | -  
 |  | 
 | 
											
												
													
														|  | -      geometry.setIndex(new THREE.BufferAttribute(indicesArray, 1));
 |  | 
 | 
											
												
													
														|  | 
 |  | +        return colors;
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  | -  
 |  | 
 | 
											
												
													
														|  | -    // 计算边界
 |  | 
 | 
											
												
													
														|  | -    geometry.computeBoundingSphere();
 |  | 
 | 
											
												
													
														|  | -    geometry.computeBoundingBox();
 |  | 
 | 
											
												
													
														|  | -    
 |  | 
 | 
											
												
													
														|  | -    console.log('几何体验证:', {
 |  | 
 | 
											
												
													
														|  | -      vertices: zone.vertices.length / 3,
 |  | 
 | 
											
												
													
														|  | -      triangles: indicesArray.length / 3,
 |  | 
 | 
											
												
													
														|  | -      radius: geometry.boundingSphere.radius.toFixed(2)
 |  | 
 | 
											
												
													
														|  | -    });
 |  | 
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -    geometry.computeVertexNormals(); 
 |  | 
 | 
											
												
													
														|  | -    console.log('法线检查:', {
 |  | 
 | 
											
												
													
														|  | -      firstNormal: geometry.attributes.normal?.array.slice(0, 3)
 |  | 
 | 
											
												
													
														|  | -    });
 |  | 
 | 
											
												
													
														|  | -  
 |  | 
 | 
											
												
													
														|  | -    return geometry;
 |  | 
 | 
											
												
													
														|  | -  }
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -  _addZoneLabel(zone, mesh, zoneIndex) {
 |  | 
 | 
											
												
													
														|  | -    // 使用CSS2DRenderer需要先初始化
 |  | 
 | 
											
												
													
														|  | -    if (!this.labelRenderer) return;
 |  | 
 | 
											
												
													
														|  | -    
 |  | 
 | 
											
												
													
														|  | -    const labelDiv = document.createElement('div');
 |  | 
 | 
											
												
													
														|  | -    labelDiv.className = 'plt-zone-label';
 |  | 
 | 
											
												
													
														|  | -    labelDiv.textContent = `${zone.name}`;
 |  | 
 | 
											
												
													
														|  | -    labelDiv.style.backgroundColor = `hsla(${zoneIndex * 360 / 8}, 70%, 50%, 0.7)`;
 |  | 
 | 
											
												
													
														|  | -    
 |  | 
 | 
											
												
													
														|  | -    const label = new THREE.CSS2DObject(labelDiv);
 |  | 
 | 
											
												
													
														|  | -    label.position.set(0, 0, 0); // 位置会在动画中更新
 |  | 
 | 
											
												
													
														|  | -    
 |  | 
 | 
											
												
													
														|  | -    mesh.userData.label = label;
 |  | 
 | 
											
												
													
														|  | -    mesh.add(label);
 |  | 
 | 
											
												
													
														|  | -  }
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -  _cleanupPreviousRender(scene) {
 |  | 
 | 
											
												
													
														|  | -    scene.children.forEach(obj => {
 |  | 
 | 
											
												
													
														|  | -      if (obj.userData?.isPLT) {
 |  | 
 | 
											
												
													
														|  | -        // 清理几何体和材质
 |  | 
 | 
											
												
													
														|  | -        if (obj.geometry) obj.geometry.dispose();
 |  | 
 | 
											
												
													
														|  | -        if (obj.material) {
 |  | 
 | 
											
												
													
														|  | -          if (Array.isArray(obj.material)) {
 |  | 
 | 
											
												
													
														|  | -            obj.material.forEach(m => m.dispose());
 |  | 
 | 
											
												
													
														|  | -          } else {
 |  | 
 | 
											
												
													
														|  | -            obj.material.dispose();
 |  | 
 | 
											
												
													
														|  | -          }
 |  | 
 | 
											
												
													
														|  | -        }
 |  | 
 | 
											
												
													
														|  | -        // 清理标签
 |  | 
 | 
											
												
													
														|  | -        if (obj.userData.label) {
 |  | 
 | 
											
												
													
														|  | -          obj.remove(obj.userData.label);
 |  | 
 | 
											
												
													
														|  | 
 |  | +    async updateProgressAsync(message) {
 | 
											
												
													
														|  | 
 |  | +        if (this.updateProgress) {
 | 
											
												
													
														|  | 
 |  | +            this.updateProgress(message);
 | 
											
												
													
														|  | 
 |  | +            await new Promise(resolve => requestAnimationFrame(resolve));
 | 
											
												
													
														|  |          }
 |  |          }
 | 
											
												
													
														|  | -        scene.remove(obj);
 |  | 
 | 
											
												
													
														|  | -      }
 |  | 
 | 
											
												
													
														|  | -    });
 |  | 
 | 
											
												
													
														|  | -  }
 |  | 
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -  // 更新标签位置(需要在动画循环中调用)
 |  | 
 | 
											
												
													
														|  | -  updateLabels(camera) {
 |  | 
 | 
											
												
													
														|  | -    if (!this.labelRenderer) return;
 |  | 
 | 
											
												
													
														|  | -    
 |  | 
 | 
											
												
													
														|  | -    this.labelRenderer.render(scene, camera);
 |  | 
 | 
											
												
													
														|  | -    
 |  | 
 | 
											
												
													
														|  | -    scene.children.forEach(obj => {
 |  | 
 | 
											
												
													
														|  | -      if (obj.userData?.label) {
 |  | 
 | 
											
												
													
														|  | -        // 将标签定位到几何中心
 |  | 
 | 
											
												
													
														|  | -        obj.geometry.computeBoundingSphere();
 |  | 
 | 
											
												
													
														|  | -        const center = obj.geometry.boundingSphere.center.clone();
 |  | 
 | 
											
												
													
														|  | -        obj.localToWorld(center);
 |  | 
 | 
											
												
													
														|  | -        obj.userData.label.position.copy(center);
 |  | 
 | 
											
												
													
														|  | -      }
 |  | 
 | 
											
												
													
														|  | -    });
 |  | 
 | 
											
												
													
														|  | -  }
 |  | 
 | 
											
												
													
														|  | 
 |  | +    clearScene(scene) {
 | 
											
												
													
														|  | 
 |  | +        this.meshGroup.traverse(child => {
 | 
											
												
													
														|  | 
 |  | +            if (child.isMesh) {
 | 
											
												
													
														|  | 
 |  | +                child.geometry.dispose();
 | 
											
												
													
														|  | 
 |  | +                child.material.dispose();
 | 
											
												
													
														|  | 
 |  | +            }
 | 
											
												
													
														|  | 
 |  | +        });
 | 
											
												
													
														|  | 
 |  | +        scene.remove(this.meshGroup);
 | 
											
												
													
														|  | 
 |  | +        this.meshGroup = new THREE.Group();
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  |  }
 |  |  }
 |