Browse Source

feat: 开始添加cad开发文件

xushiting 2 years ago
parent
commit
b5d6fc5ff1
52 changed files with 15356 additions and 0 deletions
  1. 17 0
      src/views/draw-file/board/editCAD/Constant.js
  2. 243 0
      src/views/draw-file/board/editCAD/Controls/AddWall.js
  3. 166 0
      src/views/draw-file/board/editCAD/Controls/MoveComponent.js
  4. 181 0
      src/views/draw-file/board/editCAD/Controls/MoveSymbol.js
  5. 15 0
      src/views/draw-file/board/editCAD/Controls/MoveTag.js
  6. 1153 0
      src/views/draw-file/board/editCAD/Controls/MoveWall.js
  7. 784 0
      src/views/draw-file/board/editCAD/Controls/UIControl.js
  8. 130 0
      src/views/draw-file/board/editCAD/Coordinate.js
  9. 162 0
      src/views/draw-file/board/editCAD/Geometry/BayWindow.js
  10. 76 0
      src/views/draw-file/board/editCAD/Geometry/Beam.js
  11. 470 0
      src/views/draw-file/board/editCAD/Geometry/Corridor.js
  12. 137 0
      src/views/draw-file/board/editCAD/Geometry/DoubleDoor.js
  13. 133 0
      src/views/draw-file/board/editCAD/Geometry/Flue.js
  14. 72 0
      src/views/draw-file/board/editCAD/Geometry/FrenchWindow.js
  15. 72 0
      src/views/draw-file/board/editCAD/Geometry/Furniture.js
  16. 0 0
      src/views/draw-file/board/editCAD/Geometry/Geometry.js
  17. 27 0
      src/views/draw-file/board/editCAD/Geometry/Line.js
  18. 71 0
      src/views/draw-file/board/editCAD/Geometry/Pass.js
  19. 23 0
      src/views/draw-file/board/editCAD/Geometry/Point.js
  20. 94 0
      src/views/draw-file/board/editCAD/Geometry/SingleDoor.js
  21. 61 0
      src/views/draw-file/board/editCAD/Geometry/SingleWindow.js
  22. 94 0
      src/views/draw-file/board/editCAD/Geometry/SlideDoor.js
  23. 108 0
      src/views/draw-file/board/editCAD/Geometry/Tag.js
  24. 53 0
      src/views/draw-file/board/editCAD/Geometry/Wall.js
  25. 334 0
      src/views/draw-file/board/editCAD/History/Change.js
  26. 429 0
      src/views/draw-file/board/editCAD/History/History.js
  27. 201 0
      src/views/draw-file/board/editCAD/History/HistoryUtil.js
  28. 796 0
      src/views/draw-file/board/editCAD/Layer.js
  29. 505 0
      src/views/draw-file/board/editCAD/ListenLayer.js
  30. 63 0
      src/views/draw-file/board/editCAD/Load.js
  31. 678 0
      src/views/draw-file/board/editCAD/MathUtil.js
  32. 4127 0
      src/views/draw-file/board/editCAD/Renderer/Draw.js
  33. 364 0
      src/views/draw-file/board/editCAD/Renderer/Render.js
  34. 130 0
      src/views/draw-file/board/editCAD/Service/AnalyService.js
  35. 25 0
      src/views/draw-file/board/editCAD/Service/CompassService.js
  36. 55 0
      src/views/draw-file/board/editCAD/Service/ComponentService.js
  37. 243 0
      src/views/draw-file/board/editCAD/Service/ElementService.js
  38. 523 0
      src/views/draw-file/board/editCAD/Service/FloorplanService.js
  39. 170 0
      src/views/draw-file/board/editCAD/Service/FurnitureService.js
  40. 75 0
      src/views/draw-file/board/editCAD/Service/HistoryService.js
  41. 96 0
      src/views/draw-file/board/editCAD/Service/StateService.js
  42. 928 0
      src/views/draw-file/board/editCAD/Service/SymbolService.js
  43. 76 0
      src/views/draw-file/board/editCAD/Service/TagService.js
  44. 650 0
      src/views/draw-file/board/editCAD/Service/WallService.js
  45. 329 0
      src/views/draw-file/board/editCAD/Style.js
  46. 11 0
      src/views/draw-file/board/editCAD/enum/ElementEvents.js
  47. 28 0
      src/views/draw-file/board/editCAD/enum/HistoryEvents.js
  48. 36 0
      src/views/draw-file/board/editCAD/enum/LayerEvents.js
  49. 25 0
      src/views/draw-file/board/editCAD/enum/SelectState.js
  50. 5 0
      src/views/draw-file/board/editCAD/enum/SymbolEvents.js
  51. 66 0
      src/views/draw-file/board/editCAD/enum/UIEvents.js
  52. 46 0
      src/views/draw-file/board/editCAD/enum/VectorType.js

+ 17 - 0
src/views/draw-file/board/editCAD/Constant.js

@@ -0,0 +1,17 @@
+const Constant = {
+    /*
+        最小距离
+        1.合并
+        2.拖拽
+    */
+    minPixLen: 3,
+    minScreenDis: 2, //layer.js里,判断是否拖拽了,目前暂时不用
+    minRealDis: 0.1,
+    minAdsorb: 0.1,
+    minAngle: 10,
+    maxAngle: 170,
+    defaultZoom: 100,
+    minSymbolLen: 0.2,
+    ratio: 3, //1,
+}
+export default Constant

+ 243 - 0
src/views/draw-file/board/editCAD/Controls/AddWall.js

@@ -0,0 +1,243 @@
+import { listenLayer } from '../ListenLayer'
+import Constant from '../Constant'
+import { mathUtil } from '../MathUtil'
+import { floorplanService } from '../Service/FloorplanService'
+import { elementService } from '../Service/ElementService'
+import { wallService } from '../Service/WallService'
+import { stateService } from '../Service/StateService'
+import { symbolService } from '../Service/SymbolService'
+import VectorType from '../enum/VectorType'
+
+export default class AddWall {
+    constructor() {
+        this.startInfo = {}
+        this.endInfo = {}
+        this.canAdd = false
+    }
+
+    setPointInfo(dir, pointInfo) {
+        if (dir == 'start') {
+            this.startInfo = {
+                position: {
+                    x: pointInfo.x,
+                    y: pointInfo.y,
+                },
+                linkedPointId: pointInfo.linkedPointId,
+                linkedWallId: pointInfo.linkedWallId,
+            }
+        } else if (dir == 'end') {
+            this.endInfo = {
+                position: {
+                    x: pointInfo.x,
+                    y: pointInfo.y,
+                },
+                linkedPointId: pointInfo.linkedPointId,
+                linkedWallId: pointInfo.linkedWallId,
+            }
+        }
+    }
+
+    //inoutSide表示内墙或者外墙
+    buildWall(inoutSide) {
+        console.log('添加新墙!')
+
+        let joinInfos = this.getJoinsForWalls()
+        let splitPointIds = this.splitAllJoins(joinInfos)
+        this.creatNewWalls(splitPointIds, inoutSide)
+        this.canAdd = false
+        this.updateStart(this.endInfo.position, splitPointIds[splitPointIds.length - 1])
+        listenLayer.clear()
+    }
+
+    //开始新建墙,可能是多个
+    creatNewWalls(splitPointIds, inoutSide) {
+        for (let i = 0; i < splitPointIds.length - 1; ++i) {
+            let pointId1 = splitPointIds[i]
+            let pointId2 = splitPointIds[i + 1]
+            let wallId = wallService.getWallId(pointId1, pointId2)
+            if (!wallId) {
+                let wall = wallService.createWall(pointId1, pointId2)
+                wall.setOut(inoutSide)
+            }
+        }
+    }
+
+    canAddWallForEnd(endPt) {
+        if (listenLayer.modifyPoint) {
+            if (mathUtil.getDistance(this.startInfo.position, listenLayer.modifyPoint) < Constant.minAdsorb) {
+                return false
+            }
+        } else {
+            if (mathUtil.getDistance(this.startInfo.position, endPt) < Constant.minAdsorb) {
+                return false
+            }
+        }
+
+        //是否与symbol相交
+        if (listenLayer.symbolInfo.symbolId) {
+            return false
+        } else {
+            const symbols = floorplanService.getSymbols()
+            for (let key in symbols) {
+                let symbol = symbols[key]
+                if (symbol.geoType == VectorType.Pass) {
+                    continue
+                }
+                let join = mathUtil.getIntersectionPoint3(symbol.startPoint, symbol.endPoint, this.startInfo.position, endPt)
+                if (join != null) {
+                    return false
+                }
+            }
+        }
+
+        return true
+    }
+
+    getJoinsForWalls() {
+        let result = []
+
+        const walls = floorplanService.getWalls()
+        let hasComputerPointIds = []
+        let hasExitPointIds = []
+
+        if (this.startInfo.linkedPointId) {
+            hasComputerPointIds.push(this.startInfo.linkedPointId)
+            hasExitPointIds.push(this.startInfo.linkedPointId)
+            result.push({ join: { x: this.startInfo.position.x, y: this.startInfo.position.y }, pointId: this.startInfo.linkedPointId })
+        } else if (this.startInfo.linkedWallId) {
+            result.push({ join: { x: this.startInfo.position.x, y: this.startInfo.position.y }, wallId: this.startInfo.linkedWallId })
+        } else {
+            result.push({ join: { x: this.startInfo.position.x, y: this.startInfo.position.y } })
+        }
+
+        if (this.endInfo.linkedPointId) {
+            hasComputerPointIds.push(this.endInfo.linkedPointId)
+            hasExitPointIds.push(this.endInfo.linkedPointId)
+            result.push({ join: { x: this.endInfo.position.x, y: this.endInfo.position.y }, pointId: this.endInfo.linkedPointId })
+        } else if (this.endInfo.linkedWallId) {
+            result.push({ join: { x: this.endInfo.position.x, y: this.endInfo.position.y }, wallId: this.endInfo.linkedWallId })
+        } else {
+            result.push({ join: { x: this.endInfo.position.x, y: this.endInfo.position.y } })
+        }
+
+        const line = mathUtil.createLine1(this.startInfo.position, this.endInfo.position)
+        for (let key in walls) {
+            if (this.startInfo.linkedWallId && this.startInfo.linkedWallId == key) {
+                continue
+            } else if (this.endInfo.linkedWallId && this.endInfo.linkedWallId == key) {
+                continue
+            }
+
+            let wall = walls[key]
+            if (hasExitPointIds.indexOf(wall.start) > -1 || hasExitPointIds.indexOf(wall.end) > -1) {
+                continue
+            }
+
+            let startPoint = floorplanService.getPoint(wall.start)
+            let endPoint = floorplanService.getPoint(wall.end)
+            let flag = false
+
+            if (hasComputerPointIds.indexOf(wall.start) < 0) {
+                hasComputerPointIds.push(wall.start)
+                const startJoin = mathUtil.getJoinLinePoint(startPoint, line)
+                if (mathUtil.PointInSegment(startJoin, this.startInfo.position, this.endInfo.position, Constant.minAdsorb) && mathUtil.getDistance(startPoint, startJoin) < Constant.minAdsorb) {
+                    result.push({ join: { x: startJoin.x, y: startJoin.y }, pointId: wall.start })
+                    flag = true
+
+                    hasExitPointIds.push(wall.start)
+                }
+            }
+
+            if (hasComputerPointIds.indexOf(wall.end) < 0) {
+                hasComputerPointIds.push(wall.end)
+                const endJoin = mathUtil.getJoinLinePoint(endPoint, line)
+                if (mathUtil.PointInSegment(endJoin, this.startInfo.position, this.endInfo.position, Constant.minAdsorb) && mathUtil.getDistance(endPoint, endJoin) < Constant.minAdsorb) {
+                    result.push({ join: { x: endJoin.x, y: endJoin.y }, pointId: wall.end })
+                    flag = true
+
+                    hasExitPointIds.push(wall.end)
+                }
+            }
+
+            if (!flag) {
+                //不与墙key的端点相交
+                if (hasExitPointIds.indexOf(wall.start) < 0 && hasExitPointIds.indexOf(wall.end) < 0) {
+                    let join = mathUtil.getIntersectionPoint3(startPoint, endPoint, this.startInfo.position, this.endInfo.position)
+                    if (join) {
+                        result.push({ join: { x: join.x, y: join.y }, wallId: key })
+                    }
+                }
+            }
+        }
+        return result
+    }
+
+    splitAllJoins(joinInfos) {
+        // 对joinInfos要进行排序
+        joinInfos = joinInfos.sort(sortNumber.bind(this))
+        function sortNumber(a, b) {
+            return mathUtil.getDistance(this.startInfo.position, a.join) - mathUtil.getDistance(this.startInfo.position, b.join)
+        }
+
+        const splitPointIds = []
+        for (let i = 0; i < joinInfos.length; ++i) {
+            const info = joinInfos[i]
+            const join = info.join
+            const wallId = info.wallId
+            const pointId = info.pointId
+
+            if (pointId) {
+                splitPointIds.push(pointId)
+            } else if (wallId) {
+                // 拆分wallId
+                const splitPoint = wallService.createPoint(join.x, join.y)
+                const splitPointId = splitPoint.vectorId
+
+                //可能joinInfos的两个点都在wallId上
+                let newWallId = null
+                if (joinInfos[i + 1] && joinInfos[i].wallId == joinInfos[i + 1].wallId) {
+                    let wall = floorplanService.getWall(wallId)
+                    let startPoint = floorplanService.getPoint(wall.start)
+                    if (mathUtil.getDistance(startPoint, joinInfos[i].join) < mathUtil.getDistance(startPoint, joinInfos[i + 1].join)) {
+                        newWallId = wallService.splitWall(wallId, splitPointId, 'end')
+                    } else {
+                        newWallId = wallService.splitWall(wallId, splitPointId, 'start')
+                    }
+                } else {
+                    newWallId = wallService.splitWall(wallId, splitPointId, 'start')
+                }
+
+                if (newWallId == null) {
+                    floorplanService.deletePoint(splitPointId)
+                    continue
+                }
+                symbolService.reBelongForSplitWall(wallId, wallId, newWallId)
+                splitPointIds.push(splitPointId)
+            }
+            //首尾没有吸附的情况
+            else {
+                const splitPoint = wallService.createPoint(join.x, join.y)
+                splitPointIds.push(splitPoint.vectorId)
+            }
+        }
+
+        return splitPointIds
+    }
+
+    updateStart(position, linkedPointId) {
+        mathUtil.clonePoint(this.startInfo.position, position)
+        this.startInfo.linkedPointId = linkedPointId
+        elementService.setNewWallStartPosition(this.startInfo.position)
+    }
+
+    clear() {
+        this.startInfo = {}
+        this.endInfo = {}
+        this.canAdd = false
+        elementService.hideNewWall()
+        elementService.hideStartAddWall()
+    }
+}
+
+const addWall = new AddWall()
+export { addWall }

+ 166 - 0
src/views/draw-file/board/editCAD/Controls/MoveComponent.js

@@ -0,0 +1,166 @@
+import { floorplanService } from '../Service/FloorplanService'
+import { mathUtil } from '../MathUtil.js'
+import Constant from '../Constant'
+
+export default class MoveComponent {
+    constructor() {}
+
+    moveFullComponent(position, componentId) {
+        let component = floorplanService.getComponent(componentId)
+        mathUtil.clonePoint(component.center, position)
+        const flag = this.getAdsorbInfo(component)
+
+        //未吸附
+        if (!flag) {
+            component.setPoints2d()
+        }
+        return flag
+    }
+
+    getAdsorbInfo(component) {
+        const midPoints = this.getMidPointsEdge(component)
+        const mins = this.getNearestPoints(midPoints, component.center)
+        let info = this.isAdsorb(mins.min0, midPoints[0], component.center)
+        if (info != null) {
+            component.center.x += info.dx
+            component.center.y += info.dy
+            component.setPoints2d()
+            return true
+        } else {
+            info = this.isAdsorb(mins.min1, midPoints[1], component.center)
+            if (info != null) {
+                component.center.x += info.dx
+                component.center.y += info.dy
+                component.setPoints2d()
+                return true
+            } else {
+                info = this.isAdsorb(mins.min2, midPoints[2], component.center)
+                if (info != null) {
+                    component.center.x += info.dx
+                    component.center.y += info.dy
+                    component.setPoints2d()
+                    return true
+                } else {
+                    info = this.isAdsorb(mins.min3, midPoints[3], component.center)
+                    if (info != null) {
+                        component.center.x += info.dx
+                        component.center.y += info.dy
+                        component.setPoints2d()
+                        return true
+                    }
+                }
+            }
+        }
+        return false
+    }
+
+    //获取上下左右四个点的坐标
+    getMidPointsEdge(component) {
+        let midPoints = []
+        midPoints.push({
+            x: (component.points2d[0].x + component.points2d[1].x) / 2,
+            y: (component.points2d[0].y + component.points2d[1].y) / 2,
+        })
+
+        midPoints.push({
+            x: (component.points2d[1].x + component.points2d[2].x) / 2,
+            y: (component.points2d[1].y + component.points2d[2].y) / 2,
+        })
+
+        midPoints.push({
+            x: (component.points2d[2].x + component.points2d[3].x) / 2,
+            y: (component.points2d[2].y + component.points2d[3].y) / 2,
+        })
+
+        midPoints.push({
+            x: (component.points2d[3].x + component.points2d[0].x) / 2,
+            y: (component.points2d[3].y + component.points2d[0].y) / 2,
+        })
+        return midPoints
+    }
+
+    getNearestPoints(midPoints, center) {
+        const walls = floorplanService.getWalls()
+        const line1 = mathUtil.createLine1(midPoints[0], midPoints[2])
+        const line2 = mathUtil.createLine1(midPoints[1], midPoints[3])
+
+        let min0 = null
+        let min1 = null
+        let min2 = null
+        let min3 = null
+
+        for (let key in walls) {
+            const wall = walls[key]
+            const startPoint = floorplanService.getPoint(wall.start)
+            const endPoint = floorplanService.getPoint(wall.end)
+
+            let join1 = mathUtil.getIntersectionPoint4(startPoint, endPoint, line1)
+            if (join1 != null) {
+                if (mathUtil.isContainForSegment(midPoints[0], join1, center)) {
+                    if (min0 == null || mathUtil.getDistance(midPoints[0], min0.position) > mathUtil.getDistance(midPoints[0], join1)) {
+                        min0 = {
+                            position: join1,
+                            wallId: key,
+                        }
+                    }
+                } else if (mathUtil.isContainForSegment(midPoints[2], join1, center)) {
+                    if (min2 == null || mathUtil.getDistance(midPoints[2], min2.position) > mathUtil.getDistance(midPoints[2], join1)) {
+                        min2 = {
+                            position: join1,
+                            wallId: key,
+                        }
+                    }
+                }
+            }
+
+            let join2 = mathUtil.getIntersectionPoint4(startPoint, endPoint, line2)
+            if (join2 != null) {
+                if (mathUtil.isContainForSegment(midPoints[1], join2, center)) {
+                    if (min1 == null || mathUtil.getDistance(midPoints[1], min1.position) > mathUtil.getDistance(midPoints[1], join2)) {
+                        min1 = {
+                            position: join2,
+                            wallId: key,
+                        }
+                    }
+                } else if (mathUtil.isContainForSegment(midPoints[3], join2, center)) {
+                    if (min3 == null || mathUtil.getDistance(midPoints[3], min3.position) > mathUtil.getDistance(midPoints[3], join2)) {
+                        min3 = {
+                            position: join2,
+                            wallId: key,
+                        }
+                    }
+                }
+            }
+        }
+
+        return {
+            min0: min0,
+            min1: min1,
+            min2: min2,
+            min3: min3,
+        }
+    }
+
+    isAdsorb(min, mid, center) {
+        if (min == null) {
+            return null
+        }
+        const wall = floorplanService.getWall(min.wallId)
+        const startPoint = floorplanService.getPoint(wall.start)
+        const endPoint = floorplanService.getPoint(wall.end)
+        const angle = mathUtil.Angle(min.position, center, startPoint)
+        //吸附
+        if (Math.abs(angle - Math.PI / 2) < 0.1 && mathUtil.getDistance(min.position, mid) < Constant.minAdsorb) {
+            let dx = min.position.x - mid.x
+            let dy = min.position.y - mid.y
+            return {
+                dx: dx,
+                dy: dy,
+            }
+        }
+        return null
+    }
+}
+
+const moveComponent = new MoveComponent()
+export { moveComponent }

+ 181 - 0
src/views/draw-file/board/editCAD/Controls/MoveSymbol.js

@@ -0,0 +1,181 @@
+import { stateService } from '../Service/StateService'
+import { symbolService } from '../Service/SymbolService'
+import { floorplanService } from '../Service/FloorplanService'
+import { wallService } from '../Service/WallService.js'
+import { mathUtil } from '../MathUtil.js'
+import { coordinate } from '../Coordinate'
+import Constant from '../Constant'
+import SelectState from '../enum/SelectState'
+
+export default class MoveSymbol {
+    constructor() {
+        this.symbol = null
+    }
+
+    //拖拽symbol
+    moveFullSymbol(point, symbolId, nearestWallId) {
+        const symbol = floorplanService.getSymbol(symbolId)
+        const wall = floorplanService.getWall(nearestWallId)
+        if (!wall) {
+            return null
+        }
+        const wallLine = wallService.getLine(wall)
+        const vSymbolLine = mathUtil.getVerticalLine(wallLine, point)
+        let distance = symbol.len
+        if (distance == null) {
+            distance = mathUtil.getDistance(symbol.startPoint, symbol.endPoint)
+        }
+        /*
+        const twoParallels = mathUtil.getParallelLineForDistance(vSymbolLine, distance / 2)
+        let point1 = mathUtil.getIntersectionPoint(twoParallels.line1, wallLine)
+        let point2 = mathUtil.getIntersectionPoint(twoParallels.line2, wallLine)
+
+        //墙比较短
+        if (mathUtil.getDistance(point1, point2) < Constant.minSymbolLen) {
+            return null
+        }
+        //调整
+        const startPoint = floorplanService.getPoint(wall.start)
+        const endPoint = floorplanService.getPoint(wall.end)
+        let dx, dy
+
+        let _point1 = {}
+        let _point2 = {}
+        if (!wallService.isContain(wall, point1)) {
+            dx = startPoint.x - point1.x
+            dy = startPoint.y - point1.y
+            _point2.x = point2.x + dx
+            _point2.y = point2.y + dy
+            if (!wallService.isContain(wall, _point2)) {
+                dx = endPoint.x - point1.x
+                dy = endPoint.y - point1.y
+
+                point2.x += dx
+                point2.y += dy
+                mathUtil.clonePoint(point1, endPoint)
+            } else {
+                point2.x += dx
+                point2.y += dy
+                mathUtil.clonePoint(point1, startPoint)
+            }
+        } else if (!wallService.isContain(wall, point2)) {
+            dx = startPoint.x - point2.x
+            dy = startPoint.y - point2.y
+            _point1.x = point1.x + dx
+            _point1.y = point1.y + dy
+            if (!wallService.isContain(wall, _point1)) {
+                dx = endPoint.x - point2.x
+                dy = endPoint.y - point2.y
+
+                point1.x += dx
+                point1.y += dy
+                mathUtil.clonePoint(point2, endPoint)
+            } else {
+                point1.x += dx
+                point1.y += dy
+                mathUtil.clonePoint(point2, startPoint)
+            }
+        }
+        const newPositions = symbolService.getNewForContainSymbols(point1, point2, nearestWallId, symbolId)
+        */
+        let _point = mathUtil.getIntersectionPoint(vSymbolLine, wallLine)
+        const newPositions = symbolService.getNewPosForSymbol(_point, nearestWallId, symbolId)
+        // // 和其他symbol相交
+        // if (newPositions == null) {
+        //     return null
+        // } else if (newPositions.collision) {
+        //     mathUtil.clonePoint(point1, newPositions.position1)
+        //     mathUtil.clonePoint(point2, newPositions.position2)
+        // }
+        if (newPositions != null && newPositions.state) {
+            let dir = mathUtil.dotPoints(symbol.startPoint, symbol.endPoint, newPositions.position1, newPositions.position2)
+            if (dir > 0) {
+                mathUtil.clonePoint(symbol.startPoint, newPositions.position1)
+                mathUtil.clonePoint(symbol.endPoint, newPositions.position2)
+            } else {
+                mathUtil.clonePoint(symbol.endPoint, newPositions.position1)
+                mathUtil.clonePoint(symbol.startPoint, newPositions.position2)
+            }
+
+            //换墙
+            if (symbol.parent != nearestWallId) {
+                symbolService.changeSymbolForBelong(symbolId, nearestWallId)
+            }
+
+            symbol.setOpenSide(point)
+            symbol.setPoints2d()
+        }
+
+        // if (mathUtil.getDistance(point1, symbol.startPoint) < mathUtil.getDistance(point1, symbol.endPoint)) {
+        //     symbol.setSymbolPosition(point1, 'start')
+        //     symbol.setSymbolPosition(point2, 'end')
+        // } else {
+        //     symbol.setSymbolPosition(point2, 'start')
+        //     symbol.setSymbolPosition(point1, 'end')
+        // }
+    }
+
+    // 拖拽symbol的端点
+    moveSymbolPoint(targetPosition, symbolId, selectState) {
+        const newInfo = symbolService.moveSymbolSinglePoint(targetPosition, symbolId, selectState)
+        // symbol的start和end位置交换了
+        if (newInfo == null) {
+            return null
+        }
+        const symbol = floorplanService.getSymbol(symbolId)
+        const midPoint = {
+            x: (symbol.startPoint.x + symbol.endPoint.x) / 2,
+            y: (symbol.startPoint.y + symbol.endPoint.y) / 2,
+        }
+        const distance = mathUtil.getDistance(midPoint, newInfo.position)
+        // 太短了
+        if (distance < Constant.minSymbolLen) {
+            return null
+        }
+
+        const wall = floorplanService.getWall(symbol.parent)
+        const startPoint = floorplanService.getPoint(wall.start)
+        const endPoint = floorplanService.getPoint(wall.end)
+
+        if (selectState == SelectState.Start) {
+            // 与其他symbol重合
+            const newPositions = symbolService.getNewForContainSymbols(symbol.endPoint, newInfo.position, symbol.parent, symbolId)
+            if (newPositions == null || newPositions.collision) {
+                return null
+            }
+
+            // 在wall内
+            if (wallService.isContain(wall, newInfo.position)) {
+                symbolService.setPosition(symbol, newInfo.position, 'start')
+            }
+            // 离wall的start近还是end近
+            else {
+                if (mathUtil.getDistance(symbol.startPoint, startPoint) < mathUtil.getDistance(symbol.startPoint, endPoint)) {
+                    symbolService.setPosition(symbol, startPoint, 'start')
+                } else {
+                    symbolService.setPosition(symbol, endPoint, 'start')
+                }
+            }
+        } else {
+            // 与其他symbol重合
+            const newPositions = symbolService.getNewForContainSymbols(symbol.startPoint, newInfo.position, symbol.parent, symbolId)
+            if (newPositions == null || newPositions.collision) {
+                return null
+            }
+
+            if (wallService.isContain(wall, newInfo.position)) {
+                symbolService.setPosition(symbol, newInfo.position, 'end')
+            } else {
+                if (mathUtil.getDistance(symbol.endPoint, startPoint) < mathUtil.getDistance(symbol.endPoint, endPoint)) {
+                    symbolService.setPosition(symbol, startPoint, 'end')
+                } else {
+                    symbolService.setPosition(symbol, endPoint, 'end')
+                }
+            }
+        }
+        symbol.setPoints2d()
+    }
+}
+
+const moveSymbol = new MoveSymbol()
+export { moveSymbol }

+ 15 - 0
src/views/draw-file/board/editCAD/Controls/MoveTag.js

@@ -0,0 +1,15 @@
+import { floorplanService } from '../Service/FloorplanService'
+import { mathUtil } from '../MathUtil.js'
+
+export default class MoveTag {
+    constructor() {}
+
+    moveFullTag(position, tagId) {
+        let tag = floorplanService.getTag(tagId)
+        mathUtil.clonePoint(tag.center, position)
+        tag.setPoints2d()
+    }
+}
+
+const moveTag = new MoveTag()
+export { moveTag }

File diff suppressed because it is too large
+ 1153 - 0
src/views/draw-file/board/editCAD/Controls/MoveWall.js


+ 784 - 0
src/views/draw-file/board/editCAD/Controls/UIControl.js

@@ -0,0 +1,784 @@
+import { coordinate } from '../Coordinate.js'
+import LayerEvents from '../enum/LayerEvents.js'
+import UIEvents from '../enum/UIEvents.js'
+import VectorType from '../enum/VectorType.js'
+import SymbolEvents from '../enum/SymbolEvents.js'
+import { stateService } from '../Service/StateService.js'
+import { measureService } from '../Service/MeasureService.js'
+import { floorplanService } from '../Service/FloorplanService.js'
+import { historyService } from '../Service/HistoryService.js'
+import { symbolService } from '../Service/SymbolService.js'
+import { componentService } from '../Service/ComponentService.js'
+import { elementService } from '../Service/ElementService'
+import { mathUtil } from '../MathUtil.js'
+import { wallService } from '../Service/WallService.js'
+import { tagService } from '../Service/TagService.js'
+import Constant from '../Constant'
+import { roomsUtil } from '../Room/RoomsUtil.js'
+import { addWall } from '../Controls/AddWall'
+import { floorplanData } from '../FloorplanData.js'
+import { furnitureService } from '../Service/FurnitureService.js'
+
+export default class UIControl {
+    constructor(layer) {
+        this.layer = layer
+        this.showTexture = true
+    }
+
+    /**
+     * 获取选中要添加的UI
+     */
+    get selectUI() {
+        return this.layer.$xui.selectName
+    }
+
+    /**
+     * 设置选中要添加的UI
+     */
+    set selectUI(value) {
+        this.layer.$xui.selectName = value
+        this.layer.updateEventNameForSelectUI()
+    }
+
+    /**
+     * 获取选中要操作的UI
+     */
+    get currentUI() {
+        return this.layer.$xui.currentName
+    }
+
+    /**
+     * 设置选中要操作的UI
+     */
+    set currentUI(value) {
+        if (value === null) {
+            this.layer.$xui.hideProps()
+        } else {
+            this.layer.$xui.showProps(value)
+        }
+    }
+
+    /**
+     * 获取当前楼层Id
+     */
+    get currentFloor() {
+        return this.layer.$xui.currentFloor
+    }
+
+    /**
+     * 设置当前楼层Id
+     */
+    set currentFloor(value) {
+        if (!this.layer.display) {
+            return
+        }
+        if (this.layer.app.store.getValue('flooruser').type == 'image') {
+        } else {
+            //需要补上3d的模型
+            floorplanService.setCurrentFloor(value)
+            this.layer.initPanos(floorplanService.currentFloor)
+            measureService.update()
+            historyService.clearHistoryRecord()
+            this.layer.$xui.toolbar.recall = false
+            this.layer.$xui.toolbar.recover = false
+            setTimeout(
+                function () {
+                    this.layer.renderer.autoRedraw()
+                }.bind(this),
+                50
+            )
+        }
+    }
+
+    /**
+     * 获取当前楼层Id
+     */
+    get currentUnit() {
+        return this.layer.$xui.currentUnit
+    }
+
+    /**
+     * 设置当前测量单位
+     */
+    set currentUnit(value) {
+        //this.layer.$xui.hideProps()
+        this.layer.uiControl.currentUI = null
+        measureService.unit = value //测量单位
+        tagService.convertUnit(value)
+        this.layer.history.save()
+        this.layer.renderer.autoRedraw()
+    }
+
+    /**
+     * 设置部件属性
+     * @param {*} type 部件类型
+     * @param {*} name 属性名称
+     * @param {*} value 属性值
+     */
+    setAttributes(type, name, value) {
+        console.log(name)
+        let item = stateService.getFocusItem()
+        // 回写 this.layer.$xui.currentAttributes = {...}
+        switch (name) {
+            case 'remove':
+                if (type == VectorType.Wall || type == 'OutWall') {
+                    floorplanService.deleteWall(item.vectorId)
+                } else if (symbolService.isSymbol(type)) {
+                    symbolService.deleteSymbol(item.vectorId)
+                } else if (componentService.isComponent(type)) {
+                    floorplanService.deleteComponent(item.vectorId)
+                } else if (type == VectorType.Tag) {
+                    floorplanService.deleteTag(item.vectorId)
+                    let _item = stateService.getDraggingItem()
+                    if (_item && _item.vectorId != item.vectorId) {
+                        floorplanService.deleteTag(_item.vectorId)
+                    }
+                } else if (type == VectorType.WallCorner) {
+                    wallService.deleteWallCorner(item.vectorId)
+                } else if (furnitureService.isFurniture(type)) {
+                    floorplanService.deleteFurniture(item.vectorId)
+                }
+                stateService.clearItems()
+                stateService.clearEventName()
+                //this.layer.history.save()
+                this.layer.renderer.autoRedraw()
+                break
+            case 'rotate':
+                if (symbolService.isSymbol(type)) {
+                    let symbol = floorplanService.getSymbol(item.vectorId)
+                    if (type == VectorType.SingleDoor) {
+                        if (symbol.openSide == SymbolEvents.Left) {
+                            if (mathUtil.isClockwise(symbol.points2d)) {
+                                symbol.openSide = SymbolEvents.Right
+                            } else {
+                                let temp = symbol.endPoint
+                                symbol.endPoint = symbol.startPoint
+                                symbol.startPoint = temp
+                                symbol.openSide = SymbolEvents.Right
+                            }
+                        } else if (symbol.openSide == SymbolEvents.Right) {
+                            if (mathUtil.isClockwise(symbol.points2d)) {
+                                symbol.openSide = SymbolEvents.Left
+                            } else {
+                                let temp = symbol.endPoint
+                                symbol.endPoint = symbol.startPoint
+                                symbol.startPoint = temp
+                                // let temp = {x:symbol.endPoint.x,y:symbol.endPoint.y}
+                                // mathUtil.clonePoint(symbol.endPoint,symbol.startPoint)
+                                // mathUtil.clonePoint(symbol.startPoint,temp)
+                                symbol.openSide = SymbolEvents.Left
+                                // symbol.setPoints2d()
+                            }
+                        }
+                    } else if (type == VectorType.DoubleDoor || type == VectorType.BayWindow) {
+                        if (symbol.openSide == SymbolEvents.Left) {
+                            symbol.openSide = SymbolEvents.Right
+                        } else if (symbol.openSide == SymbolEvents.Right) {
+                            symbol.openSide = SymbolEvents.Left
+                        }
+                    } else {
+                        let temp = symbol.endPoint
+                        symbol.endPoint = symbol.startPoint
+                        symbol.startPoint = temp
+                    }
+                    symbol.setPoints2d()
+                    //this.layer.history.save()
+                    this.layer.renderer.autoRedraw()
+                }
+                break
+            case 'angle':
+                if (componentService.isComponent(type)) {
+                    let component = floorplanService.getComponent(item.vectorId)
+                    component.angle = value
+                    component.setPoints2d()
+
+                    //this.layer.history.save()
+                    this.layer.renderer.autoRedraw()
+                } else if (furnitureService.isFurniture(type)) {
+                    let furniture = floorplanService.getFurniture(item.vectorId)
+                    furniture.angle = value
+
+                    //this.layer.history.save()
+                    this.layer.renderer.autoRedraw()
+                }
+                break
+            case 'width':
+                if (symbolService.isSymbol(type)) {
+                    const newStartEnd = symbolService.updateSymbolForLen(item.vectorId, value)
+                    if (newStartEnd.block) {
+                        let symbol = floorplanService.getSymbol(item.vectorId)
+                        console.log('长度阻止:' + mathUtil.getDistance(symbol.startPoint, symbol.endPoint))
+                        this.layer.$xui.currentAttributes = {
+                            limit: mathUtil.getDistance(symbol.startPoint, symbol.endPoint),
+                            type: item.type,
+                            name: 'width',
+                            width: mathUtil.getDistance(symbol.startPoint, symbol.endPoint),
+                        }
+                    }
+                } else if (componentService.isComponent(type)) {
+                    let component = floorplanService.getComponent(item.vectorId)
+                    component.sideWidth = value
+                    component.setPoints2d()
+                }
+                //this.layer.history.save()
+                this.layer.renderer.autoRedraw()
+                break
+
+            case 'scale':
+                if (furnitureService.isFurniture(type)) {
+                    let furniture = floorplanService.getFurniture(item.vectorId)
+                    furniture.scale = value
+                    //this.layer.history.save()
+                    this.layer.renderer.autoRedraw()
+                }
+                break
+            case 'thickness':
+                if (componentService.isComponent(type)) {
+                    let component = floorplanService.getComponent(item.vectorId)
+                    component.sideThickness = value
+                    component.setPoints2d()
+                    //this.layer.history.save()
+                    this.layer.renderer.autoRedraw()
+                }
+                break
+            case 'split':
+                if (type == VectorType.Wall || type == 'OutWall') {
+                    let wall = floorplanService.getWall(item.vectorId)
+                    let startPoint = floorplanService.getPoint(wall.start)
+                    let endPoint = floorplanService.getPoint(wall.end)
+                    let mid = {
+                        x: (startPoint.x + endPoint.x) / 2,
+                        y: (startPoint.y + endPoint.y) / 2,
+                    }
+                    let point = wallService.createPoint(mid.x, mid.y)
+                    const _wallId = wallService.splitWall(item.vectorId, point.vectorId, 'start')
+
+                    wall = floorplanService.getWall(item.vectorId)
+                    startPoint = floorplanService.getPoint(wall.start)
+                    endPoint = floorplanService.getPoint(wall.end)
+                    let _mid = {
+                        x: (startPoint.x + endPoint.x) / 2,
+                        y: (startPoint.y + endPoint.y) / 2,
+                    }
+                    let focusItem = {
+                        vectorId: _wallId,
+                        type: type,
+                    }
+
+                    if (mid.x < _mid.x) {
+                        stateService.setFocusItem(focusItem)
+                    } else if (mid.x == _mid.x && mid.y > _mid.y) {
+                        stateService.setFocusItem(focusItem)
+                    }
+                    //stateService.clearFocusItem()
+                    //this.layer.history.save()
+                    this.layer.renderer.autoRedraw()
+                }
+                break
+            case 'tag':
+                if (type == VectorType.Tag) {
+                    let tag = floorplanService.getTag(item.vectorId)
+                    if (value != null && value.trim() != '') {
+                        tag.setTitle(value)
+                    } else {
+                        tag.setTitle(KanKan.Config.i18n('cad.input'))
+                    }
+
+                    //this.layer.history.save()
+                    this.layer.renderer.autoRedraw()
+                }
+                break
+            case 'area':
+                if (type == VectorType.Tag) {
+                    let tag = floorplanService.getTag(item.vectorId)
+                    tag.setDes(value)
+                    tag.setUnit(measureService.unit)
+                    //this.layer.history.save()
+                    this.layer.renderer.autoRedraw()
+                }
+                break
+            case 'default':
+                if (type == 'compass') {
+                    floorplanService.setCompass(0)
+                    return
+                } else if (symbolService.isSymbol(type)) {
+                    let len = symbolService.getDefaultSymbolLen(type)
+                    const newStartEnd = symbolService.updateSymbolForLen(item.vectorId, len)
+                    if (!newStartEnd.block) {
+                        this.layer.$xui.currentAttributes = {
+                            type: item.type,
+                            name: 'width',
+                            width: mathUtil.getFixed(mathUtil.getDistance(newStartEnd.start, newStartEnd.end), 2),
+                        }
+                    }
+                } else if (componentService.isComponent(type)) {
+                    let component = floorplanService.getComponent(item.vectorId)
+                    component.sideWidth = componentService.sideWidth
+                    component.sideThickness = componentService.sideThickness
+                    component.angle = 0
+                    component.setPoints2d()
+                    this.layer.$xui.currentAttributes = {
+                        name: item.type,
+                        width: mathUtil.getFixed(component.sideWidth, 2), //Math.floor((component.sideWidth) * 100) / 100,
+                        thickness: mathUtil.getFixed(component.sideThickness, 2), //Math.floor((component.sideThickness) * 100) / 100,
+                        angle: 0,
+                    }
+                }
+                //this.layer.history.save()
+                this.layer.renderer.autoRedraw()
+                break
+            case 'enter': //入户门
+                if (type == VectorType.SingleDoor || type == VectorType.DoubleDoor || type == VectorType.SlideDoor) {
+                    let symbol = floorplanService.getSymbol(item.vectorId)
+                    if (value) {
+                        symbol.enter = 'default'
+                    } else {
+                        symbol.enter = null
+                    }
+                    //this.layer.history.save()
+                    this.layer.renderer.autoRedraw()
+                }
+                break
+            case 'enterRotate': //入户门方向
+                if (type == VectorType.SingleDoor || type == VectorType.DoubleDoor || type == VectorType.SlideDoor) {
+                    let symbol = floorplanService.getSymbol(item.vectorId)
+                    if (symbol.enter == null) {
+                        symbol.enter = 'default'
+                    } else if (symbol.enter == 'default') {
+                        symbol.enter = 'reverse'
+                    } else if (symbol.enter == 'reverse') {
+                        symbol.enter = 'default'
+                    }
+                }
+                //this.layer.history.save()
+                this.layer.renderer.autoRedraw()
+                break
+            case 'important':
+                if (type == VectorType.Wall) {
+                    let wall = floorplanService.getWall(item.vectorId)
+                    wall.setImportant(value)
+                    //this.layer.history.save()
+                    this.layer.renderer.autoRedraw()
+                }
+                break
+            case 'wallType':
+                if (type == VectorType.Wall) {
+                    let wall = floorplanService.getWall(item.vectorId)
+                    if (value == 'OutWall') {
+                        wall.setOut(true)
+                    } else {
+                        wall.setOut(false)
+                    }
+                    //this.layer.history.save()
+                    this.layer.renderer.autoRedraw()
+                }
+                break
+            case 'compass':
+                floorplanService.setCompass(parseFloat(value))
+                break
+        }
+    }
+
+    saveAttributes(type, name) {
+        if (name == 'compass' || (type == 'compass' && name == 'default')) {
+            return
+        }
+        this.layer.history.save()
+    }
+
+    showAttributes(type) {
+        if (type == 'compass') {
+            this.layer.$xui.currentAttributes = {
+                name: 'compass',
+                compass: floorplanService.getCompass(),
+            }
+            return
+        }
+        let item = stateService.getFocusItem()
+        if (item == null) {
+            item = stateService.getDraggingItem()
+        }
+        if (symbolService.isSymbol(item.type)) {
+            let symbol = floorplanService.getSymbol(item.vectorId)
+            let width = mathUtil.getDistance(symbol.startPoint, symbol.endPoint)
+            width = mathUtil.getFixed(width, 2)
+            if (item.type == VectorType.SingleDoor || item.type == VectorType.DoubleDoor || item.type == VectorType.SlideDoor) {
+                this.layer.$xui.currentAttributes = {
+                    name: item.type,
+                    width: width,
+                    enter: symbol.enter ? symbol.enter : null,
+                }
+            } else {
+                this.layer.$xui.currentAttributes = {
+                    name: item.type,
+                    width: width,
+                }
+            }
+        } else if (componentService.isComponent(item.type)) {
+            let component = floorplanService.getComponent(item.vectorId)
+            let sideWidth = component.sideWidth
+            let sideThickness = component.sideThickness
+            this.layer.$xui.currentAttributes = {
+                name: item.type,
+                width: mathUtil.getFixed(sideWidth, 2), //Math.floor((component.sideWidth) * 100) / 100,
+                thickness: mathUtil.getFixed(sideThickness, 2), //Math.floor((component.sideThickness) * 100) / 100,
+                angle: component.angle,
+            }
+        } else if (item.type == VectorType.Tag) {
+            let tag = floorplanService.getTag(item.vectorId)
+            this.layer.$xui.currentAttributes = {
+                name: item.type,
+                tag: tag.title,
+                area: tag.des,
+            }
+        } else if (item.type == VectorType.Wall) {
+            let wall = floorplanService.getWall(item.vectorId)
+            this.layer.$xui.currentAttributes = {
+                name: wall.out ? 'OutWall' : item.type,
+                important: wall.important || wall.out,
+                wallType: wall.out ? 'OutWall' : item.type,
+            }
+            // if (wall.important || wall.out) {
+            //     this.layer.$xui.currentAttributes = {
+            //         name: 'OutWall',
+            //     }
+            // } else {
+            //     this.layer.$xui.currentAttributes = {
+            //         name: item.type,
+            //     }
+            // }
+        } else if (furnitureService.isFurniture(item.type)) {
+            let furniture = floorplanService.getFurniture(item.vectorId)
+            let scale = furniture.scale
+            this.layer.$xui.currentAttributes = {
+                name: item.type,
+                scale: scale,
+                angle: furniture.angle,
+            }
+        }
+    }
+
+    clearUI() {
+        this.selectUI = null
+    }
+
+    getSymbolTypeForUI() {
+        if (this.selectUI == UIEvents.SingleDoor) {
+            return VectorType.SingleDoor
+        } else if (this.selectUI == UIEvents.DoubleDoor) {
+            return VectorType.DoubleDoor
+        } else if (this.selectUI == UIEvents.SlideDoor) {
+            return VectorType.SlideDoor
+        } else if (this.selectUI == UIEvents.SingleWindow) {
+            return VectorType.SingleWindow
+        } else if (this.selectUI == UIEvents.BayWindow) {
+            return VectorType.BayWindow
+        } else if (this.selectUI == UIEvents.FrenchWindow) {
+            return VectorType.FrenchWindow
+        } else if (this.selectUI == UIEvents.Pass) {
+            return VectorType.Pass
+        }
+    }
+
+    getComponentTypeForUI() {
+        if (this.selectUI == UIEvents.Beam) {
+            return VectorType.Beam
+        } else if (this.selectUI == UIEvents.Flue) {
+            return VectorType.Flue
+        } else if (this.selectUI == UIEvents.Corridor) {
+            return VectorType.Corridor
+        }
+    }
+
+    getFurnitureTypeForUI() {
+        if (this.selectUI == UIEvents.TV) {
+            return VectorType.TV
+        } else if (this.selectUI == UIEvents.CombinationSofa) {
+            return VectorType.CombinationSofa
+        } else if (this.selectUI == UIEvents.SingleSofa) {
+            return VectorType.SingleSofa
+        } else if (this.selectUI == UIEvents.TeaTable) {
+            return VectorType.TeaTable
+        } else if (this.selectUI == UIEvents.Carpet) {
+            return VectorType.Carpet
+        } else if (this.selectUI == UIEvents.Plant) {
+            return VectorType.Plant
+        } else if (this.selectUI == UIEvents.DiningTable) {
+            return VectorType.DiningTable
+        } else if (this.selectUI == UIEvents.DoubleBed) {
+            return VectorType.DoubleBed
+        } else if (this.selectUI == UIEvents.SingleBed) {
+            return VectorType.SingleBed
+        } else if (this.selectUI == UIEvents.Wardrobe) {
+            return VectorType.Wardrobe
+        } else if (this.selectUI == UIEvents.Dresser) {
+            return VectorType.Dresser
+        } else if (this.selectUI == UIEvents.BedsideCupboard) {
+            return VectorType.BedsideCupboard
+        } else if (this.selectUI == UIEvents.Pillow) {
+            return VectorType.Pillow
+        } else if (this.selectUI == UIEvents.GasStove) {
+            return VectorType.GasStove
+        } else if (this.selectUI == UIEvents.Cupboard) {
+            return VectorType.Cupboard
+        } else if (this.selectUI == UIEvents.Bathtub) {
+            return VectorType.Bathtub
+        } else if (this.selectUI == UIEvents.Closestool) {
+            return VectorType.Closestool
+        } else if (this.selectUI == UIEvents.Washstand) {
+            return VectorType.Washstand
+        } else if (this.selectUI == UIEvents.Desk) {
+            return VectorType.Desk
+        } else if (this.selectUI == UIEvents.BalconyChair) {
+            return VectorType.BalconyChair
+        } else if (this.selectUI == UIEvents.Elevator) {
+            return VectorType.Elevator
+        }
+    }
+
+    //截图
+    screenShot(styleType) {
+        return new Promise(resolve => {
+            this.menu_flex()
+            stateService.clearItems()
+            roomsUtil.start()
+
+            measureService.updateRegion(true)
+            measureService.update()
+
+            let canvas = this.layer.canvas
+
+            // canvas.width = Constant.cadImg_Width
+            // canvas.height = Constant.cadImg_Height
+            // coordinate.width = Constant.cadImg_Width / Constant.ratio
+            // coordinate.height = Constant.cadImg_Height / Constant.ratio
+
+            canvas.width = window.innerWidth * Constant.ratio
+            canvas.height = window.innerHeight * Constant.ratio
+            coordinate.width = window.innerWidth
+            coordinate.height = window.innerHeight
+
+            coordinate.ratio = Constant.ratio
+            let floorplanCamera = this.layer.app.core.get('CameraControls').activeControl.camera
+            coordinate.res = Math.min(window.innerWidth / Math.abs(floorplanCamera.right - floorplanCamera.left), window.innerHeight / Math.abs(floorplanCamera.top - floorplanCamera.bottom))
+            this.layer.renderer.autoRedrawForDownLoadImg(styleType)
+            setTimeout(
+                function () {
+                    let subFloor = floorplanService.getFloorNum()
+                    let file = []
+                    if (subFloor == 1) {
+                        this.downloadCadImg(canvas, 'floorPlan.jpg')
+                    } else {
+                        /*
+                        this.downloadCadImg(canvas, 'floorPlan_' + (floorplanService.getCurrentFloor() + 1) + '.jpg')
+                        let currentFloor = floorplanService.getCurrentFloor()
+                        for (let i = 0; i < subFloor; ++i) {
+                            if (i == currentFloor) {
+                                continue
+                            } else {
+                                this.currentFloor = i
+                                this.layer.renderer.autoRedrawForDownLoadImg(styleType)
+                                this.downloadCadImg(canvas, 'floorPlan_' + (i + 1) + '.jpg')
+                            }
+                        }
+                        this.currentFloor = currentFloor
+                        */
+                        let currentFloor = floorplanService.getCurrentFloor()
+                        this.layer.app.store.getValue('floorcad').floors.forEach((floor, index) => {
+                            this.currentFloor = index
+                            this.layer.renderer.autoRedrawForDownLoadImg(styleType)
+                            this.downloadCadImg(canvas, floor.name + '.jpg')
+                        })
+                        this.currentFloor = currentFloor
+                    }
+
+                    coordinate.updateForCanvas(canvas)
+                    coordinate.setRes(floorplanCamera.left, floorplanCamera.right)
+                    coordinate.ratio = 1
+                    //this.layer.renderer.autoRedrawForDownLoadImg(styleType)
+                    this.layer.renderer.autoRedraw()
+                    resolve()
+                }.bind(this),
+                100
+            )
+        })
+    }
+
+    downloadCadImg(canvas, filename) {
+        // 图片导出为 jpg 格式
+        var type = 'jpg'
+        var imgData = canvas.toDataURL(type, 3)
+
+        // 加工image data,替换mime type
+        imgData = imgData.replace(this._fixType(type), 'image/octet-stream')
+        // 下载后的图片名
+        //var filename = 'cad_' + new Date().getTime() + '.' + type
+        // download
+        this.saveFile(imgData, filename)
+    }
+
+    saveFile(data, filename) {
+        var save_link = document.createElementNS('http://www.w3.org/1999/xhtml', 'a')
+        save_link.href = data
+        save_link.download = filename
+
+        var event = document.createEvent('MouseEvents')
+        event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null)
+        save_link.dispatchEvent(event)
+    }
+
+    _fixType(type) {
+        type = type.toLowerCase().replace(/jpg/i, 'jpeg')
+        var r = type.match(/png|jpeg|bmp|gif/)[0]
+        return 'image/' + r
+    }
+    /****************************************************************************针对菜单*******************************************************************************/
+
+    execute(name, value) {
+        stateService.clearFocusItem()
+        stateService.clearSelectItem()
+        //this.layer.$xui.hideProps()
+        this.layer.uiControl.currentUI = null
+        switch (name) {
+            case 'recall': //撤销
+                this.menu_revoke()
+                break
+            case 'recover': //恢复
+                this.menu_recovery()
+                break
+            case 'default': //恢复默认
+                this.menu_default()
+                break
+            case 'download': //下载
+                this.layer.div.style.visibility = 'hidden'
+                this.menu_screenShot(value).then(() => {
+                    this.layer.div.style.visibility = 'visible'
+                })
+                break
+            case 'texture': //底图
+                this.showTexture = value
+                this.layer.app.dom.querySelector('.player[name="main"]').style.visibility = this.showTexture ? 'visible' : 'hidden'
+                break
+            case 'clear': //清空
+                this.menu_clear()
+                break
+            case 'panos': //漫游点
+                this.menu_panos(value)
+                break
+            case 'rotate': //旋转
+                this.menu_rotate()
+                break
+            case 'flex': //适应视图
+                this.menu_flex()
+                break
+        }
+    }
+
+    //撤销
+    menu_revoke() {
+        // this.layer.history.goPreState()
+        // this.layer.renderer.autoRedraw()
+
+        // const historyState = historyService.getHistoryState()
+        // if (historyState.pre) {
+        //     this.layer.$xui.toolbar.recall = true
+        // } else {
+        //     this.layer.$xui.toolbar.recall = false
+        // }
+        // this.layer.$xui.toolbar.recover = true
+        this.layer.revokeHistory()
+    }
+
+    //恢复
+    menu_recovery() {
+        // this.layer.history.goNextState()
+        // this.layer.renderer.autoRedraw()
+
+        // const historyState = historyService.getHistoryState()
+        // if (historyState.next) {
+        //     this.layer.$xui.toolbar.recover = true
+        // } else {
+        //     this.layer.$xui.toolbar.recover = false
+        // }
+        // this.layer.$xui.toolbar.recall = true
+        this.layer.recoveryHistory()
+    }
+
+    menu_default() {
+        historyService.clearHistoryRecord()
+        floorplanService.setAngle(0)
+        this.layer.app.store.getValue('metadata').floorPlanUser = 0
+        this.layer.app.store.getValue('metadata').floorPlanAngle = 0
+        this.menu_flex(true)
+        this.layer.load.loadFloorJson(true).then(() => {
+            this.layer.app.core.get('Player').model.floorplanCadImg.updatePlanes()
+            this.layer.render()
+            this.layer.app.MinMap.reload()
+            this.layer.app.core.get('Player').labelManager.reset()
+        })
+    }
+
+    //截图
+    menu_screenShot(styleType) {
+        this.layer.stopAddVector()
+        return this.screenShot(styleType)
+    }
+
+    //清空
+    menu_clear() {
+        floorplanService.clear()
+        stateService.clearEventName()
+        addWall.clear()
+        elementService.hideAll()
+        this.layer.history.save()
+        this.layer.renderer.autoRedraw()
+    }
+
+    menu_panos(value) {
+        this.layer.renderer.displayPanos = value
+        this.layer.renderer.autoRedraw()
+    }
+
+    menu_rotate() {
+        coordinate.reSet()
+        let angle = floorplanService.getAngle()
+        angle = parseFloat(angle) + Math.PI / 2
+        if (Math.abs(angle - 2 * Math.PI) < 0.1) {
+            angle = 0
+        }
+        angle = angle % 360
+        floorplanService.setAngle(angle)
+
+        //旋转三维模型
+        let info = coordinate.getScreenInfoForCAD()
+        info.floorPlanAngle = angle
+        this.layer.app.store.getValue('metadata').floorPlanAngle = angle
+        this.layer.app.core.get('CameraControls').emit('syncCadAnd3DForRotate', info)
+        let floorplanCamera = this.layer.app.core.get('CameraControls').activeControl.camera
+        coordinate.setRes(floorplanCamera.left, floorplanCamera.right)
+
+        //修改cad数据
+        coordinate.updateForRotate()
+        this.layer.initPanos(floorplanService.getCurrentFloor())
+        //修改测量线
+        measureService.update()
+        this.layer.history.save()
+        this.layer.renderer.autoRedraw()
+    }
+
+    menu_flex(updateCadRes) {
+        if (coordinate.center) {
+            coordinate.reSet()
+            this.layer.renderer.autoRedraw()
+            let info = coordinate.getScreenInfoForCAD()
+            info.floorPlanAngle = floorplanService.getAngle()
+            this.layer.app.core.get('CameraControls').emit('syncCadAnd3D', info) // info = {width:..,height:...,center:...}
+
+            if (updateCadRes) {
+                let floorplanCamera = this.layer.app.core.get('CameraControls').activeControl.camera
+                coordinate.setRes(floorplanCamera.left, floorplanCamera.right)
+            }
+        }
+    }
+    /******************************************************************************************************************************************************************/
+}

+ 130 - 0
src/views/draw-file/board/editCAD/Coordinate.js

@@ -0,0 +1,130 @@
+import Constant from './Constant'
+
+// const pad = {
+//     top: 40,
+//     bottom: 40,
+//     left: 40,
+//     right: 40,
+// }
+
+export default class Coordinate {
+    constructor() {
+        this.defaultCenter = null
+        this.center = {
+            x:0,
+            y:0
+        } // 世界坐标,中心点
+        this.zoom = 100 // 当前缩放比例,不会改变世界坐标系的坐标,只是改变渲染时转换的屏幕坐标
+        this.res = 100 //默认情况,100个像素对应1米
+        this.ratio = 1
+
+        this.initRes = null
+        this.initWidth = null
+        this.initHeight = null
+    }
+
+    // 初始化
+    init(canvas) {
+        this.updateForCanvas(canvas)
+    }
+
+    setRes(res) {
+        this.res = res
+        Constant.minRealDis = Constant.minPixLen / this.res
+        Constant.minAdsorb = Constant.minPixLen / this.res
+    }
+
+    setCenter(point) {
+        this.center = {
+            x: point.x,
+            y: point.y,
+        }
+    }
+
+    // 世界坐标转换成屏幕坐标
+    getScreenXY(point) {
+        if (this.width == null || this.height == null) {
+            return null
+        }
+
+        let pt = {
+            x: point.x,
+            y: point.y,
+        }
+
+        let x = this.width / 2 + ((pt.x - this.center.x) * this.res * this.zoom) / 100 
+        let y = this.height / 2 - ((pt.y - this.center.y) * this.res * this.zoom) / 100 
+
+        x = (0.5 + x) << 0
+        y = (0.5 + y) << 0
+        return {
+            x: Math.floor(x) * this.ratio,
+            y: Math.floor(y) * this.ratio,
+        }
+    }
+
+    // 屏幕坐标转换成世界坐标
+    getXYFromScreen(screenPoint) {
+        const point = {}
+        point.x = (((screenPoint.x - this.width / 2) / this.res) * 100) / this.zoom + this.center.x
+        point.y = (((this.height / 2 - screenPoint.y) / this.res) * 100) / this.zoom + this.center.y
+        return point
+    }
+
+    updateForCanvas(canvas) {
+        if (canvas) {
+            this.width = canvas.clientWidth
+            this.height = canvas.clientHeight
+
+            canvas.width = canvas.clientWidth
+            canvas.height = canvas.clientHeight
+        }
+    }
+
+    updateZoom(zoom) {
+        this.zoom = zoom
+    }
+
+    moveTo(zoom, screenPosition) {
+        const position = this.getXYFromScreen(screenPosition)
+        this.zoom = zoom
+        const dx = ((screenPosition.x * 100) / this.zoom - this.width / 2) / this.res
+        const dy = (this.height / 2 - (screenPosition.y * 100) / this.zoom) / this.res
+        this.center.x = position.x - dx
+        this.center.y = position.y - dy
+    }
+
+    getPixelRatio(context) {
+        var backingStore =
+            context.backingStorePixelRatio ||
+            context.webkitBackingStorePixelRatio ||
+            context.mozBackingStorePixelRatio ||
+            context.msBackingStorePixelRatio ||
+            context.oBackingStorePixelRatio ||
+            context.backingStorePixelRatio ||
+            1
+        return (window.devicePixelRatio || 1) / backingStore
+    }
+
+    reSet() {
+        this.center = {
+            x: 0,
+            y: 0,
+        }
+        this.res = 100
+        this.zoom = 100
+    }
+
+    clear() {
+        this.center = {
+            x: 0,
+            y: 0,
+        }
+        this.zoom = 100
+        this.res = 100
+        this.ratio = 1
+    }
+}
+
+const coordinate = new Coordinate()
+export { coordinate }

+ 162 - 0
src/views/draw-file/board/editCAD/Geometry/BayWindow.js

@@ -0,0 +1,162 @@
+import VectorType from '../enum/VectorType.js'
+import Geometry from './Geometry'
+import { coordinate } from '../Coordinate'
+import { mathUtil } from '../MathUtil.js'
+import SelectState from '../enum/SelectState.js'
+import Constant from '../Constant.js'
+
+export default class BayWindow extends Geometry {
+    constructor(startPoint, endPoint, vectorId, floor) {
+        super()
+        this.startPoint = startPoint
+        this.endPoint = endPoint
+        this.floor = floor
+        this.openSide = 'LEFT' // LEFT或者RIGHT
+        this.parent = null
+
+        // 渲染用的
+        this.points2d = []
+        this.name = '飘窗'
+        this.geoType = VectorType.BayWindow
+        this.setId(vectorId)
+    }
+
+    setPoints2d() {
+        const line = mathUtil.createLine1(this.startPoint, this.endPoint)
+        const len1 = mathUtil.getDistance(this.startPoint, this.endPoint) / 2
+        const len2 = 4 / coordinate.res + len1
+
+        const midPoint = {
+            x: (this.startPoint.x + this.endPoint.x) / 2,
+            y: (this.startPoint.y + this.endPoint.y) / 2,
+        }
+
+        const vertline = mathUtil.getVerticalLine(line, midPoint)
+        let vStartLine1, vStartLine2, vEndLine1, vEndLine2
+
+        //垂直
+        const lines1 = mathUtil.getParallelLineForDistance(vertline, len1)
+        const lines2 = mathUtil.getParallelLineForDistance(vertline, len2)
+        let dis1 = mathUtil.getDisForPoinLine(this.startPoint, lines1.line1)
+        let dis2 = mathUtil.getDisForPoinLine(this.startPoint, lines1.line2)
+        if (dis1 > dis2) {
+            vStartLine1 = lines1.line2
+            vStartLine2 = lines2.line2
+
+            vEndLine1 = lines1.line1
+            vEndLine2 = lines2.line1
+        } else {
+            vStartLine1 = lines1.line1
+            vStartLine2 = lines2.line1
+
+            vEndLine1 = lines1.line2
+            vEndLine2 = lines2.line2
+        }
+
+        //平行
+        const lines3 = mathUtil.getParallelLineForDistance(line, 2 / coordinate.res)
+        const lines4 = mathUtil.getParallelLineForDistance(line, 24 / coordinate.res)
+        const lines5 = mathUtil.getParallelLineForDistance(line, 28 / coordinate.res)
+
+        let pLine1 = lines3.line1
+        let pLine2 = lines3.line2
+        let pLine3 = lines4.line2
+        let pLine4 = lines5.line2
+
+        let pLine5 = lines3.line2
+        let pLine6 = lines3.line1
+        let pLine7 = lines4.line1
+        let pLine8 = lines5.line1
+
+        let point1 = mathUtil.getIntersectionPoint(vStartLine1, pLine1)
+        let point2 = mathUtil.getIntersectionPoint(vEndLine1, pLine1)
+        let point3 = mathUtil.getIntersectionPoint(vEndLine1, pLine3)
+        let point4 = mathUtil.getIntersectionPoint(vStartLine1, pLine3)
+
+        let point5 = mathUtil.getIntersectionPoint(vStartLine2, pLine2)
+        let point6 = mathUtil.getIntersectionPoint(vEndLine2, pLine2)
+        let point7 = mathUtil.getIntersectionPoint(vEndLine2, pLine4)
+        let point8 = mathUtil.getIntersectionPoint(vStartLine2, pLine4)
+
+        let point9 = mathUtil.getIntersectionPoint(vStartLine1, pLine5)
+        let point10 = mathUtil.getIntersectionPoint(vEndLine1, pLine5)
+        let point11 = mathUtil.getIntersectionPoint(vEndLine1, pLine7)
+        let point12 = mathUtil.getIntersectionPoint(vStartLine1, pLine7)
+
+        let point13 = mathUtil.getIntersectionPoint(vStartLine2, pLine6)
+        let point14 = mathUtil.getIntersectionPoint(vEndLine2, pLine6)
+        let point15 = mathUtil.getIntersectionPoint(vEndLine2, pLine8)
+        let point16 = mathUtil.getIntersectionPoint(vStartLine2, pLine8)
+
+        this.points2d = []
+
+        this.points2d.push(point1)
+        this.points2d.push(point2)
+        this.points2d.push(point3)
+        this.points2d.push(point4)
+
+        if (this.openSide == 'LEFT') {
+            //逆时针
+            if (mathUtil.isClockwise(this.points2d)) {
+                this.points2d.push(point5)
+                this.points2d.push(point6)
+                this.points2d.push(point7)
+                this.points2d.push(point8)
+            } else {
+                this.points2d = []
+                this.points2d.push(point9)
+                this.points2d.push(point10)
+                this.points2d.push(point11)
+                this.points2d.push(point12)
+                this.points2d.push(point13)
+                this.points2d.push(point14)
+                this.points2d.push(point15)
+                this.points2d.push(point16)
+            }
+        } else if (this.openSide == 'RIGHT') {
+            //逆时针
+            if (mathUtil.isClockwise(this.points2d)) {
+                this.points2d = []
+                this.points2d.push(point9)
+                this.points2d.push(point10)
+                this.points2d.push(point11)
+                this.points2d.push(point12)
+                this.points2d.push(point13)
+                this.points2d.push(point14)
+                this.points2d.push(point15)
+                this.points2d.push(point16)
+            } else {
+                this.points2d.push(point5)
+                this.points2d.push(point6)
+                this.points2d.push(point7)
+                this.points2d.push(point8)
+            }
+        }
+    }
+
+    isContain(position) {
+        const dis1 = mathUtil.getDistance(position, this.startPoint)
+        const dis2 = mathUtil.getDistance(position, this.endPoint)
+        if (dis1 < Constant.minAdsorb) {
+            return SelectState.Start
+        } else if (dis2 < Constant.minAdsorb) {
+            return SelectState.End
+        }
+        let flag = mathUtil.isContainForSegment(position, this.startPoint, this.endPoint)
+        if (flag) {
+            return SelectState.Select
+        } else {
+            let points = []
+            points[0] = this.points2d[4]
+            points[1] = this.points2d[5]
+            points[2] = this.points2d[6]
+            points[3] = this.points2d[7]
+            flag = mathUtil.isPointInPoly(position, points)
+            if (flag) {
+                return SelectState.Select
+            } else {
+                return null
+            }
+        }
+    }
+}

+ 76 - 0
src/views/draw-file/board/editCAD/Geometry/Beam.js

@@ -0,0 +1,76 @@
+import VectorType from '../enum/VectorType.js'
+import SelectState from '../enum/SelectState.js'
+import Geometry from './Geometry'
+import { mathUtil } from '../MathUtil.js'
+import Constant from '../Constant.js'
+import { coordinate } from '../Coordinate'
+
+//靠墙
+export default class Beam extends Geometry {
+    constructor(center, vectorId) {
+        super()
+        this.center = center
+        this.angle = 0 //逆时针为负,顺时针为正。单位是:°
+        this.points2d = []
+
+        this.sideWidth = 0.65
+        this.sideThickness = 0.65
+
+        this.name = '柱子'
+        this.geoType = VectorType.Beam
+        this.setId(vectorId)
+    }
+
+    isContain(position) {
+        return mathUtil.isPointInPoly(position, this.points2d)
+    }
+
+    setPoints2d() {
+        this.points2d = []
+        const minX = this.center.x - this.sideWidth / 2
+        const minY = this.center.y - this.sideThickness / 2
+        const maxX = this.center.x + this.sideWidth / 2
+        const maxY = this.center.y + this.sideThickness / 2
+
+        const point1 = this.rotatePoint(
+            {
+                x: minX,
+                y: maxY,
+            },
+            this.center,
+            this.angle
+        )
+
+        const point2 = this.rotatePoint(
+            {
+                x: maxX,
+                y: maxY,
+            },
+            this.center,
+            this.angle
+        )
+
+        const point3 = this.rotatePoint(
+            {
+                x: maxX,
+                y: minY,
+            },
+            this.center,
+            this.angle
+        )
+
+        const point4 = this.rotatePoint(
+            {
+                x: minX,
+                y: minY,
+            },
+            this.center,
+            this.angle
+        )
+
+        this.points2d.push(point1)
+        this.points2d.push(point2)
+        this.points2d.push(point3)
+        this.points2d.push(point4)
+    }
+}

+ 470 - 0
src/views/draw-file/board/editCAD/Geometry/Corridor.js

@@ -0,0 +1,470 @@
+import Geometry from './Geometry'
+import VectorType from '../enum/VectorType.js'
+import { mathUtil } from '../MathUtil.js'
+import { coordinate } from '../Coordinate'
+import Constant from '../Constant.js'
+
+//不靠墙
+export default class Corridor extends Geometry {
+    constructor(center, vectorId) {
+        super()
+        this.center = center
+        this.angle = 0 //逆时针为正,顺时针为负。单位是:°
+        this.points2d = []
+
+        this.sideWidth = 0.65
+        this.sideThickness = 0.65
+
+        this.name = '楼道'
+        this.geoType = VectorType.Corridor
+        this.setId(vectorId)
+    }
+
+    isContain(position) {
+        let points = []
+        points.push(this.points2d[0])
+        points.push(this.points2d[1])
+        points.push(this.points2d[2])
+        points.push(this.points2d[3])
+        return mathUtil.isPointInPoly(position, points)
+    }
+
+    setPoints2d() {
+        this.points2d = []
+        let minX = this.center.x - this.sideWidth / 2
+        let minY = this.center.y - this.sideThickness / 2
+        let maxX = this.center.x + this.sideWidth / 2
+        let maxY = this.center.y + this.sideThickness / 2
+
+        const point1 = this.rotatePoint(
+            {
+                x: minX,
+                y: maxY,
+            },
+            this.center,
+            this.angle
+        )
+
+        const point2 = this.rotatePoint(
+            {
+                x: maxX,
+                y: maxY,
+            },
+            this.center,
+            this.angle
+        )
+
+        const point3 = this.rotatePoint(
+            {
+                x: maxX,
+                y: minY,
+            },
+            this.center,
+            this.angle
+        )
+
+        const point4 = this.rotatePoint(
+            {
+                x: minX,
+                y: minY,
+            },
+            this.center,
+            this.angle
+        )
+
+        this.points2d.push(point1)
+        this.points2d.push(point2)
+        this.points2d.push(point3)
+        this.points2d.push(point4)
+
+        const leftX = this.center.x - 2 / coordinate.res
+        const rightX = this.center.x + 2 / coordinate.res
+        //const dy = (maxY - minY) / 9
+        const dy = 3 / coordinate.res
+        const point5 = this.rotatePoint(
+            {
+                x: leftX,
+                y: maxY,
+            },
+            this.center,
+            this.angle
+        )
+
+        const point6 = this.rotatePoint(
+            {
+                x: leftX,
+                y: minY,
+            },
+            this.center,
+            this.angle
+        )
+
+        this.points2d.push(point5)
+        this.points2d.push(point6)
+
+        const point7 = this.rotatePoint(
+            {
+                x: rightX,
+                y: maxY,
+            },
+            this.center,
+            this.angle
+        )
+
+        const point8 = this.rotatePoint(
+            {
+                x: rightX,
+                y: minY,
+            },
+            this.center,
+            this.angle
+        )
+
+        this.points2d.push(point7)
+        this.points2d.push(point8)
+
+        const num = Math.floor((this.sideThickness * coordinate.res) / 3)
+        for (let i = 0; i < num - 2; ++i) {
+            const point9 = this.rotatePoint(
+                {
+                    x: minX,
+                    y: maxY - (i + 2) * dy,
+                },
+                this.center,
+                this.angle
+            )
+
+            const point10 = this.rotatePoint(
+                {
+                    x: leftX,
+                    y: maxY - (i + 2) * dy,
+                },
+                this.center,
+                this.angle
+            )
+
+            this.points2d.push(point9)
+            this.points2d.push(point10)
+
+            // if(i!= num-2)
+            // {
+            const point11 = this.rotatePoint(
+                {
+                    x: rightX,
+                    y: maxY - (i + 1) * dy,
+                },
+                this.center,
+                this.angle
+            )
+
+            const point12 = this.rotatePoint(
+                {
+                    x: maxX,
+                    y: maxY - (i + 1) * dy,
+                },
+                this.center,
+                this.angle
+            )
+
+            this.points2d.push(point11)
+            this.points2d.push(point12)
+            // }
+        }
+
+        /*
+        const point9 = this.rotatePoint(
+            {
+                x: minX,
+                y: maxY - 2 * dy,
+            },
+            this.center,
+            this.angle
+        )
+
+        const point10 = this.rotatePoint(
+            {
+                x: leftX,
+                y: maxY - 2 * dy,
+            },
+            this.center,
+            this.angle
+        )
+
+        this.points2d.push(point9)
+        this.points2d.push(point10)
+
+        const point11 = this.rotatePoint(
+            {
+                x: minX,
+                y: maxY - 3 * dy,
+            },
+            this.center,
+            this.angle
+        )
+
+        const point12 = this.rotatePoint(
+            {
+                x: leftX,
+                y: maxY - 3 * dy,
+            },
+            this.center,
+            this.angle
+        )
+
+        this.points2d.push(point11)
+        this.points2d.push(point12)
+
+        const point13 = this.rotatePoint(
+            {
+                x: minX,
+                y: maxY - 4 * dy,
+            },
+            this.center,
+            this.angle
+        )
+
+        const point14 = this.rotatePoint(
+            {
+                x: leftX,
+                y: maxY - 4 * dy,
+            },
+            this.center,
+            this.angle
+        )
+
+        this.points2d.push(point13)
+        this.points2d.push(point14)
+
+        const point15 = this.rotatePoint(
+            {
+                x: minX,
+                y: maxY - 5 * dy,
+            },
+            this.center,
+            this.angle
+        )
+
+        const point16 = this.rotatePoint(
+            {
+                x: leftX,
+                y: maxY - 5 * dy,
+            },
+            this.center,
+            this.angle
+        )
+
+        this.points2d.push(point15)
+        this.points2d.push(point16)
+
+        const point17 = this.rotatePoint(
+            {
+                x: minX,
+                y: maxY - 6 * dy,
+            },
+            this.center,
+            this.angle
+        )
+
+        const point18 = this.rotatePoint(
+            {
+                x: leftX,
+                y: maxY - 6 * dy,
+            },
+            this.center,
+            this.angle
+        )
+
+        this.points2d.push(point17)
+        this.points2d.push(point18)
+
+        const point19 = this.rotatePoint(
+            {
+                x: minX,
+                y: maxY - 7 * dy,
+            },
+            this.center,
+            this.angle
+        )
+
+        const point20 = this.rotatePoint(
+            {
+                x: leftX,
+                y: maxY - 7 * dy,
+            },
+            this.center,
+            this.angle
+        )
+
+        this.points2d.push(point19)
+        this.points2d.push(point20)
+
+        const point21 = this.rotatePoint(
+            {
+                x: minX,
+                y: maxY - 8 * dy,
+            },
+            this.center,
+            this.angle
+        )
+
+        const point22 = this.rotatePoint(
+            {
+                x: leftX,
+                y: maxY - 8 * dy,
+            },
+            this.center,
+            this.angle
+        )
+
+        this.points2d.push(point21)
+        this.points2d.push(point22)
+
+        const point23 = this.rotatePoint(
+            {
+                x: rightX,
+                y: maxY - dy,
+            },
+            this.center,
+            this.angle
+        )
+
+        const point24 = this.rotatePoint(
+            {
+                x: maxX,
+                y: maxY - dy,
+            },
+            this.center,
+            this.angle
+        )
+
+        this.points2d.push(point23)
+        this.points2d.push(point24)
+
+        const point25 = this.rotatePoint(
+            {
+                x: rightX,
+                y: maxY - 2 * dy,
+            },
+            this.center,
+            this.angle
+        )
+
+        const point26 = this.rotatePoint(
+            {
+                x: maxX,
+                y: maxY - 2 * dy,
+            },
+            this.center,
+            this.angle
+        )
+
+        this.points2d.push(point25)
+        this.points2d.push(point26)
+
+        const point27 = this.rotatePoint(
+            {
+                x: rightX,
+                y: maxY - 3 * dy,
+            },
+            this.center,
+            this.angle
+        )
+
+        const point28 = this.rotatePoint(
+            {
+                x: maxX,
+                y: maxY - 3 * dy,
+            },
+            this.center,
+            this.angle
+        )
+
+        this.points2d.push(point27)
+        this.points2d.push(point28)
+
+        const point29 = this.rotatePoint(
+            {
+                x: rightX,
+                y: maxY - 4 * dy,
+            },
+            this.center,
+            this.angle
+        )
+
+        const point30 = this.rotatePoint(
+            {
+                x: maxX,
+                y: maxY - 4 * dy,
+            },
+            this.center,
+            this.angle
+        )
+
+        this.points2d.push(point29)
+        this.points2d.push(point30)
+
+        const point31 = this.rotatePoint(
+            {
+                x: rightX,
+                y: maxY - 5 * dy,
+            },
+            this.center,
+            this.angle
+        )
+
+        const point32 = this.rotatePoint(
+            {
+                x: maxX,
+                y: maxY - 5 * dy,
+            },
+            this.center,
+            this.angle
+        )
+
+        this.points2d.push(point31)
+        this.points2d.push(point32)
+
+        const point33 = this.rotatePoint(
+            {
+                x: rightX,
+                y: maxY - 6 * dy,
+            },
+            this.center,
+            this.angle
+        )
+
+        const point34 = this.rotatePoint(
+            {
+                x: maxX,
+                y: maxY - 6 * dy,
+            },
+            this.center,
+            this.angle
+        )
+
+        this.points2d.push(point33)
+        this.points2d.push(point34)
+
+        const point35 = this.rotatePoint(
+            {
+                x: rightX,
+                y: maxY - 7 * dy,
+            },
+            this.center,
+            this.angle
+        )
+
+        const point36 = this.rotatePoint(
+            {
+                x: maxX,
+                y: maxY - 7 * dy,
+            },
+            this.center,
+            this.angle
+        )
+
+        this.points2d.push(point35)
+        this.points2d.push(point36)
+        */
+    }
+}

+ 137 - 0
src/views/draw-file/board/editCAD/Geometry/DoubleDoor.js

@@ -0,0 +1,137 @@
+import VectorType from '../enum/VectorType.js'
+import Geometry from './Geometry'
+import SelectState from '../enum/SelectState.js'
+import { mathUtil } from '../MathUtil.js'
+import Constant from '../Constant.js'
+import SymbolEvents from '../enum/SymbolEvents.js'
+
+export default class DoubleDoor extends Geometry {
+    constructor(startPoint, endPoint, vectorId, floor) {
+        super()
+        this.startPoint = startPoint
+        this.endPoint = endPoint
+        this.floor = floor
+        this.openSide = null // LEFT或者RIGHT
+        this.parent = null
+        this.enter = null // LEFT或者RIGHT
+        // 渲染用的,四元素,0是start,1是end
+        this.points2d = []
+        this.name = '双开门'
+        this.geoType = VectorType.DoubleDoor
+        this.setId(vectorId)
+    }
+
+    setPoints2d() {
+        const line = mathUtil.createLine1(this.startPoint, this.endPoint)
+        const len = mathUtil.getDistance(this.startPoint, this.endPoint)
+        const lines = mathUtil.getParallelLineForDistance(line, len / 2)
+        const vertline1 = mathUtil.getVerticalLine(line, this.startPoint)
+        const vertline2 = mathUtil.getVerticalLine(line, this.endPoint)
+
+        const midPoint = {
+            x: (this.startPoint.x + this.endPoint.x) / 2,
+            y: (this.startPoint.y + this.endPoint.y) / 2,
+        }
+        const vertline = mathUtil.getVerticalLine(line, midPoint)
+
+        let startJoin1 = mathUtil.getIntersectionPoint(lines.line1, vertline1)
+        let startJoin2 = mathUtil.getIntersectionPoint(lines.line2, vertline1)
+
+        let endJoin1 = mathUtil.getIntersectionPoint(lines.line1, vertline2)
+        let endJoin2 = mathUtil.getIntersectionPoint(lines.line2, vertline2)
+
+        let midJoin1 = mathUtil.getIntersectionPoint(lines.line1, vertline)
+        let midJoin2 = mathUtil.getIntersectionPoint(lines.line2, vertline)
+
+        this.points2d = []
+        this.points2d.push(this.startPoint)
+        this.points2d.push(midPoint)
+        this.points2d.push(this.endPoint)
+        this.points2d.push(endJoin1)
+        this.points2d.push(midJoin1)
+        this.points2d.push(startJoin1)
+
+        //逆时针
+        if (this.openSide == SymbolEvents.Left) {
+            if (mathUtil.isClockwise(this.points2d)) {
+                return
+            } else {
+                this.points2d = []
+                this.points2d.push(this.startPoint)
+                this.points2d.push(midPoint)
+                this.points2d.push(this.endPoint)
+                this.points2d.push(endJoin2)
+                this.points2d.push(midJoin2)
+                this.points2d.push(startJoin2)
+            }
+        } else if (this.openSide == SymbolEvents.Right) {
+            if (mathUtil.isClockwise(this.points2d)) {
+                this.points2d = []
+                this.points2d.push(this.startPoint)
+                this.points2d.push(midPoint)
+                this.points2d.push(this.endPoint)
+                this.points2d.push(endJoin2)
+                this.points2d.push(midJoin2)
+                this.points2d.push(startJoin2)
+            } else {
+                return
+            }
+        }
+    }
+
+    isContain(position) {
+        const dis1 = mathUtil.getDistance(position, this.startPoint)
+        const dis2 = mathUtil.getDistance(position, this.endPoint)
+        if (dis1 < Constant.minAdsorb) {
+            return SelectState.Start
+        } else if (dis2 < Constant.minAdsorb) {
+            return SelectState.End
+        }
+
+        let flag = mathUtil.isContainForSegment(position, this.startPoint, this.endPoint)
+        if (flag) {
+            return SelectState.Select
+        }
+
+        let points = []
+        points.push(this.startPoint)
+        points.push(this.endPoint)
+        points.push(position)
+        if (this.openSide == SymbolEvents.Left) {
+            if (!mathUtil.isClockwise(points)) {
+                return null
+            }
+        } else if (this.openSide == SymbolEvents.Right) {
+            if (mathUtil.isClockwise(points)) {
+                return null
+            }
+        }
+
+        const midPoint = {
+            x: (this.points2d[0].x + this.points2d[1].x) / 2,
+            y: (this.points2d[0].y + this.points2d[1].y) / 2,
+        }
+
+        // 两个扇形
+        const radius = mathUtil.getDistance(this.points2d[1], this.points2d[2])
+
+        let len = mathUtil.getDistance(position, this.points2d[0])
+        if (len < radius) {
+            const angle1 = mathUtil.Angle(this.points2d[0], position, this.points2d[5])
+            const angle2 = mathUtil.Angle(this.points2d[0], position, midPoint)
+            if (angle1 < Math.PI / 2 && angle2 < Math.PI / 2) {
+                return SelectState.Select
+            }
+        }
+        len = mathUtil.getDistance(position, this.points2d[2])
+        if (len < radius) {
+            const angle1 = mathUtil.Angle(this.points2d[2], position, this.points2d[3])
+            const angle2 = mathUtil.Angle(this.points2d[2], position, midPoint)
+            if (angle1 < Math.PI / 2 && angle2 < Math.PI / 2) {
+                return SelectState.Select
+            }
+        }
+
+        return null
+    }
+}

+ 133 - 0
src/views/draw-file/board/editCAD/Geometry/Flue.js

@@ -0,0 +1,133 @@
+import VectorType from '../enum/VectorType.js'
+import SelectState from '../enum/SelectState.js'
+import Geometry from './Geometry'
+import { mathUtil } from '../MathUtil.js'
+import Constant from '../Constant.js'
+import { coordinate } from '../Coordinate'
+
+//不靠墙
+export default class Flue extends Geometry {
+    constructor(center, vectorId) {
+        super()
+        this.center = center
+        this.angle = 0 //逆时针为正,顺时针为负。单位是:°
+        this.points2d = []
+
+        this.sideWidth = 0.65
+        this.sideThickness = 0.65
+
+        this.name = '烟道'
+        this.geoType = VectorType.Flue
+        this.setId(vectorId)
+    }
+
+    isContain(position) {
+        let points = []
+        points.push(this.points2d[0])
+        points.push(this.points2d[1])
+        points.push(this.points2d[2])
+        points.push(this.points2d[3])
+        return mathUtil.isPointInPoly(position, points)
+    }
+
+    setPoints2d() {
+        this.points2d = []
+        let minX = this.center.x - this.sideWidth / 2
+        let minY = this.center.y - this.sideThickness / 2
+        let maxX = this.center.x + this.sideWidth / 2
+        let maxY = this.center.y + this.sideThickness / 2
+
+        const point1 = this.rotatePoint(
+            {
+                x: minX,
+                y: maxY,
+            },
+            this.center,
+            this.angle
+        )
+
+        const point2 = this.rotatePoint(
+            {
+                x: maxX,
+                y: maxY,
+            },
+            this.center,
+            this.angle
+        )
+
+        const point3 = this.rotatePoint(
+            {
+                x: maxX,
+                y: minY,
+            },
+            this.center,
+            this.angle
+        )
+
+        const point4 = this.rotatePoint(
+            {
+                x: minX,
+                y: minY,
+            },
+            this.center,
+            this.angle
+        )
+
+        this.points2d.push(point1)
+        this.points2d.push(point2)
+        this.points2d.push(point3)
+        this.points2d.push(point4)
+
+        minX = this.center.x - (this.sideWidth - 0.1) / 2
+        minY = this.center.y - (this.sideThickness - 0.1) / 2
+        maxX = this.center.x + (this.sideWidth - 0.1) / 2
+        maxY = this.center.y + (this.sideThickness - 0.1) / 2
+
+        const point5 = this.rotatePoint(
+            {
+                x: minX,
+                y: maxY,
+            },
+            this.center,
+            this.angle
+        )
+
+        const point6 = this.rotatePoint(
+            {
+                x: maxX,
+                y: maxY,
+            },
+            this.center,
+            this.angle
+        )
+
+        const point7 = this.rotatePoint(
+            {
+                x: maxX,
+                y: minY,
+            },
+            this.center,
+            this.angle
+        )
+
+        const point8 = this.rotatePoint(
+            {
+                x: minX,
+                y: minY,
+            },
+            this.center,
+            this.angle
+        )
+
+        const point9 = {
+            x: (this.center.x + point6.x) / 2,
+            y: (this.center.y + point6.y) / 2,
+        }
+
+        this.points2d.push(point5)
+        this.points2d.push(point6)
+        this.points2d.push(point7)
+        this.points2d.push(point8)
+        this.points2d.push(point9)
+    }
+}

+ 72 - 0
src/views/draw-file/board/editCAD/Geometry/FrenchWindow.js

@@ -0,0 +1,72 @@
+import VectorType from '../enum/VectorType.js'
+import Geometry from './Geometry'
+import { coordinate } from '../Coordinate'
+import { mathUtil } from '../MathUtil.js'
+import SelectState from '../enum/SelectState.js'
+import Constant from '../Constant.js'
+
+export default class FrenchWindow extends Geometry {
+    constructor(startPoint, endPoint, vectorId, floor) {
+        super()
+        this.startPoint = startPoint
+        this.endPoint = endPoint
+        this.floor = floor
+        //this.openSide = null;        // LEFT或者RIGHT
+        this.parent = null
+
+        // 渲染用的
+        this.points2d = []
+        this.name = '落地窗'
+        this.geoType = VectorType.FrenchWindow
+        this.setId(vectorId)
+    }
+
+    setPoints2d() {
+        const len = 4 / coordinate.res
+        const line = mathUtil.createLine1(this.startPoint, this.endPoint)
+        const lines = mathUtil.getParallelLineForDistance(line, len)
+        const vertline1 = mathUtil.getVerticalLine(line, this.startPoint)
+        const vertline2 = mathUtil.getVerticalLine(line, this.endPoint)
+
+        this.points2d = []
+        this.points2d.push(this.startPoint)
+        this.points2d.push(this.endPoint)
+
+        const midPoint = {
+            x: (this.startPoint.x + this.endPoint.x) / 2,
+            y: (this.startPoint.y + this.endPoint.y) / 2,
+        }
+        const vertline = mathUtil.getVerticalLine(line, midPoint)
+
+        const startJoin1 = mathUtil.getIntersectionPoint(vertline1, lines.line1)
+        const endJoin1 = mathUtil.getIntersectionPoint(vertline2, lines.line1)
+        this.points2d.push(startJoin1)
+        this.points2d.push(endJoin1)
+
+        const startJoin2 = mathUtil.getIntersectionPoint(vertline1, lines.line2)
+        const endJoin2 = mathUtil.getIntersectionPoint(vertline2, lines.line2)
+        this.points2d.push(startJoin2)
+        this.points2d.push(endJoin2)
+
+        const midJoin1 = mathUtil.getIntersectionPoint(vertline, lines.line1)
+        const midJoin2 = mathUtil.getIntersectionPoint(vertline, lines.line2)
+        this.points2d.push(midJoin1)
+        this.points2d.push(midJoin2)
+    }
+
+    isContain(position) {
+        const dis1 = mathUtil.getDistance(position, this.startPoint)
+        const dis2 = mathUtil.getDistance(position, this.endPoint)
+        if (dis1 < Constant.minAdsorb) {
+            return SelectState.Start
+        } else if (dis2 < Constant.minAdsorb) {
+            return SelectState.End
+        }
+        let flag = mathUtil.isContainForSegment(position, this.startPoint, this.endPoint)
+        if (flag) {
+            return SelectState.Select
+        } else {
+            return null
+        }
+    }
+}

+ 72 - 0
src/views/draw-file/board/editCAD/Geometry/Furniture.js

@@ -0,0 +1,72 @@
+import Geometry from './Geometry'
+import { mathUtil } from '../MathUtil.js'
+import SelectState from '../enum/SelectState.js'
+import VectorType from '../enum/VectorType.js'
+
+export default class Furniture extends Geometry {
+    constructor(center, vectorId, type) {
+        super()
+        this.center = center
+        this.geoType = type
+        this.angle = 0 //逆时针为负,顺时针为正。单位是:°
+        this.scale = 1 //缩放比例
+        this.setId(vectorId)
+    }
+
+    isContain(position) {
+        const dis = mathUtil.getDistance(position, this.center)
+        let len = this.getLen() * this.scale
+        if (dis < len / 2) {
+            return SelectState.Select
+        } else {
+            return null
+        }
+    }
+
+    getLen() {
+        switch (this.geoType) {
+            case VectorType.TV: //电视
+                return 1.3
+            case VectorType.CombinationSofa: //组合沙发
+                return 3.4
+            case VectorType.SingleSofa: //单人沙发
+                return 1
+            case VectorType.TeaTable: //茶几
+                return 0.8
+            case VectorType.Carpet: //地毯
+                return 2
+            case VectorType.Plant: //植物
+                return 0.3
+            case VectorType.DiningTable: //餐桌
+                return 2.4
+            case VectorType.DoubleBed: //双人床
+                return 2
+            case VectorType.SingleBed: //单人床
+                return 2
+            case VectorType.Wardrobe: //衣柜
+                return 1.2
+            case VectorType.Dresser: //梳妆台
+                return 0.8
+            case VectorType.BedsideCupboard: //床头柜
+                return 0.4
+            case VectorType.Pillow: //抱枕
+                return 0.6
+            case VectorType.GasStove: //燃气灶
+                return 1
+            case VectorType.Cupboard: //橱柜
+                return 1.2
+            case VectorType.Bathtub: //浴缸
+                return 1.6
+            case VectorType.Closestool: //马桶
+                return 0.63
+            case VectorType.Washstand: //洗漱台
+                return 0.8
+            case VectorType.Desk: //书桌
+                return 1.2
+            case VectorType.BalconyChair: //阳台椅
+                return 2
+            case VectorType.Elevator: //电梯
+                return 1.5
+        }
+    }
+}

+ 0 - 0
src/views/draw-file/board/editCAD/Geometry/Geometry.js


+ 27 - 0
src/views/draw-file/board/editCAD/Geometry/Line.js

@@ -0,0 +1,27 @@
+import VectorType from '../enum/VectorType.js'
+import SelectState from '../enum/SelectState.js'
+import Geometry from './Geometry'
+import { mathUtil } from '../MathUtil.js'
+import Constant from '../Constant.js'
+
+//不靠墙
+export default class Line extends Geometry {
+    constructor(start, end, vectorId) {
+        super()
+        this.start = start
+        this.end = end
+
+        this.name = null
+        this.display = false
+        this.geoType = VectorType.Line
+        this.setId(vectorId)
+    }
+
+    setPositions(point1, point2) {
+        this.start.x = point1.x
+        this.start.y = point1.y
+
+        this.end.x = point2.x
+        this.end.y = point2.y
+    }
+}

+ 71 - 0
src/views/draw-file/board/editCAD/Geometry/Pass.js

@@ -0,0 +1,71 @@
+import VectorType from '../enum/VectorType.js'
+import Geometry from './Geometry'
+import { coordinate } from '../Coordinate'
+import { mathUtil } from '../MathUtil.js'
+import SelectState from '../enum/SelectState.js'
+import Constant from '../Constant.js'
+
+export default class Pass extends Geometry {
+    constructor(startPoint, endPoint, vectorId, floor) {
+        super()
+        this.startPoint = startPoint
+        this.endPoint = endPoint
+        this.floor = floor
+        //this.openSide = null;        // LEFT或者RIGHT
+        this.parent = null
+        // 渲染用的
+        this.points2d = []
+        this.name = '垭口'
+        this.geoType = VectorType.Pass
+        this.setId(vectorId)
+    }
+
+    setPoints2d() {
+        this.points2d = []
+
+        let len = 5 / coordinate.res
+        let line = mathUtil.createLine1(this.startPoint, this.endPoint)
+        let lines = mathUtil.getParallelLineForDistance(line, len)
+        let vertline1 = mathUtil.getVerticalLine(line, this.startPoint)
+        let vertline2 = mathUtil.getVerticalLine(line, this.endPoint)
+
+        const point1 = mathUtil.getIntersectionPoint(vertline1, lines.line1)
+        const point2 = mathUtil.getIntersectionPoint(vertline2, lines.line1)
+        const point3 = mathUtil.getIntersectionPoint(vertline2, lines.line2)
+        const point4 = mathUtil.getIntersectionPoint(vertline1, lines.line2)
+
+        this.points2d.push(point1)
+        this.points2d.push(point2)
+        this.points2d.push(point3)
+        this.points2d.push(point4)
+
+        len = 2 / coordinate.res
+        lines = mathUtil.getParallelLineForDistance(line, len)
+
+        const point5 = mathUtil.getIntersectionPoint(vertline1, lines.line1)
+        const point6 = mathUtil.getIntersectionPoint(vertline2, lines.line1)
+        const point7 = mathUtil.getIntersectionPoint(vertline2, lines.line2)
+        const point8 = mathUtil.getIntersectionPoint(vertline1, lines.line2)
+
+        this.points2d.push(point5)
+        this.points2d.push(point6)
+        this.points2d.push(point7)
+        this.points2d.push(point8)
+    }
+
+    isContain(position) {
+        const dis1 = mathUtil.getDistance(position, this.startPoint)
+        const dis2 = mathUtil.getDistance(position, this.endPoint)
+        if (dis1 < Constant.minAdsorb) {
+            return SelectState.Start
+        } else if (dis2 < Constant.minAdsorb) {
+            return SelectState.End
+        }
+        let flag = mathUtil.isContainForSegment(position, this.startPoint, this.endPoint)
+        if (flag) {
+            return SelectState.Select
+        } else {
+            return null
+        }
+    }
+}

+ 23 - 0
src/views/draw-file/board/editCAD/Geometry/Point.js

@@ -0,0 +1,23 @@
+import VectorType from '../enum/VectorType.js'
+import Geometry from './Geometry'
+
+export default class Point extends Geometry {
+    constructor(x, y, vectorId, floor) {
+        super()
+        this.x = x
+        this.y = y
+
+        this.display = false
+        this.floor = floor
+
+        this.name = null
+        this.parent = {}
+        this.geoType = VectorType.Point
+        this.setId(vectorId)
+    }
+
+    setPosition(position) {
+        this.x = position.x
+        this.y = position.y
+    }
+}

+ 94 - 0
src/views/draw-file/board/editCAD/Geometry/SingleDoor.js

@@ -0,0 +1,94 @@
+import VectorType from '../enum/VectorType.js'
+import SelectState from '../enum/SelectState.js'
+import Geometry from './Geometry'
+import { mathUtil } from '../MathUtil.js'
+import Constant from '../Constant.js'
+import SymbolEvents from '../enum/SymbolEvents.js'
+
+export default class SingleDoor extends Geometry {
+    constructor(startPoint, endPoint, vectorId, floor) {
+        super()
+        this.startPoint = startPoint
+        this.endPoint = endPoint
+        this.floor = floor
+        this.openSide = null // LEFT或者RIGHT
+        this.parent = null
+        this.enter = null // LEFT或者RIGHT
+        // 渲染用的,四元素,0是start,1是end
+        this.points2d = []
+        this.name = '单开门'
+        this.geoType = VectorType.SingleDoor
+        this.setId(vectorId)
+    }
+
+    setPoints2d() {
+        const line = mathUtil.createLine1(this.startPoint, this.endPoint)
+        const len = mathUtil.getDistance(this.startPoint, this.endPoint)
+        const lines = mathUtil.getParallelLineForDistance(line, len)
+        const vertline1 = mathUtil.getVerticalLine(line, this.startPoint)
+        const vertline2 = mathUtil.getVerticalLine(line, this.endPoint)
+        let startJoin1 = mathUtil.getIntersectionPoint(lines.line1, vertline1)
+        let startJoin2 = mathUtil.getIntersectionPoint(lines.line2, vertline1)
+
+        let endJoin1 = mathUtil.getIntersectionPoint(lines.line1, vertline2)
+        let endJoin2 = mathUtil.getIntersectionPoint(lines.line2, vertline2)
+
+        this.points2d = []
+        this.points2d.push(this.startPoint)
+        this.points2d.push(this.endPoint)
+        this.points2d.push(endJoin1)
+        this.points2d.push(startJoin1)
+
+        //逆时针
+        if (this.openSide == SymbolEvents.Left) {
+            if (mathUtil.isClockwise(this.points2d)) {
+                return
+            } else {
+                this.points2d = []
+                this.points2d.push(this.startPoint)
+                this.points2d.push(this.endPoint)
+                this.points2d.push(endJoin2)
+                this.points2d.push(startJoin2)
+            }
+        } else if (this.openSide == SymbolEvents.Right) {
+            if (mathUtil.isClockwise(this.points2d)) {
+                this.points2d = []
+                this.points2d.push(this.startPoint)
+                this.points2d.push(this.endPoint)
+                this.points2d.push(endJoin2)
+                this.points2d.push(startJoin2)
+            } else {
+                return
+            }
+        }
+    }
+
+    isContain(position) {
+        const dis1 = mathUtil.getDistance(position, this.startPoint)
+        const dis2 = mathUtil.getDistance(position, this.endPoint)
+        if (dis1 < Constant.minAdsorb) {
+            return SelectState.Start
+        } else if (dis2 < Constant.minAdsorb) {
+            return SelectState.End
+        }
+
+        let flag = mathUtil.isContainForSegment(position, this.startPoint, this.endPoint)
+        if (flag) {
+            return SelectState.Select
+        }
+
+        // 是否在扇形(this.points里第0个元素是圆心,1-3是扇形的两个顶点)
+        const radius = mathUtil.getDistance(this.points2d[0], this.points2d[1])
+        const len = mathUtil.getDistance(position, this.points2d[0])
+        if (len > radius) {
+            return null
+        } else {
+            const angle1 = mathUtil.Angle(this.points2d[0], position, this.points2d[1])
+            const angle2 = mathUtil.Angle(this.points2d[0], position, this.points2d[3])
+            if (angle1 < Math.PI / 2 && angle2 < Math.PI / 2) {
+                return SelectState.Select
+            }
+        }
+        return null
+    }
+}

+ 61 - 0
src/views/draw-file/board/editCAD/Geometry/SingleWindow.js

@@ -0,0 +1,61 @@
+import VectorType from '../enum/VectorType.js'
+import Geometry from './Geometry'
+import SelectState from '../enum/SelectState.js'
+import { mathUtil } from '../MathUtil.js'
+import Constant from '../Constant.js'
+import { coordinate } from '../Coordinate'
+
+export default class SingleWindow extends Geometry {
+    constructor(startPoint, endPoint, vectorId, floor) {
+        super()
+        this.startPoint = startPoint
+        this.endPoint = endPoint
+        this.floor = floor
+        //this.openSide = null;        // LEFT或者RIGHT
+        this.parent = null
+
+        // 渲染用的
+        this.points2d = []
+        this.name = '单开窗'
+        this.geoType = VectorType.SingleWindow
+        this.setId(vectorId)
+    }
+
+    setPoints2d() {
+        this.points2d = []
+        this.points2d.push(this.startPoint)
+        this.points2d.push(this.endPoint)
+
+        const len = 4 / coordinate.res
+        const line = mathUtil.createLine1(this.startPoint, this.endPoint)
+        const lines = mathUtil.getParallelLineForDistance(line, len)
+        const vertline1 = mathUtil.getVerticalLine(line, this.startPoint)
+        const vertline2 = mathUtil.getVerticalLine(line, this.endPoint)
+
+        const point1 = mathUtil.getIntersectionPoint(vertline1, lines.line1)
+        const point2 = mathUtil.getIntersectionPoint(vertline2, lines.line1)
+        const point3 = mathUtil.getIntersectionPoint(vertline2, lines.line2)
+        const point4 = mathUtil.getIntersectionPoint(vertline1, lines.line2)
+
+        this.points2d.push(point1)
+        this.points2d.push(point2)
+        this.points2d.push(point3)
+        this.points2d.push(point4)
+    }
+
+    isContain(position) {
+        const dis1 = mathUtil.getDistance(position, this.startPoint)
+        const dis2 = mathUtil.getDistance(position, this.endPoint)
+        if (dis1 < Constant.minAdsorb) {
+            return SelectState.Start
+        } else if (dis2 < Constant.minAdsorb) {
+            return SelectState.End
+        }
+        let flag = mathUtil.isContainForSegment(position, this.startPoint, this.endPoint)
+        if (flag) {
+            return SelectState.Select
+        } else {
+            return null
+        }
+    }
+}

+ 94 - 0
src/views/draw-file/board/editCAD/Geometry/SlideDoor.js

@@ -0,0 +1,94 @@
+import VectorType from '../enum/VectorType.js'
+import Geometry from './Geometry'
+import { coordinate } from '../Coordinate'
+import { mathUtil } from '../MathUtil.js'
+import SelectState from '../enum/SelectState.js'
+import Constant from '../Constant.js'
+
+export default class SlideDoor extends Geometry {
+    constructor(startPoint, endPoint, vectorId, floor) {
+        super()
+        this.startPoint = startPoint
+        this.endPoint = endPoint
+        this.floor = floor
+        //this.openSide = null;        // LEFT或者RIGHT
+        this.parent = null
+        this.enter = null // LEFT或者RIGHT
+        // 渲染用的
+        this.points2d = []
+        this.name = '滑动门'
+        this.geoType = VectorType.SlideDoor
+        this.setId(vectorId)
+    }
+
+    setPoints2d() {
+        const line = mathUtil.createLine1(this.startPoint, this.endPoint)
+        const len = 2 / coordinate.res
+        const lines1 = mathUtil.getParallelLineForDistance(line, len)
+        if (this.startPoint.x > this.endPoint.x) {
+            let temp = lines1.line1
+            lines1.line1 = lines1.line2
+            lines1.line2 = temp
+        }
+        const vertline1 = mathUtil.getVerticalLine(line, this.startPoint)
+        const vertline2 = mathUtil.getVerticalLine(line, this.endPoint)
+        const startJoin = mathUtil.getIntersectionPoint(lines1.line1, vertline1)
+        const endJoin = mathUtil.getIntersectionPoint(lines1.line2, vertline2)
+
+        const midPoint = {
+            x: (this.startPoint.x + this.endPoint.x) / 2,
+            y: (this.startPoint.y + this.endPoint.y) / 2,
+        }
+        this.points2d = []
+        this.points2d.push(this.startPoint)
+
+        const width = 4 / coordinate.res
+        const vertline = mathUtil.getVerticalLine(line, midPoint)
+        const lines2 = mathUtil.getParallelLineForDistance(vertline, width)
+
+        let join1 = mathUtil.getIntersectionPoint(lines1.line1, lines2.line1)
+        let join2 = mathUtil.getIntersectionPoint(lines1.line1, lines2.line2)
+
+        let join3 = mathUtil.getIntersectionPoint(lines1.line2, lines2.line1)
+        let join4 = mathUtil.getIntersectionPoint(lines1.line2, lines2.line2)
+
+        let join5 = mathUtil.getIntersectionPoint(line, lines2.line1)
+        let join6 = mathUtil.getIntersectionPoint(line, lines2.line2)
+
+        if (mathUtil.getDistance(this.startPoint, join5) < mathUtil.getDistance(this.startPoint, join6)) {
+            this.points2d.push(join6)
+            this.points2d.push(join2)
+            this.points2d.push(startJoin)
+
+            this.points2d.push(this.endPoint)
+            this.points2d.push(join5)
+            this.points2d.push(join3)
+            this.points2d.push(endJoin)
+        } else {
+            this.points2d.push(join5)
+            this.points2d.push(join1)
+            this.points2d.push(startJoin)
+
+            this.points2d.push(this.endPoint)
+            this.points2d.push(join6)
+            this.points2d.push(join4)
+            this.points2d.push(endJoin)
+        }
+    }
+
+    isContain(position) {
+        const dis1 = mathUtil.getDistance(position, this.startPoint)
+        const dis2 = mathUtil.getDistance(position, this.endPoint)
+        if (dis1 < Constant.minAdsorb) {
+            return SelectState.Start
+        } else if (dis2 < Constant.minAdsorb) {
+            return SelectState.End
+        }
+        let flag = mathUtil.isContainForSegment(position, this.startPoint, this.endPoint)
+        if (flag) {
+            return SelectState.Select
+        } else {
+            return null
+        }
+    }
+}

+ 108 - 0
src/views/draw-file/board/editCAD/Geometry/Tag.js

@@ -0,0 +1,108 @@
+import VectorType from '../enum/VectorType.js'
+import Geometry from './Geometry'
+import { mathUtil } from '../MathUtil.js'
+import { coordinate } from '../Coordinate'
+import Constant from '../Constant.js'
+
+//不靠墙
+export default class Tag extends Geometry {
+    constructor(center, vectorId) {
+        super()
+        this.center = center
+        this.points2d = []
+        //this.title = KanKan.Config.i18n('cad.input')
+        this.title = ''
+        this.des = '' //面积
+        this.unit = 'm' //或者ft
+        this.name = '标注'
+        this.adding = true
+
+        this.sideWidth = 30 //像素
+        this.sideThickness = 30 //像素
+
+        this.geoType = VectorType.Tag
+        this.setId(vectorId)
+    }
+
+    isContain(position) {
+        let points = []
+        points.push(this.points2d[0])
+        points.push(this.points2d[1])
+        points.push(this.points2d[2])
+        points.push(this.points2d[3])
+        return mathUtil.isPointInPoly(position, points)
+    }
+
+    setPoints2d() {
+        this.points2d = []
+        const minX = this.center.x - ((this.sideWidth / coordinate.res) * Constant.defaultZoom) / coordinate.zoom / 2
+        const minY = this.center.y - ((this.sideThickness / coordinate.res) * Constant.defaultZoom) / coordinate.zoom / 2
+        const maxX = this.center.x + ((this.sideWidth / coordinate.res) * Constant.defaultZoom) / coordinate.zoom / 2
+        const maxY = this.center.y + ((this.sideThickness / coordinate.res) * Constant.defaultZoom) / coordinate.zoom / 2
+
+        const point1 = {
+            x: minX,
+            y: maxY,
+        }
+
+        const point2 = {
+            x: maxX,
+            y: maxY,
+        }
+
+        const point3 = {
+            x: maxX,
+            y: minY,
+        }
+
+        const point4 = {
+            x: minX,
+            y: minY,
+        }
+
+        this.points2d.push(point1)
+        this.points2d.push(point2)
+        this.points2d.push(point3)
+        this.points2d.push(point4)
+
+        //-
+        let dx = (point1.x - this.center.x) / 2
+        //+
+        let dy = (point1.y - this.center.y) / 2
+
+        this.points2d.push({
+            x: point1.x - dx,
+            y: point1.y - dy,
+        })
+
+        this.points2d.push({
+            x: point2.x + dx,
+            y: point1.y - dy,
+        })
+
+        this.points2d.push({
+            x: this.center.x,
+            y: point1.y - dy,
+        })
+
+        this.points2d.push({
+            x: this.center.x,
+            y: point3.y + dy,
+        })
+    }
+
+    setTitle(title) {
+        this.title = title
+    }
+
+    setDes(des) {
+        this.des = des
+    }
+    setUnit(unit) {
+        this.unit = unit
+    }
+
+    setAdding(flag) {
+        this.adding = flag
+    }
+}

+ 53 - 0
src/views/draw-file/board/editCAD/Geometry/Wall.js

@@ -0,0 +1,53 @@
+import VectorType from '../enum/VectorType.js'
+import Geometry from './Geometry.js'
+
+export default class Wall extends Geometry {
+    constructor(pointId1, pointId2, vectorId, floor) {
+        super()
+        this.start = pointId1
+        this.end = pointId2
+        this.floor = floor
+
+        this.children = [] //门/窗
+        this.out = false //是否外墙
+        this.important = false //是否承重墙
+        //this.border = true //true表示房间墙,粗一点,false表示非房间墙,细一点
+        //this.exterior = null //是否外墙
+        this.geoType = VectorType.Wall
+        this.setId(vectorId)
+    }
+
+    getOtherPointId(pointId) {
+        if (this.start == pointId) {
+            return this.end
+        } else if (this.end == pointId) {
+            return this.start
+        } else {
+            return null
+        }
+    }
+
+    getPointId(dir) {
+        if (dir == 'start') {
+            return this.start
+        } else {
+            return this.end
+        }
+    }
+
+    clearChildren() {
+        this.children = []
+    }
+
+    setImportant(flag) {
+        this.important = flag
+    }
+
+    setOut(flag) {
+        this.out = flag
+    }
+
+    setChildren(children) {
+        this.children = children
+    }
+}

+ 334 - 0
src/views/draw-file/board/editCAD/History/Change.js

@@ -0,0 +1,334 @@
+import { floorplanService } from '../Service/FloorplanService'
+import { elementService } from '../Service/ElementService'
+import { wallService } from '../Service/WallService'
+import { historyUtil } from './HistoryUtil'
+import { symbolService } from '../Service/SymbolService'
+import HistoryEvents from '../enum/HistoryEvents'
+import { coordinate } from '../Coordinate'
+
+export default class Change {
+    constructor() {
+        this.lastData = {} // 每次都是当前数据和lastData进行比较,一般在mouseDown的时候存储进来
+        this.elements = {} // 当前的变化
+    }
+
+    // 保存当前记录
+    saveCurrentInfo() {
+        //this.lastData.subFloorNum = floorplanService.getSubFloor();
+        this.lastData.currentFloor = floorplanService.getCurrentFloor()
+        this.lastData.points = JSON.parse(JSON.stringify(floorplanService.getPoints()))
+        this.lastData.walls = JSON.parse(JSON.stringify(floorplanService.getWalls()))
+        this.lastData.symbols = JSON.parse(JSON.stringify(floorplanService.getSymbols()))
+        this.lastData.components = JSON.parse(JSON.stringify(floorplanService.getComponents()))
+        this.lastData.furnitures = JSON.parse(JSON.stringify(floorplanService.getFurnitures()))
+        this.lastData.tags = JSON.parse(JSON.stringify(floorplanService.getTags()))
+        this.lastData.angle = floorplanService.getAngle()
+        this.lastData.res = coordinate.res
+    }
+
+    operate() {
+        //
+        this.elements = {}
+        let flag = this.compareAngle()
+        if (!flag) {
+            this.comparePoints()
+            this.compareSymbols()
+            this.compareWalls()
+            this.compareComponents()
+            this.compareTags()
+            this.compareFurnitures()
+        }
+        //旋转了
+        else {
+            this.lastData = {}
+            return true
+        }
+
+        if (
+            this.elements.points.length == 0 &&
+            this.elements.walls.length == 0 &&
+            this.elements.symbols.length == 0 &&
+            this.elements.components.length == 0 &&
+            this.elements.tags.length == 0 &&
+            this.elements.furnitures.length == 0
+        ) {
+            this.saveCurrentInfo()
+            return false
+        }
+        this.lastData = {}
+        // 这里不能取this.records.length-1,因为可能撤销后操作,这时候应该是覆盖,而不是往后面添加
+        return true
+    }
+
+    comparePoints() {
+        //const currentFloor = floorplanService.getCurrentFloorNum();
+        const points = floorplanService.getPoints()
+        this.elements.points = []
+
+        for (const key in points) {
+            const point = points[key]
+            // 不存在意味着增加
+            if (!this.lastData.points[key]) {
+                const item = {
+                    handle: HistoryEvents.AddPoint,
+                    point: historyUtil.getDataForPoint(point),
+                }
+                this.elements.points.push(item)
+            } else {
+                const lastPoint = this.lastData.points[key]
+                if (point.x == lastPoint.x && point.y == lastPoint.y && JSON.stringify(point.parent) == JSON.stringify(lastPoint.parent)) {
+                    delete this.lastData.points[key]
+                    continue
+                } else {
+                    const item = {
+                        handle: HistoryEvents.ModifyPoint,
+                        prePoint: historyUtil.getDataForPoint(lastPoint),
+                        curPoint: historyUtil.getDataForPoint(point),
+                    }
+                    this.elements.points.push(item)
+                }
+            }
+            delete this.lastData.points[key]
+        }
+
+        for (const key in this.lastData.points) {
+            const item = {
+                handle: HistoryEvents.DeletePoint,
+                point: historyUtil.getDataForPoint(this.lastData.points[key]),
+            }
+            this.elements.points.push(item)
+        }
+    }
+
+    compareWalls() {
+        //const currentFloor = floorplanService.getCurrentFloorNum();
+        this.elements.walls = []
+        const walls = floorplanService.getWalls()
+        for (const key in walls) {
+            const wall = walls[key]
+            const lastWall = this.lastData.walls[key]
+
+            // 不存在意味着增加
+            if (!lastWall) {
+                const item = {
+                    handle: HistoryEvents.AddWall,
+                    wall: historyUtil.getDataForWall(wall),
+                }
+                this.elements.walls.push(item)
+            } else {
+                if (!historyUtil.isDifferentForWalls(wall, lastWall)) {
+                    delete this.lastData.walls[key]
+                    continue
+                } else {
+                    const item = {
+                        handle: HistoryEvents.ModifyWall,
+                        preWall: historyUtil.getDataForWall(lastWall),
+                        curWall: historyUtil.getDataForWall(wall),
+                    }
+                    this.elements.walls.push(item)
+                }
+            }
+            delete this.lastData.walls[key]
+        }
+
+        for (const key in this.lastData.walls) {
+            const item = {
+                handle: HistoryEvents.DeleteWall,
+                wall: historyUtil.getDataForWall(this.lastData.walls[key]),
+            }
+            this.elements.walls.push(item)
+        }
+    }
+
+    compareSymbols() {
+        //const currentFloor = floorplanService.getCurrentFloorNum();
+
+        this.elements.symbols = []
+        const symbols = floorplanService.getSymbols()
+
+        const wallIds = []
+
+        for (const key in symbols) {
+            const symbol = symbols[key]
+            const lastSymbol = this.lastData.symbols[key]
+
+            // 不存在意味着增加
+            if (!lastSymbol) {
+                const item = {
+                    handle: HistoryEvents.AddSymbol,
+                    symbol: historyUtil.getDataForSymbol(symbol),
+                }
+                this.elements.symbols.push(item)
+            } else {
+                if (!historyUtil.isDifferentForSymbols(symbol, lastSymbol)) {
+                    delete this.lastData.symbols[key]
+                    continue
+                } else {
+                    const item = {
+                        handle: HistoryEvents.ModifySymbol,
+                        preSymbol: historyUtil.getDataForSymbol(lastSymbol),
+                        curSymbol: historyUtil.getDataForSymbol(symbol),
+                    }
+                    this.elements.symbols.push(item)
+                }
+            }
+            delete this.lastData.symbols[key]
+        }
+
+        for (const key in this.lastData.symbols) {
+            const item = {
+                handle: HistoryEvents.DeleteSymbol,
+                symbol: historyUtil.getDataForSymbol(this.lastData.symbols[key]),
+            }
+            this.elements.symbols.push(item)
+        }
+    }
+
+    compareComponents() {
+        //const currentFloor = floorplanService.getCurrentFloorNum();
+        this.elements.components = []
+        const components = floorplanService.getComponents()
+
+        for (const key in components) {
+            const component = components[key]
+            const lastComponent = this.lastData.components[key]
+
+            // 不存在意味着增加
+            if (!lastComponent) {
+                const item = {
+                    handle: HistoryEvents.AddComponent,
+                    component: historyUtil.getDataForComponent(component),
+                }
+                this.elements.components.push(item)
+            } else {
+                if (!historyUtil.isDifferentForComponents(component, lastComponent)) {
+                    delete this.lastData.components[key]
+                    continue
+                } else {
+                    const item = {
+                        handle: HistoryEvents.ModifyComponent,
+                        preComponent: historyUtil.getDataForComponent(lastComponent),
+                        curComponent: historyUtil.getDataForComponent(component),
+                    }
+                    this.elements.components.push(item)
+                }
+            }
+            delete this.lastData.components[key]
+        }
+
+        for (const key in this.lastData.components) {
+            const item = {
+                handle: HistoryEvents.DeleteComponent,
+                component: historyUtil.getDataForComponent(this.lastData.components[key]),
+            }
+            this.elements.components.push(item)
+        }
+    }
+
+    compareTags() {
+        this.elements.tags = []
+        const tags = floorplanService.getTags()
+
+        for (const key in tags) {
+            const tag = tags[key]
+            const lastTag = this.lastData.tags[key]
+
+            // 不存在意味着增加
+            if (!lastTag) {
+                const item = {
+                    handle: HistoryEvents.AddTag,
+                    tag: historyUtil.getDataForTag(tag),
+                }
+                this.elements.tags.push(item)
+            } else {
+                if (!historyUtil.isDifferentForTags(tag, lastTag)) {
+                    delete this.lastData.tags[key]
+                    continue
+                } else {
+                    const item = {
+                        handle: HistoryEvents.ModifyTag,
+                        preTag: historyUtil.getDataForTag(lastTag),
+                        curTag: historyUtil.getDataForTag(tag),
+                    }
+                    this.elements.tags.push(item)
+                }
+            }
+            delete this.lastData.tags[key]
+        }
+
+        for (const key in this.lastData.tags) {
+            const item = {
+                handle: HistoryEvents.DeleteTag,
+                tag: historyUtil.getDataForTag(this.lastData.tags[key]),
+            }
+            this.elements.tags.push(item)
+        }
+    }
+
+    compareFurnitures() {
+        //const currentFloor = floorplanService.getCurrentFloorNum();
+        this.elements.furnitures = []
+        const furnitures = floorplanService.getFurnitures()
+
+        for (const key in furnitures) {
+            const furniture = furnitures[key]
+            const lastFurniture = this.lastData.furnitures[key]
+
+            // 不存在意味着增加
+            if (!lastFurniture) {
+                const item = {
+                    handle: HistoryEvents.AddFurniture,
+                    furniture: historyUtil.getDataForFurniture(furniture),
+                }
+                this.elements.furnitures.push(item)
+            } else {
+                if (!historyUtil.isDifferentForFurnitures(furniture, lastFurniture)) {
+                    delete this.lastData.furnitures[key]
+                    continue
+                } else {
+                    const item = {
+                        handle: HistoryEvents.ModifyFurniture,
+                        preFurniture: historyUtil.getDataForFurniture(lastFurniture),
+                        curFurniture: historyUtil.getDataForFurniture(furniture),
+                    }
+                    this.elements.furnitures.push(item)
+                }
+            }
+            delete this.lastData.furnitures[key]
+        }
+
+        for (const key in this.lastData.furnitures) {
+            const item = {
+                handle: HistoryEvents.DeleteFurniture,
+                furniture: historyUtil.getDataForFurniture(this.lastData.furnitures[key]),
+            }
+            this.elements.furnitures.push(item)
+        }
+    }
+
+    compareAngle() {
+        const angle = floorplanService.getAngle()
+        const lastAngle = this.lastData.angle
+        const lastRes = this.lastData.res
+        if (historyUtil.isDifferentForAngle(angle, lastAngle)) {
+            const item = {
+                handle: HistoryEvents.ModifyAngle,
+                preState: {
+                    angle: historyUtil.getDataForAngle(lastAngle),
+                    res: historyUtil.getDataForRes(lastRes),
+                },
+                curState: {
+                    angle: historyUtil.getDataForAngle(angle),
+                    res: historyUtil.getDataForRes(coordinate.res),
+                },
+            }
+            this.elements.rotate = item
+            return true
+        } else {
+            return false
+        }
+    }
+}
+
+const change = new Change()
+export { change }

+ 429 - 0
src/views/draw-file/board/editCAD/History/History.js

@@ -0,0 +1,429 @@
+import { floorplanService } from '../Service/FloorplanService'
+import { elementService } from '../Service/ElementService'
+import { wallService } from '../Service/WallService'
+import { historyUtil } from './HistoryUtil'
+import { change } from './Change'
+import { symbolService } from '../Service/SymbolService'
+import { stateService } from '../Service/StateService'
+import HistoryEvents from '../enum/HistoryEvents'
+import { componentService } from '../Service/ComponentService'
+import { historyService } from '../Service/HistoryService'
+import { tagService } from '../Service/TagService'
+import { coordinate } from '../Coordinate'
+import { measureService } from '../Service/MeasureService'
+import { furnitureService } from '../Service/FurnitureService'
+
+export default class History {
+    constructor(layer) {
+        this.layer = layer
+    }
+
+    init() {
+        change.saveCurrentInfo()
+        const points = floorplanService.getPoints()
+        if (Object.keys(points).length > 0) {
+            this.layer.$xui.toolbar.clear = true
+            this.layer.$xui.toolbar.download = true
+        } else {
+            this.layer.$xui.toolbar.clear = false
+            this.layer.$xui.toolbar.download = false
+        }
+    }
+
+    save() {
+        const flag = change.operate()
+        if (!flag) {
+            return
+        }
+        measureService.update()
+        historyService.addHistoryRecord(change.elements)
+        change.saveCurrentInfo()
+        this.setState()
+        const historyState = historyService.getHistoryState()
+        if (historyState.pre) {
+            this.layer.$xui.toolbar.recall = true
+        }
+        this.layer.$xui.toolbar.recover = false
+
+        const points = floorplanService.getPoints()
+        if (Object.keys(points).length > 0) {
+            this.layer.$xui.toolbar.clear = true
+            this.layer.$xui.toolbar.download = true
+        } else {
+            this.layer.$xui.toolbar.clear = false
+            this.layer.$xui.toolbar.download = false
+        }
+
+        //给UI发送事件
+        this.layer.emit('change')
+
+        return change.elements
+    }
+
+    setState() {
+        const state = {
+            pre: 0,
+            next: 0,
+        }
+
+        const currentRecordIndex = historyService.getCurrentRecordIndex()
+        const records = historyService.getHistoryRecords()
+
+        if (currentRecordIndex > -1) {
+            state.pre = 1
+        }
+
+        if (currentRecordIndex < records.length - 1) {
+            state.next = 1
+        }
+        const lastState = historyService.getHistoryState()
+        if (lastState.pre != state.pre || lastState.next != state.next) {
+            historyService.setHistoryState(state.pre, state.next)
+        }
+    }
+
+    // 是否可以撤销
+    canUndo() {
+        const state = this.setState()
+        if (state.pre == 0) {
+            return false
+        } else {
+            return true
+        }
+    }
+
+    // 是否可以恢复
+    canRedo() {
+        const state = this.setState()
+        if (state.next == 0) {
+            return false
+        } else {
+            return true
+        }
+    }
+
+    // 撤销
+    handleUndo() {
+        this.goPreState()
+    }
+
+    // 恢复
+    handleRedo() {
+        this.goNextState()
+    }
+
+    // 撤销
+    goPreState() {
+        const item = historyService.getHistoryRecord()
+        if (item) {
+            stateService.clearFocusItem()
+            //this.layer.$xui.hideProps()
+            this.layer.uiControl.currentUI = null
+            item.type = 'pre'
+            let flag = false
+            if (item.rotate == null) {
+                flag = false
+            } else {
+                flag = this.goPreForAngle(item.rotate)
+            }
+
+            if (!flag) {
+                this.goPreForPoints(item.points)
+                this.goPreForWalls(item.walls)
+                // 必须在墙的后面,因为删除带symbol的墙的时候,撤销时,必须是先有墙才有symbol
+                this.goPreForSymbols(item.symbols)
+                this.goPreForComponents(item.components)
+                this.goPreForTags(item.tags)
+                this.goPreForFurnitures(item.furnitures)
+            }
+
+            measureService.update()
+            historyService.undoHistoryRecord()
+            change.saveCurrentInfo()
+            this.setState()
+
+            const points = floorplanService.getPoints()
+            if (Object.keys(points).length > 0) {
+                this.layer.$xui.toolbar.clear = true
+                this.layer.$xui.toolbar.download = true
+            } else {
+                this.layer.$xui.toolbar.clear = false
+                this.layer.$xui.toolbar.download = false
+            }
+        } else {
+            console.error('goPreState超出范围!')
+        }
+    }
+
+    goPreForPoints(itemForPoints) {
+        for (let i = 0; i < itemForPoints.length; ++i) {
+            const item = itemForPoints[i]
+            if (item.handle == HistoryEvents.AddPoint) {
+                historyUtil.deletePoint(item.point.id)
+            } else if (item.handle == HistoryEvents.DeletePoint) {
+                let point = wallService.createPoint(item.point.x, item.point.y, item.point.id)
+                point.parent = JSON.parse(JSON.stringify(item.point.parent))
+            } else if (item.handle == HistoryEvents.ModifyPoint) {
+                const prePoint = item.prePoint
+                let currentPoint = floorplanService.getPoint(item.curPoint.id)
+                historyUtil.assignPointFromPoint(currentPoint, prePoint)
+            }
+        }
+    }
+
+    goPreForWalls(itemForWalls) {
+        for (let i = 0; i < itemForWalls.length; ++i) {
+            const item = itemForWalls[i]
+            if (item.handle == HistoryEvents.AddWall) {
+                floorplanService.deleteWallNoSymbol(item.wall.id)
+            } else if (item.handle == HistoryEvents.DeleteWall) {
+                const preWall = item.wall
+                let newWall = wallService.createWall(preWall.start, preWall.end, preWall.id)
+                historyUtil.assignWallFromWall(newWall, preWall)
+            } else if (item.handle == HistoryEvents.ModifyWall) {
+                const preWall = item.preWall
+                let currentWall = floorplanService.getWall(item.curWall.id)
+                historyUtil.assignWallFromWall(currentWall, preWall)
+            }
+        }
+    }
+
+    goPreForSymbols(itemForSymbols) {
+        for (let i = 0; i < itemForSymbols.length; ++i) {
+            const item = itemForSymbols[i]
+            if (item.handle == HistoryEvents.AddSymbol) {
+                symbolService.deleteSymbol(item.symbol.id)
+            } else if (item.handle == HistoryEvents.DeleteSymbol) {
+                let newSymbol = symbolService.createSymbol(item.symbol.start, item.symbol.end, item.symbol.type, item.symbol.parent, item.symbol.id)
+                historyUtil.assignSymbolFromSymbol(newSymbol, item.symbol)
+            } else if (item.handle == HistoryEvents.ModifySymbol) {
+                const preSymbol = item.preSymbol
+                let currentSymbol = floorplanService.getSymbol(item.curSymbol.id)
+                historyUtil.assignSymbolFromSymbol(currentSymbol, preSymbol)
+            }
+        }
+    }
+
+    goPreForComponents(itemForComponents) {
+        for (let i = 0; i < itemForComponents.length; ++i) {
+            const item = itemForComponents[i]
+            if (item.handle == HistoryEvents.AddComponent) {
+                floorplanService.deleteComponent(item.component.id)
+            } else if (item.handle == HistoryEvents.DeleteComponent) {
+                let vComponent = componentService.createComponent(item.component.center, item.component.type, item.component.id)
+                historyUtil.assignComponentFromComponent(vComponent, item.component)
+            } else if (item.handle == HistoryEvents.ModifyComponent) {
+                const preComponent = item.preComponent
+                let currentComponent = floorplanService.getComponent(item.curComponent.id)
+                historyUtil.assignComponentFromComponent(currentComponent, preComponent)
+            }
+        }
+    }
+
+    goPreForFurnitures(itemForFurnitures) {
+        for (let i = 0; i < itemForFurnitures.length; ++i) {
+            const item = itemForFurnitures[i]
+            if (item.handle == HistoryEvents.AddFurniture) {
+                floorplanService.deleteFurniture(item.furniture.id)
+            } else if (item.handle == HistoryEvents.DeleteFurniture) {
+                let vFurniture = furnitureService.createFurniture(item.furniture.center, item.furniture.type, item.furniture.id)
+                historyUtil.assignFurnitureFromFurniture(vFurniture, item.furniture)
+            } else if (item.handle == HistoryEvents.ModifyFurniture) {
+                const preFurniture = item.preFurniture
+                let currentFurniture = floorplanService.getFurniture(item.curFurniture.id)
+                historyUtil.assignFurnitureFromFurniture(currentFurniture, preFurniture)
+            }
+        }
+    }
+
+    goPreForTags(itemForTags) {
+        for (let i = 0; i < itemForTags.length; ++i) {
+            const item = itemForTags[i]
+            if (item.handle == HistoryEvents.AddTag) {
+                tagService.deleteTag(item.tag.id)
+            } else if (item.handle == HistoryEvents.DeleteTag) {
+                let newTag = tagService.createTag(item.tag.center, item.tag.id)
+                historyUtil.assignTagFromTag(newTag, item.tag)
+            } else if (item.handle == HistoryEvents.ModifyTag) {
+                const preTag = item.preTag
+                let currentTag = floorplanService.getTag(item.curTag.id)
+                historyUtil.assignTagFromTag(currentTag, preTag)
+            }
+        }
+    }
+
+    goPreForAngle(itemForAngle) {
+        if (itemForAngle.handle == HistoryEvents.ModifyAngle) {
+            coordinate.reSet()
+            coordinate._setRes(itemForAngle.preState.res)
+            //旋转cad
+            floorplanService.setAngle(itemForAngle.preState.angle)
+            coordinate.updateForRotate(itemForAngle.preState.angle - itemForAngle.curState.angle)
+            //旋转三维模型
+            let info = coordinate.getScreenInfoForCAD()
+            info.floorPlanAngle = itemForAngle.preState.angle
+            this.layer.app.core.get('CameraControls').emit('syncCadAnd3DForRotate', info)
+            this.layer.app.store.getValue('metadata').floorPlanAngle = itemForAngle.preState.angle
+            this.layer.initPanos(floorplanService.getCurrentFloor())
+            return true
+        } else {
+            return false
+        }
+    }
+
+    goNextForPoints(itemForPoints) {
+        for (let i = 0; i < itemForPoints.length; ++i) {
+            const item = itemForPoints[i]
+            if (item.handle == HistoryEvents.AddPoint) {
+                let newPoint = wallService.createPoint(item.point.x, item.point.y, item.point.id)
+                historyUtil.assignPointFromPoint(newPoint, item.point)
+            } else if (item.handle == HistoryEvents.DeletePoint) {
+                historyUtil.deletePoint(item.point.id)
+            } else if (item.handle == HistoryEvents.ModifyPoint) {
+                const currentPoint = item.curPoint
+                let prePoint = floorplanService.getPoint(item.curPoint.id)
+                historyUtil.assignPointFromPoint(prePoint, currentPoint)
+            }
+        }
+    }
+
+    goNextForWalls(itemForWalls) {
+        for (let i = 0; i < itemForWalls.length; ++i) {
+            const item = itemForWalls[i]
+            if (item.handle == HistoryEvents.AddWall) {
+                const preWall = item.wall
+                let newWall = wallService.createWall(preWall.start, preWall.end, preWall.id)
+                historyUtil.assignWallFromWall(newWall, preWall)
+            } else if (item.handle == HistoryEvents.DeleteWall) {
+                floorplanService.deleteWallNoSymbol(item.wall.id)
+            } else if (item.handle == HistoryEvents.ModifyWall) {
+                const currentWall = item.curWall
+                let preWall = floorplanService.getWall(item.preWall.id)
+                historyUtil.assignWallFromWall(preWall, currentWall)
+            }
+        }
+    }
+
+    goNextForSymbols(itemForSymbols) {
+        for (let i = 0; i < itemForSymbols.length; ++i) {
+            const item = itemForSymbols[i]
+            if (item.handle == HistoryEvents.AddSymbol) {
+                let newSymbol = symbolService.createSymbol(item.symbol.start, item.symbol.end, item.symbol.type, item.symbol.parent, item.symbol.id)
+                historyUtil.assignSymbolFromSymbol(newSymbol, item.symbol)
+            } else if (item.handle == HistoryEvents.DeleteSymbol) {
+                symbolService.deleteSymbol(item.symbol.id)
+            } else if (item.handle == HistoryEvents.ModifySymbol) {
+                const currentSymbol = item.curSymbol
+                let preSymbol = floorplanService.getSymbol(item.curSymbol.id)
+                historyUtil.assignSymbolFromSymbol(preSymbol, currentSymbol)
+            }
+        }
+    }
+
+    goNextForComponents(itemForComponents) {
+        for (let i = 0; i < itemForComponents.length; ++i) {
+            const item = itemForComponents[i]
+            if (item.handle == HistoryEvents.AddComponent) {
+                let vComponent = componentService.createComponent(item.component.center, item.component.type, item.component.id)
+                historyUtil.assignComponentFromComponent(vComponent, item.component)
+            } else if (item.handle == HistoryEvents.DeleteComponent) {
+                floorplanService.deleteComponent(item.component.id)
+            } else if (item.handle == HistoryEvents.ModifyComponent) {
+                const currentComponent = item.curComponent
+                let preComponent = floorplanService.getComponent(item.curComponent.id)
+                historyUtil.assignComponentFromComponent(preComponent, currentComponent)
+            }
+        }
+    }
+
+    goNextForTags(itemForTags) {
+        for (let i = 0; i < itemForTags.length; ++i) {
+            const item = itemForTags[i]
+            if (item.handle == HistoryEvents.AddTag) {
+                let vTag = tagService.createTag(item.tag.center, item.tag.id)
+                historyUtil.assignTagFromTag(vTag, item.tag)
+            } else if (item.handle == HistoryEvents.DeleteTag) {
+                floorplanService.deleteTag(item.tag.id)
+            } else if (item.handle == HistoryEvents.ModifyTag) {
+                const currentTag = item.curTag
+                let preTag = floorplanService.getTag(item.curTag.id)
+                historyUtil.assignTagFromTag(preTag, currentTag)
+            }
+        }
+    }
+
+    goNextForFurnitures(itemForFurnitures) {
+        for (let i = 0; i < itemForFurnitures.length; ++i) {
+            const item = itemForFurnitures[i]
+            if (item.handle == HistoryEvents.AddFurniture) {
+                let vFurniture = furnitureService.createFurniture(item.furniture.center, item.furniture.type, item.furniture.id)
+                historyUtil.assignFurnitureFromFurniture(vFurniture, item.furniture)
+            } else if (item.handle == HistoryEvents.DeleteFurniture) {
+                floorplanService.deleteFurniture(item.furniture.id)
+            } else if (item.handle == HistoryEvents.ModifyFurniture) {
+                const currentFurniture = item.curFurniture
+                let preFurniture = floorplanService.getFurniture(item.curFurniture.id)
+                historyUtil.assignFurnitureFromFurniture(preFurniture, currentFurniture)
+            }
+        }
+    }
+
+    goNextForAngle(itemForAngle) {
+        if (itemForAngle.handle == HistoryEvents.ModifyAngle) {
+            coordinate.reSet()
+            coordinate._setRes(itemForAngle.curState.res)
+            //旋转cad
+            floorplanService.setAngle(itemForAngle.curState.angle)
+            coordinate.updateForRotate(itemForAngle.curState.angle - itemForAngle.preState.angle)
+            //旋转三维模型
+            let info = coordinate.getScreenInfoForCAD()
+            info.floorPlanAngle = itemForAngle.curState.angle
+            this.layer.app.core.get('CameraControls').emit('syncCadAnd3DForRotate', info)
+            this.layer.app.store.getValue('metadata').floorPlanAngle = itemForAngle.curState.angle
+            this.layer.initPanos(floorplanService.getCurrentFloor())
+            return true
+        } else {
+            return false
+        }
+    }
+
+    // 恢复
+    goNextState() {
+        historyService.redoHistoryRecord()
+        const item = historyService.getHistoryRecord()
+        if (item) {
+            stateService.clearFocusItem()
+            //this.layer.$xui.hideProps()
+            this.layer.uiControl.currentUI = null
+            let flag = false
+            if (item.rotate == null) {
+                flag = false
+            } else {
+                flag = this.goNextForAngle(item.rotate)
+            }
+            if (!flag) {
+                this.goNextForPoints(item.points)
+                this.goNextForWalls(item.walls)
+                this.goNextForSymbols(item.symbols)
+                this.goNextForComponents(item.components)
+                this.goNextForTags(item.tags)
+                this.goNextForFurnitures(item.furnitures)
+            }
+            measureService.update()
+            change.saveCurrentInfo()
+            this.setState()
+
+            const points = floorplanService.getPoints()
+            if (Object.keys(points).length > 0) {
+                this.layer.$xui.toolbar.clear = true
+                this.layer.$xui.toolbar.download = true
+            } else {
+                this.layer.$xui.toolbar.clear = false
+                this.layer.$xui.toolbar.download = false
+            }
+        } else {
+            historyService.undoHistoryRecord()
+            console.error('goNextState超出范围!')
+        }
+    }
+}

+ 201 - 0
src/views/draw-file/board/editCAD/History/HistoryUtil.js

@@ -0,0 +1,201 @@
+import { mathUtil } from '../MathUtil'
+import { componentService } from '../Service/ComponentService'
+import { floorplanService } from '../Service/FloorplanService'
+import { furnitureService } from '../Service/FurnitureService'
+import { symbolService } from '../Service/SymbolService'
+import { tagService } from '../Service/TagService'
+import { wallService } from '../Service/WallService'
+
+export default class HistoryUtil {
+    constructor() {}
+
+    isDifferentForWalls(wall1, wall2) {
+        if (wall1.start == wall2.start && wall1.end == wall2.end && wall1.out == wall2.out && wall1.important == wall2.important) {
+            return false
+        } else {
+            return true
+        }
+    }
+    isDifferentForSymbols(symbol1, symbol2) {
+        if (
+            mathUtil.equalPoint(symbol1.startPoint, symbol2.startPoint) &&
+            mathUtil.equalPoint(symbol1.endPoint, symbol2.endPoint) &&
+            symbol1.openSide == symbol2.openSide &&
+            symbol1.parent == symbol2.parent &&
+            symbol1.enter == symbol2.enter
+        ) {
+            return false
+        } else {
+            return true
+        }
+    }
+    isDifferentForComponents(component1, component2) {
+        if (JSON.stringify(component1.points2d) == JSON.stringify(component2.points) && component1.angle == component2.angle) {
+            return false
+        } else {
+            return true
+        }
+    }
+    isDifferentForTags(tag1, tag2) {
+        if (mathUtil.equalPoint(tag1.center, tag2.center) && tag1.title == tag2.title && tag1.des == tag2.des && tag1.unit == tag2.unit) {
+            return false
+        } else {
+            return true
+        }
+    }
+    isDifferentForFurnitures(furniture1, furniture2) {
+        if (furniture1.scale == furniture2.scale && JSON.stringify(furniture1.center) == JSON.stringify(furniture2.center) && furniture1.angle == furniture2.angle) {
+            return false
+        } else {
+            return true
+        }
+    }
+
+    isDifferentForAngle(angle1, angle2) {
+        if (angle1 == angle2) {
+            return false
+        } else {
+            return true
+        }
+    }
+
+    // wall2赋值给wall1
+    assignWallFromWall(wall1, wall2) {
+        const wallInfo = {}
+        wallInfo.vectorId = wall1.vectorId
+        wallInfo.children = JSON.parse(JSON.stringify(wall2.children))
+        wallInfo.out = wall2.out
+        wallInfo.important = wall2.important
+        wallInfo.start = wall2.start
+        wallInfo.end = wall2.end
+        wallService.setWallInfo(wallInfo)
+    }
+    assignPointFromPoint(point1, point2) {
+        const pointInfo = {}
+        pointInfo.vectorId = point1.vectorId
+        pointInfo.position = { x: point2.x, y: point2.y }
+        pointInfo.parent = JSON.parse(JSON.stringify(point2.parent))
+        wallService.setPointInfo(pointInfo)
+    }
+    assignSymbolFromSymbol(symbol1, symbol2) {
+        const symbolInfo = {}
+        symbolInfo.vectorId = symbol1.vectorId
+        symbolInfo.openSide = symbol2.openSide
+        symbolInfo.start = JSON.parse(JSON.stringify(symbol2.start))
+        symbolInfo.end = JSON.parse(JSON.stringify(symbol2.end))
+        symbolInfo.points2d = JSON.parse(JSON.stringify(symbol2.points))
+        symbolInfo.enter = symbol2.enter
+        symbolInfo.parent = symbol2.parent
+        symbolService.setSymbolInfo(symbolInfo)
+    }
+    assignComponentFromComponent(component1, component2) {
+        const componentInfo = {}
+        componentInfo.vectorId = component1.vectorId
+        componentInfo.angle = component2.angle
+        componentInfo.center = JSON.parse(JSON.stringify(component2.center))
+        componentInfo.points2d = JSON.parse(JSON.stringify(component2.points))
+        componentService.setComponentInfo(componentInfo)
+    }
+    assignTagFromTag(tag1, tag2) {
+        const tagInfo = {}
+        tagInfo.vectorId = tag1.vectorId
+        tagInfo.title = tag2.title
+        tagInfo.des = tag2.des
+        tagInfo.unit = tag2.unit
+        tagInfo.center = JSON.parse(JSON.stringify(tag2.center))
+        tagInfo.points2d = JSON.parse(JSON.stringify(tag2.points))
+        tagInfo.adding = false
+        tagService.setTagInfo(tagInfo)
+    }
+    assignFurnitureFromFurniture(furniture1, furniture2) {
+        const furnitureInfo = {}
+        furnitureInfo.vectorId = furniture1.vectorId
+        furnitureInfo.angle = furniture2.angle
+        furnitureInfo.center = JSON.parse(JSON.stringify(furniture2.center))
+        furnitureInfo.scale = furniture2.scale
+        furnitureService.setFurnitureInfo(furnitureInfo)
+    }
+    deletePoint(pointId) {
+        const point = floorplanService.getPoint(pointId)
+        const parent = point.parent
+        for (const key in parent) {
+            floorplanService.deletePoint(pointId, key)
+        }
+    }
+    getDataForPoint(point) {
+        const data = {}
+        data.id = point.vectorId
+        mathUtil.clonePoint(data, point)
+        data.parent = JSON.parse(JSON.stringify(point.parent))
+        data.type = point.geoType
+        return data
+    }
+    getDataForWall(wall) {
+        const data = {}
+        data.id = wall.vectorId
+        data.start = wall.start
+        data.end = wall.end
+        data.out = wall.out
+        data.important = wall.important
+        data.children = JSON.parse(JSON.stringify(wall.children))
+        data.type = wall.geoType
+        return data
+    }
+
+    getDataForSymbol(symbol) {
+        const data = {}
+        data.id = symbol.vectorId
+        data.start = JSON.parse(JSON.stringify(symbol.startPoint))
+        data.end = JSON.parse(JSON.stringify(symbol.endPoint))
+        data.openSide = symbol.openSide
+        data.enter = symbol.enter
+        data.points = JSON.parse(JSON.stringify(symbol.points2d))
+        data.parent = symbol.parent
+        data.type = symbol.geoType
+        return data
+    }
+
+    getDataForComponent(component) {
+        const data = {}
+        data.id = component.vectorId
+        data.type = component.geoType
+        data.center = JSON.parse(JSON.stringify(component.center))
+        data.angle = component.angle
+        data.points = [].concat(component.points2d)
+        return data
+    }
+
+    getDataForFurniture(furniture) {
+        const data = {}
+        data.id = furniture.vectorId
+        data.type = furniture.geoType
+        data.center = JSON.parse(JSON.stringify(furniture.center))
+        data.scale = furniture.scale
+        data.angle = furniture.angle
+        return data
+    }
+
+    getDataForTag(tag) {
+        const data = {}
+        data.id = tag.vectorId
+        data.type = tag.geoType
+        data.center = {}
+        mathUtil.clonePoint(data.center, tag.center)
+        data.points = [].concat(tag.points2d)
+        data.title = tag.title
+        data.des = tag.des
+        data.unit = tag.unit
+        return data
+    }
+
+    getDataForAngle(angle) {
+        return angle
+    }
+
+    getDataForRes(res) {
+        return res
+    }
+}
+
+const historyUtil = new HistoryUtil()
+export { historyUtil }

+ 796 - 0
src/views/draw-file/board/editCAD/Layer.js

@@ -0,0 +1,796 @@
+import Load from './Load'
+import { stateService } from './Service/StateService'
+import { symbolService } from './Service/SymbolService'
+import { elementService } from './Service/ElementService'
+import { floorplanService } from './Service/FloorplanService'
+import { measureService } from './Service/MeasureService'
+import { tagService } from './Service/TagService'
+import { historyService } from './Service/HistoryService'
+
+import UIControl from './Controls/UIControl'
+import { moveSymbol } from './Controls/MoveSymbol'
+import { moveComponent } from './Controls/MoveComponent'
+import { moveTag } from './Controls/MoveTag'
+import { addWall } from './Controls/AddWall'
+import { moveWall } from './Controls/MoveWall'
+import { coordinate } from './Coordinate'
+import Render from './Renderer/Render'
+import { draw } from './Renderer/Draw'
+import { listenLayer } from './ListenLayer'
+import { floorplanData } from './FloorplanData'
+
+import LayerEvents from './enum/LayerEvents.js'
+import UIEvents from './enum/UIEvents.js'
+import SelectState from './enum/SelectState.js'
+import Constant from './Constant'
+import VectorType from './enum/VectorType'
+import { mathUtil } from './MathUtil'
+import { wallService } from './Service/WallService'
+import { componentService } from './Service/ComponentService'
+import History from './History/History'
+import sync from './sync'
+import { roomsUtil } from './Room/RoomsUtil'
+import { roomService } from './Service/RoomService'
+import { compassService } from './Service/CompassService'
+import { furnitureService } from './Service/FurnitureService'
+
+export default class Layer {
+    constructor() {
+        //super()
+        this.load = new Load(this)
+        this.uiControl = new UIControl(this)
+        this.renderer = new Render(this)
+        this.history = new History(this)
+
+        this.startX = null
+        this.startY = null
+    }
+
+    //开始
+    start(canvas,vectorData) {
+        coordinate.init(canvas)
+        this.load.load(vectorData);
+        this.bindEvents()
+    }
+
+    bindEvents() {
+        this.div.addEventListener('contextmenu', function (e) {
+            e.preventDefault()
+        })
+        this.div.addEventListener('mousedown', this.onMouseDown.bind(this))
+        this.div.addEventListener('mousemove', this.onMouseMove.bind(this))
+        this.div.addEventListener('mouseup', this.onMouseUp.bind(this))
+        this.div.addEventListener('mousewheel', this.onWheel.bind(this))
+        this.div.addEventListener('DOMMouseScroll', this.onWheel.bind(this))
+    }
+
+    onMouseDown(e) {
+
+        this.startX = e.offsetX || e.layerX
+        this.startY = e.offsetY || e.layerY
+
+        this.lastX = e.offsetX || e.layerX
+        this.lastY = e.offsetY || e.layerY
+
+        // 右键
+        if (e.button == 2) {
+            this.stopAddVector()
+            this.uiControl.currentUI = null
+            this.renderer.autoRedraw()
+            return
+        }
+
+        const eventName = stateService.getEventName()
+        //点击第一次
+        if (eventName == LayerEvents.AddWall) {
+            let flag = this.setNewWallPoint('start', {
+                x: this.startX,
+                y: this.startY,
+            })
+            if (!flag) {
+                return
+            }
+        }
+        //点击第二次
+        else if (eventName == LayerEvents.AddingWall) {
+            let flag = this.setNewWallPoint('end', {
+                x: this.startX,
+                y: this.startY,
+            })
+            if (!flag) {
+                return
+            }
+            if (addWall.canAdd) {
+                addWall.buildWall(this.uiControl.selectUI == UIEvents.OutWall)
+                this.history.save()
+            } else {
+                return
+            }
+        } else {
+            const selectItem = stateService.getSelectItem()
+            if (eventName == null && selectItem) {
+                stateService.setDraggingItem(selectItem)
+                stateService.setFocusItem(selectItem)
+                this.uiControl.showAttributes()
+                this.uiControl.currentUI = selectItem.type
+            } else if (eventName == null) {
+                this.uiControl.currentUI = null
+            }
+        }
+        this.setEventName('mouseDown')
+        // 清除上一个状态
+        // 设置当前事件名称
+        e.preventDefault()
+        e.stopPropagation()
+    }
+
+    onMouseMove(e) {
+        const X = e.offsetX || e.layerX
+        const Y = e.offsetY || e.layerY
+        let dx = X - this.lastX
+        let dy = Y - this.lastY
+
+        let position = coordinate.getXYFromScreen({
+            x: X,
+            y: Y,
+        })
+
+        const eventName = stateService.getEventName()
+        // 是否需要重绘
+        let needAutoRedraw = false
+
+        const draggingItem = stateService.getDraggingItem()
+        switch (eventName) {
+            case null:
+                //监控
+                needAutoRedraw = listenLayer.start(position)
+                break
+            case LayerEvents.PanBackGround:
+                stateService.clearItems()
+                coordinate.center.x = coordinate.center.x - (dx * Constant.defaultZoom) / coordinate.zoom / coordinate.res
+                coordinate.center.y = coordinate.center.y + (dy * Constant.defaultZoom) / coordinate.zoom / coordinate.res
+                this.lastX = X
+                this.lastY = Y
+                needAutoRedraw = true
+                break
+            case LayerEvents.AddWall:
+                stateService.clearDraggingItem()
+                stateService.clearFocusItem()
+                needAutoRedraw = true
+                listenLayer.start(position)
+                if (listenLayer.modifyPoint) {
+                    position = {
+                        x: listenLayer.modifyPoint.x,
+                        y: listenLayer.modifyPoint.y,
+                    }
+                }
+                elementService.execute(null, position)
+                elementService.setStartAddWall(position)
+                elementService.showStartAddWall()
+                break
+            case LayerEvents.AddingWall:
+                stateService.clearDraggingItem()
+                stateService.clearFocusItem()
+                needAutoRedraw = true
+                listenLayer.start(position)
+                let startPosition = {
+                    x: addWall.startInfo.position.x,
+                    y: addWall.startInfo.position.y,
+                }
+                if (listenLayer.modifyPoint) {
+                    position = {
+                        x: listenLayer.modifyPoint.x,
+                        y: listenLayer.modifyPoint.y,
+                    }
+                }
+
+                elementService.execute(startPosition, position)
+                elementService.setStartAddWall(position)
+                if (!elementService.newWall.display) {
+                    elementService.setNewWall(startPosition, position)
+                    elementService.showNewWall() //画墙
+                } else {
+                    if (!listenLayer.modifyPoint && addWall.startInfo.linkedPointId) {
+                        let newEndPosition = elementService.checkAngle(position, addWall.startInfo.linkedPointId, null)
+                        if (newEndPosition) {
+                            mathUtil.clonePoint(position, newEndPosition)
+                        }
+                    }
+                    elementService.setNewWallEndPosition(position) //改变end位置
+                }
+
+                addWall.canAdd = addWall.canAddWallForEnd(position)
+                if (!addWall.canAdd) {
+                    elementService.setNewWallState('error')
+                } else {
+                    if (this.uiControl.selectUI == UIEvents.OutWall) {
+                        elementService.setNewWallState('normal-out')
+                    } else {
+                        elementService.setNewWallState('normal')
+                    }
+                }
+                break
+            case LayerEvents.MoveWall:
+                dx = (dx * Constant.defaultZoom) / coordinate.zoom
+                dy = (dy * Constant.defaultZoom) / coordinate.zoom
+                // 1表示可以继续移动,2表示不能移动(启动距离还不够),3表示wallId被删除了,4表示重新开始移动(需要达到一定距离才能启动),5表示不能移动(不合适)
+                let moveFlag = moveWall.moveWallPlane(draggingItem.vectorId, dx, dy)
+                // 启动的时候需要点距离,所以真正移动了才更新lastX和lastY
+                if (moveFlag == 1) {
+                    this.lastX = X
+                    this.lastY = Y
+                    needAutoRedraw = true
+                }
+                // 需要继续保持移动,一般是距离不够启动
+                else if (moveFlag == 2) {
+                }
+                // wallId被删除了
+                else if (moveFlag == 3) {
+                    this.history.save()
+                    stateService.clearSelectItem()
+                    stateService.clearDraggingItem()
+                    stateService.clearEventName()
+                    listenLayer.clear()
+                    needAutoRedraw = true
+                }
+                // wallId有一端被吸附了,这时候需要重新启动
+                else if (moveFlag == 4) {
+                    this.lastX = X
+                    this.lastY = Y
+                    this.startX = X
+                    this.startY = Y
+                    needAutoRedraw = true
+                } else if (moveFlag == 5) {
+                    this.lastX = X
+                    this.lastY = Y
+                }
+                break
+            case LayerEvents.MoveWallPoint:
+                let point = floorplanService.getPoint(draggingItem.vectorId)
+                listenLayer.start(position, draggingItem.vectorId, point.parent)
+                if (listenLayer.modifyPoint) {
+                    position = {
+                        x: listenLayer.modifyPoint.x,
+                        y: listenLayer.modifyPoint.y,
+                    }
+                }
+                elementService.execute(null, position)
+                let flag = moveWall.movePoint(draggingItem.vectorId, position, listenLayer.modifyPoint)
+                if (!flag) {
+                    elementService.hideAll()
+                }
+                needAutoRedraw = true
+                break
+            case LayerEvents.AddSymbol:
+                listenLayer.start(position)
+                //最近的墙
+                if (listenLayer.wallInfo.wallId) {
+                    needAutoRedraw = true
+                    if (draggingItem == null) {
+                        const symbolType = this.uiControl.getSymbolTypeForUI()
+                        let symbolId = symbolService.addSymbol(position, symbolType, listenLayer.wallInfo.wallId)
+                        if (symbolId) {
+                            stateService.setSelectItem(symbolId, symbolType, SelectState.All)
+                            stateService.setDraggingItem(stateService.selectItem)
+                            let symbol = floorplanService.getSymbol(symbolId)
+                            symbol.len = mathUtil.getDistance(symbol.startPoint, symbol.endPoint)
+                        }
+                    } else {
+                        moveSymbol.moveFullSymbol(position, draggingItem.vectorId, listenLayer.wallInfo.wallId)
+                    }
+                } else {
+                    needAutoRedraw = false
+                }
+                break
+            case LayerEvents.MoveSymbol:
+                listenLayer.start(position)
+                needAutoRedraw = true
+                if (draggingItem != null && symbolService.isSymbol(draggingItem.type)) {
+                    moveSymbol.moveFullSymbol(position, draggingItem.vectorId, listenLayer.wallInfo.wallId)
+                }
+                break
+            case LayerEvents.MoveSymbolPoint:
+                needAutoRedraw = true
+                if (draggingItem != null && symbolService.isSymbol(draggingItem.type)) {
+                    //移动symbol的端点
+                    moveSymbol.moveSymbolPoint(position, draggingItem.vectorId, draggingItem.selectIndex)
+                }
+                break
+            case LayerEvents.AddComponent:
+                needAutoRedraw = true
+                if (draggingItem == null) {
+                    const componentType = this.uiControl.getComponentTypeForUI()
+                    const component = componentService.createComponent(position, componentType)
+                    if (component.vectorId) {
+                        stateService.setSelectItem(component.vectorId, componentType, SelectState.All)
+                        stateService.setDraggingItem(stateService.selectItem)
+                    }
+                } else {
+                    let flag = moveComponent.moveFullComponent(position, draggingItem.vectorId)
+                    if (flag) {
+                        this.lastX = X
+                        this.lastY = Y
+                        this.startX = X
+                        this.startY = Y
+                    }
+                }
+                break
+            case LayerEvents.MoveComponent:
+                needAutoRedraw = true
+                if (draggingItem != null && componentService.isComponent(draggingItem.type)) {
+                    let flag = moveComponent.moveFullComponent(position, draggingItem.vectorId)
+                    if (flag) {
+                        this.lastX = X
+                        this.lastY = Y
+                        this.startX = X
+                        this.startY = Y
+                    }
+                }
+                break
+            case LayerEvents.AddTag:
+                needAutoRedraw = true
+                if (draggingItem == null) {
+                    const tag = tagService.createTag(position)
+                    if (tag.vectorId) {
+                        stateService.setSelectItem(tag.vectorId, VectorType.Tag, SelectState.All)
+                        stateService.setDraggingItem(stateService.selectItem)
+                    }
+                } else {
+                    moveTag.moveFullTag(position, draggingItem.vectorId)
+                }
+                break
+            case LayerEvents.MoveTag:
+                needAutoRedraw = true
+                if (draggingItem != null) {
+                    moveTag.moveFullTag(position, draggingItem.vectorId)
+                }
+                break
+            case LayerEvents.AddFurniture:
+                needAutoRedraw = true
+                if (draggingItem == null) {
+                    const furnitureType = this.uiControl.getFurnitureTypeForUI()
+                    const furniture = furnitureService.createFurniture(position, furnitureType)
+                    if (furniture.vectorId) {
+                        stateService.setSelectItem(furniture.vectorId, furnitureType, SelectState.All)
+                        stateService.setDraggingItem(stateService.selectItem)
+                    }
+                } else {
+                    const furniture = floorplanService.getFurniture(draggingItem.vectorId)
+                    mathUtil.clonePoint(furniture.center, position)
+                }
+                break
+            case LayerEvents.MoveFurniture:
+                needAutoRedraw = true
+                const furniture = floorplanService.getFurniture(draggingItem.vectorId)
+                mathUtil.clonePoint(furniture.center, position)
+                break
+        }
+
+        if (needAutoRedraw) {
+            this.renderer.autoRedraw()
+        }
+    }
+
+    onMouseUp(e) {
+        if (coordinate.defaultCenter == null) {
+            return
+        }
+
+        const X = e.offsetX || e.layerX
+        const Y = e.offsetY || e.layerY
+
+        let eventName = stateService.getEventName()
+        const draggingItem = stateService.getDraggingItem()
+        let focusItem = null
+     
+        if (draggingItem && draggingItem.vectorId) {
+            focusItem = {
+                vectorId: draggingItem.vectorId,
+                type: draggingItem.type,
+                cursor: { x: this.lastX, y: this.lastY },
+            }
+            stateService.setFocusItem(focusItem)
+            this.uiControl.showAttributes()
+        }
+
+        let position = coordinate.getXYFromScreen({
+            x: X,
+            y: Y,
+        })
+        let needAutoRedraw = false
+        let symbol = null
+        switch (eventName) {
+            case null:
+                return
+            case LayerEvents.PanBackGround:
+                needAutoRedraw = true
+                stateService.clearFocusItem()
+                this.uiControl.currentUI = null
+                break
+            case LayerEvents.MoveWallPoint:
+                needAutoRedraw = true
+                elementService.hideAll()
+                let point = floorplanService.getPoint(draggingItem.vectorId)
+                if (point) {
+                    //if (focusItem == null) {
+                    listenLayer.start(point, draggingItem.vectorId, point.parent)
+
+                    if (listenLayer.modifyPoint && listenLayer.modifyPoint.hasOwnProperty('linkedPointId')) {
+                        wallService.moveTo(draggingItem.vectorId, listenLayer.modifyPoint.linkedPointId)
+                    } else if (listenLayer.modifyPoint && (listenLayer.modifyPoint.linkedPointIdX || listenLayer.modifyPoint.linkedPointIdY)) {
+                        mathUtil.clonePoint(point, listenLayer.modifyPoint)
+                        symbolService.updateSymbolsPositionsForWallCorner(draggingItem.vectorId)
+                    } else if (listenLayer.modifyPoint && listenLayer.modifyPoint.hasOwnProperty('linkedWallId')) {
+                        point = wallService.createPoint(listenLayer.modifyPoint.x, listenLayer.modifyPoint.y)
+                        wallService.splitWall(listenLayer.modifyPoint.linkedWallId, point.vectorId, 'start')
+                        wallService.moveTo(draggingItem.vectorId, point.vectorId)
+                    } else if (moveWall.splitWallId != null) {
+                        wallService.splitWall(moveWall.splitWallId, draggingItem.vectorId, 'start')
+                    }
+                    //draggingItem.vectorId所在的墙面与其他墙角相交
+                    moveWall.updateForAbsorbWallPoints()
+                    this.history.save()
+                }
+                break
+            case LayerEvents.AddingWall:
+                needAutoRedraw = true
+                if (addWall.startInfo && addWall.startInfo.linkedPointId) {
+                    let addWallStartPoint = floorplanService.getPoint(addWall.startInfo.linkedPointId)
+                    if (addWall.endInfo.position && Object.keys(addWallStartPoint.parent).length > 1) {
+                        stateService.clearEventName()
+                        addWall.clear()
+                        elementService.hideAll()
+                    }
+                }
+                break
+            case LayerEvents.MoveWall:
+                needAutoRedraw = true
+                if (focusItem != null && focusItem.type == VectorType.Wall) {
+                    const wall = floorplanService.getWall(focusItem.vectorId)
+                    if (wall.import || wall.out) {
+                        this.uiControl.currentUI = 'OutWall'
+                    } else {
+                        this.uiControl.currentUI = focusItem.type
+                    }
+                    this.history.save()
+                } else {
+                    this.history.save()
+                }
+                break
+            case LayerEvents.AddSymbol:
+                if (draggingItem == null) {
+                    this.setEventName('mouseUp')
+                    return
+                }
+                focusItem = {
+                    vectorId: draggingItem.vectorId,
+                    type: draggingItem.type,
+                    cursor: { x: this.lastX, y: this.lastY },
+                }
+
+                stateService.setFocusItem(focusItem)
+                this.uiControl.showAttributes()
+                this.uiControl.currentUI = focusItem.type
+                this.history.save()
+                break
+            case LayerEvents.MoveSymbol:
+                symbol = floorplanService.getSymbol(draggingItem.vectorId)
+                needAutoRedraw = true
+                if (focusItem != null && symbolService.isSymbol(focusItem.type)) {
+                    this.uiControl.currentUI = focusItem.type
+                    this.history.save()
+                } else if (symbol) {
+                    symbol.len = null
+                    this.history.save()
+                }
+                break
+            case LayerEvents.MoveSymbolPoint:
+                needAutoRedraw = true
+                if (focusItem != null && symbolService.isSymbol(focusItem.type)) {
+                    this.uiControl.currentUI = focusItem.type
+                    this.history.save()
+                } else {
+                    this.history.save()
+                }
+                break
+            case LayerEvents.AddComponent:
+                focusItem = {
+                    vectorId: draggingItem.vectorId,
+                    type: draggingItem.type,
+                    cursor: { x: this.lastX, y: this.lastY },
+                }
+
+                stateService.setFocusItem(focusItem)
+                this.uiControl.showAttributes()
+                this.uiControl.currentUI = focusItem.type
+                this.history.save()
+                break
+            case LayerEvents.MoveComponent:
+                needAutoRedraw = true
+                if (focusItem != null && componentService.isComponent(focusItem.type)) {
+                    this.uiControl.currentUI = focusItem.type
+                    this.history.save()
+                } else {
+                    this.history.save()
+                }
+                break
+            case LayerEvents.MoveTag:
+                needAutoRedraw = true
+                if (focusItem != null && focusItem.type == VectorType.Tag) {
+                    this.uiControl.currentUI = focusItem.type
+                    this.history.save()
+                } else {
+                    this.history.save()
+                }
+                break
+            case LayerEvents.AddTag:
+                needAutoRedraw = true
+                let tag = floorplanService.getTag(draggingItem.vectorId)
+                tag.setAdding(false)
+                focusItem = {
+                    vectorId: draggingItem.vectorId,
+                    type: draggingItem.type,
+                    cursor: { x: this.lastX, y: this.lastY },
+                }
+                stateService.setFocusItem(focusItem)
+                this.history.save()
+                this.uiControl.currentUI = focusItem.type
+                break
+            case LayerEvents.AddFurniture:
+                focusItem = {
+                    vectorId: draggingItem.vectorId,
+                    type: draggingItem.type,
+                    cursor: { x: this.lastX, y: this.lastY },
+                }
+                stateService.setFocusItem(focusItem)
+                this.uiControl.showAttributes()
+                this.uiControl.currentUI = focusItem.type
+                this.history.save()
+                break
+            case LayerEvents.MoveFurniture:
+                needAutoRedraw = true
+                if (focusItem != null && furnitureService.isFurniture(focusItem.type)) {
+                    this.uiControl.currentUI = focusItem.type
+                    this.history.save()
+                } else {
+                    debugger
+                    this.history.save()
+                }
+                break
+        }
+
+        this.setEventName('mouseUp')
+        stateService.clearDraggingItem()
+        this.renderer.autoRedraw()
+    }
+
+    onWheel(e) {
+        if (coordinate.defaultCenter == null) {
+            return
+        }
+        e.preventDefault()
+        const type = e.type
+        if (type == 'DOMMouseScroll' || type == 'mousewheel') {
+            // 当在canvas用滚轮滚动时
+            const delta = e.wheelDelta ? (e.wheelDelta / 120) * 2 : (-(e.detail || 0) / 3) * 2
+            const zoom = coordinate.zoom + delta
+            if (zoom < 14) {
+                return
+            }
+            coordinate.updateZoom(zoom)
+
+            let info = coordinate.getScreenInfoForCAD()
+            info.floorPlanAngle = floorplanService.getAngle()
+            this.renderer.autoRedraw()
+        }
+    }
+
+    onKeydown(e) {
+        if (!this.display) {
+            return
+        }
+
+        if (e.ctrlKey && e.code == 'KeyZ') {
+            // 撤销
+            if (!this.$xui.toolbar.recall) {
+                return
+            }
+            this.revokeHistory()
+            console.log('ctrl+z')
+        } else if (e.ctrlKey && e.code == 'KeyY') {
+            // 恢复
+            if (!this.$xui.toolbar.recover) {
+                return
+            }
+            this.recoveryHistory()
+            console.log('ctrl+y')
+        } else if (e.code == 'Delete') {
+            this.deleteItem()
+            this.uiControl.currentUI = null
+            this.history.save()
+            this.renderer.autoRedraw()
+            console.log('Delete')
+        } else if (e.code == 'Escape') {
+            this.stopAddVector()
+            this.renderer.autoRedraw()
+            console.log('Esc')
+        }
+    }
+
+    //点击左侧栏后,更新事件
+    updateEventNameForSelectUI() {
+        elementService.hideAll()
+        //正在添加tag的时候,需要先删除
+        const eventName = stateService.getEventName()
+        if (eventName == LayerEvents.AddTag) {
+            let item = stateService.getDraggingItem()
+            if (item && item.type == VectorType.Tag) {
+                floorplanService.deleteTag(item.vectorId)
+            }
+        }
+        stateService.clearItems()
+        if (this.uiControl.selectUI == UIEvents.Wall || this.uiControl.selectUI == UIEvents.OutWall) {
+            stateService.setEventName(LayerEvents.AddWall)
+        } else if (
+            this.uiControl.selectUI == UIEvents.SingleDoor ||
+            this.uiControl.selectUI == UIEvents.DoubleDoor ||
+            this.uiControl.selectUI == UIEvents.SlideDoor ||
+            this.uiControl.selectUI == UIEvents.SingleWindow ||
+            this.uiControl.selectUI == UIEvents.BayWindow ||
+            this.uiControl.selectUI == UIEvents.FrenchWindow ||
+            this.uiControl.selectUI == UIEvents.Pass
+        ) {
+            stateService.setEventName(LayerEvents.AddSymbol)
+        } else if (this.uiControl.selectUI == UIEvents.Beam || this.uiControl.selectUI == UIEvents.Flue || this.uiControl.selectUI == UIEvents.Corridor) {
+            stateService.setEventName(LayerEvents.AddComponent)
+        } else if (this.uiControl.selectUI == UIEvents.Tag) {
+            stateService.setEventName(LayerEvents.AddTag)
+        } else if (
+            this.uiControl.selectUI == UIEvents.TV ||
+            this.uiControl.selectUI == UIEvents.CombinationSofa ||
+            this.uiControl.selectUI == UIEvents.SingleSofa ||
+            this.uiControl.selectUI == UIEvents.TeaTable ||
+            this.uiControl.selectUI == UIEvents.Carpet ||
+            this.uiControl.selectUI == UIEvents.Plant ||
+            this.uiControl.selectUI == UIEvents.DiningTable ||
+            this.uiControl.selectUI == UIEvents.DoubleBed ||
+            this.uiControl.selectUI == UIEvents.SingleBed ||
+            this.uiControl.selectUI == UIEvents.Wardrobe ||
+            this.uiControl.selectUI == UIEvents.Dresser ||
+            this.uiControl.selectUI == UIEvents.BedsideCupboard ||
+            this.uiControl.selectUI == UIEvents.Pillow ||
+            this.uiControl.selectUI == UIEvents.GasStove ||
+            this.uiControl.selectUI == UIEvents.Cupboard ||
+            this.uiControl.selectUI == UIEvents.Bathtub ||
+            this.uiControl.selectUI == UIEvents.Closestool ||
+            this.uiControl.selectUI == UIEvents.Washstand ||
+            this.uiControl.selectUI == UIEvents.Desk ||
+            this.uiControl.selectUI == UIEvents.BalconyChair ||
+            this.uiControl.selectUI == UIEvents.Elevator
+        ) {
+            stateService.setEventName(LayerEvents.AddFurniture)
+        }
+    }
+
+    setEventName(eventType) {
+        let eventName = stateService.getEventName()
+
+        if (eventType == 'mouseDown') {
+            if (eventName == null) {
+                const selectItem = stateService.getSelectItem()
+                if (selectItem == null) {
+                    stateService.setEventName(LayerEvents.PanBackGround)
+                } else if (selectItem.type == VectorType.Wall) {
+                    stateService.setEventName(LayerEvents.MoveWall)
+                } else if (selectItem.type == VectorType.WallCorner) {
+                    stateService.setEventName(LayerEvents.MoveWallPoint)
+                } else if (symbolService.isSymbol(selectItem.type)) {
+                    if (selectItem.selectIndex == SelectState.All || selectItem.selectIndex == SelectState.Select) {
+                        stateService.setEventName(LayerEvents.MoveSymbol)
+                        //需要保留当前的长度
+                        const symbol = floorplanService.getSymbol(selectItem.vectorId)
+                        symbol.len = mathUtil.getDistance(symbol.startPoint, symbol.endPoint)
+                    } else if (selectItem.selectIndex == SelectState.Start || selectItem.selectIndex == SelectState.End) {
+                        stateService.setEventName(LayerEvents.MoveSymbolPoint)
+                    }
+                } else if (componentService.isComponent(selectItem.type)) {
+                    stateService.setEventName(LayerEvents.MoveComponent)
+                } else if (selectItem.type == VectorType.Tag) {
+                    stateService.setEventName(LayerEvents.MoveTag)
+                } else if (furnitureService.isFurniture(selectItem.type)) {
+                    stateService.setEventName(LayerEvents.MoveFurniture)
+                }
+            } else if (eventName == LayerEvents.AddWall) {
+                stateService.setEventName(LayerEvents.AddingWall)
+            }
+        } else if (eventType == 'mouseUp') {
+            if (eventName == LayerEvents.AddTag) {
+                //可连续添加
+            } else if (eventName != LayerEvents.AddWall && eventName != LayerEvents.AddingWall) {
+                stateService.clearEventName()
+            }
+        }
+    }
+
+    exit() {
+        stateService.clearItems()
+        stateService.clearEventName()
+        this.uiControl.clearUI()
+    }
+
+    stopAddVector() {
+        let eventName = stateService.getEventName()
+        if (eventName != LayerEvents.AddingWall) {
+            stateService.clearEventName()
+            const draggingItem = stateService.getDraggingItem()
+            if (eventName == LayerEvents.AddSymbol) {
+                if (draggingItem && draggingItem.vectorId) {
+                    symbolService.deleteSymbol(draggingItem.vectorId)
+                    stateService.clearDraggingItem()
+                }
+            } else if (eventName == LayerEvents.AddComponent) {
+                if (draggingItem && draggingItem.vectorId) {
+                    floorplanService.deleteComponent(draggingItem.vectorId)
+                }
+            } else if (eventName == LayerEvents.AddTag) {
+                if (draggingItem && draggingItem.vectorId) {
+                    tagService.deleteTag(draggingItem.vectorId)
+                    this.uiControl.currentUI = null
+                }
+            } else if (eventName == LayerEvents.AddFurniture) {
+                if (draggingItem && draggingItem.vectorId) {
+                    floorplanService.deleteFurniture(draggingItem.vectorId)
+                }
+            }
+        } else {
+            stateService.setEventName(LayerEvents.AddWall)
+        }
+
+        this.uiControl.clearUI()
+        elementService.hideAll()
+    }
+
+    setNewWallPoint(dir, position) {
+        if (listenLayer.symbolInfo.state == 'select') {
+            return false
+        }
+        if (dir == 'start') {
+            if (listenLayer.modifyPoint) {
+                addWall.setPointInfo(dir, listenLayer.modifyPoint)
+            } else {
+                addWall.setPointInfo(dir, coordinate.getXYFromScreen(position))
+            }
+            return true
+        } else if (dir == 'end') {
+            if (listenLayer.modifyPoint) {
+                addWall.setPointInfo(dir, listenLayer.modifyPoint)
+            } else {
+                addWall.setPointInfo(dir, coordinate.getXYFromScreen(position))
+            }
+            return true
+        }
+        return false
+    }
+
+    deleteItem() {
+        let item = stateService.getFocusItem()
+        if (item) {
+            if (item.type == VectorType.Wall) {
+                floorplanService.deleteWall(item.vectorId)
+            } else if (symbolService.isSymbol(item.type)) {
+                symbolService.deleteSymbol(item.vectorId)
+            } else if (componentService.isComponent(item.type)) {
+                floorplanService.deleteComponent(item.vectorId)
+            } else if (item.type == VectorType.Tag) {
+                floorplanService.deleteTag(item.vectorId)
+            } else if (furnitureService.isFurniture(item.type)) {
+                floorplanService.deleteComponent(item.vectorId)
+            } else if (item.type == VectorType.WallCorner) {
+                wallService.deleteWallCorner(item.vectorId)
+            }
+            this.history.save()
+            this.renderer.autoRedraw()
+        }
+    }
+
+}

+ 505 - 0
src/views/draw-file/board/editCAD/ListenLayer.js

@@ -0,0 +1,505 @@
+import { mathUtil } from './MathUtil.js'
+import { floorplanService } from './Service/FloorplanService.js'
+import { stateService } from './Service/StateService.js'
+import { wallService } from './Service/WallService.js'
+import Constant from './Constant.js'
+import VectorType from './enum/VectorType.js'
+import SelectState from './enum/SelectState.js'
+
+export default class ListenLayer {
+    constructor() {
+        this.wallInfo = {
+            wallId: null,
+            state: null, // 未选中null
+        }
+
+        this.pointInfo = {
+            pointId: null,
+            state: null,
+        }
+
+        this.symbolInfo = {
+            symbolId: null,
+            state: null, // start,end,all表示哪个部位。与前面的wallInfo和pointInfo不同,上面两个变量一直都有值,因为他们的意义是找到最近的,而symbolInfo是判断是否选中
+        }
+
+        this.componentInfo = {
+            componentId: null,
+            state: null,
+        }
+
+        this.tagInfo = {
+            tagId: null,
+            state: null,
+        }
+
+        this.furnitureInfo = {
+            furnitureId: null,
+            state: null,
+        }
+
+        this.modifyPoint = null
+    }
+
+    //开始监听,exceptPointId表示不考虑的点,exceptWallIds表示不考虑的墙
+    start(position, exceptPointId, exceptWallIds) {
+        let nearest = this.getNearForVectors(position, exceptPointId, exceptWallIds)
+        /*
+        // getNearForWalls在一定的条件下必须执行两次!
+        // 如果吸附在墙面上,或者吸附在其余墙的顶点(x/y坐标),这时候因为抖动,可能会变成完全吸附在墙角,这时候是要再执行一次getNearForWalls
+        if (
+            nearest.modifyPoint &&
+            (nearest.modifyPoint.hasOwnProperty("linkedPointIdX") || 
+            nearest.modifyPoint.hasOwnProperty("linkedPointIdY") || 
+            nearest.modifyPoint.hasOwnProperty("linkedWallId"))
+        ) {
+            mathUtil.clonePoint(position, nearest.modifyPoint);
+            nearest = this.getNearForVectors(position, exceptPointId, exceptWallIds);
+        }
+        */
+
+        if (
+            nearest.modifyPoint &&
+            (nearest.modifyPoint.hasOwnProperty('linkedPointId') ||
+                nearest.modifyPoint.hasOwnProperty('linkedPointIdX') ||
+                nearest.modifyPoint.hasOwnProperty('linkedPointIdY') ||
+                nearest.modifyPoint.hasOwnProperty('linkedWallId'))
+        ) {
+            this.modifyPoint = {
+                x: nearest.modifyPoint.x,
+                y: nearest.modifyPoint.y,
+            }
+            if (nearest.modifyPoint.hasOwnProperty('linkedPointId') && nearest.modifyPoint.linkedPointId != null) {
+                this.modifyPoint.linkedPointId = nearest.modifyPoint.linkedPointId
+            } else if (nearest.modifyPoint.hasOwnProperty('linkedWallId') && nearest.modifyPoint.linkedWallId != null) {
+                this.modifyPoint.linkedWallId = nearest.modifyPoint.linkedWallId
+            } else {
+                if (nearest.modifyPoint.hasOwnProperty('linkedPointIdX') && nearest.modifyPoint.linkedPointIdX != null) {
+                    this.modifyPoint.linkedPointIdX = nearest.modifyPoint.linkedPointIdX
+                }
+                if (nearest.modifyPoint.hasOwnProperty('linkedPointIdY') && nearest.modifyPoint.linkedPointIdY != null) {
+                    this.modifyPoint.linkedPointIdY = nearest.modifyPoint.linkedPointIdY
+                }
+            }
+        } else {
+            this.modifyPoint = null
+        }
+
+        const flag = this.updateSelectInfos(nearest, Constant.minAdsorb)
+        this.updateSelectItem()
+        return flag
+    }
+
+    // 获得最近的墙面和墙角
+    // 同时获得吸附的相关信息
+    // 找到选中的symbol(只有选中了,才算是最近的)
+    getNearForVectors(position, exceptPointId, exceptWallIds) {
+        let min1 = null // 与墙角的距离
+        let min2 = null // 与墙面的距离
+        // 纠正
+        // 垂直,水平
+        const modifyPoint = {}
+        // 吸附在墙面上
+        let _modifyPoint = null
+        const hasPointIds = []
+        if (exceptPointId) {
+            hasPointIds.push(exceptPointId)
+        }
+
+        const walls = floorplanService.getWalls()
+        for (const wallId in walls) {
+            if (exceptWallIds && exceptWallIds.hasOwnProperty(wallId)) {
+                continue
+            }
+
+            const wall = floorplanService.getWall(wallId)
+
+            const startPoint = floorplanService.getPoint(wall.start)
+            const endPoint = floorplanService.getPoint(wall.end)
+            let distance = null
+            const line = wallService.getLine(wall)
+            if (!line) {
+                //debugger
+                //删除墙
+                floorplanService.deleteWall(wallId)
+                continue
+                console.error('getNearForVectors************************************')
+            }
+            const join = mathUtil.getJoinLinePoint(position, line)
+
+            if (hasPointIds.indexOf(wall.start) == -1) {
+                hasPointIds.push(wall.start)
+                distance = mathUtil.getDistance(position, startPoint)
+
+                if (min1 == null || min1.distance > distance) {
+                    min1 = {
+                        distance: distance,
+                        pointId: wall.start,
+                    }
+
+                    //start部分找到了墙的端点
+                    if ((mathUtil.getDistance(join, position) < Constant.minAdsorb && mathUtil.getDistance(join, startPoint) < Constant.minAdsorb) || min1.distance < Constant.minAdsorb) {
+                        modifyPoint.linkedPointId = wall.start
+                        modifyPoint.x = startPoint.x
+                        modifyPoint.y = startPoint.y
+
+                        delete modifyPoint.linkedPointIdX
+                        delete modifyPoint.linkedPointIdY
+                        break
+                    }
+                }
+                //start部分找到了与x接近的其他点
+                if (Math.abs(position.x - startPoint.x) < Constant.minAdsorb) {
+                    if (!modifyPoint.linkedPointIdX) {
+                        modifyPoint.x = startPoint.x
+                        modifyPoint.linkedPointIdX = wall.start
+                    } else {
+                        const linkedPointX = floorplanService.getPoint(modifyPoint.linkedPointIdX)
+                        if (mathUtil.getDistance(position, linkedPointX) > mathUtil.getDistance(position, startPoint)) {
+                            modifyPoint.x = startPoint.x
+                            modifyPoint.linkedPointIdX = wall.start
+                        }
+                    }
+                }
+                //start部分找到了与y接近的其他点
+                if (Math.abs(position.y - startPoint.y) < Constant.minAdsorb) {
+                    if (!modifyPoint.linkedPointIdY) {
+                        modifyPoint.y = startPoint.y
+                        modifyPoint.linkedPointIdY = wall.start
+                    } else {
+                        const linkedPointY = floorplanService.getPoint(modifyPoint.linkedPointIdY)
+                        if (mathUtil.getDistance(position, linkedPointY) > mathUtil.getDistance(position, startPoint)) {
+                            modifyPoint.y = startPoint.y
+                            modifyPoint.linkedPointIdY = wall.start
+                        }
+                    }
+                }
+            }
+
+            if (hasPointIds.indexOf(wall.end) == -1) {
+                hasPointIds.push(wall.end)
+                distance = mathUtil.getDistance(position, endPoint)
+
+                if (min1 == null || min1.distance > distance) {
+                    min1 = {
+                        distance: distance,
+                        pointId: wall.end,
+                    }
+                    //end部分找到了墙的端点
+                    if ((mathUtil.getDistance(join, position) < Constant.minAdsorb && mathUtil.getDistance(join, endPoint) < Constant.minAdsorb) || min1.distance < Constant.minAdsorb) {
+                        modifyPoint.linkedPointId = wall.end
+                        modifyPoint.x = endPoint.x
+                        modifyPoint.y = endPoint.y
+                        delete modifyPoint.linkedPointIdX
+                        delete modifyPoint.linkedPointIdY
+                        break
+                    }
+                }
+                //end部分找到了与x接近的其他点
+                if (Math.abs(position.x - endPoint.x) < Constant.minAdsorb) {
+                    if (!modifyPoint.linkedPointIdX) {
+                        modifyPoint.x = endPoint.x
+                        modifyPoint.linkedPointIdX = wall.end
+                    } else {
+                        const linkedPointX = floorplanService.getPoint(modifyPoint.linkedPointIdX)
+                        if (mathUtil.getDistance(position, linkedPointX) > mathUtil.getDistance(position, endPoint)) {
+                            modifyPoint.x = endPoint.x
+                            modifyPoint.linkedPointIdX = wall.end
+                        }
+                    }
+                }
+                //end部分找到了与y接近的其他点
+                if (Math.abs(position.y - endPoint.y) < Constant.minAdsorb) {
+                    if (!modifyPoint.linkedPointIdY) {
+                        modifyPoint.y = endPoint.y
+                        modifyPoint.linkedPointIdY = wall.end
+                    } else {
+                        const linkedPointY = floorplanService.getPoint(modifyPoint.linkedPointIdY)
+                        if (mathUtil.getDistance(position, linkedPointY) > mathUtil.getDistance(position, endPoint)) {
+                            modifyPoint.y = endPoint.y
+                            modifyPoint.linkedPointIdY = wall.end
+                        }
+                    }
+                }
+            }
+
+            distance = mathUtil.getDistance(position, join)
+            //是否在墙上,可能在墙外
+            const _flag = wallService.isContain(wall, join)
+
+            if (_flag && (min2 == null || min2.distance > distance)) {
+                min2 = {
+                    distance: distance,
+                    wallId: wallId,
+                }
+            }
+
+            if (_flag && mathUtil.getDistance(position, join) < Constant.minAdsorb) {
+                _modifyPoint = join
+                _modifyPoint.linkedWallId = wallId
+            }
+        }
+        const result = {
+            minPoint: min1,
+            minWall: min2,
+            symbolInfo: {},
+            componentInfo: {},
+            tagInfo: {},
+            furnitureInfo: {},
+        }
+
+        if (_modifyPoint != null) {
+            result.modifyPoint = JSON.parse(JSON.stringify(_modifyPoint))
+        } else if (modifyPoint.hasOwnProperty('x') && modifyPoint.hasOwnProperty('y')) {
+            result.modifyPoint = JSON.parse(JSON.stringify(modifyPoint))
+        } else if (modifyPoint.hasOwnProperty('x')) {
+            result.modifyPoint = JSON.parse(JSON.stringify(modifyPoint))
+            result.modifyPoint.x = modifyPoint.x
+            result.modifyPoint.y = position.y
+        } else if (modifyPoint.hasOwnProperty('y')) {
+            result.modifyPoint = JSON.parse(JSON.stringify(modifyPoint))
+            result.modifyPoint.x = position.x
+            result.modifyPoint.y = modifyPoint.y
+        }
+
+        //是否在门/窗 上
+        const symbols = floorplanService.getSymbols()
+        for (const symbolId in symbols) {
+            const symbol = floorplanService.getSymbol(symbolId)
+            const location = symbol.isContain(position)
+            if (location != null) {
+                result.symbolInfo = {
+                    symbolId: symbolId,
+                    state: location,
+                }
+                break
+            }
+        }
+
+        const components = floorplanService.getComponents()
+        for (const componentId in components) {
+            const component = floorplanService.getComponent(componentId)
+            const location = component.isContain(position)
+            if (location) {
+                result.componentInfo = {
+                    componentId: componentId,
+                    state: 'all',
+                }
+                break
+            }
+        }
+
+        const tags = floorplanService.getTags()
+        for (const tagId in tags) {
+            const tag = floorplanService.getTag(tagId)
+            const location = tag.isContain(position)
+            if (location) {
+                result.tagInfo = {
+                    tagId: tagId,
+                    state: 'all',
+                }
+                break
+            }
+        }
+
+        const furnitures = floorplanService.getFurnitures()
+        for (const furnitureId in furnitures) {
+            const furniture = floorplanService.getFurniture(furnitureId)
+            const location = furniture.isContain(position)
+            if (location) {
+                result.furnitureInfo = {
+                    furnitureId: furnitureId,
+                    state: 'all',
+                }
+                break
+            }
+        }
+
+        return result
+    }
+
+    // position用来判断是否在墙的symbol上
+    updateSelectInfos(nearest, minDistance) {
+        // 墙角状态是否改变
+        let flag1 = false
+        if (nearest.minPoint != null) {
+            if (nearest.minPoint.distance < minDistance) {
+                flag1 = this.isChanged(nearest.minPoint.pointId, SelectState.Select, 1)
+                this.pointInfo = {
+                    pointId: nearest.minPoint.pointId,
+                    state: SelectState.Select,
+                }
+            } else {
+                flag1 = this.isChanged(nearest.minPoint.pointId, null, 1)
+                this.pointInfo = {
+                    pointId: nearest.minPoint.pointId,
+                    state: null,
+                }
+            }
+        } else {
+            flag1 = this.isChanged(null, null, 1)
+            this.pointInfo = {
+                pointId: null,
+                state: null,
+            }
+        }
+        // 墙面状态是否改变
+        let flag2 = false
+        if (nearest.minWall != null) {
+            if (nearest.minWall.distance < minDistance) {
+                flag2 = this.isChanged(nearest.minWall.wallId, SelectState.Select, 2)
+                this.wallInfo = {
+                    wallId: nearest.minWall.wallId,
+                    state: SelectState.Select,
+                }
+            } else {
+                flag2 = this.isChanged(nearest.minWall.wallId, null, 2)
+                this.wallInfo = {
+                    wallId: nearest.minWall.wallId,
+                    state: null,
+                }
+            }
+        } else {
+            flag2 = this.isChanged(null, null, 2)
+            this.wallInfo = {
+                wallId: null,
+                state: null,
+            }
+        }
+        // symbols状态是否改变
+        const flag3 = this.isChanged(nearest.symbolInfo.symbolId, nearest.symbolInfo.state, 3)
+        this.symbolInfo = {
+            symbolId: nearest.symbolInfo.symbolId,
+            state: nearest.symbolInfo.state,
+        }
+
+        const flag4 = this.isChanged(nearest.componentInfo.componentId, nearest.componentInfo.state, 4)
+        this.componentInfo = {
+            componentId: nearest.componentInfo.componentId,
+            state: nearest.componentInfo.state,
+        }
+
+        const flag5 = this.isChanged(nearest.tagInfo.tagId, nearest.tagInfo.state, 5)
+        this.tagInfo = {
+            tagId: nearest.tagInfo.tagId,
+            state: nearest.tagInfo.state,
+        }
+
+        const flag6 = this.isChanged(nearest.furnitureInfo.furnitureId, nearest.furnitureInfo.state, 6)
+        this.furnitureInfo = {
+            furnitureId: nearest.furnitureInfo.furnitureId,
+            state: nearest.furnitureInfo.state,
+        }
+
+        return flag1 || flag2 || flag3 || flag4 || flag5 || flag6
+    }
+
+    // type是1表示点,2表示墙,3表示symbol,4表示component, 5表示tag,6表示furniture
+    isChanged(vectorId, state, type) {
+        let flag = false
+        if (type == 1) {
+            if (state == null && state == this.pointInfo.state) {
+                flag = false
+            } else if (this.pointInfo.pointId == vectorId && state == this.pointInfo.state) {
+                flag = false
+            } else {
+                flag = true
+            }
+        } else if (type == 2) {
+            if (state == null && state == this.wallInfo.state) {
+                flag = false
+            } else if (this.wallInfo.wallId == vectorId && state == this.wallInfo.state) {
+                flag = false
+            } else {
+                flag = true
+            }
+        } else if (type == 3) {
+            if (state == null && state == this.symbolInfo.state) {
+                flag = false
+            } else if (this.symbolInfo.symbolId == vectorId && state == this.symbolInfo.state) {
+                flag = false
+            } else {
+                flag = true
+            }
+        } else if (type == 4) {
+            if (state == null && state == this.componentInfo.state) {
+                flag = false
+            } else if (this.componentInfo.componentId == vectorId && state == this.componentInfo.state) {
+                flag = false
+            } else {
+                flag = true
+            }
+        } else if (type == 5) {
+            if (state == null && state == this.tagInfo.state) {
+                flag = false
+            } else if (this.tagInfo.tagId == vectorId && state == this.tagInfo.state) {
+                flag = false
+            } else {
+                flag = true
+            }
+        } else if (type == 6) {
+            if (state == null && state == this.furnitureInfo.state) {
+                flag = false
+            } else if (this.furnitureInfo.furnitureId == vectorId && state == this.furnitureInfo.state) {
+                flag = false
+            } else {
+                flag = true
+            }
+        }
+
+        return flag
+    }
+
+    updateSelectItem() {
+        if (this.tagInfo.tagId != null && this.tagInfo.state != null) {
+            const tag = floorplanService.getTag(this.tagInfo.tagId)
+            stateService.setSelectItem(this.tagInfo.tagId, tag.geoType, this.tagInfo.state)
+        } else if (this.componentInfo.componentId != null && this.componentInfo.state != null) {
+            const component = floorplanService.getComponent(this.componentInfo.componentId)
+            stateService.setSelectItem(this.componentInfo.componentId, component.geoType, this.componentInfo.state)
+        } else if (this.furnitureInfo.furnitureId != null && this.furnitureInfo.state != null) {
+            const furniture = floorplanService.getFurniture(this.furnitureInfo.furnitureId)
+            stateService.setSelectItem(this.furnitureInfo.furnitureId, furniture.geoType, this.furnitureInfo.state)
+        } else if (this.symbolInfo.symbolId != null && this.symbolInfo.state != null) {
+            const symbol = floorplanService.getSymbol(this.symbolInfo.symbolId)
+            stateService.setSelectItem(this.symbolInfo.symbolId, symbol.geoType, this.symbolInfo.state)
+        } else if (this.pointInfo.pointId != null && this.pointInfo.state != null) {
+            stateService.setSelectItem(this.pointInfo.pointId, VectorType.WallCorner, SelectState.Select)
+        } else if (this.wallInfo.wallId != null && this.wallInfo.state != null) {
+            stateService.setSelectItem(this.wallInfo.wallId, VectorType.Wall, SelectState.Select)
+        } else {
+            stateService.clearSelectItem()
+        }
+    }
+
+    clear() {
+        this.wallInfo = {
+            wallId: null,
+            state: null,
+        }
+
+        this.pointInfo = {
+            pointId: null,
+            state: null,
+        }
+
+        this.symbolInfo = {
+            symbolId: null,
+            state: null,
+        }
+
+        this.componentInfo = {
+            componentId: null,
+            state: null,
+        }
+
+        this.furnitureInfo = {
+            furnitureId: null,
+            state: null,
+        }
+
+        this.modifyPoint = null
+    }
+}
+const listenLayer = new ListenLayer()
+export { listenLayer }

+ 63 - 0
src/views/draw-file/board/editCAD/Load.js

@@ -0,0 +1,63 @@
+import { floorplanService } from './Service/FloorplanService.js'
+import { wallService } from './Service/WallService.js'
+import { symbolService } from './Service/SymbolService.js'
+import { componentService } from './Service/ComponentService.js'
+import { tagService } from './Service/TagService'
+import { furnitureService } from './Service/FurnitureService'
+
+export default class Load {
+    constructor(layer) {
+        this.layer = layer
+        this.version = 'v1.1'
+        this.vectorsJson = null
+        // 保存当前的数据
+        this.saveFloors = []
+        this.newVectorId = null
+    }
+
+    load(floorsData) {
+        for (let i = 0; i < floorsData.length; ++i) {
+            let floor = floorsData[i]
+            floorplanService.initFloor(i)
+            for (let key in floor.points) {
+                wallService.createPoint(floor.points[key].x, floor.points[key].y, floor.points[key].vectorId, i)
+            }
+
+            for (let key in floor.walls) {
+                let wall = wallService.createWall(floor.walls[key].start, floor.walls[key].end, floor.walls[key].vectorId, i)
+                wall.setChildren(floor.walls[key].children)
+            }
+
+            for (let key in floor.symbols) {
+                let symbol = symbolService.createSymbol(floor.symbols[key].startPoint, floor.symbols[key].endPoint, floor.symbols[key].geoType, floor.symbols[key].parent, floor.symbols[key].vectorId)
+                symbol.openSide = floor.symbols[key].openSide
+                symbol.enter = floor.symbols[key].enter
+                symbol.points2d = JSON.parse(JSON.stringify(floor.symbols[key].points2d))
+            }
+
+            for (let key in floor.components) {
+                let component = componentService.createComponent(floor.components[key].center, floor.components[key].geoType, floor.components[key].vectorId)
+                component.angle = floor.components[key].angle
+                component.sideThickness = floor.components[key].sideThickness
+                component.sideWidth = floor.components[key].sideWidth
+                component.points2d = JSON.parse(JSON.stringify(floor.components[key].points2d))
+            }
+
+            for (let key in floor.tags) {
+                let tag = tagService.createTag(floor.tags[key].center, floor.tags[key].vectorId, i)
+                tag.setPoints2d()
+                tag.setTitle(floor.tags[key].title)
+                tag.setDes(floor.tags[key].des)
+                tag.setUnit(floor.tags[key].unit)
+                tag.setAdding(false)
+            }
+
+            for (let key in floor.furnitures) {
+                let furniture = furnitureService.createFurniture(floor.furnitures[key].center, floor.furnitures[key].geoType, floor.furnitures[key].vectorId)
+                furniture.angle = floor.furnitures[key].angle
+            }
+        }
+    }
+
+  
+}

+ 678 - 0
src/views/draw-file/board/editCAD/MathUtil.js

@@ -0,0 +1,678 @@
+import Constant from './Constant'
+export default class MathUtil {
+    constructor() {}
+
+    getFixed(num, decimal) {
+        if (!decimal) {
+            decimal = 5
+        }
+        // return Math.floor(num * 10000) / 10000;
+        return parseFloat(num.toFixed(decimal))
+    }
+
+    // 求两个点的距离
+    getDistance(p1, p2) {
+        const x1 = p1.x
+        const y1 = p1.y
+        const x2 = p2.x
+        const y2 = p2.y
+        const num = Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2))
+        return this.getFixed(num)
+    }
+
+    createLine1(point1, point2) {
+        if (point1.x == point2.x && point1.y == point2.y) {
+            return null
+        } else if (this.getFixed(Math.abs(point1.x - point2.x)) == 0) {
+            return { x: point1.x }
+        } else if (this.getFixed(Math.abs(point1.y - point2.y)) == 0) {
+            return { y: point1.y }
+        }
+
+        const parametera = (point1.y - point2.y) / (point1.x - point2.x)
+        const parameterb = (point1.x * point2.y - point2.x * point1.y) / (point1.x - point2.x)
+        if (this.getFixed(parametera) == 0) {
+            return { y: this.getFixed(parameterb) }
+        }
+        const parameter = { a: this.getFixed(parametera), b: this.getFixed(parameterb) }
+        return parameter
+    }
+
+    createLine2(point, angle) {
+        if (angle == Math.PI / 2 || angle == 1.5 * Math.PI) {
+            return { x: point.x }
+        }
+        let a = Math.tan(angle)
+        let b = point.y - a * point.x
+        if (a != 0) {
+            return { a: a, b: b }
+        } else {
+            return { y: point.y }
+        }
+    }
+
+    // 与lineA平行并且point在线上
+    createLine3(lineA, point) {
+        const parameter = {}
+        if (typeof lineA.a === 'undefined') {
+            if (typeof lineA.x !== 'undefined') {
+                parameter.x = point.x
+            } else if (typeof lineA.y !== 'undefined') {
+                parameter.y = point.y
+            }
+        } else {
+            parameter.a = lineA.a
+            parameter.b = point.y - point.x * lineA.a
+        }
+        return parameter
+    }
+
+    create2AngleLine(point, angle, driftAngle) {
+        let line1 = this.createLine2(point, angle - driftAngle / 2)
+        let line2 = this.createLine2(point, angle + driftAngle / 2)
+        return { line1: line1, line2: line2 }
+    }
+
+    distanceForPoints(point1, point2) {
+        return Math.sqrt(Math.pow(point1.x - point2.x, 2) + Math.pow(point1.y - point2.y, 2))
+    }
+
+    //与line平行且两条线直接的距离是distance的两条线
+    getParallelLineForDistance(line, distance) {
+        let line1 = {}
+        line1.a = line.a
+        line1.b = line.b
+
+        let line2 = {}
+        line2.a = line.a
+        line2.b = line.b
+
+        if (typeof line.a == 'undefined') {
+            if (line.hasOwnProperty('x')) {
+                let x = line.x
+                line1.x = x + distance
+                line2.x = x - distance
+            } else if (line.hasOwnProperty('y')) {
+                let y = line.y
+                line1.y = y + distance
+                line2.y = y - distance
+            }
+        } else {
+            let angle = Math.atan(line.a)
+            let db = Math.abs(distance / Math.cos(angle))
+            let b = line.b
+            line1.b = b + db
+            line2.b = b - db
+        }
+
+        return { line1: line1, line2: line2 }
+    }
+
+    //获取扇形的两个端点
+    getEndpoint(point, angle, sectorAngle) {
+        const distance = 15
+        //line1是减,line2是加
+        let lines1 = this.create2AngleLine(point, angle, sectorAngle)
+        let line = this.createLine2(point, angle)
+        line = this.getLineForPoint(line, point)
+        let lines2 = this.getParallelLineForDistance(line, distance)
+
+        let point1 = this.getIntersectionPoint(lines1.line1, lines2.line1)
+        let point2 = this.getIntersectionPoint(lines1.line1, lines2.line2)
+        let point3 = this.getIntersectionPoint(lines1.line2, lines2.line1)
+        let point4 = this.getIntersectionPoint(lines1.line2, lines2.line2)
+
+        let angle1 = this.Angle(point, point1, { x: point.x + 1, y: point.y })
+        let angle2 = this.Angle(point, point2, { x: point.x + 1, y: point.y })
+        let angle3 = this.Angle(point, point3, { x: point.x + 1, y: point.y })
+        let angle4 = this.Angle(point, point4, { x: point.x + 1, y: point.y })
+        if (angle > Math.PI) {
+            angle = 2 * Math.PI - angle
+        }
+        if (Math.abs((angle1 + angle3) / 2 - angle) < Math.abs((angle2 + angle4) / 2 - angle)) {
+            return { p1: point1, p2: point3 }
+        } else {
+            return { p1: point2, p2: point4 }
+        }
+    }
+
+    // true表示逆时针,false表示顺时针
+    isClockwise(vertices) {
+        let area = 0
+        for (let i = 0; i < vertices.length; i++) {
+            const j = (i + 1) % vertices.length
+            area += vertices[i].x * vertices[j].y
+            area -= vertices[j].x * vertices[i].y
+        }
+        const sub = area / 2
+        if (sub > 0) {
+            // 逆时针
+            return true
+        } else {
+            // 顺时针
+            return false
+        }
+    }
+
+    reverse(points) {
+        const _points = []
+        for (let i = points.length - 1; i > -1; --i) {
+            _points.push(points[i])
+        }
+        return _points
+    }
+
+    //两条线的交点
+    getIntersectionPoint(parameter1, parameter2) {
+        if (this.isParallel(parameter1, parameter2)) {
+            return null
+        }
+        if (typeof parameter1.a == 'undefined' && typeof parameter2.a != 'undefined') {
+            if (parameter1.x) {
+                return { x: parameter1.x, y: parameter2.a * parameter1.x + parameter2.b }
+            } else if (parameter1.y) {
+                return { x: (parameter1.y - parameter2.b) / parameter2.a, y: parameter1.y }
+            }
+        } else if (typeof parameter2.a == 'undefined' && typeof parameter1.a != 'undefined') {
+            if (parameter2.x) {
+                return { x: parameter2.x, y: parameter1.a * parameter2.x + parameter1.b }
+            } else if (parameter2.y) {
+                return { x: (parameter2.y - parameter1.b) / parameter1.a, y: parameter2.y }
+            }
+        } else if (typeof parameter2.a == 'undefined' && typeof parameter1.a == 'undefined') {
+            if (parameter1.hasOwnProperty('x') && parameter2.hasOwnProperty('y')) {
+                return { x: parameter1.x, y: parameter2.y }
+            } else if (parameter1.hasOwnProperty('y') && parameter2.hasOwnProperty('x')) {
+                return { x: parameter2.x, y: parameter1.y }
+            } else {
+                return null
+            }
+        }
+
+        if (parameter1.a == parameter2.a) {
+            return null
+        }
+
+        let joinpointx = (parameter2.b - parameter1.b) / (parameter1.a - parameter2.a)
+        let joinpointy = (parameter1.a * parameter2.b - parameter2.a * parameter1.b) / (parameter1.a - parameter2.a)
+
+        let point = { x: joinpointx, y: joinpointy }
+        return point
+    }
+
+    // 直线的交点
+    getIntersectionPoint2(a, b, c, d) {
+        /** 1 解线性方程组, 求线段交点. **/
+
+        // 如果分母为0 则平行或共线, 不相交
+        const denominator = (b.y - a.y) * (d.x - c.x) - (a.x - b.x) * (c.y - d.y)
+        if (denominator == 0) {
+            return null
+        }
+
+        // 线段所在直线的交点坐标 (x , y)
+        const x = ((b.x - a.x) * (d.x - c.x) * (c.y - a.y) + (b.y - a.y) * (d.x - c.x) * a.x - (d.y - c.y) * (b.x - a.x) * c.x) / denominator
+        const y = -((b.y - a.y) * (d.y - c.y) * (c.x - a.x) + (b.x - a.x) * (d.y - c.y) * a.y - (d.x - c.x) * (b.y - a.y) * c.y) / denominator
+
+        return { x: x, y: y }
+    }
+
+    //两条线段交点
+    getIntersectionPoint3(a, b, c, d) {
+        const join = this.getIntersectionPoint2(a, b, c, d)
+        if (join) {
+            const x = join.x
+            const y = join.y // 交点在线段1上 且交点也在线段2上
+            /** 2 判断交点是否在两条线段上 **/
+            if ((x - a.x) * (x - b.x) <= 0.001 && (y - a.y) * (y - b.y) <= 0.001 && (x - c.x) * (x - d.x) <= 0.001 && (y - c.y) * (y - d.y) <= 0.001) {
+                // 返回交点p
+                return {
+                    x: x,
+                    y: y,
+                }
+            }
+            return null
+        }
+        return null
+    }
+
+    // 线段和直线是否相交
+    getIntersectionPoint4(point1, point2, line) {
+        const line1 = this.createLine1(point1, point2)
+        const join = this.getIntersectionPoint(line1, line)
+        if (join == null) {
+            return null
+        }
+        if (this.PointInSegment(join, point1, point2)) {
+            return join // 相交
+        } else {
+            return null
+        }
+    }
+
+    //返回true表示平行
+    isParallel(line1, line2) {
+        if (typeof line1.a == 'undefined' && typeof line2.a == 'undefined') {
+            if (line1.hasOwnProperty('x') && line2.hasOwnProperty('x')) {
+                return true
+            } else if (line1.hasOwnProperty('y') && line2.hasOwnProperty('y')) {
+                return true
+            } else {
+                return false
+            }
+        } else if (typeof line1.a == 'undefined' || typeof line2.a == 'undefined') {
+            return false
+        } else if (this.getFixed(line1.a) == this.getFixed(line2.a)) {
+            return true
+        } else {
+            return false
+        }
+    }
+
+    //两条相交的线段的夹角,永远小于180度
+    Angle(o, s, e) {
+        let cosfi = 0,
+            fi = 0,
+            norm = 0
+        let dsx = s.x - o.x
+        let dsy = s.y - o.y
+        let dex = e.x - o.x
+        let dey = e.y - o.y
+
+        cosfi = dsx * dex + dsy * dey
+        norm = (dsx * dsx + dsy * dsy) * (dex * dex + dey * dey)
+        cosfi /= Math.sqrt(norm)
+
+        if (cosfi >= 1.0) return 0
+        //if (cosfi <= -1.0) return Math.PI;
+        if (cosfi <= -1.0) return Math.PI
+        fi = Math.acos(cosfi)
+
+        if ((180 * fi) / Math.PI < 180) {
+            //return 180 * fi / Math.PI;
+            return fi
+        } else {
+            //return 360 - 180 * fi / Math.PI;
+            return 2 * Math.PI - fi
+        }
+    }
+
+    //经过point且与line垂直的线
+    getLineForPoint(line, point) {
+        let parameter = {}
+        if (line.a == 0 || typeof line.a == 'undefined') {
+            if (line.hasOwnProperty('x')) {
+                parameter.y = point.y
+            } else if (line.hasOwnProperty('y')) {
+                parameter.x = point.x
+            }
+        } else {
+            parameter.a = -1 / line.a
+            parameter.b = point.y - point.x * parameter.a
+        }
+        return parameter
+    }
+
+    // 经过point且与line垂直的直线,该直线与line的交点
+    getJoinLinePoint(point, line) {
+        const verticalLine = this.getVerticalLine(line, point)
+        const join = this.getIntersectionPoint(line, verticalLine)
+        return join
+    }
+
+    // 点到直线的距离
+    getDisForPoinLine(point, line) {
+        const join = this.getJoinLinePoint(point, line)
+        return this.getDistance(point, join)
+    }
+
+    // 垂直线
+    getVerticalLine(line, point) {
+        if (typeof line.a === 'undefined') {
+            if (line.hasOwnProperty('x')) {
+                return { y: point.y }
+            } else if (line.hasOwnProperty('y')) {
+                return { x: point.x }
+            } else {
+                return null
+            }
+        } else if (line.a == 0) {
+            return { x: point.x }
+        } else {
+            const tl = {}
+            tl.a = -1 / line.a
+            const result = this.createLine3(tl, point)
+            return result
+        }
+    }
+
+    //point在直线上,只是不确定是否在线段上
+    //方法:point到startPoint和endPoint的距离之和与startPoint和endPoint之间的距离对比
+    isContainForSegment(point, startPoint, endPoint, minDis) {
+        if (!minDis) {
+            minDis = Constant.minRealDis
+        }
+        let dis1 = this.getDistance(startPoint, point) + this.getDistance(endPoint, point)
+        let dis2 = this.getDistance(startPoint, endPoint)
+        if (Math.abs(dis1 - dis2) < minDis) {
+            return true
+        } else {
+            return false
+        }
+    }
+
+    /*
+    //minDis
+    isPointInPoly(point, points, minDis) {
+        if (!minDis) {
+            minDis = Constant.minRealDis
+        }
+        const x = point.x
+        const y = point.y
+
+        let inside = false
+
+        // 是否在顶点附近
+        for (let i = 0; i < points.length; ++i) {
+            let distance = this.getDistance(point, points[i])
+            if (distance < minDis) {
+                return true
+            }
+        }
+
+        // 是否在边沿
+        for (let i = 0, j = points.length - 1; i < points.length; j = i++) {
+            let pt1 = points[i]
+            let pt2 = points[j]
+            const flag = this.isContainForSegment(point, pt1, pt2, minDis)
+            if (flag) {
+                return true
+            }
+        }
+
+        for (let i = 0, j = points.length - 1; i < points.length; j = i++) {
+            let pt1 = points[i]
+            let pt2 = points[j]
+            const xi = pt1.x
+            const yi = pt1.y
+            const xj = pt2.x
+            const yj = pt2.y
+
+            const intersect = yi > y != yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi
+            if (intersect) inside = !inside
+        }
+
+        return inside
+    }
+    */
+
+    isPointInPoly(point, points) {
+        const x = point.x
+        const y = point.y
+
+        let inside = false
+
+        for (let i = 0, j = points.length - 1; i < points.length; j = i++) {
+            let pt1 = points[i]
+            let pt2 = points[j]
+            const xi = pt1.x
+            const yi = pt1.y
+            const xj = pt2.x
+            const yj = pt2.y
+
+            const intersect = yi > y != yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi
+            if (intersect) inside = !inside
+        }
+
+        return inside
+    }
+
+    // 点到线段的距离
+    // 在minDistance范围内,会吸附到point1/point2上
+    // 返回值:type是1表示吸附在point1,是2表示吸附在point2,是0表示在线段point1-point2上;
+    getDisForPoinSegment(point, point1, point2, minDistance) {
+        const line = this.createLine1(point1, point2)
+        const join = this.getJoinLinePoint(point, line)
+        const dis = this.getDistance(point1, point2)
+        const dis1 = this.getDistance(join, point1)
+        const dis2 = this.getDistance(join, point2)
+        if (this.getDistance(join, point1) > dis || this.getDistance(join, point2) > dis) {
+            // 在线段外
+            if (dis1 < dis2 && dis1 < minDistance) {
+                return { type: 1, join: point1 }
+            } else if (dis2 < dis1 && dis2 < minDistance) {
+                return { type: 2, join: point2 }
+            } else {
+                return null
+            }
+        } else {
+            if (dis1 < minDistance) {
+                return { type: 1, join: point1 }
+            } else if (dis2 < minDistance) {
+                return { type: 2, join: point2 }
+            } else if (this.getDistance(point, join) < minDistance) {
+                return { type: 0, join: join }
+            }
+        }
+    }
+
+    PointInSegment(Q, pi, pj, minDis) {
+        if (this.getDistance(Q, pi) < Constant.minRealDis || this.getDistance(Q, pj) < Constant.minRealDis) {
+            return true
+        }
+
+        if (!minDis) {
+            minDis = 0.1
+        }
+        minDis = minDis / 2
+
+        const offset1 = (Q.x - pi.x) * (pj.y - pi.y) - (pj.x - pi.x) * (Q.y - pi.y)
+        const offset2 = Math.min(pi.x, pj.x) - Q.x
+        const offset3 = Q.x - Math.max(pi.x, pj.x)
+        const offset4 = Math.min(pi.y, pj.y) - Q.y
+        const offset5 = Q.y - Math.max(pi.y, pj.y)
+
+        if (
+            Math.abs(offset1) < minDis &&
+            (offset2 <= 0 || Math.abs(offset2) < minDis) &&
+            (offset3 <= 0 || Math.abs(offset3) < minDis) &&
+            (offset4 <= 0 || Math.abs(offset4) < minDis) &&
+            (offset5 <= 0 || Math.abs(offset5) < minDis)
+        ) {
+            return true
+        } else {
+            return false
+        }
+    }
+
+    clonePoint(p1, p2) {
+        p1.x = p2.x
+        p1.y = p2.y
+    }
+
+    equalPoint(p1, p2) {
+        if (p1.x == p2.x && p1.y == p2.y) {
+            return true
+        } else {
+            return false
+        }
+    }
+
+    crossTwoLines(point1, point2, point3, point4, dis) {
+        if (typeof dis == 'undefined') {
+            dis = Constant.minRealDis
+        }
+        const join = this.getIntersectionPoint2(point1, point2, point3, point4)
+        if (join != null) {
+            if (this.getDistance(point1, join) > dis && this.getDistance(point2, join) > dis && this.getDistance(point3, join) > dis && this.getDistance(point4, join) > dis) {
+                if (
+                    this.getDistance(point1, join) < this.getDistance(point1, point2) &&
+                    this.getDistance(point2, join) < this.getDistance(point1, point2) &&
+                    this.getDistance(point3, join) < this.getDistance(point3, point4) &&
+                    this.getDistance(point4, join) < this.getDistance(point3, point4)
+                ) {
+                    return true
+                } else {
+                    return false
+                }
+            }
+        } else {
+            if (this.PointInSegment(point1, point3, point4) || this.PointInSegment(point2, point3, point4)) {
+                return true
+            }
+        }
+        return false
+    }
+
+    getDisPointsLine(line, point, distance1, distance2) {
+        const newpoint1 = {}
+        const newpoint2 = {}
+        const result = {}
+        if (line.hasOwnProperty('x')) {
+            newpoint1.x = line.x
+            newpoint1.y = point.y - distance1
+            newpoint2.x = line.x
+            newpoint2.y = point.y + distance2
+        } else if (line.hasOwnProperty('y')) {
+            newpoint1.y = line.y
+            newpoint1.x = point.x - distance1
+            newpoint2.y = line.y
+            newpoint2.x = point.x + distance2
+        } else {
+            const a = Math.atan(line.a)
+            const t_line = { a: -1 / line.a }
+            const line_ab2 = this.createLine3(t_line, point)
+            const join = this.getIntersectionPoint(line, line_ab2)
+
+            newpoint1.x = join.x - distance1 * Math.cos(a)
+            newpoint1.y = join.y - distance1 * Math.sin(a)
+
+            newpoint2.x = join.x + distance2 * Math.cos(a)
+            newpoint2.y = join.y + distance2 * Math.sin(a)
+        }
+        result.newpoint1 = newpoint1
+        result.newpoint2 = newpoint2
+        return result
+    }
+
+    getBoundingBox(points) {
+        let minX = points[0].x
+        let maxX = points[0].x
+        let minY = points[0].y
+        let maxY = points[0].y
+
+        for (let i = 1; i < points.length; ++i) {
+            const point = points[i]
+            if (minX > point.x) {
+                minX = point.x
+            }
+            if (minY > point.y) {
+                minY = point.y
+            }
+            if (maxX < point.x) {
+                maxX = point.x
+            }
+            if (maxY < point.y) {
+                maxY = point.y
+            }
+        }
+
+        const box = {}
+        box.minX = minX
+        box.minY = minY
+        box.maxX = maxX
+        box.maxY = maxY
+
+        return box
+    }
+
+    ComputePolygonArea(points) {
+        const point_num = points.length
+        if (point_num < 3) {
+            return 0
+        }
+        let s = points[0].y * (points[point_num - 1].x - points[1].x)
+        for (let i = 1; i < point_num; ++i) s += points[i].y * (points[i - 1].x - points[(i + 1) % point_num].x)
+        return Math.abs(s / 2.0)
+    }
+
+    // 获取多边形重心
+    getPolygonCore(points) {
+        function Area(p0, p1, p2) {
+            let area = 0.0
+            area = p0.x * p1.y + p1.x * p2.y + p2.x * p0.y - p1.x * p0.y - p2.x * p1.y - p0.x * p2.y
+            return area / 2
+        }
+
+        let sum_x = 0
+        let sum_y = 0
+        let sum_area = 0
+        let p1 = points[1]
+        for (let i = 2; i < points.length; i++) {
+            const p2 = points[i]
+            const area = Area(points[0], p1, p2)
+            sum_area += area
+            sum_x += (points[0].x + p1.x + p2.x) * area
+            sum_y += (points[0].y + p1.y + p2.y) * area
+            p1 = p2
+        }
+        const xx = sum_x / sum_area / 3
+        const yy = sum_y / sum_area / 3
+        return {
+            x: xx,
+            y: yy,
+        }
+    }
+
+    // points1是否在points2里
+    isPolyInPoly(points1, points2, minDis) {
+        for (let i = 0; i < points1.length; ++i) {
+            let flag = false
+            for (let j = 0; j < points2.length; ++j) {
+                if (this.equalPoint(points1[i], points2[j])) {
+                    flag = true
+                    break
+                }
+            }
+            if (!flag) {
+                if (!this.isPointInPoly(points1[i], points2, minDis)) {
+                    return false
+                }
+            } else {
+                const nextIndex = i == points1.length - 1 ? 0 : i + 1
+                const mid = {
+                    x: (points1[i].x + points1[nextIndex].x) / 2,
+                    y: (points1[i].y + points1[nextIndex].y) / 2,
+                }
+                if (!this.isPointInPoly(mid, points2, minDis)) {
+                    return false
+                }
+            }
+        }
+        return true
+    }
+
+    dotPoints(pt1, pt2, point1, point2) {
+        let vt1 = {}
+        let vt2 = {}
+        vt1.start = {}
+        vt1.end = {}
+        vt1.start.x = 0
+        vt1.start.y = 0
+        vt1.end.x = pt2.x - pt1.x
+        vt1.end.y = pt2.y - pt1.y
+
+        vt2.start = {}
+        vt2.end = {}
+        vt2.start.x = 0
+        vt2.start.y = 0
+        vt2.end.x = point2.x - point1.x
+        vt2.end.y = point2.y - point1.y
+
+        let result = vt1.end.x * vt2.end.x + vt1.end.y * vt2.end.y
+        return result
+    }
+}
+
+const mathUtil = new MathUtil()
+export { mathUtil }

File diff suppressed because it is too large
+ 4127 - 0
src/views/draw-file/board/editCAD/Renderer/Draw.js


+ 364 - 0
src/views/draw-file/board/editCAD/Renderer/Render.js

@@ -0,0 +1,364 @@
+import VectorType from '../enum/VectorType.js'
+import { floorplanService } from '../Service/FloorplanService.js'
+import { elementService } from '../Service/ElementService.js'
+import { measureService } from '../Service/MeasureService'
+import { coordinate } from '../Coordinate.js'
+import { draw } from './Draw.js'
+import { roomService } from '../Service/RoomService.js'
+import { roomsUtil } from '../Room/RoomsUtil.js'
+import { floorplanData } from '../FloorplanData.js'
+import { furnitureService } from '../Service/FurnitureService.js'
+
+export default class Render {
+    constructor(layer) {
+        this.layer = layer
+        this.displayPanos = false
+    }
+
+    //绘制户型
+    drawGeometry(vector, styleType, flag) {
+        if (draw.context == null) {
+            return
+        }
+        switch (vector.geoType) {
+            case VectorType.Wall:
+                draw.drawWall(vector, styleType)
+                //draw.drawMeasures(vector);
+                return
+            case VectorType.Point:
+                draw.drawPoint(vector)
+                return
+            case VectorType.SingleDoor:
+                draw.drawSingleDoor(vector, styleType, flag)
+                return
+            case VectorType.DoubleDoor:
+                draw.drawDoubleDoor(vector, styleType, flag)
+                return
+            case VectorType.SlideDoor:
+                draw.drawSlideDoor(vector, styleType, flag)
+                return
+            case VectorType.SingleWindow:
+                draw.drawSingleWindow(vector, styleType)
+                return
+            case VectorType.FrenchWindow:
+                draw.drawFrenchWindow(vector, styleType)
+                return
+            case VectorType.BayWindow:
+                draw.drawBayWindow(vector, styleType)
+                return
+            case VectorType.Pass:
+                draw.drawPass(vector)
+                return
+            case VectorType.Beam:
+                draw.drawBeam(vector)
+                return
+            case VectorType.Flue:
+                draw.drawFlue(vector)
+                return
+            case VectorType.Corridor:
+                draw.drawCorridor(vector)
+                return
+            case VectorType.Tag:
+                draw.drawTag(vector, styleType, flag)
+                return
+        }
+
+        if (furnitureService.isFurniture(vector.geoType)) {
+            draw.drawFurniture(vector)
+        }
+    }
+
+    //绘制交互的元素
+    drawElement(vector) {
+        if (draw.context == null) {
+            return
+        }
+        switch (vector.geoType) {
+            case VectorType.Point:
+                draw.drawCircle(vector)
+                break
+            case VectorType.Line:
+                draw.drawLine(vector)
+                break
+        }
+    }
+
+    drawPanos(panos) {
+        // const angle = floorplanService.getAngle()
+        // for (let i = 0; i < panos.length; ++i) {
+        //     let pano = JSON.parse(JSON.stringify(panos[i]))
+        //     //可能要旋转角度
+        //     pano = coordinate.getVectorForRotate(pano, angle)
+        //     draw.drawCircle(pano)
+        //     //draw.drawText(pano, pano.vectorId)
+        // }
+
+        for (let i = 0; i < panos.length; ++i) {
+            draw.drawCircle(panos[i])
+        }
+    }
+
+    redrawElements() {
+        if (elementService.vCheckLines.X && elementService.vCheckLines.X.display) {
+            this.drawElement(elementService.vCheckLines.X)
+        }
+
+        if (elementService.vCheckLines.Y && elementService.vCheckLines.Y.display) {
+            this.drawElement(elementService.vCheckLines.Y)
+        }
+
+        if (elementService.startAddWall && elementService.startAddWall.display) {
+            this.drawElement(elementService.startAddWall)
+        }
+
+        if (elementService.newWall && elementService.newWall.display) {
+            this.drawElement(elementService.newWall)
+        }
+
+        if (elementService.symbolPoints.Start && elementService.symbolPoints.Start.display) {
+            this.drawElement(elementService.symbolPoints.Start)
+        }
+
+        if (elementService.symbolPoints.End && elementService.symbolPoints.End.display) {
+            this.drawElement(elementService.symbolPoints.End)
+        }
+
+        if (elementService.checkLines.X && elementService.checkLines.X.display) {
+            this.drawElement(elementService.checkLines.X)
+        }
+
+        if (elementService.checkLines.Y && elementService.checkLines.Y.display) {
+            this.drawElement(elementService.checkLines.Y)
+        }
+    }
+
+    redrawMeasures(styleType) {
+        //
+        draw.drawMeasure(measureService.measureLines.top, 'top', styleType)
+        draw.drawMeasure(measureService.measureLines.bottom, 'bottom', styleType)
+        draw.drawMeasure(measureService.measureLines.left, 'left', styleType)
+        draw.drawMeasure(measureService.measureLines.right, 'right', styleType)
+    }
+
+    redrawRooms(floor) {
+        let rooms = roomService.getRooms(floor)
+        for (let i = 0; i < rooms.length; ++i) {
+            let img = null
+            for (let j = 0; j < this.layer.app.CadManager.labels.length; ++j) {
+                if (rooms[i].tagName != null && rooms[i].tagName.trim() == this.layer.app.CadManager.labels[j].text) {
+                    if (this.layer.app.CadManager.labels[j].type == 'hall') {
+                        img = roomService.getHallImg()
+                        draw.drawRoomBackGround(rooms[i], img)
+                    } else if (this.layer.app.CadManager.labels[j].type == 'room') {
+                        img = roomService.getDefaultImg()
+                        draw.drawRoomBackGround(rooms[i], img)
+                    } else if (this.layer.app.CadManager.labels[j].type == 'other') {
+                        img = roomService.getOtherImg()
+                        draw.drawRoomBackGround(rooms[i], img)
+                    }
+                    break
+                }
+            }
+
+            if (img == null) {
+                img = roomService.getOtherImg()
+                draw.drawRoomBackGround(rooms[i], img)
+            }
+        }
+    }
+
+    autoRedraw() {
+        draw.clear()
+        if (this.displayPanos) {
+            this.drawPanos(floorplanData.panos)
+        }
+        let data = floorplanService.getFloorData()
+        if (!data) {
+            return
+        }
+        let walls = data.walls
+        for (let key in walls) {
+            this.drawGeometry(walls[key])
+        }
+
+        let points = data.points
+        for (let key in points) {
+            this.drawGeometry(points[key])
+        }
+
+        draw.drawSpecialPoint()
+
+        let symbols = data.symbols
+        for (let key in symbols) {
+            this.drawGeometry(symbols[key])
+            draw.drawSymbolPoint(symbols[key])
+        }
+        draw.drawSelectSymbolPoint()
+
+        let components = data.components
+        for (let key in components) {
+            this.drawGeometry(components[key])
+        }
+
+        let furnitures = data.furnitures
+        for (let key in furnitures) {
+            this.drawGeometry(furnitures[key])
+        }
+
+        let tags = data.tags
+        for (let key in tags) {
+            this.drawGeometry(tags[key])
+        }
+
+        this.redrawElements()
+        this.redrawMeasures()
+
+        // let _rooms = floorplanService.getRooms()
+        // if(_rooms.length == 0){
+        //     roomsUtil.start()
+        // }
+        // let rooms = floorplanService.getRooms()
+        // for (let i = 0; i < rooms.length; ++i) {
+        //     draw.drawText(rooms[i].center, rooms[i].roomId, false, 0)
+        // }
+    }
+
+    autoRedrawForImg() {
+        draw.clear()
+
+        // if (this.displayPanos) {
+        //     this.drawPanos(this.layer.panos[floorplanService.currentFloor])
+        // }
+        let data = floorplanService.getFloorData()
+        if (!data) {
+            return
+        }
+        let walls = data.walls
+        for (let key in walls) {
+            this.drawGeometry(walls[key])
+        }
+
+        // let points = data.points
+        // for (let key in points) {
+        //     this.drawGeometry(points[key])
+        // }
+
+        let symbols = data.symbols
+        let noEnter = true
+        for (let key in symbols) {
+            this.drawGeometry(symbols[key], null, noEnter)
+        }
+
+        let components = data.components
+        for (let key in components) {
+            this.drawGeometry(components[key])
+        }
+
+        let furnitures = data.furnitures
+        for (let key in furnitures) {
+            this.drawGeometry(furnitures[key])
+        }
+
+        let tags = data.tags
+        for (let key in tags) {
+            this.drawGeometry(tags[key], null, true)
+        }
+
+        //this.redrawElements()
+    }
+
+    //下载图片
+    //style表示风格
+    autoRedrawForDownLoadImg(styleType) {
+        draw.clear()
+
+        if (styleType == 'style-1') {
+            draw.drawBackGround('#FFFFFF')
+            this.redrawRooms(floorplanService.getCurrentFloor())
+        } else if (styleType == 'style-2') {
+            draw.drawBackGround('#000000')
+            this.redrawRooms(floorplanService.getCurrentFloor())
+        } else if (styleType == 'style-3') {
+            draw.drawBackGround('#FFFFFF')
+        } else if (styleType == 'style-4') {
+            draw.drawBackGround('#000000')
+        }
+
+        let data = floorplanService.getFloorData()
+        if (!data) {
+            return
+        }
+        let walls = data.walls
+        for (let key in walls) {
+            this.drawGeometry(walls[key], styleType)
+        }
+
+        let symbols = data.symbols
+        let noEnter = false
+        for (let key in symbols) {
+            this.drawGeometry(symbols[key], styleType, noEnter)
+        }
+
+        let components = data.components
+        for (let key in components) {
+            this.drawGeometry(components[key])
+        }
+
+        let furnitures = data.furnitures
+        for (let key in furnitures) {
+            this.drawGeometry(furnitures[key])
+        }
+        let tags = data.tags
+        for (let key in tags) {
+            this.drawGeometry(tags[key], styleType)
+        }
+
+        this.redrawMeasures(styleType)
+        draw.drawCompass(styleType)
+    }
+
+    redrawCore() {
+        console.log('重绘!')
+        draw.clear()
+
+        let data = floorplanService.getFloorData()
+        if (!data) {
+            return
+        }
+        let walls = data.walls
+        for (let key in walls) {
+            this.drawGeometry(walls[key])
+        }
+
+        let points = data.points
+        for (let key in points) {
+            this.drawGeometry(points[key])
+        }
+
+        let symbols = data.symbols
+        for (let key in symbols) {
+            this.drawGeometry(symbols[key])
+        }
+
+        let components = data.components
+        for (let key in components) {
+            this.drawGeometry(components[key])
+        }
+
+        let furnitures = data.furnitures
+        for (let key in furnitures) {
+            this.drawGeometry(furnitures[key])
+        }
+    }
+
+    clear() {
+        draw.clear()
+    }
+
+    getContext() {
+        return draw.context
+    }
+}
+
+// const render = new Render()
+// export { render }

+ 130 - 0
src/views/draw-file/board/editCAD/Service/AnalyService.js

@@ -0,0 +1,130 @@
+//解析来自算法部的数据:https://4dkk.4dage.com/data/datat-uXiVK7k/floorplan_cad.json?_=0
+import { floorplanService } from './FloorplanService'
+import { wallService } from './WallService'
+import { floorplanData } from '../FloorplanData'
+import VectorType from '../enum/VectorType.js'
+
+export default class AnalyService {
+    constructor(layer) {
+        this.layer = layer
+        this.app = this.layer.app
+        this.houseData = null
+    }
+
+    initVectors(data) {
+        let floors = data.floors
+        let currentId = -1
+        let offWallId = 0 //算法部的id都是从0开始,且每层楼的id都是从0开始
+        let offPointId = 0
+        for (let i = 0; i < floors.length; ++i) {
+            let floorNum = floors[i].subgroup
+            let floor = floors[i]
+            floorplanData.floors[floorNum] = {}
+            floorplanData.floors[floorNum].points = {}
+            floorplanData.floors[floorNum].walls = {}
+            floorplanData.floors[floorNum].symbols = {}
+            floorplanData.floors[floorNum].components = {}
+            floorplanData.floors[floorNum].tags = {}
+            floorplanData.floors[floorNum].furnitures = {}
+            floorplanData.floors[floorNum].boundingBox = {}
+            floorplanData.floors[floorNum].rooms = []
+            let minX = null,
+                minY = null,
+                maxX = null,
+                maxY = null
+
+            for (let j = 0; j < floor['vertex-xy'].length; ++j) {
+                let vectorId = floor['vertex-xy'][j].id + offPointId
+                if (currentId < vectorId) {
+                    currentId = vectorId
+                }
+                vectorId = VectorType.Point + vectorId
+                let point = {
+                    x: floor['vertex-xy'][j].x,
+                    y: floor['vertex-xy'][j].y,
+                }
+                wallService.createPoint(point.x, point.y, vectorId, floorNum)
+                if (minX == null || minX > point.x) {
+                    minX = point.x
+                }
+                if (minY == null || minY > point.y) {
+                    minY = point.y
+                }
+
+                if (maxX == null || maxX < point.x) {
+                    maxX = point.x
+                }
+                if (maxY == null || maxY < point.y) {
+                    maxY = point.y
+                }
+            }
+            offWallId = currentId + 1
+
+            floorplanData.floors[floorNum].boundingBox.minX = minX
+            floorplanData.floors[floorNum].boundingBox.minY = minY
+            floorplanData.floors[floorNum].boundingBox.maxX = maxX
+            floorplanData.floors[floorNum].boundingBox.maxY = maxY
+
+            for (let j = 0; j < floor['segment'].length; ++j) {
+                let vectorId = floor['segment'][j].id + offWallId
+                if (currentId < vectorId) {
+                    currentId = vectorId
+                }
+                vectorId = VectorType.Wall + vectorId
+                let start = VectorType.Point + (floor['segment'][j].a + offPointId)
+                let end = VectorType.Point + (floor['segment'][j].b + offPointId)
+
+                wallService.createWall(start, end, vectorId, floorNum)
+            }
+
+            offWallId = currentId + 1
+            offPointId = currentId + 1
+        }
+        floorplanService.setCurrentId(currentId + 1)
+        const currentFloorNum = this.app.core.get('Player').model.currentFloor.floorIndex
+        floorplanService.setCurrentFloor(currentFloorNum)
+        //随心装的json数据
+        //this.houseData = this.createDecorateData(floorplanData)
+    }
+
+    //随心装数据,houseType.json
+    createDecorateData(floorplanData) {
+        let house = {}
+        house.name = 'houseType.json'
+        house.version = '2.1'
+        house.floors = []
+
+        for (let i = 0; i < floorplanData.floors.length; ++i) {
+            let item = {}
+            item.points = []
+            item.walls = []
+
+            //floorplanData.floors.points
+            //floorplanData.floors.walls
+            for (let key in floorplanData.floors[i].points) {
+                let point = {}
+                point.x = floorplanData.floors[i].points[key].x
+                point.y = floorplanData.floors[i].points[key].y
+                point.parent = floorplanData.floors[i].points[key].parent
+                point.vectorId = floorplanData.floors[i].points[key].vectorId
+
+                item.points.push(point)
+            }
+
+            for (let key in floorplanData.floors[i].walls) {
+                let wall = {}
+                wall.start = floorplanData.floors[i].walls[key].start
+                wall.end = floorplanData.floors[i].walls[key].end
+
+                wall.children = []
+                wall.vectorId = floorplanData.floors[i].walls[key].vectorId
+                wall.width = 0.2
+
+                item.walls.push(wall)
+            }
+
+            house.floors.push(item)
+        }
+        return house
+    }
+}

+ 25 - 0
src/views/draw-file/board/editCAD/Service/CompassService.js

@@ -0,0 +1,25 @@
+export default class CompassService {
+    constructor() {
+        this.whiteImg = null
+        this.blackImg = null
+    }
+
+    setWhiteImg(img) {
+        this.whiteImg = img
+    }
+
+    setBlackImg(img) {
+        this.blackImg = img
+    }
+
+    getWhiteImg() {
+        return this.whiteImg
+    }
+
+    getBlackImg() {
+        return this.blackImg
+    }
+}
+
+const compassService = new CompassService()
+export { compassService }

+ 55 - 0
src/views/draw-file/board/editCAD/Service/ComponentService.js

@@ -0,0 +1,55 @@
+import VectorType from '../enum/VectorType.js'
+import Beam from '../Geometry/Beam.js'
+import Flue from '../Geometry/Flue.js'
+import Corridor from '../Geometry/Corridor.js'
+import { floorplanService } from './FloorplanService'
+
+export class ComponentService {
+    constructor() {
+        this.sideWidth = 0.65
+        this.sideThickness = 0.65
+    }
+
+    // 新建component
+    createComponent(position, geoType, vectorId) {
+        let component = null
+        switch (geoType) {
+            case VectorType.Beam:
+                component = new Beam(position, vectorId)
+                break
+            case VectorType.Flue:
+                component = new Flue(position, vectorId)
+                break
+            case VectorType.Corridor:
+                component = new Corridor(position, vectorId)
+                break
+        }
+
+        component.setPoints2d()
+        floorplanService.addComponent(component)
+        return component
+    }
+
+    isComponent(geoType) {
+        switch (geoType) {
+            case VectorType.Beam:
+                return true
+            case VectorType.Flue:
+                return true
+            case VectorType.Corridor:
+                return true
+        }
+        return false
+    }
+
+    setComponentInfo(componentInfo) {
+        let component = floorplanService.getComponent(componentInfo.vectorId)
+        component.vectorId = componentInfo.vectorId
+        component.angle = componentInfo.angle
+        component.center = JSON.parse(JSON.stringify(componentInfo.center))
+        component.points2d = JSON.parse(JSON.stringify(componentInfo.points2d))
+    }
+}
+
+const componentService = new ComponentService()
+export { componentService }

+ 243 - 0
src/views/draw-file/board/editCAD/Service/ElementService.js

@@ -0,0 +1,243 @@
+import Point from '../Geometry/Point.js'
+import Line from '../Geometry/Line.js'
+import ElementEvents from '../enum/ElementEvents.js'
+import { listenLayer } from '../ListenLayer'
+import Constant from '../Constant'
+import { floorplanService } from './FloorplanService'
+import { mathUtil } from '../MathUtil.js'
+import { wallService } from './WallService.js'
+
+export class ElementService {
+    constructor() {
+        this.startAddWall = null
+        this.newWall = null
+        this.symbolPoints = {
+            Start: null,
+            End: null,
+        }
+        this.checkLines = {
+            X: null,
+            Y: null,
+        }
+
+        this.vCheckLines = {
+            X: null,
+            Y: null,
+        }
+
+        this.init()
+    }
+
+    init() {
+        this.startAddWall = new Point(0, 0)
+        this.startAddWall.name = ElementEvents.StartAddWall
+
+        this.newWall = new Line({ x: 0, y: 0 }, { x: 1, y: 1 })
+        this.newWall.name = ElementEvents.NewWall
+
+        this.symbolPoints.Start = new Point(0, 0)
+        this.symbolPoints.Start.name = ElementEvents.StartSymbolPoints
+
+        this.symbolPoints.End = new Point(0, 0)
+        this.symbolPoints.End.name = ElementEvents.EndSymbolPoints
+
+        this.checkLines.X = new Line({ x: 0, y: 0 }, { x: 1, y: 1 })
+        this.checkLines.X.name = ElementEvents.CheckLinesX
+
+        this.checkLines.Y = new Line({ x: 0, y: 0 }, { x: 1, y: 1 })
+        this.checkLines.Y.name = ElementEvents.CheckLinesY
+
+        this.vCheckLines.X = new Line({ x: 0, y: 0 }, { x: 1, y: 1 })
+        this.vCheckLines.X.name = ElementEvents.VCheckLinesX
+
+        this.vCheckLines.Y = new Line({ x: 0, y: 0 }, { x: 1, y: 1 })
+        this.vCheckLines.Y.name = ElementEvents.VCheckLinesY
+    }
+
+    showStartAddWall() {
+        this.startAddWall.display = true
+    }
+
+    hideStartAddWall() {
+        this.startAddWall.display = false
+    }
+
+    setStartAddWall(position) {
+        this.startAddWall.setPosition(position)
+    }
+
+    showSymbolPoints() {
+        this.symbolPoints.Start.display = true
+        this.symbolPoints.End.display = true
+    }
+
+    hideSymbolPoints() {
+        this.symbolPoints.Start.display = false
+        this.symbolPoints.End.display = false
+    }
+
+    setSymbolPoints(start, end) {
+        this.symbolPoints.Start.setPosition(start)
+        this.symbolPoints.End.setPosition(end)
+    }
+
+    showNewWall() {
+        this.newWall.display = true
+    }
+
+    hideNewWall() {
+        this.newWall.display = false
+    }
+
+    setNewWall(point1, point2) {
+        this.newWall.setPositions(point1, point2)
+    }
+
+    setNewWallStartPosition(startPosition) {
+        this.newWall.start.x = startPosition.x
+        this.newWall.start.y = startPosition.y
+    }
+
+    setNewWallEndPosition(endPosition) {
+        this.newWall.end.x = endPosition.x
+        this.newWall.end.y = endPosition.y
+    }
+
+    setNewWallState(state) {
+        this.newWall.state = state
+    }
+
+    showCheckLinesX() {
+        this.checkLines.X.display = true
+    }
+
+    hideCheckLinesX() {
+        this.checkLines.X.display = false
+    }
+
+    setCheckLinesX(point1, point2) {
+        this.checkLines.X.setPositions(point1, point2)
+    }
+
+    showCheckLinesY() {
+        this.checkLines.Y.display = true
+    }
+
+    hideCheckLinesY() {
+        this.checkLines.Y.display = false
+    }
+
+    setCheckLinesY(point1, point2) {
+        this.checkLines.Y.setPositions(point1, point2)
+    }
+
+    showVCheckLinesX() {
+        this.vCheckLines.X.display = true
+    }
+
+    hideVCheckLinesX() {
+        this.vCheckLines.X.display = false
+    }
+
+    setVCheckLinesX(point1, point2) {
+        this.vCheckLines.X.setPositions(point1, point2)
+    }
+
+    showVCheckLinesY() {
+        this.vCheckLines.Y.display = true
+    }
+
+    hideVCheckLinesY() {
+        this.vCheckLines.Y.display = false
+    }
+
+    setVCheckLinesY(point1, point2) {
+        this.vCheckLines.Y.setPositions(point1, point2)
+    }
+
+    hideAll() {
+        this.hideCheckLinesX()
+        this.hideCheckLinesY()
+        this.hideStartAddWall()
+        this.hideNewWall()
+        this.hideSymbolPoints()
+        this.hideVCheckLinesX()
+        this.hideVCheckLinesY()
+    }
+
+    execute(startPosition, position) {
+        this.hideVCheckLinesX()
+        this.hideVCheckLinesY()
+        this.hideCheckLinesX()
+        this.hideCheckLinesY()
+
+        if (listenLayer.modifyPoint) {
+            if (listenLayer.modifyPoint.linkedPointIdX) {
+                const linkedPointX = floorplanService.getPoint(listenLayer.modifyPoint.linkedPointIdX)
+                this.setCheckLinesX(linkedPointX, position)
+                this.showCheckLinesX()
+            }
+
+            if (listenLayer.modifyPoint.linkedPointIdY) {
+                const linkedPointY = floorplanService.getPoint(listenLayer.modifyPoint.linkedPointIdY)
+                this.setCheckLinesY(linkedPointY, position)
+                this.showCheckLinesY()
+            }
+        }
+        //垂直校验
+        if (startPosition) {
+            if (Math.abs(position.x - startPosition.x) < Constant.minAdsorb) {
+                position.x = startPosition.x
+                this.setVCheckLinesX(startPosition, position)
+                this.showVCheckLinesX()
+            }
+
+            if (Math.abs(position.y - startPosition.y) < Constant.minAdsorb) {
+                position.y = startPosition.y
+                this.setVCheckLinesY(startPosition, position)
+                this.showVCheckLinesY()
+            }
+
+            if (mathUtil.equalPoint(position, startPosition)) {
+                this.hideVCheckLinesX()
+                this.hideVCheckLinesY()
+            }
+        }
+    }
+
+    //pointId是角度的顶点
+    //exceptPointId表示position对应的pointId(如果有的话)
+    checkAngle(position, pointId, exceptPointId) {
+        //type:1表示90°,2表示180°
+        function ajust(position, point1, point2, type) {
+            let line = mathUtil.createLine1(point1, point2)
+            let join = null
+            if (type == 1) {
+                let vLine = mathUtil.getVerticalLine(line, point1)
+                join = mathUtil.getJoinLinePoint(position, vLine)
+            } else if (type == 2) {
+                join = mathUtil.getJoinLinePoint(position, line)
+            }
+            return join
+        }
+
+        let points = wallService.getNeighPoints(pointId, exceptPointId)
+        let point = floorplanService.getPoint(pointId)
+        let newPosition = null
+        for (let i = 0; i < points.length; ++i) {
+            let angle = mathUtil.Angle(point, position, points[i])
+            if (Math.abs((angle / Math.PI) * 180 - 90) < 5) {
+                newPosition = ajust(position, point, points[i], 1)
+            } else if (Math.abs((angle / Math.PI) * 180) < 5 || Math.abs((angle / Math.PI) * 180 - 180) < 5) {
+                newPosition = ajust(position, point, points[i], 2)
+            }
+            if (newPosition != null) {
+                return newPosition
+            }
+        }
+        return newPosition
+    }
+}
+
+const elementService = new ElementService()
+export { elementService }

+ 523 - 0
src/views/draw-file/board/editCAD/Service/FloorplanService.js

@@ -0,0 +1,523 @@
+import { floorplanData } from '../FloorplanData'
+import { coordinate } from '../Coordinate.js'
+import Constant from '../Constant'
+
+export class FloorplanService {
+    constructor() {
+        this.currentId = 0 // 当前可用id
+        this.currentFloor = 0 // 当前楼层,第一层是0
+        this.angle = 0 //旋转角度
+    }
+
+    setCurrentId(id) {
+        this.currentId = id
+    }
+
+    getCurrentId() {
+        return this.currentId
+    }
+
+    updateCurrentId() {
+        ++this.currentId
+    }
+
+    setCurrentFloor(floor) {
+        if (floorplanData.floors.length == 1) {
+            this.currentFloor = 0
+        } else {
+            this.currentFloor = floor
+        }
+    }
+
+    getCurrentFloor() {
+        return this.currentFloor
+    }
+
+    getCompass() {
+        return floorplanData.compass
+    }
+
+    setCompass(angle) {
+        floorplanData.compass = angle
+    }
+
+    getFloorNum() {
+        return floorplanData.floors.length
+    }
+
+    initFloor(floorNum) {
+        floorplanData.initFloor(floorNum)
+    }
+
+    getFloors() {
+        return floorplanData.floors
+    }
+
+    getPoint(pointId, floor) {
+        if (floor == null || typeof floor == 'undefined') {
+            floor = this.currentFloor
+        }
+        return floorplanData.floors[floor].points[pointId]
+    }
+
+    deletePoint(pointId, wallId, floor) {
+        if (floor == null || typeof floor == 'undefined') {
+            floor = this.currentFloor
+        }
+        let point = this.getPoint(pointId)
+        //有可能先删除墙,导致点没了
+        if (point) {
+            if (Object.keys(point.parent).length == 0) {
+                point = null
+                delete floorplanData.floors[floor].points[pointId]
+            } else if (Object.keys(point.parent).length == 1 && !wallId) {
+                delete floorplanData.floors[floor].points[pointId]
+            } else if (Object.keys(point.parent).length == 1 && point.parent[wallId]) {
+                delete floorplanData.floors[floor].points[pointId]
+            } else if (Object.keys(point.parent).length == 1 && !point.parent[wallId]) {
+                return
+            } else {
+                delete point.parent[wallId]
+            }
+        }
+    }
+
+    getWall(wallId, floor) {
+        if (floor == null || typeof floor == 'undefined') {
+            floor = this.currentFloor
+        }
+        return floorplanData.floors[floor].walls[wallId]
+    }
+
+    deleteWall(wallId, floor) {
+        if (floor == null || typeof floor == 'undefined') {
+            floor = this.currentFloor
+        }
+        let wall = this.getWall(wallId, floor)
+        for (let i = 0; i < wall.children.length; ++i) {
+            this.deleteSymbol(wall.children[i], floor)
+        }
+
+        this.deletePoint(wall.start, wallId, floor)
+        this.deletePoint(wall.end, wallId, floor)
+        delete floorplanData.floors[floor].walls[wallId]
+    }
+
+    deleteWallNoSymbol(wallId, floor) {
+        if (floor == null || typeof floor == 'undefined') {
+            floor = this.currentFloor
+        }
+        let wall = this.getWall(wallId, floor)
+        this.deletePoint(wall.start, wallId, floor)
+        this.deletePoint(wall.end, wallId, floor)
+        delete floorplanData.floors[floor].walls[wallId]
+    }
+
+    getAngle() {
+        return this.angle
+    }
+
+    setAngle(angle) {
+        this.angle = angle
+    }
+
+    setBoundingBox(boundingBox, floor) {
+        if (floor == null || typeof floor == 'undefined') {
+            floor = this.currentFloor
+        }
+        floorplanData.floors[floor].boundingBox = JSON.parse(JSON.stringify(boundingBox))
+    }
+
+    // getBoundingBox(floor) {
+    //     if (floor == null || typeof floor == 'undefined') {
+    //         floor = this.currentFloor
+    //     }
+    //     if (
+    //         floorplanData.floors[floor].boundingBox.hasOwnProperty('maxX') &&
+    //         floorplanData.floors[floor].boundingBox.hasOwnProperty('maxY') &&
+    //         floorplanData.floors[floor].boundingBox.hasOwnProperty('minX') &&
+    //         floorplanData.floors[floor].boundingBox.hasOwnProperty('minY')
+    //     ) {
+    //         return floorplanData.floors[floor].boundingBox
+    //     } else {
+    //         this.updateBoundingBox(floor)
+    //         return floorplanData.floors[floor].boundingBox
+    //     }
+    // }
+
+    getBoundingBox(floor) {
+        if (floor == null || typeof floor == 'undefined') {
+            let minX = null,
+                maxX = null,
+                minY = null,
+                maxY = null
+            for (let i = 0; i < floorplanData.floors.length; ++i) {
+                if (
+                    !floorplanData.floors[i].boundingBox.hasOwnProperty('maxX') ||
+                    !floorplanData.floors[i].boundingBox.hasOwnProperty('minX') ||
+                    !floorplanData.floors[i].boundingBox.hasOwnProperty('maxY') ||
+                    !floorplanData.floors[i].boundingBox.hasOwnProperty('minY')
+                ) {
+                    this.updateBoundingBox(i)
+                }
+                if (minX == null || minX > floorplanData.floors[i].boundingBox.minX) {
+                    minX = floorplanData.floors[i].boundingBox.minX
+                }
+                if (maxX == null || maxX < floorplanData.floors[i].boundingBox.maxX) {
+                    maxX = floorplanData.floors[i].boundingBox.maxX
+                }
+                if (minY == null || minY > floorplanData.floors[i].boundingBox.minY) {
+                    minY = floorplanData.floors[i].boundingBox.minY
+                }
+                if (maxY == null || maxY < floorplanData.floors[i].boundingBox.maxY) {
+                    maxY = floorplanData.floors[i].boundingBox.maxY
+                }
+            }
+
+            return {
+                minX: minX,
+                maxX: maxX,
+                minY: minY,
+                maxY: maxY,
+            }
+        } else {
+            return floorplanData.floors[floor].boundingBox
+        }
+    }
+
+    updateBoundingBox(floor) {
+        const points = this.getPoints(floor)
+        let minX = null,
+            maxX = null,
+            minY = null,
+            maxY = null
+        for (let key in points) {
+            let point = points[key]
+            if (minX == null || minX > point.x) {
+                minX = point.x
+            }
+            if (maxX == null || maxX < point.x) {
+                maxX = point.x
+            }
+            if (minY == null || minY > point.y) {
+                minY = point.y
+            }
+            if (maxY == null || maxY < point.y) {
+                maxY = point.y
+            }
+        }
+        this.setBoundingBox(
+            {
+                minX: minX,
+                maxX: maxX,
+                minY: minY,
+                maxY: maxY,
+            },
+            floor
+        )
+    }
+
+    getFloorData(floor) {
+        if (floor == null || typeof floor == 'undefined') {
+            floor = this.currentFloor
+        }
+        return floorplanData.floors[floor]
+    }
+
+    getWalls(floor) {
+        if (floor == null || typeof floor == 'undefined') {
+            floor = this.currentFloor
+        }
+        return floorplanData.floors[floor].walls
+    }
+
+    getPoints(floor) {
+        if (floor == null || typeof floor == 'undefined') {
+            floor = this.currentFloor
+        }
+        return floorplanData.floors[floor].points
+    }
+
+    getSymbol(symbolId, floor) {
+        if (floor == null || typeof floor == 'undefined') {
+            floor = this.currentFloor
+        }
+        return floorplanData.floors[floor].symbols[symbolId]
+    }
+
+    addWall(wall, floor) {
+        if (floor == null || typeof floor == 'undefined') {
+            floor = this.currentFloor
+        }
+        floorplanData.floors[floor].walls[wall.vectorId] = wall
+    }
+
+    addPoint(point, floor) {
+        if (floor == null || typeof floor == 'undefined') {
+            floor = this.currentFloor
+        }
+        floorplanData.floors[floor].points[point.vectorId] = point
+    }
+
+    addSymbol(symbol, floor) {
+        if (floor == null || typeof floor == 'undefined') {
+            floor = this.currentFloor
+        }
+        floorplanData.floors[floor].symbols[symbol.vectorId] = symbol
+    }
+
+    addComponent(component, floor) {
+        if (floor == null || typeof floor == 'undefined') {
+            floor = this.currentFloor
+        }
+        floorplanData.floors[floor].components[component.vectorId] = component
+    }
+
+    addFurniture(furniture, floor) {
+        if (floor == null || typeof floor == 'undefined') {
+            floor = this.currentFloor
+        }
+        floorplanData.floors[floor].furnitures[furniture.vectorId] = furniture
+    }
+
+    deleteSymbol(symbolId, floor) {
+        if (floor == null || typeof floor == 'undefined') {
+            floor = this.currentFloor
+        }
+        let symbol = this.getSymbol(symbolId, floor)
+        symbol = null
+        delete floorplanData.floors[floor].symbols[symbolId]
+    }
+
+    getComponent(componentId, floor) {
+        if (floor == null || typeof floor == 'undefined') {
+            floor = this.currentFloor
+        }
+        return floorplanData.floors[floor].components[componentId]
+    }
+
+    deleteComponent(componentId, floor) {
+        if (floor == null || typeof floor == 'undefined') {
+            floor = this.currentFloor
+        }
+        let component = this.getComponent(componentId, floor)
+        component = null
+        delete floorplanData.floors[floor].components[componentId]
+    }
+
+    getFurniture(furnitureId, floor) {
+        if (floor == null || typeof floor == 'undefined') {
+            floor = this.currentFloor
+        }
+        return floorplanData.floors[floor].furnitures[furnitureId]
+    }
+
+    deleteFurniture(furnitureId, floor) {
+        if (floor == null || typeof floor == 'undefined') {
+            floor = this.currentFloor
+        }
+        let furniture = this.getFurniture(furnitureId, floor)
+        furniture = null
+        delete floorplanData.floors[floor].furnitures[furnitureId]
+    }
+
+    addTag(tag, floor) {
+        if (floor == null || typeof floor == 'undefined') {
+            floor = this.currentFloor
+        }
+        floorplanData.floors[floor].tags[tag.vectorId] = tag
+    }
+
+    getTag(tagId, floor) {
+        if (floor == null || typeof floor == 'undefined') {
+            floor = this.currentFloor
+        }
+        return floorplanData.floors[floor].tags[tagId]
+    }
+
+    deleteTag(tagId, floor) {
+        if (floor == null || typeof floor == 'undefined') {
+            floor = this.currentFloor
+        }
+        let tag = this.getTag(tagId, floor)
+        tag = null
+        delete floorplanData.floors[floor].tags[tagId]
+    }
+
+    getSymbols(floor) {
+        if (floor == null || typeof floor == 'undefined') {
+            floor = this.currentFloor
+        }
+        return floorplanData.floors[floor].symbols
+    }
+
+    getComponents(floor) {
+        if (floor == null || typeof floor == 'undefined') {
+            floor = this.currentFloor
+        }
+        return floorplanData.floors[floor].components
+    }
+
+    getTags(floor) {
+        if (floor == null || typeof floor == 'undefined') {
+            floor = this.currentFloor
+        }
+        return floorplanData.floors[floor].tags
+    }
+
+    getFurnitures(floor) {
+        if (floor == null || typeof floor == 'undefined') {
+            floor = this.currentFloor
+        }
+        return floorplanData.floors[floor].furnitures
+    }
+
+    getAllBoundingBox() {
+        let bounds = []
+        for (let i = 0; i < floorplanData.floors.length; ++i) {
+            let minX, minY, maxX, maxY
+            let bound = {}
+            for (let key in floorplanData.floors[i].points) {
+                let x = floorplanData.floors[i].points[key].x
+                let y = floorplanData.floors[i].points[key].y
+                if (typeof minX == 'undefined' || minX > x) {
+                    minX = x
+                }
+                if (typeof maxX == 'undefined' || maxX < x) {
+                    maxX = x
+                }
+                if (typeof minY == 'undefined' || minY > y) {
+                    minY = y
+                }
+                if (typeof maxY == 'undefined' || maxY < y) {
+                    maxY = y
+                }
+            }
+
+            bound.left = minX
+            bound.top = maxY
+            bound.right = maxX
+            bound.bottom = minY
+
+            bounds.push(bound)
+        }
+        return bounds
+    }
+
+    getCadInfo(canvas) {
+        let cadInfo = []
+        let bounds = this.getAllBoundingBox()
+        for (let i = 0; i < bounds.length; ++i) {
+            let item = {}
+
+            let leftTop = coordinate.getScreenXY({
+                x: bounds[i].left,
+                y: bounds[i].top,
+            })
+
+            let rightBottom = coordinate.getScreenXY({
+                x: bounds[i].right,
+                y: bounds[i].bottom,
+            })
+
+            let left = leftTop.x
+            let top = leftTop.y
+
+            let right = canvas.width - rightBottom.x
+            let bottom = canvas.height - rightBottom.y
+
+            // item.left = Constant.ratio * left
+            // item.top = Constant.ratio * top
+            // item.right = Constant.ratio * right
+            // item.bottom = Constant.ratio * bottom
+            item.left = left
+            item.top = top
+            item.right = right
+            item.bottom = bottom
+
+            item.bound = bounds[i]
+            item.bound.top = -1 * item.bound.top
+            item.bound.bottom = -1 * item.bound.bottom
+            cadInfo.push(item)
+        }
+        return cadInfo
+    }
+
+    getRooms(floor) {
+        if (floor == null || typeof floor == 'undefined') {
+            floor = this.currentFloor
+        }
+        return floorplanData.floors[floor].rooms
+    }
+
+    clear() {
+        // for (let i = 0; i < floorplanData.floors.length; ++i) {
+        //     floorplanData.floors[i].points = {}
+        //     floorplanData.floors[i].walls = {}
+        //     floorplanData.floors[i].symbols = {}
+        //     floorplanData.floors[i].components = {}
+        //     floorplanData.floors[i].tags = {}
+        //     floorplanData.floors[i].boundingBox = {}
+        //     floorplanData.floors[i].rooms = []
+        // }
+        if (floorplanData.floors[this.currentFloor]) {
+            floorplanData.floors[this.currentFloor].points = {}
+            floorplanData.floors[this.currentFloor].walls = {}
+            floorplanData.floors[this.currentFloor].symbols = {}
+            floorplanData.floors[this.currentFloor].components = {}
+            floorplanData.floors[this.currentFloor].tags = {}
+            floorplanData.floors[this.currentFloor].furnitures = {}
+            floorplanData.floors[this.currentFloor].boundingBox = {}
+            floorplanData.floors[this.currentFloor].rooms = []
+        }
+
+        //floorplanData.angle = 0
+    }
+
+    // getBoundingBox2DPosition(floorIndex) {
+    //     let bound = floorplanData.floors[floorIndex].boundingBox
+    //     let leftTop = coordinate.getScreenXY({
+    //         x: bound.minX,
+    //         y: bound.maxY,
+    //     })
+
+    //     let rightBottom = coordinate.getScreenXY({
+    //         x: bound.maxX,
+    //         y: bound.minY,
+    //     })
+
+    //     return {
+    //         top: leftTop.y,
+    //         bottom: rightBottom.y,
+    //         left: leftTop.x,
+    //         right: rightBottom.x,
+    //     }
+    // }
+
+    //boundingBox3d是__sdk.core.get('Player').model.floors.index[floorIndex].boundingBox.Box3
+    getBoundingBox2DPosition(boundingBox3d) {
+        let leftTop = coordinate.getScreenXY({
+            x: boundingBox3d.min.x,
+            y: boundingBox3d.max.z,
+        })
+
+        let rightBottom = coordinate.getScreenXY({
+            x: boundingBox3d.max.x,
+            y: boundingBox3d.min.z,
+        })
+
+        return {
+            top: leftTop.y,
+            bottom: rightBottom.y,
+            left: leftTop.x,
+            right: rightBottom.x,
+        }
+    }
+
+    deleteFloorData() {
+        floorplanData.floors = []
+    }
+}
+
+const floorplanService = new FloorplanService()
+export { floorplanService }

+ 170 - 0
src/views/draw-file/board/editCAD/Service/FurnitureService.js

@@ -0,0 +1,170 @@
+import VectorType from '../enum/VectorType.js'
+import Furniture from '../Geometry/Furniture.js'
+import { floorplanService } from './FloorplanService'
+import { Furnitures } from '../enum/UIEvents'
+
+export class FurnitureService {
+    constructor() {
+        this.$app = null
+        this.furnitures = null
+    }
+    fetchFurnitures() {
+        if (this.furnitures) {
+            return
+        }
+        this.furnitures = {}
+        for (let key in Furnitures) {
+            // 测试代码
+            if (key != Furnitures.TV) {
+                continue
+            }
+
+            this.$app.store
+                .getAppImage(`images/cad/furnitures/${Furnitures[key]}.svg`)
+                .then(img => {
+                    this.furnitures[Furnitures[key]] = img
+                    console.log(this.furnitures)
+                })
+                .catch(err => {
+                    console.error(err)
+                })
+        }
+    }
+
+    // 新建component
+    createFurniture(position, geoType, vectorId) {
+        let furniture = null
+        switch (geoType) {
+            case VectorType.TV:
+                furniture = new Furniture(position, vectorId, VectorType.TV)
+                break
+            case VectorType.CombinationSofa:
+                furniture = new Furniture(position, vectorId, VectorType.CombinationSofa)
+                break
+            case VectorType.SingleSofa:
+                furniture = new Furniture(position, vectorId, VectorType.SingleSofa)
+                break
+            case VectorType.TeaTable:
+                furniture = new Furniture(position, vectorId, VectorType.TeaTable)
+                break
+            case VectorType.Carpet:
+                furniture = new Furniture(position, vectorId, VectorType.Carpet)
+                break
+            case VectorType.Plant:
+                furniture = new Furniture(position, vectorId, VectorType.Plant)
+                break
+            case VectorType.DiningTable:
+                furniture = new Furniture(position, vectorId, VectorType.DiningTable)
+                break
+
+            case VectorType.DoubleBed:
+                furniture = new Furniture(position, vectorId, VectorType.DoubleBed)
+                break
+            case VectorType.SingleBed:
+                furniture = new Furniture(position, vectorId, VectorType.SingleBed)
+                break
+            case VectorType.Wardrobe:
+                furniture = new Furniture(position, vectorId, VectorType.Wardrobe)
+                break
+            case VectorType.Dresser:
+                furniture = new Furniture(position, vectorId, VectorType.Dresser)
+                break
+            case VectorType.BedsideCupboard:
+                furniture = new Furniture(position, vectorId, VectorType.BedsideCupboard)
+                break
+            case VectorType.Pillow:
+                furniture = new Furniture(position, vectorId, VectorType.Pillow)
+                break
+
+            case VectorType.GasStove:
+                furniture = new Furniture(position, vectorId, VectorType.GasStove)
+                break
+            case VectorType.Cupboard:
+                furniture = new Furniture(position, vectorId, VectorType.Cupboard)
+                break
+            case VectorType.Bathtub:
+                furniture = new Furniture(position, vectorId, VectorType.Bathtub)
+                break
+            case VectorType.Closestool:
+                furniture = new Furniture(position, vectorId, VectorType.Closestool)
+                break
+            case VectorType.Washstand:
+                furniture = new Furniture(position, vectorId, VectorType.Washstand)
+                break
+
+            case VectorType.Desk:
+                furniture = new Furniture(position, vectorId, VectorType.Desk)
+                break
+            case VectorType.BalconyChair:
+                furniture = new Furniture(position, vectorId, VectorType.BalconyChair)
+                break
+            case VectorType.Elevator:
+                furniture = new Furniture(position, vectorId, VectorType.Elevator)
+                break
+        }
+
+        floorplanService.addFurniture(furniture)
+        return furniture
+    }
+
+    isFurniture(geoType) {
+        switch (geoType) {
+            case VectorType.TV:
+                return true
+            case VectorType.CombinationSofa:
+                return true
+            case VectorType.SingleSofa:
+                return true
+            case VectorType.TeaTable:
+                return true
+            case VectorType.Carpet:
+                return true
+            case VectorType.Plant:
+                return true
+            case VectorType.DiningTable:
+                return true
+            case VectorType.DoubleBed:
+                return true
+            case VectorType.SingleBed:
+                return true
+            case VectorType.Wardrobe:
+                return true
+            case VectorType.Dresser:
+                return true
+            case VectorType.BedsideCupboard:
+                return true
+            case VectorType.Pillow:
+                return true
+            case VectorType.GasStove:
+                return true
+            case VectorType.Cupboard:
+                return true
+            case VectorType.Bathtub:
+                return true
+            case VectorType.Closestool:
+                return true
+            case VectorType.Washstand:
+                return true
+            case VectorType.Desk:
+                return true
+            case VectorType.BalconyChair:
+                return true
+            case VectorType.Elevator:
+                return true
+        }
+        return false
+    }
+
+    setFurnitureInfo(furnitureInfo) {
+        let furniture = floorplanService.getFurniture(furnitureInfo.vectorId)
+        furniture.vectorId = furnitureInfo.vectorId
+        furniture.angle = furnitureInfo.angle
+        furniture.center = JSON.parse(JSON.stringify(furnitureInfo.center))
+    }
+    getFurniture(name) {
+        return this.furnitures[name]
+    }
+}
+
+const furnitureService = new FurnitureService()
+export { furnitureService }

+ 75 - 0
src/views/draw-file/board/editCAD/Service/HistoryService.js

@@ -0,0 +1,75 @@
+export class HistoryService {
+    constructor() {
+        this.history = {
+            records: [],
+            currentRecordIndex: -1,
+            state: {
+                pre: 0,
+                next: 0,
+            },
+        }
+    }
+
+    getCurrentRecordIndex() {
+        return this.history.currentRecordIndex
+    }
+
+    getHistoryRecord() {
+        if (this.history.currentRecordIndex == null || this.history.records.length == 0) {
+            return null
+        } else {
+            return this.history.records[this.history.currentRecordIndex]
+        }
+    }
+
+    getHistoryRecords() {
+        return this.history.records
+    }
+
+    getHistoryState() {
+        return this.history.state
+    }
+
+    addHistoryRecord(item) {
+        const len = this.history.records.length
+        if (len == 0) {
+            this.history.records.push(item)
+            this.history.currentRecordIndex = 0
+        } else if (this.history.currentRecordIndex + 1 == len) {
+            this.history.records.push(item)
+            ++this.history.currentRecordIndex
+        }
+        // 覆盖
+        else {
+            const records = this.history.records.slice(0, this.history.currentRecordIndex + 1)
+            records.push(item)
+            this.history.records = records
+            ++this.history.currentRecordIndex
+        }
+    }
+
+    setHistoryState(pre, next) {
+        this.history.state.pre = pre
+        this.history.state.next = next
+    }
+
+    undoHistoryRecord() {
+        --this.history.currentRecordIndex
+    }
+
+    redoHistoryRecord() {
+        ++this.history.currentRecordIndex
+    }
+
+    clearHistoryRecord() {
+        this.history.records = []
+        this.setHistoryState(0, 0)
+    }
+    hasRecords() {
+        return this.history.records.length > 0
+    }
+}
+
+const historyService = new HistoryService()
+window.historyService = historyService
+export { historyService }

+ 96 - 0
src/views/draw-file/board/editCAD/Service/StateService.js

@@ -0,0 +1,96 @@
+import VectorType from '../enum/VectorType.js'
+import SelectState from '../enum/SelectState.js'
+import { symbolService } from './SymbolService.js'
+import { componentService } from './ComponentService.js'
+import { furnitureService } from './FurnitureService.js'
+
+export default class StateService {
+    constructor() {
+        this.eventName = null
+        this.selectItem = null
+        this.focusItem = null
+        this.draggingItem = null
+    }
+
+    getEventName() {
+        return this.eventName
+    }
+
+    setEventName(eventName) {
+        this.eventName = eventName
+    }
+
+    clearEventName() {
+        this.eventName = null
+    }
+
+    // type表示类型,state默认是select,但是有的元素需要知道选中的是哪个顶点
+    setSelectItem(vectorId, type, state) {
+        this.selectItem = {}
+        this.selectItem.vectorId = vectorId
+        this.selectItem.type = type
+
+        if (symbolService.isSymbol(type)) {
+            if (state == SelectState.Select) {
+                this.selectItem.selectIndex = SelectState.All
+            } else {
+                this.selectItem.selectIndex = state
+            }
+        } else if (componentService.isComponent(type)) {
+            if (state == SelectState.Select) {
+                this.selectItem.selectIndex = SelectState.All
+            }
+        } else if (type == VectorType.Tag) {
+            if (state == SelectState.Select) {
+                this.selectItem.selectIndex = SelectState.All
+            } else {
+                this.selectItem.selectIndex = state
+            }
+        } else if (furnitureService.isFurniture(type)) {
+            if (state == SelectState.Select) {
+                this.selectItem.selectIndex = SelectState.All
+            }
+        }
+    }
+
+    getSelectItem() {
+        return this.selectItem
+    }
+
+    clearSelectItem() {
+        this.selectItem = null
+    }
+
+    getDraggingItem() {
+        return this.draggingItem
+    }
+
+    setDraggingItem(draggingItem) {
+        this.draggingItem = draggingItem
+    }
+
+    clearDraggingItem() {
+        this.draggingItem = null
+    }
+
+    getFocusItem() {
+        return this.focusItem
+    }
+
+    setFocusItem(focusItem) {
+        this.focusItem = focusItem
+    }
+
+    clearFocusItem() {
+        this.focusItem = null
+    }
+
+    clearItems() {
+        this.selectItem = null
+        this.focusItem = null
+        this.draggingItem = null
+    }
+}
+
+const stateService = new StateService()
+export { stateService }

+ 928 - 0
src/views/draw-file/board/editCAD/Service/SymbolService.js

@@ -0,0 +1,928 @@
+import { mathUtil } from '../MathUtil.js'
+import SingleDoor from '../Geometry/SingleDoor.js'
+import DoubleDoor from '../Geometry/DoubleDoor.js'
+import SlideDoor from '../Geometry/SlideDoor.js'
+import SingleWindow from '../Geometry/SingleWindow.js'
+import FrenchWindow from '../Geometry/FrenchWindow.js'
+import BayWindow from '../Geometry/BayWindow.js'
+import Pass from '../Geometry/Pass.js'
+import { coordinate } from '../Coordinate'
+import { floorplanService } from './FloorplanService'
+import { wallService } from './WallService.js'
+import VectorType from '../enum/VectorType.js'
+
+import Constant from '../Constant'
+
+export class SymbolService {
+    constructor() {
+        this.enterImg = null
+    }
+
+    // 新建symbol
+    createSymbol(start, end, geoType, parent, symbolId) {
+        let symbol = null
+        switch (geoType) {
+            case VectorType.BayWindow:
+                symbol = new BayWindow(start, end, symbolId)
+                break
+            case VectorType.FrenchWindow:
+                symbol = new FrenchWindow(start, end, symbolId)
+                break
+            case VectorType.SingleDoor:
+                symbol = new SingleDoor(start, end, symbolId)
+                break
+            case VectorType.DoubleDoor:
+                symbol = new DoubleDoor(start, end, symbolId)
+                break
+            case VectorType.SlideDoor:
+                symbol = new SlideDoor(start, end, symbolId)
+                break
+            case VectorType.SingleWindow:
+                symbol = new SingleWindow(start, end, symbolId)
+                break
+            case VectorType.Pass:
+                symbol = new Pass(start, end, symbolId)
+                break
+        }
+        if (symbol != null) {
+            symbol.setSymbolParent(parent)
+            symbol.setPoints2d()
+            floorplanService.addSymbol(symbol)
+        }
+        if (parent) {
+            const wall = floorplanService.getWall(parent)
+            wallService.addChildren(wall, symbol.vectorId)
+        }
+
+        return symbol
+    }
+
+    addSymbol(position, symbolType, wallId) {
+        const symbolLen = this.getDefaultSymbolLen(symbolType)
+        const wall = floorplanService.getWall(wallId)
+        const wallLine = wallService.getLine(wall)
+        position = mathUtil.getJoinLinePoint(position, wallLine)
+        // const twoParallels = mathUtil.getParallelLineForDistance(vSymbolLine, symbolLen / 2)
+        // const point1 = mathUtil.getIntersectionPoint(twoParallels.line1, wallLine)
+        // const point2 = mathUtil.getIntersectionPoint(twoParallels.line2, wallLine)
+        // 不能超出墙的范围
+        // const newPositions = this.getNewForContainSymbols(point1, point2, wallId)
+        // if (wallService.isContain(wall, point1) && wallService.isContain(wall, point2) && newPositions != null && !newPositions.collision) {
+        //     const symbol = this.createSymbol(point1, point2, symbolType, wallId)
+        //     return symbol.vectorId
+        // }
+
+        const newPositions = this.getNewPosForSymbol(position, wallId, null, symbolLen)
+        if (newPositions.state) {
+            const symbol = this.createSymbol(newPositions.position1, newPositions.position2, symbolType, wallId)
+            return symbol.vectorId
+        }
+        return null
+    }
+
+    isSymbol(geoType) {
+        switch (geoType) {
+            case 'BayWindow':
+                return true
+            case 'FrenchWindow':
+                return true
+            case 'SingleDoor':
+                return true
+            case 'DoubleDoor':
+                return true
+            case 'SlideDoor':
+                return true
+            case 'SingleWindow':
+                return true
+            case 'Pass':
+                return true
+        }
+        return false
+    }
+
+    getDefaultSymbolLen(geoType) {
+        let len = 0
+        switch (geoType) {
+            case 'BayWindow':
+                len = 1.5
+                break
+            case 'FrenchWindow':
+                len = 1.5
+                break
+            case 'SingleDoor':
+                len = 0.8
+                break
+            case 'DoubleDoor':
+                len = 1.5
+                break
+            case 'SlideDoor':
+                len = 1.5
+                break
+            case 'SingleWindow':
+                len = 0.8
+                break
+            case 'Pass':
+                len = 0.8
+                break
+        }
+        return len
+    }
+
+    //从墙上去掉symbol的所属
+    deleteSymbolForWall(wall, symbolId) {
+        if (wall) {
+            let index = wall.children.indexOf(symbolId)
+            if (index > -1) {
+                wall.children.splice(index, 1)
+            }
+            let symbol = floorplanService.getSymbol(symbolId)
+            symbol.parent = null
+        }
+    }
+
+    deleteSymbol(symbolId) {
+        const symbol = floorplanService.getSymbol(symbolId)
+        if (symbol.parent) {
+            let wall = floorplanService.getWall(symbol.parent)
+            this.deleteSymbolForWall(wall, symbolId)
+        }
+        floorplanService.deleteSymbol(symbolId)
+    }
+
+    // 更新symbol的归属
+    changeSymbolForBelong(symbolId, wallId) {
+        const symbol = floorplanService.getSymbol(symbolId)
+        const parentId = symbol.parent
+        const parent = floorplanService.getWall(parentId)
+
+        this.deleteSymbolForWall(parent, symbolId)
+        symbol.setSymbolParent(wallId)
+        let wall = floorplanService.getWall(wallId)
+        wallService.addChildren(wall, symbolId)
+    }
+
+    // 拆分墙的时候,symbol也要相应的改变
+    // wall拆分成wallId1和wallId2,一般情况wallId和wallId1是相同的
+    reBelongForSplitWall(wallId, wallId1, wallId2) {
+        const wall = floorplanService.getWall(wallId)
+        for (let i = 0; i < wall.children.length; ++i) {
+            const symbolId = wall.children[i]
+            if (wallId != wallId1 && this.isContainSymbolForWall(symbolId, wallId1)) {
+                this.changeSymbolForBelong(symbolId, wallId1)
+            } else if (wallId != wallId2 && this.isContainSymbolForWall(symbolId, wallId2)) {
+                this.changeSymbolForBelong(symbolId, wallId2)
+            }
+        }
+    }
+
+    // wallId对应的墙是否包含symbol
+    isContainSymbolForWall(symbolId, wallId) {
+        const wall = floorplanService.getWall(wallId)
+        const symbol = floorplanService.getSymbol(symbolId)
+        const point = { x: (symbol.startPoint.x + symbol.endPoint.x) / 2, y: (symbol.startPoint.y + symbol.endPoint.y) / 2 }
+
+        if (wallService.isContain(wall, point)) {
+            return true
+        }
+    }
+
+    // 更新symbol的归属
+    // 墙可能删除了,也可能合并了等等
+    changeSymbolForBelong(symbolId, wallId) {
+        const symbol = floorplanService.getSymbol(symbolId)
+        const parentId = symbol.parent
+        let parent = floorplanService.getWall(parentId)
+        this.deleteSymbolForWall(parent, symbolId)
+        symbol.setSymbolParent(wallId)
+        let wall = floorplanService.getWall(wallId)
+        wallService.addChildren(wall, symbolId)
+    }
+
+    // 墙角pointId移动的时候,周围的symbol都跟着变化
+    updateSymbolsPositionsForWallCorner(pointId) {
+        const point = floorplanService.getPoint(pointId)
+        const parent = point.parent
+        for (const key in parent) {
+            this.updateSymbolsPositionsForWall(key)
+        }
+    }
+
+    // wallId对应的wall改变的时候,上面的symbol也跟着改变
+    updateSymbolsPositionsForWall(wallId) {
+        const wall = floorplanService.getWall(wallId)
+        const symbolIds = wall.children
+        for (let i = 0; i < symbolIds.length; ++i) {
+            const symbol = floorplanService.getSymbol(symbolIds[i])
+            this.updateSEForChangeWall(symbol)
+        }
+    }
+
+    // 更新Symbold的startPoint,endPoint和points2d,随着wall来
+    updateSEForChangeWall(symbol) {
+        const symbolId = symbol.vectorId
+        //const symbol = floorplanService.getSymbol(symbolId);
+        const wall = floorplanService.getWall(symbol.parent)
+
+        const startPoint = floorplanService.getPoint(wall.start)
+        const endPoint = floorplanService.getPoint(wall.end)
+
+        const line = mathUtil.createLine1(startPoint, endPoint)
+        const newStart = mathUtil.getJoinLinePoint(symbol.startPoint, line)
+        const newEnd = mathUtil.getJoinLinePoint(symbol.endPoint, line)
+
+        const dif = { x: 0, y: 0 }
+        const min = 0.001 //不要超出一点
+        let containFlag = true
+        if (!wallService.isContain(wall, newStart)) {
+            // symbol的start与wall的start挨的近
+            if (mathUtil.getDistance(newStart, startPoint) < mathUtil.getDistance(newStart, endPoint)) {
+                dif.x = startPoint.x - newStart.x
+                dif.y = startPoint.y - newStart.y
+            } else {
+                dif.x = endPoint.x - newStart.x
+                dif.y = endPoint.y - newStart.y
+            }
+            newStart.x += dif.x
+            newStart.y += dif.y
+
+            if (
+                wallService.isContain(wall, {
+                    x: newEnd.x + dif.x,
+                    y: newEnd.y + dif.y,
+                })
+            ) {
+                newEnd.x += dif.x
+                newEnd.y += dif.y
+            }
+
+            containFlag = false
+        } else if (!wallService.isContain(wall, newEnd)) {
+            if (mathUtil.getDistance(newEnd, startPoint) < mathUtil.getDistance(newEnd, endPoint)) {
+                dif.x = startPoint.x - newEnd.x
+                dif.y = startPoint.y - newEnd.y
+            } else {
+                dif.x = endPoint.x - newEnd.x
+                dif.y = endPoint.y - newEnd.y
+            }
+
+            newEnd.x += dif.x
+            newEnd.y += dif.y
+
+            if (
+                wallService.isContain(wall, {
+                    x: newStart.x + dif.x,
+                    y: newStart.y + dif.y,
+                })
+            ) {
+                newStart.x += dif.x
+                newStart.y += dif.y
+            }
+
+            containFlag = false
+        }
+
+        // 是否与wall上别的symbol部分重合
+        if (!containFlag) {
+            this.updateSEForCollideSymbols(symbolId, newStart, newEnd)
+        } else {
+            this.setPosition(symbol, newStart, 'start')
+            this.setPosition(symbol, newEnd, 'end')
+            symbol.setPoints2d()
+        }
+    }
+
+    //需要考虑碰撞
+    updateSEForCollideSymbols(symbolId, newStart, newEnd) {
+        const symbol = floorplanService.getSymbol(symbolId)
+        // 是否与wall上别的symbol部分重合
+        const newPositions = this.getNewForContainSymbols(newStart, newEnd, symbol.parent, symbolId)
+        // if (newPositions != null) {
+        //     this.setPosition(symbol, newPositions.position1, 'start')
+        //     this.setPosition(symbol, newPositions.position2, 'end')
+        //     symbol.setPoints2d()
+        // }
+
+        // if (mathUtil.getDistance(symbol.startPoint, symbol.endPoint) < Constant.minSymbolLen) {
+        //     this.deleteSymbol(symbolId)
+        // }
+        if (newPositions != null) {
+            if (mathUtil.getDistance(newPositions.position1, newPositions.position2) < Constant.minSymbolLen) {
+                this.deleteSymbol(symbolId)
+            } else {
+                this.setPosition(symbol, newPositions.position1, 'start')
+                this.setPosition(symbol, newPositions.position2, 'end')
+                symbol.setPoints2d()
+            }
+        }
+    }
+
+    //position1, position2表示exceptSymbolId新的坐标
+    getNewForContainSymbols(position1, position2, wallId, exceptSymbolId) {
+        const min = 0.01
+        const wall = floorplanService.getWall(wallId)
+        let points = []
+        for (let i = 0; i < wall.children.length; ++i) {
+            const symbolId = wall.children[i]
+            if (symbolId == exceptSymbolId) {
+                continue
+            }
+            const symbol = floorplanService.getSymbol(symbolId)
+            points.push({
+                x: symbol.startPoint.x,
+                y: symbol.startPoint.y,
+                index: 1,
+                vectorId: symbolId,
+            })
+            points.push({
+                x: symbol.endPoint.x,
+                y: symbol.endPoint.y,
+                index: 2,
+                vectorId: symbolId,
+            })
+        }
+
+        points.push({
+            x: position1.x,
+            y: position1.y,
+            index: 1,
+            vectorId: exceptSymbolId,
+        })
+        points.push({
+            x: position2.x,
+            y: position2.y,
+            index: 2,
+            vectorId: exceptSymbolId,
+        })
+
+        const startPoint = floorplanService.getPoint(wall.start)
+        points = points.sort(sortNumber.bind(this))
+        function sortNumber(a, b) {
+            return mathUtil.getDistance(startPoint, a) - mathUtil.getDistance(startPoint, b)
+        }
+
+        for (let i = 0; i < points.length - 1; ++i) {
+            if (points[i].vectorId == exceptSymbolId) {
+                if (i == 0 || i == points.length - 2) {
+                    if (mathUtil.getDistance(points[i], points[i + 1]) < Constant.minSymbolLen) {
+                        return null
+                    } else if (points[i + 1].vectorId == exceptSymbolId) {
+                        return {
+                            position1: position1,
+                            position2: { x: points[i + 1].x, y: points[i + 1].y },
+                        }
+                    } else if (points[i + 1].vectorId != exceptSymbolId) {
+                        return {
+                            position1: position1,
+                            position2: { x: points[i + 1].x, y: points[i + 1].y },
+                            collision: true,
+                        }
+                    }
+                }
+                //不在其他symbol内部
+                else if (points[i + 1].vectorId == exceptSymbolId && points[i - 1].vectorId != points[i + 2].vectorId) {
+                    if (mathUtil.getDistance({ x: points[i - 1].x, y: points[i - 1].y }, { x: points[i + 2].x, y: points[i + 2].y }) < Constant.minSymbolLen) {
+                        return null
+                    } else {
+                        return {
+                            position1: { x: points[i - 1].x, y: points[i - 1].y },
+                            position2: { x: points[i + 2].x, y: points[i + 2].y },
+                            //collision: true,
+                        }
+                    }
+                }
+            }
+        }
+        return null
+    }
+
+    getNewPosForSymbol(point, wallId, exceptSymbolId, currentSymbolLen) {
+        const wall = floorplanService.getWall(wallId)
+        const startPoint = floorplanService.getPoint(wall.start)
+        const endPoint = floorplanService.getPoint(wall.end)
+        const wallLine = wallService.getLine(wall)
+        const vSymbolLine = mathUtil.getVerticalLine(wallLine, point)
+        let symbolLen = currentSymbolLen
+        if (exceptSymbolId) {
+            const currentSymbol = floorplanService.getSymbol(exceptSymbolId)
+            symbolLen = currentSymbol.len
+        }
+
+        const twoParallels = mathUtil.getParallelLineForDistance(vSymbolLine, symbolLen / 2)
+        let point1 = mathUtil.getIntersectionPoint(twoParallels.line1, wallLine)
+        let point2 = mathUtil.getIntersectionPoint(twoParallels.line2, wallLine)
+
+        //如果在墙外部,就平移到墙内部
+        if (mathUtil.getDistance(startPoint, endPoint) < symbolLen) {
+            mathUtil.clonePoint(point1, startPoint)
+            mathUtil.clonePoint(point2, endPoint)
+        } else {
+            let dx, dy
+            let _point1 = {}
+            let _point2 = {}
+            if (!wallService.isContain(wall, point1)) {
+                dx = startPoint.x - point1.x
+                dy = startPoint.y - point1.y
+                _point2.x = point2.x + dx
+                _point2.y = point2.y + dy
+                if (!wallService.isContain(wall, _point2)) {
+                    dx = endPoint.x - point1.x
+                    dy = endPoint.y - point1.y
+
+                    point2.x += dx
+                    point2.y += dy
+                    mathUtil.clonePoint(point1, endPoint)
+                } else {
+                    point2.x += dx
+                    point2.y += dy
+                    mathUtil.clonePoint(point1, startPoint)
+                }
+            } else if (!wallService.isContain(wall, point2)) {
+                dx = startPoint.x - point2.x
+                dy = startPoint.y - point2.y
+                _point1.x = point1.x + dx
+                _point1.y = point1.y + dy
+                if (!wallService.isContain(wall, _point1)) {
+                    dx = endPoint.x - point2.x
+                    dy = endPoint.y - point2.y
+
+                    point1.x += dx
+                    point1.y += dy
+                    mathUtil.clonePoint(point2, endPoint)
+                } else {
+                    point1.x += dx
+                    point1.y += dy
+                    mathUtil.clonePoint(point2, startPoint)
+                }
+            }
+        }
+
+        let points = []
+        for (let i = 0; i < wall.children.length; ++i) {
+            const symbolId = wall.children[i]
+            if (symbolId == exceptSymbolId) {
+                continue
+            }
+            const symbol = floorplanService.getSymbol(symbolId)
+            points.push({
+                x: symbol.startPoint.x,
+                y: symbol.startPoint.y,
+                index: 1, //表示start
+                vectorId: symbolId,
+            })
+            points.push({
+                x: symbol.endPoint.x,
+                y: symbol.endPoint.y,
+                index: 2, //表示end
+                vectorId: symbolId,
+            })
+        }
+
+        points.push({
+            x: startPoint.x,
+            y: startPoint.y,
+            index: 1,
+            vectorId: wallId,
+            type: VectorType.Wall,
+        })
+        points.push({
+            x: endPoint.x,
+            y: endPoint.y,
+            index: 2,
+            vectorId: wallId,
+            type: VectorType.Wall,
+        })
+
+        points = points.sort(sortNumber.bind(this))
+        function sortNumber(a, b) {
+            return mathUtil.getDistance(startPoint, a) - mathUtil.getDistance(startPoint, b)
+        }
+
+        let flag = true
+        for (let i = 0; i < points.length - 1; ++i) {
+            if (mathUtil.isContainForSegment(point, points[i], points[i + 1])) {
+                if (mathUtil.getDistance(points[i], points[i + 1]) > symbolLen) {
+                    //完全在一个symbol内部或者symbol内有其他的symbol
+                    if (points[i].vectorId == points[i + 1].vectorId && points[i].type != VectorType.Wall) {
+                        return {
+                            position1: point1,
+                            position2: point2,
+                            collision: true,
+                            state: false,
+                        }
+                    }
+                    //完全在wall内部
+                    else if (points[i].vectorId == points[i + 1].vectorId && points[i].type == VectorType.Wall) {
+                        return {
+                            position1: point1,
+                            position2: point2,
+                            collision: true,
+                            state: true,
+                        }
+                    }
+                    //一端在墙/门/窗外部
+                    else if (!mathUtil.isContainForSegment(point1, points[i], points[i + 1]) || !mathUtil.isContainForSegment(point2, points[i], points[i + 1])) {
+                        return {
+                            position1: point1,
+                            position2: point2,
+                            collision: true,
+                            state: false,
+                        }
+                    }
+                } else if (mathUtil.getDistance(points[i], points[i + 1]) < Constant.minSymbolLen) {
+                    return {
+                        position1: point1,
+                        position2: point2,
+                        collision: true,
+                        state: false,
+                    }
+                }
+                //大于最小距离,小于本来的长度。
+                else if (points[i].vectorId != points[i + 1].vectorId) {
+                    return {
+                        position1: { x: points[i].x, y: points[i].y },
+                        position2: { x: points[i + 1].x, y: points[i + 1].y },
+                        collision: true,
+                        state: true,
+                    }
+                }
+                //完全在一个symbol内部
+                else if (points[i].vectorId == points[i + 1].vectorId && points[i].type != VectorType.Wall) {
+                    return {
+                        position1: point1,
+                        position2: point2,
+                        collision: true,
+                        state: false,
+                    }
+                } else if (points[i].vectorId == points[i + 1].vectorId && points[i].type == VectorType.Wall) {
+                    return {
+                        position1: { x: points[i].x, y: points[i].y },
+                        position2: { x: points[i + 1].x, y: points[i + 1].y },
+                        collision: true,
+                        state: true,
+                    }
+                }
+                flag = false
+            } else if (mathUtil.getDistance(point, points[i]) < Constant.minRealDis) {
+                return {
+                    position1: point1,
+                    position2: point2,
+                    collision: true,
+                    state: false,
+                }
+            }
+        }
+        if (flag) {
+            return {
+                position1: point1,
+                position2: point2,
+                collision: false,
+                state: true,
+            }
+        } else {
+            //console.error(566)
+            return {
+                position1: point1,
+                position2: point2,
+                collision: false,
+                state: true,
+            }
+        }
+        // return {
+        //     position1: point1,
+        //     position2: point2,
+        //     collision: false,
+        //     state: true,
+        // }
+    }
+
+    setPosition(symbol, position, dir) {
+        if (dir == 'start') {
+            mathUtil.clonePoint(symbol.startPoint, position)
+        } else if (dir == 'end') {
+            mathUtil.clonePoint(symbol.endPoint, position)
+        }
+    }
+
+    // 只考虑symbol的端点可能不在墙面上了,这时候要更新
+    // 用在移动墙面的时候,邻居墙的symbols可能要变
+    updateSymbolsPositionsForNeighWall(wallId) {
+        const wall = floorplanService.getWall(wallId)
+        const symbolIds = wall.children
+        for (let i = 0; i < symbolIds.length; ++i) {
+            this.updateSEForWallSize(symbolIds[i])
+        }
+    }
+
+    // 更新symbol的start或者end,一般是symbol的端点在墙外了
+    updateSEForWallSize(symbolId) {
+        const symbol = floorplanService.getSymbol(symbolId)
+        const wall = floorplanService.getWall(symbol.parent)
+        const startPoint = floorplanService.getPoint(wall.start)
+        const endPoint = floorplanService.getPoint(wall.end)
+        const newStart = {
+            x: symbol.startPoint.x,
+            y: symbol.startPoint.y,
+        }
+
+        const newEnd = {
+            x: symbol.endPoint.x,
+            y: symbol.endPoint.y,
+        }
+
+        const dif = { x: 0, y: 0 }
+
+        if (!wallService.isContain(wall, newStart)) {
+            // symbol的start与wall的start挨的近
+            if (mathUtil.getDistance(newStart, startPoint) < mathUtil.getDistance(newStart, endPoint)) {
+                dif.x = startPoint.x - newStart.x
+                dif.y = startPoint.y - newStart.y
+            } else {
+                dif.x = endPoint.x - newStart.x
+                dif.y = endPoint.y - newStart.y
+            }
+
+            newStart.x += dif.x
+            newStart.y += dif.y
+        } else if (!wallService.isContain(wall, newEnd)) {
+            if (mathUtil.getDistance(newEnd, startPoint) < mathUtil.getDistance(newEnd, endPoint)) {
+                dif.x = startPoint.x - newEnd.x
+                dif.y = startPoint.y - newEnd.y
+            } else {
+                dif.x = endPoint.x - newEnd.x
+                dif.y = endPoint.y - newEnd.y
+            }
+
+            newEnd.x += dif.x
+            newEnd.y += dif.y
+        } else {
+            return null
+        }
+        this.updateSEForCollideSymbols(symbolId, newStart, newEnd)
+    }
+
+    updateSymbolForLen(symbolId, len) {
+        const symbol = floorplanService.getSymbol(symbolId)
+        const start = symbol.startPoint
+        const end = symbol.endPoint
+        const line = mathUtil.createLine1(start, end)
+        const midPoint = { x: (start.x + end.x) / 2, y: (start.y + end.y) / 2 }
+        const vertLine = mathUtil.getVerticalLine(line, midPoint)
+
+        const wall = floorplanService.getWall(symbol.parent)
+        const startPoint = floorplanService.getPoint(wall.start)
+        const endPoint = floorplanService.getPoint(wall.end)
+
+        if (len == null || typeof len === 'undefined') {
+            len = mathUtil.getDistance(start, end)
+            const distance = mathUtil.getDistance(startPoint, endPoint)
+            if (len > distance) {
+                len = distance
+            }
+        }
+        const lines = mathUtil.getParallelLineForDistance(vertLine, len / 2)
+
+        const join1 = mathUtil.getIntersectionPoint(lines.line1, line)
+        const join2 = mathUtil.getIntersectionPoint(lines.line2, line)
+
+        const symbolInfo = {}
+        if (mathUtil.getDistance(start, join1) < mathUtil.getDistance(start, join2)) {
+            symbolInfo.start = join1
+            symbolInfo.end = join2
+        } else {
+            symbolInfo.start = join2
+            symbolInfo.end = join1
+        }
+
+        let startFlag = false
+        let endFlag = false
+        let dx, dy
+        const nearestPosition = this.getNearestPosition(symbol.parent, symbolId, true)
+        if (nearestPosition.startPosition != null && mathUtil.PointInSegment(nearestPosition.startPosition, symbolInfo.start, symbolInfo.end)) {
+            // start堵住了,end需要增加
+            //dx = symbolInfo.end.x - symbol.endPoint.x
+            //dy = symbolInfo.end.y - symbol.endPoint.y
+            dx = symbolInfo.start.x - nearestPosition.startPosition.x
+            dy = symbolInfo.start.y - nearestPosition.startPosition.y
+            mathUtil.clonePoint(symbolInfo.start, nearestPosition.startPosition)
+            symbolInfo.end.x -= dx
+            symbolInfo.end.y -= dy
+
+            startFlag = true
+        }
+
+        if (nearestPosition.endPosition != null && mathUtil.PointInSegment(nearestPosition.endPosition, symbolInfo.start, symbolInfo.end)) {
+            // end堵住了,start需要增加
+            dx = symbolInfo.end.x - nearestPosition.endPosition.x
+            dy = symbolInfo.end.y - nearestPosition.endPosition.y
+            mathUtil.clonePoint(symbolInfo.end, nearestPosition.endPosition)
+            if (!startFlag) {
+                symbolInfo.start.x -= dx
+                symbolInfo.start.y -= dy
+                //这时候可能start又超出范围了
+                if (mathUtil.PointInSegment(nearestPosition.startPosition, symbolInfo.start, symbolInfo.end)) {
+                    mathUtil.clonePoint(symbolInfo.start, nearestPosition.startPosition)
+                    startFlag = true
+                }
+            }
+            endFlag = true
+        }
+        symbolInfo.vectorId = symbolId
+        mathUtil.clonePoint(symbol.startPoint, symbolInfo.start)
+        mathUtil.clonePoint(symbol.endPoint, symbolInfo.end)
+        symbol.setPoints2d()
+
+        return {
+            block: startFlag & endFlag,
+            start: symbolInfo.start,
+            end: symbolInfo.end,
+        }
+    }
+
+    getNearestPosition(wallId, symbolId, isExceedWall, position1, position2) {
+        const wall = floorplanService.getWall(wallId)
+        const startPoint = floorplanService.getPoint(wall.start)
+        const endPoint = floorplanService.getPoint(wall.end)
+        const symbolIds = wall.children
+        let symbol = floorplanService.getSymbol(symbolId)
+
+        if (!symbol && !symbolId) {
+            symbol = {}
+            symbol = {
+                struct: {},
+            }
+            symbol.startPoint = position1
+            symbol.endPoint = position2
+        }
+
+        let minSdis = 10000
+        let minEdis = 10000
+        let startPosition = null
+        let endPosition = null
+
+        // 与startPosition同属symbol端点(另一头)
+        let startPosition2 = null
+        // 与endPosition同属symbol端点(另一头)
+        let endPosition2 = null
+
+        for (let i = 0; i < symbolIds.length; ++i) {
+            if (symbolIds[i] == symbolId) {
+                continue
+            }
+
+            const otherSymbol = floorplanService.getSymbol(symbolIds[i])
+
+            const dis1 = mathUtil.getDistance(symbol.startPoint, otherSymbol.startPoint)
+            const dis2 = mathUtil.getDistance(symbol.startPoint, otherSymbol.endPoint)
+            if (minSdis > Math.min(dis1, dis2)) {
+                if (dis1 < dis2) {
+                    startPosition = otherSymbol.startPoint
+                    startPosition2 = otherSymbol.endPoint
+                } else {
+                    startPosition = otherSymbol.endPoint
+                    startPosition2 = otherSymbol.startPoint
+                }
+                if (mathUtil.getDistance(symbol.startPoint, startPosition) > mathUtil.getDistance(symbol.endPoint, startPosition)) {
+                    startPosition = null
+                    startPosition2 = null
+                } else {
+                    minSdis = Math.min(dis1, dis2)
+                }
+            }
+
+            const dis3 = mathUtil.getDistance(symbol.endPoint, otherSymbol.startPoint)
+            const dis4 = mathUtil.getDistance(symbol.endPoint, otherSymbol.endPoint)
+            if (minEdis > Math.min(dis3, dis4)) {
+                if (dis3 < dis4) {
+                    endPosition = otherSymbol.startPoint
+                    endPosition2 = otherSymbol.endPoint
+                } else {
+                    endPosition = otherSymbol.endPoint
+                    endPosition2 = otherSymbol.startPoint
+                }
+                if (mathUtil.getDistance(symbol.endPoint, endPosition) > mathUtil.getDistance(symbol.startPoint, endPosition)) {
+                    endPosition = null
+                    endPosition2 = null
+                } else {
+                    minEdis = Math.min(dis3, dis4)
+                }
+            }
+        }
+
+        if (isExceedWall) {
+            if (startPosition == null) {
+                if (mathUtil.getDistance(startPoint, symbol.startPoint) > mathUtil.getDistance(startPoint, symbol.endPoint)) {
+                    startPosition = endPoint
+                    startPosition2 = endPoint
+                } else {
+                    startPosition = startPoint
+                    startPosition2 = startPoint
+                }
+            }
+
+            if (endPosition == null) {
+                if (mathUtil.getDistance(startPoint, symbol.startPoint) > mathUtil.getDistance(startPoint, symbol.endPoint)) {
+                    endPosition = startPoint
+                    endPosition2 = startPoint
+                } else {
+                    endPosition = endPoint
+                    endPosition2 = endPoint
+                }
+            }
+        }
+        return {
+            startPosition: startPosition,
+            startPosition2: startPosition2,
+            endPosition: endPosition,
+            endPosition2: endPosition2,
+        }
+    }
+
+    // point是目标点,selectState表示start还是end
+    // 只是不允许start和end互换位置
+    moveSymbolSinglePoint(targetPosition, symbolId, selectState) {
+        const symbol = floorplanService.getSymbol(symbolId)
+        const symbolLine = mathUtil.createLine1(symbol.startPoint, symbol.endPoint)
+
+        const vSymbolLine = mathUtil.getVerticalLine(symbolLine, targetPosition)
+        targetPosition = mathUtil.getIntersectionPoint(vSymbolLine, symbolLine)
+
+        const midPoint = {
+            x: (symbol.startPoint.x + symbol.endPoint.x) / 2,
+            y: (symbol.startPoint.y + symbol.endPoint.y) / 2,
+        }
+
+        // 是否超过了wall外
+        const wall = floorplanService.getWall(symbol.parent)
+        const startPoint = floorplanService.getPoint(wall.start)
+        const endPoint = floorplanService.getPoint(wall.end)
+
+        if (selectState == 'start') {
+            // symbol的start和end位置交换了
+            if (!mathUtil.PointInSegment(midPoint, targetPosition, symbol.endPoint)) {
+                return null
+            } else {
+                // start-start
+                if (mathUtil.getDistance(symbol.startPoint, startPoint) < mathUtil.getDistance(symbol.endPoint, startPoint)) {
+                    // 超出了
+                    if (mathUtil.getDistance(targetPosition, midPoint) > mathUtil.getDistance(startPoint, midPoint)) {
+                        mathUtil.clonePoint(targetPosition, startPoint)
+                    }
+                }
+                // start-end
+                else {
+                    // 超出了
+                    if (mathUtil.getDistance(targetPosition, midPoint) > mathUtil.getDistance(endPoint, midPoint)) {
+                        mathUtil.clonePoint(targetPosition, endPoint)
+                    }
+                }
+            }
+        } else if (selectState == 'end') {
+            // symbol的start和end位置交换了
+            if (!mathUtil.PointInSegment(midPoint, targetPosition, symbol.startPoint)) {
+                return null
+            } else {
+                // start-start
+                if (mathUtil.getDistance(symbol.endPoint, endPoint) < mathUtil.getDistance(symbol.startPoint, endPoint)) {
+                    // 超出了
+                    if (mathUtil.getDistance(targetPosition, midPoint) > mathUtil.getDistance(endPoint, midPoint)) {
+                        mathUtil.clonePoint(targetPosition, endPoint)
+                    }
+                }
+                // start-end
+                else {
+                    // 超出了
+                    if (mathUtil.getDistance(targetPosition, midPoint) > mathUtil.getDistance(startPoint, midPoint)) {
+                        mathUtil.clonePoint(targetPosition, startPoint)
+                    }
+                }
+            }
+        }
+
+        return {
+            dir: selectState,
+            position: targetPosition,
+        }
+    }
+
+    setSymbolInfo(symbolInfo) {
+        let symbol = floorplanService.getSymbol(symbolInfo.vectorId)
+        symbol.openSide = symbolInfo.openSide
+        symbol.startPoint = symbolInfo.start
+        symbol.endPoint = symbolInfo.end
+        symbol.points2d = JSON.parse(JSON.stringify(symbolInfo.points2d))
+        symbol.enter = symbolInfo.enter
+        symbol.parent = symbolInfo.parent
+        return symbol
+    }
+
+    setEnterImg(img) {
+        this.enterImg = img
+    }
+
+    getEnterImg() {
+        return this.enterImg
+    }
+}
+
+const symbolService = new SymbolService()
+export { symbolService }

+ 76 - 0
src/views/draw-file/board/editCAD/Service/TagService.js

@@ -0,0 +1,76 @@
+import Tag from '../Geometry/Tag.js'
+import { floorplanService } from './FloorplanService'
+import { floorplanData } from '../FloorplanData'
+import { measureService } from './MeasureService.js'
+import { mathUtil } from '../MathUtil.js'
+import { uoMService } from './UoMService.js'
+
+export default class TagService {
+    constructor() {}
+
+    // 新建tag
+    createTag(position, tagId, floor) {
+        let tag = new Tag(position, tagId)
+        tag.setPoints2d()
+        floorplanService.addTag(tag, floor)
+        return tag
+    }
+
+    setTagInfo(tagInfo) {
+        let tag = floorplanService.getTag(tagInfo.vectorId)
+        tag.vectorId = tagInfo.vectorId
+        tag.center = JSON.parse(JSON.stringify(tagInfo.center))
+        tag.points2d = JSON.parse(JSON.stringify(tagInfo.points2d))
+        tag.title = tagInfo.title
+        tag.des = tagInfo.des
+        tag.unit = tagInfo.unit
+        tag.adding = tagInfo.adding
+    }
+
+    deleteTag(tagId, floorNum) {
+        floorplanService.deleteTag(tagId, floorNum)
+    }
+
+    clearDefaultTags() {
+        for (let i = 0; i < floorplanData.floors.length; ++i) {
+            let tags = floorplanData.floors[i].tags
+            for (let key in tags) {
+                let tag = tags[key]
+                if ((tag.title == null || tag.title.trim() == '') && (tag.des == null || tag.des == '')) {
+                    this.deleteTag(tag.vectorId, i)
+                }
+            }
+        }
+    }
+
+    convertUnit(unit) {
+        for (let i = 0; i < floorplanData.floors.length; ++i) {
+            let tags = floorplanData.floors[i].tags
+            for (let key in tags) {
+                let tag = tags[key]
+                if (tag.unit == unit) {
+                    continue
+                } else if (tag.des) {
+                    tag.unit = unit
+                    if (unit == 'm') {
+                        //平方英尺转平方米
+                        tag.des = uoMService.convertBack(tag.des, 'area', 7, 'imperial', 0.01, false)
+                        tag.des = parseFloat(tag.des)
+                    } else {
+                        //平方米转平方英尺
+                        tag.des = uoMService.convert(tag.des, 'area', 7, 'imperial', 0.01, false)
+                        tag.des = tag.des.replace('ft²', '')
+                        //tag.des = parseFloat(tag.des)
+                    }
+                }
+            }
+        }
+    }
+
+    getTags(floorNum) {
+        return floorplanData.floors[floorNum].tags
+    }
+}
+
+const tagService = new TagService()
+export { tagService }

+ 650 - 0
src/views/draw-file/board/editCAD/Service/WallService.js

@@ -0,0 +1,650 @@
+import Point from '../Geometry/Point.js'
+import Wall from '../Geometry/Wall.js'
+import { mathUtil } from '../MathUtil.js'
+import { floorplanService } from './FloorplanService.js'
+import Constant from '../Constant'
+
+export class WallService {
+    constructor() {}
+
+    getLine(wall) {
+        const startPoint = floorplanService.getPoint(wall.start)
+        const endPoint = floorplanService.getPoint(wall.end)
+        const line = mathUtil.createLine1(startPoint, endPoint)
+        return line
+    }
+
+    //point在wall所在的线上,只是不确定是否在线段上
+    isContain(wall, point, minDis) {
+        const startPoint = floorplanService.getPoint(wall.start)
+        const endPoint = floorplanService.getPoint(wall.end)
+        return mathUtil.isContainForSegment(point, startPoint, endPoint, minDis)
+    }
+
+    addChildren(wall, symbolId) {
+        let index = wall.children.indexOf(symbolId)
+        if (index < 0) {
+            wall.children.push(symbolId)
+        }
+    }
+
+    createWall(startId, endId, vectorId, floor) {
+        let wall = new Wall(startId, endId, vectorId, floor)
+        if (floor == null || typeof floor == 'undefined') {
+            floor = floorplanService.currentFloor
+        }
+        floorplanService.addWall(wall, floor)
+        this.setPointParent(wall.vectorId, startId, 'start', floor)
+        this.setPointParent(wall.vectorId, endId, 'end', floor)
+        return wall
+    }
+
+    createPoint(x, y, vectorId, floor) {
+        let point = new Point(x, y, vectorId, floor)
+        if (floor == null || typeof floor == 'undefined') {
+            floor = floorplanService.currentFloor
+        }
+        floorplanService.addPoint(point, floor)
+        return point
+    }
+
+    setPointParent(wallId, pointId, dir, floor) {
+        let point = floorplanService.getPoint(pointId, floor)
+        let wall = floorplanService.getWall(wallId, floor)
+        point.setPointParent(wallId, dir)
+        if (dir == 'start') {
+            wall.start = pointId
+        } else if (dir == 'end') {
+            wall.end = pointId
+        }
+    }
+
+    // wallId对应墙的两个端点。尽量不要改
+    // dir表示:保留start还是保留end(对应端点的parent不用变)
+    splitWall(wallId, pointId, dir) {
+        const wall = floorplanService.getWall(wallId)
+        const startPoint = floorplanService.getPoint(wall.start)
+        const endPoint = floorplanService.getPoint(wall.end)
+        const point = floorplanService.getPoint(pointId)
+        if (mathUtil.getDistance(startPoint, point) < Constant.minAdsorb || mathUtil.getDistance(endPoint, point) < Constant.minAdsorb) {
+            //console.error('splitWall********************************************1')
+            //return null
+        }
+
+        // point1属于旧墙,point2属于新墙
+        let newWall = null
+        if (dir == 'start') {
+            //floorplanService.deletePoint(wall.end, wallId)
+            // 第一步先断开链接
+            delete endPoint.parent[wallId]
+            //新墙
+            newWall = this.createWall(pointId, wall.end)
+            newWall.setOut(wall.out)
+            newWall.setImportant(wall.important)
+
+            //修改旧墙的end
+            this.setPointParent(wallId, pointId, 'end')
+            //旧墙的end的parent换成新墙
+            endPoint.setPointParent(newWall.vectorId, dir)
+        } else if (dir == 'end') {
+            //floorplanService.deletePoint(wall.start, wallId)
+            delete startPoint.parent[wallId]
+            //新墙
+            newWall = this.createWall(wall.start, pointId)
+            newWall.setOut(wall.out)
+            newWall.setImportant(wall.important)
+
+            //修改旧墙的end
+            this.setPointParent(wallId, pointId, 'start')
+            //旧墙的end的parent换成新墙
+            startPoint.setPointParent(newWall.vectorId, dir)
+        }
+        //更新symbol的所属
+        for (let i = 0; i < wall.children.length; ++i) {
+            const symbolId = wall.children[i]
+            let symbol = floorplanService.getSymbol(symbolId)
+            let symbolMid = {
+                x: (symbol.startPoint.x + symbol.endPoint.x) / 2,
+                y: (symbol.startPoint.y + symbol.endPoint.y) / 2,
+            }
+            if (this.isContain(newWall, symbolMid)) {
+                symbol.setSymbolParent(newWall.vectorId)
+                wall.children.splice(i, 1)
+                --i
+                newWall.children.push(symbolId)
+            }
+        }
+
+        return newWall.vectorId
+    }
+
+    // wallId的两个端点分别是pointId1,pointId2,获取这个wallId
+    getWallId(pointId1, pointId2) {
+        const point1 = floorplanService.getPoint(pointId1)
+        const point2 = floorplanService.getPoint(pointId2)
+        // 墙可能删除了。
+        if (!point1 || !point2) {
+            console.log('pointId1或者pointId2不存在')
+            return null
+        }
+        if (pointId1 == pointId2) {
+            console.log('给的是同一个point')
+            return null
+        }
+
+        const parent1 = point1.parent
+        const parent2 = point2.parent
+
+        for (const key in parent1) {
+            if (parent2.hasOwnProperty(key)) {
+                return key
+            }
+        }
+
+        return null
+    }
+
+    isWallLink(wallId1, wallId2) {
+        let wall1 = floorplanService.getWall(wallId1)
+        let wall2 = floorplanService.getWall(wallId2)
+
+        if (wall1.start == wall2.start || wall1.start == wall2.end || wall1.end == wall2.start || wall1.end == wall2.end) {
+            return true
+        } else {
+            return false
+        }
+    }
+
+    // id1和id2不相交
+    AngleForWall(id1, id2) {
+        const wall1 = floorplanService.getWall(id1)
+        const wall2 = floorplanService.getWall(id2)
+
+        if (wall1 == null || wall2 == null || typeof wall1 === 'undefined' || typeof wall2 === 'undefined') {
+            return null
+        }
+
+        const start1 = floorplanService.getPoint(wall1.start)
+        const end1 = floorplanService.getPoint(wall1.end)
+
+        const start2 = floorplanService.getPoint(wall2.start)
+        const end2 = floorplanService.getPoint(wall2.end)
+
+        const distance1 = mathUtil.getDistance(start1, start2)
+        const distance2 = mathUtil.getDistance(start1, end2)
+
+        const distance3 = mathUtil.getDistance(end1, start2)
+        const distance4 = mathUtil.getDistance(end1, end2)
+
+        const minDistance = Math.min(distance1, distance2, distance3, distance4)
+        const join = mathUtil.getIntersectionPoint2(start1, end1, start2, end2)
+
+        if (join == null) {
+            return Math.PI
+        }
+
+        // start和start相交
+        if (distance1 == minDistance) {
+            end1.x += start2.x - start1.x
+            end1.y += start2.y - start1.y
+            return mathUtil.Angle(start2, end1, end2)
+        } else if (distance2 == minDistance) {
+            end1.x += end2.x - start1.x
+            end1.y += end2.y - start1.y
+            return mathUtil.Angle(end2, end1, start2)
+        } else if (distance3 == minDistance) {
+            start1.x += start2.x - end1.x
+            start1.y += start2.y - end1.y
+            return mathUtil.Angle(start2, start1, end2)
+        } else if (distance4 == minDistance) {
+            start1.x += end2.x - end1.x
+            start1.y += end2.y - end1.y
+            return mathUtil.Angle(end2, start1, start2)
+        } else {
+            console.error('AngleForWall**************************1')
+            return null
+        }
+    }
+
+    // 除了返回角度,还返回:id1对应的start,end和id2对应的另外一点组成的三角形,是顺时针还是逆时针
+    AngleForWall2(id1, id2) {
+        const wall1 = floorplanService.getWall(id1)
+        const wall2 = floorplanService.getWall(id2)
+
+        if (wall1 == null || wall2 == null || typeof wall1 === 'undefined' || typeof wall2 === 'undefined') {
+            return null
+        }
+
+        const start1 = floorplanService.getPoint(wall1.start)
+        const end1 = floorplanService.getPoint(wall1.end)
+
+        const start2 = floorplanService.getPoint(wall2.start)
+        const end2 = floorplanService.getPoint(wall2.end)
+
+        let angle = null
+        const points = []
+        points.push(start1)
+        points.push(end1)
+        if (wall1.start == wall2.start) {
+            angle = mathUtil.Angle(start1, end1, end2)
+            points.push(end2)
+        } else if (wall1.start == wall2.end) {
+            angle = mathUtil.Angle(start1, end1, start2)
+            points.push(start2)
+        } else if (wall1.end == wall2.start) {
+            angle = mathUtil.Angle(end1, start1, end2)
+            points[0] = end1
+            points[1] = start1
+            points.push(end2)
+        } else if (wall1.end == wall2.end) {
+            angle = mathUtil.Angle(end1, start1, start2)
+            points[0] = end1
+            points[1] = start1
+            points.push(start2)
+        }
+
+        if (angle == null) {
+            return null
+        } else {
+            const flag = mathUtil.isClockwise(points)
+            if (flag) {
+                return {
+                    angle: angle,
+                    clockwise: 1,
+                }
+            } else {
+                return {
+                    angle: angle,
+                    clockwise: 0,
+                }
+            }
+        }
+    }
+
+    // id1的端点坐标不变
+    AngleForWall3(id1, id2) {
+        const wall1 = floorplanService.getWall(id1)
+        const wall2 = floorplanService.getWall(id2)
+
+        if (wall1 == null || wall2 == null || typeof wall1 === 'undefined' || typeof wall2 === 'undefined') {
+            return null
+        }
+
+        const start1 = floorplanService.getPoint(wall1.start)
+        const end1 = floorplanService.getPoint(wall1.end)
+
+        const start2 = floorplanService.getPoint(wall2.start)
+        const end2 = floorplanService.getPoint(wall2.end)
+
+        const distance1 = mathUtil.getDistance(start1, start2)
+        const distance2 = mathUtil.getDistance(start1, end2)
+
+        const distance3 = mathUtil.getDistance(end1, start2)
+        const distance4 = mathUtil.getDistance(end1, end2)
+
+        const minDistance = Math.min(distance1, distance2, distance3, distance4)
+
+        const _start1 = {}
+        const _end1 = {}
+
+        // start和start相交
+        if (distance1 == minDistance) {
+            _end1.x = end1.x + start2.x - start1.x
+            _end1.y = end1.y + start2.y - start1.y
+            return mathUtil.Angle(start2, _end1, end2)
+        } else if (distance2 == minDistance) {
+            _end1.x = end1.x + end2.x - start1.x
+            _end1.y = end1.y + end2.y - start1.y
+            return mathUtil.Angle(end2, _end1, start2)
+        } else if (distance3 == minDistance) {
+            _start1.x = start1.x + start2.x - end1.x
+            _start1.y = start1.y + start2.y - end1.y
+            return mathUtil.Angle(start2, _start1, end2)
+        } else if (distance4 == minDistance) {
+            _start1.x = start1.x + end2.x - end1.x
+            _start1.y = start1.y + end2.y - end1.y
+            return mathUtil.Angle(end2, _start1, start2)
+        } else {
+            console.error('WallService.AngleForWall3************************************1')
+            return null
+        }
+    }
+
+    // pointId的parent超过两个
+    // 获取最小角度(顺时针和逆时针)
+    // 可能缺顺时针或者逆时针,这时候对应的取最大角度的逆时针或者顺时针
+    wallIdForMinAngle(pointId, wallId) {
+        const point = floorplanService.getPoint(pointId)
+        const parent = point.parent
+
+        let minAngle0 = null
+        let maxAngle0 = null // 可能minAngle1不存在,这时候要找逆时针最大的
+        let minAngle1 = null
+        let maxAngle1 = null
+
+        let minInfo0, minInfo1
+        let maxInfo0, maxInfo1
+
+        if (Object.keys(parent).length > 2) {
+            for (const key in parent) {
+                if (key == wallId) {
+                    continue
+                }
+                const angleInfo = this.AngleForWall2(wallId, key)
+                if (minAngle1 == null && angleInfo.clockwise == 1) {
+                    minInfo1 = angleInfo
+                    minInfo1.wallId = key
+                    minAngle1 = angleInfo.angle
+
+                    maxInfo1 = angleInfo
+                    maxInfo1.wallId = key
+                    maxAngle1 = angleInfo.angle
+                } else if (minAngle1 > angleInfo.angle && angleInfo.clockwise == 1) {
+                    minInfo1 = angleInfo
+                    minInfo1.wallId = key
+                    minAngle1 = angleInfo.angle
+                } else if (maxAngle1 < angleInfo.angle && angleInfo.clockwise == 1) {
+                    maxInfo1 = angleInfo
+                    maxInfo1.wallId = key
+                    maxAngle1 = angleInfo.angle
+                } else if (minAngle0 == null && angleInfo.clockwise == 0) {
+                    minInfo0 = angleInfo
+                    minInfo0.wallId = key
+                    minAngle0 = angleInfo.angle
+
+                    maxInfo0 = angleInfo
+                    maxInfo0.wallId = key
+                    maxAngle0 = angleInfo.angle
+                } else if (minAngle0 > angleInfo.angle && angleInfo.clockwise == 0) {
+                    minInfo0 = angleInfo
+                    minInfo0.wallId = key
+                    minAngle0 = angleInfo.angle
+                } else if (maxAngle0 < angleInfo.angle && angleInfo.clockwise == 0) {
+                    maxInfo0 = angleInfo
+                    maxInfo0.wallId = key
+                    maxAngle0 = angleInfo.angle
+                }
+            }
+
+            const result = {
+                min0: minInfo0,
+                min1: minInfo1,
+            }
+
+            if (!result.min0) {
+                result.min0 = maxInfo1
+                result.min0.angle = 360 - maxInfo1.angle
+            }
+
+            if (!result.min1) {
+                result.min1 = maxInfo0
+                result.min1.angle = 360 - maxInfo0.angle
+            }
+
+            return result
+        } else {
+            console.error('wallIdForMinAngle*********************************************************')
+            return null
+        }
+    }
+
+    // wallId1和wallId2合并,其中,wallId1保留,wallId2删除
+    // 返回目标点
+    mergeWall(wallId1, wallId2) {
+        const linkPointId = this.getLinkPointId(wallId1, wallId2)
+        const wall2 = floorplanService.getWall(wallId2)
+        const targetPointId = wall2.getOtherPointId(linkPointId)
+        const targetPoint = floorplanService.getPoint(targetPointId)
+        this.changeSymbolsWallToWall(wallId2, wallId1)
+
+        if (Object.keys(targetPoint.parent).length > 1) {
+            // 将linkPointId 移动到 targetPointId
+            this.moveTo(linkPointId, targetPointId)
+        } else {
+            // 删除墙wallId2
+            floorplanService.deleteWall(wallId2)
+            let linkPoint = floorplanService.getPoint(linkPointId)
+            mathUtil.clonePoint(linkPoint, targetPoint)
+        }
+        return targetPointId
+    }
+
+    // wall1.deleteSymbol(symbolId);
+    // 合并墙的时候用的上
+    changeSymbolsWallToWall(wallId1, wallId2, floor) {
+        const wall1 = floorplanService.getWall(wallId1, floor)
+        const wall2 = floorplanService.getWall(wallId2, floor)
+        for (let i = 0; i < wall1.children.length; ++i) {
+            const symbolId = wall1.children[i]
+            const symbol = floorplanService.getSymbol(symbolId, floor)
+            symbol.setSymbolParent(wallId2)
+            this.addChildren(wall2, symbolId)
+        }
+        wall1.clearChildren()
+    }
+
+    mergeWallForPoint(pointId) {
+        const point = floorplanService.getPoint(pointId)
+        if (point != null && Object.keys(point.parent).length == 2) {
+            const angle = this.AngleForWall(Object.keys(point.parent)[0], Object.keys(point.parent)[1])
+            if (angle > (Constant.maxAngle / 180) * Math.PI) {
+                return this.mergeWall(Object.keys(point.parent)[0], Object.keys(point.parent)[1])
+            }
+        }
+        return null
+    }
+
+    getLinkPointId(wallId1, wallId2) {
+        const wall1 = floorplanService.getWall(wallId1)
+        const wall2 = floorplanService.getWall(wallId2)
+
+        if (wall1.start == wall2.start) {
+            return wall1.start
+        } else if (wall1.start == wall2.end) {
+            return wall1.start
+        } else if (wall1.end == wall2.start) {
+            return wall1.end
+        } else if (wall1.end == wall2.end) {
+            return wall1.end
+        } else if (wall1.start == wall2.start) {
+            return null
+        }
+    }
+
+    // pointId1移动到pointId2
+    // 如果有一堵墙(wallId)的两头是pointId1和pointId2,那么这堵墙会被删除
+    moveTo(pointId1, pointId2) {
+        const wallId = this.getWallId(pointId1, pointId2)
+        // 不能重合
+        let point1 = floorplanService.getPoint(pointId1)
+        let point2 = floorplanService.getPoint(pointId2)
+        const dx = point1.x - point2.x
+        const dy = point1.y - point2.y
+        let parent1 = point1.parent
+        const parent2 = point2.parent
+        //确保pointId1与pointId2重合后,墙的角度不能太小
+        for (const wallId1 in parent1) {
+            if (wallId1 == wallId) {
+                continue
+            }
+
+            const wall1 = floorplanService.getWall(wallId1)
+            const otherPointId1 = wall1.getOtherPointId(pointId1)
+            const otherPoint1 = floorplanService.getPoint(otherPointId1)
+
+            for (const wallId2 in parent2) {
+                if (wallId2 == wallId) {
+                    continue
+                }
+                const wall2 = floorplanService.getWall(wallId2)
+                const otherPointId2 = wall2.getOtherPointId(pointId2)
+                const otherPoint2 = floorplanService.getPoint(otherPointId2)
+                const angle = mathUtil.Angle(point2, otherPoint1, otherPoint2)
+                if (Math.abs(angle) < (Constant.minAngle / 180) * Math.PI) {
+                    return false
+                }
+            }
+        }
+        // pointId1,pointId2属于同一堵墙
+        if (wallId != null) {
+            floorplanService.deleteWall(wallId)
+        }
+
+        point1 = floorplanService.getPoint(pointId1)
+        point2 = floorplanService.getPoint(pointId2)
+        if (!point1 || !point2) {
+            return false
+        }
+
+        //准备合并
+        for (const wallId1 in parent1) {
+            const wall1 = floorplanService.getWall(wallId1)
+            const otherPointId = wall1.getOtherPointId(pointId1)
+            const _wallId = this.getWallId(otherPointId, pointId2)
+            if (_wallId != null) {
+                return false
+            }
+
+            // wall1上pointId1被pointId2取代
+            if (wall1.start == pointId1) {
+                floorplanService.deletePoint(wall1.start, wallId1)
+                wall1.start = pointId2
+                point2.setPointParent(wallId1, 'start')
+            } else if (wall1.end == pointId1) {
+                floorplanService.deletePoint(wall1.end, wallId1)
+                wall1.end = pointId2
+                point2.setPointParent(wallId1, 'end')
+            } else {
+                console.error('wallService.moveTo****************************************************')
+            }
+        }
+        return true
+    }
+
+    getDirction(pointId, wallId) {
+        const wall = floorplanService.getWall(wallId)
+        if (wall.start == pointId) {
+            return 'start'
+        } else if (wall.end == pointId) {
+            return 'end'
+        } else {
+            console.error('WallService.getDirction*******************************************************************************************')
+            return null
+        }
+    }
+
+    isOverlapForMergePoint(pointId1, pointId2) {
+        const wallId = this.getWallId(pointId1, pointId2)
+        // 不能重合
+        const point1 = floorplanService.getPoint(pointId1)
+        const point2 = floorplanService.getPoint(pointId2)
+        const dx = point1.x - point2.x
+        const dy = point1.y - point2.y
+        const parent1 = point1.parent
+        const parent2 = point2.parent
+        for (const wallId1 in parent1) {
+            if (wallId1 == wallId) {
+                continue
+            }
+            const wall1 = floorplanService.getWall(wallId1)
+            const otherPointId1 = wall1.getOtherPointId(pointId1)
+            const otherPoint1 = floorplanService.getPoint(otherPointId1)
+            const newPoint = {
+                x: otherPoint1.x - dx,
+                y: otherPoint1.y - dy,
+            }
+            for (const wallId2 in parent2) {
+                if (wallId2 == wallId) {
+                    continue
+                }
+                const wall2 = floorplanService.getWall(wallId2)
+                const otherPointId2 = wall2.getOtherPointId(pointId2)
+                const otherPoint2 = floorplanService.getPoint(otherPointId2)
+                const angle = mathUtil.Angle(point2, newPoint, otherPoint2)
+                if (Math.abs(angle) < (Constant.minAngle / 180) * Math.PI) {
+                    return true
+                }
+            }
+        }
+        return false
+    }
+
+    subtraWallFromIntersect(pointId, wallId) {
+        const point = floorplanService.getPoint(pointId)
+        const parent = point.parent
+        const dir = this.getDirction(pointId, wallId)
+
+        if (Object.keys(parent).length == 1) {
+            return
+        }
+
+        // 第一步先断开链接
+        delete parent[wallId]
+        // 第二步先新建端点
+        const newPoint = this.createPoint(point.x, point.y)
+        // 第三步建立链接
+        newPoint.setPointParent(wallId, dir)
+        let wall = floorplanService.getWall(wallId)
+        if (dir == 'start') {
+            wall.start = newPoint.vectorId
+        } else if (dir == 'end') {
+            wall.end = newPoint.vectorId
+        }
+    }
+
+    setWallInfo(wallInfo) {
+        let wall = floorplanService.getWall(wallInfo.vectorId)
+        wall.start = wallInfo.start
+        wall.end = wallInfo.end
+        wall.children = wallInfo.children
+        wall.out = wallInfo.out
+        wall.important = wallInfo.important
+        return wall
+    }
+
+    setPointInfo(pointInfo) {
+        let point = floorplanService.getPoint(pointInfo.vectorId)
+        mathUtil.clonePoint(point, pointInfo.position)
+        point.parent = JSON.parse(JSON.stringify(pointInfo.parent))
+        return point
+    }
+
+    getNeighPoints(pointId, exceptPointId) {
+        let points = []
+        let point = floorplanService.getPoint(pointId)
+        for (let key in point.parent) {
+            let wall = floorplanService.getWall(key)
+            const otherPointId = wall.getOtherPointId(pointId)
+            if (exceptPointId && exceptPointId == otherPointId) {
+                continue
+            }
+            const otherPoint = floorplanService.getPoint(otherPointId)
+            points.push(otherPoint)
+        }
+        return points
+    }
+
+    deleteWallCorner(pointId) {
+        let point = floorplanService.getPoint(pointId)
+        if (Object.keys(point.parent).length == 1) {
+            floorplanService.deleteWall(Object.keys(point.parent)[0])
+        } else if (Object.keys(point.parent).length > 2) {
+            for (let key in point.parent) {
+                floorplanService.deleteWall(key)
+            }
+        } else if (Object.keys(point.parent).length == 2) {
+            const angle = this.AngleForWall(Object.keys(point.parent)[0], Object.keys(point.parent)[1])
+            if (angle > (Constant.maxAngle / 180) * Math.PI) {
+                //合并
+                this.mergeWall(Object.keys(point.parent)[0], Object.keys(point.parent)[1])
+            } else {
+                floorplanService.deleteWall(Object.keys(point.parent)[0])
+                //上一个删除后,下面的数组只有一个元素了
+                floorplanService.deleteWall(Object.keys(point.parent)[0])
+            }
+        }
+    }
+}
+
+const wallService = new WallService()
+export { wallService }

+ 329 - 0
src/views/draw-file/board/editCAD/Style.js

@@ -0,0 +1,329 @@
+const Style = {
+    Wall: {
+        strokeStyle: '#FFFFFF',
+        lineWidth: 4,
+        lineWidth_out: 6,
+        //承重墙
+        important: {
+            strokeStyle: '#FFFFFF',
+            lineWidth: 6,
+        },
+        error: {
+            strokeStyle: 'rgba(255,0,0,0.5)',
+            fillStyle: 'rgba(255,0,0,0.8)',
+        },
+    },
+    Point: {
+        strokeStyle: 'green',
+        fillStyle: 'rgb(0, 200, 175)',
+        radius: 4,
+    },
+    Symbol: {
+        strokeStyle: 'rgba(255,255,255,1)',
+        fillStyle: 'rgba(255,255,255,0)',
+        lineWidth: 2,
+        //垭口
+        Pass: {},
+    },
+    Component: {
+        strokeStyle: 'rgba(255,255,255,1)',
+        fillStyle: 'rgba(255,255,255,0)',
+        lineWidth: 1,
+    },
+    Tag: {
+        strokeStyle: 'rgb(255,255,255,1)',
+        fillStyle: 'rgb(255,255,255,1)',
+        strokeStyle_adding: 'rgba(243, 255, 0, 0.8)',
+        fillStyle_adding: 'rgba(243, 255, 0, 0.8)',
+        lineWidth: 1,
+    },
+    Furniture: {
+        strokeStyle: 'rgb(255,255,255,1)',
+        fillStyle: 'rgba(0,0,0,0)',
+        lineWidth: 1,
+    },
+    Select: {
+        Wall: {
+            strokeStyle: 'rgba(243, 255, 0, 1)',
+        },
+        Wall_out: {
+            strokeStyle: 'rgba(243, 255, 0, 1)',
+        },
+        Symbol: {
+            strokeStyle: 'rgba(243, 255, 0, 0.8)',
+            fillStyle: 'rgba(243, 255, 0, 0.5)',
+            lineWidth: 2,
+        },
+        Component: {
+            strokeStyle: 'rgba(243, 255, 0, 0.8)',
+            fillStyle: 'rgba(243, 255, 0, 0.5)',
+        },
+        Tag: {
+            strokeStyle: '#00C8AF',
+            fillStyle: '#00C8AF',
+        },
+        Furniture: {
+            strokeStyle: 'rgba(243, 255, 0, 0.8)',
+            fillStyle: 'rgba(243, 255, 0, 0.5)',
+        },
+        Point: {
+            radius: 4,
+            lineWidth: 2,
+            fillStyle: 'rgba(245, 255, 0, 1)',
+            strokeStyle: 'rgba(245, 255, 255, 1)',
+        },
+    },
+    Focus: {
+        Wall: {
+            strokeStyle: 'rgba(243, 255, 0, 1)',
+        },
+        Wall_out: {
+            strokeStyle: 'rgba(162, 164, 124, 1)',
+        },
+        Symbol: {
+            strokeStyle: 'rgba(243, 255, 0, 0.8)',
+            fillStyle: 'rgba(243, 255, 0, 0.5)',
+        },
+        Component: {
+            strokeStyle: 'rgba(243, 255, 0, 0.8)',
+            fillStyle: 'rgba(243, 255, 0, 0.5)',
+        },
+        Tag: {
+            strokeStyle: '#00C8AF',
+            fillStyle: '#00C8AF',
+        },
+        Furniture: {
+            strokeStyle: 'rgba(243, 255, 0, 0.8)',
+            fillStyle: 'rgba(243, 255, 0, 0.5)',
+        },
+        Point: {
+            radius: 4,
+            lineWidth: 2,
+            fillStyle: 'rgba(245, 255, 0, 1)',
+            strokeStyle: 'rgba(245, 255, 255, 1)',
+        },
+    },
+    Element: {
+        StartAddWall: {
+            radius: 4,
+            fillStyle: 'yellow',
+            strokeStyle: 'green',
+        },
+        NewWall: {
+            lineWidth: 4,
+            lineWidth_out: 6,
+            strokeStyle: 'rgba(255,255,255,0.3)',
+            strokeStyle_out: 'rgba(102,102,102,0.3)',
+            errorStrokeStyle: 'rgb(250,63,72,0.3)',
+        },
+        StartSymbolPoints: {
+            radius: 4,
+            fillStyle: 'yellow',
+            strokeStyle: 'green',
+        },
+        EndSymbolPoints: {
+            radius: 4,
+            fillStyle: 'yellow',
+            strokeStyle: 'green',
+        },
+        CheckLinesX: {
+            lineWidth: 2,
+            strokeStyle: '#CED806',
+        },
+        CheckLinesY: {
+            lineWidth: 2,
+            strokeStyle: '#CED806',
+        },
+        VCheckLinesX: {
+            lineWidth: 2,
+            strokeStyle: '#CED806',
+            //strokeStyle: 'rgba(100,149,237,0.5)',
+        },
+        VCheckLinesY: {
+            lineWidth: 2,
+            strokeStyle: '#CED806',
+            //strokeStyle: 'rgba(100,149,237,0.5)',
+        },
+    },
+    Font: {
+        font: '14px Microsoft YaHei',
+        fillStyle: '#FFFFFF',
+        strokeStyle: '#FFFFFF',
+        textAlign: 'center',
+        textBaseline: 'middle',
+        miterLimit: 10,
+        direction: 'ltr',
+    },
+    Pano: {
+        radius: 10,
+        lineWidth: 2,
+        strokeStyle: 'rgba(255,255,255,0.4)',
+        fillStyle: 'rgba(255,255,255,0.1)',
+    },
+    Measure: {
+        txt: 'rgba(255,255,255,1)', //画墙/选墙的时候 测量值的颜色
+        strokeStyle: 'rgba(255,255,255,1)',
+        lineWidth: 1,
+    },
+    DownLoad: {
+        style1: {
+            Wall: {
+                strokeStyle: '#666666',
+                lineWidth: 4,
+                lineWidth_out: 6,
+                //承重墙
+                important: {
+                    strokeStyle: '#666666',
+                    lineWidth: 6,
+                },
+            },
+            Symbol: {
+                strokeStyle: '#666666',
+                lineWidth: 1,
+            },
+            Component: {
+                strokeStyle: '#666666',
+                fillStyle: '#666666',
+                lineWidth: 1,
+            },
+            Tag: {
+                strokeStyle: '#000000', //标注的颜色
+                fillStyle: '#000000', //标注的颜色
+                lineWidth: 1,
+            },
+            Font: {
+                font: '14px Microsoft YaHei',
+                fillStyle: '#000000', //上下左右测量值
+                strokeStyle: '#000000',
+                textAlign: 'center',
+                textBaseline: 'middle',
+                miterLimit: 10,
+                direction: 'ltr',
+            },
+            Measure: {
+                strokeStyle: '#CCCCCC',
+                lineWidth: 1,
+            },
+        },
+        style2: {
+            Wall: {
+                strokeStyle: '#FFFFFF',
+                lineWidth: 4,
+                lineWidth_out: 6,
+                //承重墙
+                important: {
+                    strokeStyle: '#FFFFFF',
+                    lineWidth: 6,
+                },
+            },
+            Symbol: {
+                strokeStyle: '#FFFFFF',
+                lineWidth: 1,
+            },
+            Component: {
+                strokeStyle: '#FFFFFF',
+                fillStyle: '#FFFFFF',
+                lineWidth: 1,
+            },
+            Tag: {
+                strokeStyle: '#FFFFFF', //标注的颜色
+                fillStyle: '#FFFFFF', //标注的颜色
+                lineWidth: 1,
+            },
+            Font: {
+                font: '14px Microsoft YaHei',
+                fillStyle: '#FFFFFF', //上下左右测量值
+                strokeStyle: '#FFFFFF',
+                textAlign: 'center',
+                textBaseline: 'middle',
+                miterLimit: 10,
+                direction: 'ltr',
+            },
+            Measure: {
+                strokeStyle: '#FFFFFF',
+                lineWidth: 1,
+            },
+        },
+        style3: {
+            Wall: {
+                strokeStyle: '#666666',
+                lineWidth: 4,
+                lineWidth_out: 6,
+                //承重墙
+                important: {
+                    strokeStyle: '#666666',
+                    lineWidth: 6,
+                },
+            },
+            Symbol: {
+                strokeStyle: '#666666',
+                lineWidth: 1,
+            },
+            Component: {
+                strokeStyle: '#666666',
+                fillStyle: '#666666',
+                lineWidth: 1,
+            },
+            Tag: {
+                strokeStyle: '#000000', //标注的颜色
+                fillStyle: '#000000', //标注的颜色
+                strokeStyle_adding: 'rgba(243, 255, 0, 0.8)',
+                fillStyle_adding: 'rgba(243, 255, 0, 0.8)',
+                lineWidth: 1,
+            },
+            Font: {
+                font: '14px Microsoft YaHei',
+                fillStyle: '#000000', //上下左右测量值
+                strokeStyle: '#000000',
+                textAlign: 'center',
+                textBaseline: 'middle',
+                miterLimit: 10,
+                direction: 'ltr',
+            },
+            Measure: {
+                strokeStyle: '#CCCCCC',
+                lineWidth: 2,
+            },
+        },
+        style4: {
+            Wall: {
+                strokeStyle: '#FFFFFF',
+                lineWidth: 4,
+                lineWidth_out: 6,
+                //承重墙
+                important: {
+                    strokeStyle: '#FFFFFF',
+                    lineWidth: 6,
+                },
+            },
+            Symbol: {
+                strokeStyle: '#FFFFFF',
+                lineWidth: 1,
+            },
+            Component: {
+                strokeStyle: '#FFFFFF',
+                fillStyle: '#FFFFFF',
+                lineWidth: 1,
+            },
+            Tag: {
+                strokeStyle: '#FFFFFF', //标注的颜色
+                fillStyle: '#FFFFFF', //标注的颜色
+                lineWidth: 1,
+            },
+            Font: {
+                font: '14px Microsoft YaHei',
+                fillStyle: '#FFFFFF', //上下左右测量值
+                strokeStyle: '#FFFFFF',
+                textAlign: 'center',
+                textBaseline: 'middle',
+                miterLimit: 10,
+                direction: 'ltr',
+            },
+            Measure: {
+                strokeStyle: '#FFFFFF',
+                lineWidth: 1,
+            },
+        },
+    },
+}
+export default Style

+ 11 - 0
src/views/draw-file/board/editCAD/enum/ElementEvents.js

@@ -0,0 +1,11 @@
+const ElementEvents = {
+    StartAddWall: 'StartAddWall',
+    NewWall: 'NewWall',
+    StartSymbolPoints: 'StartSymbolPoints',
+    EndSymbolPoints: 'EndSymbolPoints',
+    CheckLinesX: 'CheckLinesX',
+    CheckLinesY: 'CheckLinesY',
+    VCheckLinesX: 'vCheckLinesX',
+    VCheckLinesY: 'vCheckLinesY',
+}
+export default ElementEvents

+ 28 - 0
src/views/draw-file/board/editCAD/enum/HistoryEvents.js

@@ -0,0 +1,28 @@
+const HistoryEvents = {
+    AddPoint: 'addPoint',
+    DeletePoint: 'deletePoint',
+    ModifyPoint: 'modifyPoint',
+
+    AddWall: 'addWall',
+    DeleteWall: 'deleteWall',
+    ModifyWall: 'modifyWall',
+
+    AddSymbol: 'addSymbol',
+    DeleteSymbol: 'deleteSymbol',
+    ModifySymbol: 'modifySymbol',
+
+    AddComponent: 'addComponent',
+    DeleteComponent: 'deleteComponent',
+    ModifyComponent: 'modifyComponent',
+
+    AddTag: 'addTag',
+    DeleteTag: 'deleteTag',
+    ModifyTag: 'modifyTag',
+
+    AddFurniture: 'addFurniture',
+    DeleteFurniture: 'deleteFurniture',
+    ModifyFurniture: 'modifyFurniture',
+
+    ModifyAngle: 'modifyAngle',
+}
+export default HistoryEvents

+ 36 - 0
src/views/draw-file/board/editCAD/enum/LayerEvents.js

@@ -0,0 +1,36 @@
+const LayerEvents = {
+    PanBackGround: 'panBackGround', //拖拽背景
+    AddWall: 'addWall', //开始添加墙
+    AddingWall: 'addingWall', //添加墙进行中
+    MoveWall: 'moveWall', //拖拽墙面
+    MoveWallPoint: 'moveWallPoint', //拖拽墙角
+
+    AddSymbol: 'addSymbol', //添加门/窗
+    MoveSymbol: 'moveSymbol', //移动门/窗
+    MoveSymbolPoint: 'moveSymbolPoint', //移动门/窗的端点
+
+    AddComponent: 'addComponent',
+    MoveComponent: 'moveComponent',
+
+    AddTag: 'addTag',
+    MoveTag: 'moveTag',
+
+    // AddBeam: 'addBeam',
+    // AddFlue: 'addFlue',
+    // AddCorridor: 'addCorridor',
+
+    // MoveBeam: 'moveBeam',
+    // MoveFlue: 'moveFlue',
+    // MoveCorridor: 'moveCorridor',
+    // AddSingleDoor: 'addSingleDoor', //添加单开门
+    // MoveSingleDoor: 'moveSingleDoor', //移动单开门
+    // MoveSingleDoorPoint: 'moveSingleDoorPoint', //移动单开门的端点
+
+    // AddSingleWindow: 'addSingleWindow',
+    // MoveSingleWindow: 'moveSingleWindow',
+    // MoveSingleWindowPoint: 'moveSingleWindowPoint',
+
+    AddFurniture: 'addFurniture',
+    MoveFurniture: 'moveFurniture',
+}
+export default LayerEvents

+ 25 - 0
src/views/draw-file/board/editCAD/enum/SelectState.js

@@ -0,0 +1,25 @@
+const SelectState = {
+    All: 'all',
+    Start: 'start',
+    End: 'end',
+    Select: 'select',
+    /*,
+    focus: "focus",
+    selectArrow: "selectArrow", // beam,flue  focus后,选中下面的箭头
+    dragging: "dragging",
+    error: "error",
+    full: "full",
+    building: "building",
+    rotate: "rotate",
+    resize: "resize",
+    num1: 1,
+    num2: 2,
+    num3: 3,
+    num4: 4,
+    num5: 5,
+    num6: 6,
+    num7: 7,
+    num8: 8,
+    */
+}
+export default SelectState

+ 5 - 0
src/views/draw-file/board/editCAD/enum/SymbolEvents.js

@@ -0,0 +1,5 @@
+const SymbolEvents = {
+    Left: 'LEFT',
+    Right: 'RIGHT',
+}
+export default SymbolEvents

+ 66 - 0
src/views/draw-file/board/editCAD/enum/UIEvents.js

@@ -0,0 +1,66 @@
+const UIEvents = {
+    Wall: 'Wall',
+    OutWall: 'OutWall',
+    SingleDoor: 'SingleDoor',
+    DoubleDoor: 'DoubleDoor',
+    SlideDoor: 'SlideDoor',
+    SingleWindow: 'SingleWindow',
+    BayWindow: 'BayWindow',
+    FrenchWindow: 'FrenchWindow',
+    Pass: 'Pass',
+    Beam: 'Beam',
+    Flue: 'Flue',
+    Corridor: 'Corridor',
+    Tag: 'Tag', //这个是标注,暂时这样
+
+    TV: 'TV', //电视
+    CombinationSofa: 'CombinationSofa', //组合沙发
+    SingleSofa: 'SingleSofa', //单人沙发
+    TeaTable: 'TeaTable', //茶几
+    Carpet: 'Carpet', //地毯
+    Plant: 'Plant', //植物
+    DiningTable: 'DiningTable', //餐桌
+
+    DoubleBed: 'DoubleBed', //双人床
+    SingleBed: 'SingleBed', //单人床
+    Wardrobe: 'Wardrobe', //衣柜
+    Dresser: 'Dresser', //梳妆台
+    BedsideCupboard: 'BedsideCupboard', //床头柜
+    Pillow: 'Pillow', //抱枕
+
+    GasStove: 'GasStove', //燃气灶
+    Cupboard: 'Cupboard', //橱柜
+    Bathtub: 'Bathtub', //浴缸
+    Closestool: 'Closestool', //马桶
+    Washstand: 'Washstand', //洗漱台
+
+    Desk: 'Desk', //书桌
+    BalconyChair: 'BalconyChair', //阳台椅
+    Elevator: 'Elevator', //电梯
+}
+
+export const Furnitures = {
+    TV: UIEvents.TV, //电视
+    CombinationSofa: UIEvents.CombinationSofa, //组合沙发
+    SingleSofa: UIEvents.SingleSofa, //单人沙发
+    TeaTable: UIEvents.TeaTable, //茶几
+    Carpet: UIEvents.Carpet, //地毯
+    Plant: UIEvents.Plant, //植物
+    DiningTable: UIEvents.DiningTable, //餐桌
+    DoubleBed: UIEvents.DoubleBed, //双人床
+    SingleBed: UIEvents.SingleBed, //单人床
+    Wardrobe: UIEvents.Wardrobe, //衣柜
+    Dresser: UIEvents.Dresser, //梳妆台
+    BedsideCupboard: UIEvents.BedsideCupboard, //床头柜
+    Pillow: UIEvents.Pillow, //抱枕
+    GasStove: UIEvents.GasStove, //燃气灶
+    Cupboard: UIEvents.Cupboard, //橱柜
+    Bathtub: UIEvents.Bathtub, //浴缸
+    Closestool: UIEvents.Closestool, //马桶
+    Washstand: UIEvents.Washstand, //洗漱台
+    Desk: UIEvents.Desk, //书桌
+    BalconyChair: UIEvents.BalconyChair, //阳台椅
+    Elevator: UIEvents.Elevator, //电梯
+}
+
+export default UIEvents

+ 46 - 0
src/views/draw-file/board/editCAD/enum/VectorType.js

@@ -0,0 +1,46 @@
+const VectorType = {
+    Point: 'Point',
+    WallCorner: 'WallCorner',
+    Wall: 'Wall',
+    SingleDoor: 'SingleDoor',
+    DoubleDoor: 'DoubleDoor',
+    SlideDoor: 'SlideDoor',
+
+    SingleWindow: 'SingleWindow',
+    BayWindow: 'BayWindow',
+    FrenchWindow: 'FrenchWindow',
+    Pass: 'Pass',
+
+    Beam: 'Beam',
+    Flue: 'Flue',
+    Corridor: 'Corridor',
+    Line: 'Line',
+
+    Tag: 'Tag',
+
+    TV: 'TV', //电视
+    CombinationSofa: 'CombinationSofa', //组合沙发
+    SingleSofa: 'SingleSofa', //单人沙发
+    TeaTable: 'TeaTable', //茶几
+    Carpet: 'Carpet', //地毯
+    Plant: 'Plant', //植物
+    DiningTable: 'DiningTable', //餐桌
+
+    DoubleBed: 'DoubleBed', //双人床
+    SingleBed: 'SingleBed', //单人床
+    Wardrobe: 'Wardrobe', //衣柜
+    Dresser: 'Dresser', //梳妆台
+    BedsideCupboard: 'BedsideCupboard', //床头柜
+    Pillow: 'Pillow', //抱枕
+
+    GasStove: 'GasStove', //燃气灶
+    Cupboard: 'Cupboard', //橱柜
+    Bathtub: 'Bathtub', //浴缸
+    Closestool: 'Closestool', //马桶
+    Washstand: 'Washstand', //洗漱台
+
+    Desk: 'Desk', //书桌
+    BalconyChair: 'BalconyChair', //阳台椅
+    Elevator: 'Elevator', //电梯
+}
+export default VectorType