import { __awaiter, __extends, __generator } from "tslib";
import { throttle } from 'lodash';
import { Cartesian3, Cartesian2, Color, Cartographic, ClippingPlane, Matrix4, ClippingPlaneCollection, CallbackProperty, createGuid, Matrix3, Quaternion } from '@taotieh/cesium_extend';
import { TIMESPAN_INSTANT } from '../../../core/Constant';
import Clip from './Clip';
var State;
(function (State) {
    State[State["READY"] = 0] = "READY";
    State[State["POINT_ORIGIN_SELECTED"] = 1] = "POINT_ORIGIN_SELECTED";
    State[State["POINT_ORIGIN_CHANGED"] = 2] = "POINT_ORIGIN_CHANGED";
    State[State["DONE"] = 3] = "DONE";
})(State || (State = {}));
/** ******************************************************************
 *  使用一个简单面刨切, 该类实现通用单面裁剪的基本功能
 * 1. 根据参数创建出一个平面
 * 2. 通过鼠标动作更改平面的位置
 * 3. 不实现平面旋转
 *********************************************************************/
var ClipWithPlane = /** @class */ (function (_super) {
    __extends(ClipWithPlane, _super);
    function ClipWithPlane(viewer, instance, origin, normal) {
        var _this = _super.call(this, viewer, instance) || this;
        _this._state = State.READY;
        _this._origin = Cartesian3.ZERO.clone();
        _this._normal = Cartesian3.UNIT_Y.clone();
        _this._isPanning = false;
        _this._lastMovePoint = { x: 0, y: 0 };
        _this._distance = {};
        _this._rotate = 0;
        _this._coefficient = 10;
        _this._onPointerDown = function (evt) { return __awaiter(_this, void 0, void 0, function () {
            var button, x, y, cart2, plane, scene;
            return __generator(this, function (_a) {
                button = evt.button, x = evt.layerX, y = evt.layerY;
                if (button === 0) {
                    cart2 = new Cartesian2(x, y);
                    plane = void 0;
                    try {
                        scene = this._viewer.scene;
                        plane = scene.pick(cart2);
                    }
                    catch (e) {
                        return [2 /*return*/];
                    }
                    console.log(plane);
                    if (plane && plane.id && plane.id.plane) {
                        this._selectedPlane = plane;
                        this._lastMovePoint = { x: x, y: y };
                        this._switchPanning(true);
                    }
                }
                else if (button === 2) {
                    this.stop();
                }
                return [2 /*return*/];
            });
        }); };
        _this._onMove = throttle(function (evt) { return __awaiter(_this, void 0, void 0, function () {
            var x, y, _a, lastMovePoint, plane, deduceX, deduceY, distance;
            return __generator(this, function (_b) {
                if (this._isPanning) {
                    x = evt.layerX, y = evt.layerY;
                    _a = this, lastMovePoint = _a._lastMovePoint, plane = _a._selectedPlane;
                    deduceX = lastMovePoint.x - x;
                    deduceY = lastMovePoint.y - y;
                    distance = (Math.abs(deduceY) > Math.abs(deduceX) ? deduceY : deduceX) / 10;
                    this._updateCutingPlaneWithOrigin({ distance: distance, id: plane.id.id });
                    this._lastMovePoint = { x: x, y: y };
                }
                return [2 /*return*/];
            });
        }); }, TIMESPAN_INSTANT);
        _this._onPointerUp = function (evt) { return __awaiter(_this, void 0, void 0, function () {
            return __generator(this, function (_a) {
                this._switchPanning(false);
                return [2 /*return*/];
            });
        }); };
        _this._origin = origin;
        _this._normal = normal;
        _this._state = State.POINT_ORIGIN_SELECTED;
        _this._toReset();
        return _this;
    }
    /**
     * 使用原点来创建平面
     * @param position 中心点
     * @param direction 方向
     */
    ClipWithPlane.prototype._createCuttingPlaneWithOrigin = function (normal, origin) {
        if (normal === void 0) { normal = this._normal; }
        return __awaiter(this, void 0, void 0, function () {
            var _a, viewer, distance, cSc, tileset, boundingSphere, radius, center, plane, planes, transformCenter, transformCartographic, boundingSphereCartographic, height, guid, entity;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        _a = this, viewer = _a._viewer, distance = _a._distance;
                        return [4 /*yield*/, this._instance.getInstanceSceneControl()];
                    case 1:
                        cSc = _b.sent();
                        tileset = cSc._layer3DTile;
                        if (!tileset)
                            return [2 /*return*/];
                        boundingSphere = tileset.boundingSphere;
                        radius = boundingSphere.radius;
                        center = origin || boundingSphere.center;
                        // const center: Cartesian3 = boundingSphere.center;
                        center.clone(this._origin);
                        normal.clone(this._normal);
                        plane = new ClippingPlane(normal, 0);
                        window['plane'] = plane;
                        this._levelPlaneCut = plane;
                        planes = (tileset.clippingPlanes =
                            tileset.clippingPlanes ||
                                new ClippingPlaneCollection({
                                    planes: [],
                                    edgeWidth: 1.0,
                                    edgeColor: Color.GREEN
                                }));
                        // @ts-ignore
                        planes.add(plane);
                        return [4 /*yield*/, tileset['readyPromise']];
                    case 2:
                        _b.sent();
                        if (!Matrix4.equals(tileset.root.transform, Matrix4.IDENTITY)) {
                            transformCenter = Matrix4.getTranslation(tileset.root.transform, new Cartesian3());
                            transformCartographic = Cartographic.fromCartesian(transformCenter);
                            boundingSphereCartographic = Cartographic.fromCartesian(center);
                            height = boundingSphereCartographic.height - transformCartographic.height;
                            planes.modelMatrix = Matrix4.fromTranslation(new Cartesian3(0.0, 0.0, height));
                        }
                        guid = createGuid();
                        entity = viewer.entities.add({
                            id: guid,
                            position: center,
                            orientation: new CallbackProperty(this._cbpCreateRotateUpdateFunction(), false),
                            plane: {
                                dimensions: new Cartesian2(radius * 2, radius * 2),
                                material: Color.GREEN.withAlpha(0.1),
                                plane: new CallbackProperty(this._cbpCreatePlaneUpdateFunction(plane, guid), false),
                                outline: true,
                                outlineColor: Color.WHITE
                            }
                        });
                        this._radius = radius * 2;
                        distance[guid] = 0;
                        return [2 /*return*/, entity];
                }
            });
        });
    };
    ClipWithPlane.prototype.transPositionWithMatrix = function (point) {
        var cSc = this._instance.getInstanceSceneControl();
        var tileset = cSc._layer3DTile;
        var matrix = Matrix4.fromArray(tileset.root.transform);
        var inverse = new Matrix4();
        Matrix4.inverse(matrix, inverse);
        var result = new Cartesian3();
        Matrix4.multiplyByPoint(matrix, point, result);
        return result;
    };
    ClipWithPlane.prototype.createRotateHandler = function (normal, origin, entity) {
        if (normal === void 0) { normal = this._normal; }
        if (entity === void 0) { entity = null; }
        return __awaiter(this, void 0, void 0, function () {
            var cSc, tileset, boundingSphere, radius, center, viewer;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0: return [4 /*yield*/, this._instance.getInstanceSceneControl()];
                    case 1:
                        cSc = _a.sent();
                        tileset = cSc._layer3DTile;
                        if (!tileset)
                            return [2 /*return*/];
                        boundingSphere = tileset.boundingSphere;
                        radius = boundingSphere.radius;
                        center = origin || boundingSphere.center;
                        viewer = this._viewer;
                        return [2 /*return*/];
                }
            });
        });
    };
    /**
     * 使用原点来更新平面
     * @param origin 平面上一点
     */
    ClipWithPlane.prototype._updateCutingPlaneWithOrigin = function (_a) {
        var distance = _a.distance, id = _a.id;
        var _b = this, plane = _b._selectedPlane, _radius = _b._radius;
        this._state = State.POINT_ORIGIN_CHANGED;
        if (Math.abs(this._distance[id] + distance) > _radius / 2)
            return;
        // 限定平移距离
        this._distance[id] += distance;
        plane.id.plane.material = Color.GREEN.withAlpha(0.3);
    };
    ClipWithPlane.prototype._updateCuttingPlaneWithOrientation = function (rotate) {
        var _a = this, plane = _a._selectedPlane, normal = _a._normal;
        // this._rotate += rotate;
        // const hpr = new HeadingPitchRoll(this._rotate, 0, 0);
        // this._orientation = Transforms.headingPitchRollQuaternion(this._origin, hpr);
        plane.id.plane.material = Color.GREEN.withAlpha(0.3);
        // var rotate = Math.toRadians(rotate);//转成弧度
        var quat = Quaternion.fromAxisAngle(Cartesian3.UNIT_Z, rotate); //quat为围绕这个z轴旋转d度的四元数
        var rot_mat3 = Matrix3.fromQuaternion(quat); //rot_mat3为根据四元数求得的旋转矩阵
        var v = new Cartesian3(normal.x, normal.y, normal.z); //p1的局部坐标
        var m = Matrix4.fromRotationTranslation(rot_mat3, Cartesian3.ZERO);
        // m2为旋转加平移的4x4变换矩阵，这里平移为(0,0,0)
        Matrix4.multiplyByTranslation(m, v, m); //m = m X v
        var p2 = new Cartesian3();
        Matrix4.getTranslation(m, p2); //根据最终变换矩阵m得到p2
        this._normal = p2.clone();
    };
    ClipWithPlane.prototype._toReset = function () {
        return __awaiter(this, void 0, void 0, function () {
            var cSc;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0: return [4 /*yield*/, this._instance.getInstanceSceneControl()];
                    case 1:
                        cSc = _a.sent();
                        if (!cSc._layer3DTile)
                            return [2 /*return*/];
                        // @ts-ignore
                        this._viewer.entities.removeAll();
                        cSc._layer3DTile.clippingPlanes
                            ? cSc._layer3DTile.clippingPlanes.removeAll()
                            : '';
                        this._state = State.READY;
                        return [2 /*return*/];
                }
            });
        });
    };
    /** **************************************************************
     *  需要一个单独的函数来维护, 因为不仅仅是要改变标志位. 相应的, 还要冻结视窗
     *  最终需要实现, 当 this._isPanning === true 时候, 鼠标的拖拽动作不会
     *  导致相机移动.
     * @param isPanning 是否激活移动状态
     *****************************************************************/
    ClipWithPlane.prototype._switchPanning = function (isPanning) {
        if (isPanning === void 0) { isPanning = true; }
        return __awaiter(this, void 0, void 0, function () {
            var viewer, cPo;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        viewer = this._viewer;
                        return [4 /*yield*/, this._instance.getInstancePointerControl()];
                    case 1:
                        cPo = _a.sent();
                        if (isPanning) {
                            cPo.isForzen = true;
                            this._isPanning = true;
                        }
                        else {
                            this._isPanning = false;
                            viewer.scene.screenSpaceCameraController.enableInputs = true;
                            this._selectedPlane &&
                                (this._selectedPlane.id.plane.material = Color.GREEN.withAlpha(0.1));
                            this._selectedPlane = undefined;
                            cPo.isForzen = false;
                        }
                        return [2 /*return*/];
                }
            });
        });
    };
    ClipWithPlane.prototype._cbpCreatePlaneUpdateFunction = function (plane, id) {
        var _this = this;
        return function () {
            plane.distance = _this._distance[id];
            plane.normal = _this._normal;
            return plane;
        };
    };
    ClipWithPlane.prototype._cbpCreateRotateUpdateFunction = function () {
        var _this = this;
        return function () {
            return _this._orientation;
        };
    };
    ClipWithPlane.prototype.getDistance = function () {
        return this._distance;
    };
    ClipWithPlane.prototype.start = function () {
        return __awaiter(this, void 0, void 0, function () {
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0: return [4 /*yield*/, _super.prototype.start.call(this)];
                    case 1:
                        _a.sent();
                        return [4 /*yield*/, this._toReset()];
                    case 2:
                        _a.sent();
                        return [2 /*return*/];
                }
            });
        });
    };
    ClipWithPlane.prototype.next = function () {
        return __awaiter(this, void 0, void 0, function () {
            var _a;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        _a = this._state;
                        return [3 /*break*/, 1];
                    case 1: return [4 /*yield*/, this._toReset()];
                    case 2:
                        _b.sent();
                        _b.label = 3;
                    case 3: return [2 /*return*/];
                }
            });
        });
    };
    ClipWithPlane.prototype.stop = function () {
        return __awaiter(this, void 0, void 0, function () {
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0: return [4 /*yield*/, this._toReset()];
                    case 1:
                        _a.sent();
                        return [4 /*yield*/, _super.prototype.stop.call(this)];
                    case 2:
                        _a.sent();
                        return [2 /*return*/];
                }
            });
        });
    };
    return ClipWithPlane;
}(Clip));
export default ClipWithPlane;
