Browse Source

Merge remote-tracking branch 'origin/master'

张维新 4 years ago
parent
commit
d8fba44f05
50 changed files with 1980 additions and 194 deletions
  1. 74 0
      docs/.vuepress/components/example/web/graph/Circle1.vue
  2. 30 3
      docs/.vuepress/components/example/web/graph/DrawLine1.vue
  3. 6 6
      docs/.vuepress/components/example/web/graph/scene/ClockItem.vue
  4. 62 0
      docs/.vuepress/components/example/web/graph/scene/ImageItem.vue
  5. 253 0
      docs/.vuepress/components/example/web/graph/scene/SEditLine.vue
  6. 568 0
      docs/.vuepress/components/example/web/graph/scene/SEditPolygon.vue
  7. 231 0
      docs/.vuepress/components/example/web/graph/scene/SImgTextItem.vue
  8. 119 0
      docs/.vuepress/components/example/web/graph/scene/TextItem.vue
  9. 27 30
      docs/.vuepress/components/example/web/graph/scene/Undo1.vue
  10. 1 7
      docs/.vuepress/enhanceApp.js
  11. 1 1
      docs/dev/data-center/index.js
  12. 11 11
      docs/dev/data-center/relations/belongs/Bd2Sp.md
  13. 5 5
      docs/dev/data-center/relations/belongs/Eq2Bd.md
  14. 16 9
      docs/dev/data-center/relations/belongs/Eq2Fl.md
  15. 7 6
      docs/dev/data-center/relations/belongs/Eq2Sh.md
  16. 26 18
      docs/dev/data-center/relations/belongs/Eq2Sp.md
  17. 6 7
      docs/dev/data-center/relations/belongs/Fl2Fl.md
  18. 3 3
      docs/dev/data-center/relations/belongs/Pe2Bd.md
  19. 2 2
      docs/dev/data-center/relations/belongs/Pe2Fl.md
  20. 1 1
      docs/dev/data-center/relations/belongs/Pe2Sh.md
  21. 1 1
      docs/dev/data-center/relations/belongs/Pe2Sp.md
  22. 3 3
      docs/dev/data-center/relations/belongs/Sh2Bd.md
  23. 3 2
      docs/dev/data-center/relations/belongs/Sh2Sh.md
  24. 11 5
      docs/dev/data-center/relations/belongs/Sp2Fl.md
  25. 5 5
      docs/dev/data-center/relations/belongs/Sp2Sp.md
  26. 294 29
      docs/dev/data-center/relations/belongs/Sp2Sp2.md
  27. 1 1
      docs/dev/data-center/relations/belongs/Sy2Bd.md
  28. 1 1
      docs/dev/data-center/relations/belongs/Sy2Fl.md
  29. 1 1
      docs/dev/data-center/relations/belongs/Sy2Sh.md
  30. 1 1
      docs/dev/data-center/relations/belongs/Sy2Sp.md
  31. 3 3
      docs/dev/data-center/relations/belongs/f_rel_calc.md
  32. BIN
      docs/dev/data-center/relations/belongs/img/sp2sp2-1.PNG
  33. 1 1
      docs/dev/data-center/relations/other/calc_area_v3.md
  34. 5 5
      docs/dev/data-center/relations/other/calc_vertically_overlap.md
  35. 1 1
      docs/dev/data-center/relations/other/other_ispace_floor_overlap.md
  36. 1 1
      docs/dev/data-center/relations/other/rel_affected_space.md
  37. 1 1
      docs/dev/data-center/relations/other/rel_str_similar.md
  38. 1 1
      docs/dev/data-center/relations/topology/sys_block.md
  39. 1 1
      docs/dev/data-center/relations/topology/sys_direction.md
  40. 7 1
      docs/dev/saga-graphy/graphy-engine/draw.md
  41. 6 1
      docs/dev/saga-graphy/index.js
  42. 17 0
      docs/dev/saga-graphy/scene-manage/items/edit-polygon.md
  43. 17 0
      docs/dev/saga-graphy/scene-manage/items/editLine.md
  44. 10 0
      docs/dev/saga-graphy/scene-manage/items/image.md
  45. 6 0
      docs/dev/saga-graphy/scene-manage/items/imgText.md
  46. 10 0
      docs/dev/saga-graphy/scene-manage/items/text.md
  47. 103 0
      docs/dev/saga-graphy/system-diagram/json-file.md
  48. 6 3
      package.json
  49. 13 16
      publish.js
  50. 1 1
      tsconfig.json

+ 74 - 0
docs/.vuepress/components/example/web/graph/Circle1.vue

@@ -0,0 +1,74 @@
+import {SLineCapStyle} from "@saga-web/draw/lib";
+<template>
+    <canvas id="circle" width="740" height="250" />
+</template>
+
+<script lang="ts">
+    import {SCanvasView, SColor, SPainter, SRect, SLineCapStyle} from "@saga-web/draw/lib";
+
+    class TestView extends SCanvasView {
+
+        constructor() {
+            super("circle")
+        }
+
+        onDraw(canvas: SPainter): void {
+            canvas.clearRect(new SRect(0,0,800,400));
+
+            canvas.pen.color = SColor.Blue;
+            canvas.brush.color = SColor.Red;
+            canvas.drawCircle(100,100,50);
+
+            canvas.pen.lineWidth = 10;
+            canvas.pen.lineDash = [10,11];
+            canvas.pen.lineCapStyle = SLineCapStyle.Butt;
+            canvas.pen.color = new SColor("#585858");
+            canvas.brush.color = new SColor("#585858");
+
+            canvas.pen.dashOffset = new Date().getTime()/50%60;
+            canvas.drawCircle(230,100,40);
+
+            canvas.pen.dashOffset = -new Date().getTime()/50%60;
+            canvas.drawCircle(315,100,40);
+
+            canvas.pen.color = SColor.Transparent;
+            canvas.brush.color = SColor.White;
+            canvas.drawCircle(230,100,15);
+            canvas.drawCircle(315,100,15);
+
+            canvas.pen.color = SColor.Red;
+            for (let i = 0; i < 360; i += 10) {
+                let q1 = i * Math.PI / 180;
+                let q2 = (i + 120) * Math.PI / 180;
+                canvas.drawLine(
+                    450 + 50 * Math.cos(q1),
+                    100 + 50 * Math.sin(q1),
+                    450 + 50 * Math.cos(q2),
+                    100 + 50 * Math.sin(q2));
+            }
+
+            canvas.pen.color = SColor.Blue;
+            for (let i = 0; i < 360; i += 10) {
+                let q = i * Math.PI / 180;
+                canvas.drawLine(
+                    650,
+                    100,
+                    650 + 50 * Math.cos(q),
+                    100 + 50 * Math.sin(q));
+            }
+
+            this.update();
+        }
+    }
+
+    export default {
+        name: "Circle1",
+        mounted(): void {
+            new TestView();
+        }
+    }
+</script>
+
+<style scoped>
+
+</style>

+ 30 - 3
docs/.vuepress/components/example/web/graph/DrawLine1.vue

@@ -19,9 +19,36 @@
             canvas.drawLine(0,0, 100, 100);
 
             canvas.pen.lineWidth = 1;
-            canvas.pen.dashOffset = new Date().getTime()/50%60;
-            canvas.pen.lineDash = [10,50];
-            canvas.drawLine(200, 50, 400, 50);
+
+            canvas.pen.color = SColor.Blue;
+            for (let i = 0; i < 360; i += 10) {
+                let q = i * Math.PI / 180;
+                canvas.drawLine(
+                    200,
+                    50,
+                    200 + 50 * Math.cos(q),
+                    50 + 50 * Math.sin(q));
+            }
+
+            canvas.pen.color = SColor.Red;
+            for (let i = 0; i < 360; i += 10) {
+                let q1 = i * Math.PI / 180;
+                let q2 = (i + 120) * Math.PI / 180;
+                canvas.drawLine(
+                    350 + 50 * Math.cos(q1),
+                    50 + 50 * Math.sin(q1),
+                    350 + 50 * Math.cos(q2),
+                    50 + 50 * Math.sin(q2));
+            }
+
+            canvas.pen.color = new SColor('#03a9f4');
+            canvas.pen.lineWidth = 5;
+            canvas.drawLine(450, 50, 700, 50);
+            canvas.pen.lineWidth = 3;
+            canvas.pen.dashOffset = new Date().getTime()/50%80;
+            canvas.pen.lineDash = [30,50];
+            canvas.pen.color = SColor.White;
+            canvas.drawLine(450, 50, 700, 50);
             this.update();
         }
     }

+ 6 - 6
docs/.vuepress/components/example/web/graph/scene/ClockItem.vue

@@ -4,9 +4,9 @@
 
 <script lang="ts">
     import { SColor, SPainter, SRect } from "@saga-web/draw";
-    import { SGraphyItem, SGraphyScene, SGraphyView } from "@saga-web/graphy";
+    import { SGraphItem, SGraphScene, SGraphView } from "@saga-web/graph";
 
-    class ClockItem extends SGraphyItem {
+    class ClockItem extends SGraphItem {
         /** 宽度 */
         width = 100;
         /** 高度 */
@@ -24,7 +24,7 @@
          * @param   width       宽度
          * @param   height      高度
          */
-        constructor(parent: SGraphyItem | null, width: number, height: number) {
+        constructor(parent: SGraphItem | null, width: number, height: number) {
             super(parent);
             this.width = width;
             this.height = height;
@@ -171,12 +171,12 @@
         }
     }
 
-    class TestView extends SGraphyView {
+    class TestView extends SGraphView {
         clock1 = new ClockItem(null, 300, 300);
 
         constructor() {
             super("clockItem1");
-            this.scene = new SGraphyScene();
+            this.scene = new SGraphScene();
             this.scene.addItem(this.clock1);
         }
     }
@@ -190,4 +190,4 @@
 
 <style scoped>
 
-</style>
+</style>

+ 62 - 0
docs/.vuepress/components/example/web/graph/scene/ImageItem.vue

@@ -0,0 +1,62 @@
+<template>
+    <div>
+        <el-row>
+            <el-button @click="Full">铺满</el-button>
+            <el-button @click="Equivalency">等比缩放</el-button>
+            <el-button @click="AutoFit">自适应</el-button>
+        </el-row>
+        <canvas id="ImageItem1" width="740" height="400"/>
+    </div>
+</template>
+
+<script lang="ts">
+    import { SGraphScene, SGraphView } from "@saga-web/graph";
+    import { SImageItem } from "@saga-web/big/lib";
+    import { SImageShowType } from "@saga-web/big/lib/enums/SImageShowType";
+
+    class SScene extends SGraphScene {
+        imageItem: SImageItem = new SImageItem(null);
+        constructor() {
+            super();
+            this.imageItem.moveable = true;
+            this.imageItem.width = 400;
+            this.imageItem.height = 300;
+            this.imageItem.url = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1591685374103&di=cd5a56b2e3f5e12d7145b967afbcfb7a&imgtype=0&src=http%3A%2F%2Fcdn.duitang.com%2Fuploads%2Fitem%2F201408%2F05%2F20140805191039_cuTPn.jpeg";
+            this.addItem(this.imageItem);
+        }
+    }
+
+    class ImageView extends SGraphView {
+        constructor() {
+            super("ImageItem1");
+        }
+    }
+
+    export default {
+        mounted(): void {
+            let view = new ImageView();
+            view.scene = this.scene;
+            view.fitSceneToView();
+        },
+        data() {
+            return {
+                scene: new SScene(),
+            }
+        },
+        methods: {
+            Full() {
+                this.scene.imageItem.showType = SImageShowType.Full;
+            },
+            Equivalency() {
+                this.scene.imageItem.showType = SImageShowType.Equivalency;
+            },
+            AutoFit() {
+                this.scene.imageItem.showType = SImageShowType.AutoFit;
+            },
+        }
+    }
+</script>
+
+<style scoped>
+
+</style>

+ 253 - 0
docs/.vuepress/components/example/web/graph/scene/SEditLine.vue

@@ -0,0 +1,253 @@
+<template>
+    <div>
+        <el-button @click="show">展示</el-button>
+        <el-button @click="create">创建</el-button>
+        <el-button @click="edit">编辑</el-button>
+        <canvas id="editLine" width="740" height="400"  tabindex="0" />
+    </div>
+</template>
+<script lang='ts'>
+    import {SGraphItem, SGraphScene, SGraphView} from "@saga-web/graph/";
+    import {SMouseEvent} from "@saga-web/base/";
+    import {SColor, SLine, SPainter, SPoint, SRect} from "@saga-web/draw";
+    import {SRelationState} from "@saga-web/big/lib/enums/SRelationState";
+    import {SMathUtil} from "@saga-web/big/lib/utils/SMathUtil";
+
+    /**
+     * 直线item
+     *
+     * */
+
+    class SLineItem extends SGraphItem {
+        /** 线段   */
+        line: SPoint[] = [];
+        /** 是否完成绘制  */
+        _status: SRelationState = SRelationState.Create;
+        get status(): SRelationState {
+            return this._status;
+        }
+        set status(v: SRelationState) {
+            this._status = v;
+            this.update();
+        }
+        /** 线条颜色    */
+        _strokeColor: string = "#000000";
+        get strokeColor(): string {
+            return this._strokeColor;
+        }
+        set strokeColor(v: string) {
+            this._strokeColor = v;
+            this.update();
+        }
+        /** 填充色 */
+        _fillColor: string = "#2196f3";
+        get fillColor(): string {
+            return this._fillColor;
+        }
+        set fillColor(v: string) {
+            this._fillColor = v;
+            this.update();
+        }
+        /** 线条宽度    */
+        _lineWidth: number = 1;
+        get lineWidth(): number {
+            return this._lineWidth;
+        }
+        set lineWidth(v: number) {
+            this._lineWidth = v;
+            this.update();
+        }
+        /** 拖动灵敏度   */
+        dis: number = 10;
+        /** 拖动灵敏度   */
+        sceneDis: number = 10;
+
+        /**
+         * 构造函数
+         *
+         * @param   parent  父级
+         * @param   line    坐标集合
+         * */
+        constructor(parent: SGraphItem | null, line: SPoint[]);
+
+        /**
+         * 构造函数
+         *
+         * @param   parent  父级
+         * @param   point   第一个点坐标
+         * */
+        constructor(parent: SGraphItem | null, point: SPoint);
+
+        /**
+         * 构造函数
+         *
+         * @param   parent  父级
+         * @param   l       坐标集合|第一个点坐标
+         * */
+        constructor(parent: SGraphItem | null, l: SPoint | SPoint[]) {
+            super(parent);
+            if (l instanceof SPoint) {
+                this.line.push(l);
+            } else {
+                this.line = l;
+            }
+        }
+
+        /**
+         * 鼠标按下事件
+         *
+         * @param   event   鼠标事件
+         * @return  是否处理事件
+         * */
+        onMouseDown(event: SMouseEvent): boolean {
+            console.log(this);
+            if (this.status == SRelationState.Normal) {
+                return super.onMouseDown(event);
+            } else if (this.status == SRelationState.Edit) {
+            } else if (this.status == SRelationState.Create) {
+
+            }
+            this.$emit("mousedown");
+            return true;
+        } // Function onMouseDown()
+
+        /**
+         * 鼠标移动事件
+         *
+         * @param   event   鼠标事件
+         * @return  是否处理事件
+         * */
+        onMouseMove(event: SMouseEvent): boolean {
+            if (this.status == SRelationState.Create) {
+
+                return true;
+            } else {
+                return super.onMouseMove(event);
+            }
+        } // Function onMouseMove()
+
+        /**
+         * 鼠标移动事件
+         *
+         * @param   event   鼠标事件
+         * @return  是否处理事件
+         * */
+        onMouseUp(event: SMouseEvent): boolean {
+            // if (this.status == SRelationState.Create) {
+            //     this.status = SRelationState.Edit;
+            //     return true;
+            // } else {
+                return super.onMouseUp(event);
+            // }
+        } // Function onMouseUp()
+
+        /**
+         * 判断点是否在区域内
+         *
+         * @param   x
+         * @param   y
+         * @return  true-是
+         */
+        contains(x: number, y: number): boolean {
+            if (this.line.length == 2) {
+                let p = new SPoint(x, y);
+                if (
+                    SMathUtil.pointToLine(p, new SLine(this.line[0], this.line[1])).MinDis <
+                    this.dis
+                ) {
+                    return true;
+                }
+            }
+            return false;
+        } // Function contains()
+
+        /**
+         * Item对象边界区域
+         *
+         * @return	SRect
+         */
+        boundingRect(): SRect {
+            if (this.line.length == 2) {
+                let x: number = this.line[0].x > this.line[1].x ? this.line[1].x : this.line[0].x;
+                let y: number = this.line[0].x > this.line[1].x ? this.line[1].y : this.line[0].y;
+                let width: number = Math.abs(this.line[0].x - this.line[1].x);
+                let height: number = Math.abs(this.line[0].y - this.line[1].y);
+                return new SRect(
+                    x,
+                    y,
+                    width,
+                    height
+                );
+            } else {
+                return new SRect();
+            }
+        } // Function boundingRect()
+
+        /**
+         * Item绘制操作
+         *
+         * @param   painter painter对象
+         */
+        onDraw(painter: SPainter): void {
+            this.sceneDis = painter.toPx(this.dis);
+            painter.pen.lineWidth = painter.toPx(this.lineWidth);
+            painter.pen.color = new SColor(this.strokeColor);
+            if (this.p1 instanceof SPoint && this.p2 instanceof SPoint) {
+                // 绘制外轮廓
+                painter.brush.color = SColor.Transparent;
+                painter.pen.color = new SColor("#128eee");
+                painter.drawRect(this.boundingRect());
+
+                // 绘制基本图形
+                painter.pen.color = new SColor(this.strokeColor);// 需注释
+                painter.drawLine(this.p1, this.p2);
+
+                // 编辑态
+                if (this.status == SRelationState.Edit) {
+                    painter.brush.color = SColor.White;
+
+                    // painter.brush.color = new SColor(this.fillColor);
+
+                    painter.drawCircle(this.p1.x, this.p1.y, painter.toPx(5));
+
+                    painter.drawCircle(this.p2.x, this.p2.y, painter.toPx(5));
+                }
+            }
+        } // Function onDraw()
+    } // Class SLineItem
+
+    export default {
+        data() {
+            return {
+                scene: null,
+                view: null
+            };
+        },
+        mounted(): void {
+            this.view = new SGraphView("editLine");
+        },
+        methods: {
+            show() {
+                const scene = new SGraphScene();
+                this.view.scene = scene;
+                const line: SPoint[] = [new SPoint(100, 100), new SPoint(300, 300)];
+                const lineItem = new SLineItem(null, line);
+                lineItem.status = SRelationState.Normal;
+                scene.addItem(lineItem);
+                this.view.fitSceneToView();
+            },
+            create() {
+                const scene = new SGraphScene();
+                this.view.scene = scene;
+                const lineItem = new SLineItem(null, [] );
+                lineItem.status = SRelationState.Create;
+                scene.addItem(lineItem);
+                scene.grabItem = lineItem;
+                this.view.fitSceneToView();
+            },
+            edit() {
+
+            }
+        }
+    };
+</script>

+ 568 - 0
docs/.vuepress/components/example/web/graph/scene/SEditPolygon.vue

@@ -0,0 +1,568 @@
+<template>
+  <div>
+    <el-button @click="show">展示</el-button>
+    <el-button @click="create">创建</el-button>
+    <el-button @click="edit">编辑</el-button>
+    <canvas id="editPolygon" width="800" height="400"  tabindex="0" />
+  </div>
+</template>
+<script lang='ts'>
+import { SGraphItem, SGraphView, SGraphScene } from "@saga-web/graph/";
+import { SMouseEvent } from "@saga-web/base/";
+import {
+  SColor,
+  SLineCapStyle,
+  SPainter,
+  SPath2D,
+  SPoint,
+  SPolygonUtil,
+  SRect,
+  SLine
+} from "@saga-web/draw";
+import { SRelationState } from "@saga-web/big/lib/enums/SRelationState";
+import { SMathUtil } from "@saga-web/big/lib/utils/SMathUtil";
+
+export default {
+  data() {
+    return {
+      scene: null,
+      view: null
+    };
+  },
+  mounted(): void {
+    this.view = new SGraphView("editPolygon");
+  },
+  methods: {
+    show() {
+      const scene = new SGraphScene();
+      this.view.scene = scene;
+      const spolygonItem = new SPolygonItem(null);
+      spolygonItem.setStatus = SRelationState.Normal;
+      const PointList: SPoint[] = [
+        new SPoint(0, 0),
+        new SPoint(50, 0),
+        new SPoint(50, 50),
+        new SPoint(0, 50)
+      ];
+      spolygonItem.setPointList = PointList;
+      scene.addItem(spolygonItem);
+      this.view.fitSceneToView();
+    },
+    create() {
+      const scene = new SGraphScene();
+      this.view.scene = scene;
+      const spolygonItem = new SPolygonItem(null);
+      spolygonItem.setStatus = SRelationState.Create;
+      scene.addItem(spolygonItem);
+      scene.grabItem = spolygonItem;
+      this.view.fitSceneToView();
+    },
+    edit() {
+      const scene = new SGraphScene();
+      this.view.scene = scene;
+      const spolygonItem = new SPolygonItem(null);
+      spolygonItem.setStatus = SRelationState.Edit;
+      const PointList: SPoint[] = [
+        new SPoint(0, 0),
+        new SPoint(50, 0),
+        new SPoint(50, 60),
+        new SPoint(0, 50)
+      ];
+      spolygonItem.setPointList = PointList;
+      scene.addItem(spolygonItem);
+      scene.grabItem = spolygonItem;
+      this.view.fitSceneToView();
+    }
+  }
+};
+
+/**
+ * @author hanyaolong
+ */
+
+class SPolygonItem extends SGraphItem {
+  /** X坐标最小值  */
+  private minX = Number.MAX_SAFE_INTEGER;
+  /** X坐标最大值  */
+  private maxX = Number.MIN_SAFE_INTEGER;
+  /** Y坐标最小值  */
+  private minY = Number.MAX_SAFE_INTEGER;
+  /** Y坐标最大值  */
+  private maxY = Number.MIN_SAFE_INTEGER;
+  /** 轮廓线坐标  */
+  private pointList: SPoint[] = [];
+  // 获取当前状态
+  get getPointList(): SPoint[] {
+    return this.pointList;
+  }
+  // 编辑当前状态
+  set setPointList(arr: SPoint[]) {
+    this.pointList = arr;
+    if (arr) {
+      this._xyzListToSPointList(arr);
+    }
+    this.update();
+  }
+  /** 是否闭合    */
+  closeFlag: boolean = false;
+  // 当前状态 1:show 2 创建中,3 编辑中
+  _status: number = SRelationState.Normal;
+  // 获取当前状态
+  get getStatus(): number {
+    return this._status;
+  }
+  // 编辑当前状态
+  set setStatus(value: number) {
+    this._status = value;
+    this.update();
+  }
+  /** 边框颜色 */
+  borderColor: SColor = new SColor("#0091FF");
+  /** 填充颜色 */
+  brushColor: SColor = new SColor("#1EE887");
+  /** border宽 只可输入像素宽*/
+  borderLine: number = 4;
+  /** 鼠标移动点  */
+  private lastPoint = new SPoint();
+  /** 当前鼠标获取顶点对应索引 */
+  private curIndex: number = -1;
+  /** 灵敏像素 */
+  private len: number = 15;
+  /** 场景像素  */
+  private scenceLen: number = 15;
+  /** 场景像素  */
+  private isAlt: boolean = false;
+
+  /**
+   * 构造函数
+   *
+   * @param parent    指向父对象
+   */
+
+  constructor(parent: SGraphItem | null) {
+    super(parent);
+  }
+
+  ///////////////以下为对pointList 数组的操作方法
+
+  /**
+   * 储存新的多边形顶点
+   * @param x   点位得x坐标
+   * @param y   点位得y坐标
+   * @param i   储存所在索引
+   * @return SPoint
+   */
+
+  insertPoint(x: number, y: number, i: number | null = null): SPoint {
+    const point = new SPoint(x, y);
+    if (i == null) {
+      this.pointList.push(point);
+    } else {
+      this.pointList.splice(i, 0, point);
+    }
+    this.update();
+    return point;
+  }
+
+  /**
+   * 删除点位
+   * @param i   删除点所在的索引
+   * @return SPoint
+   */
+
+  deletePoint(i: number | null = null): SPoint | null | undefined {
+    let point = null;
+    if (i != null) {
+      if (this.pointList.length - 1 >= i) {
+        point = this.pointList[i];
+        this.pointList.splice(i, 1);
+      } else {
+        point = null;
+      }
+    } else {
+      point = this.pointList.pop();
+    }
+    this.update();
+    return point;
+  }
+
+  /**
+   * 多边形顶点的移动位置
+   * @param x   点位得x坐标
+   * @param y   点位得y坐标
+   * @param i   点位得i坐标
+   * @return SPoint
+   */
+
+  movePoint(x: number, y: number, i: number): SPoint | null | undefined {
+    let point = null;
+    if (this.pointList.length) {
+      this.pointList[i].x = x;
+      this.pointList[i].y = y;
+    }
+    point = this.pointList[i];
+    return point;
+  }
+
+  /**
+   * 打印出多边形数组
+   * @return SPoint[]
+   */
+
+  PrintPointList(): SPoint[] {
+    return this.pointList;
+  }
+
+  ///////////////////////////
+
+  /**
+   * xyz数据转换为SPoint格式函数;获取外接矩阵参数
+   *
+   * @param arr    外层传入的数据PointList
+   */
+
+  protected _xyzListToSPointList(arr: SPoint[]): void {
+    if (arr.length) {
+      this.pointList = arr.map(it => {
+        let x = it.x,
+          y = it.y;
+        if (x < this.minX) {
+          this.minX = x;
+        }
+        if (y < this.minY) {
+          this.minY = y;
+        }
+        if (x > this.maxX) {
+          this.maxX = x;
+        }
+        if (y > this.maxY) {
+          this.maxY = y;
+        }
+        return new SPoint(x, y);
+      });
+    } else {
+      this.pointList = [];
+    }
+  }
+
+  ////////////以下为三种状态下的绘制多边形方法
+
+  /**
+   * 展示状态 --绘制多边形数组
+   * @param painter    绘制类
+   * @param pointList    绘制多边形数组
+   *
+   */
+
+  protected drawShowPolygon(painter: SPainter, pointList: SPoint[]): void {
+    painter.pen.lineCapStyle = SLineCapStyle.Square;
+    painter.pen.color = this.borderColor;
+    painter.pen.lineWidth = painter.toPx(this.borderLine);
+    painter.brush.color = this.brushColor;
+    painter.drawPolygon([...pointList]);
+  }
+
+  /**
+   *
+   * 创建状态 --绘制多边形数组
+   * @param painter    绘制类
+   * @param pointList    绘制多边形数组
+   *
+   */
+
+  protected drawCreatePolygon(painter: SPainter, pointList: SPoint[]): void {
+    painter.pen.lineCapStyle = SLineCapStyle.Square;
+    painter.pen.color = this.borderColor;
+    painter.pen.lineWidth = painter.toPx(4);
+    painter.drawPolyline(pointList);
+    if (this.lastPoint) {
+      painter.drawLine(pointList[pointList.length - 1], this.lastPoint);
+    }
+    painter.pen.color = SColor.Transparent;
+    painter.brush.color = this.brushColor;
+    painter.pen.lineWidth = painter.toPx(4);
+    painter.drawPolygon([...pointList, this.lastPoint]);
+  }
+
+  /**
+   *
+   * 编辑状态 --绘制多边形数组
+   *
+   * @param painter    绘制类
+   * @param pointList    绘制多边形数组
+   *
+   * */
+
+  protected drawEditPolygon(painter: SPainter, pointList: SPoint[]): void {
+    // 展示多边形
+    this.drawShowPolygon(painter, pointList);
+    // 绘制顶点块
+    pointList.forEach((item, index) => {
+      painter.drawCircle(item.x, item.y, painter.toPx(8));
+    });
+  }
+
+  ////////////////////////////////
+
+  /**
+   * 编辑状态操作多边形数组
+   *
+   * @param event    鼠标事件
+   *
+   *
+   * */
+
+  protected editPolygonPoint(event: SMouseEvent): void {
+    //  判断是否为删除状态 isAlt = true为删除状态
+    if (this.isAlt) {
+      // 1 判断是否点击在多边形顶点
+      let lenIndex = -1; // 当前点击到的点位索引;
+      let curenLen = this.scenceLen; // 当前的灵敏度
+      this.pointList.forEach((item, index) => {
+        let dis = SMathUtil.pointDistance(event.x, event.y, item.x, item.y);
+        if (dis < curenLen) {
+          curenLen = dis;
+          lenIndex = index;
+        }
+      });
+      // 若点击到,对该索引对应的点做删除
+      if (lenIndex != -1) {
+        if (this.pointList.length <= 3) {
+          return;
+        }
+        this.deletePoint(lenIndex);
+      }
+    } else {
+      // 1 判断是否点击在多边形顶点
+      this.curIndex = -1;
+      let lenIndex = -1; // 当前点击到的点位索引;
+      let curenLen = this.scenceLen; // 当前的灵敏度
+      this.pointList.forEach((item, index) => {
+        let dis = SMathUtil.pointDistance(event.x, event.y, item.x, item.y);
+        if (dis < curenLen) {
+          curenLen = dis;
+          lenIndex = index;
+        }
+      });
+      this.curIndex = lenIndex;
+
+      // 2判断是否点击在多边形得边上
+      if (-1 == lenIndex) {
+        let len = SMathUtil.pointToLine(
+            new SPoint(event.x, event.y),
+            new SLine(this.pointList[0], this.pointList[1])
+          ),
+          index = 0;
+        if (this.pointList.length > 2) {
+          for (let i = 1; i < this.pointList.length; i++) {
+            let dis = SMathUtil.pointToLine(
+              new SPoint(event.x, event.y),
+              new SLine(this.pointList[i], this.pointList[i + 1])
+            );
+            if (i + 1 == this.pointList.length) {
+              dis = SMathUtil.pointToLine(
+                new SPoint(event.x, event.y),
+                new SLine(this.pointList[i], this.pointList[0])
+              );
+            }
+            if (dis.MinDis < len.MinDis) {
+              len = dis;
+              index = i;
+            }
+          }
+        }
+        // 如果再线上则为新增点
+        if (len.Point) {
+          if (len.MinDis <= this.scenceLen) {
+            this.pointList.splice(index + 1, 0, len.Point);
+          }
+        }
+      }
+      // 刷新视图
+      this.update();
+    }
+  }
+
+  ///////////////////////////////以下为鼠标事件
+
+  /**
+   * 鼠标双击事件
+   *
+   * @param	event         事件参数
+   * @return	boolean
+   */
+
+  onDoubleClick(event: SMouseEvent): boolean {
+    // 如果位show状态 双击改对象则需改为编辑状态
+    if (SRelationState.Normal == this._status) {
+      this._status = SRelationState.Edit;
+    } else if (SRelationState.Edit == this._status) {
+      this._status = SRelationState.Normal;
+    }
+    this.update();
+    return true;
+  } // Function onDoubleClick()
+
+  /**
+   * 键盘事件
+   *
+   * @param	event         事件参数
+   * @return	boolean
+   */
+
+  onKeyDown(event: KeyboardEvent): boolean {
+    console.log(event);
+    if (this._status == SRelationState.Normal) {
+      return false;
+    } else if (this._status == SRelationState.Create) {
+      if (event.code == "Enter") {
+        this._status = SRelationState.Normal;
+      }
+    } else if (this._status == SRelationState.Edit) {
+      if (event.key == "Alt") {
+        this.isAlt = true;
+      }
+    } else {
+    }
+    this.update();
+    return true;
+  } // Function onKeyDown()
+
+  /**
+   * 键盘键抬起事件
+   *
+   * @param	event         事件参数
+   * @return	boolean
+   */
+  onKeyUp(event: KeyboardEvent): boolean {
+    if (this._status == SRelationState.Edit) {
+      if (event.key == "Alt") {
+        this.isAlt = false;
+      }
+    }
+    this.update();
+    return true;
+  } // Function onKeyUp()
+
+  /**
+   * 鼠标按下事件
+   *
+   * @param	event         事件参数
+   * @return	boolean
+   */
+  onMouseDown(event: SMouseEvent): boolean {
+    console.log("aaaaaa");
+    // 如果状态为编辑状态则添加点
+    if (this._status == SRelationState.Create) {
+      // 新增顶点
+      this.insertPoint(event.x, event.y);
+    } else if (this._status == SRelationState.Edit) {
+      // 对多边形数组做编辑操作
+      this.editPolygonPoint(event);
+    }
+    return true;
+  } // Function onMouseDown()
+
+  /**
+   * 鼠标移入事件
+   *
+   * @param	event         事件参数
+   * @return	boolean
+   */
+  onMouseEnter(event: SMouseEvent): boolean {
+    return true;
+  } // Function onMouseEnter()
+
+  /**
+   * 鼠标移出事件
+   *
+   * @param	event         事件参数
+   * @return	boolean
+   */
+
+  onMouseLeave(event: SMouseEvent): boolean {
+    return true;
+  } // Function onMouseLeave()
+
+  /**
+   * 鼠标移动事件
+   *
+   * @param	event         事件参数
+   * @return	boolean
+   */
+
+  onMouseMove(event: SMouseEvent): boolean {
+    if (this._status == SRelationState.Create) {
+      this.lastPoint.x = event.x;
+      this.lastPoint.y = event.y;
+    } else if (this._status == SRelationState.Edit) {
+      if (-1 != this.curIndex) {
+        this.pointList[this.curIndex].x = event.x;
+        this.pointList[this.curIndex].y = event.y;
+      }
+    }
+    this.update();
+    return true;
+  } // Function onMouseMove()
+
+  /**
+   * 鼠标抬起事件
+   *
+   * @param	event         事件参数
+   * @return	boolean
+   */
+
+  onMouseUp(event: SMouseEvent): boolean {
+    if (this._status == SRelationState.Edit) {
+      this.curIndex = -1;
+    }
+    return true;
+  } // Function onMouseUp()
+
+  /**
+   * 适配事件
+   *
+   * @param	event         事件参数
+   * @return	boolean
+   */
+
+  onResize(event: SMouseEvent): boolean {
+    return true;
+  } // Function onResize()
+
+  /**
+   * Item对象边界区域
+   *
+   * @return SRect
+   */
+  boundingRect(): SRect {
+    return new SRect(
+      this.minX,
+      this.minY,
+      this.maxX - this.minX,
+      this.maxY - this.minY
+    );
+  } // Function boundingRect()
+
+  /**
+   * Item绘制操作
+   *
+   * @param   painter       painter对象
+   */
+
+  onDraw(painter: SPainter): void {
+    this.scenceLen = painter.toPx(this.len);
+    // 当状态为展示状态
+    if (this._status == SRelationState.Normal) {
+      // 闭合多边形
+      this.drawShowPolygon(painter, this.pointList);
+    } else if (this._status == SRelationState.Create) {
+      // 创建状态
+      this.drawCreatePolygon(painter, this.pointList);
+    } else {
+      // 编辑状态
+      this.drawEditPolygon(painter, this.pointList);
+    }
+  } // Function onDraw()
+}
+</script>

+ 231 - 0
docs/.vuepress/components/example/web/graph/scene/SImgTextItem.vue

@@ -0,0 +1,231 @@
+<template>
+    <div>
+        <el-button @click="changemaodian">切换锚点显示状态</el-button>
+        <el-button @click="changetext">切换文本显示状态</el-button>
+        <canvas id="editPolygon" width="740" height="400" tabindex="0"></canvas>
+    </div>
+</template>
+
+<script lang="ts">
+    import {SGraphItem, SGraphScene, SGraphView} from "@saga-web/graph/lib";
+    import {SAnchorItem, SImageItem, SItemStatus, SObjectItem, STextItem} from "@saga-web/big/lib";
+    import {SColor, SPainter, SRect, SSize, STextBaseLine} from "@saga-web/draw/lib";
+    import {SMouseEvent} from "@saga-web/base/lib";
+
+    /**
+     * 图例item  icon
+     *
+     * */
+    class SImgTextItem extends SObjectItem {
+
+        /** item状态  */
+        _status: SItemStatus = SItemStatus.Normal;
+        get status(): SItemStatus {
+            return this._status;
+        }
+        set status(v: SItemStatus) {
+            this._status = v;
+            this.update();
+        }
+
+        /** 是否显示文字  */
+        _showText: boolean = true;
+        get showText(): boolean {
+            return this._showText;
+        }
+        set showText(v: boolean) {
+            if (v === this._showText) {
+                return
+            }
+            this._showText = v;
+            this.textItem.visible = v;
+        }
+
+        /** 是否显示锚点  */
+        _showAnchor: boolean = false;
+        get showAnchor():boolean{
+            return this._showAnchor;
+        }
+        set showAnchor(v:boolean){
+            this._showAnchor = v;
+            this.anchorList.forEach(t => {
+                t.visible = v;
+            })
+        }
+
+        /** X轴坐标 */
+        get x(): number {
+            return this.pos.x;
+        } // Get x
+        set x(v: number) {
+            this.pos.x = v;
+            this.$emit("changePos");
+            this.update();
+        } // Set x
+        /** Y轴坐标 */
+        get y(): number {
+            return this.pos.y;
+        } // Get y
+        set y(v: number) {
+            this.pos.y = v;
+            this.$emit("changePos");
+            this.update();
+        } // Set y
+
+        /** img Item    */
+        img: SImageItem = new SImageItem(this);
+
+        /** text item   */
+        textItem: STextItem = new STextItem(this);
+
+        /**
+         * 构造体
+         *
+         * */
+        constructor(parent: SGraphItem | null) {
+            super(parent);
+            this.img.url = `http://adm.sagacloud.cn:8080/doc/assets/img/logo.png`;
+            this.img.width = 32;
+            this.img.height = 32;
+            let anchorPoint = [{ x: 0, y: this.img.height / 2 }, { x: 0, y: -this.img.height / 2 }, { x: -this.img.width / 2, y: 0 }, { x: this.img.width / 2, y: 0 }];
+            this.anchorList = anchorPoint.map(t => {
+                let item = new SAnchorItem(this);
+                item.moveTo(t.x, t.y);
+                return item;
+            });
+            this.update();
+            this.textItem.text = "请填写文本";
+            this.textItem.moveTo(16, -6);
+            this.moveable = true;
+            this.selectable = true;
+        }
+
+        onMouseEnter(event: SMouseEvent): boolean {
+            this.showAnchor = true;
+            return true;
+        }
+
+        onMouseLeave(event: SMouseEvent): boolean {
+            this.showAnchor = false;
+            return true;
+        }
+
+        onMouseMove(event: SMouseEvent): boolean {
+            return super.onMouseMove(event);
+        }
+
+        /**
+         * 鼠标按下事件
+         *
+         * */
+        onMouseDown(event: SMouseEvent): boolean {
+            if (this.status == SItemStatus.Normal) {
+                return super.onMouseDown(event);
+            } else if (this.status == SItemStatus.Edit) {
+                return super.onMouseDown(event);
+            }
+            return true;
+        } // Function onMouseDown()
+
+        /**
+         * 宽高发发生变化
+         *
+         * @param   oldSize 改之前的大小
+         * @param   newSize 改之后大小
+         * */
+        onResize(oldSize: SSize, newSize: SSize) {
+            console.log(arguments);
+        } // Function onResize()
+
+        /**
+         * 鼠标双击事件
+         *
+         * @param   event   鼠标事件
+         * @return  是否处理事件
+         * */
+        onDoubleClick(event: SMouseEvent): boolean {
+            console.log('doubleclick');
+            this.status = SItemStatus.Edit;
+            return true;
+        } // Function onDoubleClick()
+
+        /**
+         * 宽高发发生变化
+         *
+         * @return  SRect   所有子对象的并集
+         * */
+        boundingRect(): SRect {
+            let rect :SRect = new SRect();
+            this.children.forEach(t => {
+                if (rect.isNull()) {
+                    rect = t.boundingRect().adjusted(t.pos.x,t.pos.y,0,0);
+                } else {
+                    rect = rect.unioned(t.boundingRect().adjusted(t.pos.x,t.pos.y,0,0));
+                }
+            });
+            return rect;
+        } // Function boundingRect()
+
+        /**
+         * Item绘制操作
+         *
+         * @param   painter painter对象
+         */
+        onDraw(painter: SPainter): void {
+            painter.pen.lineWidth = painter.toPx(1);
+            painter.pen.color = new SColor("#00FF00");
+            painter.brush.color = SColor.Transparent;
+            if (this.showAnchor) {
+                painter.brush.color = SColor.Gray
+            }
+            painter.drawRect(this.boundingRect());
+            // super.onDraw(painter);
+        } // Function onDraw()
+    }
+
+
+    export default {
+        name: "ImgTextItem",
+        data() {
+            return {
+                scene: null,
+                view: null,
+                input:'',
+            };
+        },
+        mounted() {
+            console.log(22222222222222222)
+            this.view = new SGraphView("editPolygon");
+            this.scene = new SGraphScene();
+            this.view.scene = this.scene;
+            this.init()
+        },
+        methods:{
+            init(){
+                this.item = new SImgTextItem(null);
+                this.item.moveable = true;
+
+                this.scene.addItem(this.item);
+                // this.view.fitSceneToView();
+            },
+            change() {
+
+            },
+            changemaodian(){
+                this.item.showAnchor = !this.item.showAnchor;
+            },
+            changetext(){
+                this.item.showText = !this.item.showText;
+            }
+        }
+    }
+</script>
+
+<style scoped>
+    canvas{
+        border:1px solid #ccc;
+    }
+    canvas:focus{
+        outline: none;
+    }
+</style>

+ 119 - 0
docs/.vuepress/components/example/web/graph/scene/TextItem.vue

@@ -0,0 +1,119 @@
+<template>
+	<div>
+		<el-row>
+			<el-input v-model="text" @change="handleChangeText" type="textarea" :autosize="{ minRows: 1, maxRows: 1}" placeholder="请输入内容" style="width:200px;"></el-input>
+			<el-input-number v-model="size" @change="handleChangeSize" :min="1" label="字号"></el-input-number>
+			<el-color-picker v-model="color" @change="handleChangeColor" style="top: 15px;"></el-color-picker>
+			<el-button @click="undo">Undo</el-button>
+			<el-button @click="redo">Redo</el-button>
+			<el-button @click="reset">Reset</el-button>
+		</el-row>
+		<canvas id="TextItem1" width="740" height="400" tabindex="0"/>
+	</div>
+</template>
+
+<script lang="ts">
+	import { SUndoStack } from "@saga-web/base";
+    import { SFont } from "@saga-web/draw";
+	import { SGraphItem, SGraphScene, SGraphView, SGraphPropertyCommand, SGraphMoveCommand } from "@saga-web/graph";
+	import { SPoint } from "@saga-web/draw/lib";
+	import {STextItem} from "@saga-web/big/lib";
+
+	class SScene extends SGraphScene {
+		undoStack = new SUndoStack();
+		textItem: STextItem = new STextItem(null);
+
+		constructor() {
+			super();
+			this.textItem.moveable = true;
+			this.textItem.x = 100;
+			this.textItem.y = 100;
+			this.addItem(this.textItem);
+			this.textItem.connect("onMove", this, this.onItemMove.bind(this));
+		}
+
+		updateText(str: string): void {
+			if (this.textItem.text !== str) {
+				let old = this.textItem.text;
+				this.textItem.text = str;
+				this.undoStack.push(new SGraphPropertyCommand(this, this.textItem, "text", old, str));
+			}
+		}
+
+		updateColor(color: string): void {
+			if (this.textItem.color !== color) {
+				let old = this.textItem.color;
+				this.textItem.color = color;
+				this.undoStack.push(new SGraphPropertyCommand(this, this.textItem, "color", old, color));
+			}
+		}
+
+		updateSize(size: number): void {
+			if (this.textItem.font.size !== size) {
+				let old = new SFont(this.textItem.font);
+				let font = new SFont(this.textItem.font);
+				font.size = size;
+				this.textItem.font = font;
+				this.undoStack.push(new SGraphPropertyCommand(this, this.textItem, "font", old, font));
+			}
+		}
+
+		onItemMove(item: SGraphItem, ...arg: any): void {
+            this.undoStack.push(new SGraphMoveCommand(this, item, arg[0][0] as SPoint, arg[0][1] as SPoint));
+        }
+
+	}
+
+	class TestView extends SGraphView {
+        constructor() {
+			super("TextItem1");
+        }
+	}
+
+    export default {
+        mounted(): void {
+			let view = new TestView();
+			this.scene.updateText(this.text);
+			this.scene.updateColor(this.color);
+			this.scene.updateSize(this.size);
+			view.scene = this.scene;
+		},
+		data() {
+			return {
+				scene: new SScene(),
+				text: '测试文本',
+				size: 20,
+				color: "#333333",
+			}
+		},
+		methods: {
+			handleChangeText(text): void {
+				this.scene.updateText(this.text);
+			},
+			handleChangeColor(color): void {
+				this.scene.updateColor(color);
+			},
+			handleChangeSize(size): void {
+				this.scene.updateSize(size);
+			},
+			undo(): void {
+				this.scene.undoStack.undo();
+			},
+			redo(): void {
+				this.scene.undoStack.redo();
+			},
+			reset(): void {
+				this.text = "测试文本";
+				this.size = 20;
+				this.color = "#333333";
+				this.scene.updateText(this.text);
+				this.scene.updateColor(this.color);
+				this.scene.updateSize(this.size);
+			}
+		},
+    }
+</script>
+
+<style scoped>
+
+</style>

+ 27 - 30
docs/.vuepress/components/example/web/graph/scene/Undo1.vue

@@ -10,22 +10,18 @@
 </template>
 
 <script lang="ts">
-    import Vue from "vue";
-    import ElementUI from "element-ui";
     import { SMouseEvent, SUndoStack } from "@saga-web/base";
     import { SColor, SPainter, SRect } from "@saga-web/draw";
-    import { SGraphyItem, SGraphyScene, SGraphyView } from "@saga-web/graphy";
-    import {SGraphyCommand} from "@saga-web/graphy/lib";
+    import { SGraphItem, SGraphScene, SGraphView } from "@saga-web/graph";
+    import {SGraphCommand} from "@saga-web/graph/lib";
     import {SUndoCommand} from "@saga-web/base/lib";
     import {SPoint} from "@saga-web/draw/lib";
 
-    Vue.use(ElementUI);
-
-    class RectItem extends SGraphyItem {
+    class RectItem extends SGraphItem {
         width = 100;
         height = 100;
 
-        constructor(parent: SGraphyItem | null) {
+        constructor(parent: SGraphItem | null) {
             super(parent);
             this.moveable = true;
             this.selectable = true;
@@ -44,10 +40,10 @@
         }
     }
 
-    class CircleItem extends SGraphyItem {
+    class CircleItem extends SGraphItem {
         r = 50;
 
-        constructor(parent: SGraphyItem | null) {
+        constructor(parent: SGraphItem | null) {
             super(parent);
             this.moveable = true;
             this.selectable = true;
@@ -65,7 +61,7 @@
         }
     }
 
-    class SScene extends SGraphyScene {
+    class SScene extends SGraphScene {
         undoStack = new SUndoStack();
         /** 定义命令 */
         cmd = 0;
@@ -75,7 +71,7 @@
         }
 
 
-        onMouseUp(event: SMouseEvent): void {
+        onMouseUp(event: SMouseEvent): boolean {
             switch(this.cmd) {
                 case 1:
                     this.addCircle(event.x, event.y);
@@ -87,40 +83,41 @@
                     super.onMouseUp(event);
             }
             this.cmd = 0;
+            return false
         }
 
         private addCircle(x: number, y: number): void {
-            let item = new CircleItem();
+            let item = new CircleItem(null);
             item.moveTo(x - 50, y - 50);
             this.addItem(item);
-            this.undoStack.push(new SGraphyAddCommand(this, item));
+            this.undoStack.push(new SGraphAddCommand(this, item));
             item.connect("onMove", this, this.onItemMove.bind(this));
         }
 
         private addRect(x: number, y: number): void {
-            let item = new RectItem();
+            let item = new RectItem(null);
             item.moveTo(x - 50, y - 50);
             this.addItem(item);
-            this.undoStack.push(new SGraphyAddCommand(this, item));
+            this.undoStack.push(new SGraphAddCommand(this, item));
             item.connect("onMove", this, this.onItemMove.bind(this));
         }
 
-        onItemMove(item: SGraphyItem, ...arg: any): void {
-            this.undoStack.push(new SGraphyMoveCommand(this, item, arg[0][0] as SPoint, arg[0][1] as SPoint));
+        onItemMove(item: SGraphItem, ...arg: any): void {
+            this.undoStack.push(new SGraphMoveCommand(this, item, arg[0][0] as SPoint, arg[0][1] as SPoint));
         }
     }
 
-    class TestView extends SGraphyView {
+    class TestView extends SGraphView {
         constructor() {
             super("undoFrame");
         }
     }
 
-    class SGraphyAddCommand extends SGraphyCommand {
-        item: SGraphyItem;
-        parent: SGraphyItem | null;
+    class SGraphAddCommand extends SGraphCommand {
+        item: SGraphItem;
+        parent: SGraphItem | null;
 
-        constructor(scene: SGraphyScene, item: SGraphyItem) {
+        constructor(scene: SGraphScene, item: SGraphItem) {
             super(scene);
             this.item = item;
             this.parent = item.parent;
@@ -140,7 +137,7 @@
         }
     }
 
-    class SGraphyDeleteCommand extends SGraphyCommand {
+    class SGraphDeleteCommand extends SGraphCommand {
         mergeWith(command: SUndoCommand): boolean {
             return false;
         }
@@ -152,19 +149,19 @@
         }
     }
 
-    class SGraphyMoveCommand extends SGraphyCommand {
-        item: SGraphyItem;
+    class SGraphMoveCommand extends SGraphCommand {
+        item: SGraphItem;
         old: SPoint;
         pos: SPoint;
 
-        constructor(scene: SGraphyScene, item: SGraphyItem, old: SPoint, pos: SPoint) {
+        constructor(scene: SGraphScene, item: SGraphItem, old: SPoint, pos: SPoint) {
             super(scene);
             this.item = item;
             this.old = old;
             this.pos = pos;
         }
         mergeWith(command: SUndoCommand): boolean {
-            if (command instanceof  SGraphyMoveCommand && command.item == this.item) {
+            if (command instanceof  SGraphMoveCommand && command.item == this.item) {
                 command.pos = this.pos;
                 return true;
             }
@@ -185,7 +182,7 @@
     export default {
         data() {
             return {
-                scene: new SScene();
+                scene: new SScene(),
             }
         },
         mounted(): void {
@@ -215,4 +212,4 @@
 
 <style scoped>
 
-</style>
+</style>

+ 1 - 7
docs/.vuepress/enhanceApp.js

@@ -5,10 +5,4 @@ import Vue from 'vue'
 import Element from 'element-ui'
 import 'element-ui/lib/theme-chalk/index.css'
 
-export default ({
-        Vue,
-        options,
-        router
-    }) => {
-    Vue.use(Element)
-}
+Vue.use(Element);

+ 1 - 1
docs/dev/data-center/index.js

@@ -32,7 +32,7 @@ const content = [
             ["/dev/data-center/relations/belongs/Sh2Sh", "竖井贯通关系"],
             ["/dev/data-center/relations/belongs/Sp2Fl", "业务空间所属楼层"],
             ["/dev/data-center/relations/belongs/Sp2Sp", "业务空间邻接关系"],
-            ["/dev/data-center/relations/belongs/Sp2Sp_new", "业务空间邻接关系(新)"],
+            ["/dev/data-center/relations/belongs/Sp2Sp2", "业务空间邻接关系(新)"],
             ["/dev/data-center/relations/belongs/Sy2Bd", "系统所在建筑"],
             ["/dev/data-center/relations/belongs/Sy2Fl", "系统所在楼层"],
             ["/dev/data-center/relations/belongs/Sy2Sh", "系统所在竖井"],

+ 11 - 11
docs/dev/data-center/relations/belongs/Bd2Sp.md

@@ -1,25 +1,24 @@
-建筑下的业务空间
+# 建筑下的业务空间
 ## 前置条件
-有所属楼层的业务空间(所有业务空间表都需要处理)
+    1. 业务空间必须要有所属的楼层
 ```
 FROM zone_* WHERE project_id='Pj4201050001' AND floor_id is not null
 ```
-## 处理方式
+## 处理逻辑
 
-从绑定的楼层里取建筑ID,
-将建筑ID填入设备ID(建筑ID为空,则设备的建筑ID也为空)。
+    1. 从业务空间绑定的楼层信息里取到楼层所属的建筑ID,
+    2. 取到的建筑ID即是业务空间的所属建筑 (建筑ID为空,则的建筑ID也为空).
 
 ## 实现方式
 SQL
 ```
-update zone_air_conditioning zone set zone.building_id = floor.building_id from floor where zone.floor_id = floor.id and zone.project_id = 'Pj4201050001' and zone.floor_id is not null
+update zone_space_base zone set zone.building_id = floor.building_id from floor where zone.floor_id = floor.id and zone.project_id = 'Pj4201050001' and zone.floor_id is not null
 ```
 
 # 函数
 ```
-create or replace function public.rel_bd2sp(tables text, project_id character varying) returns boolean
-as
-$$
+CREATE OR REPLACE FUNCTION "public"."rel_bd2sp"("tables" text, "project_id" varchar)
+  RETURNS "pg_catalog"."bool" AS $BODY$
 try:
     list = tables.split(',')
     # 将下面对数据库的操作作为一个事务, 出异常则自动rollback
@@ -33,8 +32,9 @@ except Exception as e:
     return False
 else:
     return True
-$$
-LANGUAGE 'plpython3u' VOLATILE;
+$BODY$
+  LANGUAGE plpython3u VOLATILE
+  COST 100
 ```
 
 ## 输入

+ 5 - 5
docs/dev/data-center/relations/belongs/Eq2Bd.md

@@ -1,16 +1,16 @@
-设备所在建筑
+# 设备所在建筑
 ## 前置条件
-设备已经绑定楼层
+    1. 设备已经绑定楼层
 ```
 FROM equipment WHERE project_id='Pj4201050001' AND floor_id is not null
 ```
 
 ## 依赖函数
     Eq2Fl
-## 处理方式
+## 处理逻辑
 
-从绑定的楼层里取建筑ID,
-将建筑ID填入设备ID(建筑ID为空,则设备的建筑ID也为空)。
+    1. 设备绑定的楼层里取楼层所属的建筑ID,
+    2. 将取到的建筑ID填入设备的所属建筑中(建筑ID为空,则设备的所属建筑ID也为空)。
 
 ## 实现方式
 SQL

+ 16 - 9
docs/dev/data-center/relations/belongs/Eq2Fl.md

@@ -1,20 +1,26 @@
 设备所在楼层
 ## 前置条件
-    1. 设备有ModelId信息点
-    2. 楼层有ModelId信息点
-    3. 楼层的ModelId信息点等于设备的ModelId所属模型楼层的信息点
-    4. 设备没有所在楼层关系
-    5. 设备有Location(非必要)
-    6. 楼层有Outline(非必要)
+    1. 设备有ModelId信息点  (模型web服务的模型id)
+    2. 楼层有ModelId信息点  (模型web服务的楼层id)
+    3. 设备没有所在楼层关系
+    4. 设备有Location(非必要)
+    5. 楼层有Outline(非必要)
     
 
-## 处理方式
-    1. 如果楼层有Outline, 设备有Location, 做点(Location)在多边形(Outline)内的判断, 在多边形内则认为有关系
-    2. 如果不满足条件1, 则判断ModelId信息点的值, 相等则认为有关系
+## 处理逻辑
+    1. 如果楼层有Outline, 设备有Location, 做点(Location)在多边形(Outline)内的判断, 点在多边形内则认为有关系
+    2. 如果不满足条件1, 即楼层没有Outline, 设备没有Location, 则判断它们ModelId信息点的值, 相等则认为有关系   
+        (此处的相等表示设备上的ModelId信息点在关系上从属于楼层上的ModelId信息点, 即模型web服务中的模型id属于楼层id)
+
+## 技术细节
+    1. 做点在多边形内的判断, 使用到了python的 shapely 库 中的 Path 类的contains_points 方法
 
 # 函数
 
 ## 代码
+<details>
+<summary>源码</summary>
+
 ```
 -- 设备所在楼层
 CREATE OR REPLACE FUNCTION "public"."rel_eq2fl"("project_id" varchar)
@@ -101,6 +107,7 @@ $BODY$
 
 select public.rel_eq2fl('Pj1101010015');
 ```
+</details>
 
 ## 输入
     1. 项目id

+ 7 - 6
docs/dev/data-center/relations/belongs/Eq2Sh.md

@@ -1,13 +1,14 @@
-设备所在竖井关系计算
+# 设备所在竖井关系计算
 ## 前置条件
-    1. 首先需要有设备所在业务空间关系
-    2. 需要有竖井包含业务空间关系
+    1. 设备需要有所在业务空间关系
+    2. 竖井需要有包含业务空间关系
     
 ## 依赖函数
     Eq2Sp
-## 计算过程
-    1. 通过 竖井--> 业务空间 --> 设备的间接关系, 堆出竖井和设备的关系
-    2. 结果保存到r_eq_in_sh表中
+    
+## 处理逻辑
+    1. 通过 竖井 --> 业务空间 --> 设备 的间接所属关系, 推出竖井和设备的关系
+    
 ## 函数
 ```
 -- 设备所在竖井

+ 26 - 18
docs/dev/data-center/relations/belongs/Eq2Sp.md

@@ -1,21 +1,23 @@
-设备所在业务空间
+# 设备所在业务空间
 ## 前置条件
-    1. 业务空间有所属楼层
-    2. 设备有所属楼层
-    3. 业务空间有轮廓数据(outline)
-    4. 设备有坐标信息(bimLocation)
+    1. 业务空间有所属楼层关系
+    2. 设备有所属楼层关系
+    3. 业务空间有轮廓数据(outline信息点)
+    4. 设备有坐标信息(bimLocation信息点)
 ## 依赖函数
-    Eq2Fl
-## 处理方式
-    将在同一楼层内的设备和业务空间取出, 判断设备的bim_location是否在业务空间的outline内, 
-    如果在, 则添加进对应的关系表内, 控制sign = 2
+    Eq2Fl, Sp2Fl
+## 处理逻辑
+    1. 取出项目内的所有业务空间和设备, 将在同一楼层内的设备和业务空间分成一组
+    2. 在一组内, 判断设备的bim_location是否在业务空间的outline内, 即做点在多边形内的判断, 点在多边形内则认为有关系
 
 # 函数
 ## 代码
+<details>
+<summary>源码</summary>
+
 ```
-create or replace function public.rel_eq2sp(tables text, out_tables text, project_id character varying, sign1 integer, sign2 integer) returns boolean
-as
-$$
+CREATE OR REPLACE FUNCTION "public"."rel_eq2sp"("tables" text, "out_tables" text, "project_id" varchar, "sign1" int4, "sign2" int4)
+  RETURNS "pg_catalog"."bool" AS $BODY$
 from matplotlib.path import Path
 import json
 
@@ -80,8 +82,9 @@ with plpy.subtransaction():
             if len(equips) == 0:
                 continue
             # 获取楼层下的业务空间
-            space_plan = plpy.prepare("select id, outline from {0} as sp where project_id = $1 and outline is not null and floor_id = $2".format(in_table_name), ["text", "text"])
-            spaces = space_plan.execute([project_id, floor_id])
+
+            space_plan = plpy.prepare("select sp.id, sp.outline, sp.object_type from public.r_sp_in_fl rel inner join {0} sp on rel.space_id = sp.id where outline is not null and rel.floor_id = $1".format(in_table_name), ["text"])
+            spaces = space_plan.execute([floor_id])
             if len(spaces) == 0:
                 continue
             # 判断设备的bim_location是否在业务空间的outline内
@@ -91,18 +94,23 @@ with plpy.subtransaction():
                         location = equip['bim_location'].split(',')
                         if is_point_in_polygon(location[0], location[1], space['outline']):
                             # 设备在业务空间内, 添加关系
-                            insert_plan = plpy.prepare("insert into {0}(equip_id, space_id, project_id, sign) values($1, $2, $3, 2) ".format(out_table_name.strip()), ["text", "text", 'text'])
-                            insert_plan.execute([equip['id'], space['id'], project_id])
+                            insert_plan = plpy.prepare("insert into {0}(eq_id, sp_id, project_id, sign, type, zone_type) values($1, $2, $3, 2, 'eq2sp_in', $4)".format(out_table_name.strip()), ["text", "text", "text", "text"])
+                            insert_plan.execute([equip['id'], space['id'], project_id, space['object_type']])
                     except Exception as ex:
+                        plpy.warning(ex)
                         continue
 return True
-$$
-LANGUAGE 'plpython3u' VOLATILE;
+$BODY$
+  LANGUAGE plpython3u VOLATILE
+  COST 100
 
 
 例子:
 select public.rel_eq2sp('zone_general,zone_lighting', 'r_eq_in_sp_zone_general,r_eq_in_sp_zone_lighting', 'Pj1101010015', 2, 2);
 ```
+</details>
+
+
 ## 输入
     1. 参与计算的业务空间表的全名称, 带schema名, 以英文逗号隔开
     2. 关系计算结果存储的表, 跟第一个参数一一对应, 带schema名, 以英文逗号隔开

+ 6 - 7
docs/dev/data-center/relations/belongs/Fl2Fl.md

@@ -1,14 +1,13 @@
-楼层贯通关系
+# 楼层贯通关系
 ## 前置条件
-两个楼层的model_id信息点需要一致并不能为空, 则认为两个楼层是贯通关系
+
+    1. 两个楼层的model_id信息点需要一致且不能为空, 则认为两个楼层是贯通关系
 ```
 FROM floor WHERE project_id='Pj4201050001' AND model_id is not null
 ```
-## 处理方式
-    1. 先删除项目下所有的贯通关系(只删除sign为2的关系)
-    2. 多表连接更新:
-        1. 根据model_id信息点多表连接
-        2. 将结果插入到r_fl_through_fl表中, sign置为2
+## 处理逻辑
+    1. 拿到所有楼层
+    2. 如果两个楼层的ModelId信息点相同, 则认为两楼层有贯通关系
 
 # 函数
 

+ 3 - 3
docs/dev/data-center/relations/belongs/Pe2Bd.md

@@ -1,11 +1,11 @@
-资产所在建筑
+# 资产所在建筑
 ## 前置条件
     1. 资产有绑定的设备或部件
     2. 绑定的设备或部件有所在建筑
 ## 依赖函数
     Eq2Bd
-## 计算流程
-    根据 资产 --> 设备/部件 --> 建筑 的间接关系, 来获取资产和建筑的所在关系
+## 处理逻辑
+    根据 资产 --> 设备/部件 --> 建筑 的间接从属关系, 来获取资产和建筑的所在关系
     
 ## 函数
 ```

+ 2 - 2
docs/dev/data-center/relations/belongs/Pe2Fl.md

@@ -1,10 +1,10 @@
-资产所在楼层
+# 资产所在楼层
 ## 前置条件
     1. 资产有绑定的设备或部件
     2. 绑定的设备或部件有所在楼层
 ## 依赖函数
     Eq2Fl
-## 计算流程
+## 处理逻辑
     根据 资产 --> 设备/部件 --> 楼层 的间接关系, 来获取资产所在建筑的关系
     
 ## 函数

+ 1 - 1
docs/dev/data-center/relations/belongs/Pe2Sh.md

@@ -1,4 +1,4 @@
-资产所在竖井
+# 资产所在竖井
 ## 前置条件
     1. 资产有绑定的设备或部件
     2. 绑定的设备或部件有所在竖井关系

+ 1 - 1
docs/dev/data-center/relations/belongs/Pe2Sp.md

@@ -1,4 +1,4 @@
-资产所在业务空间
+# 资产所在业务空间
 ## 前置条件
     1. 资产有绑定的设备或部件
     2. 绑定的设备或部件有所在业务空间关系

+ 3 - 3
docs/dev/data-center/relations/belongs/Sh2Bd.md

@@ -1,11 +1,11 @@
-竖井关联的建筑
+# 竖井关联的建筑
 
 # 计算流程
     
     根据竖井关联的空间关系来推导
     
-# 处理流程
-    1. 竖井包含有业务空间, 并且业务空间有所属建筑
+## 处理逻辑
+    1. 根据 竖井 --> 业务空间 --> 建筑 的间接关系, 来获取资产所在业务空间的关系
     
 # 函数
 

+ 3 - 2
docs/dev/data-center/relations/belongs/Sh2Sh.md

@@ -1,8 +1,9 @@
-竖井贯通关系
+# 竖井贯通关系
 ## 前置条件
     1. 竖井包含的有元空间(竖井在r_sh_contain_si表中有数据)
-## 处理流程
+## 处理逻辑
     1. 竖井包含有相同的元空间, 则认为两竖井贯通
+    (竖井包含元空间的数据是前端做划分)
 ## 函数
 ```
 -- 竖井贯通关系

+ 11 - 5
docs/dev/data-center/relations/belongs/Sp2Fl.md

@@ -1,16 +1,21 @@
-在多个楼层划分一个模型时, 根据已有的业务空间所属楼层数据重新计算业务空间所属楼层
+# 业务空间所属楼层 (关系由前端生成, 此算法是在多个楼层划分一个模型时, 根据已有的业务空间所属楼层数据重新计算业务空间所属楼层)
 ## 前置条件
     1. 楼层有外轮廓
     2. 业务空间有外轮廓
     3. 有2个或2个以上的楼层的ModelId相同(意思是一个模型划分成了多个楼层)
     4. 这些ModelId相同的楼层下有所属的业务空间关系
     5. 业务空间所属楼层表内维护的关系是正确的
-## 处理流程
-    1. 查出项目内所有ModelId相同的楼层(如果没有则返回)
-    2. 按照ModelId将楼层分组, 相同ModelId的楼层为一组, 每组内按照以下规则计算
-    3. 获取组内所有楼层下的业务空间, 将查出的业务空间的轮廓与楼层的轮廓比对是否有重叠部分(所有业务空间 X 所有楼层次对比), 如果有重叠则认为该业务空间和该楼层有关系
+    
+## 处理逻辑
+    1. 查出项目内所有ModelId相同的楼层(如果没有则结束)
+    2. 按照ModelId信息点将楼层分组, 相同ModelId的楼层为一组, 每组内按照以下规则计算
+    3. 获取组内所有楼层下的业务空间, 将查出的业务空间的轮廓与组内楼层的轮廓比对是否有重叠部分(所有业务空间 X 组内楼层个数次对比), 如果有重叠则认为该业务空间和该楼层有关系
     4. 在业务空间所属楼层表内删除该组楼层下的所有业务空间关系, 并插入新计算出的业务空间所属楼层的关系
 ## 函数
+
+<details>
+<summary>源码</summary>
+
 ```
 
 CREATE OR REPLACE FUNCTION "public"."rel_sp2fl"("project_id" varchar)
@@ -171,6 +176,7 @@ $BODY$
 
 select public.rel_sp2fl('Pj1101050001')
 ```
+</details>
 
 ## 入参
     1. 项目id

+ 5 - 5
docs/dev/data-center/relations/belongs/Sp2Sp.md

@@ -2,15 +2,15 @@
 ## 前置条件
     1. 业务空间有所在楼层
     2. 业务空间有外轮廓
-## 处理流程
+## 处理逻辑
     1. 查出所有有所在楼层, 并且外轮廓不是null的业务空间
-    2. 根据所在楼层, 业务空间分区来将业务空间分组
-    3. 计算每个分组内的业务空间的相邻关系
+    2. 根据所在楼层, 业务空间分区类型来将业务空间分组
+    3. 分别计算每个分组内的业务空间的相邻关系
     计算相邻算法:
-    1. 首先判断围成业务空间的线段, 两两空间之间是否有近似平行的线段(线段偏转误差小于1度)
+    1. 首先判断围成业务空间轮廓的线段, 两两业务空间之间是否有近似平行的线段(线段平行偏转误差小于1度算作近似平行)
         1). 近似平行判断: 首先获取两个线段的斜率, 再计算斜率的反正切(即与x轴的角度, 不过是以pi为单位), 再判断两个角度差的绝对值是否小于1度
     2. 如果有近似平行的线段, 判断是否相互有投影在线段上, 有投影在线段上, 则认为是两平行线段有重合部分, 业务空间有相邻的可能性
-    3. 判断互相有投影点在对方线段上之后, 判断投影线的长度, 是否小于250mm(墙的最大厚度), 如果小于250mm则认为两空间相邻
+    3. 判断互相有投影点在对方线段上之后, 判断投影线的长度, 是否小于250mm(墙的最大厚度), 如果小于250mm则认为两空间相邻
 ## 函数
 ```
 create or replace function public.rel_sp2sp1(project_id character varying) returns boolean

+ 294 - 29
docs/dev/data-center/relations/belongs/Sp2Sp2.md

@@ -2,47 +2,312 @@
 ## 前置条件
     1. 业务空间有所在楼层
     2. 业务空间有外轮廓
-## 处理流程
-    1. 查出所有有所在楼层, 并且外轮廓不是null的业务空间
-    2. 根据所在楼层, 业务空间分区来将业务空间分组
+## 处理逻辑
+    1. 查出所有有所在楼层关系, 并且外轮廓不是null的业务空间
+    2. 根据所在楼层, 业务空间分区类型来将业务空间分为不同的 (例如 : A 楼层下的默认业务空间是一组, A楼层下的空调分区是另外一组)
     3. 计算每个分组内的业务空间的相邻关系
-    计算相邻算法:
-    1. 首先判断围成业务空间的线段, 两两空间之间是否有近似平行的线段(线段偏转误差小于1度)
-        1). 近似平行判断: 首先获取两个线段的斜率, 再计算斜率的反正切(即与x轴的角度, 不过是以pi为单位), 再判断两个角度差的绝对值是否小于1度
-    2. 如果有近似平行的线段, 判断是否相互有投影在线段上, 有投影在线段上, 则认为是两平行线段有重合部分, 业务空间有相邻的可能性
-    3. 在判断互相有投影点在对方线段上之后, 判断投影线的长度, 是否小于250mm(墙的最大厚度), 如果小于250mm则认为两空间相邻
+    计算相邻算法 (如下图):
+    1. 在一个分组内, 遍历每个业务空间上组成外轮廓的每条线段, 根据线段的长度, 是否超过delta_distance来区分成两种情况判断
+        1). 如果线段长度大于delta_distance, 假如图中线段AB长度大于delta_distance, 则在距离A点delta_distance的距离找到点P5, 
+        在P5点处作AB线段的垂线线段, 上下两边长度均为door_length长, 找到点P4和P6. 同理可以找到点P7和P9. 
+        2). 如果线段长度小于或等于delta_distance, 假设线段AE长度小于delta_distance, 则在线段中间点P2处作垂直于AE的垂线线段, 
+        上下两边长度均为door_length长, 找到点P1和P3.
+    2. 将上面找到的点, 依次与组内其他业务空间外轮廓做一次点是否在多边形内的判断, 如果在, 则认为该多边形与图中多边形相邻
+    
+   
+![Image text](./img/sp2sp2-1.PNG)
+
 ## 函数
+
+
+<details>
+<summary>源码</summary>
+
 ```
-create or replace function public.rel_sp2sp1(project_id character varying) returns boolean
+create function rel_sp2sp_v2(project_id character varying) returns boolean
+    language plpython3u
 as
 $$
-from relations.src.business_space_adjacent.adjacent import calc_space_adjacent
-try:
-    # 将下面对数据库的操作作为一个事务, 出异常则自动rollback
-    with plpy.subtransaction():
-        delete_plan = plpy.prepare("delete from r_spatial_connection where project_id = $1 and sign = 2", ["text"])
-        delete_plan.execute([project_id])
-        space_data_plan = plpy.prepare("SELECT id, project_id, floor_id, object_type, bim_location, outline FROM zone_space_base where project_id = $1 and outline is not null and floor_id is not null order by floor_id, object_type", ["text"])
-        space_data = space_data_plan.execute([project_id])
-        rel_data = calc_space_adjacent(space_data)
-        for single_rel in rel_data:
+import math
+import json
+from shapely.geometry import Polygon
+from matplotlib.path import Path
+
+column_project_id = 'project_id'
+column_location_one = 'location_one'
+column_location_two = 'location_two'
+column_space_id_one = 'space_id_one'
+column_space_id_two = 'space_id_two'
+column_zone_type = 'zone_type'
+column_added_polygon = 'polygon'
+
+column_id = 'id'
+column_bim_location = 'bim_location'
+column_floor_id = 'floor_id'
+column_object_type = 'object_type'
+column_outline = 'outline'
+key_x = 'X'
+key_y = 'Y'
+
+delta_distance = 200
+door_length = 1500
+
+
+# 获取两点之间的距离
+def get_segment_distance(x1, y1, x2, y2):
+    x_diff = x1 - x2
+    y_diff = y1 - y2
+    return math.sqrt(x_diff ** 2 + y_diff ** 2)
+
+
+# 获取垂直方向的斜率
+def get_vertical_k(k):
+    if k is None:
+        return 0
+    if k == 0:
+        return None
+    return 1 / k
+
+# 根据点 x, y 计算 y = kx + a 中的 a
+def get_a_by_point_k(x, y, k):
+    if k is None:
+        return None
+    return y - k * x
+
+
+# 在直线   y = kx + a 上找到距离点 base_x, base_y 距离为distance 的坐标点(两个坐标点)
+def get_point_by_distance(base_x, base_y, k, a, distance):
+    if k is None:
+        return base_x, base_y + distance, base_x, base_y - distance
+    vector_x1 = math.sqrt(distance ** 2 / (1 + k ** 2))
+    vector_x2 = -vector_x1
+    vector_y1 = k * vector_x1
+    vector_y2 = k * vector_x2
+    return base_x + vector_x1, base_y + vector_y1, base_x + vector_x2, base_y + vector_y2
+
+# 在直线 y = kx + a 上找到一个点, 该点距离点(base_x, base_y) 长度为 distance, 并且距离vec_x, vec_y最近
+def get_point_by_distance_on_segment(base_x, base_y, k, a, distance, vec_x, vec_y):
+    x1, y1, x2, y2 = get_point_by_distance(base_x, base_y, k, a, distance)
+    distance1 = get_segment_distance(x1, y1, vec_x, vec_y)
+    distance2 = get_segment_distance(x2, y2, vec_x, vec_y)
+    if distance1 > distance2:
+        return x2, y2
+    return x1, y1
+
+
+# 获取输入的两点之间开门之后门的坐标点
+# 返回格式
+# 如果线段距离小于等于door_length的情况 : x1, y1, x2, y2
+# 如果线段距离大于door_length的情况 (两端各开一个门): x1, y1, x2, y2, x3, y3, x4, y4
+def get_points(x1, y1, x2, y2):
+    # 如果两个点是同一个点
+    if x1 == y1 and x2 == y2:
+        return None, None, None, None
+    # 计算线段的距离
+    distance = get_segment_distance(x1, y1, x2, y2)
+    # 计算当前线段的 k
+    if x1 == x2:
+        k = None
+    else:
+        k = (y1 - y2) / (x1 - x2)
+    # 计算垂直方向的k
+    vertical_k = get_vertical_k(k)
+    # 计算当前线段的 a
+    a = get_a_by_point_k(x1, y1, k)
+    # 距离大于delta_distance, 则足够开两个门
+    if distance > delta_distance:
+        seg_x1, seg_y1 = get_point_by_distance_on_segment(x1, y1, k, a, delta_distance, x2, y2)
+        seg_x2, seg_y2 = get_point_by_distance_on_segment(x2, y2, k, a, delta_distance, x1, y1)
+        vertical_a1 = get_a_by_point_k(seg_x1, seg_y1, vertical_k)
+        vertical_a2 = get_a_by_point_k(seg_x2, seg_y2, vertical_k)
+        dest_x1, dest_y1, dest_x2, dest_y2 = get_point_by_distance(seg_x1, seg_y1, vertical_k, vertical_a1, door_length)
+        dest_x3, dest_y3, dest_x4, dest_y4 = get_point_by_distance(seg_x2, seg_y2, vertical_k, vertical_a2, door_length)
+        return [dest_x1, dest_x2, dest_x3, dest_x4], [dest_y1, dest_y2, dest_y3, dest_y4]
+    else:
+        # 距离太小, 在中间开门
+        seg_x1, seg_y1 = get_point_by_distance_on_segment(x1, y1, k, a, distance/2, x2, y2)
+        vertical_a1 = get_a_by_point_k(seg_x1, seg_y1, vertical_k)
+        dest_x1, dest_y1, dest_x2, dest_y2 = get_point_by_distance(seg_x1, seg_y1, vertical_k, vertical_a1, door_length)
+        return [dest_x1, dest_x2], [dest_y1, dest_y2]
+
+# 获取Polygon对象
+def get_polygon(single_poly):
+    poly_len = len(single_poly)
+    # plpy.info("poly_len : {0}, single_poly : {1} ".format(poly_len, single_poly))
+    poly = []
+    for i in range(poly_len):
+        pair = single_poly[i]
+        poly.append((pair[key_x], pair[key_y]))
+        # plpy.info((pair[key_x], pair[key_y]))
+    return Path(poly)
+
+
+# 获取业务空间每个块的最外层轮廓, 组成arr返回, 如果数据不合法发生异常则返回None
+def get_outer_polygon_arr(raw_outline):
+    try:
+        arr = []
+        outline_json = json.loads(raw_outline)
+        for i in range(len(outline_json)):
+            try:
+                single_polygon = get_polygon(outline_json[i][0])
+            except Exception as ex:
+                # plpy.info("error getting polygon : {0}".format(outline_json))
+                continue
+            arr.append(single_polygon)
+        return arr
+    except Exception as e:
+        return []
+
+
+# 判断一个点是否在多边形数组中的某一个多边形内
+def is_point_in_polygons(point, polygon_arr):
+    try:
+        for polygon in polygon_arr:
+            try:
+                if polygon.contains_points([point], None, -0.0001):
+                    return True
+            except Exception as ee:
+                plpy.warning("point in polygon : {0}".format(ee))
+        return False
+    except Exception as e:
+        plpy.warning(e)
+        return False
+
+
+# 检查是否已经加过这个关系(单向检查)
+def check_is_in_rel(space_adjacent, probe_id, id):
+    if probe_id in space_adjacent:
+        rel_set = space_adjacent[probe_id]
+        if id in rel_set:
+            return True
+    return False
+
+# 检查是否关系存在(双向检查)
+def check_is_in_rel_bidirection(space_adjacent, probe_id, id):
+    is_in = check_is_in_rel(space_adjacent, probe_id, id)
+    is_in = is_in or check_is_in_rel(space_adjacent, id, probe_id)
+    return is_in
+
+# 将业务空间相邻关系插入map中
+def insert_into_rel(space_adjacent, probe_id, id):
+    if check_is_in_rel_bidirection(space_adjacent, probe_id, id):
+        return
+    if probe_id not in space_adjacent:
+        space_adjacent[probe_id] = set()
+    rel_set = space_adjacent[probe_id]
+    rel_set.add(id)
+
+# 计算一个分组内的邻接关系, space_adjacent用来保存关系, 结构是  space_id  -->  set(space_id)
+def calc_adjacent_sub_arr(space_sub_arr, space_adjacent, space_info):
+    # space_sub_arr 是一个楼层内的一类业务空间
+    for space_row in space_sub_arr:
+        raw_outline = space_row.get(column_outline)
+        id = space_row.get(column_id)
+        space_info[id] = space_row
+        outline_json = json.loads(raw_outline)
+        #plpy.info("outline_json : {0}".format(len(outline_json)))
+        for i in range(len(outline_json)):
+            try:
+                single_poly = outline_json[i][0]
+            except Exception as ee :
+                # plpy.warning("error outline : {0}, id : {1}".format(outline_json, id))
+                continue
+            #single_poly = outline_json[i][0]
+            poly_len = len(single_poly)
+            for idx in range(1, poly_len):
+                # 线段
+                segment_point1 = single_poly[idx - 1]
+                segment_point2 = single_poly[idx]
+                # segment_length = get_segment_distance(segment_point1[key_x], segment_point1[key_y], segment_point2[key_x], segment_point2[key_y])
+                x_arr, y_arr = get_points(segment_point1[key_x], segment_point1[key_y], segment_point2[key_x], segment_point2[key_y])
+                # plpy.info("x_arr : {0} , y_arr : {1}".format(x_arr, y_arr))
+                for probe_space_row in space_sub_arr:
+                    probe_polygon_arr = probe_space_row.get(column_added_polygon)
+                    probe_id = probe_space_row.get(column_id)
+                    # 如果自己跟自己比较或者已经存在该关系的话, 跳过
+                    if probe_id == id or check_is_in_rel_bidirection(space_adjacent, probe_id, id):
+                        continue
+                    for arr_index in range(0, len(x_arr)):
+                        prob_x = x_arr[arr_index]
+                        prob_y = y_arr[arr_index]
+                        is_hit = is_point_in_polygons((prob_x, prob_y), probe_polygon_arr)
+                        # plpy.info("is hit : {0}".format(is_hit))
+                        if is_hit:
+                            # plpy.info("hit")
+                            insert_into_rel(space_adjacent, probe_id, id)
+                            break
+
+# 将输入数据按照楼层id, 业务空间类型分类
+def classify(space_list):
+    current_floor_id = ''
+    current_object_type = ''
+    current_sub_arr = []
+    space_arr = []
+    for row in space_list:
+        if row.get(column_floor_id) == current_floor_id and row.get(column_object_type) == current_object_type:
+            current_sub_arr.append(row)
+        else:
+            current_floor_id = row.get(column_floor_id)
+            current_object_type = row.get(column_object_type)
+            current_sub_arr = [row]
+            space_arr.append(current_sub_arr)
+        row[column_added_polygon] = get_outer_polygon_arr(row.get(column_outline))
+    for sub_arr in space_arr:
+        if len(sub_arr) == 1:
+            space_arr.remove(sub_arr)
+    return space_arr
+
+# 计算业务空间相邻
+def calc_space_adjacent(space_list):
+    # 给业务空间按照所属楼层和业务空间类型分组
+    space_arr = classify(space_list)
+    space_adjacent = dict()
+    space_info = dict()
+    for space_sub_arr in space_arr:
+        calc_adjacent_sub_arr(space_sub_arr, space_adjacent, space_info)
+    return space_adjacent, space_info
+
+
+#try:
+# 将下面对数据库的操作作为一个事务, 出异常则自动rollback
+with plpy.subtransaction():
+    # 获取有所在楼层的所有业务空间, 并按照所在楼层和业务空间类型排序, 方便分组
+    sql_str = "SELECT sp.id, sp.project_id, rel.floor_id, sp.object_type, sp.bim_location, sp.outline FROM zone_space_base sp inner join r_sp_in_fl rel on rel.space_id = sp.id where sp.project_id = $1 and rel.project_id = $1 and outline is not null order by floor_id, object_type"
+    space_data_plan = plpy.prepare(sql_str, ["text"])
+    space_data = space_data_plan.execute([project_id])
+    plpy.info("space data : {0}".format(len(space_data)))
+    rel_data, space_info = calc_space_adjacent(space_data)
+    # 删除以前的业务空间相邻关系
+    delete_plan = plpy.prepare("delete from r_spatial_connection where project_id = $1 and sign = 2", ["text"])
+    delete_plan.execute([project_id])
+    plpy.info("rel_data : {0}".format(len(rel_data)))
+    for space_id1, to_space_set in rel_data.items():
+        space1 = space_info[space_id1]
+        for space_id2 in to_space_set:
+            space2 = space_info[space_id2]
             delete_duplicate_plan = plpy.prepare("delete from r_spatial_connection where space_id_one = $1 and space_id_two = $2", ["text", "text"])
-            delete_duplicate_plan.execute([single_rel['space_id_one'], single_rel['space_id_two']])
+            delete_duplicate_plan.execute([space_id1, space_id2])
             insert_plan = plpy.prepare("insert into r_spatial_connection(project_id, location_one, location_two, space_id_one, space_id_two, sign, graph_type, floor_id, zone_type) values($1, $2, $3, $4, $5, 2, 'SpaceNeighborhood', $6, $7)", ["text", "text", "text", "text", "text", "text", "text"])
-            insert_plan.execute([project_id, single_rel['location_one'], single_rel['location_two'], single_rel['space_id_one'], single_rel['space_id_two'], single_rel['floor_id'], single_rel['zone_type']])
-except Exception as e:
-    plpy.warning(e)
-    return False
-else:
+            # plpy.info("{0}, {1}, {2}, {3}, {4}, {5}, {6}".format(project_id, space1.get(column_bim_location), space2.get(column_bim_location), space_id1, space2, space1.get(column_floor_id), space1.get(column_object_type)))
+            insert_plan.execute([project_id, space1.get(column_bim_location), space2.get(column_bim_location), space_id1, space2.get(column_id), space1.get(column_floor_id), space1.get(column_object_type)])
     return True
-$$
-LANGUAGE 'plpython3u' VOLATILE;
+#except Exception as e:
+#    plpy.warning(e)
+#    return False
+#else:
+#    return True
+$$;
+
+alter function rel_sp2sp_v2(varchar) owner to postgres;
 
 
-select public.rel_sp2sp1('Pj1101050001')
+
+select public.rel_sp2sp_v2('Pj1101050001')
 ```
 
+</details>
+
 ## 入参
     1. 项目id
 ## 例子
-    select public.rel_sp2sp1('Pj1102290002');
+    select public.rel_sp2sp_v2('Pj1102290002');

+ 1 - 1
docs/dev/data-center/relations/belongs/Sy2Bd.md

@@ -4,7 +4,7 @@
     2. 系统下的设备有所属建筑的关系
 ## 依赖函数
     Eq2Bd
-## 计算流程
+## 处理逻辑
     1. 通过 系统 --> 设备 --> 建筑 的间接关系, 获取系统所在建筑的关系
     2. 结果存储在 r_sy_in_bd 表中
     

+ 1 - 1
docs/dev/data-center/relations/belongs/Sy2Fl.md

@@ -4,7 +4,7 @@
     2. 系统下的设备有所属楼层关系
 ## 依赖函数
     Eq2Fl
-## 计算流程
+## 处理逻辑
     1. 通过 系统 --> 设备 --> 楼层 的间接关系, 获取系统所在楼层的关系
     2. 计算关系存储在表 r_sy_in_fl 中
 ## 函数

+ 1 - 1
docs/dev/data-center/relations/belongs/Sy2Sh.md

@@ -4,7 +4,7 @@
     2. 系统下的设备有所在竖井关系
 ## 依赖函数
     Eq2Sh
-## 计算流程
+## 处理逻辑
     1. 根据 系统 --> 设备 --> 竖井 来间接获取系统所属竖井关系
     2. 计算后的关系存储在表 r_sy_in_sh
 ## 函数

+ 1 - 1
docs/dev/data-center/relations/belongs/Sy2Sp.md

@@ -4,7 +4,7 @@
     2. 系统下的设备有所在业务空间关系
 ## 依赖函数
     Eq2Sp
-## 计算流程
+## 处理逻辑
     1. 根据 系统 --> 设备 --> 业务空间 的间接关系, 获取系统和业务空间的关系
     2. 计算结果存储在r_sy_in_sp_*中
 ## 函数

+ 3 - 3
docs/dev/data-center/relations/belongs/f_rel_calc.md

@@ -1,4 +1,4 @@
-管理关系计算函数依赖和函数输入类型
+# 管理关系计算函数依赖和函数输入类型
 
 # 说明
     classify 该变量是根据函数的输入将函数分类
@@ -6,12 +6,13 @@
 
 # 函数
 ## 代码
+
 ```
 CREATE OR REPLACE FUNCTION "public"."f_rel_calc"("func" text, "project_id" varchar, "tables" text, "out_tables" text, "sign1" int4, "sign2" int4)
   RETURNS "pg_catalog"."int4" AS $BODY$
 # 根据函数输入类型分类
 classify = {"eq2bd":1, "eq2fl":1, "sp2fl":1, "eq2sh":1, "pe2bd":1, "pe2fl":1, "pe2sh":1, "pe2sp":1, "sh2sh":1, "sy2bd":1,
-    "sy2fl":1, "sy2sh":1, "sy2sp":1, "bd2sp":2, "eq2sp":3, "fl2fl":4}
+    "sy2fl":1, "sy2sh":1, "sy2sp":1, "sh2bd":1, "bd2sp":2, "eq2sp":3, "fl2fl":4}
 dependency = {"eq2bd":["eq2fl"], "eq2sh":["eq2sp"], "eq2sp":["eq2fl", "sp2fl"], "pe2bd":["eq2bd"], "pe2fl":["eq2fl"], "pe2sh":["eq2sh"],
     "pe2sp":["eq2sp"], "sy2bd":["eq2bd"], "sy2fl":["eq2fl"], "sy2sh":["eq2sh"], "sy2sp":["eq2sp"]}
 def get_type_by_func_name(func_name):
@@ -76,7 +77,6 @@ $BODY$
   LANGUAGE plpython3u VOLATILE
   COST 100
 
-
 例子:
 select public.f_rel_calc('rel_eq2sh', 'Pj*******', 'zone_space_base','relationship.r_eq2sp', 2, 2)
 ```

BIN
docs/dev/data-center/relations/belongs/img/sp2sp2-1.PNG


+ 1 - 1
docs/dev/data-center/relations/other/calc_area_v3.md

@@ -3,7 +3,7 @@
 
 
-## 处理方式
+## 处理逻辑
 
 根据业务空间轮廓的格式, 以此计算内部每个小轮廓的面积, 加和在一起为最终结果
 小轮廓面积计算: 计算首个子轮廓面积, 并减去随后所有子轮廓的面积. 结果为小轮廓面积

+ 5 - 5
docs/dev/data-center/relations/other/calc_vertically_overlap.md

@@ -4,12 +4,12 @@
 ```
 
 ```
-## 处理方式
+## 处理逻辑
 
-获取所有建筑, for循环获取每个建筑下所有的业务空间, 按楼层分类
-每个楼层的每个业务空间分别和别的楼层的每个业务空间判断is_vertically_overlap
-将结果是true的两个业务空间保存起来
-删除旧业务空间的垂直交通关系(自动计算的), 添加新关系
+    1. 获取所有建筑, for循环获取每个建筑下所有的业务空间, 按楼层分类
+    2. 每个楼层的每个业务空间分别和别的楼层的每个业务空间判断is_vertically_overlap
+    3. 将结果是true的两个业务空间保存起来
+    4. 删除旧业务空间的垂直交通关系(自动计算的), 添加新关系
 
 ## 实现方式
 

+ 1 - 1
docs/dev/data-center/relations/other/other_ispace_floor_overlap.md

@@ -3,7 +3,7 @@
     1. 元空间和楼层必须都有轮廓
     2. 轮廓必须符合规则
     
-# 处理方式
+# 处理逻辑
 
     将楼层的外轮廓与元空间的最外层轮廓做是否重叠检查操作
 

+ 1 - 1
docs/dev/data-center/relations/other/rel_affected_space.md

@@ -9,7 +9,7 @@
 
 ## 依赖函数
-## 处理方式
+## 处理逻辑
 
     1. 查询出所有绑定该revit模型楼层的数据中心楼层
         SELECT id FROM public.floor where model_id = 'revit模型楼层'

+ 1 - 1
docs/dev/data-center/relations/other/rel_str_similar.md

@@ -6,7 +6,7 @@
 
 ## 依赖函数
-## 处理方式
+## 处理逻辑
 
     根据编辑距离来计算相似度
 

+ 1 - 1
docs/dev/data-center/relations/topology/sys_block.md

@@ -5,7 +5,7 @@
 3. 相邻层立管开放端口坐标位置相等(距离差值不能超过0.01)
 4. (非强制)通过模型检查:连接件检查、系统类型名称检查、管网及相关设备检查、管段检查
 
-## 处理方式
+## 处理逻辑
 
 1. 获取所有当前项目project_id下的的有模型文件models; 表:revit.model_folder、revit.model_floor、revit.model_file
 2. 遍历models,获取model层的系统图systemGraphs;

+ 1 - 1
docs/dev/data-center/relations/topology/sys_direction.md

@@ -4,7 +4,7 @@
 1. 通过管网系统分块计算;
 2. 指定源。
 
-## 处理方式
+## 处理逻辑
 
 1. 从connected_block表中取出所有关系,构建无向图
 2. 从connected_block_source表中取出所有的源

+ 7 - 1
docs/dev/saga-graphy/graphy-engine/draw.md

@@ -14,6 +14,7 @@
 :::
 
 ## 折线
+
 <example-web-graph-DrawPolyline1 /> 
 
 ::: details 查看代码
@@ -34,10 +35,15 @@
 
 ## 圆
 
+<example-web-graph-Circle1 /> 
+
+::: details 查看代码
+
+<<< @/docs/.vuepress/components/example/web/graph/Circle1.vue
 
 
 ## 椭圆
 
 ## 多边形
 
-## 路径
+## 路径

+ 6 - 1
docs/dev/saga-graphy/index.js

@@ -23,6 +23,11 @@ const content = [
                 path: "/dev/saga-graphy/scene-manage/items/",
                 children: [
                     ["/dev/saga-graphy/scene-manage/items/clock", "时钟"],
+                    ["/dev/saga-graphy/scene-manage/items/text", "文本"],
+                    ["/dev/saga-graphy/scene-manage/items/image", "图片"],
+                    ["/dev/saga-graphy/scene-manage/items/editLine", "可编辑直线"],
+                    ["/dev/saga-graphy/scene-manage/items/edit-polygon", "可编辑多边形示例"],
+                    ["/dev/saga-graphy/scene-manage/items/imgText", "图例item(图片文本组合)"]
                 ]
             },
             ["/dev/saga-graphy/scene-manage/undo", "Undo示例"]
@@ -42,7 +47,7 @@ const content = [
         title: "系统图",
         path: "/dev/saga-graphy/system-diagram/",
         children: [
-
+            ["/dev/saga-graphy/system-diagram/json-file", "json数据格式"]
         ]
     },
 ];

+ 17 - 0
docs/dev/saga-graphy/scene-manage/items/edit-polygon.md

@@ -0,0 +1,17 @@
+# 可编辑多边形示例
+::: details 目录
+[[toc]]
+:::
+
+<example-web-graph-scene-SEditPolygon/>
+
+::: tip 注
+1、可以通过双击table在编辑状态和展示状态来回切换,<br/>
+2、创建状态时;enter + 左键闭合多边形 <br/>
+3、编辑状态时:鼠标点击在边上可加点,可拖动点;<br/>
+4、编辑状态时:通过ALT键 + 鼠标左键 删除顶点
+:::
+
+::: details 查看代码
+<<< @/docs/.vuepress/components/example/web/graph/scene/SEditPolygon.vue
+:::

+ 17 - 0
docs/dev/saga-graphy/scene-manage/items/editLine.md

@@ -0,0 +1,17 @@
+# 可编辑直线示例
+::: details 目录
+[[toc]]
+:::
+
+<example-web-graph-scene-SEditLine/>
+
+::: tip 注
+1、可以通过双击table在编辑状态和展示状态来回切换,<br/>
+2、创建状态时;enter + 左键闭合多边形 <br/>
+3、编辑状态时:鼠标点击在边上可加点,可拖动点;<br/>
+4、编辑状态时:通过ALT键 + 鼠标左键 删除顶点
+:::
+
+::: details 查看代码
+<<< @/docs/.vuepress/components/example/web/graph/scene/SEditLine.vue
+:::

+ 10 - 0
docs/dev/saga-graphy/scene-manage/items/image.md

@@ -0,0 +1,10 @@
+# 图片实例
+::: details 目录
+[[toc]]
+:::
+
+<example-web-graph-scene-ImageItem />
+
+::: details 查看代码
+<<< @/docs/.vuepress/components/example/web/graph/scene/ImageItem.vue
+:::

+ 6 - 0
docs/dev/saga-graphy/scene-manage/items/imgText.md

@@ -0,0 +1,6 @@
+# 图例item示例
+::: details 目录
+[[toc]]
+:::
+
+<example-web-graph-scene-SImgTextItem/>

+ 10 - 0
docs/dev/saga-graphy/scene-manage/items/text.md

@@ -0,0 +1,10 @@
+# 文本实例
+::: details 目录
+[[toc]]
+:::
+
+<example-web-graph-scene-TextItem />
+
+::: details 查看代码
+<<< @/docs/.vuepress/components/example/web/graph/scene/TextItem.vue
+:::

+ 103 - 0
docs/dev/saga-graphy/system-diagram/json-file.md

@@ -0,0 +1,103 @@
+# Json 文件格式
+::: details 目录
+[[toc]]
+:::
+
+## 整体数据格式
+
+```
+{
+    Data:[
+        {
+            EntityList:[],
+            Elements:{                          // 系统图展示所需数据
+                Nodes:[],                       // 图例节点,所有与工程信息化相关的图例(图标类型与区域)
+                Markers:[],                     // 与工程信息无关的标识对象(增加文本注释,图上的图片说明)
+                Relations:[],                   // 管线对象
+            },
+            ID: '',                             // 图ID
+            Name: '',                           // 名称
+            CategoryID: '',                     // 图分类ID
+            ProjectID: '',                      // 项目ID
+            BuildingID: '',                     // 建筑ID
+            FloorID: '',                        // 楼层id
+            Note: ''                           // 图说明
+            
+        }
+    ],
+    Message: '',
+    Result: ''
+}
+```
+
+## 图例节点
+
+```
+    Nodes:[
+        {   
+            ID: '',                             // ID
+            Name: '',                           // 名称
+            AttachObjectIds:[],                 // 返回工程信息化对象 ID 列表
+            GraphElementType: '',               // 图例类型 None/Line/Zone/Image:非图例/线条/区域类型/图标
+            GraphElementId: '',                 // 对应的图元ID
+            Num: 1                              //图例数量
+            Pos: {X: 0, Y: 0},                  // 位置
+            Scale: {X: 1, Y: 1, Z: 1},          // 缩放
+            Rolate: {X: 0, Y: 0, Z: 0},         // 旋转
+            Size: {Width:0, Height: 0},         // 大小
+            AnchorList:[
+                    {
+                        ID: '',                 // 锚点ID
+                        Pos: '',                // 锚点的坐标
+                    },
+                    ...
+                ],
+            OutLine: [
+                [{X:0,Y:0,Z:0},...],            // 外轮廓 
+                ...                             // 内轮廓
+            ],                                  // 轮廓线
+            Properties: {}                      // 由应用自己定义
+        },
+        ...
+    ]
+```
+
+## 标识对象
+
+```
+    Markers:[
+        {
+            ID: '',                             // ID
+            Name: '',                           // 名称
+            Type: '',                           // 图标(Image),线类型(Line),文本(Text)
+            Pos: {X: 0, y: 0},                  // 位置
+            Scale: {X: 1, Y: 1, Z: 1},          // 缩放
+            Rolate: {X: 0, Y: 0, Z: 0},         // 旋转
+            Size: {Width:0, Height: 0},         // 大小
+            Properties: {}                      // 由应用自己定义
+        },
+        ...
+    ]
+```
+
+## 对象关系
+
+```
+    Relations: [
+        {
+            ID: '',                             // ID
+            Name: '',                           // 名称
+            GraphElementId: '',                 // 对应的图例ID
+            Node1ID: '',                        // 关联节点1_id
+            Node2ID: '',                        // 关联节点2_id
+            Anchor1ID: '',                      // 关联锚点1_id
+            Anchor2ID: '',                      // 关联锚点2_id
+            Dir: 0,                             // 方向(0:无向,1:节点1到节点2,2:节点2到节点1)
+            LineType: '',                       // 直线(Line),水平垂直
+            PointList: [],                      // 线的顶点坐标
+            Style: ''                           // 线的绘图样式
+        },
+        ...
+    ]
+```
+```

+ 6 - 3
package.json

@@ -12,9 +12,11 @@
     "publish": "node publish.js"
   },
   "dependencies": {
-    "@saga-web/base": "^2.1.14",
-    "@saga-web/draw": "^2.1.83",
-    "@saga-web/graphy": "^2.1.58",
+    "@saga-web/base": "^2.1.9",
+    "@saga-web/big": "^1.0.24",
+    "@saga-web/draw": "^2.1.84",
+    "@saga-web/graph": "^2.1.68",
+    "@saga-web/feng-map": "1.0.6",
     "axios": "^0.18.1",
     "element-ui": "^2.12.0",
     "vue": "^2.6.10",
@@ -26,6 +28,7 @@
     "ts-loader": "^7.0.4",
     "typescript": "^3.9.2",
     "vuepress": "^1.2.0",
+    "polybooljs": "^1.2.0",
     "vuepress-plugin-typescript": "^0.2.0",
     "vuepress-types": "^0.9.2"
   }

+ 13 - 16
publish.js

@@ -1,22 +1,19 @@
 /*
  * ********************************************************************************************************************
  *
- *               iFHS7.
- *              ;BBMBMBMc                  rZMBMBR              BMB
- *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
- *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
- *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
- *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
- *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
- *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
- *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
- *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
- *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
- *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
- *         i0BM: SWKHKGO  MBDv
- *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
- *              ,  XMW  ..
- *                  r                                                                     All rights reserved.
+ *                      :*$@@%$*:                         ;:                ;;    ;;
+ *                    :@@%!  :!@@%:                       %!             ;%%@@%$ =@@@@@@@%;     @%@@@%%%%@@@@@
+ *                   :@%;       :$=                       %%$$$%$$         ;$$  ;$@=   !@$
+ *                   =@!                                  %!              @ $=;%   !@@@%:      !$$$$$$$$$$$$$$=
+ *                   =@*                                  %!              @ $= % %@=   =%@!      %=
+ *              *$%%! @@=        ;=$%%%$*:                %!              @ $= % =%%%%%%@$      *%:         =%
+ *            %@@!:    !@@@%=$@@@@%!  :*@@$:              %!              @ $= % $*     ;@      @*          :%*
+ *          ;@@!          ;!!!;:         ;@%:      =======@%========*     @ $$ % $%*****$@     :@$=*********=@$
+ *          $@*   ;@@@%=!:                *@*
+ *          =@$    ;;;!=%@@@@=!           =@!
+ *           %@$:      =@%: :*@@@*       %@=                    Copyright (c) 2016-2019.  北京上格云技术有限公司
+ *            ;%@@$=$@@%*       *@@@$=%@@%;
+ *               ::;::             ::;::                                              All rights reserved.
  *
  * ********************************************************************************************************************
  */

+ 1 - 1
tsconfig.json

@@ -1,7 +1,7 @@
 {
     "compilerOptions": {
         "types": ["vuepress-types"],
-        "target": "es5",                            // Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'.
+        "target": "es6",                            // Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'.
         "module": "commonjs",                       // Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'.
         "rootDir": "./docs",
 //        "outDir": "./lib",                          // 编译后生成的文件目录