three.js 记录


   1 var THREE = require('three');
   2 
   3 import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
   4 import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader.js';
   5 import Stats from 'three/examples/jsm/libs/stats.module.js';
   6 import Zlib from 'three/examples/jsm/libs/inflate.module.min.js';
   7 
   8 import { CSS2DRenderer, CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer.js';
   9 import {
  10   fjFacti, cdzsqFacti, sxtFacti, lightFacti, qbbfFacti, qbbmFacti, coviFacti, xfsbFacti, hztcqFacti, jjdhFacti, fsfxFacti, kzsFacti, kbxsFacti, cljcqFacti, jlmFacti,
  11   hldFacti, dngqFacti, bxFacti, cdzsqFactiNo
  12 } from './loadFactites.js'
  13 import { getFacs, getHoles, listPartitionByHoleId } from "@/api/mainsys.js"
  14 import { showPop } from './pop';
  15 
  16 
  17 var container, stats, controls;
  18 var camera, scene, renderer, light, labelRenderer;
  19 var vueObj;
  20 
  21 
  22 // 创建一个时钟对象Clock
  23 //var clock = new THREE.Clock();
  24 
  25 var groupSb = new THREE.Group();//设备模型
  26 var fjArray = [];//风机模型数组
  27 var fjdirection;//风机旋转方向控制变量
  28 
  29 //var textLoader = new THREE.FontLoader();//文字加载器
  30 
  31 
  32 var speedRight = null;//可变限速数值文字模型(右洞)
  33 var kbxsRightSb = null;//可变限速模型(右洞)
  34 
  35 var speedLeft = null;//可变限速数值文字模型(左洞)
  36 var kbxsLeftSb = null;//可变限速模型(左洞)
  37 
  38 
  39 var textM = null;//可变信息板门架式文字模型
  40 var qbbmSb = null;//可变信息板门架式模型
  41 var mapM = 0;//循环控制文字显示
  42 var textMwidth;//纹理X坐标
  43 
  44 var textF = null;//可变信息板F式文字模型
  45 var qbbfSb = null;//可变信息板F式模型
  46 var mapF = 0;//循环控制文字显示
  47 var intervalF = null;
  48 
  49 
  50 var ani = null;
  51 var ani2 = null;
  52 
  53 const toResize = () => {
  54   renderer.setSize(container.offsetWidth, container.offsetHeight);
  55 }//窗口自适应函数
  56 
  57 var loader = new FBXLoader();
  58 
  59 export function init(obj) {
  60 
  61   vueObj = null;
  62   vueObj = obj;
  63   container = document.getElementById('info');
  64   console.log('vueObj', vueObj)
  65 
  66   camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 2525000);
  67 
  68   // camera.rotation.set( 30,0,0)
  69   // 摄像机位置
  70   camera.position.set(60000, 7000, 37000);
  71   // camera.zoom = -3
  72   controls = new OrbitControls(camera, container);
  73   // 控制缩放范围
  74   controls.maxDistance = 252500;
  75   controls.minDistance = 0;
  76   // 控制垂直旋转角度
  77   controls.maxPolarAngle = 1.5
  78   controls.minPolarAngle = 0.1
  79 
  80   // controls.enablePan = false
  81   // 旋转中心点
  82   //controls.target.set(1000, 0, 1000);
  83   controls.update();
  84   //场景
  85   scene = new THREE.Scene();
  86   // scene.background = new THREE.Color( '#62A5F4' );
  87   // scene.fog = new THREE.Fog( 0xa0a0a0, 200, 1000 );
  88 
  89   light = new THREE.HemisphereLight(0xffffff, 0xffffff, 1);
  90   light.position.set(0, 2000, 0);
  91   scene.add(light);
  92 
  93 
  94   // 坐标轴工具类
  95   var axesHelper = new THREE.AxesHelper(35000);
  96   scene.add(axesHelper);
  97 
  98   light = new THREE.DirectionalLight(0xffffff, 0.7);
  99   light.position.set(0, 200, 100);
 100   light.castShadow = true;
 101   light.shadow.camera.top = 180;
 102   light.shadow.camera.bottom = -100;
 103   light.shadow.camera.left = -120;
 104   light.shadow.camera.right = 120;
 105   scene.add(light);
 106   // 模拟相机视锥体的辅助对象
 107   // scene.add( new THREE.CameraHelper( light.shadow.camera ) );
 108 
 109 
 110   // var grid = new THREE.GridHelper( 2000, 20, 0x000000, 0x000000 );
 111   // grid.material.opacity = 0.2;
 112   // grid.material.transparent = true;
 113   // scene.add( grid );
 114   renderer = new THREE.WebGLRenderer({
 115     antialias: true,
 116     alpha: true
 117   });
 118   renderer.setClearAlpha(0.2);
 119   renderer.setPixelRatio(window.devicePixelRatio);
 120   renderer.setSize(container.offsetWidth, container.offsetHeight);
 121   renderer.shadowMap.enabled = true;
 122   document.getElementById("info").appendChild(renderer.domElement);
 123 
 124   window.addEventListener('resize', toResize)
 125 
 126   // model
 127   // var loader = new FBXLoader();
 128   // 地面模型
 129   loader.load('../../static/threed/隧道三车道.FBX', function (object) {
 130     console.log('loader', loader)
 131     object.name = "dm";
 132     scene.add(object);
 133 
 134     // console.log(object)
 135 
 136     // object.children.forEach((item,index)=>{
 137     //   // if(index===7) item.translateY(10000)
 138     //   // if(index===8) item.translateY(10000)
 139     //   // if(index===9) item.translateY(10000)
 140     //   //if(index===15) item.translateY(10000)
 141     //   //if(index===15) item.translateY(10000)
 142     // })
 143 
 144   });
 145 
 146   // function getTextCanvas(text) {
 147   //   var width = 512, height = 256;
 148   //   var canvas = document.createElement('canvas');
 149   //   canvas.width = width;
 150   //   canvas.height = height;
 151   //   var ctx = canvas.getContext('2d');
 152   //   ctx.fillStyle = '#C3C3C3';
 153   //   ctx.fillRect(0, 0, width, height);
 154   //   ctx.font = 50 + 'px " bold';
 155   //   ctx.fillStyle = '#2891FF';
 156   //   ctx.textAlign = 'center';
 157   //   ctx.textBaseline = 'middle';
 158   //   ctx.fillText(text, width / 2, height / 2);
 159   //   return canvas;
 160   // }
 161   // var geometry = new THREE.PlaneBufferGeometry(512, 256);
 162   // var material = new THREE.MeshBasicMaterial({ map: new THREE.CanvasTexture(getTextCanvas('我是你爸爸')) });// top
 163   // var mesh = new THREE.Mesh(geometry, material);
 164   // scene.add(mesh)
 165   // mesh.scale.set(10, 10, 10)
 166 
 167 
 168 
 169   // 基础设备  包含控制室  车道白线等
 170   getBaseSB().then(obj => {
 171     getBaseFacl(obj)
 172 
 173   })
 174 
 175   // window.addEventListener( 'resize', onWindowResize, false );
 176 
 177 
 178   // window.addEventListener( 'mousemove', dragScence, false );
 179 
 180   // 隧道所用设备  风机  情报板等等
 181   getSB().then(obj => {
 182     getFacl(obj)
 183   });
 184 
 185   container.addEventListener('mousedown', onDocumentMouseDown, false);
 186   animate()
 187 
 188 }
 189 
 190 function animate() {
 191   ani = requestAnimationFrame(animate);
 192   fjRotate();
 193   fontRun();
 194   controls.update();
 195   renderer.render(scene, camera);
 196 }
 197 async function getBaseSB() {
 198   let kzs = await kzsFacti();
 199   let bx = await bxFacti();
 200   let o = { kzs, bx };
 201   return o;
 202 }
 203 async function getSB() {
 204 
 205   let fj = await fjFacti();
 206   let cdzsq = await cdzsqFacti();
 207   let sxt = await sxtFacti();
 208   let light = await lightFacti();
 209   let qbbf = await qbbfFacti();
 210   let qbbm = await qbbmFacti();
 211   let covi = await coviFacti();
 212   let xfsb = await xfsbFacti();
 213   let hztcq = await hztcqFacti();
 214   let jjdh = await jjdhFacti();
 215   let fsfx = await fsfxFacti();
 216   let kbxs = await kbxsFacti();
 217   let hld = await hldFacti();
 218   let dngq = await dngqFacti();
 219   let cljcq = await cljcqFacti();
 220   let jlm = await jlmFacti();
 221   let o = { fj, cdzsq, sxt, light, qbbf, qbbm, covi, xfsb, hztcq, jjdh, fsfx, hld, dngq, kbxs, cljcq, jlm };
 222   return o;
 223 }
 224 
 225 function onDocumentMouseDown(event) {
 226 
 227   event.preventDefault();
 228   var mainCanvas = event.path[0];
 229 
 230   if (scene) {
 231 
 232     // 清空当前弹框
 233 
 234     clearLabel();
 235     var raycaster = new THREE.Raycaster(); var mouse = new THREE.Vector2();
 236 
 237 
 238     mouse.x = ((event.clientX - mainCanvas.getBoundingClientRect().left) / mainCanvas.offsetWidth) * 2 - 1;
 239     mouse.y = - ((event.clientY - mainCanvas.getBoundingClientRect().top) / mainCanvas.offsetHeight) * 2 + 1;
 240 
 241 
 242 
 243     raycaster.setFromCamera(mouse, camera); // 计算物体和射线的焦点
 244     //console.log("mouse--",mouse)
 245     var intersects = raycaster.intersectObjects(scene.children, true);
 246     //console.log("点击后相交的物体位置", intersects[0].point.x, intersects[0].point.y, intersects[0].point.z)
 247 
 248     // 递归找到点击的是属于该点击处的模型名称
 249     var str = [];
 250     if (intersects.length > 0) {
 251       console.log('3d坐标----------》》》》》》》》》》', intersects[0].point)
 252       for (var i = 0; i < intersects.length; i++) {
 253 
 254         // 递归找到点击的是属于该点击处的模型
 255         findMesh(intersects[i].object, str);
 256 
 257       }
 258 
 259       //console.log("模型",str)
 260       let num = true;
 261       for (var item of str) {
 262         let name = item.name
 263         if (num === false) return;
 264         //开启点击弹窗的模型
 265         let array = ["fj", "cdzsq", "sxt", "qbbm", "qbbf", "covi", "xfsb", "hztcq", "hld", "dngq", "fsfx", "jjdh", "sxt", "kbxs", "cljcq", "jlm"]
 266         if (array.indexOf(name) !== -1) {
 267           num = false;
 268           console.log("点击得到的数据》》》》》》》", item)
 269           showMsg(item, item.userData)
 270 
 271         }
 272       }
 273     }
 274 
 275   }
 276 
 277 
 278 }
 279 
 280 // 递归找到点击的模型下所有的材质
 281 function findMesh(obj, str) {
 282   if (obj.parent != null) {
 283     findMesh(obj.parent, str);
 284     return str.push(obj.parent)
 285   }
 286 
 287 }
 288 
 289 // 加载弹框信息
 290 /*
 291  加载弹框信息
 292  params obj 点击的3d对象,o是该设备信息
 293  */
 294 function showMsg(obj, o) {
 295 
 296   clearLabel();
 297 
 298   var earthDiv = document.createElement('div');
 299 
 300   //生成不同的弹框
 301   showPop(earthDiv, o, function (newState) {
 302     clearLabel();
 303     if (!newState) return;
 304     var oldState = o.defaultCommandStatus;
 305     o.defaultCommandStatus = newState;
 306     cdzsqChangeState(obj);
 307     hldChangeState(obj);
 308     jlmChangeState(obj)
 309   }, vueObj)
 310   // earthDiv.style.marginTop = '-1em';
 311   var earthLabel = new CSS2DObject(earthDiv);
 312   earthLabel.name = "label";
 313   // earthLabel.position.set(0, obj.position.y + 10, 0);
 314   obj.add(earthLabel);
 315   labelRender();
 316 
 317 }
 318 function labelRender() {
 319 
 320   if (labelRenderer) {
 321 
 322     // new CSS2DRenderer().dispatchEvent("removed")
 323 
 324     // 确保3D相关对象已销毁
 325     cancelAnimationFrame(ani2) // 可以取消动画
 326 
 327     if (document.getElementsByClassName("label").length > 0) {
 328       document.getElementsByClassName("label")[0].parentNode.removeChild(document.getElementsByClassName("label")[0])
 329       //console.log("document.getElementsByClassName--------",document.getElementsByClassName("label")[0])
 330 
 331     }
 332   }
 333   labelRenderer = new CSS2DRenderer();
 334   labelRenderer.setSize(container.offsetWidth, container.offsetHeight);
 335   labelRenderer.domElement.style.position = 'absolute';
 336   labelRenderer.domElement.style.top = '180px';
 337   labelRenderer.domElement.className = "labelRenderer";
 338   document.getElementById("info").appendChild(labelRenderer.domElement);
 339 
 340 
 341   // var controls = new OrbitControls( camera ,labelRenderer.domElement);
 342   // // 控制缩放范围
 343   // controls.maxDistance= 252500;
 344   // controls.minDistance = 0;
 345   // // 控制垂直旋转角度
 346   // controls.maxPolarAngle =1.5
 347   // controls.minPolarAngle = 0.1
 348 
 349   // controls.enablePan = false
 350   // 旋转中心点
 351   // controls.target.set( 1000, 0, 1000 );
 352   // controls.update();
 353   animate2();
 354 }
 355 function animate2() {
 356   ani2 = requestAnimationFrame(animate2);
 357   if (renderer) {
 358     renderer.render(scene, camera);
 359     labelRenderer.render(scene, camera);
 360   }
 361 }
 362 
 363 
 364 export function clearScene() {
 365 
 366   // // 这是清空
 367   // if (scene) {
 368   //   clearLabel();//清空对应的2d
 369   //   for (let i = 0; i < scene.children.length; i++) {
 370   //     // 清空设备层
 371   //     for (let item of scene.children) {
 372   //       scene.remove(item);
 373   //     }
 374   //   }
 375   //   for (let item of scene.children) {
 376   //     if (item.name == "sb") {
 377   //       scene.remove(item);
 378   //     }
 379   //   }
 380 
 381   // }
 382 
 383   if (container.childNodes[0]) {
 384     container.removeChild(container.childNodes[0])
 385   }
 386   // scene.dispose();
 387   // if (renderer) {
 388   //   renderer.dispose();
 389   // }
 390   // cancelAnimationFrame(ani)
 391 
 392   function dispose(parent, child) {
 393     if (child.children.length) {
 394       let arr = child.children.filter(x => x);
 395       arr.forEach(a => {
 396         dispose(child, a)
 397       })
 398     }
 399     if (child instanceof THREE.Mesh) {
 400       // console.log('item', child)
 401       if (Array.isArray(child.material) && child.material.length > 0) {
 402         child.material.forEach(item => {
 403           if (item.map) item.map.dispose();
 404           item.dispose();
 405         })
 406       }
 407       else {
 408         if (child.material.map) child.material.map.dispose();
 409         child.material.dispose();
 410       }
 411       child.geometry.dispose();
 412     } else if (child.material) {
 413       child.material.dispose();
 414     }
 415     child.remove();
 416     parent.remove(child);
 417   }
 418 
 419   let arr = scene.children.filter(x => x)
 420   arr.forEach(a => {
 421     dispose(scene, a);
 422   })
 423 
 424 
 425 
 426   window.removeEventListener("resize", toResize);
 427 
 428   scene.dispose();
 429   if (renderer) {
 430     console.log('查看memery字段即可', renderer.info)   //查看memery字段即可
 431     renderer.renderLists.dispose();
 432     renderer.dispose();
 433     renderer.forceContextLoss();
 434     renderer.domElement = null;
 435     renderer.content = null;
 436     renderer = null;
 437   }
 438   cancelAnimationFrame(ani);
 439   cancelAnimationFrame(ani)
 440   THREE.Cache.clear();
 441 }
 442 
 443 function clearLabel() {
 444 
 445 
 446   let ll = scene.getObjectByName("label");
 447   if (ll) {
 448     ll.parent.remove(ll)
 449   }
 450   if (document.getElementsByClassName("labelRenderer").length > 0) {
 451     document.getElementsByClassName("labelRenderer")[0].parentNode.removeChild(document.getElementsByClassName("labelRenderer")[0])
 452 
 453   }
 454   let ll2 = scene.getObjectByName("labelRenderer");
 455   //console.log("ll2.domElement------------",ll2)
 456   if (ll2) {
 457     //console.log("ll2.domElement------------222",ll2.domElement)
 458     ll2.domElement.parent.remove(ll2.domElement)
 459     ll2.parent.remove(ll2)
 460     ll2.dispose();
 461 
 462   }
 463 }
 464 
 465 
 466 export function addModel(obj) {
 467   clearScene();
 468   init(obj);
 469   console.log(THREE.Cache)
 470 }
 471 
 472 function getBaseFacl(obj) {
 473   var group = new THREE.Group();
 474   group.name = "basesb";
 475   let sb = {};
 476   // 控制室模型
 477   // let kzsPos = [{ x: 15408, y: -2236, z: 15000 }];
 478   // obj.kzs.userData = { id: "id_kzs" }
 479   // let kzs = obj.kzs.clone();
 480   // kzs.rotateY(Math.PI);
 481   // kzs.position.copy(new THREE.Vector3(kzsPos[0].x, kzsPos[0].y, kzsPos[0].z))
 482   // group.add(kzs)
 483   // let kzsPos1 = [{ x: 28080, y: -1500, z: -15757 }];
 484   // obj.kzs.userData = { id: "id_kzs" }
 485   // let kzs1 = obj.kzs.clone();
 486   // kzs1.rotateY(Math.PI);
 487   // kzs1.position.copy(new THREE.Vector3(kzsPos1[0].x, kzsPos1[0].y, kzsPos1[0].z))
 488   // group.add(kzs1)
 489   // let kzsPos2 = [{ x: -21202, y: -2085, z: -15757 }];
 490   // obj.kzs.userData = { id: "id_kzs" }
 491   // let kzs2 = obj.kzs.clone();
 492   // // kzs2.rotateY(Math.PI);
 493   // kzs2.position.copy(new THREE.Vector3(kzsPos2[0].x, kzsPos2[0].y, kzsPos2[0].z))
 494   // group.add(kzs2)
 495   let kzsPos3 = [{ x: -29000, y: 1250, z: 22000 }];
 496   obj.kzs.userData = { id: "id_kzs" }
 497   let kzs3 = obj.kzs.clone();
 498   kzs3.position.copy(new THREE.Vector3(kzsPos3[0].x, kzsPos3[0].y, kzsPos3[0].z))
 499   kzs3.scale.set(1.2, 1.2, 1.2);
 500   group.add(kzs3)
 501 
 502 
 503   scene.add(group);
 504 }
 505 function getFacl(obj) {
 506 
 507   // var array = ['fj', 'cdzsq', 'sxt', 'qbbm', 'qbbf', 'covi', 'hztcq', 'kbxs', 'jjdh', 'light']//普瑞不需要加载的模型:xfsb,hld
 508   // for (let key in obj) {
 509   //   obj[key].visible = array.indexOf(obj[key].name) === -1 ? false : true;
 510   // }
 511 
 512 
 513 
 514   let tunnerid = vueObj.$store.getters.tunnerid;
 515   let arr = ["?tunnelId=" + tunnerid];
 516 
 517   getFacs(arr.join('')).then(async response => {
 518     let { code, value } = response.data;
 519     console.log('全部设备信息', value)
 520     // 单洞信息
 521     await getHoles(tunnerid).then(response => {
 522       let { code, value } = response.data;
 523       if (value && value.length > 0) {
 524 
 525 
 526         value.forEach(item => {
 527 
 528           if (item.direction == 'left') {
 529 
 530             vueObj.hole_1 = item;
 531 
 532           } else if (item.direction == 'right') {
 533 
 534             vueObj.hole_2 = item;
 535 
 536           } else {
 537             return;
 538           }
 539         })
 540       }
 541 
 542     });
 543     // 取得分区数据
 544     var sorted = groupBy(value, function (item) {
 545       return [item.holeId];
 546     });
 547     if (sorted.length > 0) {
 548 
 549       vueObj.hole_1_list = vueObj.hole_1.id == sorted[0][0].holeId ? sorted[0] : sorted[1];//左洞设备信息
 550       vueObj.hole_2_list = vueObj.hole_2.id == sorted[0][0].holeId ? sorted[0] : sorted[1];//右洞设备信息
 551 
 552     } else {
 553       vueObj.hole_1_list = [];
 554       vueObj.hole_2_list = [];
 555     }
 556     var hole_1_type = groupBy(vueObj.hole_1_list, function (item) {
 557       return [item.classifyCode];
 558     });
 559     var hole_2_type = groupBy(vueObj.hole_2_list, function (item) {
 560       return [item.classifyCode];
 561     });
 562     // 转换为子数组
 563     toSonArr(hole_1_type, 1)
 564     toSonArr(hole_2_type, 2)
 565 
 566     var group = groupSb;
 567     group.name = "sb";
 568     let sb = {};
 569 
 570 
 571     // 左洞的比例
 572     let left_bl = 86000 / vueObj.hole_1.finishPosition;
 573     let right_bl = 86000 / vueObj.hole_2.finishPosition;
 574 
 575 
 576 
 577     let lightPos = [{ x: -30000, y: 4400, z: -12800 }, { x: -30000, y: 4400, z: -4150 }, { x: -30000, y: 4400, z: 4150 }, { x: -30000, y: 4400, z: 12800 }];//
 578     for (let i = 0; i < 12; i++) {
 579       // 加上设备信息
 580       obj.light.userData = { id: "id_light_right1" + i }
 581       let sb = obj.light.clone();
 582       // sb.rotateY(40);
 583       sb.rotateX(-Math.PI / 2);
 584       sb.position.copy(new THREE.Vector3(lightPos[0].x + 5200 * i, lightPos[0].y, lightPos[0].z))
 585       if (i >= 10) {
 586         sb.position.copy(new THREE.Vector3(lightPos[0].x + 5200 * i + 1500, lightPos[0].y, lightPos[0].z - 3700))
 587       }
 588       group.add(sb)
 589     }
 590     for (let i = 0; i < 12; i++) {
 591       // 加上设备信息
 592       obj.light.userData = { id: "id_light_right2" + i }
 593       let sb = obj.light.clone();
 594       sb.position.copy(new THREE.Vector3(lightPos[1].x + 5200 * i, lightPos[1].y, lightPos[1].z))
 595       if (i >= 10) {
 596         sb.position.copy(new THREE.Vector3(lightPos[1].x + 5200 * i + 1500, lightPos[1].y, lightPos[1].z))
 597       }
 598       group.add(sb)
 599     }
 600     for (let i = 0; i < 12; i++) {
 601       // 加上设备信息
 602       obj.light.userData = { id: "id_light_left1" + i }
 603       let sb = obj.light.clone();
 604       sb.rotateX(-Math.PI / 2);
 605       sb.position.copy(new THREE.Vector3(lightPos[2].x + 5200 * i, lightPos[2].y, lightPos[2].z))
 606       if (i >= 10) {
 607         sb.position.copy(new THREE.Vector3(lightPos[2].x + 5200 * i + 1500, lightPos[2].y, lightPos[2].z))
 608       }
 609       group.add(sb)
 610     }
 611     for (let i = 0; i < 12; i++) {
 612       // 加上设备信息
 613       obj.light.userData = { id: "id_light_left2" + i }
 614       let sb = obj.light.clone();
 615       sb.position.copy(new THREE.Vector3(lightPos[3].x + 5200 * i, lightPos[3].y, lightPos[3].z))
 616       if (i >= 10) {
 617         sb.position.copy(new THREE.Vector3(lightPos[3].x + 5200 * i + 1500, lightPos[3].y, lightPos[3].z + 3700))
 618       }
 619       group.add(sb)
 620     }
 621 
 622 
 623 
 624     let vd = vueObj.$data
 625     let keysArr = Object.keys(vd)
 626     //console.log('vueObj:-------',vueObj.$data)
 627 
 628     keysArr.forEach(item => {
 629       // console.log(item,item.indexOf('_',item.length - 2))
 630       if (Array.isArray(vd[item]) && item.indexOf('_', item.length - 2) > 0) {
 631         //console.log('item,vd[item]',item,vd[item])
 632         localSb(vd[item], obj, left_bl, right_bl, group)
 633 
 634       }
 635     })
 636     scene.add(group);
 637 
 638   })
 639 }
 640 // 设备定位
 641 async function localSb(list, obj, left_bl, right_bl, group) {
 642 
 643   let sdLeftStartPosition = -42600;
 644   let sdRightStartPosition = -42600;
 645   if (list.length > 0) {
 646 
 647     for (let i = 0; i < list.length; i++) {
 648       console.log(list[i].name, list[i].typeCode, list[i])
 649       let { typeCode } = list[i]
 650       let param, posLeft, posRight, rotx = 0, roty = 0
 651       switch (typeCode) {
 652         case 'TrafficLights':
 653           param = 'hld';
 654           // 加上设备信息
 655           obj[param].userData = list[i]
 656           var d = list[i]
 657           var sb = obj[param].clone();
 658           var x, y, z;
 659           if (d.direction == 'right') {
 660             x = right_bl * Math.abs(list[i].position) + sdRightStartPosition - 7000
 661             y = 3800
 662             z = 13400
 663             roty = Math.PI
 664           } else {
 665             x = left_bl * Math.abs(list[i].position) + sdLeftStartPosition + 7000
 666             y = 3800
 667             z = -16700
 668           }
 669           sb.children[0].children[4].children[0].visible = false;//绿灯
 670           sb.children[0].children[4].children[1].visible = true;//绿灯灰色
 671           sb.children[0].children[5].children[1].visible = false;//黄灯
 672           sb.children[0].children[5].children[2].visible = true;//黄灯灰色
 673           sb.children[0].children[6].children[1].visible = false;//红灯
 674           sb.children[0].children[6].children[2].visible = true;//红灯灰色
 675           sb.children[0].children[7].children[2].visible = false;//箭头
 676           sb.children[0].children[7].children[1].visible = true;//箭头灰色
 677           sb.children[0].children[7].children[3].visible = false;//清楚箭头边缘绿色
 678           sb.position.copy(new THREE.Vector3(x, y, z))
 679           sb.rotateY(roty)
 680           //sb.scale.set(1)
 681           group.add(sb);
 682           hldChangeState(sb);
 683           break;
 684         case 'Camera':
 685           param = 'sxt'
 686           // 加上设备信息
 687           obj[param].userData = list[i]
 688           var d = list[i]
 689           var sb = obj[param].clone();
 690           var x, y, z;
 691           if (d.direction == 'right') {
 692             rotx = Math.PI / 2
 693             roty = Math.PI
 694           } else {
 695             rotx = Math.PI / 2
 696           }
 697           x = right_bl * Math.abs(list[i].position) + sdLeftStartPosition;
 698           var direction = d.direction === 'right' ? 1 : -1;
 699           y = 4000;
 700           z = d.laneNum === 4 ? direction * 16700 : direction * 13200;
 701           sb.position.copy(new THREE.Vector3(x, y, z))
 702           sb.rotateY(roty)
 703           sb.rotateX(rotx)
 704           group.add(sb)
 705           break;
 706         case 'CoViDetector':
 707           param = 'covi'
 708           // 加上设备信息
 709           obj[param].userData = list[i]
 710           var d = list[i]
 711           var sb = obj[param].clone();
 712           var x, y, z;
 713           if (d.direction == 'right') {
 714             x = left_bl * Math.abs(list[i].position) + sdRightStartPosition
 715             y = 3500
 716             z = 13580
 717           } else {
 718             x = right_bl * Math.abs(list[i].position) + sdLeftStartPosition
 719             y = 3500
 720             z = -13750
 721           }
 722           sb.position.copy(new THREE.Vector3(x, y, z))
 723           sb.scale.set(10, 10, 10);
 724           group.add(sb)
 725           break;
 726         case 'FireFightingPump':
 727           param = 'xfsb'
 728           // 加上设备信息
 729           obj[param].userData = list[i]
 730           var d = list[i]
 731           var sb = obj[param].clone();
 732           var x, y, z;
 733           if (d.direction == 'right') {
 734             x = left_bl * Math.abs(list[i].position) + sdRightStartPosition
 735             y = -2000
 736             z = 14700
 737             //roty = Math.PI
 738           } else {
 739             x = left_bl * Math.abs(list[i].position) + sdLeftStartPosition
 740             y = -2000
 741             z = -14700
 742           }
 743           sb.position.copy(new THREE.Vector3(x, y, z))
 744           sb.rotateY(roty)
 745           group.add(sb)
 746           break;
 747         case 'FireDetector':
 748           param = 'hztcq'
 749           // 加上设备信息
 750           obj[param].userData = list[i]
 751           var d = list[i]
 752           var sb = obj[param].clone();
 753           var x, y, z;
 754           if (d.direction == 'right') {
 755             y = 1500
 756             z = d.position >= 645 ? 17700 : 14400;
 757             roty = Math.PI
 758           } else {
 759             y = 1500
 760             z = d.position >= 645 ? -17700 : -14400;
 761           }
 762           x = d.position >= 645 ? left_bl * Math.abs(list[i].position) + sdLeftStartPosition + 1000 : left_bl * Math.abs(list[i].position) + sdLeftStartPosition;
 763           sb.position.copy(new THREE.Vector3(x, y, z))
 764           sb.rotateY(roty)
 765           group.add(sb)
 766           break;
 767         case 'EmergencyCallBroadCast':
 768           param = 'jjdh'
 769           // 加上设备信息
 770           obj[param].userData = list[i]
 771           var d = list[i]
 772           var sb = obj[param].clone();
 773           var x, y, z;
 774           if (d.direction == 'right') {
 775             x = left_bl * Math.abs(list[i].position) + sdRightStartPosition
 776             y = -600
 777             z = 10250
 778             roty = Math.PI
 779           } else {
 780             x = left_bl * Math.abs(list[i].position) + sdLeftStartPosition
 781             y = -600
 782             z = -10250
 783           }
 784           sb.position.copy(new THREE.Vector3(x, y, z))
 785           sb.rotateY(roty)
 786           group.add(sb)
 787           break;
 788         case 'WindSpeedDetector':
 789           param = 'fsfx'
 790           // 加上设备信息
 791           obj[param].userData = list[i]
 792           var d = list[i]
 793           var sb = obj[param].clone();
 794           var x, y, z;
 795           if (d.direction == 'right') {
 796             x = left_bl * Math.abs(list[i].position) + sdRightStartPosition
 797             y = 3500
 798             z = 13600
 799             rotx = -Math.PI / 2
 800           } else {
 801             x = left_bl * Math.abs(list[i].position) + sdLeftStartPosition
 802             y = 3500
 803             z = -13600
 804             rotx = Math.PI / 2
 805           }
 806           sb.position.copy(new THREE.Vector3(x, y, z))
 807           sb.rotateX(rotx)
 808           group.add(sb)
 809           break;
 810         case 'JetFans':
 811           param = 'fj'
 812           // 加上设备信息
 813           obj[param].userData = list[i]
 814           var d = list[i]
 815           var sb = obj[param].clone();
 816           var x, y, z;
 817           x = right_bl * Math.abs(list[i].position) + sdLeftStartPosition;
 818           var direction = d.direction === 'right' ? 1 : -1;
 819           switch (d.laneNum) {
 820             case 1:
 821               y = 5000;
 822               z = 5000 * direction;
 823               break;
 824             case 2:
 825               y = 5900;
 826               z = 8500 * direction;
 827               break;
 828             case 3:
 829               y = 5000;
 830               z = 12000 * direction;
 831               break;
 832 
 833           }
 834           sb.position.copy(new THREE.Vector3(x, y, z))
 835           group.add(sb)
 836           fjArray.push(sb)
 837           break;
 838         case 'LaneLights':
 839           param = 'cdzsq'
 840           // 加上设备信息
 841           obj[param].userData = list[i]
 842           var d = list[i]
 843           var sb = obj[param].clone();
 844           var x, y, z;
 845           x = right_bl * Math.abs(list[i].position) + sdLeftStartPosition;
 846           y = 5300;
 847           var direction = d.direction === 'right' ? 1 : -1;
 848           switch (d.laneNum) {
 849             case 1:
 850               z = 5000 * direction;
 851               break;
 852             case 2:
 853               z = 8500 * direction;
 854               break;
 855             case 3:
 856               z = 12000 * direction;
 857               break;
 858           }
 859           sb.position.copy(new THREE.Vector3(x, y, z))
 860           group.add(sb)
 861           cdzsqChangeState(sb)
 862           break;
 863         case 'PRFlexMessageBroadFType':
 864           param = 'qbbf'
 865           // 加上设备信息
 866           obj[param].userData = list[i]
 867           var d = list[i]
 868           var sb = obj[param].clone();
 869           var x, y, z;
 870           if (d.direction == 'right') {
 871             x = right_bl * Math.abs(list[i].position) + sdRightStartPosition - 2000
 872             y = 2400
 873             z = 13400
 874           } else {
 875             x = left_bl * Math.abs(list[i].position) + sdLeftStartPosition + 2000
 876             y = 2400
 877             z = -16500
 878             roty = Math.PI
 879           }
 880           sb.position.copy(new THREE.Vector3(x, y, z))
 881           sb.rotateY(roty)
 882           sb.scale.set(1, 1.2, 1.2)
 883           group.add(sb)
 884           var textContent = d.displayContent ? d.displayContent : '暂无内容';
 885           qbbfSb = sb
 886           qbbfChangeState(textContent);
 887           break;
 888         case 'PRFlexMessageBroad':
 889           param = 'qbbm'
 890           // 加上设备信息
 891           obj[param].userData = list[i]
 892           var d = list[i]
 893           var sb = obj[param].clone();
 894           var x, y, z;
 895           if (d.direction == 'right') {
 896             x = right_bl * Math.abs(list[i].position) + sdRightStartPosition - 2000
 897             y = 2250
 898             z = 8400
 899             roty = Math.PI
 900           } else {
 901             x = left_bl * Math.abs(list[i].position) + sdLeftStartPosition + 2000
 902             y = 2250
 903             z = -5900
 904           }
 905           sb.position.copy(new THREE.Vector3(x, y, z))
 906           sb.rotateY(roty)
 907           sb.scale.set(0.3, 0.8, 1.05);
 908           group.add(sb)
 909           var textContent = d.displayContent ? d.displayContent : '暂无内容';
 910           qbbmSb = sb
 911           qbbmChangeState(textContent);
 912           break;
 913         case 'PRFlexSpeedBroad':
 914           param = 'kbxs'
 915           // 加上设备信息
 916           obj[param].userData = list[i]
 917           var d = list[i]
 918           var sb = obj[param].clone();
 919           var x, y, z;
 920 
 921           if (d.direction == 'right') {
 922             x = right_bl * Math.abs(list[i].position) + sdRightStartPosition - 10000
 923             y = 1700
 924             z = 2500
 925             roty = Math.PI
 926           } else {
 927             x = left_bl * Math.abs(list[i].position) + sdLeftStartPosition + 10000
 928             y = 1700
 929             z = -2500
 930           }
 931           sb.position.copy(new THREE.Vector3(x, y, z));
 932           sb.rotateY(roty)
 933           group.add(sb)
 934           var number = d.displaySpeed ? d.displaySpeed : 0;
 935           if (d.direction == 'right') {
 936             kbxsRightSb = sb
 937           }
 938           else {
 939             kbxsLeftSb = sb
 940           }
 941           kbxsChangeState(number, d.direction);
 942           break;
 943 
 944         case 'FlexMessageBroadFType':
 945           param = 'qbbf'
 946           // 加上设备信息
 947           obj[param].userData = list[i]
 948           var d = list[i]
 949           var sb = obj[param].clone();
 950           var x, y, z;
 951           if (d.direction == 'right') {
 952             x = right_bl * Math.abs(list[i].position) + sdRightStartPosition - 2000
 953             y = 2400
 954             z = 13400
 955           } else {
 956             x = left_bl * Math.abs(list[i].position) + sdLeftStartPosition + 2000
 957             y = 2400
 958             z = -16500
 959             roty = Math.PI
 960           }
 961           sb.position.copy(new THREE.Vector3(x, y, z))
 962           sb.rotateY(roty)
 963           sb.scale.set(1, 1.2, 1.2)
 964           group.add(sb)
 965           var textContent = d.displayContent ? d.displayContent : '暂无内容';
 966           qbbfSb = sb
 967           qbbfChangeState(textContent);
 968           break;
 969         case 'FlexMessageBroadPortalType':
 970           param = 'qbbm'
 971           // 加上设备信息
 972           obj[param].userData = list[i]
 973           var d = list[i]
 974           var sb = obj[param].clone();
 975           var x, y, z;
 976           if (d.direction == 'right') {
 977             x = right_bl * Math.abs(list[i].position) + sdRightStartPosition - 2000
 978             y = 2250
 979             z = 8400
 980             roty = Math.PI
 981           } else {
 982             x = left_bl * Math.abs(list[i].position) + sdLeftStartPosition + 2000
 983             y = 2250
 984             z = -5900
 985           }
 986           sb.position.copy(new THREE.Vector3(x, y, z))
 987           sb.rotateY(roty)
 988           sb.scale.set(0.3, 0.8, 1.05);
 989           group.add(sb)
 990           var textContent = d.displayContent ? d.displayContent : '暂无内容';
 991           qbbmSb = sb
 992           qbbmChangeState(textContent);
 993           break;
 994         case 'FlexSpeedBroad':
 995           param = 'kbxs'
 996           // 加上设备信息
 997           obj[param].userData = list[i]
 998           var d = list[i]
 999           var sb = obj[param].clone();
1000           var x, y, z;
1001 
1002           if (d.direction == 'right') {
1003             x = right_bl * Math.abs(list[i].position) + sdRightStartPosition - 10000
1004             y = 1700
1005             z = 2500
1006             roty = Math.PI
1007           } else {
1008             x = left_bl * Math.abs(list[i].position) + sdLeftStartPosition + 10000
1009             y = 1700
1010             z = -2500
1011           }
1012           sb.position.copy(new THREE.Vector3(x, y, z));
1013           sb.rotateY(roty)
1014           group.add(sb)
1015           var number = d.displaySpeed ? d.displaySpeed : 0;
1016           if (d.direction == 'right') {
1017             kbxsRightSb = sb
1018           }
1019           else {
1020             kbxsLeftSb = sb
1021           }
1022           kbxsChangeState(number, d.direction);
1023           break;
1024         case 'PREmergencyCall':
1025           param = 'jjdh'
1026           // 加上设备信息
1027           obj[param].userData = list[i]
1028           var d = list[i]
1029           var sb = obj[param].clone();
1030           var x, y, z;
1031           if (d.direction == 'right') {
1032             x = left_bl * Math.abs(list[i].position) + sdRightStartPosition
1033             y = 1800
1034             z = 14410
1035             roty = Math.PI
1036           } else {
1037             x = left_bl * Math.abs(list[i].position) + sdLeftStartPosition
1038             y = 1800
1039             z = -14410
1040           }
1041           if (d.position >= 610) {
1042             z = d.direction == 'right' ? 17820 : -17820;
1043           }
1044           sb.position.copy(new THREE.Vector3(x, y, z))
1045           sb.rotateY(roty)
1046           group.add(sb)
1047           break;
1048 
1049         case 'VehicleDetector':
1050           param = 'cljcq'
1051           // 加上设备信息
1052           obj[param].userData = list[i]
1053           var d = list[i]
1054           var sb = obj[param].clone();
1055           var x, y, z;
1056           if (d.direction == 'right') {
1057             x = left_bl * Math.abs(list[i].position) + sdRightStartPosition
1058             y = -2450
1059             z = 7300
1060             roty = -Math.PI / 2
1061           } else {
1062             x = left_bl * Math.abs(list[i].position) + sdLeftStartPosition
1063             y = -2450
1064             z = -7300
1065             roty = Math.PI / 2
1066           }
1067           sb.position.copy(new THREE.Vector3(x, y, z))
1068           sb.rotateY(roty)
1069           //sb.scale.set(10,10,10)
1070           group.add(sb)
1071           break;
1072         case 'FireFightingDoor':
1073           param = 'jlm'
1074           // 加上设备信息
1075           obj[param].userData = list[i]
1076           var sb = obj[param].clone();
1077           var x = 0;
1078           var y = -100;
1079           var z = 0;
1080           sb.position.copy(new THREE.Vector3(x, y, z))
1081           group.add(sb)
1082           jlmChangeState(sb);
1083           break;
1084       }
1085     }
1086   }
1087 
1088 }
1089 
1090 function groupBy(array, f) {
1091   if (array == undefined) {
1092     return []
1093   }
1094   var groups = {};
1095   array.forEach(function (o) {
1096     var group = JSON.stringify(f(o));
1097     groups[group] = groups[group] || [];
1098     groups[group].push(o);
1099   });
1100   //  console.log('groups',groups)
1101   return Object.keys(groups).map(function (group) {
1102     return groups[group];
1103   });
1104 }
1105 function toSonArr(arr, i) {
1106   arr.forEach(function (o) {
1107     switch (o[0].classifyCode) {
1108       case '1':
1109         vueObj.$data['ventilationList_' + i] = o;
1110         //  氮氧化物检测器...
1111         break;
1112       case '2':
1113         vueObj.$data['lightList_' + i] = o;
1114         //  照明集中控制器...
1115         break;
1116       case '3':
1117         vueObj.$data['videomoniList_' + i] = o;
1118         //  摄像头...
1119         break;
1120       case '4':
1121         vueObj.$data['msgdeliverList_' + i] = o;
1122         //  紧急电话广播...
1123         break;
1124       case '5':
1125         vueObj.$data['firecontrolList_' + i] = o;
1126         //  消防水泵...
1127         break;
1128       case '6':
1129         vueObj.$data['traficcontrolList_' + i] = o;
1130         //  车道指示器...
1131         break;
1132       case '7':
1133         vueObj.$data['trafguideList_' + i] = o;
1134         console.log('7:', o[0].name)
1135         break;
1136       case '8':
1137         vueObj.$data['powerMoni_' + i] = o;
1138         //  电力监测仪表...
1139         break;
1140       default:
1141       //text = 'List';
1142     }
1143   })
1144 
1145 }
1146 
1147 //动态化风机  //旋转方向
1148 function fjRotate() {
1149   if (fjArray.length === 0) return;
1150   fjArray.forEach(item => {
1151     fjdirection = item.userData.direction === 'right' ? -1 : 1;
1152     switch (item.userData.defaultCommandStatus) {
1153       case '1'://正转
1154         item.children[2].children[2].children[1].rotateX(fjdirection * Math.PI / 6);
1155         item.children[2].children[2].children[2].rotateX(fjdirection * Math.PI / 6);
1156         break;
1157       case '2'://反转
1158         item.children[2].children[2].children[1].rotateX(fjdirection * -Math.PI / 6);
1159         item.children[2].children[2].children[2].rotateX(fjdirection * -Math.PI / 6);
1160         break;
1161       default:
1162         break;
1163     }
1164   })
1165 }
1166 
1167 //车道指示器动态化
1168 async function cdzsqChangeState(obj) {
1169   if (obj.userData.typeCode !== 'LaneLights') return;
1170   groupSb.remove(obj);
1171 
1172   var newobj = null;
1173   switch (obj.userData.defaultCommandStatus) {
1174     case '10':
1175       //禁止通行状态
1176       newobj = await cdzsqFactiNo();
1177       newobj.userData = obj.userData;
1178       newobj.position.copy(obj.position);
1179       break;
1180     case '6':
1181       //反向状态
1182       newobj = await cdzsqFacti();
1183       newobj.scale.set(10, 10, 10);
1184       newobj.userData = obj.userData;
1185       newobj.position.copy(obj.position);
1186       newobj.children[2].children[2].visible = true;
1187       newobj.children[2].children[4].visible = true;
1188       newobj.children[2].children[6].visible = true;
1189       break;
1190     case '9':
1191       //正向状态
1192       newobj = await cdzsqFacti();
1193       newobj.scale.set(10, 10, 10);
1194       newobj.rotateY(Math.PI)
1195       newobj.userData = obj.userData;
1196       newobj.position.copy(obj.position);
1197       newobj.children[2].children[2].visible = true;
1198       newobj.children[2].children[4].visible = true;
1199       newobj.children[2].children[6].visible = true;
1200       break;
1201     default://默认关闭状态
1202       newobj = await cdzsqFacti();
1203       newobj.scale.set(10, 10, 10);
1204       newobj.userData = obj.userData;
1205       newobj.position.copy(obj.position);
1206       newobj.children[2].children[2].visible = false;
1207       newobj.children[2].children[4].visible = false;
1208       newobj.children[2].children[6].visible = false;
1209       break;
1210   }
1211   if (newobj.userData.direction === 'left') newobj.rotateY(Math.PI)
1212   groupSb.add(newobj)
1213   //设置默认状态
1214   newobj.children[2].children[9].visible = false;
1215   newobj.children[2].children[10] && (newobj.children[2].children[10].visible = false);
1216 
1217 }
1218 
1219 //红绿灯动态化
1220 function hldChangeState(obj) {
1221   if (obj.userData.typeCode !== 'TrafficLights') return;
1222   switch (obj.userData.defaultCommandStatus) {
1223     case '1':
1224       //红灯状态
1225       obj.children[0].children[4].children[0].visible = false;//绿灯
1226       obj.children[0].children[4].children[1].visible = true;//绿灯灰色
1227       obj.children[0].children[5].children[1].visible = false;//黄灯
1228       obj.children[0].children[5].children[2].visible = true;//黄灯灰色
1229       obj.children[0].children[6].children[1].visible = true;//红灯
1230       obj.children[0].children[6].children[2].visible = false;//红灯灰色
1231       obj.children[0].children[7].children[2].visible = false;//箭头
1232       obj.children[0].children[7].children[1].visible = true;//箭头灰色
1233       break;
1234     case '2':
1235       //黄灯状态
1236       obj.children[0].children[4].children[0].visible = false;//绿灯
1237       obj.children[0].children[4].children[1].visible = true;//绿灯灰色
1238       obj.children[0].children[5].children[1].visible = true;//黄灯
1239       obj.children[0].children[5].children[2].visible = false;//黄灯灰色
1240       obj.children[0].children[6].children[1].visible = false;//红灯
1241       obj.children[0].children[6].children[2].visible = true;//红灯灰色
1242       obj.children[0].children[7].children[2].visible = false;//箭头
1243       obj.children[0].children[7].children[1].visible = true;//箭头灰色
1244       break;
1245     case '4':
1246       //绿灯状态
1247       obj.children[0].children[4].children[0].visible = true;//绿灯
1248       obj.children[0].children[4].children[1].visible = false;//绿灯灰色
1249       obj.children[0].children[5].children[1].visible = false;//黄灯
1250       obj.children[0].children[5].children[2].visible = true;//黄灯灰色
1251       obj.children[0].children[6].children[1].visible = false;//红灯
1252       obj.children[0].children[6].children[2].visible = true;//红灯灰色
1253       obj.children[0].children[7].children[2].visible = false;//箭头
1254       obj.children[0].children[7].children[1].visible = true;//箭头灰色
1255       break;
1256     case '8':
1257       //左转状态
1258       obj.children[0].children[4].children[0].visible = false;//绿灯
1259       obj.children[0].children[4].children[1].visible = true;//绿灯灰色
1260       obj.children[0].children[5].children[1].visible = false;//黄灯
1261       obj.children[0].children[5].children[2].visible = true;//黄灯灰色
1262       obj.children[0].children[6].children[1].visible = false;//红灯
1263       obj.children[0].children[6].children[2].visible = true;//红灯灰色
1264       obj.children[0].children[7].children[2].visible = true;//箭头
1265       obj.children[0].children[7].children[1].visible = false;//箭头灰色
1266       break;
1267     default://默认停止状态 '0'
1268       obj.children[0].children[4].children[0].visible = false;//绿灯
1269       obj.children[0].children[4].children[1].visible = true;//绿灯灰色
1270       obj.children[0].children[5].children[1].visible = false;//黄灯
1271       obj.children[0].children[5].children[2].visible = true;//黄灯灰色
1272       obj.children[0].children[6].children[1].visible = false;//红灯
1273       obj.children[0].children[6].children[2].visible = true;//红灯灰色
1274       obj.children[0].children[7].children[2].visible = false;//箭头
1275       obj.children[0].children[7].children[1].visible = true;//箭头灰色
1276       break;
1277   }
1278 }
1279 
1280 // //可变限速数值动态化
1281 // export function kbxsChangeState(number,direction) {
1282 //   number = String(number)
1283 //   var speed=direction==='right'?speedRight:speedLeft;
1284 //   var kbxsSb=direction==='right'?kbxsRightSb:kbxsLeftSb;
1285 //   if (speed) {
1286 //     speed.geometry.dispose();
1287 //     speed.material.dispose();
1288 //     kbxsSb.remove(speed);
1289 //   }
1290 //   textLoader.load('three/examples/fonts/gentilis_regular.typeface.json', function (font) {
1291 //     var geometry = new THREE.TextGeometry(number, {
1292 //       font: font,
1293 //       size: 250,
1294 //       height: 5,
1295 //       curveSegments: 12,
1296 //       bevelEnabled: true,
1297 //       bevelThickness: 10,
1298 //       bevelSize: 8,
1299 //       bevelSegments: 5
1300 //     });
1301 //     speed = new THREE.Mesh(geometry, new THREE.MeshLambertMaterial({ color: 0xff0000 }));
1302 //     number.length === 2 ? speed.position.set(200, 780, 200) : (number.length === 3 ? speed.position.set(200, 780, 300) : speed.position.set(200, 780, 100))
1303 //     speed.rotation.set(0, Math.PI / 2, 0);
1304 //     kbxsSb.add(speed);
1305 //   });
1306 // }
1307 
1308 //可变限速数值动态化
1309 export function kbxsChangeState(number, direction) {
1310   number = String(number)
1311   var speed = direction === 'right' ? speedRight : speedLeft;
1312   var kbxsSb = direction === 'right' ? kbxsRightSb : kbxsLeftSb;
1313   if (speed) {
1314     speed.geometry.dispose();
1315     speed.material.dispose();
1316     kbxsSb.remove(speed);
1317   }
1318   function getTextCanvas(text) {
1319     var width = 45, height = 45;
1320     var canvas = document.createElement('canvas');
1321     canvas.width = width;
1322     canvas.height = height;
1323     var ctx = canvas.getContext('2d');
1324     ctx.fillStyle = '#000000';
1325     ctx.fillRect(0, 0, width, height);
1326     ctx.font = 40 + 'px " bold';
1327     ctx.fillStyle = '#00FF00';
1328     ctx.textAlign = 'center';
1329     ctx.textBaseline = 'middle';
1330     ctx.fillText(text, width / 2, height / 2);
1331     return canvas;
1332   }
1333   var geometry = new THREE.PlaneBufferGeometry(45, 45);
1334   var material = new THREE.MeshBasicMaterial({ map: new THREE.CanvasTexture(getTextCanvas('60')) });// top
1335   speed = new THREE.Mesh(geometry, material);
1336   kbxsSb.add(speed)
1337   speed.scale.set(10, 10, 10)
1338   speed.position.set(200, 890, 0)
1339   speed.rotateY(Math.PI / 2)
1340 
1341 }
1342 
1343 
1344 //可变信息板门架式文字动态化
1345 export function qbbmChangeState(textContent) {
1346   textContent = String(textContent);
1347   //textContent = `道路千万条,安全第一条;行车不规范,亲人两行泪!一二三四五,上山打老虎;老虎不在家,就当我没说。`
1348   if (textM) {
1349     textM.geometry.dispose();
1350     textM.material.dispose();
1351     qbbmSb.remove(textM);
1352   }
1353 
1354   var width = textContent.length * 50 + 200;
1355   var height = 125;
1356   function getTextCanvas(text) {
1357     var canvas = document.createElement('canvas');
1358     canvas.width = width;
1359     canvas.height = height;
1360     var ctx = canvas.getContext('2d');
1361     ctx.fillStyle = '#050507';
1362     ctx.fillRect(0, 0, width, height);
1363     ctx.font = 50 + 'px " bold';
1364     ctx.fillStyle = '#FF0000';
1365     ctx.textAlign = 'center';
1366     ctx.textBaseline = 'middle';
1367     ctx.fillText(text, width / 2, height / 2);
1368     return canvas;
1369   }
1370   textMwidth = Number((1000 / width).toFixed(2));
1371   var geometry = new THREE.PlaneGeometry(1020, height);
1372   geometry.faceVertexUvs[0][0][0] = new THREE.Vector2(0, 1);
1373   geometry.faceVertexUvs[0][0][1] = new THREE.Vector2(0, 0);
1374   geometry.faceVertexUvs[0][0][2] = new THREE.Vector2(textMwidth, 1);
1375   geometry.faceVertexUvs[0][1][0] = new THREE.Vector2(0, 0);
1376   geometry.faceVertexUvs[0][1][1] = new THREE.Vector2(textMwidth, 0);
1377   geometry.faceVertexUvs[0][1][2] = new THREE.Vector2(textMwidth, 1);
1378   mapM = new THREE.CanvasTexture(getTextCanvas(textContent))
1379 
1380   var material = new THREE.MeshBasicMaterial({ map: mapM });// top
1381   textM = new THREE.Mesh(geometry, material);
1382   qbbmSb.add(textM)
1383   textM.scale.set(10, 10, 10)
1384   textM.rotation.set(0, Math.PI / 2, 0)
1385   mapM.wrapS = THREE.RepeatWrapping;//无限水平平铺
1386   textM.position.set(1000, 1750, 0)
1387 }
1388 
1389 //可变信息板F式文字动态化
1390 export function qbbfChangeState(textContent) {
1391   if (textF) {
1392     if (Array.isArray(textF)) {
1393       textF.forEach(item => {
1394         item.geometry.dispose();
1395         item.material.dispose();
1396         qbbfSb.remove(item);
1397       })
1398     }
1399     else {
1400       textF.geometry.dispose();
1401       textF.material.dispose();
1402       qbbfSb.remove(textF);
1403     }
1404   }
1405   clearInterval(intervalF);
1406   textF = [];
1407   textContent = String(textContent);
1408   var re = /[^\u4E00-\u9FA5]/g;
1409   textContent = textContent.replace(re, '');
1410   var index = 0;
1411   for (let i = 0; i < Math.ceil(textContent.length / 4); i++) {
1412     var str = textContent.substr(index, 4);
1413     index += 4;
1414     var width = 148;
1415     var height = 45;
1416     function getTextCanvas(text) {
1417       var canvas = document.createElement('canvas');
1418       canvas.width = width;
1419       canvas.height = height;
1420       var ctx = canvas.getContext('2d');
1421       ctx.fillStyle = '#0A0A0A';
1422       ctx.fillRect(0, 0, width, height);
1423       ctx.font = 30 + 'px " bold';
1424       ctx.fillStyle = '#FF0000';
1425       ctx.textAlign = 'center';
1426       ctx.textBaseline = 'middle';
1427       ctx.fillText(text, width / 2, height / 2);
1428       return canvas;
1429     }
1430     var geometry = new THREE.PlaneGeometry(148, height);
1431     mapF = new THREE.CanvasTexture(getTextCanvas(str))
1432     var material = new THREE.MeshBasicMaterial({ map: mapF });// top
1433     textF[i] = new THREE.Mesh(geometry, material);
1434     qbbfSb.add(textF[i]);
1435     textF[i].scale.set(10, 10, 10);
1436     textF[i].rotation.set(0, -Math.PI / 2, 0);
1437     if ((i + 1) % 2 === 1) {
1438       textF[i].position.set(-100, 1500, -405);
1439     }
1440     else {
1441       textF[i].position.set(-100, 1050, -405);
1442     }
1443     textF[i].visible = (i === 0 || i === 1) ? true : false;
1444 
1445   }
1446   var indexs = 2;
1447   intervalF = setInterval(() => {
1448     textF.forEach(item => {
1449       item.visible = false;
1450     })
1451     textF[indexs] && (textF[indexs].visible = true);
1452     textF[indexs + 1] && (textF[indexs + 1].visible = true);
1453     if (indexs + 1 === textF.length || indexs + 2 === textF.length) {
1454       indexs = 0
1455     }
1456     else {
1457       indexs += 2;
1458     }
1459   }, 4000)
1460 
1461 
1462 }
1463 
1464 //卷帘门动态化
1465 function jlmChangeState(obj) {
1466   if (obj.userData.typeCode !== 'FireFightingDoor') return;
1467   switch (obj.userData.defaultCommandStatus) {
1468     case "0"://全开
1469       obj.children[2].children[1].visible = false;//
1470       obj.children[2].children[2].visible = false;//
1471       break;
1472     case "1"://半开
1473       obj.children[2].children[1].visible = true;//
1474       obj.children[2].children[2].visible = false;//
1475       break;
1476     default:
1477       obj.children[2].children[1].visible = true;//
1478       obj.children[2].children[2].visible = true;//
1479       break;
1480   }
1481 }
1482 
1483 //修改颜色
1484 export function colorChange(color, opacity) {
1485   let object = scene.children.find(item => item.name === 'dm')
1486   object.children[14].material.color.set(color)
1487   object.children[14].material.transparent = true;
1488   object.children[14].material.opacity = opacity;
1489 
1490   object.children[15].material.color.set(color)
1491   object.children[15].material.transparent = true;
1492   object.children[15].material.opacity = opacity;
1493 
1494   object.children[16].material.color.set(color)
1495   object.children[16].material.transparent = true;
1496   object.children[16].material.opacity = opacity;
1497 
1498   object.children[17].material.color.set(color)
1499   object.children[17].material.transparent = true;
1500   object.children[17].material.opacity = opacity;
1501 
1502   object.children[158].children[0].material.color.set(color)
1503   object.children[158].children[0].material.transparent = true;
1504   object.children[158].children[0].material.opacity = opacity;
1505 }
1506 
1507 //情报板(门式)实现文字跑马灯效果
1508 function fontRun() {
1509   if (!textM) return;
1510   mapM.offset.x += 0.001
1511 }