import { wallService } from '../Service/WallService' import { floorplanService } from '../Service/FloorplanService' import Constant from '../Constant' import { mathUtil } from '../MathUtil' import { elementService } from '../Service/ElementService' import { coordinate } from '../Coordinate' export default class MoveWall { constructor() { this.needUpdateRoom = false //是否重新计算房间 this.startMoving = false this.moveFlag = false //拖拽墙角的时候,墙角的父亲与其他墙角相交 this.adsorbPointWalls = {} //拖拽墙角的时候,该墙角与其他墙面相交 this.splitWallId = null } // 测试要考虑pointId拖拽到包含他的所有墙的另一头 // 这个函数不会删除/拆分/合并墙或者点 movePoint(pointId, position, modifyPoint) { let point = floorplanService.getPoint(pointId) let linkedPointId = null let linkedWallId = null if (modifyPoint != null) { position = { x: modifyPoint.x, y: modifyPoint.y, } linkedPointId = modifyPoint.linkedPointId linkedWallId = modifyPoint.linkedWallId } this.needUpdateRoom = false this.adsorbPointWalls = {} this.splitWallId = null let flag = this.canMoveForPoint(pointId, position, linkedPointId, linkedWallId) if (!flag) { if (this.splitWallId == null && Object.keys(this.adsorbPointWalls).length > 0) { //要吸附一下 const parent = point.parent const wall = floorplanService.getWall(Object.keys(parent)[0]) const otherPointId = wall.getOtherPointId(pointId) let otherPoint = floorplanService.getPoint(otherPointId) let modifyPoint = floorplanService.getPoint(Object.keys(this.adsorbPointWalls)[0]) let line = mathUtil.createLine1(otherPoint, modifyPoint) position = mathUtil.getJoinLinePoint(position, line) point.setPosition(position) } return false } let newPosition = null if (modifyPoint == null) { //90°或者180°纠正 //不考虑当前角度 //当前点的parent只有一个,考虑邻居点 let neighPoints = wallService.getNeighPoints(pointId) if (neighPoints.length == 1) { newPosition = elementService.checkAngle(position, neighPoints[0].vectorId, pointId) } //当前点的parent有两个 else if (neighPoints.length == 2) { newPosition = elementService.checkAngle(position, neighPoints[0].vectorId, pointId) if (!newPosition) { newPosition = elementService.checkAngle(position, neighPoints[1].vectorId, pointId) } // let angle = mathUtil.Angle(position, neighPoints[0], neighPoints[1]) // if (Math.abs((angle / Math.PI) * 180 - 90) < 5) { // let line = mathUtil.createLine1(position, neighPoints[0]) // let join = mathUtil.getJoinLinePoint(neighPoints[1], line) // if (join) { // mathUtil.clonePoint(position, join) // } // } else if (Math.abs((angle / Math.PI) * 180) < 5 || Math.abs((angle / Math.PI) * 180 - 180) < 5) { // let line = mathUtil.createLine1(neighPoints[0], neighPoints[1]) // let join = mathUtil.getJoinLinePoint(position, line) // if (join) { // mathUtil.clonePoint(position, join) // } // } } if (newPosition) { flag = this.canMoveForPoint(pointId, newPosition, linkedPointId, linkedWallId) if (!flag) { return false } mathUtil.clonePoint(position, newPosition) } point.setPosition(position) } // 与别的墙角重合 else if (modifyPoint.hasOwnProperty('linkedPointId') && modifyPoint.linkedPointId != null) { const wallId = wallService.getWallId(pointId, modifyPoint.linkedPointId) // pointId与linkedPointId属于同一堵墙,不允许,所以不移动 if (wallId != null) { return false } else { point.setPosition(modifyPoint) this.needUpdateRoom = true } } // 与别的墙面重合 // 如果墙面的交点与其余墙角的距离过短,那也不允许拖动 else if (modifyPoint.hasOwnProperty('linkedWallId')) { const wall = floorplanService.getWall(modifyPoint.linkedWallId) const startPoint = floorplanService.getPoint(wall.start) const endPoint = floorplanService.getPoint(wall.end) // 与其余墙角的距离过短,不允许拖动 if (mathUtil.getDistance(startPoint, position) < Constant.minAdsorb || mathUtil.getDistance(endPoint, position) < Constant.minAdsorb) { return false } point.setPosition(modifyPoint) this.needUpdateRoom = true } else { if (modifyPoint.hasOwnProperty('linkedPointIdX') && modifyPoint.linkedPointIdX) { //const linkedPointX = floorplanService.getPoint(modifyPoint.linkedPointIdX) //elementService.setCheckLinesX(position, linkedPointX) point.setPosition(position) } if (modifyPoint.hasOwnProperty('linkedPointIdY') && modifyPoint.linkedPointIdY) { //const linkedPointY = floorplanService.getPoint(modifyPoint.linkedPointIdY) //elementService.setCheckLinesY(position, linkedPointY) point.setPosition(position) } } return true } // 拖拽墙面 moveWallPlane(wallId, dx, dy) { // 1表示可以继续移动,2表示不能移动(启动距离还不够),3表示wallId被删除了,4表示重新开始移动(需要达到一定距离才能启动),5表示不能移动(不合适) let MoveState = 1 let wall = floorplanService.getWall(wallId) let startPointId = wall.start let endPointId = wall.end let startPoint = floorplanService.getPoint(wall.start) let endPoint = floorplanService.getPoint(wall.end) // 不考虑约束的情况,得到移动后的坐标 const newpts = this.getNewPointsForMoveWall(wallId, dx, dy) let newLine = mathUtil.createLine1(newpts.point1, newpts.point2) // 获取约束信息,包括:是否新建墙,受约束的侧墙 const limit = this.getTwoLimitInfos(wallId, newLine) this.needUpdateRoom = false // 不考虑吸附的情况下,经过约束条件后,得到的新的移动后的坐标 let virtualStartPoint = mathUtil.getIntersectionPoint(newLine, limit.startLimitLine) let virtualEndPoint = mathUtil.getIntersectionPoint(newLine, limit.endLimitLine) // 刚刚开始移动的时候,或者吸附后再移动的时候,都需要积累一点移动距离才能真正开始移动 if (!this.startMoving && (mathUtil.getDistance(startPoint, virtualStartPoint) < Constant.minAdsorb || mathUtil.getDistance(endPoint, virtualEndPoint) < Constant.minAdsorb)) { this.moveFlag = false MoveState = 2 return MoveState } this.startMoving = true // 判断是否会吸附到邻居墙的另一头端点,同时确保新的坐标在邻居墙内 let startInfo = this.updateVirtualPosition(wall.start, virtualStartPoint, limit.startWallId, limit.newStartWallId) let endInfo = this.updateVirtualPosition(wall.end, virtualEndPoint, limit.endWallId, limit.newEndWallId) if (startInfo == null || endInfo == null) { this.moveFlag = false MoveState = 2 this.startMoving = false return MoveState } // 判断wallId的 1端/2端 吸附后,是否和别的墙重合 let coincideFlag = false // wallId的长度,可能会很短,要删除 let distance = null // 如果一头被吸附,另一头的坐标还要再次调整 if (startInfo.adsorb && !endInfo.adsorb) { // 先更新newLine newLine = mathUtil.createLine3(newLine, startInfo.virtualPosition) // 需要判断夹角,如果接近0,则不能移动 const flag = this.isOKForTwoSegmentsAngle(startInfo.adsorbPointId, wall.start, wall.end) if (!flag) { this.moveFlag = false MoveState = 5 return MoveState } // 更新virtualEndPoint virtualEndPoint = mathUtil.getIntersectionPoint(newLine, limit.endLimitLine) // 再次判断是否吸附 endInfo = this.updateVirtualPosition(wall.end, virtualEndPoint, limit.endWallId, limit.newEndWallId) if (endInfo == null) { endInfo = { adsorb: false, adsorbPointId: null, virtualPosition: virtualEndPoint, } } // 一头吸附后,wallId可能和别的墙重合 coincideFlag = this.isCoincideForAdsorbOne(wall.start, startInfo.adsorbPointId, wallId) distance = mathUtil.getDistance(startInfo.virtualPosition, virtualEndPoint) MoveState = 4 this.needUpdateRoom = true this.startMoving = false } else if (!startInfo.adsorb && endInfo.adsorb) { newLine = mathUtil.createLine3(newLine, endInfo.virtualPosition) // 需要判断夹角,如果接近0,则不能移动 const flag = this.isOKForTwoSegmentsAngle(endInfo.adsorbPointId, wall.end, wall.start) if (!flag) { this.moveFlag = false MoveState = 5 return MoveState } virtualStartPoint = mathUtil.getIntersectionPoint(newLine, limit.startLimitLine) startInfo = this.updateVirtualPosition(wall.start, virtualStartPoint, limit.startWallId, limit.newStartWallId) if (startInfo == null) { startInfo = { adsorb: false, adsorbPointId: null, virtualPosition: virtualStartPoint, } } coincideFlag = this.isCoincideForAdsorbOne(wall.end, endInfo.adsorbPointId, wallId) distance = mathUtil.getDistance(endInfo.virtualPosition, virtualStartPoint) MoveState = 4 this.needUpdateRoom = true this.startMoving = false } // 两头同时吸附呢,wallId可能和别的墙重合 if (startInfo && endInfo && startInfo.adsorb && endInfo.adsorb) { coincideFlag = this.isCoincideForAdsorbOne2(wallId, startInfo.adsorbPointId, endInfo.adsorbPointId) distance = mathUtil.getDistance(startInfo.virtualPosition, endInfo.virtualPosition) this.startMoving = false if (coincideFlag) { this.moveFlag = false MoveState = 5 return MoveState } MoveState = 4 this.needUpdateRoom = true } else { distance = mathUtil.getDistance(virtualStartPoint, virtualEndPoint) if (distance < Constant.minAdsorb) { // 执行deleteWallForLinked后start和end会变,所以提前保存 this.deleteWallForLinked(wallId) startPoint = floorplanService.getPoint(startPointId) endPoint = floorplanService.getPoint(endPointId) if (!startPoint || !endPoint) { this.moveFlag = false MoveState = 3 this.needUpdateRoom = true return MoveState } if ( (Object.keys(startPoint.parent).length > 1 && Object.keys(endPoint.parent).length == 1) || (Object.keys(startPoint.parent).length == 1 && Object.keys(endPoint.parent).length == 1) ) { wallService.moveTo(endPointId, startPointId) } else if (Object.keys(startPoint.parent).length == 1 && Object.keys(endPoint.parent).length > 1) { wallService.moveTo(startPointId, endPointId) } this.moveFlag = false MoveState = 3 this.needUpdateRoom = true return MoveState } } startPointId = wall.start endPointId = wall.end // 是否交叉 const crossFlag = this.isOKForCrossForMoveWall(virtualStartPoint, virtualEndPoint, wallId, startPointId, endPointId, startInfo.adsorbPointId, endInfo.adsorbPointId) // ok if (!crossFlag) { MoveState = 2 this.moveFlag = false this.startMoving = false return MoveState } // 要删除墙了 if (coincideFlag || (distance != null && distance < Constant.minAdsorb)) { this.deleteWallForLinked(wallId) MoveState = 3 // 删除完墙,邻居墙可能会合并 wallService.mergeWallForPoint(startPointId) wallService.mergeWallForPoint(endPointId) this.moveFlag = false this.needUpdateRoom = true return MoveState } else { // 要删除墙了 const join = mathUtil.getIntersectionPoint3(startPoint, virtualStartPoint, endPoint, virtualEndPoint) if (join != null) { startPoint.setPosition(join) endPoint.setPosition(join) wallService.moveTo(startPointId, endPointId) MoveState = 3 this.moveFlag = false this.needUpdateRoom = true return MoveState } } let overlapFlag = false if (!limit.newStartWallId && startInfo.adsorbPointId) { overlapFlag = wallService.isOverlapForMergePoint(startPointId, startInfo.adsorbPointId) } else if (!limit.newEndWallId && endInfo.adsorbPointId) { overlapFlag = wallService.isOverlapForMergePoint(endPointId, endInfo.adsorbPointId) } if (overlapFlag) { this.moveFlag = false MoveState = 5 return MoveState } // 到了这一步,端点的新坐标已经确定了,这里开始更新端点坐标 // 这里需要升级优化,因为 updatePointForMoveWall方法里也更新了edge,这个其实不需要的。 this.updatePointForMoveWall(wallId, startPointId, startInfo, limit.startWallId, limit.newStartWallId) this.updatePointForMoveWall(wallId, endPointId, endInfo, limit.endWallId, limit.newEndWallId) wall = floorplanService.getWall(wallId) if (wall == null) { MoveState = 3 this.moveFlag = false this.needUpdateRoom = true // console.log(271) return MoveState } if (MoveState == 1) { this.moveFlag = true } else { this.moveFlag = false } return MoveState } //拖拽墙角/墙面,被其他墙角吸附 updateForAbsorbWallPoints() { if (Object.keys(this.adsorbPointWalls).length == 0) { return } else if (Object.keys(this.adsorbPointWalls).length == 2) { debugger } let joins = [] let wallId = null for (let key in this.adsorbPointWalls) { let point = floorplanService.getPoint(key) joins.push({ join: point, pointId: key, }) wallId = this.adsorbPointWalls[key] } const wall = floorplanService.getWall(wallId) const startPoint = floorplanService.getPoint(wall.start) function sortNumber(a, b) { return mathUtil.getDistance(startPoint, a.join) - mathUtil.getDistance(startPoint, b.join) } joins = joins.sort(sortNumber.bind(this)) for (let i = 0; i < joins.length; ++i) { const info = joins[i] const join = info.join const pointId = info.pointId wallService.splitWall(wallId, pointId, 'end') } } getNewPointsForMoveWall(wallId, dx, dy) { dx = dx / coordinate.res * Constant.defaultZoom/coordinate.zoom dy = -dy / coordinate.res * Constant.defaultZoom/coordinate.zoom const wall = floorplanService.getWall(wallId) const startPoint = floorplanService.getPoint(wall.start) const endPoint = floorplanService.getPoint(wall.end) const p1 = { x: startPoint.x + dx, y: startPoint.y + dy } const p2 = { x: endPoint.x + dx, y: endPoint.y + dy } return { point1: p1, point2: p2, } } getTwoLimitInfos(wallId, newLine) { const wall = floorplanService.getWall(wallId) const startPoint = floorplanService.getPoint(wall.start) const endPoint = floorplanService.getPoint(wall.end) let startLimitLine, endLimitLine, info const wallLine = mathUtil.createLine1(startPoint, endPoint) const limitInfos = {} limitInfos.newStartWallId = false // 不需要新建墙 limitInfos.newEndWallId = false // 不需要新建墙 // 先处理start if (Object.keys(startPoint.parent).length == 1) { startLimitLine = mathUtil.getVerticalLine(wallLine, startPoint) limitInfos.startWallId = null } else if (Object.keys(startPoint.parent).length == 2) { let tempWall if (Object.keys(startPoint.parent)[0] == wallId) { tempWall = floorplanService.getWall(Object.keys(startPoint.parent)[1]) } else if (Object.keys(startPoint.parent)[1] == wallId) { tempWall = floorplanService.getWall(Object.keys(startPoint.parent)[0]) } if (!tempWall) { console.error(352) } const angle = wallService.AngleForWall(tempWall.vectorId, wallId) startLimitLine = wallService.getLine(tempWall) limitInfos.startWallId = tempWall.vectorId if (angle > (Constant.maxAngle / 180) * Math.PI) { startLimitLine = mathUtil.getVerticalLine(wallLine, startPoint) limitInfos.startWallId = null limitInfos.newStartWallId = true } } else { let tempWall, tempWallId info = wallService.wallIdForMinAngle(wall.start, wallId) const wall1 = floorplanService.getWall(info.min0.wallId) const startPoint1 = floorplanService.getPoint(wall1.start) const endPoint1 = floorplanService.getPoint(wall1.end) const wall2 = floorplanService.getWall(info.min1.wallId) const startPoint2 = floorplanService.getPoint(wall2.start) const endPoint2 = floorplanService.getPoint(wall2.end) const join1 = mathUtil.getIntersectionPoint4(startPoint1, endPoint1, newLine) const join2 = mathUtil.getIntersectionPoint4(startPoint2, endPoint2, newLine) // 取角度大的 if (join1 == null && join2 == null) { let angle0 = wallService.AngleForWall(wallId, info.min0.wallId) let angle1 = wallService.AngleForWall(wallId, info.min1.wallId) if (angle0 > Math.PI) { angle0 = Math.PI - angle0 } if (angle1 > Math.PI) { angle1 = Math.PI - angle1 } if (angle0 < angle1) { tempWallId = info.min0.wallId } else { tempWallId = info.min1.wallId } limitInfos.newStartWallId = true } // 取角度小的 else if (join1 != null && join2 != null) { if (info.min0.angle < info.min1.angle) { tempWallId = info.min0.wallId } else { tempWallId = info.min1.wallId } } else if (join1 == null && join2 != null) { tempWallId = info.min1.wallId } else if (join1 != null && join2 == null) { tempWallId = info.min0.wallId } limitInfos.startWallId = tempWallId tempWall = floorplanService.getWall(tempWallId) const angle = wallService.AngleForWall(tempWallId, wallId) startLimitLine = wallService.getLine(tempWall) if (angle > (Constant.maxAngle / 180) * Math.PI) { startLimitLine = mathUtil.getVerticalLine(wallLine, startPoint) limitInfos.startWallId = null limitInfos.newStartWallId = true } } // 再处理end if (Object.keys(endPoint.parent).length == 1) { endLimitLine = mathUtil.getVerticalLine(wallLine, endPoint) limitInfos.endWallId = null } else if (Object.keys(endPoint.parent).length == 2) { let tempWall if (Object.keys(endPoint.parent)[0] == wallId) { tempWall = floorplanService.getWall(Object.keys(endPoint.parent)[1]) } else if (Object.keys(endPoint.parent)[1] == wallId) { tempWall = floorplanService.getWall(Object.keys(endPoint.parent)[0]) } const angle = wallService.AngleForWall(tempWall.vectorId, wallId) endLimitLine = wallService.getLine(tempWall) limitInfos.endWallId = tempWall.vectorId if (angle > (Constant.maxAngle / 180) * Math.PI) { endLimitLine = mathUtil.getVerticalLine(wallLine, endPoint) limitInfos.endWallId = null limitInfos.newEndWallId = true } } else { let tempWall, tempWallId info = wallService.wallIdForMinAngle(wall.end, wallId) const wall1 = floorplanService.getWall(info.min0.wallId) const startPoint1 = floorplanService.getPoint(wall1.start) const endPoint1 = floorplanService.getPoint(wall1.end) const wall2 = floorplanService.getWall(info.min1.wallId) const startPoint2 = floorplanService.getPoint(wall2.start) const endPoint2 = floorplanService.getPoint(wall2.end) const join1 = mathUtil.getIntersectionPoint4(startPoint1, endPoint1, newLine) const join2 = mathUtil.getIntersectionPoint4(startPoint2, endPoint2, newLine) // 取角度大的 if (join1 == null && join2 == null) { let angle0 = wallService.AngleForWall(wallId, info.min0.wallId) let angle1 = wallService.AngleForWall(wallId, info.min1.wallId) if (angle0 > Math.PI) { angle0 = Math.PI - angle0 } if (angle1 > Math.PI) { angle1 = Math.PI - angle1 } if (angle0 < angle1) { tempWallId = info.min0.wallId } else { tempWallId = info.min1.wallId } limitInfos.newEndWallId = true } // 取角度小的 else if (join1 != null && join2 != null) { if (info.min0.angle < info.min1.angle) { tempWallId = info.min0.wallId } else { tempWallId = info.min1.wallId } } else if (join1 == null && join2 != null) { tempWallId = info.min1.wallId } else if (join1 != null && join2 == null) { tempWallId = info.min0.wallId } limitInfos.endWallId = tempWallId tempWall = floorplanService.getWall(tempWallId) const angle = wallService.AngleForWall(tempWallId, wallId) endLimitLine = wallService.getLine(tempWall) if (angle > (Constant.maxAngle / 180) * Math.PI) { endLimitLine = mathUtil.getVerticalLine(wallLine, endPoint) limitInfos.endWallId = null limitInfos.newEndWallId = true } } limitInfos.startLimitLine = startLimitLine limitInfos.endLimitLine = endLimitLine return limitInfos } // 是否可以移动point // 两个判断:拖拽的墙(可能是多个),一方面不能与其他墙相交,另一方面这些墙之间或者与别的墙之间的角度必须大于Constant.minAngle canMoveForPoint(pointId, position, linkedPointId, linkedWallId) { const point = floorplanService.getPoint(pointId) // 先判断第二点(这些墙之间或者与别的墙之间的角度必须大于MinAngle) let flag = this.isOKForMinAngleWall(pointId, position) // 开始考虑第一点 if (flag) { // 不仅仅角度,还有相交 flag = this.isOKForCross(pointId, position, point.parent, linkedPointId, linkedWallId) } return flag } isOKForMinAngleWall(pointId, position) { const point = floorplanService.getPoint(pointId) const parent = point.parent const angle = this.getMinAngle(pointId, position) if (Math.abs(angle) < (Constant.minAngle / 180) * Math.PI) { return false } // 判断邻居点 for (const key in parent) { const wall = floorplanService.getWall(key) const otherPointId = wall.getOtherPointId(pointId) const info = this.getNeighMinAngle(otherPointId, key, position) if (info && Math.abs(info.angle) < (Constant.minAngle / 180) * Math.PI) { return false } else { const otherPoint = floorplanService.getPoint(otherPointId) if (mathUtil.getDistance(position, otherPoint) < Constant.minAdsorb) { return false } } } return true } //点pointId移动到position后,求出最小角度 getMinAngle(pointId, position) { const point = floorplanService.getPoint(pointId) const parent = point.parent let angle = null if (Object.keys(parent).length == 1) { return 2 * Math.PI } else if (Object.keys(parent).length == 2) { const wall1 = floorplanService.getWall(Object.keys(parent)[0]) const wall2 = floorplanService.getWall(Object.keys(parent)[1]) const otherPointId1 = wall1.getOtherPointId(pointId) const otherPoint1 = floorplanService.getPoint(otherPointId1) const otherPointId2 = wall2.getOtherPointId(pointId) const otherPoint2 = floorplanService.getPoint(otherPointId2) angle = mathUtil.Angle(position, otherPoint1, otherPoint2) return angle } else { const _position = { x: position.x + 1, y: position.y, } let angles = [] for (const key in parent) { const wall = floorplanService.getWall(key) const otherPointId = wall.getOtherPointId(pointId) const otherPoint = floorplanService.getPoint(otherPointId) if (mathUtil.equalPoint(_position, otherPoint)) { angles.push(0) continue } else { let angle = mathUtil.Angle(position, _position, otherPoint) // 统一按照逆时针顺序 if (otherPoint.y < position.y) { angle = 2 * Math.PI - angle } angles.push(angle) } } angles = angles.sort(sortNumber) let minAngle = 2 * Math.PI for (let i = 0; i < angles.length - 1; ++i) { for (let j = i + 1; j < angles.length; ++j) { const _angle = angles[j] - angles[i] if (_angle < minAngle) { minAngle = _angle } } } const angle1 = angles[0] const angle2 = angles[angles.length - 1] if (angle1 < Math.PI && angle2 > Math.PI) { const dAngle = 2 * Math.PI + angle1 - angle2 if (dAngle < minAngle) { minAngle = dAngle } } return minAngle } function sortNumber(a, b) { return a - b } } // 用于邻居点 // pointId是顶点 // position是wallId相对于pointId另一头的点的坐标,一般发生改变的时候使用这个函数 getNeighMinAngle(otherPointId, wallId, position) { const point1 = floorplanService.getPoint(otherPointId) const point2 = { x: position.x, y: position.y, } let pointId3 = null let point3 = null let minAngle = null let result = null for (const key in point1.parent) { if (key == wallId) { continue } const wall = floorplanService.getWall(key) pointId3 = wall.getOtherPointId(otherPointId) point3 = floorplanService.getPoint(pointId3) const angle = mathUtil.Angle(point1, point2, point3) if (minAngle == null || minAngle > angle) { minAngle = angle result = { angle: minAngle, pointId: pointId3, } } } return result } // linkedPointId,linkedWallId表示吸附 // wallIds是pointId的parent isOKForCross(pointId, position, wallIds, linkedPointId, linkedWallId) { const walls = floorplanService.getWalls() for (const key in walls) { if (wallIds.hasOwnProperty(key)) { continue } else if (linkedWallId == key) { continue } for (const _key in wallIds) { //相连就不用考虑了 if (wallService.isWallLink(key, _key)) { continue } const _wall = floorplanService.getWall(_key) const otherPointId = _wall.getOtherPointId(pointId) const otherPoint = floorplanService.getPoint(otherPointId) const flag = this.isOKForCrossTwoWall(position, otherPoint, key, linkedPointId, linkedWallId, _wall.vectorId) // 交叉 if (!flag) { this.adsorbPointWalls = {} return false } } } //需要吸附了。 if (Object.keys(this.adsorbPointWalls).length > 0) { return false } else if (this.splitWallId != null) { return false } // 不交叉 return true } // position1表示拖拽的点的坐标(修复过了的) // position2对应墙的另一头坐标 // wallId表示其余的墙(与position1无关的墙) isOKForCrossTwoWall(position1, position2, wallId, linkedPointId, linkedWallId, dragWallId) { const wall = floorplanService.getWall(wallId) const startPoint = floorplanService.getPoint(wall.start) const endPoint = floorplanService.getPoint(wall.end) const join = mathUtil.getIntersectionPoint3(position1, position2, startPoint, endPoint) if (join && wall.start != linkedPointId && wall.end != linkedPointId) { // 交叉了 this.splitWallId = wallId return true } else { if (mathUtil.equalPoint(position1, position2)) { return true } let line = mathUtil.createLine1(position1, position2) let join1 = mathUtil.getJoinLinePoint(startPoint, line) let join2 = mathUtil.getJoinLinePoint(endPoint, line) if (mathUtil.getDistance(join1, startPoint) < Constant.minAdsorb && mathUtil.PointInSegment(join1, position1, position2)) { if (wall.start != linkedPointId) { // 交叉了 this.adsorbPointWalls[startPoint.vectorId] = dragWallId //为了找到全部的吸附点,暂时返回true,在外面一层再做判断 return true } } else if (mathUtil.getDistance(join2, endPoint) < Constant.minAdsorb && mathUtil.PointInSegment(join2, position1, position2)) { if (wall.end != linkedPointId) { // 交叉了 this.adsorbPointWalls[endPoint.vectorId] = dragWallId //为了找到全部的吸附点,暂时返回true,在外面一层再做判断 return true } } line = mathUtil.createLine1(startPoint, endPoint) join1 = mathUtil.getJoinLinePoint(position1, line) join2 = mathUtil.getJoinLinePoint(position2, line) if (mathUtil.getDistance(join1, position1) < Constant.minAdsorb && mathUtil.PointInSegment(join1, startPoint, endPoint)) { if (wall.start != linkedPointId && wall.end != linkedPointId && wallId != linkedWallId) { // 交叉了 //return false return true } } else if (mathUtil.getDistance(join2, position2) < Constant.minAdsorb && mathUtil.PointInSegment(join2, startPoint, endPoint)) { if (wall.start != linkedPointId && wall.end != linkedPointId && wallId != linkedWallId) { // 交叉了 //return false return true } } } return true } isOKForCrossTwoWall2(position1, position2, wallId) { const wall = floorplanService.getWall(wallId) const startPoint = floorplanService.getPoint(wall.start) const endPoint = floorplanService.getPoint(wall.end) let flag = mathUtil.crossTwoLines(position1, position2, startPoint, endPoint, 0.01) if (flag) { // 交叉了 return false } else { if (mathUtil.equalPoint(position1, position2)) { return true } flag = this.isCoincide(position1, position2, wallId) if (!flag) { return false } } return true } isOKForCrossTwoWall3(position1, position2, wallId) { const wall = floorplanService.getWall(wallId) const startPoint = floorplanService.getPoint(wall.start) const endPoint = floorplanService.getPoint(wall.end) const flag = mathUtil.crossTwoLines(position1, position2, startPoint, endPoint, 0.01) if (flag) { // 交叉了 return false } else { if (mathUtil.equalPoint(position1, position2)) { return true } let line = mathUtil.createLine1(position1, position2) let join1 = mathUtil.getJoinLinePoint(startPoint, line) const join2 = mathUtil.getJoinLinePoint(endPoint, line) if (mathUtil.getDistance(join1, startPoint) < Constant.minAdsorb && mathUtil.PointInSegment(join1, position1, position2)) { // 交叉了 return false } else if (mathUtil.getDistance(join2, endPoint) < Constant.minAdsorb && mathUtil.PointInSegment(join2, position1, position2)) { // 交叉了 return false } line = mathUtil.createLine1(startPoint, endPoint) join1 = mathUtil.getJoinLinePoint(position1, line) if (mathUtil.getDistance(join1, position1) < Constant.minAdsorb && wallService.isContain(wall, join1)) { // 交叉了 return false } } return true } isCoincide(position1, position2, wallId) { const wall = floorplanService.getWall(wallId) const startPoint = floorplanService.getPoint(wall.start) const endPoint = floorplanService.getPoint(wall.end) let line = mathUtil.createLine1(position1, position2) let join1 = mathUtil.getJoinLinePoint(startPoint, line) let join2 = mathUtil.getJoinLinePoint(endPoint, line) if (mathUtil.getDistance(join1, startPoint) < Constant.minAdsorb && mathUtil.PointInSegment(join1, position1, position2)) { // 交叉了 return false } else if (mathUtil.getDistance(join2, endPoint) < Constant.minAdsorb && mathUtil.PointInSegment(join2, position1, position2)) { // 交叉了 return false } line = mathUtil.createLine1(startPoint, endPoint) join1 = mathUtil.getJoinLinePoint(position1, line) join2 = mathUtil.getJoinLinePoint(position2, line) if (mathUtil.getDistance(join1, position1) < Constant.minAdsorb && wallService.isContain(wall, join1)) { // 交叉了 return false } else if (mathUtil.getDistance(join2, position2) < Constant.minAdsorb && wallService.isContain(wall, join2)) { // 交叉了 return false } return true } // 更新virtualPosition(一般是吸附) updateVirtualPosition(pointId, virtualPosition, limitWallId, needNew) { const limitWall = floorplanService.getWall(limitWallId) const point = floorplanService.getPoint(pointId) let otherPointId, otherPoint let adsorb = false // 不需要新建墙 if (!needNew) { if (limitWall != null) { otherPointId = limitWall.getOtherPointId(pointId) otherPoint = floorplanService.getPoint(otherPointId) // 会吸附另一头 if ( mathUtil.getDistance(virtualPosition, otherPoint) < Constant.minAdsorb || (!wallService.isContain(limitWall, virtualPosition) && mathUtil.getDistance(virtualPosition, otherPoint) < mathUtil.getDistance(virtualPosition, point)) ) { mathUtil.clonePoint(virtualPosition, otherPoint) adsorb = true } } } // 需要新建墙 else { // 新建的墙太短,不允许 if (mathUtil.getDistance(point, virtualPosition) < Constant.minAdsorb) { return null } } return { adsorb: adsorb, adsorbPointId: adsorb ? otherPointId : null, virtualPosition: virtualPosition, } } // 两条线段的夹角,这两条线段分别有一个端点挨的很近 isOKForTwoSegmentsAngle(pointId, pointId1, pointId2) { const point = floorplanService.getPoint(pointId) const point1 = floorplanService.getPoint(pointId1) const point2 = floorplanService.getPoint(pointId2) const dx = point.x - point1.x const dy = point.y - point1.y const newPoint2 = { x: dx + point2.x, y: dy + point2.y, } for (const key in point.parent) { const wall = floorplanService.getWall(key) const otherPointId = wall.getOtherPointId(pointId) const otherPoint = floorplanService.getPoint(otherPointId) const angle = mathUtil.Angle(point, otherPoint, newPoint2) if (Math.abs(angle) < (Constant.minAngle / 180) * Math.PI) { return false } } return true } // 一头吸附后,是否会重合 // pointId属于wallId,当pointId吸附到adsorbPointId时 isCoincideForAdsorbOne(pointId, adsorbPointId, wallId) { if (pointId && adsorbPointId) { const wall = floorplanService.getWall(wallId) const otherPointId = wall.getOtherPointId(pointId) const _wallId = wallService.getWallId(otherPointId, adsorbPointId) if (_wallId != null) { return true } } return false } isCoincideForAdsorbOne2(wallId, adsorbPointId1, adsorbPointId2) { if (adsorbPointId1 && adsorbPointId2) { const _wallId = wallService.getWallId(adsorbPointId1, adsorbPointId2) if (_wallId != null) { return true } // 可能吸附的是两堵墙,但是这两堵墙呈180° else { let adsorbPoint = floorplanService.getPoint(adsorbPointId1) let parent = adsorbPoint.parent for (const key in parent) { const angle = wallService.AngleForWall3(wallId, key) if (Math.abs(angle) < (Constant.minAngle / 180) * Math.PI) { return true } } adsorbPoint = floorplanService.getPoint(adsorbPointId2) parent = adsorbPoint.parent for (const key in parent) { const angle = wallService.AngleForWall3(wallId, key) if (Math.abs(angle) < (Constant.minAngle / 180) * Math.PI) { return true } } } } return false } // position1和position2表示wall的两个端点坐标(下一步的) // position3和position4表示wall的start一边的线段(startPoint——virtualStartPoint) // position5和position6表示wall的end一边的线段(endPoint——virtualEndPoint) // adsorbPointId1对应start那一头的吸附点 // adsorbPointId2对应end那一头的吸附点 isOKForCrossForMoveWall(position1, position2, wallId, startPointId, endPointId, adsorbPointId1, adsorbPointId2) { const startPoint = floorplanService.getPoint(startPointId) const endPoint = floorplanService.getPoint(endPointId) let flag = true const walls = floorplanService.getWalls() for (const key in walls) { if (key == wallId) { continue } let flag1 = true let flag2 = true const _wall = floorplanService.getWall(key) if (adsorbPointId1 && (adsorbPointId1 == _wall.start || adsorbPointId1 == _wall.end)) { flag1 = false } if (adsorbPointId2 && (adsorbPointId2 == _wall.start || adsorbPointId2 == _wall.end)) { flag2 = false } if (_wall.start == startPointId || _wall.end == startPointId) { flag1 = false } if (_wall.start == endPointId || _wall.end == endPointId) { flag2 = false } // 两头不连 if (flag1 && flag2) { flag = this.isOKForCrossTwoWall2(position1, position2, key) } if (!flag) { return false } if (flag1 && _wall.start != startPointId && _wall.end != startPointId) { flag = this.isOKForCrossTwoWall3(position1, startPoint, key) } if (!flag) { return false } if (flag2 && _wall.start != endPointId && _wall.end != endPointId) { flag = this.isOKForCrossTwoWall3(position2, endPoint, key) } if (!flag) { return false } } return flag } // 更新pointId的坐标 updatePointForMoveWall(wallId, pointId, virtualInfo, limitWallId, needNew) { const point = floorplanService.getPoint(pointId) const wall = floorplanService.getWall(wallId) // 如果没有约束墙,只有两种情况:一种是不新建墙,另一种是需要新建墙 if (limitWallId == null) { // 不需要新建墙,这种情况一般是pointId的parent只有一个 if (!needNew) { point.setPosition(virtualInfo.virtualPosition) } // 新建墙 else { this.createWallForMoveWall(pointId, wallId, virtualInfo.virtualPosition) this.needUpdateRoom = true } } else { /* 不新建墙: 1. 更新坐标(一种是当pointId的parent是2个,另一种是三个,但是wallId对应的两堵墙接近180°) 2. 拆分墙 3. 吸附邻居墙的另一个端点 新建墙: */ // 不新建墙 if (!needNew) { if (!virtualInfo.adsorb) { // 只更新坐标 if (Object.keys(point.parent).length == 2) { point.setPosition(virtualInfo.virtualPosition) } else { const info = wallService.wallIdForMinAngle(pointId, wallId) const angle = wallService.AngleForWall(info.min0.wallId, info.min1.wallId) // 只更新坐标 if (Object.keys(point.parent).length == 3 && angle > (Constant.maxAngle / 180) * Math.PI) { point.setPosition(virtualInfo.virtualPosition) } // 拆分墙 else { const dir = wallService.getDirction(pointId, wallId) // 先断开链接 wallService.subtraWallFromIntersect(pointId, wallId) const newPointId = wall.getPointId(dir) const newPoint = floorplanService.getPoint(newPointId) // 更新新坐标 newPoint.setPosition(virtualInfo.virtualPosition) // 拆分 wallService.splitWall(limitWallId, newPointId, dir) this.needUpdateRoom = true } } } // 吸附邻居墙的另一个端点。 else { wallService.moveTo(pointId, virtualInfo.adsorbPointId) this.needUpdateRoom = true } } // 新建墙 else { this.createWallForMoveWall(pointId, wallId, virtualInfo.virtualPosition) this.needUpdateRoom = true } } } // createWallForMoveWall(pointId, wallId, newPosition) { const wall = floorplanService.getWall(wallId) const dir = wallService.getDirction(pointId, wallId) // 第一步是断开连接 wallService.subtraWallFromIntersect(pointId, wallId) // 第二步更新端点坐标 const newPointId = wall.getPointId(dir) const newPoint = floorplanService.getPoint(newPointId) newPoint.setPosition(newPosition) // 第三步先新建墙 wallService.createWall(pointId, newPointId) // 还缺少wall和newWall相交,这需要等另一头的point完成后最后处理 } deleteWallForLinked(wallId) { const wall = floorplanService.getWall(wallId) wallService.subtraWallFromIntersect(wall.start, wallId) wallService.subtraWallFromIntersect(wall.end, wallId) floorplanService.deleteWall(wallId) } clear(){ this.needUpdateRoom = false this.startMoving = false this.moveFlag = false this.adsorbPointWalls = {} this.splitWallId = null } } const moveWall = new MoveWall() export { moveWall }