var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
  __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
  return value;
};
var __async = (__this, __arguments, generator) => {
  return new Promise((resolve, reject) => {
    var fulfilled = (value) => {
      try {
        step(generator.next(value));
      } catch (e) {
        reject(e);
      }
    };
    var rejected = (value) => {
      try {
        step(generator.throw(value));
      } catch (e) {
        reject(e);
      }
    };
    var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
    step((generator = generator.apply(__this, __arguments)).next());
  });
};

// packages/plugins/sand-table/src/types.ts
var DemoAction = /* @__PURE__ */ ((DemoAction2) => {
  DemoAction2[DemoAction2["In"] = 0] = "In";
  DemoAction2[DemoAction2["Out"] = 1] = "Out";
  DemoAction2[DemoAction2["Jam"] = 2] = "Jam";
  return DemoAction2;
})(DemoAction || {});

// packages/plugins/sand-table/src/sandTable.ts
import { Service } from "@ktmap/map";
import {
  AStar as AStar2,
  getObjectsByName as getObjectsByName2,
  sleep as sleep2,
  getBox3Center
} from "@ktmap/shared";
import {
  Box3 as Box32
} from "three";
import { ParkingLayer } from "@ktmap/plugin-parking-layer";
import { LabelsLayer, LabelMarker } from "@ktmap/plugin-labels-layer";
import { RoadNetLayer } from "@ktmap/plugin-roadnet-layer";

// packages/plugins/sand-table/src/car.ts
import {
  getAngle,
  getDistance,
  getObjectByName,
  getObjectsByName,
  GLTFLoaderPromise,
  sleep,
  truncateVector3
} from "@ktmap/shared";
import TWEEN from "@tweenjs/tween.js";
import {
  Box3,
  BoxGeometry,
  BufferGeometry,
  Line,
  LineBasicMaterial,
  Mesh,
  MeshBasicMaterial,
  Vector3
} from "three";
import { OBB } from "three/examples/jsm/math/OBB.js";
var CarAction = /* @__PURE__ */ ((CarAction2) => {
  CarAction2[CarAction2["Empty"] = 0] = "Empty";
  CarAction2[CarAction2["EnterActive"] = 1] = "EnterActive";
  CarAction2[CarAction2["Enter"] = 2] = "Enter";
  CarAction2[CarAction2["LeaveActive"] = 3] = "LeaveActive";
  CarAction2[CarAction2["Leave"] = 4] = "Leave";
  CarAction2[CarAction2["Jam"] = 5] = "Jam";
  CarAction2[CarAction2["Violation"] = 6] = "Violation";
  return CarAction2;
})(CarAction || {});
var Car = class {
  constructor(map, options) {
    this.map = map;
    this.options = options;
    __publicField(this, "stopID");
    __publicField(this, "tweenGroupCar");
    __publicField(this, "carAction", 0 /* Empty */);
    __publicField(this, "car");
    var _a;
    options.speed = (_a = options.speed) != null ? _a : 5.6;
    this.car = options.car;
    this.init();
  }
  static loadCarModal(BASE_URL) {
    return __async(this, null, function* () {
      const car = yield GLTFLoaderPromise(
        `${BASE_URL}sandTable/assets/car/scene.gltf`
      );
      car.name = "car";
      car.traverse((child) => {
        if (child.isMesh) {
          child.material.emissive = child.material.color;
          child.material.emissiveMap = child.material.map;
        }
      });
      car.visible = false;
      car.scale.multiplyScalar(240);
      car.position.copy(new Vector3(0, 0, 0));
      car.rotateX(Math.PI * (90 / 180));
      car.matrixAutoUpdate = false;
      if (true) {
        const aabb = new Box3().setFromObject(car);
        const obb = new OBB().fromBox3(aabb);
        const size = new Vector3();
        obb.getSize(size);
        const geometry = new BoxGeometry(size.x, size.y, size.z);
        const obbHelper = new Mesh(
          geometry,
          new MeshBasicMaterial({ color: 0, wireframe: true })
        );
        obbHelper.position.copy(obb.center);
        car.add(obbHelper);
      }
      return car;
    });
  }
  init() {
    return __async(this, null, function* () {
      const {
        map,
        options: { car }
      } = this;
      map.scene.add(car);
      map.reDraw();
    });
  }
  in({
    begin,
    end,
    parkObject,
    violation
  }) {
    return this.runPrepare({
      begin,
      end,
      action: 0 /* In */,
      parkObject,
      violation
    });
  }
  out({
    begin,
    end,
    jam
  }) {
    return this.runPrepare({ begin, end, action: 1 /* Out */, jam });
  }
  runPrepare(_0) {
    return __async(this, arguments, function* ({
      begin,
      end,
      action,
      parkObject,
      jam,
      violation
    }) {
      const {
        map,
        options: { aStar }
      } = this;
      begin = truncateVector3(begin);
      end = truncateVector3(end);
      if (begin && end) {
        const trackPoints = aStar.calcShortestPath(
          [begin.x, begin.y],
          [end.x, end.y]
        );
        if (trackPoints.length >= 2) {
          console.log("trackPoints :>> ", trackPoints);
          const points = [];
          for (const item of trackPoints) {
            points.push(new Vector3(item.x, item.y, 0));
          }
          if (true) {
            this.drawNormalLine(points, {
              name: "ar_track",
              color: "green"
            });
          }
          yield this.run({
            trackPoints,
            parkPosition: end,
            action,
            parkObject,
            jam,
            violation
          });
        } else {
          console.warn("\u7EBF\u6BB5\u957F\u5EA6\u5C0F\u4E8E2\uFF0C\u65E0\u6CD5\u8FDB\u884C\u7ED8\u5236");
        }
        map.reDraw();
      }
    });
  }
  run(_0) {
    return __async(this, arguments, function* ({
      trackPoints,
      parkPosition,
      action,
      parkObject,
      jam,
      violation
    }) {
      var _a;
      const {
        map,
        options: { car, speed }
      } = this;
      car && (car.visible = true);
      const r = 0.01 * speed;
      const loopWheel = (wheels) => {
        map.reDraw();
        for (const item of wheels)
          item.rotateX(-r * Math.PI);
        this.stopID = requestAnimationFrame(() => loopWheel(wheels));
      };
      (_a = this.tweenGroupCar) == null ? void 0 : _a.removeAll();
      map.tweenGroupMap.delete(this.tweenGroupCar);
      cancelAnimationFrame(this.stopID);
      if (car) {
        const frontLeftWheel = getObjectByName("F_L_Wheel_2", car);
        const frontRightWheel = getObjectByName("F_R_Wheel_3", car);
        const rearWheel = getObjectByName("Rear_Wheels_1", car);
        loopWheel([frontLeftWheel, frontRightWheel, rearWheel]);
      }
      this.tweenGroupCar = new TWEEN.Group();
      map.tweenGroupMap.set(this.tweenGroupCar, null);
      const start = (trackPoints2) => {
        this.carAction = action === 0 /* In */ ? 1 /* EnterActive */ : 3 /* LeaveActive */;
        Object.assign(this.options.car.userData, {
          carAction: this.carAction
        });
        let resolve;
        const p = new Promise((_) => resolve = _);
        const tweens = [];
        for (let i = 1, len = trackPoints2.length; i < len; i++) {
          tweens.push(
            createTween(
              trackPoints2[i - 1],
              trackPoints2[i],
              this.tweenGroupCar,
              i === trackPoints2.length - 1 ? resolve : () => {
              }
            )
          );
        }
        for (let i = 1; i < tweens.length; i++) {
          tweens[i - 1].chain(tweens[i]);
        }
        tweens[0].start();
        return p;
      };
      const parking = (parkPosition2, parkObject2) => {
        var _a2;
        const { map: map2 } = this;
        const getParkRadian = (data2) => {
          let len = 0, tempLen = 0, p1, p2;
          for (let i = 1, l = data2.length; i < l; i++) {
            tempLen = getDistance(data2[i - 1], data2[i]);
            if (tempLen > len) {
              p1 = data2[i - 1];
              p2 = data2[i];
              len = tempLen;
            }
          }
          const { radian: radian2 } = getAngle(p1, p2);
          return radian2;
        };
        const { data } = parkObject2.userData;
        const radian = getParkRadian(data);
        car == null ? void 0 : car.position.copy(parkPosition2);
        car && (car.rotation.y = radian - Math.PI / 2);
        car.updateMatrix();
        car.updateMatrixWorld();
        car.userData.obb.copy(car.userData.obbSetup);
        car.userData.obb.applyMatrix4(car.matrixWorld);
        (_a2 = this.tweenGroupCar) == null ? void 0 : _a2.removeAll();
        map2.tweenGroupMap.delete(this.tweenGroupCar);
        cancelAnimationFrame(this.stopID);
        map2.reDraw();
      };
      const exit = () => {
        this.dispose();
      };
      const createTween = (oldT, newT, tweenGroupCar, cb) => {
        const t = new TWEEN.Tween(
          {
            x: oldT.x,
            y: oldT.y,
            z: 0
          },
          tweenGroupCar
        ).to(
          { x: newT.x, y: newT.y, z: newT.z || 0 },
          getDistance(oldT, newT) / speed
        ).easing(TWEEN.Easing.Linear.None).onStart(() => {
          const { radian } = getAngle(oldT, newT);
          car && (car.rotation.y = radian - Math.PI / 2);
          map.cameraControls.normalizeRotations();
        }).onUpdate((object) => {
          car.position.set(object.x, object.y, object.z);
          car.updateMatrix();
          car.updateMatrixWorld();
          car.userData.obb.copy(car.userData.obbSetup);
          car.userData.obb.applyMatrix4(car.matrixWorld);
          const carArr = getObjectsByName("car", map.scene).filter(
            (item) => item.userData.carNo !== car.userData.carNo
          );
          const obb = car.userData.obb;
          for (let i = 0, il = carArr.length; i < il; i++) {
            const object2 = carArr[i];
            const obbToTest = object2.userData.obb;
            if (obb.intersectsOBB(obbToTest)) {
              console.log("\u5835\u8F66\u4E86 :>> ", "\u5835\u8F66\u4E86");
              this.carAction = 5 /* Jam */;
              Object.assign(car.userData, {
                carAction: this.carAction
              });
              t.stop();
              cancelAnimationFrame(this.stopID);
            }
          }
          map.reDraw();
        }).onComplete(() => {
          cb == null ? void 0 : cb();
        });
        return t;
      };
      yield start(trackPoints);
      yield sleep(300);
      if (action === 0 /* In */) {
        if (violation) {
          this.carAction = 6 /* Violation */;
          Object.assign(this.options.car.userData, {
            carAction: this.carAction,
            parkTime: "-"
          });
        } else {
          parking(parkPosition, parkObject);
          this.carAction = 2 /* Enter */;
          Object.assign(this.options.car.userData, {
            carAction: this.carAction,
            parkTime: new Date().toLocaleString()
          });
        }
      } else {
        if (jam) {
          this.carAction = 5 /* Jam */;
          Object.assign(this.options.car.userData, {
            carAction: this.carAction
          });
        } else {
          this.carAction = 4 /* Leave */;
          Object.assign(this.options.car.userData, {
            carAction: this.carAction,
            outTime: new Date().toLocaleString()
          });
          exit();
        }
      }
      yield sleep(1e3);
    });
  }
  dispose() {
    var _a;
    const {
      map,
      options: { car }
    } = this;
    (_a = this.tweenGroupCar) == null ? void 0 : _a.removeAll();
    map.tweenGroupMap.delete(this.tweenGroupCar);
    map.scene.remove(car);
    cancelAnimationFrame(this.stopID);
    map.reDraw();
  }
  drawNormalLine(points, ext) {
    const { map } = this;
    const line = new Line(
      new BufferGeometry().setFromPoints(points),
      new LineBasicMaterial({
        color: (ext == null ? void 0 : ext.color) || "blue",
        opacity: 1,
        transparent: true,
        depthTest: false
      })
    );
    line.name = (ext == null ? void 0 : ext.name) || "";
    line.userData = {};
    map.scene.add(line);
  }
};
__publicField(Car, "carQueue", []);

// packages/plugins/sand-table/src/sandTable.ts
import { InfoWindow } from "@ktmap/plugin-info-window";
import { OBB as OBB2 } from "three/examples/jsm/math/OBB.js";
var SandTable = class extends Service {
  constructor(map, options) {
    super();
    this.map = map;
    this.options = options;
    __publicField(this, "complateHook");
    __publicField(this, "carModal");
    __publicField(this, "aStar");
    __publicField(this, "infoWindowJam");
    __publicField(this, "infoWindowViolation");
    this.__init();
    if (true) {
      console.log("dev :>> ", "dev");
    }
  }
  __init() {
    return __async(this, null, function* () {
      const {
        map,
        options: { BASE_URL }
      } = this;
      console.log("SandTable init success");
      const labelsLayer = new LabelsLayer({
        name: "labelsLayer",
        collision: true
      });
      map.add(labelsLayer);
      this.initData((data) => __async(this, null, function* () {
        const { floorDatas } = data;
        const paths = floorDatas[0].data.filter((_) => _.type === "path");
        this.aStar = new AStar2(paths);
        const parkingLayer = new ParkingLayer({
          poiCollision: false,
          data
        });
        map.add(parkingLayer);
        if (true) {
          const roadNetLayer = new RoadNetLayer({
            data: paths
          });
          map.add(roadNetLayer);
        }
        const parks = getObjectsByName2("park", map.scene);
        let position;
        const labelMarkers = [];
        for (const item of parks) {
          position = getBox3Center(item);
          labelMarkers.push(
            new LabelMarker({
              name: item.userData.id + "",
              text: `A-${item.userData.id}`,
              fontSize: 10,
              position,
              renderOrder: 10
            })
          );
        }
        labelsLayer.add(...labelMarkers);
        this.carModal = yield Car.loadCarModal(BASE_URL);
        const infoWindow = new InfoWindow(map, {
          type: "info",
          title: "\u8F66\u8F86\u4FE1\u606F",
          content: "",
          trigger: "hover",
          targetName: "car",
          align: { offset: [10, 0] }
        });
        infoWindow.on("hover", (car) => {
          this.emitter.emit("carHover", { car, infoWindow });
        });
        const infoWindow2 = new InfoWindow(map, {
          type: "info",
          title: "\u76D1\u63A7\u4FE1\u606F",
          trigger: "click",
          targetName: "park",
          align: { offset: [10, 0] }
        });
        infoWindow2.on("click", (park) => {
          this.emitter.emit("parkClick", { park, infoWindow: infoWindow2 });
        });
        this.infoWindowJam = new InfoWindow(map, {
          type: "warning",
          close: true,
          title: "\u62E5\u5835\u544A\u8B66",
          trigger: "custom",
          align: { points: ["bc"] }
        });
        this.infoWindowViolation = new InfoWindow(map, {
          type: "error",
          close: true,
          title: "\u8FDD\u505C\u544A\u8B66",
          trigger: "custom",
          align: { points: ["bc"] }
        });
        this.emitter.emit("complete");
      }));
    });
  }
  demo(action, ext) {
    return __async(this, null, function* () {
      const {
        map,
        map: { scene, $map, camera },
        options: { entry, exit, speed }
      } = this;
      switch (action) {
        case 0 /* In */:
          {
            const {
              parkNo,
              carNo,
              violation
            } = ext;
            if (Car.carQueue.find((item) => item.carNo === carNo)) {
              console.warn("\u8BE5\u8F66\u5DF2\u5B58\u5728\u961F\u5217\u4E2D\uFF0C\u8BF7\u52FF\u91CD\u590D\u6DFB\u52A0");
              return;
            }
            const parkObject = this.getParkObjectById(parkNo);
            if (parkObject) {
              const carModal = this.carModal.clone();
              const car = new Car(map, {
                car: carModal,
                aStar: this.aStar,
                speed
              });
              carModal.userData = Object.assign(carModal.userData, {
                carNo,
                parkNo: `A-${parkNo}`,
                inTime: new Date().toLocaleString()
              });
              const aabb = new Box32().setFromObject(carModal);
              aabb.expandByScalar(1.2);
              const obb = new OBB2().fromBox3(aabb);
              carModal.userData = Object.assign(carModal.userData, {
                obbSetup: obb,
                obb: new OBB2()
              });
              Car.carQueue.push({
                parkNo,
                carNo,
                parkObject,
                car
              });
              const end = getBox3Center(parkObject);
              yield car.in({ begin: entry, end, parkObject, violation });
              if (car.carAction === 6 /* Violation */) {
                this.emitter.emit("violation", {
                  car: car.car,
                  infoWindow: this.infoWindowViolation
                });
                const worldPosition = getBox3Center(car.car);
                this.infoWindowViolation.show(worldPosition);
              }
            } else {
              console.warn("\u627E\u4E0D\u5230\u5BF9\u5E94\u7684\u8F66\u4F4D\u7F16\u53F7");
            }
          }
          break;
        case 1 /* Out */:
          {
            const {
              parkNo,
              carNo,
              jam
            } = ext;
            const carItem = Car.carQueue.find((_) => _.carNo === carNo);
            const car = carItem == null ? void 0 : carItem.car;
            const parkObject = carItem == null ? void 0 : carItem.parkObject;
            if (car && parkObject && car.carAction === 2 /* Enter */) {
              const begin = getBox3Center(parkObject);
              yield car.out({ begin, end: exit, jam });
              if (!jam) {
                Car.carQueue = Car.carQueue.filter((_) => _.carNo !== carNo);
              }
              console.log("Car.carQueue :>> ", Car.carQueue);
            } else {
              console.warn("\u79BB\u573A\u51FA\u73B0\u9519\u8BEF");
            }
          }
          break;
        case 2 /* Jam */:
          {
            const isJam = () => {
              const jamCars = Car.carQueue.filter(
                (item) => item.car.carAction === 5 /* Jam */
              );
              if (jamCars.length >= 5) {
                this.emitter.emit("jam", {
                  infoWindow: this.infoWindowJam,
                  carQueue: jamCars
                });
                const firstCar = jamCars[0].car.car;
                const worldPosition = getBox3Center(firstCar);
                this.infoWindowJam.show(worldPosition);
              }
            };
            (() => __async(this, null, function* () {
              for (let i = 0; i < Car.carQueue.length; i++) {
                const item = Car.carQueue[i];
                yield sleep2(1e3);
                this.demo(1 /* Out */, {
                  carNo: item.carNo,
                  jam: i === 0
                });
                isJam();
              }
            }))();
          }
          break;
        default:
          break;
      }
    });
  }
  initData(cb) {
    return __async(this, null, function* () {
      const { data } = this.options;
      if (typeof data === "function") {
        try {
          const res = yield data();
          cb == null ? void 0 : cb(res);
        } catch (_) {
        }
      } else {
        cb == null ? void 0 : cb(data);
      }
    });
  }
  getParkObjectById(id) {
    const { map } = this;
    return getObjectsByName2("park", map.scene).find(
      (item) => item.userData.id === id
    );
  }
};
__publicField(SandTable, "NAME", "SandTable");
export {
  Car,
  CarAction,
  DemoAction,
  SandTable
};
//# sourceMappingURL=sand-table.esm-bundler.js.map
