text: import * as mars3d from "mars3d"
  
  export let map // mars3d.Map三维地图对象
  
  // 需要覆盖config.json中地图属性参数（当前示例框架中自动处理合并）
  export const mapOptions = {
    scene: {
      center: { lat: 31.834317, lng: 117.2199, alt: 87, heading: 30, pitch: -29 },
      fxaa: true
    }
  }
  
  /**
   * 初始化地图业务，生命周期钩子函数（必须）
   * 框架在地图初始化完成后自动调用该函数
   * @param {mars3d.Map} mapInstance 地图对象
   * @returns {void} 无
   */
  export function onMounted(mapInstance) {
    map = mapInstance // 记录map
  
    globalNotify("操作提示", `鼠标左键单击进行发射`, { duration: null })
    addDemo()
  }
  
  /**
   * 释放当前地图业务的生命周期函数
   * @returns {void} 无
   */
  export function onUnmounted() {
    map = null
  }
  
  function addDemo() {
    const center = Cesium.Cartesian3.fromDegrees(117.220206, 31.834866, 50)
    const modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(center)
  
    const meshVisualizer = new Cesium.MeshVisualizer({
      modelMatrix: modelMatrix,
      up: { y: 1 },
      referenceAxisParameter: {
        length: 100,
        width: 0.05,
        headLength: 2,
        headWidth: 0.1
      }
    })
    map.scene.primitives.add(meshVisualizer)
  
    meshVisualizer.showReference = true // 显示坐标轴
  
    function createRandomColor() {
      return Cesium.Color.fromRandom({ alpha: 1 }) // fromRgba(Math.floor(Math.random() * (1 << 24)));
    }
    function createMaterial(color) {
      if (typeof color === "string") {
        //
      } else if (Cesium.defined(color)) {
        color = Cesium.Color.fromRgba(color).withAlpha(1)
      } else {
        color = createRandomColor()
      }
      return new Cesium.MeshPhongMaterial({
        defaultColor: color,
        side: Cesium.MeshMaterial.Sides.DOUBLE,
        translucent: false
      })
    }
    // const groundMaterial = new Cesium.MeshPhongMaterial({
    //   defaultColor: "rgb(255,0,0)",
    //   side: Cesium.MeshMaterial.Sides.DOUBLE,
    //   translucent: false
    // })
    Cesium.Cartesian3.prototype.set = function (x, y, z) {
      this.x = x
      this.y = y
      this.z = z
    }
    Cesium.Cartesian2.prototype.set = function (x, y) {
      this.x = x
      this.y = y
    }
    Cesium.Quaternion.prototype.set = function (x, y, z, w) {
      this.x = x
      this.y = y
      this.z = z
      this.w = w
    }
  
    Ammo().then(function () {
      // - Global variables -
  
      // Graphics variables
      // const clock = new THREE.Clock()
  
      const mouseCoords = new THREE.Vector2()
      // const raycaster = new THREE.Raycaster()
      const ballMaterial = createMaterial(0x202020)
  
      // Physics variables
      const gravityConstant = 7.8
      let collisionConfiguration
      let dispatcher
      let broadphase
      let solver
      let physicsWorld
      const margin = 0.05
  
      const convexBreaker = new THREE.ConvexObjectBreaker()
  
      // Rigid bodies include all movable objects
      const rigidBodies = []
  
      const pos = new THREE.Vector3()
      const quat = new THREE.Quaternion()
      const transformAux1 = new Ammo.btTransform()
      const tempBtVec3_1 = new Ammo.btVector3(0, 0, 0)
  
      // const time = 0
  
      const objectsToRemove = []
      for (let i = 0; i < 500; i++) {
        objectsToRemove[i] = null
      }
      let numObjectsToRemove = 0
  
      const impactPoint = new THREE.Vector3()
      const impactNormal = new THREE.Vector3()
  
      function initPhysics() {
        // Physics configuration
  
        collisionConfiguration = new Ammo.btDefaultCollisionConfiguration()
        dispatcher = new Ammo.btCollisionDispatcher(collisionConfiguration)
        broadphase = new Ammo.btDbvtBroadphase()
        solver = new Ammo.btSequentialImpulseConstraintSolver()
        physicsWorld = new Ammo.btDiscreteDynamicsWorld(dispatcher, broadphase, solver, collisionConfiguration)
        physicsWorld.setGravity(new Ammo.btVector3(0, -gravityConstant, 0))
      }
  
      function createObject(mass, halfExtents, pos, quat, material) {
        // y，z调换位置
        const object = new THREE.Mesh(new THREE.BoxGeometry(halfExtents.x * 2, halfExtents.y * 2, halfExtents.z * 2), material)
        object.position.copy(pos)
        object.quaternion.copy(quat)
        // object.position.y += 3;
        convexBreaker.prepareBreakableObject(object, mass, new THREE.Vector3(), new THREE.Vector3(), true)
  
        createDebrisFromBreakableObject(object)
      }
  
      function createObjects() {
        // Ground
        pos.set(0, -0.5, 0)
        quat.set(0, 0, 0, 1)
        const ground = createParalellepipedWithPhysics(40, 1, 40, 0, pos, quat, createMaterial(0xffffff))
  
        // Tower 1
        const towerMass = 1000
        const towerHalfExtents = new THREE.Vector3(2, 5, 2)
        pos.set(-8, 5, 0)
        quat.set(0, 0, 0, 1)
        createObject(towerMass, towerHalfExtents, pos, quat, createMaterial("rgb(247,174,68)"))
  
        // Tower 2
        pos.set(8, 5, 0)
        quat.set(0, 0, 0, 1)
        createObject(towerMass, towerHalfExtents, pos, quat, createMaterial("rgb(247,174,68)"))
  
        // Bridge
        const bridgeMass = 100
        const bridgeHalfExtents = new THREE.Vector3(7, 0.2, 1.5)
        pos.set(0, 10.2, 0)
        quat.set(0, 0, 0, 1)
        createObject(bridgeMass, bridgeHalfExtents, pos, quat, createMaterial("rgb(247,174,68)"))
  
        // Stones
        const stoneMass = 120
        const stoneHalfExtents = new THREE.Vector3(1, 2, 0.15)
        const numStones = 8
        quat.set(0, 0, 0, 1)
        for (let i = 0; i < numStones; i++) {
          pos.set(0, 2, 15 * (0.5 - i / (numStones + 1)))
  
          createObject(stoneMass, stoneHalfExtents, pos, quat, createMaterial(0xb0b0b0))
        }
  
        // Mountain
        const mountainMass = 860
        const mountainHalfExtents = new THREE.Vector3(4, 5, 4)
        pos.set(5, mountainHalfExtents.y * 0.5, -7)
        quat.set(0, 0, 0, 1)
        const mountainPoints = []
        // y，z调换位置
        mountainPoints.push(new THREE.Vector3(mountainHalfExtents.x, -mountainHalfExtents.y, mountainHalfExtents.z))
        mountainPoints.push(new THREE.Vector3(-mountainHalfExtents.x, -mountainHalfExtents.y, mountainHalfExtents.z))
        mountainPoints.push(new THREE.Vector3(mountainHalfExtents.x, -mountainHalfExtents.y, -mountainHalfExtents.z))
        mountainPoints.push(new THREE.Vector3(-mountainHalfExtents.x, -mountainHalfExtents.y, -mountainHalfExtents.z))
        mountainPoints.push(new THREE.Vector3(0, mountainHalfExtents.y, 0))
        const mountain = new THREE.Mesh(new THREE.ConvexGeometry(mountainPoints), createMaterial("rgb(247,174,68)"))
        mountain.position.copy(pos)
        mountain.quaternion.copy(quat)
        convexBreaker.prepareBreakableObject(mountain, mountainMass, new THREE.Vector3(), new THREE.Vector3(), true)
        createDebrisFromBreakableObject(mountain)
      }
  
      function createParalellepipedWithPhysics(sx, sy, sz, mass, pos, quat, material) {
        const box = Cesium.BoxGeometry.createGeometry(
          Cesium.BoxGeometry.fromDimensions({
            dimensions: new Cesium.Cartesian3(sx, sy, sz),
            vertexFormat: new Cesium.VertexFormat({
              position: true,
              normal: true
            })
          })
        )
        const object = new Cesium.Mesh(box, material)
        object.quaternion = new Cesium.Quaternion()
        const shape = new Ammo.btBoxShape(new Ammo.btVector3(sx * 0.5, sy * 0.5, sz * 0.5))
        shape.setMargin(margin)
  
        createRigidBody(object, shape, mass, pos, quat)
  
        return object
      }
  
      function createDebrisFromBreakableObject(object) {
        object.castShadow = true
        object.receiveShadow = true
  
        const shape = createConvexHullPhysicsShape(object.geometry.vertices)
        shape.setMargin(margin)
  
        const body = createRigidBody(object, shape, object.userData.mass, null, null, object.userData.velocity, object.userData.angularVelocity)
  
        // Set pointer back to the three object only in the debris objects
        const btVecUserData = new Ammo.btVector3(0, 0, 0)
        btVecUserData.threeObject = object
        body.setUserPointer(btVecUserData)
      }
  
      function removeDebris(object) {
        meshVisualizer.remove(object)
  
        physicsWorld.removeRigidBody(object.userData.physicsBody)
      }
  
      function createConvexHullPhysicsShape(points) {
        const shape = new Ammo.btConvexHullShape()
  
        for (let i = 0, il = points.length; i < il; i++) {
          const p = points[i]
          tempBtVec3_1.setValue(p.x, p.y, p.z) // y,z调换位置
          const lastOne = i === il - 1
          shape.addPoint(tempBtVec3_1, lastOne)
        }
  
        return shape
      }
  
      function createRigidBody(object, physicsShape, mass, pos, quat, vel, angVel) {
        if (pos) {
          object.position.copy(pos)
        } else {
          pos = object.position
        }
        if (quat) {
          if (object.quaternion) {
            object.quaternion.copy(quat)
          }
        } else {
          quat = object.quaternion
        }
  
        const transform = new Ammo.btTransform()
        transform.setIdentity()
        transform.setOrigin(new Ammo.btVector3(pos.x, pos.y, pos.z))
        transform.setRotation(new Ammo.btQuaternion(quat.x, quat.y, quat.z, quat.w))
        const motionState = new Ammo.btDefaultMotionState(transform)
  
        const localInertia = new Ammo.btVector3(0, 0, 0)
        physicsShape.calculateLocalInertia(mass, localInertia)
  
        const rbInfo = new Ammo.btRigidBodyConstructionInfo(mass, motionState, physicsShape, localInertia)
        const body = new Ammo.btRigidBody(rbInfo)
  
        body.setFriction(0.5)
  
        if (vel) {
          body.setLinearVelocity(new Ammo.btVector3(vel.x, vel.y, vel.z))
        }
        if (angVel) {
          body.setAngularVelocity(new Ammo.btVector3(angVel.x, angVel.y, angVel.z))
        }
  
        object.userData.physicsBody = body
        object.userData.collided = false
  
        meshVisualizer.add(object)
  
        if (mass > 0) {
          rigidBodies.push(object)
  
          // Disable deactivation
          body.setActivationState(4)
        }
  
        physicsWorld.addRigidBody(body)
  
        return body
      }
  
      function updatePhysics(deltaTime) {
        // Step world
        physicsWorld.stepSimulation(deltaTime, 10)
  
        // Update rigid bodies
        for (let i = 0, il = rigidBodies.length; i < il; i++) {
          const objThree = rigidBodies[i]
          const objPhys = objThree.userData.physicsBody
          const ms = objPhys.getMotionState()
          if (ms) {
            ms.getWorldTransform(transformAux1)
            const p = transformAux1.getOrigin()
            const q = transformAux1.getRotation()
            objThree.position.set(p.x(), p.y(), p.z())
            if (objThree.quaternion) {
              objThree.quaternion.set(q.x(), q.y(), q.z(), q.w())
            }
  
            objThree.userData.collided = false
            objThree.modelMatrixNeedsUpdate = true
          }
        }
  
        for (let i = 0, il = dispatcher.getNumManifolds(); i < il; i++) {
          const contactManifold = dispatcher.getManifoldByIndexInternal(i)
          const rb0 = contactManifold.getBody0()
          const rb1 = contactManifold.getBody1()
  
          const threeObject0 = Ammo.castObject(rb0.getUserPointer(), Ammo.btVector3).threeObject
          const threeObject1 = Ammo.castObject(rb1.getUserPointer(), Ammo.btVector3).threeObject
  
          if (!threeObject0 && !threeObject1) {
            continue
          }
  
          const userData0 = threeObject0 ? threeObject0.userData : null
          const userData1 = threeObject1 ? threeObject1.userData : null
  
          const breakable0 = userData0 ? userData0.breakable : false
          const breakable1 = userData1 ? userData1.breakable : false
  
          const collided0 = userData0 ? userData0.collided : false
          const collided1 = userData1 ? userData1.collided : false
  
          if ((!breakable0 && !breakable1) || (collided0 && collided1)) {
            continue
          }
  
          let contact = false
          let maxImpulse = 0
          for (let j = 0, jl = contactManifold.getNumContacts(); j < jl; j++) {
            const contactPoint = contactManifold.getContactPoint(j)
            if (contactPoint.getDistance() < 0) {
              contact = true
              const impulse = contactPoint.getAppliedImpulse()
              if (impulse > maxImpulse) {
                maxImpulse = impulse
                const pos = contactPoint.get_m_positionWorldOnB()
                const normal = contactPoint.get_m_normalWorldOnB()
                impactPoint.set(pos.x(), pos.y(), pos.z())
                impactNormal.set(normal.x(), normal.y(), normal.z())
              }
              break
            }
          }
  
          // If no point has contact, abort
          if (!contact) {
            continue
          }
  
          // Subdivision
  
          const fractureImpulse = 250
  
          if (breakable0 && !collided0 && maxImpulse > fractureImpulse) {
            const debris = convexBreaker.subdivideByImpact(threeObject0, impactPoint, impactNormal, 1, 2, 1.5)
  
            const numObjects = debris.length
            for (let j = 0; j < numObjects; j++) {
              createDebrisFromBreakableObject(debris[j])
            }
  
            objectsToRemove[numObjectsToRemove++] = threeObject0
            userData0.collided = true
          }
  
          if (breakable1 && !collided1 && maxImpulse > fractureImpulse) {
            const debris = convexBreaker.subdivideByImpact(threeObject1, impactPoint, impactNormal, 1, 2, 1.5)
  
            const numObjects = debris.length
            for (let j = 0; j < numObjects; j++) {
              createDebrisFromBreakableObject(debris[j])
            }
  
            objectsToRemove[numObjectsToRemove++] = threeObject1
            userData1.collided = true
          }
        }
  
        for (let i = 0; i < numObjectsToRemove; i++) {
          removeDebris(objectsToRemove[i])
        }
        numObjectsToRemove = 0
      }
  
      const ray = new Cesium.Ray()
      let clickRequest = false
      let start = false
      let hasInit = false
      let startTime = new Date()
      const rayDir = new Cesium.Cartesian3()
  
      function initInput() {
        const scene = map.scene
        const handler = new Cesium.ScreenSpaceEventHandler(scene.canvas)
        const lastMesh = null
        handler.setInputAction(function (movement) {
          if (!clickRequest) {
            Cesium.Cartesian2.clone(movement.position, mouseCoords)
            clickRequest = true
          }
        }, Cesium.ScreenSpaceEventType.LEFT_DOWN)
      }
  
      function processClick() {
        if (clickRequest) {
          meshVisualizer.getPickRay(mouseCoords, ray)
          if (!ray) {
            clickRequest = false
            return
          }
          // Creates a ball
          const ballMass = 35
          const ballRadius = 0.4
          const ball = new Cesium.Mesh(
            new Cesium.SphereGeometry({
              radius: ballRadius,
              stackPartitions: 14,
              slicePartitions: 10
            }),
            ballMaterial
          )
  
          const ballShape = new Ammo.btSphereShape(ballRadius)
          ballShape.setMargin(margin)
  
          Cesium.Cartesian3.clone(ray.direction, rayDir)
          Cesium.Cartesian3.subtract(ray.origin, ray.direction, pos)
  
          quat.set(0, 0, 0, 1)
          const ballBody = createRigidBody(ball, ballShape, ballMass, pos, quat)
          // ballBody.setFriction(0.5);
  
          Cesium.Cartesian3.normalize(rayDir, rayDir)
          Cesium.Cartesian3.multiplyByScalar(rayDir, 50, rayDir)
          ballBody.setLinearVelocity(new Ammo.btVector3(rayDir.x, rayDir.y, rayDir.z))
  
          clickRequest = false
        }
      }
      const hs = false
      function update(frameState) {
        if (hs) {
          return
        }
        const deltaTime = (new Date() - startTime) / 1000.0
        updatePhysics(deltaTime)
        processClick()
        startTime = new Date()
        // hs = true;
      }
      setTimeout(function () {
        if (!hasInit) {
          // - Init -
  
          initPhysics()
  
          createObjects()
  
          initInput()
  
          hasInit = true
        }
        if (!start) {
          startTime = new Date()
          meshVisualizer.beforeUpdate.addEventListener(update)
          start = true
        } else {
          meshVisualizer.beforeUpdate.removeEventListener(update)
          start = false
        }
      }, 1000 * 3)
    })
  }
  