import * as THREE from "three";
import type { MessageReactive } from 'naive-ui';
import {CSS2DObject} from "three/examples/jsm/renderers/CSS2DRenderer";
import {t} from "@/language";
import {IPreviewOperation, usePreviewOperationStore} from "@/store/modules/previewOperation";
import {useDispatchSignal} from "@/hooks/useSignal";

export enum MeasureMode {
    Distance = "Distance",
    Area = "Area",
    Angle = "Angle"
}

let pdFn, pmFn, puFn, kdFn;
let messageReactive: MessageReactive | undefined = undefined

/**
 * Measure class
 */
export default class Measure {
    static LINE_MATERIAL = new THREE.LineBasicMaterial({
        color: 0xE63C17,
        linewidth: 2,
        opacity: 0.9,
        transparent: true,
        side: THREE.DoubleSide,
        depthWrite: false,
        depthTest: false
    });
    static MESH_MATERIAL = new THREE.MeshBasicMaterial({
        color: 0x87cefa,
        transparent: true,
        opacity: 0.7,
        side: THREE.DoubleSide,
        depthWrite: false,
        depthTest: false
    });
    static MAX_DISTANCE = 500; //当相交物体的距离太远时，忽略它
    static OBJ_NAME = "object_for_measure";
    static LABEL_NAME = "label_for_measure";

    public isCompleted = true; // 测量操作是否完成
    public isClose = true; // 测量操作是否已关闭(全销毁)
    protected mode: MeasureMode;
    protected domElement: HTMLCanvasElement;
    protected scene: THREE.Scene;
    protected camera: THREE.Camera;
    protected spriteMaterial?: THREE.SpriteMaterial;
    protected raycaster?: THREE.Raycaster;
    protected mouseMoved = false;
    protected polyline?: THREE.Line; // 用户在测量时绘制的线的当前实例
    protected faces?: THREE.Mesh; // 用于测量面积的当前实例
    protected curve?: THREE.Line; // 用弧线表示角度
    protected tempPointMarker?: THREE.Sprite; // 用于存储临时点
    protected tempLine?: THREE.Line; // 用于存储临时线条，用于在鼠标移动时绘制线条/区域/角度
    protected tempLabel?: CSS2DObject; // 用于在鼠标移动时存储临时标签,只有测量距离时才有
    protected pointArray: THREE.Vector3[] = []; // 存储点
    protected lastClickTime?: number; //保存上次点击时间，以便检测双击事件

    protected viewport;
    // 所有测绘内容组
    protected measureGroup: THREE.Group;
    // 当前测绘内容组
    protected group: THREE.Group;

    constructor(viewport, mode: MeasureMode = MeasureMode.Distance) {
        this.mode = mode;
        this.domElement = viewport.renderer.domElement;
        this.scene = viewport.sceneHelpers;
        this.camera = viewport.camera;
        this.viewport = viewport;

        // 初始化group
        this.measureGroup = new THREE.Group();
        this.measureGroup.name = `measure_group`;

        this.group = new THREE.Group();

        this.scene.add(this.measureGroup);
    }

    get canvas(): HTMLCanvasElement {
        return this.domElement as HTMLCanvasElement;
    }

    addEvent() {
        pdFn = this.mousedown.bind(this);
        this.canvas.addEventListener("pointerdown", pdFn);
        pmFn = this.mousemove.bind(this);
        this.canvas.addEventListener("pointermove", pmFn);
        puFn = this.mouseup.bind(this);
        this.canvas.addEventListener("pointerup", puFn);
        kdFn = this.keydown.bind(this);
        window.addEventListener("keydown", kdFn);
    }

    removeEvent() {
        this.canvas.removeEventListener("pointerdown", pdFn);
        pdFn = undefined;
        this.canvas.removeEventListener("pointermove", pmFn);
        pmFn = undefined;
        this.canvas.removeEventListener("pointerup", puFn);
        puFn = undefined;
        window.removeEventListener("keydown", kdFn);
        kdFn = undefined;
    }

    // 开始测量
    open() {
        messageReactive = window.$message?.info(t("prompt['Left click to confirm the drawing point, and right click to complete the drawing.']"),{
            duration: 0,
        })

        this.addEvent();

        if (this.isClose) {
            this.raycaster = new THREE.Raycaster();
        }

        // 重置
        this.group = new THREE.Group();
        this.group.name = `${Measure.OBJ_NAME}_group`;
        this.group.userData = {
            mode: this.mode
        }
        this.measureGroup.add(this.group);

        // 当次绘制点
        this.pointArray = [];

        // 测量距离、面积和角度需要折线
        this.polyline = this.createLine();
        this.group.add(this.polyline);

        if (this.mode === MeasureMode.Area) {
            this.faces = this.createFaces();
            this.group.add(this.faces);
        }
        this.isCompleted = false;
        this.isClose = false;
        this.domElement.style.cursor = "crosshair";

        // 禁用拖拽控制器
        this.viewport.modules.dragControl.dragControls.enabled = false;
    }

    // 重绘
    redraw(point: THREE.Sprite) {
        // 当次绘制点
        this.pointArray = [];

        (point.parent as THREE.Group).children.forEach(child => {
            switch (child.userData.type) {
                case "measure-marker":
                    // 当前点正在操作，不加入
                    if(child.uuid !== point.uuid) {
                        this.pointArray[child.userData.pointIndex] = child.userData.point;
                    }else{
                        this.tempPointMarker = child as THREE.Sprite;
                    }
                    break;
                case "line":
                    this.polyline = child as THREE.Line;
                    this.tempLine = this.createLine();
                    this.scene.add(this.tempLine);
                    break;
                case "faces":
                    this.faces = child as THREE.Mesh;
                    break;
                case "curve":
                    this.curve = child as THREE.Line;
                    break;
            }
        })

        // 重写move事件
        pmFn = this.redrawMousemove.bind(this);
        this.canvas.addEventListener("pointermove", pmFn);

        this.group = point.parent as THREE.Group;
        this.isCompleted = false;
        this.mode = this.group.userData.mode;
    }

    /**
     * 结束测量,清空所有结果
     */
    dispose() {
        this.removeEvent();

        this.clearTemp();

        this.measureGroup.children.forEach(g => {
            for (let i = g.children.length - 1; i >= 0; i--) {
                const c = g.children[i];

                if(c.userData.type == "measure-marker"){
                    // 从拖拽控制器移除
                    this.viewport.modules.dragControl.setDragObjects([c], "remove");
                }

                g.remove(c)
            }
        })
        this.measureGroup.remove(...this.measureGroup.children);
        this.polyline = undefined;
        this.faces = undefined;
        this.curve = undefined;

        this.pointArray = [];
        this.raycaster = undefined;

        this.domElement.style.cursor = "";

        this.isClose = true;

        useDispatchSignal("sceneGraphChanged")
    }

    /**
     * 初始化点标记材料
     */
    initPointMarkerMaterial() {
        const markerTexture = new THREE.TextureLoader().load("/static/images/logo/logo.png");
        this.spriteMaterial = new THREE.SpriteMaterial({
            map: markerTexture,
            depthTest: false,  // 深度测试
            depthWrite: false, // 深度写入
            sizeAttenuation: false,
            transparent: true,
            opacity: 0.9
        });
    }

    // 创建点标记
    createPointMarker(position?: THREE.Vector3): THREE.Sprite {
        if (!this.spriteMaterial) {
            this.initPointMarkerMaterial();
        }
        const p = position;
        const scale = 0.012;
        const obj = new THREE.Sprite(this.spriteMaterial);
        obj.scale.set(scale, scale, scale);
        if (p) {
            obj.position.set(p.x, p.y, p.z);
        }
        obj.name = Measure.OBJ_NAME;

        obj.userData = {
            mode: this.mode,
            type: "measure-marker",
        }
        return obj;
    }

    /**
     * Creates THREE.Line
     */
    private createLine(): THREE.Line {
        const geom = new THREE.BufferGeometry();
        const obj = new THREE.Line(geom, Measure.LINE_MATERIAL);
        obj.frustumCulled = false;
        obj.name = Measure.OBJ_NAME;
        obj.userData = {
            type: "line",
        }
        return obj;
    }

    /**
     * Creates THREE.Mesh
     */
    private createFaces() {
        const geom = new THREE.BufferGeometry();
        const obj = new THREE.Mesh(geom, Measure.MESH_MATERIAL);

        obj.frustumCulled = false;
        obj.name = Measure.OBJ_NAME;
        obj.userData = {
            // 将点存储到userData中
            vertices: [],
            type: "faces",
        }
        return obj;
    }

    // 清除临时信息
    clearTemp() {
        this.tempPointMarker && this.scene.remove(this.tempPointMarker);
        this.tempLine && this.scene.remove(this.tempLine);
        this.tempLabel && this.scene.remove(this.tempLabel);
        this.tempPointMarker = undefined;
        this.tempLine = undefined;
        this.tempLabel = undefined;
    }

    // 完成绘制，不清空结果
    complete() {
        if (this.isCompleted) return;

        useDispatchSignal("sceneGraphChanged")

        let clearPoints = false;
        let clearPolyline = false;
        // 为了测量面积，我们需要制作一个接近的表面，然后添加面积标签
        const count = this.pointArray.length;
        if (this.mode === MeasureMode.Area && this.polyline) {
            if (count > 2) {
                const p0 = this.pointArray[0];
                this.polyline.geometry.setFromPoints([...this.pointArray, p0]);
                // 计算面积
                const area = this.calculateArea(this.pointArray);
                const label = `${this.numberToString(area)} ${this.getUnitString()}`;
                const p = this.getBarycenter(this.pointArray);
                const labelObj = this.createLabel(label);
                labelObj.position.set(p.x, p.y, p.z);
                labelObj.element.innerHTML = label;
                this.group.add(labelObj);
            } else {
                clearPoints = true;
                clearPolyline = true;
            }
        }
        if (this.mode === MeasureMode.Distance) {
            if (count < 2) {
                clearPoints = true;
            }
        }
        if (this.mode === MeasureMode.Angle && this.polyline) {
            if (count >= 3) {
                const p0 = this.pointArray[0];
                const p1 = this.pointArray[1];
                const p2 = this.pointArray[2];
                const dir0 = new THREE.Vector3(p0.x - p1.x, p0.y - p1.y, p0.z - p1.z).normalize();
                const dir1 = this.getAngleBisector(p0, p1, p2);
                const dir2 = new THREE.Vector3(p2.x - p1.x, p2.y - p1.y, p2.z - p1.z).normalize();
                const angle = this.calculateAngle(p0, p1, p2);
                const label = `${this.numberToString(angle)} ${this.getUnitString()}`;
                const distance = Math.min(p0.distanceTo(p1), p2.distanceTo(p1));
                let d = distance * 0.3; // distance from label to p1
                let p = p1.clone().add(new THREE.Vector3(dir1.x * d, dir1.y * d, dir1.z * d)); // label's position
                const labelObj = this.createLabel(label);
                labelObj.position.set(p.x, p.y, p.z);
                labelObj.element.innerHTML = label;
                this.group.add(labelObj);

                d = distance * 0.2; // 弧到p1的距离
                p = p1.clone().add(new THREE.Vector3(dir1.x * d, dir1.y * d, dir1.z * d)); // 圆弧中间位置
                const arcP0 = p1.clone().add(new THREE.Vector3(dir0.x * d, dir0.y * d, dir0.z * d));
                const arcP2 = p1.clone().add(new THREE.Vector3(dir2.x * d, dir2.y * d, dir2.z * d));
                this.curve = this.createCurve(arcP0, p, arcP2);
                // 添加弧
                this.group.add(this.curve);
            } else {
                clearPoints = true;
                clearPolyline = true;
            }
        }
        // 无效的情况，清除此次的无用的对象
        if (clearPoints) {
            // 从this.measureGroup移除
            this.measureGroup.remove(this.group);
        }
        if (clearPolyline && this.polyline) {
            this.group.remove(this.polyline);
            this.polyline = undefined;
        }
        this.isCompleted = true;
        this.domElement.style.cursor = "";

        this.clearTemp();

        useDispatchSignal("sceneGraphChanged")

        if(messageReactive){
            messageReactive.destroy();
            messageReactive = undefined;
        }

        // 激活清除测量按钮
        if (!this.isClose && this.measureGroup.children.length > 0) {
            (<{ [key: string]: IPreviewOperation }>usePreviewOperationStore().menuList.measure.children).clearMeasure.disabled = false;
        }

        this.removeEvent();

        // 启用拖拽控制器
        this.viewport.modules.dragControl.dragControls.enabled = true;

        usePreviewOperationStore().menuList.measure.active = false;
    }

    // 清除当前group label
    clearCurrentLabel() {
        for (let i = this.group.children.length - 1; i >=0 ; i--) {
            const c = this.group.children[i];
            if(c.userData.type === "label"){
                this.group.remove(c);
            }
        }
    }

    // 获取按下对应三维位置
    getClosestIntersection(e: MouseEvent){
        const _point = new THREE.Vector2();
        _point.x = e.offsetX / this.viewport.renderer.domElement.offsetWidth;
        _point.y = e.offsetY / this.viewport.renderer.domElement.offsetHeight;

        const intersects = this.viewport.getIntersects(_point);
        if (intersects && intersects.length > 0) {
            if (intersects.length > 0 && intersects[0].distance < Measure.MAX_DISTANCE) {
                return intersects[0].point;
            }
        }
        return null;
    }

    // 重绘监听鼠标移动
    redrawMousemove(e: MouseEvent) {
        let point = this.getClosestIntersection(e);

        if (!point && this.tempPointMarker) {
            this.tempPointMarker.position.set(this.tempPointMarker.userData.point.x, this.tempPointMarker.userData.point.y, this.tempPointMarker.userData.point.z);
            return;
        }

        if (!point || !this.tempPointMarker) return;

        // 在鼠标移动时绘制临时点
        this.tempPointMarker.position.set(point.x, point.y, point.z);
        this.tempPointMarker.userData.point = point;

        // 当前点的索引
        const cIndex = this.tempPointMarker.userData.pointIndex;

        // 移动时绘制临时线
        if (this.pointArray.length > 0) {
            const line = this.tempLine || this.createLine();
            const geom = line.geometry;
            let startPoint = this.pointArray[cIndex + 1];
            let lastPoint = this.pointArray[cIndex - 1];

            // 如果是面积测量，且当前点是最后一个点或者第一个点
            // 则需要重置其中一个点，才能有两条线拖动效果
            if(this.mode === MeasureMode.Area){
                if(!lastPoint){
                    lastPoint = this.pointArray[this.pointArray.length - 1];
                }else if(!startPoint){
                    startPoint = this.pointArray[0];
                }
            }

            if (startPoint && lastPoint) {
                geom.setFromPoints([lastPoint, point, startPoint]);
            } else {
                geom.setFromPoints([startPoint || lastPoint, point]);
            }
        }
    }

    // 重绘完成
    redrawComplete() {
        if(!this.tempPointMarker) return;

        const point = this.tempPointMarker.userData.point;
        this.pointArray[this.tempPointMarker.userData.pointIndex] = point;
        const count = this.pointArray.length;

        if (this.polyline) {
            this.polyline.geometry.setFromPoints(this.pointArray);
            // 如果是距离测量，则清除group中已有的label，再重新创建
            if (this.mode === MeasureMode.Distance && count > 1) {
                this.clearCurrentLabel();
                // 绘制label
                for (let i = 0; i < count - 1; i++) {
                    const p0 = this.pointArray[i];
                    const p1 = this.pointArray[i + 1];
                    if(!p0 || !p1) continue;
                    const dist = p0.distanceTo(p1);
                    const label = `${this.numberToString(dist)} ${this.getUnitString()}`;
                    const position = new THREE.Vector3((p0.x + p1.x) / 2, (p0.y + p1.y) / 2, (p0.z + p1.z) / 2);
                    const labelObj = this.createLabel(label);
                    labelObj.position.set(position.x, position.y, position.z);
                    labelObj.element.innerHTML = label;
                    this.group.add(labelObj);
                }
            }
        }

        // 面积测量
        if (this.mode === MeasureMode.Area && this.faces) {
            const geom = this.faces.geometry as THREE.BufferGeometry;
            const vertices = this.faces.userData.vertices;
            // vertices.push(point);
            vertices[this.tempPointMarker.userData.pointIndex] = point;
            geom.setFromPoints(vertices);
            const len = vertices.length;
            if (len > 2) {
                const indexArray:number[] = [];
                for (let i = 1; i < len - 1; ++i) {
                    indexArray.push(0, i, i + 1);
                }
                geom.setIndex(indexArray);
                geom.computeVertexNormals();
            }

            // 移除原来的label,新的label会在complete中创建
            this.clearCurrentLabel();
        }

        // 角度测量
        if (this.mode === MeasureMode.Angle && this.curve) {
            // 清除弧跟原来的label 会在complete中创建
            this.group.remove(this.curve);
            this.clearCurrentLabel();
        }

        this.complete();
    }

    mousedown = () => {
        this.mouseMoved = false;
    };

    // 鼠标移动，创建对应的临时点与线
    mousemove = (e: MouseEvent) => {
        if(this.isCompleted) return;

        this.mouseMoved = true;

        const point = this.getClosestIntersection(e);
        if (!point) {
            return;
        }

        // 在鼠标移动时绘制临时点
        if (this.tempPointMarker) {
            this.tempPointMarker.position.set(point.x, point.y, point.z);
        } else {
            this.tempPointMarker = this.createPointMarker(point);
            this.scene.add(this.tempPointMarker);
        }

        // 移动时绘制临时线
        if (this.pointArray.length > 0) {
            const p0 = this.pointArray[this.pointArray.length - 1]; // 获取最后一个点
            const line = this.tempLine || this.createLine();
            const geom = line.geometry;
            const startPoint = this.pointArray[0];
            const lastPoint = this.pointArray[this.pointArray.length - 1];
            if (this.mode === MeasureMode.Area) {
                geom.setFromPoints([lastPoint, point, startPoint]);
            } else {
                geom.setFromPoints([lastPoint, point]);
            }
            if (this.mode === MeasureMode.Distance) {
                const dist = p0.distanceTo(point);
                const label = `${this.numberToString(dist)} ${this.getUnitString()}`;
                const position = new THREE.Vector3((point.x + p0.x) / 2, (point.y + p0.y) / 2, (point.z + p0.z) / 2);
                this.addOrUpdateTempLabel(label, position);
            }
            // tempLine 只需添加到场景一次
            if (!this.tempLine) {
                this.scene.add(line);
                this.tempLine = line;
            }
        }

        useDispatchSignal("sceneGraphChanged")
    };

    mouseup = (e: MouseEvent) => {
        // 如果mouseMoved是true，那么它可能在移动，而不是点击
        if (!this.mouseMoved) {
            // 右键点击表示完成绘图操作
            if (e.button === 2) {
                this.complete();
            } else if (e.button === 0) { // 左键点击表示添加点
                this.onMouseClicked(e);
            }
        }
    };

    onMouseClicked = (e: MouseEvent) => {
        if (!this.raycaster || !this.camera || !this.scene || this.isCompleted) {
            return;
        }

        const point =this.getClosestIntersection(e);
        if (!point) {
            return;
        }

        // 双击触发两次点击事件，我们需要避免这里的第二次点击
        const now = Date.now();
        if (this.lastClickTime && (now - this.lastClickTime < 100)) return;

        this.lastClickTime = now;

        this.pointArray.push(point);
        const count = this.pointArray.length;
        const marker = this.createPointMarker(point);
        marker.userData.point = point;
        marker.userData.pointIndex = count - 1;
        this.group.add(marker);
        // 把点加入拖拽控制器
        this.viewport.modules.dragControl.setDragObjects([marker], "push");

        if (this.polyline) {
            this.polyline.geometry.setFromPoints(this.pointArray);
            if (this.tempLabel && count > 1) {
                const p0 = this.pointArray[count - 2];
                this.tempLabel.position.set((p0.x + point.x) / 2, (p0.y + point.y) / 2, (p0.z + point.z) / 2);
                this.group.add(this.tempLabel);

                // 创建距离测量线时，此处的 临时label 将作为正式的使用，不在this.clearTemp()中清除，故置为undefined
                this.tempLabel = undefined;
            }
        }
        if (this.mode === MeasureMode.Area && this.faces) {
            const geom = this.faces.geometry as THREE.BufferGeometry;
            const vertices = this.faces.userData.vertices;
            vertices.push(point);
            geom.setFromPoints(vertices);
            const len = vertices.length;
            if (len > 2) {
                const indexArray:number[] = [];
                for (let i = 1; i < len - 1; ++i) {
                    indexArray.push(0, i, i + 1);
                }
                geom.setIndex(indexArray);
                geom.computeVertexNormals();
            }
        }
        // 创建角度测量时，三个点完成
        if (this.mode === MeasureMode.Angle && this.pointArray.length % 3 === 0) {
            this.complete();
        }
    };

    keydown = (e: KeyboardEvent) => {
        if (e.key === "Enter") {
            this.complete();
        }
    };

    /**
     * 添加或更新临时标签和位置
     */
    addOrUpdateTempLabel(label: string, position: THREE.Vector3) {
        if (!this.tempLabel) {
            this.tempLabel = this.createLabel(label);
            this.scene.add(this.tempLabel);
        }
        this.tempLabel.position.set(position.x, position.y, position.z);
        this.tempLabel.element.innerHTML = label;
    }

    /**
     * 创建标签
     */
    createLabel(text: string): CSS2DObject {
        const div = document.createElement("div");
        div.className = 'css2dObjectLabel';
        div.innerHTML = text;
        div.style.padding = "5px 8px";
        div.style.color = "#fff";
        div.style.fontSize = "14px";
        div.style.position = "absolute";
        div.style.backgroundColor = "rgba(25, 25, 25, 0.3)";
        div.style.borderRadius = "12px";
        div.style.top = "0px";
        div.style.left = "0px";
        // div.style.pointerEvents = 'none' //避免HTML元素影响场景的鼠标事件
        const obj = new CSS2DObject(div);
        obj.name = Measure.LABEL_NAME;
        obj.userData = {
            type: "label"
        }
        return obj;
    }

    /**
     * 创建圆弧曲线以表示角度
     */
    createCurve(p0: THREE.Vector3, p1: THREE.Vector3, p2: THREE.Vector3) {
        const curve = new THREE.QuadraticBezierCurve3(p0, p1, p2);
        const points = curve.getPoints(4);
        const geometry = new THREE.BufferGeometry().setFromPoints(points);
        const obj = new THREE.Line(geometry, Measure.LINE_MATERIAL);
        obj.name = Measure.OBJ_NAME;
        obj.userData = {
            type: "curve"
        }
        return obj;
    }

    /**
     * 计算区域
     * TODO: 对于凹多边形，数值不对，需要修正
     * @param points
     */
    calculateArea(points: THREE.Vector3[]) {
        let area = 0;
        for (let i = 0, j = 1, k = 2; k < points.length; j++, k++) {
            const a = points[i].distanceTo(points[j]);
            const b = points[j].distanceTo(points[k]);
            const c = points[k].distanceTo(points[i]);
            const p = (a + b + c) / 2;
            area += Math.sqrt(p * (p - a) * (p - b) * (p - c));
        }
        return area;
    }

    /**
     * 以度表示两条直线的夹角
     */
    calculateAngle(startPoint: THREE.Vector3, middlePoint: THREE.Vector3, endPoint: THREE.Vector3) {
        const p0 = startPoint;
        const p1 = middlePoint;
        const p2 = endPoint;
        const dir0 = new THREE.Vector3(p0.x - p1.x, p0.y - p1.y, p0.z - p1.z);
        const dir1 = new THREE.Vector3(p2.x - p1.x, p2.y - p1.y, p2.z - p1.z);
        const angle = dir0.angleTo(dir1);
        return angle * 180 / Math.PI; // convert to degree
    }

    /**
     * 获取两条线的角平分线
     */
    getAngleBisector(startPoint: THREE.Vector3, middlePoint: THREE.Vector3, endPoint: THREE.Vector3): THREE.Vector3 {
        const p0 = startPoint;
        const p1 = middlePoint;
        const p2 = endPoint;
        const dir0 = new THREE.Vector3(p0.x - p1.x, p0.y - p1.y, p0.z - p1.z).normalize();
        const dir2 = new THREE.Vector3(p2.x - p1.x, p2.y - p1.y, p2.z - p1.z).normalize();
        return new THREE.Vector3(dir0.x + dir2.x, dir0.y + dir2.y, dir0.z + dir2.z).normalize(); // the middle direction between dir0 and dir2
    }

    /**
     * 得到点的重心
     */
    getBarycenter(points: THREE.Vector3[]): THREE.Vector3 {
        const l = points.length;
        let x = 0;
        let y = 0;
        let z = 0;
        points.forEach(p => {
            x += p.x;
            y += p.y;
            z += p.z
        });
        return new THREE.Vector3(x / l, y / l, z / l);
    }

    /**
     * 获取距离、面积或角度的单位字符串
     */
    getUnitString() {
        if (this.mode === MeasureMode.Distance) return "m";
        if (this.mode === MeasureMode.Area) return "m²";
        if (this.mode === MeasureMode.Angle) return "°";
        return "";
    }

    /**
     * 将数字转换为具有适当分数数字的字符串
     */
    numberToString(num: number) {
        if (num < 0.0001) {
            return num.toString();
        }
        let fractionDigits = 2;
        if (num < 0.01) {
            fractionDigits = 4;
        } else if (num < 0.1) {
            fractionDigits = 3;
        }
        return num.toFixed(fractionDigits);
    }
}