<template>
  <div style="height: 100%">
    <div
      id="viewPort"
      :style="{ height: containerHeight, width: containerWidth }"
      style="display: flex; align-items: center; justify-content: center"
    ></div>
    <div ref="modelProcess" style="position: absolute; top: 10px; left: 2px; color: white">
      正在加载模型0%
    </div>
    <div style="display: none">
      <audio controls loop id="alarm">
        <source src="/public/alarm.mp3" type="audio/mpeg" />
      </audio>
      <audio controls id="clash">
        <source src="/public/alarm.mp3" type="audio/mpeg" />
      </audio>
    </div>
  </div>
</template>

<script>
import * as THREE from './build/three.module'
import axios from 'axios'
import { EXRLoader } from './jsm/loaders/EXRLoader.js'
import { GLTFLoader } from './jsm/loaders/GLTFLoader.js'
import { DRACOLoader } from './jsm/loaders/DRACOLoader.js'
import * as TWEEN from './jsm/libs/tween.module.js'
import { DmtControl } from './js/DmtControl.js'
import { connect } from './js/websocketConnect.js'
import { connectMqtt } from './js/MqttConnect.js'
import { PlaySoundCommand } from './js/PlaySoundCommand.js'
import SpriteText from './js/three-spritetext.module.js'
import { acceleratedRaycast, computeBoundsTree, disposeBoundsTree } from './libs/bvh/index.js'
import { floorFileConfig } from '@/components/DMT/js/constEnvironment.js'
import DMT_Light from '@/components/DMT/js/DMT_Light.js'
import { EnvironmentLoader_DMT } from '@/components/DMT/js/EnvironmentLoader_DMT.js'
THREE.Mesh.prototype.raycast = acceleratedRaycast
THREE.BufferGeometry.prototype.computeBoundsTree = computeBoundsTree
THREE.BufferGeometry.prototype.disposeBoundsTree = disposeBoundsTree
import { EventBus } from '@/components/DMT/js/event-bus'

let container, scene, camera, axesHelper, renderer
let modelCount = 0

let editor = {
  EventBus: null,
  autoPlayCraftCode: '',
  currentModelPath: 'models', // DT:models；SM:models2
  currentMode: 'DT', // DT:孪生模式，接收数据；SM:仿真模式，播放预制数据
  drawLinedModelIdMoveInfo: [],
  drawLinedModel: {},
  drawPointModel: {},
  isDrawLinedModel: true,
  isDrawPointModel: true,
  lineMap: new Map(),
  cameraStateZoom: 25,
  addEventListener: THREE.EventDispatcher.prototype.addEventListener,
  removeEventListener: THREE.EventDispatcher.prototype.removeEventListener,
  dispatchEvent: THREE.EventDispatcher.prototype.dispatchEvent,
  hasEventListener: THREE.EventDispatcher.prototype.hasEventListener,
  ip: '',
  scene: null,
  objectIdUUidMap: new Map(),
  opname: '',
  connectType: 2,
  BSport: '',
  IsAllowConnect: true,
  service: axios.create({
    baseURL: './submit/MESCommonBase.ashx',
    timeout: 1500000, // 请求超时时间
  }),
  selected: null,
  socket: null,
  mqttClient: {
    connected: false,
  },
  dmtFloor: null,
  ProjectCode: null,
  sceneConfig: null,
  resourcesTree: null,
  attachments: null,
  resources: null,
  cameraState: null,
  cameraStateAll: [],
  FocusSetList: [],
  isOk: false,
  objectIdSet: new Map(),
  animOperations: null,
  CraftList: {},
  moveTrigger: null,
  camera: null,
  cameraPosition: 10,
  currentButton: 1,
  cameraControls: null,
  TagActList: {}, // 存放tag对应的类型
  worker: {}, // 播放工艺的线程
  RotationWorker: {}, // 自传工艺的线程
  ModelRotateWorker: {}, // 自传工艺的的状态数据
  rotateSpeed: (5 * Math.PI) / 180,
  getObjectById: null, // 方法 根据ModelId获取模型
  solveAttachModel: null, // 方法 处理attach问题
  removeObject: null, // 方法 移除模型
  setModelWireFrame: null, // 方法 设置线框
  setTransparent: null, // 方法 设置透明
  showMessage: null, // 方法 显示消息
  drawPartTextInfo: null, // 方法 模型上显示文字
  drawLineByPoints: null, // 方法
  drawLineByModel: null, // 方法
  drawPointByModel: null, // 方法
  ModelLabelList: new Map(), // 模型上显示列表
  modelGoHome: null, // 方法
  craftPlayFinish: null, // 方法
  createPipeObject: null, // 方法 创建管道对象
  playSoundCommand: new PlaySoundCommand(), //  方法 警告
  attachList: new Map(), // 记录attach列表
  objMaterial: new Map(),
  WareHouseList: [],
  WareHouse: new Map(), // 立库库存表
  WareHouseBasicModel: new Map(), // 立库库存基础 零件模型需要命名为warehousepart1-100 立库定位模型需要命名为warehouse1000-1009
  ProtocolIdentifiers: {
    Robot_7: 'Robot_7',
    Device_3: 'Device_3',
    Agv_3: 'Agv_3',
    Device_1: 'Device_1',
    FirstPosition: 'FirstPosition',
    WareHousePart: 'WareHousePart',
    Robot_6: 'Robot_6',
    RobotTcp: 'RobotTcp',
    DrawPath: 'DrawPath',
    ReLoadData: 'ReLoadData',
    PlayAct: 'PlayAct',
    CraftCurrOperation: 'CraftCurrOperation',
    Position: 'Position',
    Select: 'Select',
    DragMove: 'DragMove',
    ModelTransparent: 'ModelTransparent',
    Visible: 'Visible',
    Frames: 'Frames',
    ModelRotation: 'ModelRotation',
    GoHome: 'GoHome',
    GetJointAxisInfo: 'GetJointAxisInfo',
    GetDeviceBaseTool: 'GetDeviceBaseTool',
    GetJointValue: 'GetJointValue',
    C_B_ImportModel: 'C_B_ImportModel',
    SendURDF: 'SendURDF',
    SendDeviceJson: 'SendDeviceJson',
    GetDeviceJson: 'GetDeviceJson',
    SendMotionInfo: 'SendMotionInfo',
    C_B_ImportLayout: 'C_B_ImportLayout',
    GetPoseLocation: 'GetPoseLocation',
    C_B_SetProjectCode: 'C_B_SetProjectCode',
    C_B_TagIDTrigger: 'C_B_TagIDTrigger',
    C_B_ReLoad_TagIDHandler: 'C_B_ReLoad_TagIDHandler',
    C_B_SetCurrSignalList: 'C_B_SetCurrSignalList',
    SendClearModelInfo: 'SendClearModelInfo',
    C_B_SaveProjectSimulationData: 'C_B_SaveProjectSimulationData',
    C_B_GetProjectSimulationData: 'C_B_GetProjectSimulationData',
    C_B_KinematicsEditing: 'C_B_KinematicsEditing',
    C_B_SaveModel: 'C_B_SaveModel',
    C_B_ObjectAlarm: 'C_B_ObjectAlarm',
    C_B_JointMoveTo: 'C_B_JointMoveTo',
    JointMoveTo: 'JointMoveTo', // DT|JointMoveTo|modelCode|{"J1":"1","J2":"2","J3":"3","J4":"4","J5":"5","J6":"6","J7":"7","J8":"8","J9":"9"}
  },
  craftPlaySolveType: {
    visible: 'visible',
    rotation: 'rotation',
    craft: 'craft',
    signalwrite: 'signalwrite',
    wait: 'wait',
    FrameData: 'FrameData',
    attach: 'attach',
    warning: 'warning',
    camera: 'camera',
  },
  FrameOperation: {
    playCraft: true,
    visibleObject: true,
    rotationObject: true,
    writeSignal: true,
    waitSignal: true,
    attach: true,
    warning: true,
    camera: true,
  },
  signalSolveType: {
    visible: 'visible',
    rotation: 'rotation',
    craft: 'craft',
    targetLocation: 'targetlocation',
    attach: 'attach',
    warning: 'warning',
  },
}
// eslint-disable-next-line no-unused-vars
let ModelListTransParentList = []
let ModelList = []
let ModelListId = []
// eslint-disable-next-line no-unused-vars
const timer = null
// eslint-disable-next-line no-unused-vars
const lastIntersectModel = null
// eslint-disable-next-line no-unused-vars
const onUpPosition = new THREE.Vector2()

var raycaster = new THREE.Raycaster()
var mouse = new THREE.Vector2()

export default {
  components: {},
  name: 'DMT',
  props: {
    containerHeight: {
      type: String,
      default: '100vh',
    },
    containerWidth: {
      type: String,
      default: '100vw',
    },
  },
  data() {
    return {
      animationId: null,
      dmtMode: 'DT',
      checked: false,
      cameraData: [],
      object: null,
      s: null,
    }
  },
  created() {
    console.log('dmt-created')
    container = null
    scene = null
    camera = null
    axesHelper = null
    renderer = null
    modelCount = 0
    editor = {
      EventBus: null,
      autoPlayCraftCode: '',
      currentModelPath: 'models', // DT:models；SM:models2
      currentMode: 'DT', // DT:孪生模式，接收数据；SM:仿真模式，播放预制数据
      drawLinedModelIdMoveInfo: [],
      drawLinedModel: {},
      drawPointModel: {},
      isDrawLinedModel: true,
      isDrawPointModel: true,
      lineMap: new Map(),
      cameraStateZoom: 25,
      addEventListener: THREE.EventDispatcher.prototype.addEventListener,
      removeEventListener: THREE.EventDispatcher.prototype.removeEventListener,
      dispatchEvent: THREE.EventDispatcher.prototype.dispatchEvent,
      hasEventListener: THREE.EventDispatcher.prototype.hasEventListener,
      ip: '',
      scene: null,
      objectIdUUidMap: new Map(),
      opname: '',
      connectType: 2,
      BSport: '',
      IsAllowConnect: true,
      service: axios.create({
        baseURL: './submit/MESCommonBase.ashx',
        timeout: 1500000, // 请求超时时间
      }),
      selected: null,
      socket: null,
      mqttClient: {
        connected: false,
      },
      dmtFloor: null,
      ProjectCode: null,
      sceneConfig: null,
      resourcesTree: null,
      attachments: null,
      resources: null,
      cameraState: null,
      cameraStateAll: [],
      FocusSetList: [],
      isOk: false,
      objectIdSet: new Map(),
      animOperations: null,
      CraftList: {},
      moveTrigger: null,
      camera: null,
      cameraPosition: 10,
      currentButton: 1,
      cameraControls: null,
      TagActList: {}, // 存放tag对应的类型
      worker: {}, // 播放工艺的线程
      RotationWorker: {}, // 自传工艺的线程
      ModelRotateWorker: {}, // 自传工艺的的状态数据
      rotateSpeed: (5 * Math.PI) / 180,
      getObjectById: null, // 方法 根据ModelId获取模型
      solveAttachModel: null, // 方法 处理attach问题
      removeObject: null, // 方法 移除模型
      setModelWireFrame: null, // 方法 设置线框
      setTransparent: null, // 方法 设置透明
      showMessage: null, // 方法 显示消息
      drawPartTextInfo: null, // 方法 模型上显示文字
      drawLineByPoints: null, // 方法
      drawLineByModel: null, // 方法
      drawPointByModel: null, // 方法
      ModelLabelList: new Map(), // 模型上显示列表
      modelGoHome: null, // 方法
      craftPlayFinish: null, // 方法
      createPipeObject: null, // 方法 创建管道对象
      playSoundCommand: new PlaySoundCommand(), //  方法 警告
      attachList: new Map(), // 记录attach列表
      objMaterial: new Map(),
      WareHouseList: [],
      WareHouse: new Map(), // 立库库存表
      WareHouseBasicModel: new Map(), // 立库库存基础 零件模型需要命名为warehousepart1-100 立库定位模型需要命名为warehouse1000-1009
      ProtocolIdentifiers: {
        Robot_7: 'Robot_7',
        Device_3: 'Device_3',
        Agv_3: 'Agv_3',
        Device_1: 'Device_1',
        FirstPosition: 'FirstPosition',
        WareHousePart: 'WareHousePart',
        Robot_6: 'Robot_6',
        RobotTcp: 'RobotTcp',
        DrawPath: 'DrawPath',
        ReLoadData: 'ReLoadData',
        PlayAct: 'PlayAct',
        CraftCurrOperation: 'CraftCurrOperation',
        Position: 'Position',
        Select: 'Select',
        DragMove: 'DragMove',
        ModelTransparent: 'ModelTransparent',
        Visible: 'Visible',
        Frames: 'Frames',
        ModelRotation: 'ModelRotation',
        GoHome: 'GoHome',
        GetJointAxisInfo: 'GetJointAxisInfo',
        GetDeviceBaseTool: 'GetDeviceBaseTool',
        GetJointValue: 'GetJointValue',
        C_B_ImportModel: 'C_B_ImportModel',
        SendURDF: 'SendURDF',
        SendDeviceJson: 'SendDeviceJson',
        GetDeviceJson: 'GetDeviceJson',
        SendMotionInfo: 'SendMotionInfo',
        C_B_ImportLayout: 'C_B_ImportLayout',
        GetPoseLocation: 'GetPoseLocation',
        C_B_SetProjectCode: 'C_B_SetProjectCode',
        C_B_TagIDTrigger: 'C_B_TagIDTrigger',
        C_B_ReLoad_TagIDHandler: 'C_B_ReLoad_TagIDHandler',
        C_B_SetCurrSignalList: 'C_B_SetCurrSignalList',
        SendClearModelInfo: 'SendClearModelInfo',
        C_B_SaveProjectSimulationData: 'C_B_SaveProjectSimulationData',
        C_B_GetProjectSimulationData: 'C_B_GetProjectSimulationData',
        C_B_KinematicsEditing: 'C_B_KinematicsEditing',
        C_B_SaveModel: 'C_B_SaveModel',
        C_B_ObjectAlarm: 'C_B_ObjectAlarm',
        C_B_JointMoveTo: 'C_B_JointMoveTo',
        JointMoveTo: 'JointMoveTo', // DT|JointMoveTo|modelCode|{"J1":"1","J2":"2","J3":"3","J4":"4","J5":"5","J6":"6","J7":"7","J8":"8","J9":"9"}
      },
      craftPlaySolveType: {
        visible: 'visible',
        rotation: 'rotation',
        craft: 'craft',
        signalwrite: 'signalwrite',
        wait: 'wait',
        FrameData: 'FrameData',
        attach: 'attach',
        warning: 'warning',
        camera: 'camera',
      },
      FrameOperation: {
        playCraft: true,
        visibleObject: true,
        rotationObject: true,
        writeSignal: true,
        waitSignal: true,
        attach: true,
        warning: true,
        camera: true,
      },
      signalSolveType: {
        visible: 'visible',
        rotation: 'rotation',
        craft: 'craft',
        targetLocation: 'targetlocation',
        attach: 'attach',
        warning: 'warning',
      },
    }
    editor.EventBus = EventBus
    raycaster = new THREE.Raycaster()
    mouse = new THREE.Vector2()
  },
  mounted() {
    const hash = window.location.hash.substring(1) // 去掉 `#`
    const queryIndex = hash.indexOf('?')
    if (queryIndex !== -1) {
      const queryString = hash.substring(queryIndex + 1)
      const searchParams = new URLSearchParams(queryString)
      this.dmtMode = searchParams.get('dmtmode')
      editor['autoPlayCraftCode'] = searchParams.get('autoPlayCraftCode')
    }

    editor.currentMode = this.dmtMode
    editor.currentModelPath = this.dmtMode === 'DT' ? 'models' : 'models2'
    console.log(editor.currentModelPath)
    const scope = this
    editor.objectIdSet = new Map()
    editor.objMaterial = new Map()
    editor.attachList = new Map()
    this.getConfig().then((res) => {
      if (Object.hasOwnProperty.call(res, 'robotList')) {
        editor.robotList = res.robotList
      }
      if (Object.hasOwnProperty.call(res, 'WareHouseList')) {
        editor.WareHouseList = res.WareHouseList
      }
      if (Object.hasOwnProperty.call(res, 'transParentList')) {
        ModelListTransParentList = res.transParentList
      }
      if (Object.hasOwnProperty.call(res, 'connectType')) {
        editor.connectType = res.connectType
      }
      editor.mqttHost = res.MQTTHost
      editor.mqttPort = res.MQTTPort
      editor.ip = res.webSocketIp
      //
      editor.opname = window.dt_Config.mqttTopic // res.webSocketOpName
      editor.BSport = res.webSocketBSport
      editor.rootIp = res.NodeRootIp

      editor.drawLinedModelIdMoveInfo = res.drawLinedModelIdMoveInfo
        ? res.drawLinedModelIdMoveInfo
        : []
      this.getProjectConfig()
    })
    editor.showMessage = function (message, type, time = 2000) {
      scope.$message({
        message: message,
        type: type,
        duration: time,
        center: true,
      })
    }
    editor.addEventListener('dmtModelDBClick', function (event) {
      console.log('dmtModelDBClick', event)
    })
  },
  beforeDestroy() {
    window.removeEventListener('resize', this.onWindowResize)
    editor.mqttClient?.disconnect()
    this.disposeThreeResources()
  },
  methods: {
    disposeThreeResources() {
      ModelList = []
      container = null
      scene = null
      camera = null
      axesHelper = null
      if (this.animationId) {
        cancelAnimationFrame(this.animationId)
        this.animationId = null
        console.log('动画已停止')
      }
      editor.currentMode = ''
      for (const workerKey in editor?.worker) {
        editor.worker[workerKey].terminate()
      }
      // 清理模型和几何体
      for (let i = 0; i < editor.resources?.length; i++) {
        let currentModel = null
        const currentModelData = editor.objectIdSet.get(editor.resources[i].id)
        if (currentModelData) {
          currentModel = currentModelData.object
          currentModel.traverse((mesh) => {
            if (mesh.geometry) {
              mesh.geometry.dispose() // 释放几何体
              mesh.material.dispose() // 释放材质
              editor.scene.remove(mesh) // 从场景移除
            }
          })
        }
      }
      editor.resources = []
      editor.scene = null

      // 清理渲染器
      renderer?.dispose()
      renderer?.forceContextLoss()
      renderer = null

      // 其他自定义清理（如纹理、事件监听等）
      if (this.texture) this.texture.dispose()

      editor = {}
      window.editor = {}
    },
    getConfig() {
      return new Promise((resolve, reject) => {
        axios
          .get('./DMT_WEB/config/config.json')
          .then((res) => {
            const configData = res.data
            resolve(configData)
          })
          .catch((err) => {
            reject(err)
          })
      })
    },
    /**
     * 获取项目配置文件，用于初始隐藏模型
     */
    getProjectConfig() {
      const scope = this
      const P1 = new Promise(function (resolve, reject) {
        axios({
          method: 'get',
          url: `./DMT_WEB/${editor.currentModelPath}/DTDATA.json`,
        }).then((res) => {
          editor.animOperations = {}
          editor.moveTrigger = {}
          editor.CraftList = {}
          editor.TagActList = {}

          res.data.forEach((n) => {
            Object.keys(n).forEach(function (key) {
              /**
               * 获取播放数据并解析数据
               */
              if (key === 'OperationTree') {
                n[key].forEach((CraftData) => {
                  editor.CraftList[CraftData.CraftCode] = {}
                  editor.CraftList[CraftData.CraftCode]['CraftName'] = CraftData.CraftName
                  editor.CraftList[CraftData.CraftCode]['Varieties'] = CraftData.Varieties
                  editor.CraftList[CraftData.CraftCode]['CurrPlay'] = CraftData.CurrPlay
                  if (CraftData.CraftPlayData.length < 2) {
                    editor.animOperations[CraftData.CraftCode] = ''
                  } else {
                    editor.animOperations[CraftData.CraftCode] = JSON.parse(CraftData.CraftPlayData)
                  }
                  editor.moveTrigger[CraftData.CraftCode] = {
                    moveStatus: 0,
                    myVarSetInterval: null,
                    doAnimation: false,
                    currentFrame: 0,
                    pausedFrame: 0,
                    animOperations: editor.animOperations[CraftData.CraftCode],
                    simPaceTime: 20,
                    moveStatusPosition: 0,
                  }
                })
              }
              /**
               * HandlerType: 1:显隐,2:自转,3行为
               * HandlerCode: 模型或者工艺代码
               * HandlerValue: 显隐：0/1 ,自传：正负转速&axis,行为暂停播放：0/1
               * TagValue:信号值
               */
              if (key === 'TagTriggerHandler') {
                n[key].forEach((TagActListValue) => {
                  if (editor.TagActList[TagActListValue.TagID]) {
                    editor.TagActList[TagActListValue.TagID].push({
                      HandlerType: TagActListValue.HandlerType,
                      HandlerCode: TagActListValue.HandlerCode,
                      HandlerValue: TagActListValue.HandlerValue,
                      TagValue: TagActListValue.TagValue,
                      JointType: TagActListValue.JointType,
                      Axis: TagActListValue.Axis,
                      Flip: TagActListValue.Flip,
                      Value: TagActListValue.Value,
                      ValueFactor: TagActListValue.ValueFactor,
                    })
                  } else {
                    editor.TagActList[TagActListValue.TagID] = []
                    editor.TagActList[TagActListValue.TagID].push({
                      HandlerType: TagActListValue.HandlerType,
                      HandlerCode: TagActListValue.HandlerCode,
                      HandlerValue: TagActListValue.HandlerValue,
                      TagValue: TagActListValue.TagValue,
                      JointType: TagActListValue.JointType,
                      Axis: TagActListValue.Axis,
                      Flip: TagActListValue.Flip,
                      Value: TagActListValue.Value,
                      ValueFactor: TagActListValue.ValueFactor,
                    })
                  }
                })
              }
            })
          })
          resolve(1)
        })
      })
      const P2 = new Promise(function (resolve, reject) {
        axios({
          method: 'get',
          url: `./DMT_WEB/${editor.currentModelPath}/RobotPlan_Process.json`,
        })
          .then((res) => {
            console.log(res)
            ModelList = []
            editor.objectIdUUidMap.clear()
            editor.attachList.clear()
            editor.sceneConfig = scope.getSceneConfig(res.data.sceneConfig) // 场景配置
            editor.attachments = res.data.attachments // 附加物体
            editor.resources = res.data.resources // 场景模型资源
            editor.resourcesTree = res.data.resourcesTree // 模型树
            editor.cameraState = res.data.cameraState // 场景相机位置
            editor.ProjectCode = res.data.ProjectCode // 项目代码
            editor.FocusSetList = res.data['cameraStateList'] ? res.data['cameraStateList'] : []
            editor.resourcesTree.forEach((res) => {
              if (res.treeType === 'OriginModel') {
                ModelList.push(res.name)
              }
            })
            editor.resources.forEach((res) => {
              editor.objectIdUUidMap.set(res.id, res)
            })
            editor.attachments.forEach((res) => {
              editor.attachList.set(res.RootId, res.attachList)
            })
            resolve(1)
          })
          .catch((error) => {
            console.log(error)
          })
      })
      Promise.all([P1, P2]).then((res) => {
        this.init()
      })
    },
    getSceneConfig(config) {
      if (!config) {
        config = {}
      }
      if (!Object.hasOwnProperty.call(config, 'environmentFileName')) {
        config['environmentFileName'] = 'IndoorEnvironment.exr'
      }
      if (!Object.hasOwnProperty.call(config, 'environmentFileContent')) {
        config['environmentFileContent'] = {
          type: 'binary',
          data: [],
          format: '',
        }
      }
      if (!Object.hasOwnProperty.call(config, 'environmentRotation')) {
        config['environmentRotation'] = [0, 0, 0]
      }
      if (!Object.hasOwnProperty.call(config, 'floorFileName')) {
        config['floorFileName'] = {
          showName: '无样式',
          filePath: '0',
          fileContent: '',
        }
      }
      if (!Object.hasOwnProperty.call(config, 'lightConfig')) {
        config['lightConfig'] = [{}, {}]
      }
      if (!Object.hasOwnProperty.call(config, 'OperationPanelState')) {
        config['OperationPanelState'] = true
      }
      if (!Object.hasOwnProperty.call(config, 'RenderColorModel')) {
        config['RenderColorModel'] = {
          model: '0',
          color: '#dcdcdc',
          image: '',
        }
      }
      if (!Object.hasOwnProperty.call(config, 'ModelChangeColorState')) {
        config['ModelChangeColorState'] = true
      }
      if (!Object.hasOwnProperty.call(config, 'ModelRightMenuState')) {
        config['ModelRightMenuState'] = true
      }
      if (!Object.hasOwnProperty.call(config, 'sliderToneMappingExposure')) {
        config['sliderToneMappingExposure'] = 1
      }
      if (!Object.hasOwnProperty.call(config, 'ModelAxisState')) {
        config['ModelAxisState'] = true
      }
      return config
    },
    /**
     * 设定模型初始状态
     */
    setModelSates() {
      // 模型的显示隐藏
      editor.resourcesTree.forEach((res) => {
        if (res.visible === '0') {
          if (editor.getObjectById(res.id)) {
            editor.getObjectById(res.id).visible = !!parseInt(res.visible)
          }
        }
      })
      const treeRes = editor.resourcesTree
      for (const treeResValue of treeRes) {
        if (treeResValue.treeType !== 'folder') {
          const currentModel = editor.getObjectById(treeResValue.id)

          if (Object.hasOwnProperty.call(treeResValue, 'WireFrame') && treeResValue.WireFrame) {
            editor.setModelWireFrame(currentModel, true)
          }
          if (Object.hasOwnProperty.call(treeResValue, 'transParent') && treeResValue.transParent) {
            editor.setTransparent(treeResValue.id, 0.3)
          }
          if (currentModel) currentModel.visible = !!parseInt(treeResValue.visible)
        }
      }
    },

    setSceneStates_Environment(sceneConfig) {
      renderer.toneMappingExposure = sceneConfig.sliderToneMappingExposure

      const pmremGenerator = new THREE.PMREMGenerator(renderer)
      pmremGenerator.compileEquirectangularShader()
      if (sceneConfig.environmentFileContent.data.length === 0) {
        new EXRLoader().load(
          './DMT_WEB/assets/IndoorEnvironment.exr',
          (texture) => {
            const envMap = pmremGenerator.fromEquirectangular(texture).texture
            scene.environment = envMap
            pmremGenerator.dispose()
          },
          undefined,
          undefined,
        )
        return
      }
      const format = sceneConfig.environmentFileContent.format
      const environmentData = new Uint8Array(sceneConfig.environmentFileContent.data).buffer
      switch (format) {
        case 'exr':
          new EnvironmentLoader_DMT().parseBuffer_exr(
            environmentData,
            (texture) => {
              const envMap = pmremGenerator.fromEquirectangular(texture).texture
              scene.environment = envMap
              pmremGenerator.dispose()
            },
            undefined,
            undefined,
          )
          break
        case 'hdr':
          new EnvironmentLoader_DMT().parseBuffer_hdr(
            environmentData,
            function (texture) {
              const envMap = pmremGenerator.fromEquirectangular(texture).texture
              scene.environment = envMap
              pmremGenerator.dispose()
            },
            undefined,
            undefined,
          )
          break
        default:
          new EXRLoader().load(
            './DMT_WEB/assets/IndoorEnvironment.exr',
            (texture) => {
              const envMap = pmremGenerator.fromEquirectangular(texture).texture
              scene.environment = envMap
              pmremGenerator.dispose()
            },
            undefined,
            undefined,
          )
          break
      }
    },
    setSceneStates_background(sceneConfig) {
      const type = '3' // sceneConfig.RenderColorModel.model
      switch (type) {
        case '0':
          scene.background = new THREE.Color('#dcdcdc')
          break
        case '1':
          scene.background = new THREE.Color(sceneConfig.RenderColorModel.color)
          break
        case '2':
          if (sceneConfig.RenderColorModel.image === '') {
            editor.scene.background = new THREE.Color(sceneConfig.RenderColorModel.color)
            return
          }
          new THREE.TextureLoader().load(
            sceneConfig.RenderColorModel.image === '',
            function (texture) {
              scene.background = texture
              texture.dispose()
            },
          )
          break
        case '3':
          renderer.setClearAlpha(0)
          scene.background = null
          break
        default:
          scene.background = new THREE.Color('#dcdcdc')
          break
      }
    },
    setSceneStates_floor(sceneConfig) {
      return
      const fileNameIndex = sceneConfig['floorFileName'].filePath
      const fileContent = floorFileConfig[parseInt(fileNameIndex)].fileContent
      if (fileContent === '') {
        editor.scene.remove(editor.dmtFloor)
        editor.dmtFloor = null
        return
      }
      const texture = new THREE.TextureLoader().load(fileContent)
      texture.wrapS = THREE.RepeatWrapping
      texture.wrapT = THREE.RepeatWrapping
      texture.repeat.set(2000, 2000)

      const material = new THREE.MeshStandardMaterial({
        map: texture,
        transparent: true,
        blending: THREE.NormalBlending,
      })

      if (!editor.dmtFloor) {
        const geometry = new THREE.CircleGeometry(8000, 64)
        editor.dmtFloor = new THREE.Mesh(geometry, material)
        editor.dmtFloor.position.z = -0.01
        editor.scene.add(editor.dmtFloor)
      } else {
        editor.dmtFloor.material = material
      }
    },
    setSceneStates_light(sceneConfig) {
      const directionalLightConfig = sceneConfig['lightConfig'][0]
      const pointLightConfig = sceneConfig['lightConfig'][1]
      const directionalLight = new DMT_Light(editor.scene, directionalLightConfig)
      directionalLight.createDirectionalLight()
      const pointLight = new DMT_Light(editor.scene, pointLightConfig)
      pointLight.createPointLight()
    },
    /**
     * 初始化场景信息
     */
    init() {
      this.setEditorFunction()
      const scope = this
      container = document.getElementById('viewPort')
      scene = new THREE.Scene()
      editor.scene = scene
      const width = container.clientWidth
      const height = container.clientHeight
      const aspect = width / height

      camera = new THREE.PerspectiveCamera(45, aspect, 0.01, 2000)
      camera.name = 'Camera'
      camera.position.set(0, 50, 100)
      camera.up.set(0, 0, 1)
      camera.lookAt(new THREE.Vector3(1, 1, 1))

      scene.add(camera)
      editor.camera = camera
      axesHelper = new THREE.AxesHelper(1)
      scene.add(axesHelper)

      renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true })
      renderer.outputColorSpace = THREE.SRGBColorSpace
      renderer.setPixelRatio(window.devicePixelRatio)
      renderer.setSize(container.clientWidth, container.clientHeight)
      renderer.setClearColor(0xcccccc)
      renderer.shadowMap.enabled = true
      renderer.shadowMap.type = THREE.BasicShadowMap
      renderer.toneMapping = THREE.LinearToneMapping

      const loader = new GLTFLoader().setPath(`./DMT_WEB/${editor.currentModelPath}/`)
      const dracoLoader = new DRACOLoader()
      dracoLoader.setDecoderPath('./DMT_WEB/draco/')
      loader.setDRACOLoader(dracoLoader)

      this.setSceneStates_Environment(editor.sceneConfig)
      this.setSceneStates_background(editor.sceneConfig)
      this.setSceneStates_floor(editor.sceneConfig)
      this.setSceneStates_light(editor.sceneConfig)

      container.appendChild(renderer.domElement)
      container.addEventListener('dblclick', this.ondblclick, false)
      editor.cameraControls = new DmtControl(editor.camera, renderer.domElement)
      editor.cameraControls.listenToKeyEvents(window) // optional
      editor.cameraControls.update()
      editor.cameraControls.addEventListener('change', (e) => {
        this.sendCameraState()
      })
      window.addEventListener('resize', this.onWindowResize, false)
      editor.cameraControls.resetState(
        editor.cameraState.target,
        editor.cameraState.position,
        editor.cameraState.zoom0,
      )
      this.startAnimation()
      console.log(ModelList)
      setTimeout(() => {
        for (let i = 0; i < ModelList.length; i++) {
          loader.load(
            ModelList[i] + '.glb',
            function (gltf) {
              const currentModel = gltf.scene.children[0]
              scene.add(currentModel)
              scope.setObjectByConfig(currentModel)
              ModelListId.push(gltf.scene.id)
              modelCount += 1
              scope.$refs.modelProcess.innerText =
                '正在加载模型' + ((modelCount / ModelList.length) * 100).toFixed(2) + '%'
              if (modelCount === ModelList.length) {
                scope.$refs.modelProcess.style.display = 'none'
                scope.lookObject(scene)
                scope.setModelSates()
                scope.connectService()
              }
            },
            (xhr) => {
              // eslint-disable-next-line handle-callback-err
            },
            (error) => {
              console.log(error)
              modelCount += 1
              console.log(`加载模型${ModelList[i]}出错!`)
              if (modelCount === ModelList.length) {
                scope.$refs.modelProcess.style.display = 'none'
                scope.lookObject(scene)
                scope.setModelSates()
                scope.connectService()
              }
            },
          )
        }
      }, 1000)
    },
    setEditorFunction() {
      const scope = this
      /**
       * 创建管道对象
       * @param length 长度
       * @param directly 直径
       * @param thickness 厚度
       * @param position 位置
       * @param quaternion 角度
       * @param material 材质
       * @return {THREE.Mesh} 返回创建的网格对象
       */
      editor.createPipeObject = function (
        length,
        directly,
        thickness,
        position,
        quaternion,
        material,
      ) {
        const radius = directly / 2.0
        const radius1 = radius - thickness
        const arcShape = new THREE.Shape().moveTo(0, 0).absarc(0, 0, radius, 0, Math.PI * 2, false)
        const holePath = new THREE.Path().moveTo(0, 0).absarc(0, 0, radius1, 0, Math.PI * 2, true)
        arcShape.holes.push(holePath)
        const extrudeSettings = {
          depth: length, // 挤压深度/厚度
          bevelEnabled: false,
          curveSegments: 48,
        }
        const geometry = new THREE.ExtrudeGeometry(arcShape, extrudeSettings)
        const mesh = new THREE.Mesh(geometry, material)
        mesh.position.copy(position)
        mesh.quaternion.copy(quaternion)
        mesh.scale.copy(new THREE.Vector3(1, 1, 1))
        return mesh
      }
      /**
       * 设置模型的初始状态
       * @param ModelId
       */
      editor.modelGoHome = function (ModelId) {
        if (ModelId) {
          let currentModel = null
          const currentModelData = editor.objectIdSet.get(ModelId)
          if (currentModelData) {
            currentModel = currentModelData.object
            currentModel.traverse((obj) => {
              if (obj.userData.ModelId) {
                const position = editor.objectIdSet.get(obj.userData.ModelId).position
                const rotation = editor.objectIdSet.get(obj.userData.ModelId).rotation
                obj.position.copy(position)
                obj.rotation.copy(rotation)
                obj.updateMatrixWorld()
              }
            })
          }
        } else {
          for (let i = 0; i < editor.resources.length; i++) {
            let currentModel = null
            const currentModelData = editor.objectIdSet.get(editor.resources[i].id)
            if (currentModelData) {
              currentModel = currentModelData.object
              currentModel.traverse((obj) => {
                if (obj.userData.ModelId) {
                  const position = editor.objectIdSet.get(obj.userData.ModelId).position
                  const rotation = editor.objectIdSet.get(obj.userData.ModelId).rotation
                  obj.position.copy(position)
                  obj.rotation.copy(rotation)
                  obj.updateMatrixWorld()
                }
              })
            }
          }
        }
      }
      /**
       * 通过ModelId获取模型
       * @param ModelId
       * @returns {null}
       */
      editor.getObjectById = function (ModelId) {
        let currentModel = null
        const currentModelData = editor.objectIdSet.get(ModelId)
        if (currentModelData) currentModel = currentModelData.object
        return currentModel
      }
      /**
       * attach 弃用
       * @param ModelId
       * @param attach
       */
      editor.solveAttachModel = function (ModelId, attach = true) {
        console.warn('DMT: solveAttachModel弃用！')
      }
      /**
       * 移出物体
       * @param object
       */
      editor.removeObject = function (object) {
        if (object === null) return
        if (object.parent === null) return
        object.parent.remove(object)
      }
      /**
       * 设置模型线框
       * @param currentObject
       * @param WireframeValue
       */
      editor.setModelWireFrame = function (currentObject, WireframeValue) {
        currentObject.traverse((obj) => {
          if (obj instanceof THREE.Mesh) {
            obj.material = editor.objMaterial.get(obj.id).clone()
            obj.material['wireframe'] = WireframeValue
            obj.material.needsUpdate = true
          }
        })
      }

      /**
       * 模型透明
       * @param ModelId
       * @param Opacity 透明度
       */
      editor.setTransparent = function (ModelId, Opacity = 0.3) {
        new Promise((resolve, reject) => {
          const TransModel = editor.getObjectById(ModelId)
          if (!TransModel) {
            console.warn('模型不存在！（setTransparent）')
            reject(false)
          } else {
            TransModel.traverse((obj) => {
              if (obj.material) {
                const material_yuan = editor.objMaterial.get(obj.id).clone()
                obj.material = material_yuan
                if (Opacity !== 1) {
                  obj.material = new THREE.MeshStandardMaterial({
                    color: material_yuan.color,
                    side: 2,
                    transparent: true,
                    opacity: Opacity,
                  })
                }
              }
            })
            resolve(true)
          }
        })
      }

      /**
       * 模型上方显示悬浮文字
       * @param ModelId 模型ID
       * @param TagValue  显示的位置 可以换行
       */
      editor.drawPartTextInfo = function (ModelId, TagValue) {
        new Promise((resolve, reject) => {
          let LabelInfo = editor.ModelLabelList.get(ModelId)
          const TransModel = editor.getObjectById(ModelId)
          if (TransModel) {
            if (!LabelInfo) {
              LabelInfo = {
                position: scope.getDeltaPosition(new THREE.Vector3(), { x: 0, y: 0, z: 0.5 }),
                label: TagValue,
                object: null,
              }
              editor.ModelLabelList.set(ModelId, LabelInfo)
            }
            if (LabelInfo.object) editor.removeObject(LabelInfo.object)
            if (TransModel.visible) {
              LabelInfo.label = TagValue.replaceAll('\\n', '\n')
              const spriteLabel = new SpriteText(LabelInfo.label, 0.2, '#000000')
              // spriteLabel.borderColor = '#30ff00'
              // spriteLabel.borderWidth = [0.3, 0.2]
              spriteLabel.backgroundColor = 'rgb(255,183,0)'
              spriteLabel.position.copy(LabelInfo.position)
              LabelInfo.object = spriteLabel
              TransModel.add(spriteLabel)
            }
          }
        })
      }
      /**
       * 根据点绘制线
       * @param {string} lineId
       * @param {[{x:1,y:1,z:1},{x:1,y:1,z:1}]} points
       * @param {string} color
       */
      editor.drawLineByPoints = function (lineId, points, color = '#00893d') {
        if (!editor.isOk) return
        const PointItem = points.map((point) => {
          return new THREE.Vector3(point.x, point.y, point.z)
        })
        if (editor.lineMap.has(lineId)) {
          const LineObject = editor.lineMap.get(lineId)
          LineObject.geometry = new THREE.BufferGeometry().setFromPoints(PointItem)
        } else {
          const geometry = new THREE.BufferGeometry().setFromPoints(PointItem)
          const material = new THREE.LineBasicMaterial({ color: color, linewidth: 1 })
          const LineObject = new THREE.Line(geometry, material)
          LineObject.name = lineId
          editor.lineMap.set(lineId, LineObject)
          editor.scene.add(LineObject)
        }
      }
      editor.drawLineByModel = function (KeyItem, isClear = false) {
        if (!editor.isDrawLinedModel) return
        setInterval(() => {
          new Promise((resolve) => {
            if (editor.drawLinedModel[KeyItem]) {
              editor.drawLinedModel[KeyItem].drawLinedModel.updateWorldMatrix()
              const currentPosition = editor.drawLinedModel[
                KeyItem
              ].drawLinedModel.getWorldPosition(new THREE.Vector3())
              const currentPositionFinal = new THREE.Vector3(
                currentPosition.x + editor.drawLinedModel[KeyItem].drawLinedModelDelta[0] / 1000,
                currentPosition.y + editor.drawLinedModel[KeyItem].drawLinedModelDelta[1] / 1000,
                currentPosition.z + editor.drawLinedModel[KeyItem].drawLinedModelDelta[2] / 1000,
              )
              const lastPosition =
                editor.drawLinedModel[KeyItem].drawToolLineHash[
                  editor.drawLinedModel[KeyItem].drawToolLineHash.length - 1
                ]
              if (
                lastPosition.x !== currentPositionFinal.x ||
                lastPosition.y !== currentPositionFinal.y ||
                lastPosition.z !== currentPositionFinal.z
              ) {
                editor.drawLinedModel[KeyItem].drawToolLineHash.push(currentPositionFinal)
              }
              editor.drawLinedModel[KeyItem].drawToolLine.geometry =
                new THREE.BufferGeometry().setFromPoints(
                  editor.drawLinedModel[KeyItem].drawToolLineHash,
                )
            }
          })
        }, 100)
      }
      editor.drawPointByModel = function (KeyItem, isClear = false) {
        if (!editor.isDrawPointModel) return
        new Promise((resolve) => {
          if (editor.drawPointModel[KeyItem]) {
            editor.drawPointModel[KeyItem].drawPointModel.updateWorldMatrix()
            const currentPosition = editor.drawPointModel[KeyItem].drawPointModel.getWorldPosition(
              new THREE.Vector3(),
            )
            const currentPositionFinal = new THREE.Vector3(
              currentPosition.x + editor.drawPointModel[KeyItem].drawPointModelDelta[0] / 1000,
              currentPosition.y + editor.drawPointModel[KeyItem].drawPointModelDelta[1] / 1000,
              currentPosition.z + editor.drawPointModel[KeyItem].drawPointModelDelta[2] / 1000,
            )
            const lastPosition_z =
              editor.drawPointModel[KeyItem].drawPointLineHash[
                editor.drawPointModel[KeyItem].drawPointLineHash.length - 1
              ]
            const lastPosition_y =
              editor.drawPointModel[KeyItem].drawPointLineHash[
                editor.drawPointModel[KeyItem].drawPointLineHash.length - 2
              ]
            const lastPosition_x =
              editor.drawPointModel[KeyItem].drawPointLineHash[
                editor.drawPointModel[KeyItem].drawPointLineHash.length - 3
              ]
            if (
              lastPosition_x.x !== currentPositionFinal.x ||
              lastPosition_y.y !== currentPositionFinal.y ||
              lastPosition_z.z !== currentPositionFinal.z
            ) {
              editor.drawPointModel[KeyItem].drawPointLineHash.push(
                currentPositionFinal.x,
                currentPositionFinal.y,
                currentPositionFinal.z,
              )
            }
            editor.drawPointModel[KeyItem].drawPointLine.geometry.setAttribute(
              'position',
              new THREE.Float32BufferAttribute(editor.drawPointModel[KeyItem].drawPointLineHash, 3),
            )
          }
        })
      }
      editor.startLine_Point = function () {
        editor.isDrawPointModel = true
      }
      editor.clearLine_Point = function () {
        editor.isDrawPointModel = false
        for (const KeyItem in editor.drawLinedModel) {
          const info = editor.drawLinedModel[KeyItem]
          const currentModel = info.drawLinedModel
          editor.drawPointModel[KeyItem].drawPointLineHash = []
          if (currentModel) {
            const currentPositionFinal = new THREE.Vector3(0, 0, 0)
            editor.drawPointModel[KeyItem].drawPointLineHash.push(
              currentPositionFinal.x,
              currentPositionFinal.y,
              currentPositionFinal.z,
            )
            editor.drawPointModel[KeyItem].drawPointLine.geometry.setAttribute(
              'position',
              new THREE.Float32BufferAttribute(editor.drawPointModel[KeyItem].drawPointLineHash, 3),
            )
          }
        }
      }
    },

    /**
     * 自适应窗口尺寸
     */
    onWindowResize() {
      const aspect = container.clientWidth / container.clientHeight
      renderer.setSize(container.clientWidth, container.clientHeight)
      camera.aspect = aspect
      camera.updateProjectionMatrix()
      this.render()
      this.sendCameraState()
    },
    /**
     * 根据有配置文件设置模型初始化属性
     * @param object
     */
    setObjectByConfig(object) {
      const objectId = object.userData['ModelId']
      const objectResource = editor.objectIdUUidMap.get(objectId)
      if (objectResource) {
        object.position.copy(
          new THREE.Vector3(
            parseFloat(objectResource.location.position.x),
            parseFloat(objectResource.location.position.y),
            parseFloat(objectResource.location.position.z),
          ),
        )
        object.quaternion.copy(
          new THREE.Quaternion(
            parseFloat(objectResource.location.quaternion.x),
            parseFloat(objectResource.location.quaternion.y),
            parseFloat(objectResource.location.quaternion.z),
            parseFloat(objectResource.location.quaternion.w),
          ),
        )
        object.visible = Boolean(parseInt(objectResource.visible))
      }
    },
    /**
     * 渲染
     */

    startAnimation() {
      this.animationId = requestAnimationFrame(this.animate)
    },

    animate() {
      this.render()
      this.animationId = requestAnimationFrame(this.animate)
      editor.attachList.forEach((attackList, ModelId) => {
        const ModelAttachParent = editor.getObjectById(ModelId)
        if (ModelAttachParent) {
          if (!ModelAttachParent.lastMatrixWorld.equals(ModelAttachParent.matrixWorld)) {
            for (const attackListElement of attackList) {
              const attachModel = editor.getObjectById(attackListElement.ModelId)
              if (attachModel) {
                const newMatrixWord = ModelAttachParent.matrixWorld.clone()
                const cubeTransWorld = newMatrixWord
                  .clone()
                  .multiply(ModelAttachParent.lastMatrixWorld.clone().invert())
                  .clone()
                const cube2OldWorld = attachModel.matrixWorld.clone()
                const cube2NewWorld = cubeTransWorld.clone().multiply(cube2OldWorld)
                const cube2ParentWorld = attachModel.parent.matrixWorld.clone()
                const cube2ParentNew = cube2ParentWorld.invert().multiply(cube2NewWorld)
                const position = new THREE.Vector3()
                const quaternion = new THREE.Quaternion()
                const scale = new THREE.Vector3()
                cube2ParentNew.decompose(position, quaternion, scale)
                attachModel.quaternion.copy(quaternion)
                attachModel.position.copy(position)
                attachModel.updateMatrixWorld()
              }
            }
            ModelAttachParent.lastMatrixWorld = ModelAttachParent.matrixWorld.clone()
          }
        }
      })
    },

    /**
     * 渲染
     */
    render() {
      if (editor.currentMode !== '' && renderer) {
        renderer.render(scene, camera)
        TWEEN.update()
      }
      // this.updatePosition(editor.selected)
    },
    connectService() {
      switch (editor.connectType) {
        case 1:
          connect(editor)
          break
        case 2:
          connectMqtt(editor)
          break
        default:
          break
      }
    },
    /**
     * 解析模型
     * @param object
     */
    lookObject(object) {
      object.traverse(function (child) {
        if (!child) return
        // 避免modelId重复
        if (Object.hasOwnProperty.call(child.userData, 'ModelId')) {
          editor.objectIdSet.set(child.userData['ModelId'], {
            ModelId: child.userData['ModelId'],
            Name: child.userData['name'],
            position: JSON.parse(JSON.stringify(child.position)),
            rotation: JSON.parse(JSON.stringify(child.rotation)),
            quaternion: JSON.parse(JSON.stringify(child.quaternion)),
            object: child,
            matrix: child.matrix.clone(),
            lastValue: null,
          })
        }
      })
      for (const robotListInfo in editor.robotList) {
        for (const info of editor.robotList[robotListInfo]) {
          info.object = editor.getObjectById(info.ModelId)
          info.matrix = info.object ? info.object.matrix.clone() : null
          info.lastValue = null
        }
      }
      object.traverse(function (child) {
        child.lastMatrixWorld = child.matrixWorld.clone()
        if (child.isMesh && child['material']) {
          if (child.material.userData['flatShading']) {
            child.material.flatShading = child.material.userData['flatShading']
          }
          if (child.userData['receiveShadow']) {
            child.receiveShadow = child.userData['receiveShadow']
          }
          if (child.userData['castShadow']) {
            child.castShadow = child.userData['castShadow']
          }
          child.geometry.computeBoundsTree({
            maxLeafTris: 5,
            strategy: 0,
          })
          child.geometry.boundsTree.splitStrategy = 0
          editor.objMaterial.set(child.id, child['material'])
        }
      })
      for (let i = 0; i < editor.drawLinedModelIdMoveInfo.length; i++) {
        const info = editor.drawLinedModelIdMoveInfo[i]
        const currentModel = editor.getObjectById(info.DrawModelId)
        editor.drawLinedModel[info.ModelIdTrigger] = {
          ModelIdTrigger: info.ModelIdTrigger,
          DrawModelId: info.DrawModelId,
          drawLinedModel: currentModel,
          color: info.color,
          drawToolLineHash: [],
          drawToolLine: null,
          drawLinedModelDelta: info.delta,
        }

        if (currentModel) {
          const defaultGeometry = new THREE.BufferGeometry()
          const defaultMaterial = new THREE.LineBasicMaterial({ color: 0x00ff00 })
          editor.drawLinedModel[info.ModelIdTrigger].drawToolLine = new THREE.Line(
            defaultGeometry,
            defaultMaterial,
          )
          editor.scene.add(editor.drawLinedModel[info.ModelIdTrigger].drawToolLine)
          const currentPosition = currentModel.getWorldPosition(new THREE.Vector3())
          const currentPositionFinal = new THREE.Vector3(
            currentPosition.x + info.delta[0] / 1000,
            currentPosition.y + info.delta[1] / 1000,
            currentPosition.z + info.delta[2] / 1000,
          )
          editor.drawLinedModel[info.ModelIdTrigger].drawToolLineHash.push(currentPositionFinal)
        }

        editor.drawPointModel[info.ModelIdTrigger] = {
          ModelIdTrigger: info.ModelIdTrigger,
          DrawModelId: info.DrawModelId,
          drawPointModel: currentModel,
          color: info.color,
          drawPointLineHash: [],
          drawPointLine: null,
          drawPointModelDelta: info.delta,
        }
        if (currentModel) {
          const currentPosition = currentModel.getWorldPosition(new THREE.Vector3())
          const currentPositionFinal = new THREE.Vector3(
            currentPosition.x + info.delta[0] / 1000,
            currentPosition.y + info.delta[1] / 1000,
            currentPosition.z + info.delta[2] / 1000,
          )

          const defaultGeometry1 = new THREE.BufferGeometry()
          defaultGeometry1.setAttribute(
            'position',
            new THREE.Float32BufferAttribute(
              [currentPositionFinal.x, currentPositionFinal.y, currentPositionFinal.z],
              3,
            ),
          )

          const createCircleTexture = () => {
            const canvas = document.createElement('canvas')
            canvas.width = 32
            canvas.height = 32
            const context = canvas.getContext('2d')
            const centerX = canvas.width / 2
            const centerY = canvas.height / 2
            const radius = canvas.width / 2

            context.beginPath()
            context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false)
            context.fillStyle = info.color
            context.fill()

            const texture = new THREE.CanvasTexture(canvas)
            return texture
          }
          const defaultMaterial1 = new THREE.PointsMaterial({
            size: 0.01,
            map: createCircleTexture(),
            transparent: true,
            alphaTest: 0.01,
          })
          editor.drawPointModel[info.ModelIdTrigger].drawPointLine = new THREE.Points(
            defaultGeometry1,
            defaultMaterial1,
          )
          editor.drawPointModel[info.ModelIdTrigger].drawPointLine.frustumCulled = false
          editor.scene.add(editor.drawPointModel[info.ModelIdTrigger].drawPointLine)
          editor.drawPointModel[info.ModelIdTrigger].drawPointLineHash.push(
            currentPositionFinal.x,
            currentPositionFinal.y,
            currentPositionFinal.z,
          )
        }
      }
      window.editor = editor
    },
    /**
     * 获取鼠标位置
     * @param dom
     * @param x
     * @param y
     * @returns {number[]}
     */
    getMousePosition(dom, x, y) {
      const rect = dom.getBoundingClientRect()
      return [(x - rect.left) / rect.width, (y - rect.top) / rect.height]
    },
    /**
     * 双击
     * @param event
     */
    ondblclick(event) {
      try {
        const array = this.getMousePosition(container, event.clientX, event.clientY)
        onUpPosition.fromArray(array)
        let intersects = this.getIntersects(onUpPosition, editor.scene.children)
        intersects = intersects.filter((res) => {
          return res.object.visible
        })
        if (intersects.length > 0) {
          const rootObjId = intersects[0].object.userData['RootId']
          editor.selected = editor.getObjectById(rootObjId)
          editor.dispatchEvent({
            type: 'dmtModelDBClick',
            ModelId: editor.selected.userData['ModelId'],
            ModelName: editor.selected.userData['name'],
          })
        } else {
          editor.selected = null
          editor.dispatchEvent({
            type: 'dmtModelDBClick',
            ModelId: '',
            ModelName: '',
          })
        }
      } catch (e) {
        editor.selected = null
        editor.dispatchEvent({
          type: 'dmtModelDBClick',
          ModelId: '',
          ModelName: '',
        })
      }
    },
    /**
     * 射线检测
     * @param point
     * @param objects
     * @returns {[]}
     */
    getIntersects(point, objects) {
      mouse.set(point.x * 2 - 1, -(point.y * 2) + 1)
      raycaster.setFromCamera(mouse, camera)
      return raycaster.intersectObjects(objects, true)
    },
    /**
     * 发送相机距离旋转中心点的位置
     * @param state
     */
    sendCameraState(state) {
      const ModelCenter = editor.cameraControls.target
      const cameraPosition = camera.position
      const cameraZoom = cameraPosition.distanceTo(ModelCenter)
      this.$emit('changeCameraState', cameraZoom) // 自定义事件  传递值“子向父组件传值”
    },
    /**
     * 实时发送双击模型的位置
     */
    updatePosition() {
      if (editor.selected) {
        const targetPosition = editor.selected
          .getWorldPosition(new THREE.Vector3())
          .clone()
          .project(camera)
        const halfWidth = window.innerWidth / 2
        const halfHeight = window.innerHeight / 2
        const position = {
          left: targetPosition.x * halfWidth + halfWidth - 200,
          top: -targetPosition.y * halfHeight + halfHeight - 500,
        }
        this.$emit('clickModel', editor.selected, position) // 自定义事件  传递值“子向父组件传值”
      }
    },
    getDeltaPosition(positionModel, positionLabel) {
      return new THREE.Vector3(
        positionLabel.x - positionModel.x,
        positionLabel.y - positionModel.y,
        positionLabel.z - positionModel.z,
      )
    },
  },
}
</script>
<style>
html {
  height: 99%;
}

body {
  height: 100%;
}

#app {
  height: 100%;
}
</style>
