Browse Source

鼠标吸附版本发布,及功能添加

haojianlong 5 years ago
parent
commit
196aab8de9

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
     "name": "@saga-web/cad-engine",
-    "version": "2.0.307",
+    "version": "2.0.328",
     "description": "上格云 CAD图形引擎。",
     "main": "lib/index.js",
     "types": "lib/index.d.js",

+ 160 - 1
src/DivideFloorScene.ts

@@ -19,12 +19,16 @@
  */
 
 import { FloorScene } from "./FloorScene";
-import { SPoint } from "@saga-web/draw/lib";
+import { SPoint, SRect } from "@saga-web/draw/lib";
 import { SceneMarkItem } from "./items/SceneMarkItem";
 import { ZoneItem } from "./items/ZoneItem";
 import { Zone } from "./types/Zone";
 import { SMouseEvent } from "@saga-web/base/lib";
 import { SGraphyItem } from "@saga-web/graphy/lib";
+import { HighlightItem } from "./items/HighlightItem";
+import { SMathUtil } from "./utils/SMathUtil";
+import { MinDis } from "./types/MinDis";
+import { PointToLine } from "./types/PointToLine";
 
 /**
  * 划分业务空间
@@ -65,6 +69,17 @@ export class DivideFloorScene extends FloorScene {
         });
     } // Set isZoneSelectable
 
+    /** 高亮item  */
+    hightLight: HighlightItem = new HighlightItem(null, new SPoint(), 0);
+    /** 吸附距离   */
+    private _absorbLen: number = 1;
+    get absorbLen(): number {
+        return this._absorbLen;
+    } // Get absorbLen
+    set absorbLen(v: number) {
+        this._absorbLen = v;
+    } // Set absorbLen
+
     /**
      * 构造函数
      *
@@ -72,6 +87,7 @@ export class DivideFloorScene extends FloorScene {
      */
     constructor() {
         super();
+        this.addItem(this.hightLight);
     } // Constructor
 
     /**
@@ -221,4 +237,147 @@ export class DivideFloorScene extends FloorScene {
         });
         zoneitem.visible = false;
     } // Function changeSelectZone
+
+    /**
+     *  吸附空间
+     *
+     *  @param  鼠标事件对象
+     */
+    onMouseMove(event: SMouseEvent): boolean {
+        this.hightLight.visible = false;
+        this.absorbSpace(event);
+        return false;
+    } // Function onMouseMove
+
+    /**
+     *  吸附空间
+     *
+     *  @param  鼠标事件对象
+     */
+    absorbSpace(event: SMouseEvent): void {
+        let P = this.absorbPoint(event);
+        if (P.Point) {
+            this.hightLight.distance = P.MinDis;
+            this.hightLight.point = new SPoint(P.Point.X, -P.Point.Y);
+            this.hightLight.visible = true;
+        } else {
+            let L = this.absorbLine(event);
+            if (L.Line) {
+                this.hightLight.distance = L.MinDis;
+                this.hightLight.line = L.Line;
+                this.hightLight.visible = true;
+            }
+        }
+    } // Function absorbSpace
+
+    /**
+     *  点是否在吸附区域内
+     *
+     *  @param  p       要判断的点
+     *  @param  minX    空间区域
+     *  @param  minY    空间区域
+     *  @param  maxX    空间区域
+     *  @param  maxY    空间区域
+     */
+    isPointInAbsorbArea(
+        p: SPoint,
+        minX: number,
+        maxX: number,
+        minY: number,
+        maxY: number
+    ): boolean {
+        let rect = new SRect(
+            minX - 1000,
+            minY - 1000,
+            maxX - minX + 200,
+            maxY - minY + 2000
+        );
+        return rect.contains(p.x, p.y);
+    } // Function isPointInAbsorbArea
+
+    /**
+     *  吸附点
+     *
+     *  @param  鼠标事件对象
+     *  @return 吸附的点
+     */
+    absorbPoint(event: SMouseEvent): MinDis {
+        let minPointDis = Number.MAX_SAFE_INTEGER;
+        let Point;
+        this.spaceList.map(space => {
+            if (
+                this.isPointInAbsorbArea(
+                    new SPoint(event.x, event.y),
+                    space.minX,
+                    space.maxX,
+                    space.minY,
+                    space.maxY
+                )
+            ) {
+                space.data.OutLine.map(item => {
+                    let minDis = SMathUtil.getMinDisPoint(
+                        new SPoint(event.x, event.y),
+                        item
+                    );
+                    if (
+                        minDis &&
+                        minDis.MinDis < 2500 &&
+                        minDis.MinDis < minPointDis
+                    ) {
+                        minPointDis = minDis.MinDis;
+                        Point = minDis.Point;
+                    }
+                });
+            }
+        });
+        let minPoint = {
+            MinDis: minPointDis,
+            Point: Point
+        };
+        return minPoint;
+    } // Function absorbPoint
+
+    /**
+     *  吸附点
+     *
+     *  @param  鼠标事件对象
+     *  @return 吸附的线
+     */
+    absorbLine(event: SMouseEvent): PointToLine {
+        let minPointDis = Number.MAX_SAFE_INTEGER;
+        let Point, Line;
+        this.spaceList.map(space => {
+            if (
+                this.isPointInAbsorbArea(
+                    new SPoint(event.x, event.y),
+                    space.minX,
+                    space.maxX,
+                    space.minY,
+                    space.maxY
+                )
+            ) {
+                space.data.OutLine.map(item => {
+                    let minDisLine = SMathUtil.getMinDisLine(
+                        new SPoint(event.x, event.y),
+                        item
+                    );
+                    if (
+                        minDisLine &&
+                        minDisLine.MinDis < 2500 &&
+                        minDisLine.MinDis < minPointDis
+                    ) {
+                        minPointDis = minDisLine.MinDis;
+                        Point = minDisLine.Point;
+                        Line = minDisLine.Line;
+                    }
+                });
+            }
+        });
+        let minPointLine = {
+            MinDis: minPointDis,
+            Point: Point,
+            Line: Line
+        };
+        return minPointLine;
+    } // Function absorbLine
 } // Class DivideFloorScene

+ 12 - 0
src/FloorScene.ts

@@ -35,6 +35,7 @@ import { ColumnItem } from "./items/ColumnItem";
 import { VirtualWallItem } from "./items/VirtualWallItem";
 import { DoorItem } from "./items/DoorItem";
 import { WindowItem } from "./items/WindowItem";
+import { SPoint } from "@saga-web/draw/lib";
 
 /**
  * 楼层场景
@@ -457,4 +458,15 @@ export class FloorScene extends SGraphyScene {
             return sp;
         });
     } // Function clearSelectedSpaces
+
+    /**
+     *  点到点距离
+     *  @param  p1  第一点
+     *  @param  p2  第二点
+     */
+    PointToPointDis(p1: SPoint, p2: SPoint): number {
+        return Math.sqrt(
+            (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y)
+        );
+    } // Function PointToPointDis()
 } // Class FloorScene

+ 2 - 1
src/index.ts

@@ -1,5 +1,6 @@
 import { FloorScene } from "./FloorScene";
 import { LocationPointScene } from "./LocationPointScene";
+import { FloorView } from "./FloorView";
 import { DivideFloorScene } from "./DivideFloorScene";
 import { SpaceItem } from "./items/SpaceItem";
 import { ColumnItem } from "./items/ColumnItem";
@@ -11,7 +12,7 @@ import { VirtualWallItem } from "./items/VirtualWallItem";
 import { SceneMarkItem } from "./items/SceneMarkItem";
 import { MarkerItem } from "./items/MarkItem";
 
-export { FloorScene, LocationPointScene, DivideFloorScene };
+export { FloorScene, LocationPointScene, DivideFloorScene, FloorView };
 
 export {
     SpaceItem,

+ 93 - 0
src/items/HighlightItem.ts

@@ -0,0 +1,93 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *                      :*$@@%$*:                         ;:                ;;    ;;
+ *                    :@@%!  :!@@%:                       %!             ;%%@@%$ =@@@@@@@%;     @%@@@%%%%@@@@@
+ *                   :@%;       :$=                       %%$$$%$$         ;$$  ;$@=   !@$
+ *                   =@!                                  %!              @ $=;%   !@@@%:      !$$$$$$$$$$$$$$=
+ *                   =@*                                  %!              @ $= % %@=   =%@!      %=
+ *              *$%%! @@=        ;=$%%%$*:                %!              @ $= % =%%%%%%@$      *%:         =%
+ *            %@@!:    !@@@%=$@@@@%!  :*@@$:              %!              @ $= % $*     ;@      @*          :%*
+ *          ;@@!          ;!!!;:         ;@%:      =======@%========*     @ $$ % $%*****$@     :@$=*********=@$
+ *          $@*   ;@@@%=!:                *@*
+ *          =@$    ;;;!=%@@@@=!           =@!
+ *           %@$:      =@%: :*@@@*       %@=                    Copyright (c) 2016-2019.  北京上格云技术有限公司
+ *            ;%@@$=$@@%*       *@@@$=%@@%;
+ *               ::;::             ::;::                                              All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+import { SGraphyItem } from "@saga-web/graphy/lib";
+import { SColor, SLine, SPainter, SPoint } from "@saga-web/draw/lib";
+
+/**
+ * 吸附时高亮对象
+ *
+ * @author  郝建龙
+ */
+export class HighlightItem extends SGraphyItem {
+    /** 对象与鼠标位置距离   */
+    distance: number = 0;
+    /** 对象类型   */
+    private type: number = 1;
+
+    /** 点对象数据   */
+    _point: SPoint = new SPoint();
+    get point(): SPoint {
+        return this._point;
+    } // Get point
+    set point(v: SPoint) {
+        this._point = v;
+        this.type = 1;
+    } // Set point
+
+    /** 点对象数据   */
+    _line: SLine = new SLine();
+    get line(): SLine {
+        return this._line;
+    } // Get line
+    set line(v: SLine) {
+        this._line = v;
+        this.type = 2;
+    } // Set line
+
+    /**
+     * 构造函数
+     *
+     * @param parent    指向父对象
+     * @param data      对象
+     * @param distance  对象与鼠标位置的距离
+     */
+    constructor(
+        parent: SGraphyItem | null,
+        data: SPoint | SLine,
+        distance: number
+    ) {
+        super(parent);
+        if (data instanceof SPoint) {
+            this.point = data;
+        } else {
+            this.line = data;
+        }
+        this.distance = distance;
+        this.visible = false;
+        this.zOrder = 19;
+    } // Constructor
+
+    /**
+     * Item绘制操作
+     *
+     * @param   painter       painter对象
+     */
+    onDraw(painter: SPainter): void {
+        painter.pen.lineWidth = painter.toPx(5);
+        painter.pen.color = new SColor("#409EFF");
+        if (this.type == 1) {
+            painter.drawCircle(this.point.x, this.point.y, painter.toPx(10));
+        } else if (this.type == 2) {
+            painter.pen.lineWidth = painter.toPx(10);
+            painter.drawLine(this.line);
+        }
+    } // Function onDraw()
+} // Class HighlightItem

+ 9 - 7
src/items/SpaceItem.ts

@@ -42,13 +42,13 @@ export class SpaceItem extends SGraphyItem {
     /** 空间轮廓线坐标list  */
     private readonly pointArr: SPoint[][] = [];
     /** X坐标最小值  */
-    private minX = 0;
+    minX = 0;
     /** X坐标最大值  */
-    private maxX = 0;
+    maxX = 0;
     /** Y坐标最小值  */
-    private minY = 0;
+    minY = 0;
     /** Y坐标最大值  */
-    private maxY = 0;
+    maxY = 0;
     /** path对象     */
     private path = new SPath2D();
     /** 选中时颜色   */
@@ -120,6 +120,10 @@ export class SpaceItem extends SGraphyItem {
         return true;
     } // Function onClick()
 
+    onMouseMove(event: SMouseEvent): boolean {
+        return false;
+    }
+
     /**
      * 判断点是否在区域内
      *
@@ -148,9 +152,7 @@ export class SpaceItem extends SGraphyItem {
      */
     onDraw(painter: SPainter): void {
         painter.pen.color = SColor.Transparent;
-        painter.brush.color = this.selected
-            ? this.selectColor
-            : Opt.spaceColor;
+        painter.brush.color = this.selected ? this.selectColor : Opt.spaceColor;
         painter.pen.lineWidth = 200;
         painter.drawPath(this.path);
 

+ 5 - 1
src/items/ZoneItem.ts

@@ -68,7 +68,11 @@ export class ZoneItem extends SGraphyItem {
     constructor(parent: SGraphyItem | null, data: Zone) {
         super(parent);
         this.data = data;
-        if (this.data.OutLine.length && this.data.OutLine[0].length) {
+        if (
+            this.data.OutLine.length &&
+            this.data.OutLine[0] &&
+            this.data.OutLine[0].length
+        ) {
             let tempArr = this.data.OutLine;
             this.minX = tempArr[0][0][0].X;
             this.maxX = this.minX;

+ 33 - 0
src/types/MinDis.ts

@@ -0,0 +1,33 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *                      :*$@@%$*:                         ;:                ;;    ;;
+ *                    :@@%!  :!@@%:                       %!             ;%%@@%$ =@@@@@@@%;     @%@@@%%%%@@@@@
+ *                   :@%;       :$=                       %%$$$%$$         ;$$  ;$@=   !@$
+ *                   =@!                                  %!              @ $=;%   !@@@%:      !$$$$$$$$$$$$$$=
+ *                   =@*                                  %!              @ $= % %@=   =%@!      %=
+ *              *$%%! @@=        ;=$%%%$*:                %!              @ $= % =%%%%%%@$      *%:         =%
+ *            %@@!:    !@@@%=$@@@@%!  :*@@$:              %!              @ $= % $*     ;@      @*          :%*
+ *          ;@@!          ;!!!;:         ;@%:      =======@%========*     @ $$ % $%*****$@     :@$=*********=@$
+ *          $@*   ;@@@%=!:                *@*
+ *          =@$    ;;;!=%@@@@=!           =@!
+ *           %@$:      =@%: :*@@@*       %@=                    Copyright (c) 2016-2019.  北京上格云技术有限公司
+ *            ;%@@$=$@@%*       *@@@$=%@@%;
+ *               ::;::             ::;::                                              All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+import { Point } from "./Point";
+
+/**
+ * 距离最短点接口
+ *
+ * @author  郝建龙
+ */
+export interface MinDis {
+    /** 最短距离      */
+    MinDis: number;
+    /** 最短距离的点  */
+    Point: Point | undefined;
+} // Interface Space

+ 32 - 0
src/types/PointToLine.ts

@@ -0,0 +1,32 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *                      :*$@@%$*:                         ;:                ;;    ;;
+ *                    :@@%!  :!@@%:                       %!             ;%%@@%$ =@@@@@@@%;     @%@@@%%%%@@@@@
+ *                   :@%;       :$=                       %%$$$%$$         ;$$  ;$@=   !@$
+ *                   =@!                                  %!              @ $=;%   !@@@%:      !$$$$$$$$$$$$$$=
+ *                   =@*                                  %!              @ $= % %@=   =%@!      %=
+ *              *$%%! @@=        ;=$%%%$*:                %!              @ $= % =%%%%%%@$      *%:         =%
+ *            %@@!:    !@@@%=$@@@@%!  :*@@$:              %!              @ $= % $*     ;@      @*          :%*
+ *          ;@@!          ;!!!;:         ;@%:      =======@%========*     @ $$ % $%*****$@     :@$=*********=@$
+ *          $@*   ;@@@%=!:                *@*
+ *          =@$    ;;;!=%@@@@=!           =@!
+ *           %@$:      =@%: :*@@@*       %@=                    Copyright (c) 2016-2019.  北京上格云技术有限公司
+ *            ;%@@$=$@@%*       *@@@$=%@@%;
+ *               ::;::             ::;::                                              All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+import { SLine, SPoint } from "@saga-web/draw/lib";
+
+/**
+ * 距离最短线接口
+ *
+ * @author  郝建龙
+ */
+export interface PointToLine {
+    MinDis: number;
+    Line: SLine | undefined;
+    Point: SPoint | undefined;
+} // Interface Space

+ 2 - 0
src/types/Space.ts

@@ -31,6 +31,8 @@ export interface Space {
     BoundarySegments: string[];
     /** 位置  */
     Location: Place;
+    /** 高度  */
+    Height: number;
     /** 模型id(外键)    */
     ModelId: string;
     /** 名称  */

+ 2 - 0
src/types/Zone.ts

@@ -35,4 +35,6 @@ export interface Zone {
     RoomID: string;
     /** 颜色  */
     Color: SColor;
+    /** 高度  */
+    Height: number;
 } // Interface Space

+ 149 - 0
src/utils/SMathUtil.ts

@@ -0,0 +1,149 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *                      :*$@@%$*:                         ;:                ;;    ;;
+ *                    :@@%!  :!@@%:                       %!             ;%%@@%$ =@@@@@@@%;     @%@@@%%%%@@@@@
+ *                   :@%;       :$=                       %%$$$%$$         ;$$  ;$@=   !@$
+ *                   =@!                                  %!              @ $=;%   !@@@%:      !$$$$$$$$$$$$$$=
+ *                   =@*                                  %!              @ $= % %@=   =%@!      %=
+ *              *$%%! @@=        ;=$%%%$*:                %!              @ $= % =%%%%%%@$      *%:         =%
+ *            %@@!:    !@@@%=$@@@@%!  :*@@$:              %!              @ $= % $*     ;@      @*          :%*
+ *          ;@@!          ;!!!;:         ;@%:      =======@%========*     @ $$ % $%*****$@     :@$=*********=@$
+ *          $@*   ;@@@%=!:                *@*
+ *          =@$    ;;;!=%@@@@=!           =@!
+ *           %@$:      =@%: :*@@@*       %@=                    Copyright (c) 2016-2019.  北京上格云技术有限公司
+ *            ;%@@$=$@@%*       *@@@$=%@@%;
+ *               ::;::             ::;::                                              All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+import { SLine, SPoint } from "@saga-web/draw/lib";
+import { MinDis } from "../types/MinDis";
+import { Point } from "../types/Point";
+import { PointToLine } from "../types/PointToLine";
+
+export class SMathUtil {
+    /**
+     * 计算点到点距离
+     *
+     * @param   p1  第一个点
+     * @param   p2  第二个点
+     * @return  距离
+     */
+    static pointDistance(
+        x1: number,
+        y1: number,
+        x2: number,
+        y2: number
+    ): number {
+        return Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
+    } // Function pointDistance()
+
+    /**
+     * 计算点到点集中点最小距离,返回该点和该距离
+     *
+     * @param   p       第一个点
+     * @param   arr     点集
+     * @return  距离,点坐标
+     */
+    static getMinDisPoint(p: SPoint, arr: Point[]): MinDis | null {
+        if (!arr.length) {
+            return null;
+        }
+        let minDis = {
+            MinDis: SMathUtil.pointDistance(p.x, p.y, arr[0].X, -arr[0].Y),
+            Point: arr[0]
+        };
+        for (let i = 1; i < arr.length; i++) {
+            let ds = SMathUtil.pointDistance(p.x, p.y, arr[i].X, -arr[i].Y);
+            if (ds < minDis.MinDis) {
+                minDis.MinDis = ds;
+                minDis.Point = arr[i];
+            }
+        }
+        return minDis;
+    } // Function getMinDisPoint()
+
+    /**
+     * 计算点到线段垂线与线段的交点
+     *
+     * @param   p   点
+     * @param   l   线段
+     * @return  距离
+     */
+    static pointToLine(p: SPoint, l: SLine): PointToLine {
+        let d = {
+            MinDis: Number.MAX_SAFE_INTEGER,
+            Line: new SLine(),
+            Point: new SPoint()
+        };
+        let bgX = Math.max(l.x1, l.x2);
+        let smX = Math.min(l.x1, l.x2);
+        if (l.dx == 0) {
+            // l.dx为0 说明线段是垂直于x轴的
+            let bgY = Math.max(l.y1, l.y2);
+            let smY = Math.min(l.y1, l.y2);
+            if (p.y > smY && p.y < bgY) {
+                d.MinDis = Math.abs(p.x - l.x1);
+                d.Line = l;
+                d.Point = new SPoint(l.x1, p.y);
+            }
+        } else if (l.dy == 0) {
+            // l.dy为0 说明线段是平行于x轴的
+            if (p.x > smX && p.x < bgX) {
+                d.MinDis = Math.abs(p.y - l.y1);
+                d.Line = l;
+                d.Point = new SPoint(p.x, l.y1);
+            }
+        } else {
+            // 直线1
+            let k1 = (l.y1 - l.y2) / (l.x1 - l.x2);
+            let b1 = l.y1 - k1 * l.x1;
+            // 直线2
+            let k2 = -1 / k1;
+            let b2 = p.y - k2 * p.x;
+            // 交点
+            let x = (b1 - b2) / (k2 - k1);
+            let y = k1 * x + b1;
+            if (x > smX && x < bgX) {
+                d.MinDis = SMathUtil.pointDistance(p.x, p.y, x, y);
+                d.Line = l;
+                d.Point = new SPoint(x, y);
+            }
+        }
+        return d;
+    } // Function pointDistance()
+
+    /**
+     * 计算点到点集中线段最小距离,返回该点和该距离
+     *
+     * @param   p       第一个点
+     * @param   arr     点集
+     * @return  距离,点坐标
+     */
+    static getMinDisLine(p: SPoint, arr: Point[]): PointToLine | null {
+        if (arr.length < 2) {
+            return null;
+        }
+        let PTL = SMathUtil.pointToLine(
+            p,
+            new SLine(
+                arr[arr.length - 1].X,
+                -arr[arr.length - 1].Y,
+                arr[0].X,
+                -arr[0].Y
+            )
+        );
+        for (let i = 0; i < arr.length - 1; i++) {
+            let temp = SMathUtil.pointToLine(
+                p,
+                new SLine(arr[i].X, -arr[i].Y, arr[i + 1].X, -arr[i + 1].Y)
+            );
+            if (temp.MinDis < PTL.MinDis) {
+                PTL = temp;
+            }
+        }
+        return PTL;
+    } // Function getMinDisPoint()
+}