import { SMouseEvent } from "@persagy-web/base/lib"; import { SMathUtil } from "@persagy-web/big/lib/utils/SMathUtil"; import { SPoint, SRect } from "@persagy-web/draw/lib"; import { FloorScene } from "./FloorScene"; import { HighlightItem } from "./HighlightItem"; import { ShadeItem } from "./ShadeItem"; // @ts-ignore import { intersect, polygon, segments, combine, selectIntersect, selectUnion, selectDifference, selectDifferenceRev, difference } from "polybooljs"; import { DrawZoneItem } from "./DrawZoneItem"; import { SItemStatus } from "@persagy-web/big/lib"; export class DivideFloorScene extends FloorScene { /** 划分item */ cutItem: ShadeItem | null = null; /** 绘制的分区item */ drawItem: DrawZoneItem | null = null; /** 当前绘制命令 cut-交集区域绘制 zoneDraw-绘制业务空间 */ // 2021.3.4需求不算交集,直接绘制业务空间 drawCmd: string = ''; /** 是否开启吸附 */ private _isAbsorbing: boolean = false; get isAbsorbing(): boolean { return this._isAbsorbing; } // Get isAbsorbing set isAbsorbing(v: boolean) { this._isAbsorbing = v; } // Set isAbsorbing /** 高亮item */ highLight: HighlightItem | null = null; /** * 清除划分区域 */ clearCut(): void { if (this.cutItem && this.drawCmd == 'cut') { this.grabItem = null; this.removeItem(this.cutItem); this.cutItem = null; this.view && this.view.update(); } if (this.drawItem && this.drawCmd == 'zoneDraw') { this.grabItem = null; this.removeItem(this.drawItem); this.drawItem = null; this.view && this.view.update(); } this.drawCmd = ''; } // Function clearCut() /** * 鼠标按下事件 * * @param event 保存事件参数 * @return boolean */ onMouseDown(event: SMouseEvent): boolean { if (event.buttons == 1) { // 判断是否开启吸附,并且有吸附的点 if ( this.isAbsorbing && this.highLight && this.highLight.visible ) { event.x = this.highLight.point.x; event.y = this.highLight.point.y; } if (this.drawCmd == 'cut') { if (!this.cutItem) { let point = new SPoint(event.x, event.y); let item = new ShadeItem(null, point); this.addItem(item); this.cutItem = item; this.grabItem = item; return true; } } else if (this.drawCmd == 'zoneDraw') { if (!this.drawItem) { let point = new SPoint(event.x, event.y); let item = new DrawZoneItem(null, point); item.status = SItemStatus.Create; this.addItem(item); this.drawItem = item; this.grabItem = item; return true; } } } return super.onMouseDown(event) } /** * 吸附空间 * * @param event 鼠标事件对象 */ onMouseMove(event: SMouseEvent): boolean { super.onMouseMove(event); if (this.isAbsorbing) { if (!this.highLight) { this.highLight = new HighlightItem(null); this.addItem(this.highLight); } this.highLight.visible = false; // if (!this.absorbShade(event)) { this.absorbSpace(event); // } } return false; } // Function onMouseMove() /** * 吸附空间 * * @param event 鼠标事件对象 * @return boolean 是否找到吸附的对象 */ absorbSpace(event: SMouseEvent): boolean { if (!this.highLight) { return false; } let absorbLen = 1000; if (this.view) { absorbLen = 10 / this.view.scale; } let P = this.absorbSpacePoint(event, absorbLen); if (P.Point) { this.highLight.distance = P.MinDis; this.highLight.point = new SPoint(P.Point.X, -P.Point.Y); this.highLight.visible = true; return true; } else { let L = this.absorbSpaceLine(event, absorbLen); if (L.Line && L.Point) { this.highLight.distance = L.MinDis; this.highLight.point = L.Point; this.highLight.line = L.Line; this.highLight.visible = true; return true; } return false; } } // Function absorbSpace() /** * 吸附空间点 * * @param event 鼠标事件对象 * @param absorbLen 吸附距离 * @return MinDis 吸附的点 */ absorbSpacePoint(event: SMouseEvent, absorbLen: number): any { let minPointDis = Number.MAX_SAFE_INTEGER; let Point; this.spaceList.map((space): void => { if ( DivideFloorScene.isPointInAbsorbArea( new SPoint(event.x, event.y), space.minX, space.maxX, space.minY, space.maxY ) ) { space.data.OutLine.forEach((item): void => { let minDis = SMathUtil.getMinDisPoint( new SPoint(event.x, event.y), item ); if ( minDis && minDis.MinDis < absorbLen && minDis.MinDis < minPointDis ) { minPointDis = minDis.MinDis; Point = minDis.Point; } }); } }); return { MinDis: minPointDis, Point: Point }; } // Function absorbSpacePoint() /** * 点是否在吸附区域内 * * @param p 要判断的点 * @param minX 空间区域 * @param minY 空间区域 * @param maxX 空间区域 * @param maxY 空间区域 */ static isPointInAbsorbArea( p: SPoint, minX: number, maxX: number, minY: number, maxY: number ): boolean { let rect = new SRect( minX - 1000, minY - 1000, maxX - minX + 2000, maxY - minY + 2000 ); return rect.contains(p.x, p.y); } // Function isPointInAbsorbArea() /** * 吸附空间线 * * @param event 鼠标事件对象 * @param absorbLen 吸附距离 * @return PointToLine 吸附的线 */ absorbSpaceLine(event: SMouseEvent, absorbLen: number): any { let minPointDis = Number.MAX_SAFE_INTEGER; let Point, Line; this.spaceList.forEach((space): void => { if ( DivideFloorScene.isPointInAbsorbArea( new SPoint(event.x, event.y), space.minX, space.maxX, space.minY, space.maxY ) ) { space.data.OutLine.forEach((item): void => { let minDisLine = SMathUtil.getMinDisLine( new SPoint(event.x, event.y), item ); if ( minDisLine && minDisLine.MinDis < absorbLen && minDisLine.MinDis < minPointDis ) { minPointDis = minDisLine.MinDis; Point = minDisLine.Point; Line = minDisLine.Line; } }); } }); return { MinDis: minPointDis, Point: Point, Line: Line }; } // Function absorbSpaceLine() /** * 计算选中的空间与业务空间的差集 */ getSpaceZoneIntersect(): SPoint[][] | undefined { // 未选中空间- 不计算 if (!this.selectContainer.itemList.length) { return } // 没有业务空间不计算 if (!this.zoneList.length) { return } // 生成选中的空间计算时用的格式 const space = { regions: [], inverted: false } const sourceIdToDiff = {}; try { let poly1, poly2; const start = +new Date(); let rect1: SRect, list = []; // 计算外接矩阵与选中空间相交的业务空间的所有轮廓 this.selectContainer.itemList.forEach(item => { rect1 = item.boundingRect(); this.zoneList.forEach(t => { if (t.visible) { let rect2 = t.boundingRect(); // 外接矩阵是否相交,缩小计算范围 if (SMathUtil.rectIntersection(rect1, rect2)) { t.pointList.forEach((zoneLine): void => { let polygons = { regions: [], inverted: false }; zoneLine.forEach((po): void => { let point = SMathUtil.transferToArray(po); polygons.regions.push(point); }); list.push(polygons); }) } } }) }) // if (list.length) { let seg1 = segments(list[0]), seg2, comb; for (let i = 1; i < list.length; i++) { seg2 = segments(list[i]); comb = combine(seg1, seg2); seg1 = selectUnion(comb); } poly1 = seg1; this.selectContainer.itemList.forEach(t => { let key = t.data.SourceId; poly2 = { regions: [], inverted: false } poly2.regions = t.pointList[0].map((item): number[][] => { return SMathUtil.transferToArray(item); }); const comb = combine(segments(poly2), poly1) const diffObj = selectDifference(comb); const diffPoly = polygon(diffObj) // 理论上只要选择了空间 length就不会为0 if (diffPoly.regions.length) { let outlineList = SMathUtil.getIntersectInArray( diffPoly.regions ); console.log(outlineList); // @ts-ignore sourceIdToDiff[key] = outlineList.map(t => { let arr = [t.Outer]; t.Inner.forEach((inner): void => { arr.push(inner); }); return arr; }); } }); const end = +new Date() console.log(sourceIdToDiff); console.log(end - start, 'comb-diff'); return sourceIdToDiff } } catch (err) { console.log(err); } } /** * 计算选中的空间与绘制的区域交集 */ getSpaceCutIntersect(seg?: any): SPoint[][] | undefined { // 未选中空间- 不计算 if (!this.selectContainer.itemList.length) { return } // 没有绘制不计算 if (!this.cutItem) { return } const sourceIdToIntersect = {}; try { const start = +new Date(); let cutPoly; if (seg) { cutPoly = seg } else { const poly = { regions: [SMathUtil.transferToArray(this.cutItem.pointList)], inverted: false } cutPoly = segments(poly) } this.selectContainer.itemList.forEach(item => { const arr = item.pointList[0].map(t => { return SMathUtil.transferToArray(t); }) const poly2 = { regions: arr, inverted: false } const seg = segments(poly2) const comb = combine(cutPoly, seg) if (item.data.SourceId) { const spoly = polygon(selectIntersect(comb)); // 绘制切割区域可能与空间没有交集 if (spoly.regions.length) { let outlineList = SMathUtil.getIntersectInArray( spoly.regions ); console.log(outlineList); // @ts-ignore sourceIdToIntersect[item.data.SourceId] = outlineList.map(t => { let arr = [t.Outer]; t.Inner.forEach((inner): void => { arr.push(inner); }); return arr; }); // 得到的结果 // sourceIdToIntersect[item.data.SourceId] = polygon(selectIntersect(comb)) } else { // 没有交集 } } }) const end = +new Date() console.log(end - start, 'comb-intersect', sourceIdToIntersect); return sourceIdToIntersect } catch (err) { console.log(err); } return } /** * 如果场景中既有绘制的区域也有创建好的业务空间,则在区域中将已创建的业务空间减去 */ getCurInZone() { if (!this.cutItem) { return } // 绘制区域外接矩阵 const rect2 = this.cutItem.boundingRect() // 绘制区域的多边形 - 也是每次减去业务空间后剩下的多边形 let poly = segments({ regions: [SMathUtil.transferToArray(this.cutItem.pointList)], inverted: false }) this.zoneList.forEach(item => { if (item.visible) { const rect1 = item.boundingRect(); if (SMathUtil.rectIntersection(rect1, rect2)) { item.pointList.forEach((zoneLine): void => { let polygons = { regions: [], inverted: false } zoneLine.forEach((po): void => { let point = SMathUtil.transferToArray(po); polygons.regions.push(point); }); const segZone = segments(polygons); const comb = combine(poly, segZone); poly = selectDifference(comb) }) } } }) console.log(poly); // poly为segments类型 return poly; } }