123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686 |
- 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, unzip } from "@persagy-web/big/lib";
- import { Wall } from "@persagy-web/big/lib/types/floor/Wall";
- import { CustomWall } from "./CustomWall";
- import { SGraphItem, SGraphStyleItem } from "@persagy-web/graph/lib";
- import { SWallItem } from "@persagy-web/big/lib/items/floor/SWallItem";
- // @ts-ignore
- import pako from "pako";
- export class DivideFloorScene extends FloorScene {
- /** 划分item */
- cutItem: ShadeItem | null = null;
- /** 绘制的分区item */
- drawItem: DrawZoneItem | null = null;
- /** 当前绘制命令 cut-交集区域绘制 zoneDraw-绘制业务空间 wallDraw-画墙 */
- // 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;
- /** 删除日志 */
- deleteWallLog: Wall[] = []
- /** 用户自己增加的墙item */
- customWall: CustomWall[] = []
- /**
- * 清除划分区域
- */
- 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()
- /**
- * 清除绘制的墙
- */
- clearWalls() {
- if (this.customWall.length) {
- this.customWall.forEach(t => {
- this.removeItem(t)
- })
- this.customWall = []
- this.grabItem = null;
- }
- }
- /**
- * 删除墙功能
- */
- delWall() {
- if (this.grabItem && this.grabItem instanceof CustomWall && this.grabItem.status == SItemStatus.Create) {
- this.deleteItem(this.grabItem);
- this.grabItem = null;
- } else if (this.selectContainer.count > 0) {
- const item = this.selectContainer.itemList[0];
- if (item instanceof SWallItem || item instanceof CustomWall) {
- this.deleteItem(item);
- this.selectContainer.itemList.shift();
- }
- }
- }
- /**
- * 删除墙
- */
- deleteItem(item: SGraphItem) {
- if (item instanceof CustomWall) {
- this.removeItem(item);
- for (let i = 0; i < this.customWall.length; i++) {
- if (this.customWall[i] == item) {
- this.customWall.splice(i, 1)
- break
- }
- }
- this.view?.update()
- } else if (item instanceof SWallItem) {
- this.removeItem(item);
- this.deleteWallLog.push(item.data)
- this.view?.update()
- }
- }
- /**
- * 鼠标按下事件
- *
- * @param event 保存事件参数
- * @return boolean
- */
- onMouseDown(event: SMouseEvent): boolean {
- // 判断是否开启吸附,并且有吸附的点
- if (
- this.isAbsorbing &&
- this.highLight &&
- this.highLight.visible
- ) {
- event.x = this.highLight.point.x;
- event.y = this.highLight.point.y;
- }
- if (this.grabItem) {
- return this.grabItem.onMouseDown(event);
- }
- if (event.buttons == 1) {
- 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;
- }
- } else if (this.drawCmd == "wallDraw") {
- let point = new SPoint(event.x, event.y);
- let item = new CustomWall(null, point)
- item.status = SItemStatus.Create;
- this.addItem(item);
- this.customWall.push(item)
- item.connect("finishCreated", this, this.finishCreated)
- 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;
- }
- /**
- * 读取场景中的底图对象并生成相应json
- */
- getMapObject(): string {
- try {
- if (this.json) {
- let map = JSON.parse(this.json);
- const tempWall = map.EntityList[0].Elements.Walls
- console.log(map.EntityList[0].Elements.Walls.length);
- const logArr = this.deleteWallLog.map(t => {
- return t.SourceId
- })
- if (this.deleteWallLog.length) {
- for (let i = 0; i < tempWall.length; i++) {
- if (logArr.includes(tempWall[i].SourceId)) {
- tempWall.splice(i, 1);
- i--;
- }
- }
- }
- if (this.customWall.length) {
- this.customWall.forEach(t => {
- const data = t.toData();
- if (data.OutLine.length) {
- tempWall.push(data)
- }
- })
- }
- console.log(map.EntityList[0].Elements.Walls.length);
- return JSON.stringify(map);
- }
- return ''
- } catch (err) {
- console.log(err)
- return ''
- }
- }
- /**
- * item绘制完成
- */
- finishCreated(item: SGraphStyleItem) {
- this.grabItem = null;
- // @ts-ignore
- item.status = SItemStatus.Normal;
- this.selectContainer.clear();
- this.selectContainer.toggleItem(item);
- this.clearCmdStatus()
- }
- /**
- * 清除命令
- */
- clearCmdStatus() {
- this.drawCmd = ''
- }
- /**
- * 生成txt文件流
- *
- * @param fName 文件名
- */
- generateFile(fName: string, _fn: Function) {
- if (this.json) {
- // const zip = new JSZip();
- // // // // // // 名称-文件内容
- // zip.file(fName, this.json)
- // // console.log(zip);
- // zip.generateAsync({ type: "blob", compression: "DEFLATE" }).then(blob => {
- // // console.log(blob);
- // unzip(blob);
- // // this.upload('testmap4.jsonz', blob)
- // // let url = URL.createObjectURL(blob);
- // // SNetUtil.downLoad('12312312', url);
- // let xxx = new JSZip()
- // xxx.loadAsync(blob).then(res => {
- // // console.log(res.files)
- // // for(let i in res.files) {
- // // console.log(res.files[i]);
- // // res.files[i].async('nodebuffer').then(con => {
- // // console.log(con);
- // // })
- // // }
- // xxx.file('1').async("string").then(resp => {
- // // console.log(resp)
- // })
- // });
- // }, err => {
- // console.log(err)
- // });
- //
- const json = this.getMapObject()
- // 生成压缩的字符串
- const bl = this.zip(json);
- // const blob = new File([bl], '1')
- // 生成blob对象
- const blob = new Blob([bl], { type: 'application/octet-stream' })
- // let url = URL.createObjectURL(new Blob([bl]))
- // SNetUtil.downLoad('12312312', url)
- // 测试能否正常解压
- // unzip(blob);
- // console.log(blob)
- // const file = new File([bl], '111')
- this.upload(fName, blob, _fn)
- }
- }
- /**
- * 上传
- *
- * @param key 当前显示的楼层平面图的key
- * @param blob 上传的blob对象
- */
- upload(key: string, blob: Blob, _fn: Function) {
- let reader = new FileReader();
- reader.onloadstart = function () {
- // 这个事件在读取开始时触发
- console.log('start');
- };
- reader.onprogress = function (p) {
- // 这个事件在读取进行中定时触发
- console.log('onprogress--------', p);
- };
- reader.onload = function () {
- // 这个事件在读取成功结束后触发
- console.log('onload');
- };
- reader.onloadend = function () {
- var xhr = new XMLHttpRequest();
- xhr.open(
- "POST",
- `/image-service/common/file_upload?systemId=revit&secret=63afbef6906c342b&overwrite=true&key=${key}`
- );
- xhr.send(reader.result);
- xhr.onreadystatechange = function () {
- if (xhr.readyState == 4) {
- if (xhr.status == 200) {
- _fn()
- } else {
- }
- }
- };
- }
- reader.readAsArrayBuffer(blob);
- }
- /**
- * 压缩文件
- *
- * @param str 要压缩的字符串
- */
- zip(str: string): string {
- var binaryString = pako.deflate(str)
- // var binaryString = pako.gzip(escape(str), { to: 'string' });
- return binaryString;
- }
- }
|