<template>
  <div style="height: 100%">
    <!-- <div style="position: absolute;right: 10px;bottom: 230px;">
      <el-radio-group v-model="viewType" size="mini" @change="changeViewMode">
        <el-radio-button label="漫游模式"></el-radio-button>
        <el-radio-button label="固定模式"></el-radio-button>
      </el-radio-group>
    </div> -->
    <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 SpriteText from './js/three-spritetext.module.js'

import * as THREE from 'three'
import axios from 'axios'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js'
import * as TWEEN from 'three/examples/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 { EXRLoader } from 'three/examples/jsm/loaders/EXRLoader'
import { acceleratedRaycast, computeBoundsTree, disposeBoundsTree } from './libs/bvh'
THREE.Mesh.prototype.raycast = acceleratedRaycast
THREE.BufferGeometry.prototype.computeBoundsTree = computeBoundsTree
THREE.BufferGeometry.prototype.disposeBoundsTree = disposeBoundsTree
let container, scene, camera, axesHelper, renderer
let modelCount = 0
const updateCameraStateTimer = null
const editor = {
  WeldLightList: [],
  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
  },
  ProjectCode: null,
  sceneConfig: null,
  resourcesTree: null,
  attachments: null,
  resources: null,
  cameraState: null,
  cameraStateAll: [],
  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, // 方法 模型上显示文字
  ModelLabelList: new Map(), // 模型上显示列表
  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',
    C_B_ImportDevice: 'C_B_ImportDevice',
    C_B_OutputDevice: 'C_B_OutputDevice',
    C_B_ANDON: 'C_B_ANDON',
    C_B_SparkTrigger: 'C_B_SparkTrigger',
    C_B_ModeRun: 'C_B_ModeRun' // 1标准模式 2虚拟调试模式 3数字孪生模式
  },
  craftPlaySolveType: {
    visible: 'visible',
    rotation: 'rotation',
    craft: 'craft',
    signalwrite: 'signalwrite',
    wait: 'wait',
    FrameData: 'FrameData',
    attach: 'attach',
    warning: 'warning'
  },
  FrameOperation: {
    playCraft: true,
    visibleObject: true,
    rotationObject: true,
    writeSignal: true,
    waitSignal: true,
    attach: true,
    warning: true
  },
  signalSolveType: {
    visible: 'visible',
    rotation: 'rotation',
    craft: 'craft',
    targetLocation: 'targetlocation',
    attach: 'attach',
    warning: 'warning'
  }
}
// eslint-disable-next-line no-unused-vars
let ModelListTransParentList = []
const ModelList = []
const 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 {
      deviceStatusDataOld: {},
      timer: null,
      viewType: '固定模式',
      isMove: false,
      checked: false,
      cameraData: [],
      object: null,
      flag: 0,
      s: null
    }
  },
  mounted() {
    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 = res.webSocketOpName
      editor.BSport = res.webSocketBSport
      editor.rootIp = res.NodeRootIp
      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)
    })
  },
  created() {
  },
  beforeDestroy() {
    clearInterval(updateCameraStateTimer)
    clearInterval(timer)
  },
  methods: {
    changeViewMode(value) {
      console.log(value)
      if (value === '漫游模式') {
        this.isMove = true
        this.$message.success('开启漫游模式！')
        this.updateCameraState()
      }
      if (value === '固定模式') {
        this.isMove = false
        this.$message.success('开启固定模式，请使用鼠标操作！')
      }
    },
    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 P1 = new Promise(function (resolve, reject) {
        axios({
          method: 'get',
          url: './DMT_WEB/models/DTDATA.json'
        }).then((res) => {
          editor.animOperations = {}
          editor.moveTrigger = {}
          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/models/RobotPlan_Process.json'
        }).then((res) => {
          editor.sceneConfig = 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.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)
          })
          res.data.cameraStateList.forEach(CameraData => {
            editor.cameraStateAll.push({
              name: CameraData.explain,
              cameraDate: JSON.parse(CameraData.data)
            })
          })
          if (editor.cameraStateAll.length > 0) {
            editor.cameraStateAll.push(editor.cameraStateAll[0])
          }
          resolve(1)
        }).catch((error) => { console.log(error) })
      })
      Promise.all([P1, P2]).then(res => {
        this.init()
      })
    },
    /**
    * 设定模型初始状态
    */
    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)
        }
      }
    },

    /**
    * 设定场景初始状态
    * @param sceneConfig  {object}
    * @param sceneConfig.RenderColorModel  {object}
    * @param sceneConfig.RenderColorModel.color  {string} '#dcdcdc'
    * @param sceneConfig.RenderColorModel.image  {string} base64
    * @param sceneConfig.RenderColorModel.model  {string} '0' '1' '2'
    * @param sceneConfig.sliderToneMappingExposure  {number} 1
    */
    setSceneStates(sceneConfig) {
      const type = 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
        default:
          scene.background = new THREE.Color('#dcdcdc')
          break
      }
      const sliderToneMappingExposure = sceneConfig.sliderToneMappingExposure
      renderer.toneMappingExposure = sliderToneMappingExposure
      // this.updateCameraState()
    },
    /**
    * 初始化场景信息
    */
    init() {
      this.setEditorFunction()
      const scope = this
      container = document.getElementById('viewPort')
      scene = new THREE.Scene()
      scene.environmentRotation = new THREE.Euler(Math.PI / 2, 0, 0)
      scene.backgroundRotation = new THREE.Euler(Math.PI / 2, 0, 0)
      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 })
      renderer.outputColorSpace = THREE.SRGBColorSpace
      renderer.setPixelRatio(window.devicePixelRatio)
      renderer.setSize(container.clientWidth, container.clientHeight)
      renderer.setClearColor(0xcccccc)
      renderer.toneMapping = THREE.LinearToneMapping
      renderer.toneMappingExposure = Math.pow(2, 0)

      const pmremGenerator = new THREE.PMREMGenerator(renderer)
      pmremGenerator.compileEquirectangularShader()
      const loader = new GLTFLoader().setPath('./DMT_WEB/models/')
      const dracoLoader = new DRACOLoader()
      dracoLoader.setDecoderPath('./DMT_WEB/draco/')
      loader.setDRACOLoader(dracoLoader)
      new EXRLoader().load('./DMT_WEB/assets/IndoorEnvironment.exr', (texture) => {
        const envMap = pmremGenerator.fromEquirectangular(texture).texture
        scene.environment = envMap
        scene.background = new THREE.Color('#000d3a')
        pmremGenerator.dispose()
      }, undefined, undefined)
      this.setSceneStates(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()
      })

      const light1 = new THREE.AmbientLight(new THREE.Color('#ffffff'), 1)
      light1.name = 'ambient_light'
      editor.cameraControls.object.add(light1)

      const light2 = new THREE.DirectionalLight(new THREE.Color('#ffffff'), 1)
      light2.position.set(0.5, 0, 0.866) // ~60º
      light2.name = 'main_light'
      editor.cameraControls.object.add(light2)

      window.addEventListener('resize', this.onWindowResize, false)
      editor.cameraControls.resetState(editor.cameraState.target, editor.cameraState.position, editor.cameraState.zoom0)
      this.animate()
      setTimeout(() => {
        for (let i = 0; i < ModelList.length; i++) {
          loader.load(ModelList[i] + '.glb', function (gltf) {
            const currentModel = gltf.scene.children[0]
            currentModel.traverse(child => {
              if (child.isMesh && child['material']) {
                child.geometry.computeBoundsTree({
                  maxLeafTris: 5,
                  strategy: 0
                })
                child.geometry.boundsTree.splitStrategy = 0
                editor.objMaterial.set(child.id, child['material'])
              }
            })
            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) => {
            modelCount += 1
            console.log(`加载模型${ModelList[i].ModelName}出错!`)
            if (modelCount === ModelList.length) {
              scope.$refs.modelProcess.style.display = 'none'
              scope.lookObject(scene)
              scope.setModelSates()
              scope.connectService()
            }
          })
        }
      }, 1000)
    },
    setEditorFunction() {
      const scope = this
      /**
    * 通过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) {
      }
      /**
    * 移出物体
    * @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)
            }
          }
        })
      }
    },

    /**
    * 自适应窗口尺寸
    */
    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))
      }
    },
    /**
    * 渲染
    */
    animate() {
      this.render()
      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()
          }
        }
      })
      TWEEN.update()
    },

    /**
    * 渲染
    */
    render() {
      renderer.render(scene, camera)
      // for (let i = 0; i < editor.WeldLightList.length; i++) {
      //   if (editor.WeldLightList[i].TagValue === '1') {
      //     editor.WeldLightList[i].light.visible = !editor.WeldLightList[i].light.visible
      //   } else {
      //     editor.WeldLightList[i].light.visible = false
      //   }
      // }
      // this.updatePosition(editor.selected)
    },
    connectService() {
      switch (editor.connectType) {
        case 1:
          connect(editor)
          break
        case 2:
          connectMqtt(editor)
          break
        default:
          break
      }
    },
    /**
    * 解析模型
    * @param object
    */
    lookObject(object) {
      const scope = this
      object.traverse(function (child) {
        if (!child) return
        // 避免modelId重复
        if (Object.hasOwnProperty.call(child.userData, 'ModelId')) {
          if (editor.objectIdSet.has(child.userData['ModelId'])) {
            child.userData['ModelId'] = child.uuid
            editor.objectIdSet.set(child.uuid, {
              ModelId: child.id,
              Name: child.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
            })
          } else {
            editor.objectIdSet.set(child.userData['ModelId'], {
              ModelId: child.id,
              Name: child.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()
      })
      // for (const weldInfo in window.dt_Config.weldInfo) {
      //   editor.WeldLightList.push({
      //     id: weldInfo,
      //     name: window.dt_Config.weldInfo[weldInfo].name,
      //     TagValue: '0',
      //     light: this.drawWeldLight(weldInfo, window.dt_Config.weldInfo[weldInfo].weldPosition)
      //   })
      // }
      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))
    },
    drawWeldLight(modelId, positionDelta) {
      const geometry = new THREE.BufferGeometry()
      const vertices = []
      const textureLoader = new THREE.TextureLoader()
      const sprite1 = textureLoader.load('./css/lensflare0_alpha.png')
      const x = 0 + positionDelta.x
      const y = 0 + positionDelta.y
      const z = 0 + positionDelta.z
      const materials = []
      vertices.push(x, y, z)
      geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3))
      const parameters = [
        [[1.0, 1, 1], sprite1, 0.1]
      ]
      const sprite = parameters[0][1]
      const size = parameters[0][2]

      materials[0] = new THREE.PointsMaterial({ size: size, map: sprite, blending: THREE.AdditiveBlending, depthTest: false, transparent: true })
      const Points = new THREE.Points(geometry, materials[0])
      const parentModel = editor.getObjectById(modelId)
      if (parentModel) {
        parentModel.add(Points)
      }
      return Points
    },
    updateCameraState() {
      const that = this
      new TWEEN.Tween({
        target: editor.cameraStateAll[that.flag].cameraDate.target,
        position: editor.cameraStateAll[that.flag].cameraDate.position,
        zoom0: editor.cameraStateAll[that.flag].cameraDate.zoom0
      }).to({
        target: editor.cameraStateAll[that.flag + 1].cameraDate.target,
        position: editor.cameraStateAll[that.flag + 1].cameraDate.position,
        zoom0: editor.cameraStateAll[that.flag + 1].cameraDate.zoom0
      }, 4000)
        .onStart(function () {
        }).onUpdate(function () {
          editor.cameraControls.resetState(this._object.target, this._object.position, this._object.zoom0)
        }).onComplete(function () {
          that.flag++
          if (that.flag === editor.cameraStateAll.length - 1) {
            that.flag = 0
          }
          setTimeout(() => {
            if (that.isMove) {
              that.updateCameraState()
            }
          }, 1000)
        }).start()
      //
      // editor.cameraControls.resetState(editor.cameraStateAll[flag].cameraDate.target, editor.cameraStateAll[flag].cameraDate.position, editor.cameraStateAll[flag].cameraDate.zoom0)
      // updateCameraStateTimer = setInterval(() => {
      //   if (!this.isMove) return
      //   if (editor.cameraStateAll.length - 1 > flag) {
      //
      //   } else {
      //     flag = 0
      //   }
      // }, 5000)
    },
    changeModelColorByAndon(ModelCode, triggerType, triggerColor) {
      return new Promise(resolve => {
        const currentModel = editor.getObjectById(ModelCode)
        if (currentModel) {
          if (triggerType === 1) {
            currentModel.traverse(object => {
              if (object instanceof THREE.Mesh && !Object.hasOwnProperty.call(object.userData, 'isAxis')) {
                object.material.color = new THREE.Color(triggerColor)
                object.material.side = 2
                object.material.transparent = true
                object.material.opacity = 0.8
              }
            })
          } else {
            currentModel.traverse(object => {
              if (object instanceof THREE.Mesh) {
                const m = editor.objMaterial.get(object.id)
                if (m) {
                  if (Array.isArray(m)) {
                    const materialArray = []
                    m.forEach(item => {
                      materialArray.push(item.clone())
                    })
                    object.material = materialArray
                  } else {
                    object.material = m.clone()
                  }
                }
              }
            })
          }
        }
        resolve(true)
      })
    },
  }
}
</script>
<style>
html {
  height: 99%;
}

body {
  height: 100%;
}

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