var KTMapPluginPoisLayer = (function (exports, three) {
    'use strict';

    /******************************************************************************
    Copyright (c) Microsoft Corporation.

    Permission to use, copy, modify, and/or distribute this software for any
    purpose with or without fee is hereby granted.

    THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
    REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
    AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
    INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
    LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
    OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
    PERFORMANCE OF THIS SOFTWARE.
    ***************************************************************************** */

    function __awaiter(thisArg, _arguments, P, generator) {
        function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
        return new (P || (P = Promise))(function (resolve, reject) {
            function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
            function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
            function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
            step((generator = generator.apply(thisArg, _arguments || [])).next());
        });
    }

    function mitt(n){return {all:n=n||new Map,on:function(t,e){var i=n.get(t);i?i.push(e):n.set(t,[e]);},off:function(t,e){var i=n.get(t);i&&(e?i.splice(i.indexOf(e)>>>0,1):n.set(t,[]));},emit:function(t,e){var i=n.get(t);i&&i.slice().map(function(n){n(e);}),(i=n.get("*"))&&i.slice().map(function(n){n(t,e);});}}}

    /**
     * mitt 事件总程
     */
    class MyMitt {
        constructor() {
            Object.defineProperty(this, "emitter", {
                enumerable: true,
                configurable: true,
                writable: true,
                value: mitt()
            });
        }
        on(type, handler) {
            this.emitter.on(type, handler);
            return this;
        }
        off(type, handler) {
            this.emitter.off(type, handler);
            return this;
        }
    }

    /**
     * 基类，element
     *
     * 被添加到地图上的元素
     *
     * 若当前扩展类不需要 mitt，在继承时，泛型填写 any，如：
     *
     * ```ts
     * class Foo extends Element<any>{
     *
     * }
     * ```
     */
    class Element extends MyMitt {
        constructor() {
            super();
            /**
             * NAME
             * 一般为子类的类名（防止工具压缩把类名压缩了，导致一些拿类名判断的逻辑失效，所以手动加上类名）
             */
            // abstract NAME: string;
            Object.defineProperty(this, "map", {
                enumerable: true,
                configurable: true,
                writable: true,
                value: void 0
            });
        }
        /**
         * __inject
         * 当元素被 map.add 之后，会注入整个 map 对象到子类，提供子类使用 map
         */
        __inject(map) {
            this.map = map;
            return this;
        }
    }

    class PoiMarker extends Element {
        constructor(options) {
            super();
            Object.defineProperty(this, "options", {
                enumerable: true,
                configurable: true,
                writable: true,
                value: options
            });
            Object.defineProperty(this, "_scale", {
                enumerable: true,
                configurable: true,
                writable: true,
                value: void 0
            });
            Object.defineProperty(this, "sprite", {
                enumerable: true,
                configurable: true,
                writable: true,
                value: void 0
            });
        }
        complete() { }
        // 重写父类 _inject
        __inject(map, _scale) {
            super.__inject(map);
            this._scale = _scale;
            return this;
        }
        __init() { }
        _create() {
            return __awaiter(this, void 0, void 0, function* () {
                const canvas = yield this.generateCanvas(this.options);
                this.sprite = this.makeCanvasSprite(canvas, this.options);
                return this.sprite;
            });
        }
        setPosition(position) {
            this.sprite && this.sprite.position.copy(position);
            this.map.reDraw();
        }
        generateCanvas({ icon, scale = 1 }) {
            const canvas = document.createElement('canvas');
            const context = canvas.getContext('2d');
            return new Promise((resolve, reject) => {
                const img = new Image();
                img.onload = () => {
                    const w = img.width * scale;
                    const h = img.height * scale;
                    // 根据文字内容获取宽度
                    canvas.width = w * this._scale;
                    canvas.height = h * this._scale;
                    // canvas.width = w;
                    // canvas.height = h;
                    context.drawImage(img, 0, 0, canvas.width, canvas.height);
                    resolve(canvas);
                };
                img.src = icon;
            });
        }
        makeCanvasSprite(canvas, { name, renderOrder, position }) {
            const texture = new three.Texture(canvas);
            texture.needsUpdate = true;
            const spriteMaterial = new three.SpriteMaterial({
                map: texture,
                transparent: true,
                depthTest: false,
                // depthTest: this.depthTest,
                depthWrite: false
            });
            const sprite = new three.Sprite(spriteMaterial);
            // sprite.name = OBJECT_NAME.POILabel
            sprite.name = name;
            // sprite.userData.name = name
            sprite.renderOrder = renderOrder;
            sprite.center = new three.Vector2(0.5, 0);
            sprite.position.copy(position);
            // sprite.position.z += 10
            // this.group.add(sprite)
            // reDraw()
            return sprite;
        }
    }
    Object.defineProperty(PoiMarker, "NAME", {
        enumerable: true,
        configurable: true,
        writable: true,
        value: 'PoiMarker'
    });

    class PoisLayer extends Element {
        constructor({ name, collision }) {
            super();
            Object.defineProperty(this, "_scale", {
                enumerable: true,
                configurable: true,
                writable: true,
                value: 4
            });
            Object.defineProperty(this, "options", {
                enumerable: true,
                configurable: true,
                writable: true,
                value: void 0
            });
            Object.defineProperty(this, "_group", {
                enumerable: true,
                configurable: true,
                writable: true,
                value: void 0
            });
            this.options = { name, collision };
            this._group = new three.Object3D();
            this._group.name = name;
        }
        complete() { }
        __init() {
            this.map.scene.add(this._group);
            this.map.updateSizeMap.set(this, () => this._updateSize());
        }
        add(...poiMarker) {
            return __awaiter(this, void 0, void 0, function* () {
                for (const item of poiMarker) {
                    item.__inject(this.map, this._scale);
                    const marker = yield item._create();
                    this._group.add(marker);
                }
                this.map.reDraw();
                return this;
            });
        }
        remove(...poiMarker) {
            var _a, _b, _c, _d, _e, _f;
            for (const item of poiMarker) {
                (_c = (_b = (_a = item === null || item === void 0 ? void 0 : item.sprite) === null || _a === void 0 ? void 0 : _a.geometry) === null || _b === void 0 ? void 0 : _b.dispose) === null || _c === void 0 ? void 0 : _c.call(_b);
                (_f = (_e = (_d = item === null || item === void 0 ? void 0 : item.sprite) === null || _d === void 0 ? void 0 : _d.material) === null || _e === void 0 ? void 0 : _e.dispose) === null || _f === void 0 ? void 0 : _f.call(_e);
                (item === null || item === void 0 ? void 0 : item.sprite) && this._group.remove(item === null || item === void 0 ? void 0 : item.sprite);
            }
            this.map.reDraw();
            return this;
        }
        /**
         * @desc 暴露出更新size方法，使其可以在 cameraControls 控制时候更新
         */
        _updateSize() {
            const sprites = this._group ? this._group.children : [];
            if (sprites.length === 0)
                return;
            //  是否需要碰撞检测
            if (this.options.collision) {
                for (let i = 0; i < sprites.length; i++) {
                    const sprite = sprites[i];
                    sprite.visible = true;
                }
            }
            for (let i = 0; i < sprites.length; i++) {
                const compareSprite = sprites[i];
                // @ts-ignore
                const canvas = compareSprite.material.map.image;
                if (canvas) {
                    const position = compareSprite.position;
                    const scale = this.getPoiScale(position, {
                        w: canvas.width,
                        h: canvas.height
                    });
                    // 缩小 4 倍在 retina 屏幕会比较高清
                    compareSprite.scale.set(scale[0] / this._scale, scale[1] / this._scale, 1.0);
                    // 是否需要碰撞检测
                    if (this.options.collision && compareSprite.visible) {
                        for (let j = i + 1; j < sprites.length; j++) {
                            const sprite = sprites[j];
                            if (this.isMarkerCollision(compareSprite, sprite)) {
                                sprite.visible = false;
                            }
                        }
                    }
                }
            }
        }
        getPoiScale(position, poiRect) {
            const distance = this.map.camera.position.distanceTo(position); // 相机和标注点的距离
            const top = Math.tan(((this.map.camera.fov / 2) * Math.PI) / 180) * distance; // camera.fov 相机的拍摄距离
            // var meterPerPixel = (2 * top) / window.innerHeight;
            const meterPerPixel = (2 * top) / this.map.$map.clientHeight;
            const scaleX = poiRect.w * meterPerPixel;
            const scaleY = poiRect.h * meterPerPixel;
            return [scaleX, scaleY, 1.0];
        }
        /**
         * @desc 检测两个标注sprite是否碰撞
         */
        isMarkerCollision(compareSprite, sprite) {
            const comparePosition = this.toScreenPos([
                compareSprite.position.x,
                compareSprite.position.y,
                compareSprite.position.z
            ], this.map.camera);
            const spritePosition = this.toScreenPos([sprite.position.x, sprite.position.y, sprite.position.z], this.map.camera);
            const image1 = compareSprite.material.map.image;
            const image2 = sprite.material.map.image;
            const w1 = image1.width / this._scale;
            const h1 = image1.height / this._scale;
            const x1 = comparePosition.x - w1 / 2;
            const y1 = comparePosition.y - h1 / 2;
            const w2 = image2 ? image2.width / this._scale : 0;
            const h2 = image2 ? image2.height / this._scale : 0;
            const x2 = spritePosition.x - w2 / 2; // 点2左下角的xy点
            const y2 = spritePosition.y - h2 / 2;
            if (x1 >= x2 && x1 >= x2 + w2) {
                return false;
            }
            else if (x1 <= x2 && x1 + w1 <= x2) {
                return false;
            }
            else if (y1 >= y2 && y1 >= y2 + h2) {
                return false;
            }
            else if (y1 <= y2 && y1 + h1 <= y2) {
                return false;
            }
            else {
                return true;
            }
        }
        /**
         * @desc three世界坐标转为屏幕坐标
         */
        toScreenPos(position, camera) {
            const worldVector = new three.Vector3(position[0], position[1], position[2]);
            const standardVector = worldVector.project(camera); // 世界坐标转标准设备坐标
            const a = this.map.$map.clientWidth / 2;
            const b = this.map.$map.clientHeight / 2;
            const x = Math.round(standardVector.x * a + a); // 标准设备坐标转屏幕坐标
            const y = Math.round(-standardVector.y * b + b); // 标准设备坐标转屏幕坐标
            return {
                x,
                y
            };
        }
    }
    Object.defineProperty(PoisLayer, "NAME", {
        enumerable: true,
        configurable: true,
        writable: true,
        value: 'PoisLayer'
    });

    exports.PoiMarker = PoiMarker;
    exports.PoisLayer = PoisLayer;

    Object.defineProperty(exports, '__esModule', { value: true });

    return exports;

})({}, THREE);
