From cfc224e6602a3bd963c4605cf9eb191e0d59ed26 Mon Sep 17 00:00:00 2001 From: ChenX Date: Thu, 22 Mar 2018 11:01:13 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=88=E5=B9=B6=E5=A4=9A=E6=AE=B5=E7=BA=BF?= =?UTF-8?q?=E5=81=8F=E7=A7=BB=E5=88=86=E6=94=AF,=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E5=A4=9A=E6=AE=B5=E7=BA=BF=E5=A4=A7=E9=83=A8=E5=88=86=E6=96=B9?= =?UTF-8?q?=E6=B3=95.=20=E9=87=8D=E6=9E=84=E4=BF=AE=E5=A4=8Darc=E7=9A=84?= =?UTF-8?q?=E5=A4=A7=E9=83=A8=E5=88=86=E6=96=B9=E6=B3=95.=20=20=E9=87=8D?= =?UTF-8?q?=E6=96=B0=E7=BC=96=E5=86=99=E6=B5=8B=E8=AF=95=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Geometry/__snapshots__/arc.test.ts.snap | 72 + .../__snapshots__/circle.test.ts.snap | 145 ++ .../__snapshots__/intersect.test.ts.snap | 8 +- __test__/Geometry/angleTo.test.ts | 2 +- __test__/Geometry/arc.test.ts | 129 +- __test__/Geometry/circle.test.ts | 131 ++ __test__/Geometry/intersect.test.ts | 10 +- __test__/Interest/line.test.ts | 4 +- __test__/Polyline/Intersect.test.ts | 118 ++ .../Polyline/PolylineGetPointAtParam.test.ts | 85 ++ .../PolylineGetPointAtParam.test.ts.snap | 1049 +++++++++++++ .../Polyline/__snapshots__/split.test.ts.snap | 1305 +++++++++++++++++ __test__/Polyline/polyline.test.ts | 472 ++++++ __test__/Polyline/split.test.ts | 111 ++ src/Add-on/DrawPolyline.ts | 66 +- src/Add-on/Export.ts | 31 + src/Add-on/Offset.ts | 73 +- src/Add-on/RevPl.ts | 7 +- src/Add-on/Save.ts | 2 +- src/Add-on/TestBox.ts | 24 + src/Add-on/Trim.ts | 7 + src/Add-on/closetest.ts | 46 + src/Add-on/instest.ts | 40 + src/Add-on/polytest.ts | 270 ++++ src/ApplicationServices/mesh/createBoard.ts | 19 +- src/Common/CurveUtils.ts | 79 +- src/Common/KeyEnum.ts | 3 +- src/Common/Utils.ts | 10 + src/DatabaseServices/Arc.ts | 457 +++--- src/DatabaseServices/Circle.ts | 86 +- src/DatabaseServices/Curve.ts | 27 +- src/DatabaseServices/Ellipse.ts | 51 +- src/DatabaseServices/Entity.ts | 8 + src/DatabaseServices/Line.ts | 27 +- src/DatabaseServices/Polyline.ts | 1305 ++++++++++++----- src/Editor/CommandRegister.ts | 26 +- src/Editor/SnapServices.ts | 9 +- src/Geometry/GeUtils.ts | 66 +- src/GraphicsSystem/IntersectWith.ts | 242 ++- src/GraphicsSystem/Viewer.ts | 3 - src/UI/Components/Modal/ModalsManage.tsx | 1 + src/UI/Components/SourceManage/FileItem.tsx | 10 +- 42 files changed, 5776 insertions(+), 860 deletions(-) create mode 100644 __test__/Geometry/__snapshots__/circle.test.ts.snap create mode 100644 __test__/Geometry/circle.test.ts create mode 100644 __test__/Polyline/Intersect.test.ts create mode 100644 __test__/Polyline/PolylineGetPointAtParam.test.ts create mode 100644 __test__/Polyline/__snapshots__/PolylineGetPointAtParam.test.ts.snap create mode 100644 __test__/Polyline/__snapshots__/split.test.ts.snap create mode 100644 __test__/Polyline/polyline.test.ts create mode 100644 __test__/Polyline/split.test.ts create mode 100644 src/Add-on/Export.ts create mode 100644 src/Add-on/TestBox.ts create mode 100644 src/Add-on/closetest.ts create mode 100644 src/Add-on/instest.ts create mode 100644 src/Add-on/polytest.ts diff --git a/__test__/Geometry/__snapshots__/arc.test.ts.snap b/__test__/Geometry/__snapshots__/arc.test.ts.snap index 7e3d80240..5d3716b29 100644 --- a/__test__/Geometry/__snapshots__/arc.test.ts.snap +++ b/__test__/Geometry/__snapshots__/arc.test.ts.snap @@ -7,3 +7,75 @@ exports[`三点同一位置 2`] = `0`; exports[`三点圆心 1`] = `3.141592653589793`; exports[`三点圆心 2`] = `0`; + +exports[`圆弧偏移 1`] = ` +Vector3 { + "x": 5, + "y": 0, + "z": 0, +} +`; + +exports[`圆弧偏移 2`] = `3.141592653589793`; + +exports[`圆弧偏移 3`] = `0`; + +exports[`圆弧偏移 4`] = `5`; + +exports[`圆弧偏移 5`] = ` +Vector3 { + "x": 5, + "y": 0, + "z": 0, +} +`; + +exports[`圆弧偏移 6`] = `3.141592653589793`; + +exports[`圆弧偏移 7`] = `0`; + +exports[`圆弧偏移 8`] = `15`; + +exports[`圆弧偏移 9`] = ` +Vector3 { + "x": 5, + "y": 0, + "z": 0, +} +`; + +exports[`圆弧偏移 10`] = `0`; + +exports[`圆弧偏移 11`] = `3.141592653589793`; + +exports[`圆弧偏移 12`] = `5`; + +exports[`圆弧偏移 13`] = ` +Vector3 { + "x": 5, + "y": 0, + "z": 0, +} +`; + +exports[`圆弧偏移 14`] = `0`; + +exports[`圆弧偏移 15`] = `3.141592653589793`; + +exports[`圆弧偏移 16`] = `25`; + +exports[`最近点 1`] = ` +Vector3 { + "x": 0, + "y": 0, + "z": 0, +} +`; + +exports[`最近点 2`] = ` +Vector3 { + "x": 10, + "y": 0, + "z": 0, +} +`; diff --git a/__test__/Geometry/__snapshots__/circle.test.ts.snap b/__test__/Geometry/__snapshots__/circle.test.ts.snap new file mode 100644 index 000000000..ba912f250 --- /dev/null +++ b/__test__/Geometry/__snapshots__/circle.test.ts.snap @@ -0,0 +1,145 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`圆偏移 1`] = ` +Vector3 { + "x": 2, + "y": 0, + "z": 0, +} +`; + +exports[`圆偏移 2`] = ` +Vector3 { + "x": 2, + "y": 0, + "z": 0, +} +`; + +exports[`圆偏移 3`] = ` +Vector3 { + "x": 5, + "y": 0, + "z": 0, +} +`; + +exports[`圆偏移 4`] = ` +Vector3 { + "x": 5, + "y": 0, + "z": 0, +} +`; + +exports[`圆偏移 5`] = ` +Vector3 { + "x": 20, + "y": 0, + "z": 0, +} +`; + +exports[`圆偏移 6`] = ` +Vector3 { + "x": 20, + "y": 0, + "z": 0, +} +`; + +exports[`圆偏移 7`] = ` +Vector3 { + "x": 20, + "y": 0, + "z": 0, +} +`; + +exports[`圆偏移 8`] = ` +Vector3 { + "x": 20, + "y": 0, + "z": 0, +} +`; + +exports[`圆偏移 9`] = ` +Vector3 { + "x": 5, + "y": 0, + "z": 0, +} +`; + +exports[`圆偏移 10`] = ` +Vector3 { + "x": 5, + "y": 0, + "z": 0, +} +`; + +exports[`圆的切割2 1`] = ` +Vector3 { + "x": 5, + "y": 5, + "z": 0, +} +`; + +exports[`圆的切割2 2`] = ` +Vector3 { + "x": 4.999999999999999, + "y": -5, + "z": 0, +} +`; + +exports[`圆的切割2 3`] = ` +Vector3 { + "x": 4.999999999999999, + "y": -5, + "z": 0, +} +`; + +exports[`圆的切割2 4`] = ` +Vector3 { + "x": 0, + "y": 6.123233995736766e-16, + "z": 0, +} +`; + +exports[`圆的切割2 5`] = ` +Vector3 { + "x": 0, + "y": 6.123233995736766e-16, + "z": 0, +} +`; + +exports[`圆的切割2 6`] = ` +Vector3 { + "x": 5, + "y": 5, + "z": 0, +} +`; + +exports[`最近点 1`] = ` +Vector3 { + "x": 0, + "y": 0, + "z": 0, +} +`; + +exports[`最近点 2`] = ` +Vector3 { + "x": 10, + "y": 0, + "z": 0, +} +`; diff --git a/__test__/Geometry/__snapshots__/intersect.test.ts.snap b/__test__/Geometry/__snapshots__/intersect.test.ts.snap index 76d7ed1a6..3547efee7 100644 --- a/__test__/Geometry/__snapshots__/intersect.test.ts.snap +++ b/__test__/Geometry/__snapshots__/intersect.test.ts.snap @@ -8,7 +8,13 @@ Vector3 { } `; -exports[`相交测试 2`] = `undefined`; +exports[`相交测试 2`] = ` +Vector3 { + "x": 2.5, + "y": 0, + "z": 0, +} +`; exports[`相交测试 3`] = ` Vector3 { diff --git a/__test__/Geometry/angleTo.test.ts b/__test__/Geometry/angleTo.test.ts index ef84df478..d9197d9ed 100644 --- a/__test__/Geometry/angleTo.test.ts +++ b/__test__/Geometry/angleTo.test.ts @@ -35,5 +35,5 @@ test('0向量', () => test('变量补全', () => { let v = angleTo(new Vector3(1, 0, 0), new Vector3(0, 0, 1)) //? - expect(v).toEqual(0) + expect(v).toEqual(Math.PI * 0.5) }); diff --git a/__test__/Geometry/arc.test.ts b/__test__/Geometry/arc.test.ts index dba520916..ef2cd439c 100644 --- a/__test__/Geometry/arc.test.ts +++ b/__test__/Geometry/arc.test.ts @@ -4,6 +4,7 @@ import { app } from '../../src/ApplicationServices/Application'; import { Command } from '../../src/Editor/CommandMachine'; import { PromptStatus } from '../../src/Editor/PromptResult'; import { RenderType } from '../../src/GraphicsSystem/Enum'; +import { equal, equaln } from '../../src/Geometry/GeUtils'; test("三点共线", () => { @@ -22,8 +23,6 @@ test("三点共线", () => expect(arc.Center.toArray()).toMatchObject([0, 0, 0]); }) - - test("三点圆心", () => { let arc = new Arc(); @@ -53,9 +52,133 @@ test("三点同一位置", () => console.log(arc.StartAngle); console.log(arc.EndAngle); - expect(arc.Center.toArray()).toMatchObject([0, 0, 0]); + expect(arc.Center.toArray()).toMatchObject([5, 5, 0]); expect(arc.StartAngle).toMatchSnapshot(); expect(arc.EndAngle).toMatchSnapshot(); }) +test('圆弧参数', () => +{ + + let arc = new Arc(new Vector3(5, 0, 0), 5, Math.PI, 0); + + expect(arc.GetParamAtPoint(new Vector3(0, 0, 0))).toBe(0); + + expect(equaln(arc.GetParamAtPoint(new Vector3(5, 5, 0)), 0.5)).toBeTruthy(); + + expect(equaln(arc.GetParamAtPoint(new Vector3(10, 0, 0)), 1)).toBeTruthy(); + + expect(equaln(arc.GetParamAtPoint(new Vector3(5, -5, 0)), 1.5)).toBeTruthy(); + + +}); + +test('0长度圆弧,参数', () => +{ + + let arc = new Arc(new Vector3(), 0, 0, 0); + + expect(arc.GetParamAtPoint(new Vector3(0, 0, 0))).toBe(NaN); + +}); + +test("圆弧的切割1", () => +{ + let arc = new Arc(new Vector3(5, 0, 0), 5, Math.PI, 0); + expect(arc.GetSplitCurves(0.5)[0].EndPoint).toMatchObject({ 'x': 5, 'y': 5, 'z': 0 }); + expect(arc.GetSplitCurves(0.5)[1].EndPoint).toMatchObject({ 'x': 10, 'y': 0, 'z': 0 }); + +}); +test("圆弧的切割2", () => +{ + let arc = new Arc(new Vector3(5, 0, 0), 5, Math.PI, 0); + expect(arc.GetSplitCurves([0.5, 0.8, 0.2])[0].StartPoint.distanceTo(new Vector3(0, 0, 0)) < 0.01).toBeTruthy(); + expect(arc.GetSplitCurves([0.5, 0.2, 0.8])[1].EndPoint.distanceTo(new Vector3(5, 5, 0)) < 0.01).toBeTruthy(); + expect(arc.GetSplitCurves([0.2, 0.5, 0.8]).length).toBe(4); +}); + +test("圆弧延伸-反向", () => +{ + let arc = new Arc(new Vector3(5, 0, 0), 5, Math.PI, 0); + arc.Extend(-0.5); + expect(arc.StartPoint.distanceTo(new Vector3(5, -5, 0)) < 0.01).toBeTruthy(); +}); + +test("圆弧延伸-正向", () => +{ + let arc = new Arc(new Vector3(5, 0, 0), 5, Math.PI, 0); + arc.Extend(1.5); + expect(arc.EndPoint.distanceTo(new Vector3(5, -5, 0)) < 0.01).toBeTruthy(); +}); + +test("由距离得到圆弧参数", () => +{ + let arc = new Arc(new Vector3(5, 0, 0), 5, Math.PI, 0); + expect(equaln(arc.GetParamAtDist(0.25 * Math.PI * 5), 0.25)).toBeTruthy(); +} +); +test("由距离得到对应点", () => +{ + let arc = new Arc(new Vector3(5, 0, 0), 5, Math.PI, 0); + + expect(equal(arc.GetPointAtDistance(0.5 * Math.PI * 5), new Vector3(5, 5, 0))).toBeTruthy(); +} +); + +test("由参数得到距离", () => +{ + let arc = new Arc(new Vector3(5, 0, 0), 5, Math.PI, 0); + equaln(arc.GetDistAtParam(0.5), 0.5 * Math.PI * 5) + expect(equaln(arc.GetDistAtParam(0.5), 0.5 * Math.PI * 5)).toBeTruthy(); +} +); +test("由点得到距离", () => +{ + let arc = new Arc(new Vector3(5, 0, 0), 5, Math.PI, 0); + expect(equaln(arc.GetDistAtPoint(new Vector3(5, 5, 0)), 0.5 * Math.PI * 5)).toBeTruthy(); + expect(arc.GetDistAtPoint(new Vector3(10, 0, 0))).toBe(Math.PI * 5); +} +); + +test('圆弧偏移', () => +{ + let arc = new Arc(new Vector3(5, 0, 0), 5, Math.PI, 0); + + for (let d of [0, -10, 20]) + { + let arcs = arc.GetOffsetCurves(d); + + for (let a of arcs) + { + expect(a.Center).toMatchSnapshot(); + expect(a.StartAngle).toMatchSnapshot(); + expect(a.EndAngle).toMatchSnapshot(); + expect(a.Radius).toMatchSnapshot(); + } + } + arc.Reverse(); + + for (let d of [0, -10, 20]) + { + let arcs = arc.GetOffsetCurves(d); + + for (let a of arcs) + { + expect(a.Center).toMatchSnapshot(); + expect(a.StartAngle).toMatchSnapshot(); + expect(a.EndAngle).toMatchSnapshot(); + expect(a.Radius).toMatchSnapshot(); + } + } + + +}); + +test('最近点', () => +{ + let arc = new Arc(new Vector3(5, 0, 0), 5, Math.PI, 0); + + expect(arc.GetClosestPointTo(new Vector3(-5, 0, 0), true)/*?*/).toMatchSnapshot();//0,0,0. + expect(arc.GetClosestPointTo(new Vector3(8, 0, 0), true)/*?*/).toMatchSnapshot();//0,0,0. +}); diff --git a/__test__/Geometry/circle.test.ts b/__test__/Geometry/circle.test.ts new file mode 100644 index 000000000..16b923736 --- /dev/null +++ b/__test__/Geometry/circle.test.ts @@ -0,0 +1,131 @@ +import { Circle } from '../../src/DatabaseServices/Circle'; +import { Vector3, Vector2 } from 'three'; +import { app } from '../../src/ApplicationServices/Application'; +import { Command } from '../../src/Editor/CommandMachine'; +import { PromptStatus } from '../../src/Editor/PromptResult'; +import { RenderType } from '../../src/GraphicsSystem/Enum'; +import { equal, equaln } from '../../src/Geometry/GeUtils'; + +test('圆参数', () => +{ + + let circle = new Circle(new Vector3(5, 0, 0), 5); + + circle.GetParamAtPoint(new Vector3(0, 0, 0))/*?*/ + expect(equaln(circle.GetParamAtPoint(new Vector3(0, 0, 0))/*?*/, 0.5)).toBeTruthy(); + + expect(equaln(circle.GetParamAtPoint(new Vector3(5, 5, 0)), 0.25)).toBeTruthy(); + + expect(equaln(circle.GetParamAtPoint(new Vector3(10, 0, 0)), 0)).toBeTruthy(); + + expect(circle.GetParamAtPoint(new Vector3(-5, -5, 0))).toBe(NaN); + + expect(circle.GetParamAtPoint(new Vector3(10, 0, 0))).toBe(0); + +}); + +test('半径为0的圆,参数', () => +{ + + let circle = new Circle(new Vector3(), 0); + + expect(circle.GetParamAtPoint(new Vector3(0, 0, 0))).toBe(0); + +}); + +test("圆的切割1", () => +{ + let circle = new Circle(new Vector3(5, 0, 0), 5); + let cs = circle.GetSplitCurves(0.5); + expect(cs.length).toBe(0); +}); + +test("圆的切割2", () => +{ + let circle = new Circle(new Vector3(5, 0, 0), 5); + + let cs = circle.GetSplitCurves([0.5, 0.75, 0.25]); + + for (let c of cs) + { + expect(c.StartPoint).toMatchSnapshot() + expect(c.EndPoint).toMatchSnapshot() + } +}); + +test("由距离得到圆参数", () => +{ + let circle = new Circle(new Vector3(5, 0, 0), 5); + expect(equaln(circle.GetParamAtDist(0.5 * Math.PI * 5), 0.25)).toBeTruthy(); +} +); +test("由距离得到对应点", () => +{ + let circle = new Circle(new Vector3(5, 0, 0), 5); + expect(equal(circle.GetPointAtDistance(0.5 * Math.PI * 5), new Vector3(5, 5, 0))).toBeTruthy(); +} +); + +test("由参数得到距离", () => +{ + let circle = new Circle(new Vector3(5, 0, 0), 5); + expect(equaln(circle.GetDistAtParam(0.5), Math.PI * 5)).toBeTruthy(); +} +); +test("由点得到距离", () => +{ + let circle = new Circle(new Vector3(5, 0, 0), 5); + expect(equaln(circle.GetDistAtPoint(new Vector3(5, 5, 0)), 0.5 * Math.PI * 5)).toBeTruthy(); + expect(circle.GetDistAtPoint(new Vector3(10, 0, 0))).toBe(0); +} +); + +test('圆偏移', () => +{ + + let circle = new Circle(new Vector3(5, 0, 0), 5); + let arcs3 = circle.GetOffsetCurves(10); + let arcs = circle.GetOffsetCurves(-3); + + arcs3[0].StartPoint //? + arcs3[0].EndPoint //? + + arcs[0].StartPoint //? + arcs[0].EndPoint //? + // expect(arcs.length).toBe(1); + // expect(arcs.length).toBe(Math.PI * 2); + + let newArc = arcs[0]; + expect(newArc.StartPoint).toMatchSnapshot(); + expect(newArc.EndPoint).toMatchSnapshot(); + + let circle2 = new Circle(new Vector3(10, 0, 0), 10); + let circles2 = circle2.GetOffsetCurves(-5)[0]; //? + circles2.StartPoint //? + circles2.EndPoint //? + expect(circles2.StartPoint).toMatchSnapshot(); + expect(circles2.EndPoint).toMatchSnapshot(); + + circles2 = circle2.GetOffsetCurves(10)[0]; //? + circles2.StartPoint //? + circles2.EndPoint //? + expect(circles2.StartPoint).toMatchSnapshot(); + expect(circles2.EndPoint).toMatchSnapshot(); + + expect(circles2.StartPoint).toMatchSnapshot(); + expect(circles2.EndPoint).toMatchSnapshot(); + circles2 = circle2.GetOffsetCurves(-5)[0]; //? + circles2.StartPoint //? + circles2.EndPoint //? + expect(circles2.StartPoint).toMatchSnapshot(); + expect(circles2.EndPoint).toMatchSnapshot(); +}); + +test('最近点', () => +{ + let circle = new Circle(new Vector3(5, 0, 0), 5); + + expect(circle.GetClosestPointTo(new Vector3(-5, 0, 0), true)/*?*/).toMatchSnapshot();//0,0,0. + expect(circle.GetClosestPointTo(new Vector3(8, 0, 0), true)/*?*/).toMatchSnapshot();//10,0,0. + +}); diff --git a/__test__/Geometry/intersect.test.ts b/__test__/Geometry/intersect.test.ts index b183d8a4c..43f34b545 100644 --- a/__test__/Geometry/intersect.test.ts +++ b/__test__/Geometry/intersect.test.ts @@ -1,7 +1,6 @@ import * as THREE from 'three'; -import { Intersect } from '../../src/Geometry/GeUtils'; - +import { IntersectLAndL } from '../../src/GraphicsSystem/IntersectWith'; test('相交测试', () => { @@ -13,14 +12,13 @@ test('相交测试', () => let p5 = new THREE.Vector3(3, 0, 0); let p6 = new THREE.Vector3(6, 0, 0); - let res = Intersect(p1, p2, p3, p4);/*?*/ - + let res = IntersectLAndL(p1, p2, p3, p4);/*?*/ expect(res).toMatchSnapshot(); - res = Intersect(p1, p2, p5, p6);/*?*/ + res = IntersectLAndL(p1, p2, p5, p6);/*?*/ expect(res).toMatchSnapshot(); - let ins = Intersect( + let ins = IntersectLAndL( new THREE.Vector3(0, 5), new THREE.Vector3(5, 5), new THREE.Vector3(0.5, 1), diff --git a/__test__/Interest/line.test.ts b/__test__/Interest/line.test.ts index 456a32913..e4c19d4f8 100644 --- a/__test__/Interest/line.test.ts +++ b/__test__/Interest/line.test.ts @@ -19,9 +19,9 @@ test('直线相交,共线', () => expect(pts.length).toBe(0); pts = IntersectLineAndLine(l1, l2, IntersectOption.ExtendArg); - expect(pts.length).toBe(1); + expect(pts.length).toBe(0); - pts = IntersectLineAndLine(l1, l2, IntersectOption.ExtendBoth); + pts = IntersectLineAndLine(l1, l2, IntersectOption.ExtendBoth);//? expect(pts.length).toBe(1); }); diff --git a/__test__/Polyline/Intersect.test.ts b/__test__/Polyline/Intersect.test.ts new file mode 100644 index 000000000..b3a1a9df7 --- /dev/null +++ b/__test__/Polyline/Intersect.test.ts @@ -0,0 +1,118 @@ +import { Polyline } from "../../src/DatabaseServices/Polyline"; +import { Vector2, Vector3 } from "three"; +import { IntersectOption } from "../../src/GraphicsSystem/IntersectWith"; +describe("相交", () => +{ + test("不相交曲线", () => + { + let pl = new Polyline([ + { + pt: new Vector2(37, 5), + bul: -1.63 + }, + { + pt: new Vector2(26.7, -4), + bul: 0.32 + }, + ]) + let p2 = new Polyline([ + { + pt: new Vector2(26, -3), + bul: 0.32 + }, + { + pt: new Vector2(9.5, -8.2), + bul: 2.01 + }, + ]) + let pts = pl.IntersectWith(p2, IntersectOption.OnBothOperands); + expect(pts.length).toBe(0); + let pts1 = pl.IntersectWith(p2, IntersectOption.ExtendBoth); + expect(pts1.length).toBe(2); + let pts2 = pl.IntersectWith(p2, IntersectOption.ExtendThis); + expect(pts2.length).toBe(0); + let pts3 = pl.IntersectWith(p2, IntersectOption.ExtendArg); + expect(pts3.length).toBe(1); + }) + test("相交曲线", () => + { + let pl = new Polyline([ + { + pt: new Vector2(0, 0), + bul: 1 + }, + { + pt: new Vector2(0, 5), + bul: 0.32 + }, + ]) + let p2 = new Polyline([ + { + pt: new Vector2(-1, 0), + bul: -1 + }, + { + pt: new Vector2(4, 0), + bul: 0 + }, + ]) + let p3 = new Polyline([ + { + pt: new Vector2(0, 0), + bul: 0 + }, + { + pt: new Vector2(3, 3), + bul: 0 + }, + ]) + let p4 = new Polyline([ + { + pt: new Vector2(0, 0), + bul: 0 + }, + { + pt: new Vector2(1, 1), + bul: 0 + }, + ]) + let p5 = new Polyline([ + { + pt: new Vector2(1, 0), + bul: 0 + }, + { + pt: new Vector2(1, 0.5), + bul: 0 + }, + ]) + let p6 = new Polyline([ + { + pt: new Vector2(0, 0), + bul: 0 + }, + { + pt: new Vector2(3, 3), + bul: 0 + }, + ]) + let pts = pl.IntersectWith(p2, IntersectOption.OnBothOperands); + expect(pts.length).toBe(1); + let pts1 = pl.IntersectWith(p2, IntersectOption.ExtendBoth); + expect(pts1.length).toBe(2); + let pts2 = pl.IntersectWith(p2, IntersectOption.ExtendThis); + expect(pts2.length).toBe(2); + let pts3 = pl.IntersectWith(p2, IntersectOption.ExtendArg); + expect(pts3.length).toBe(1); + let pts4 = pl.IntersectWith(p3, IntersectOption.OnBothOperands); + expect(pts4[0]).toEqual(new Vector3(2.5, 2.5, 0)) + expect(pts4.length).toBe(2); + let pts5 = pl.IntersectWith(p4, IntersectOption.OnBothOperands); + expect(pts5.length).toBe(1); + let pts6 = pl.IntersectWith(p4, IntersectOption.ExtendArg); + expect(pts6.length).toBe(2); + let pts7 = p5.IntersectWith(p6, IntersectOption.ExtendThis); + expect(pts7.length).toBe(1); + }) +}) + diff --git a/__test__/Polyline/PolylineGetPointAtParam.test.ts b/__test__/Polyline/PolylineGetPointAtParam.test.ts new file mode 100644 index 000000000..475fa3539 --- /dev/null +++ b/__test__/Polyline/PolylineGetPointAtParam.test.ts @@ -0,0 +1,85 @@ +import { Vector2 } from "three"; +import { Polyline } from "../../src/DatabaseServices/Polyline"; +import { equaln } from "../../src/Geometry/GeUtils"; + +test('获得点,来自参数', () => +{ + let pl = new Polyline([ + { + pt: new Vector2(0, 0), + bul: 0 + }, + { + pt: new Vector2(5, 0), + bul: 1 + }, + { + pt: new Vector2(5, 5), + bul: -1 + }, + { + pt: new Vector2(5, 10), + bul: 0 + }, + { + pt: new Vector2(0, 10), + bul: 0 + }, + { + pt: new Vector2(0, 0), + bul: 0 + } + ]); + + //不闭合时 + pl.CloseMark = false; + for (let p = -2; p < 7; p += 0.2) + { + let pt = pl.GetPointAtParam(p); + + //反向测试 + if (pt) + { + let pn = pl.GetParamAtPoint(pt); + + if (equaln(pn, 0)) + { + expect(equaln(p, 0) || equaln(p, pl.EndParam)).toBeTruthy(); + } + else + { + expect(equaln(p, pn)).toBeTruthy(); + } + } + //测试一阶导数 + let deriv = pl.GetFistDeriv(p); + expect(deriv).toMatchSnapshot(); + expect(pt).toMatchSnapshot(); + } + //闭合时 + pl.CloseMark = true; + for (let p = -2; p < 7; p += 0.3) + { + let pt = pl.GetPointAtParam(p); + + //反向测试 + if (pt) + { + let pn = pl.GetParamAtPoint(pt); + + if (equaln(pn, 0)) + { + expect(equaln(pn, 0) || equaln(p, pl.EndParam)).toBeTruthy(); + } + else + { + expect(equaln(p, pn)).toBeTruthy(); + } + } + + //测试一阶导数 + let deriv = pl.GetFistDeriv(p); + expect(deriv).toMatchSnapshot(); + expect(pt).toMatchSnapshot(); + } +}); diff --git a/__test__/Polyline/__snapshots__/PolylineGetPointAtParam.test.ts.snap b/__test__/Polyline/__snapshots__/PolylineGetPointAtParam.test.ts.snap new file mode 100644 index 000000000..f319d4fe3 --- /dev/null +++ b/__test__/Polyline/__snapshots__/PolylineGetPointAtParam.test.ts.snap @@ -0,0 +1,1049 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`获得点,来自参数 1`] = ` +Vector3 { + "x": 5, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 2`] = ` +Vector3 { + "x": -10, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 3`] = ` +Vector3 { + "x": 5, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 4`] = ` +Vector3 { + "x": -9, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 5`] = ` +Vector3 { + "x": 5, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 6`] = ` +Vector3 { + "x": -8, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 7`] = ` +Vector3 { + "x": 5, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 8`] = ` +Vector3 { + "x": -7.000000000000001, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 9`] = ` +Vector3 { + "x": 5, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 10`] = ` +Vector3 { + "x": -6.000000000000001, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 11`] = ` +Vector3 { + "x": 5, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 12`] = ` +Vector3 { + "x": -5.000000000000001, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 13`] = ` +Vector3 { + "x": 5, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 14`] = ` +Vector3 { + "x": -4.000000000000002, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 15`] = ` +Vector3 { + "x": 5, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 16`] = ` +Vector3 { + "x": -3.0000000000000018, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 17`] = ` +Vector3 { + "x": 5, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 18`] = ` +Vector3 { + "x": -2.0000000000000013, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 19`] = ` +Vector3 { + "x": 5, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 20`] = ` +Vector3 { + "x": -1.0000000000000013, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 21`] = ` +Vector3 { + "x": 5, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 22`] = ` +Vector3 { + "x": -1.3877787807814457e-15, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 23`] = ` +Vector3 { + "x": 5, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 24`] = ` +Vector3 { + "x": 0.9999999999999987, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 25`] = ` +Vector3 { + "x": 5, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 26`] = ` +Vector3 { + "x": 1.9999999999999987, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 27`] = ` +Vector3 { + "x": 5, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 28`] = ` +Vector3 { + "x": 2.9999999999999987, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 29`] = ` +Vector3 { + "x": 5, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 30`] = ` +Vector3 { + "x": 3.999999999999999, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 31`] = ` +Vector3 { + "x": 5, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 32`] = ` +Vector3 { + "x": 4.999999999999999, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 33`] = ` +Vector3 { + "x": 2.0225424859373704, + "y": 1.4694631307311807, + "z": 0, +} +`; + +exports[`获得点,来自参数 34`] = ` +Vector3 { + "x": 6.469463130731181, + "y": 0.4774575140626296, + "z": 0, +} +`; + +exports[`获得点,来自参数 35`] = ` +Vector3 { + "x": 0.7725424859373714, + "y": 2.377641290737883, + "z": 0, +} +`; + +exports[`获得点,来自参数 36`] = ` +Vector3 { + "x": 7.377641290737883, + "y": 1.7274575140626287, + "z": 0, +} +`; + +exports[`获得点,来自参数 37`] = ` +Vector3 { + "x": -0.7725424859373677, + "y": 2.377641290737884, + "z": 0, +} +`; + +exports[`获得点,来自参数 38`] = ` +Vector3 { + "x": 7.377641290737885, + "y": 3.272542485937366, + "z": 0, +} +`; + +exports[`获得点,来自参数 39`] = ` +Vector3 { + "x": -2.0225424859373655, + "y": 1.469463130731187, + "z": 0, +} +`; + +exports[`获得点,来自参数 40`] = ` +Vector3 { + "x": 6.469463130731187, + "y": 4.5225424859373655, + "z": 0, +} +`; + +exports[`获得点,来自参数 41`] = ` +Vector3 { + "x": -2.5, + "y": 5.3593771978611406e-15, + "z": 0, +} +`; + +exports[`获得点,来自参数 42`] = ` +Vector3 { + "x": 5.000000000000005, + "y": 5, + "z": 0, +} +`; + +exports[`获得点,来自参数 43`] = ` +Vector3 { + "x": -2.02254248593737, + "y": 1.4694631307311812, + "z": 0, +} +`; + +exports[`获得点,来自参数 44`] = ` +Vector3 { + "x": 3.5305368692688184, + "y": 5.47745751406263, + "z": 0, +} +`; + +exports[`获得点,来自参数 45`] = ` +Vector3 { + "x": -0.7725424859373684, + "y": 2.377641290737884, + "z": 0, +} +`; + +exports[`获得点,来自参数 46`] = ` +Vector3 { + "x": 2.622358709262116, + "y": 6.727457514062632, + "z": 0, +} +`; + +exports[`获得点,来自参数 47`] = ` +Vector3 { + "x": 0.7725424859373686, + "y": 2.3776412907378837, + "z": 0, +} +`; + +exports[`获得点,来自参数 48`] = ` +Vector3 { + "x": 2.6223587092621163, + "y": 8.272542485937368, + "z": 0, +} +`; + +exports[`获得点,来自参数 49`] = ` +Vector3 { + "x": 2.02254248593737, + "y": 1.469463130731181, + "z": 0, +} +`; + +exports[`获得点,来自参数 50`] = ` +Vector3 { + "x": 3.5305368692688193, + "y": 9.52254248593737, + "z": 0, +} +`; + +exports[`获得点,来自参数 51`] = ` +Vector3 { + "x": -5, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 52`] = ` +Vector3 { + "x": 4.999999999999998, + "y": 10, + "z": 0, +} +`; + +exports[`获得点,来自参数 53`] = ` +Vector3 { + "x": -5, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 54`] = ` +Vector3 { + "x": 3.999999999999997, + "y": 10, + "z": 0, +} +`; + +exports[`获得点,来自参数 55`] = ` +Vector3 { + "x": -5, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 56`] = ` +Vector3 { + "x": 2.999999999999996, + "y": 10, + "z": 0, +} +`; + +exports[`获得点,来自参数 57`] = ` +Vector3 { + "x": -5, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 58`] = ` +Vector3 { + "x": 1.9999999999999951, + "y": 10, + "z": 0, +} +`; + +exports[`获得点,来自参数 59`] = ` +Vector3 { + "x": -5, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 60`] = ` +Vector3 { + "x": 0.9999999999999947, + "y": 10, + "z": 0, +} +`; + +exports[`获得点,来自参数 61`] = ` +Vector3 { + "x": 0, + "y": -10, + "z": 0, +} +`; + +exports[`获得点,来自参数 62`] = ` +Vector3 { + "x": 0, + "y": 9.999999999999991, + "z": 0, +} +`; + +exports[`获得点,来自参数 63`] = ` +Vector3 { + "x": 0, + "y": -10, + "z": 0, +} +`; + +exports[`获得点,来自参数 64`] = ` +Vector3 { + "x": 0, + "y": 7.999999999999989, + "z": 0, +} +`; + +exports[`获得点,来自参数 65`] = ` +Vector3 { + "x": 0, + "y": -10, + "z": 0, +} +`; + +exports[`获得点,来自参数 66`] = ` +Vector3 { + "x": 0, + "y": 5.999999999999988, + "z": 0, +} +`; + +exports[`获得点,来自参数 67`] = ` +Vector3 { + "x": 0, + "y": -10, + "z": 0, +} +`; + +exports[`获得点,来自参数 68`] = ` +Vector3 { + "x": 0, + "y": 3.999999999999986, + "z": 0, +} +`; + +exports[`获得点,来自参数 69`] = ` +Vector3 { + "x": 0, + "y": -10, + "z": 0, +} +`; + +exports[`获得点,来自参数 70`] = ` +Vector3 { + "x": 0, + "y": 1.999999999999984, + "z": 0, +} +`; + +exports[`获得点,来自参数 71`] = ` +Vector3 { + "x": 0, + "y": -10, + "z": 0, +} +`; + +exports[`获得点,来自参数 72`] = ` +Vector3 { + "x": 0, + "y": -1.7763568394002505e-14, + "z": 0, +} +`; + +exports[`获得点,来自参数 73`] = ` +Vector3 { + "x": 0, + "y": -10, + "z": 0, +} +`; + +exports[`获得点,来自参数 74`] = ` +Vector3 { + "x": 0, + "y": -2.0000000000000195, + "z": 0, +} +`; + +exports[`获得点,来自参数 75`] = ` +Vector3 { + "x": 0, + "y": -10, + "z": 0, +} +`; + +exports[`获得点,来自参数 76`] = ` +Vector3 { + "x": 0, + "y": -4.000000000000021, + "z": 0, +} +`; + +exports[`获得点,来自参数 77`] = ` +Vector3 { + "x": 0, + "y": -10, + "z": 0, +} +`; + +exports[`获得点,来自参数 78`] = ` +Vector3 { + "x": 0, + "y": -6.000000000000021, + "z": 0, +} +`; + +exports[`获得点,来自参数 79`] = ` +Vector3 { + "x": 0, + "y": -10, + "z": 0, +} +`; + +exports[`获得点,来自参数 80`] = ` +Vector3 { + "x": 0, + "y": -8.000000000000025, + "z": 0, +} +`; + +exports[`获得点,来自参数 81`] = ` +Vector3 { + "x": 0, + "y": -10, + "z": 0, +} +`; + +exports[`获得点,来自参数 82`] = ` +Vector3 { + "x": 0, + "y": -10.000000000000028, + "z": 0, +} +`; + +exports[`获得点,来自参数 83`] = ` +Vector3 { + "x": 0, + "y": -10, + "z": 0, +} +`; + +exports[`获得点,来自参数 84`] = ` +Vector3 { + "x": 0, + "y": -12.000000000000028, + "z": 0, +} +`; + +exports[`获得点,来自参数 85`] = ` +Vector3 { + "x": 0, + "y": -10, + "z": 0, +} +`; + +exports[`获得点,来自参数 86`] = ` +Vector3 { + "x": 0, + "y": -14.000000000000028, + "z": 0, +} +`; + +exports[`获得点,来自参数 87`] = ` +Vector3 { + "x": 0, + "y": -10, + "z": 0, +} +`; + +exports[`获得点,来自参数 88`] = ` +Vector3 { + "x": 0, + "y": -16.000000000000032, + "z": 0, +} +`; + +exports[`获得点,来自参数 89`] = ` +Vector3 { + "x": 0, + "y": -10, + "z": 0, +} +`; + +exports[`获得点,来自参数 90`] = ` +Vector3 { + "x": 0, + "y": -18.000000000000036, + "z": 0, +} +`; + +exports[`获得点,来自参数 91`] = `undefined`; + +exports[`获得点,来自参数 92`] = `undefined`; + +exports[`获得点,来自参数 93`] = `undefined`; + +exports[`获得点,来自参数 94`] = `undefined`; + +exports[`获得点,来自参数 95`] = `undefined`; + +exports[`获得点,来自参数 96`] = `undefined`; + +exports[`获得点,来自参数 97`] = `undefined`; + +exports[`获得点,来自参数 98`] = `undefined`; + +exports[`获得点,来自参数 99`] = `undefined`; + +exports[`获得点,来自参数 100`] = `undefined`; + +exports[`获得点,来自参数 101`] = `undefined`; + +exports[`获得点,来自参数 102`] = `undefined`; + +exports[`获得点,来自参数 103`] = `undefined`; + +exports[`获得点,来自参数 104`] = `undefined`; + +exports[`获得点,来自参数 105`] = ` +Vector3 { + "x": 5, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 106`] = ` +Vector3 { + "x": 0.5000000000000007, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 107`] = ` +Vector3 { + "x": 5, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 108`] = ` +Vector3 { + "x": 2.000000000000001, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 109`] = ` +Vector3 { + "x": 5, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 110`] = ` +Vector3 { + "x": 3.500000000000001, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 111`] = ` +Vector3 { + "x": 2.5, + "y": 1.6081226496766366e-15, + "z": 0, +} +`; + +exports[`获得点,来自参数 112`] = ` +Vector3 { + "x": 5.000000000000002, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 113`] = ` +Vector3 { + "x": 1.4694631307311816, + "y": 2.0225424859373695, + "z": 0, +} +`; + +exports[`获得点,来自参数 114`] = ` +Vector3 { + "x": 7.02254248593737, + "y": 1.0305368692688186, + "z": 0, +} +`; + +exports[`获得点,来自参数 115`] = ` +Vector3 { + "x": -0.7725424859373677, + "y": 2.377641290737884, + "z": 0, +} +`; + +exports[`获得点,来自参数 116`] = ` +Vector3 { + "x": 7.377641290737884, + "y": 3.27254248593737, + "z": 0, +} +`; + +exports[`获得点,来自参数 117`] = ` +Vector3 { + "x": -2.377641290737885, + "y": 0.7725424859373652, + "z": 0, +} +`; + +exports[`获得点,来自参数 118`] = ` +Vector3 { + "x": 5.772542485937365, + "y": 4.877641290737885, + "z": 0, +} +`; + +exports[`获得点,来自参数 119`] = ` +Vector3 { + "x": -2.022542485937367, + "y": 1.4694631307311847, + "z": 0, +} +`; + +exports[`获得点,来自参数 120`] = ` +Vector3 { + "x": 3.530536869268815, + "y": 5.477457514062634, + "z": 0, +} +`; + +exports[`获得点,来自参数 121`] = ` +Vector3 { + "x": 1.5308084989341916e-16, + "y": 2.5, + "z": 0, +} +`; + +exports[`获得点,来自参数 122`] = ` +Vector3 { + "x": 2.5, + "y": 7.5, + "z": 0, +} +`; + +exports[`获得点,来自参数 123`] = ` +Vector3 { + "x": 2.022542485937368, + "y": 1.4694631307311836, + "z": 0, +} +`; + +exports[`获得点,来自参数 124`] = ` +Vector3 { + "x": 3.5305368692688166, + "y": 9.522542485937368, + "z": 0, +} +`; + +exports[`获得点,来自参数 125`] = ` +Vector3 { + "x": -5, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 126`] = ` +Vector3 { + "x": 4.500000000000002, + "y": 10, + "z": 0, +} +`; + +exports[`获得点,来自参数 127`] = ` +Vector3 { + "x": -5, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 128`] = ` +Vector3 { + "x": 3.0000000000000027, + "y": 10, + "z": 0, +} +`; + +exports[`获得点,来自参数 129`] = ` +Vector3 { + "x": -5, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 130`] = ` +Vector3 { + "x": 1.5000000000000036, + "y": 10, + "z": 0, +} +`; + +exports[`获得点,来自参数 131`] = ` +Vector3 { + "x": -5, + "y": 0, + "z": 0, +} +`; + +exports[`获得点,来自参数 132`] = ` +Vector3 { + "x": 4.440892098500626e-15, + "y": 10, + "z": 0, +} +`; + +exports[`获得点,来自参数 133`] = ` +Vector3 { + "x": 0, + "y": -10, + "z": 0, +} +`; + +exports[`获得点,来自参数 134`] = ` +Vector3 { + "x": 0, + "y": 7.000000000000011, + "z": 0, +} +`; + +exports[`获得点,来自参数 135`] = ` +Vector3 { + "x": 0, + "y": -10, + "z": 0, +} +`; + +exports[`获得点,来自参数 136`] = ` +Vector3 { + "x": 0, + "y": 4.000000000000012, + "z": 0, +} +`; + +exports[`获得点,来自参数 137`] = ` +Vector3 { + "x": 0, + "y": -10, + "z": 0, +} +`; + +exports[`获得点,来自参数 138`] = ` +Vector3 { + "x": 0, + "y": 1.0000000000000142, + "z": 0, +} +`; + +exports[`获得点,来自参数 139`] = `undefined`; + +exports[`获得点,来自参数 140`] = `undefined`; + +exports[`获得点,来自参数 141`] = `undefined`; + +exports[`获得点,来自参数 142`] = `undefined`; + +exports[`获得点,来自参数 143`] = `undefined`; + +exports[`获得点,来自参数 144`] = `undefined`; + +exports[`获得点,来自参数 145`] = `undefined`; + +exports[`获得点,来自参数 146`] = `undefined`; + +exports[`获得点,来自参数 147`] = `undefined`; + +exports[`获得点,来自参数 148`] = `undefined`; + +exports[`获得点,来自参数 149`] = `undefined`; + +exports[`获得点,来自参数 150`] = `undefined`; + +exports[`获得点,来自参数 151`] = `undefined`; + +exports[`获得点,来自参数 152`] = `undefined`; diff --git a/__test__/Polyline/__snapshots__/split.test.ts.snap b/__test__/Polyline/__snapshots__/split.test.ts.snap new file mode 100644 index 000000000..bc3e83fa3 --- /dev/null +++ b/__test__/Polyline/__snapshots__/split.test.ts.snap @@ -0,0 +1,1305 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`单刀 1`] = ` +Array [ + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 0, + }, + }, + Object { + "bul": 1, + "pt": Vector2 { + "x": 5, + "y": 0, + }, + }, + Object { + "bul": -1, + "pt": Vector2 { + "x": 5, + "y": 5, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 5, + "y": 10, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 10, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 0, + }, + }, +] +`; + +exports[`单刀 2`] = ` +Array [ + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 0, + }, + }, + Object { + "bul": 0.41421356237309503, + "pt": Vector2 { + "x": 5, + "y": 0, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 7.5, + "y": 2.4999999999999996, + }, + }, +] +`; + +exports[`单刀 3`] = ` +Array [ + Object { + "bul": 0.41421356237309503, + "pt": Vector2 { + "x": 7.5, + "y": 2.4999999999999996, + }, + }, + Object { + "bul": -1, + "pt": Vector2 { + "x": 5, + "y": 5, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 5, + "y": 10, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 10, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 0, + }, + }, +] +`; + +exports[`单刀 4`] = ` +Array [ + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 0, + }, + }, + Object { + "bul": 1, + "pt": Vector2 { + "x": 5, + "y": 0, + }, + }, + Object { + "bul": -1, + "pt": Vector2 { + "x": 5, + "y": 5, + }, + }, +] +`; + +exports[`单刀 5`] = ` +Array [ + Object { + "bul": -0.9999999999999999, + "pt": Vector2 { + "x": 5, + "y": 5, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 5, + "y": 10, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 10, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 0, + }, + }, +] +`; + +exports[`单刀 6`] = ` +Array [ + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 0, + }, + }, + Object { + "bul": 1, + "pt": Vector2 { + "x": 5, + "y": 0, + }, + }, + Object { + "bul": -0.41421356237309503, + "pt": Vector2 { + "x": 5, + "y": 5, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 2.5, + "y": 7.5, + }, + }, +] +`; + +exports[`单刀 7`] = ` +Array [ + Object { + "bul": -0.41421356237309503, + "pt": Vector2 { + "x": 2.5, + "y": 7.5, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 5, + "y": 10, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 10, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 0, + }, + }, +] +`; + +exports[`单刀 8`] = ` +Array [ + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 0, + }, + }, + Object { + "bul": 1, + "pt": Vector2 { + "x": 5, + "y": 0, + }, + }, + Object { + "bul": -1, + "pt": Vector2 { + "x": 5, + "y": 5, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 5, + "y": 10, + }, + }, +] +`; + +exports[`单刀 9`] = ` +Array [ + Object { + "bul": 0, + "pt": Vector2 { + "x": 5, + "y": 10, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 10, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 0, + }, + }, +] +`; + +exports[`单刀闭合 1`] = ` +Array [ + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 0, + }, + }, + Object { + "bul": 1, + "pt": Vector2 { + "x": 5, + "y": 0, + }, + }, + Object { + "bul": -1, + "pt": Vector2 { + "x": 5, + "y": 5, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 5, + "y": 10, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 10, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 0, + }, + }, +] +`; + +exports[`单刀闭合 2`] = ` +Array [ + Object { + "bul": 0.41421356237309503, + "pt": Vector2 { + "x": 7.5, + "y": 2.4999999999999996, + }, + }, + Object { + "bul": -1, + "pt": Vector2 { + "x": 5, + "y": 5, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 5, + "y": 10, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 10, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 0, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 0, + }, + }, + Object { + "bul": 0.41421356237309503, + "pt": Vector2 { + "x": 5, + "y": 0, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 7.5, + "y": 2.4999999999999996, + }, + }, +] +`; + +exports[`单刀闭合 3`] = ` +Array [ + Object { + "bul": -0.9999999999999999, + "pt": Vector2 { + "x": 5, + "y": 5, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 5, + "y": 10, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 10, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 0, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 0, + }, + }, + Object { + "bul": 1, + "pt": Vector2 { + "x": 5, + "y": 0, + }, + }, + Object { + "bul": -1, + "pt": Vector2 { + "x": 5, + "y": 5, + }, + }, +] +`; + +exports[`单刀闭合 4`] = ` +Array [ + Object { + "bul": -0.41421356237309503, + "pt": Vector2 { + "x": 2.5, + "y": 7.5, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 5, + "y": 10, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 10, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 0, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 0, + }, + }, + Object { + "bul": 1, + "pt": Vector2 { + "x": 5, + "y": 0, + }, + }, + Object { + "bul": -0.41421356237309503, + "pt": Vector2 { + "x": 5, + "y": 5, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 2.5, + "y": 7.5, + }, + }, +] +`; + +exports[`单刀闭合 5`] = ` +Array [ + Object { + "bul": 0, + "pt": Vector2 { + "x": 5, + "y": 10, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 10, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 0, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 0, + }, + }, + Object { + "bul": 1, + "pt": Vector2 { + "x": 5, + "y": 0, + }, + }, + Object { + "bul": -1, + "pt": Vector2 { + "x": 5, + "y": 5, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 5, + "y": 10, + }, + }, +] +`; + +exports[`多切刀 1`] = ` +Array [ + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 0, + }, + }, + Object { + "bul": 1, + "pt": Vector2 { + "x": 5, + "y": 0, + }, + }, +] +`; + +exports[`多切刀 2`] = ` +Array [ + Object { + "bul": 0.15838444032453625, + "pt": Vector2 { + "x": 5, + "y": 0, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 6.4694631307311825, + "y": 0.4774575140626309, + }, + }, +] +`; + +exports[`多切刀 3`] = ` +Array [ + Object { + "bul": 0.24007875908011606, + "pt": Vector2 { + "x": 6.4694631307311825, + "y": 0.4774575140626309, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 7.5, + "y": 2.4999999999999996, + }, + }, +] +`; + +exports[`多切刀 4`] = ` +Array [ + Object { + "bul": 0.24007875908011606, + "pt": Vector2 { + "x": 7.5, + "y": 2.4999999999999996, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 6.469463130731183, + "y": 4.522542485937368, + }, + }, +] +`; + +exports[`多切刀 5`] = ` +Array [ + Object { + "bul": 0.15838444032453625, + "pt": Vector2 { + "x": 6.469463130731183, + "y": 4.522542485937368, + }, + }, + Object { + "bul": -1, + "pt": Vector2 { + "x": 5, + "y": 5, + }, + }, +] +`; + +exports[`多切刀 6`] = ` +Array [ + Object { + "bul": -0.15838444032453644, + "pt": Vector2 { + "x": 5, + "y": 5, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 3.530536869268815, + "y": 5.477457514062634, + }, + }, +] +`; + +exports[`多切刀 7`] = ` +Array [ + Object { + "bul": -0.2400787590801159, + "pt": Vector2 { + "x": 3.530536869268815, + "y": 5.477457514062634, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 2.5, + "y": 7.5, + }, + }, +] +`; + +exports[`多切刀 8`] = ` +Array [ + Object { + "bul": -0.2400787590801159, + "pt": Vector2 { + "x": 2.5, + "y": 7.5, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 3.5305368692688166, + "y": 9.522542485937368, + }, + }, +] +`; + +exports[`多切刀 9`] = ` +Array [ + Object { + "bul": -0.15838444032453644, + "pt": Vector2 { + "x": 3.5305368692688166, + "y": 9.522542485937368, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 5, + "y": 10, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 10, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 0, + }, + }, +] +`; + +exports[`多切刀 10`] = ` +Array [ + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 0, + }, + }, + Object { + "bul": 1, + "pt": Vector2 { + "x": 5, + "y": 0, + }, + }, +] +`; + +exports[`多切刀 11`] = ` +Array [ + Object { + "bul": 0.15838444032453625, + "pt": Vector2 { + "x": 5, + "y": 0, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 6.4694631307311825, + "y": 0.4774575140626309, + }, + }, +] +`; + +exports[`多切刀 12`] = ` +Array [ + Object { + "bul": 0.24007875908011606, + "pt": Vector2 { + "x": 6.4694631307311825, + "y": 0.4774575140626309, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 7.5, + "y": 2.4999999999999996, + }, + }, +] +`; + +exports[`多切刀 13`] = ` +Array [ + Object { + "bul": 0.24007875908011606, + "pt": Vector2 { + "x": 7.5, + "y": 2.4999999999999996, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 6.469463130731183, + "y": 4.522542485937368, + }, + }, +] +`; + +exports[`多切刀 14`] = ` +Array [ + Object { + "bul": 0.15838444032453625, + "pt": Vector2 { + "x": 6.469463130731183, + "y": 4.522542485937368, + }, + }, + Object { + "bul": -1, + "pt": Vector2 { + "x": 5, + "y": 5, + }, + }, +] +`; + +exports[`多切刀 15`] = ` +Array [ + Object { + "bul": -0.15838444032453644, + "pt": Vector2 { + "x": 5, + "y": 5, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 3.530536869268815, + "y": 5.477457514062634, + }, + }, +] +`; + +exports[`多切刀 16`] = ` +Array [ + Object { + "bul": -0.2400787590801159, + "pt": Vector2 { + "x": 3.530536869268815, + "y": 5.477457514062634, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 2.5, + "y": 7.5, + }, + }, +] +`; + +exports[`多切刀 17`] = ` +Array [ + Object { + "bul": -0.2400787590801159, + "pt": Vector2 { + "x": 2.5, + "y": 7.5, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 3.5305368692688166, + "y": 9.522542485937368, + }, + }, +] +`; + +exports[`多切刀 18`] = ` +Array [ + Object { + "bul": -0.15838444032453644, + "pt": Vector2 { + "x": 3.5305368692688166, + "y": 9.522542485937368, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 5, + "y": 10, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 10, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 0, + }, + }, +] +`; + +exports[`多切刀闭合 1`] = ` +Array [ + Object { + "bul": 0.15838444032453625, + "pt": Vector2 { + "x": 5, + "y": 0, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 6.4694631307311825, + "y": 0.4774575140626309, + }, + }, +] +`; + +exports[`多切刀闭合 2`] = ` +Array [ + Object { + "bul": 0.24007875908011606, + "pt": Vector2 { + "x": 6.4694631307311825, + "y": 0.4774575140626309, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 7.5, + "y": 2.4999999999999996, + }, + }, +] +`; + +exports[`多切刀闭合 3`] = ` +Array [ + Object { + "bul": 0.24007875908011606, + "pt": Vector2 { + "x": 7.5, + "y": 2.4999999999999996, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 6.469463130731183, + "y": 4.522542485937368, + }, + }, +] +`; + +exports[`多切刀闭合 4`] = ` +Array [ + Object { + "bul": 0.15838444032453625, + "pt": Vector2 { + "x": 6.469463130731183, + "y": 4.522542485937368, + }, + }, + Object { + "bul": -1, + "pt": Vector2 { + "x": 5, + "y": 5, + }, + }, +] +`; + +exports[`多切刀闭合 5`] = ` +Array [ + Object { + "bul": -0.15838444032453644, + "pt": Vector2 { + "x": 5, + "y": 5, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 3.530536869268815, + "y": 5.477457514062634, + }, + }, +] +`; + +exports[`多切刀闭合 6`] = ` +Array [ + Object { + "bul": -0.2400787590801159, + "pt": Vector2 { + "x": 3.530536869268815, + "y": 5.477457514062634, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 2.5, + "y": 7.5, + }, + }, +] +`; + +exports[`多切刀闭合 7`] = ` +Array [ + Object { + "bul": -0.2400787590801159, + "pt": Vector2 { + "x": 2.5, + "y": 7.5, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 3.5305368692688166, + "y": 9.522542485937368, + }, + }, +] +`; + +exports[`多切刀闭合 8`] = ` +Array [ + Object { + "bul": -0.15838444032453644, + "pt": Vector2 { + "x": 3.5305368692688166, + "y": 9.522542485937368, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 5, + "y": 10, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 10, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 0, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 0, + }, + }, + Object { + "bul": 1, + "pt": Vector2 { + "x": 5, + "y": 0, + }, + }, +] +`; + +exports[`多切刀闭合 9`] = ` +Array [ + Object { + "bul": 0.15838444032453625, + "pt": Vector2 { + "x": 5, + "y": 0, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 6.4694631307311825, + "y": 0.4774575140626309, + }, + }, +] +`; + +exports[`多切刀闭合 10`] = ` +Array [ + Object { + "bul": 0.24007875908011606, + "pt": Vector2 { + "x": 6.4694631307311825, + "y": 0.4774575140626309, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 7.5, + "y": 2.4999999999999996, + }, + }, +] +`; + +exports[`多切刀闭合 11`] = ` +Array [ + Object { + "bul": 0.24007875908011606, + "pt": Vector2 { + "x": 7.5, + "y": 2.4999999999999996, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 6.469463130731183, + "y": 4.522542485937368, + }, + }, +] +`; + +exports[`多切刀闭合 12`] = ` +Array [ + Object { + "bul": 0.15838444032453625, + "pt": Vector2 { + "x": 6.469463130731183, + "y": 4.522542485937368, + }, + }, + Object { + "bul": -1, + "pt": Vector2 { + "x": 5, + "y": 5, + }, + }, +] +`; + +exports[`多切刀闭合 13`] = ` +Array [ + Object { + "bul": -0.15838444032453644, + "pt": Vector2 { + "x": 5, + "y": 5, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 3.530536869268815, + "y": 5.477457514062634, + }, + }, +] +`; + +exports[`多切刀闭合 14`] = ` +Array [ + Object { + "bul": -0.2400787590801159, + "pt": Vector2 { + "x": 3.530536869268815, + "y": 5.477457514062634, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 2.5, + "y": 7.5, + }, + }, +] +`; + +exports[`多切刀闭合 15`] = ` +Array [ + Object { + "bul": -0.2400787590801159, + "pt": Vector2 { + "x": 2.5, + "y": 7.5, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 3.5305368692688166, + "y": 9.522542485937368, + }, + }, +] +`; + +exports[`多切刀闭合 16`] = ` +Array [ + Object { + "bul": -0.15838444032453644, + "pt": Vector2 { + "x": 3.5305368692688166, + "y": 9.522542485937368, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 5, + "y": 10, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 10, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 0, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 0, + }, + }, + Object { + "bul": 1, + "pt": Vector2 { + "x": 5, + "y": 0, + }, + }, +] +`; diff --git a/__test__/Polyline/polyline.test.ts b/__test__/Polyline/polyline.test.ts new file mode 100644 index 000000000..7ea193074 --- /dev/null +++ b/__test__/Polyline/polyline.test.ts @@ -0,0 +1,472 @@ +import { Vector2, Vector3 } from 'three'; + +import { Polyline } from '../../src/DatabaseServices/Polyline'; +import { equal, equaln } from '../../src/Geometry/GeUtils'; + +test("多段线点获取参数", () => +{ + let pl = new Polyline([ + { + pt: new Vector2(0, 0), + bul: 0 + }, + { + pt: new Vector2(5, 0), + bul: 1 + }, + { + pt: new Vector2(5, 5), + bul: -1 + }, + { + pt: new Vector2(5, 10), + bul: 0 + }, + { + pt: new Vector2(0, 10), + bul: 0 + }, + { + pt: new Vector2(0, 0), + bul: 0 + } + ]) + expect(pl.GetParamAtPoint(new Vector3(5, 0, 0))).toBe(1); + expect(pl.GetParamAtPoint(new Vector3(6, 0, 0)) /*?*/).toBe(NaN); + expect(pl.GetParamAtPoint(new Vector3(-2.5, 0, 0))/*?*/).toBe(-0.5); + expect(pl.GetParamAtPoint(new Vector3(7.5, 2.5, 0))).toBe(1.5); + expect(pl.GetParamAtPoint(new Vector3(5, 5, 0))).toBe(2); + expect(pl.GetParamAtPoint(pl.GetPointAtParam(1.25)) /*?*/).toBe(1.25); + expect(equaln(pl.GetParamAtPoint(new Vector3(0, 5, 0)), 4.5)).toBeTruthy(); + expect(pl.GetParamAtPoint(new Vector3(0, -5, 0))).toBe(5.5); + expect(pl.GetParamAtPoint(new Vector3(0, 10, 0))).toBe(4); + + let pl2 = new Polyline([ + { + pt: new Vector2(1.5, 8.5), + bul: 0 + }, + { + pt: new Vector2(1.5, 1.5), + bul: 0 + } + ]) + expect(pl2.GetParamAtPoint(new Vector3(1.5, 5))).toBe(0.5) + +}) + +describe('多段线', () => +{ + + test("多段线参数获取点", () => + { + let pl = new Polyline([ + { + pt: new Vector2(0, 0), + bul: 0 + }, + { + pt: new Vector2(5, 0), + bul: 1 + }, + { + pt: new Vector2(5, 5), + bul: -1 + }, + { + pt: new Vector2(5, 10), + bul: 0 + }, + { + pt: new Vector2(0, 10), + bul: 0 + }, + { + pt: new Vector2(0, 0), + bul: 0 + } + ]) + + expect(equal(pl.GetPointAtParam(1), new Vector3(5, 0, 0))).toBeTruthy(); + expect(equal(pl.GetPointAtParam(0.5), new Vector3(2.5, 0, 0))).toBeTruthy(); + expect(equal(pl.GetPointAtParam(-0.5), new Vector3(-2.5, 0, 0))).toBeTruthy(); + expect(equal(pl.GetPointAtParam(4.5), new Vector3(0, 5, 0))).toBeTruthy(); + expect(equal(pl.GetPointAtParam(5), new Vector3(0, 0, 0))).toBeTruthy(); + expect(equal(pl.GetPointAtParam(5.5), new Vector3(0, -5, 0))).toBeTruthy(); + }) + test("多段线参数获取弧长", () => + { + let pl = new Polyline([ + { + pt: new Vector2(0, 0), + bul: 0 + }, + { + pt: new Vector2(5, 0), + bul: 1 + }, + { + pt: new Vector2(5, 5), + bul: -1 + }, + { + pt: new Vector2(5, 10), + bul: 0 + }, + { + pt: new Vector2(0, 10), + bul: 0 + }, + { + pt: new Vector2(0, 0), + bul: 0 + } + ]) + expect(pl.GetDistAtParam(1)).toBe(5); + expect(pl.GetDistAtParam(2)).toBe(5 + Math.PI * 2.5); + expect(pl.GetDistAtParam(1.5)).toBe(5 + Math.PI * 2.5 / 2); + expect(pl.GetDistAtParam(3)).toBe(5 + Math.PI * 5); + expect(pl.GetDistAtParam(4)).toBe(5 + Math.PI * 5 + 5); + expect(pl.GetDistAtParam(3.5)).toBe(5 + Math.PI * 5 + 2.5); + }) + test("多段线弧长获取点", () => + { + let pl = new Polyline([ + { + pt: new Vector2(0, 0), + bul: 0 + }, + { + pt: new Vector2(5, 0), + bul: 1 + }, + { + pt: new Vector2(5, 5), + bul: -1 + }, + { + pt: new Vector2(5, 10), + bul: 0 + }, + { + pt: new Vector2(0, 10), + bul: 0 + }, + { + pt: new Vector2(0, 0), + bul: 0 + } + ]) + expect(equal(pl.GetPointAtDistance(5), new Vector3(5, 0, 0))).toBeTruthy(); + expect(equal(pl.GetPointAtDistance(2.5), new Vector3(2.5, 0, 0))).toBeTruthy(); + expect(equal(pl.GetPointAtDistance(5 + Math.PI * 2.5), new Vector3(5, 5, 0))).toBeTruthy(); + expect(equal(pl.GetPointAtDistance(5 + Math.PI * 2.5 * 2), new Vector3(5, 10, 0))).toBeTruthy(); + expect(equal(pl.GetPointAtDistance(0), new Vector3(0, 0, 0))).toBeTruthy(); + }) + test("多段线距离获取参数", () => + { + let pl = new Polyline([ + { + pt: new Vector2(0, 0), + bul: 0 + }, + { + pt: new Vector2(5, 0), + bul: 1 + }, + { + pt: new Vector2(5, 5), + bul: -1 + }, + { + pt: new Vector2(5, 10), + bul: 0 + }, + { + pt: new Vector2(0, 10), + bul: 0 + }, + { + pt: new Vector2(0, 0), + bul: 0 + } + ]) + expect(pl.GetParamAtDist(5)).toBe(1); + expect(pl.GetParamAtDist(5 + Math.PI * 2.5)).toBe(2); + expect(pl.GetParamAtDist(5 + Math.PI * 2.5 / 2)).toBe(1.5); + }) + test("多段线点获取弧长", () => + { + let pl = new Polyline([ + { + pt: new Vector2(0, 0), + bul: 0 + }, + { + pt: new Vector2(5, 0), + bul: 1 + }, + { + pt: new Vector2(5, 5), + bul: -1 + }, + { + pt: new Vector2(5, 10), + bul: 0 + }, + { + pt: new Vector2(0, 10), + bul: 0 + }, + { + pt: new Vector2(0, 0), + bul: 0 + } + ]) + expect(pl.GetDistAtPoint(new Vector3(0, 0, 0))).toBe(0); + expect(pl.GetDistAtPoint(new Vector3(5, 0, 0))).toBe(5); + expect(pl.GetDistAtPoint(new Vector3(7.5, 2.5, 0))).toBe(5 + Math.PI / 2 * 2.5); + expect(pl.GetDistAtPoint(new Vector3(7.5, 2.5, 0))).toBe(5 + Math.PI / 2 * 2.5); + expect(equaln(pl.Length, 20 + 2 * Math.PI * 2.5)).toBeTruthy(); + }) + test("多段线延伸,不闭合", () => + { + let pl = new Polyline([ + { + pt: new Vector2(0, 0), + bul: 0 + }, + { + pt: new Vector2(5, 0), + bul: 1 + }, + { + pt: new Vector2(5, 5), + bul: -1 + }, + { + pt: new Vector2(5, 10), + bul: 0 + }, + { + pt: new Vector2(0, 10), + bul: 0 + }, + { + pt: new Vector2(0, 0), + bul: 0 + } + ]) + let pl2 = new Polyline([ + { + pt: new Vector2(0, 0), + bul: 0 + }, + { + pt: new Vector2(5, 0), + bul: 1 + }, + { + pt: new Vector2(5, 5), + bul: -1 + }, + { + pt: new Vector2(5, 10), + bul: 0 + }, + { + pt: new Vector2(0, 10), + bul: 0 + } + ]) + expect(pl.IsClose).toBeTruthy(); + pl.Extend(5.5); + expect(pl.EndPoint).toEqual(new Vector3(0, -5, 0)); + expect(pl.LineData.length).toEqual(6); + expect(pl.GetPointAtParam(5)).toEqual(new Vector3(0, -5, 0)); + pl.Extend(-0.5); + expect(pl.StartPoint).toEqual(new Vector3(-2.5, 0, 0)); + expect(pl.IsClose).toBeFalsy(); + pl2.Extend(4.5) + expect(pl2.EndPoint).toEqual(new Vector3(-2.5, 10, 0)); + pl2.Extend(-0.5) + expect(pl2.EndPoint).toEqual(new Vector3(-2.5, 10, 0)); + expect(pl2.StartPoint).toEqual(new Vector3(-2.5, 0, 0)); + + let pl3 = new Polyline([ + { + pt: new Vector2(0, 0), + bul: 1 + }, + { + pt: new Vector2(0, 5), + bul: 0 + } + ]) + pl3.Extend(1.5); + expect(equal(pl3.EndPoint, new Vector3(-2.5, 2.5, 0))).toBeTruthy(); + pl3.Extend(1 + 1 / 3); + // expect(pl3.EndPoint).toEqual(new Vector3(0, 0, 0)); + expect(equal(pl3.EndPoint /*?*/, new Vector3(0, 0, 0))).toBeTruthy(); + }) + test("多段线延伸,闭合", () => + { + let pl = new Polyline([ + { + pt: new Vector2(0, 0), + bul: 0 + }, + { + pt: new Vector2(5, 0), + bul: 1 + }, + { + pt: new Vector2(5, 5), + bul: -1 + }, + { + pt: new Vector2(5, 10), + bul: 0 + }, + { + pt: new Vector2(0, 10), + bul: 0 + }, + { + pt: new Vector2(0, 0), + bul: 0 + } + ]) + pl.CloseMark = true; + pl.Extend(5.5); + expect(pl.EndPoint).toEqual(new Vector3()); + }) + test("多段线点在线上", () => + { + let pl = new Polyline([ + { + pt: new Vector2(0, 0), + bul: 0 + }, + { + pt: new Vector2(5, 0), + bul: 1 + }, + { + pt: new Vector2(5, 5), + bul: -1 + }, + { + pt: new Vector2(5, 10), + bul: 0 + }, + { + pt: new Vector2(0, 10), + bul: 0 + }, + { + pt: new Vector2(0, 0), + bul: 0 + } + ]) + expect(pl.GetParamAtPoint(new Vector3())).toBe(0); + expect(pl.PtOnCurve(new Vector3(0, 0, 0))).toBeTruthy(); + expect(pl.PtOnCurve(new Vector3(5, 0, 0))).toBeTruthy(); + expect(pl.PtOnCurve(new Vector3(7.5, 2.5, 0))).toBeTruthy(); + expect(pl.PtOnCurve(new Vector3(7.5, 3.5, 0))).toBeFalsy(); + + }) + test("多段线最近点", () => + { + let pl = new Polyline([ + { + pt: new Vector2(0, 0), + bul: 0 + }, + { + pt: new Vector2(5, 0), + bul: 1 + }, + { + pt: new Vector2(5, 5), + bul: -1 + }, + { + pt: new Vector2(5, 10), + bul: 0 + }, + { + pt: new Vector2(0, 10), + bul: 0 + }, + { + pt: new Vector2(0, 0), + bul: 0 + } + ]) + expect(pl.GetClosestPointTo(new Vector3(), true)).toEqual(new Vector3()); + expect(pl.GetClosestPointTo(new Vector3(3.5, 2.5), true)).toEqual(new Vector3(3.5, 0, 0)); + expect(pl.GetClosestPointTo(new Vector3(1.5, 3.5), true)).toEqual(new Vector3(0, 3.5, 0)); + expect(equal(pl.GetClosestPointTo(new Vector3(1.5, 3.5), true), new Vector3(0, 3.5, 0))).toBeTruthy(); + expect(equal(pl.GetClosestPointTo(new Vector3(-0.5, -1), true), new Vector3(0, -1, 0))).toBeTruthy(); + + }) + test("多段线包围盒", () => + { + let pl = new Polyline([ + { + pt: new Vector2(0, 0), + bul: 0 + }, + { + pt: new Vector2(5, 0), + bul: 1 + }, + { + pt: new Vector2(5, 5), + bul: -1 + }, + { + pt: new Vector2(5, 10), + bul: 0 + }, + { + pt: new Vector2(0, 10), + bul: 0 + }, + { + pt: new Vector2(0, 0), + bul: 0 + } + ]) + expect(pl.BoundingBox.getSize()).toEqual(new Vector3(7.5, 10, 0)) + + }) + test("多段线反转", () => + { + let pl = new Polyline([ + { + pt: new Vector2(0, 0), + bul: 0 + }, + { + pt: new Vector2(5, 0), + bul: 1 + }, + { + pt: new Vector2(5, 5), + bul: -1 + }, + { + pt: new Vector2(5, 10), + bul: 0 + }, + { + pt: new Vector2(0, 10), + bul: 0 + } + ]) + pl.Reverse(); + expect(pl.StartPoint).toEqual(new Vector3(0, 10, 0)) + }) +}) diff --git a/__test__/Polyline/split.test.ts b/__test__/Polyline/split.test.ts new file mode 100644 index 000000000..2b7d93fa8 --- /dev/null +++ b/__test__/Polyline/split.test.ts @@ -0,0 +1,111 @@ +import { Polyline } from "../../src/DatabaseServices/Polyline"; +import { Vector2 } from "three"; + + +//构造测试的多段线 +function createTestPolyline(): Polyline +{ + return new Polyline([ + { + pt: new Vector2(0, 0), + bul: 0 + }, + { + pt: new Vector2(5, 0), + bul: 1 + }, + { + pt: new Vector2(5, 5), + bul: -1 + }, + { + pt: new Vector2(5, 10), + bul: 0 + }, + { + pt: new Vector2(0, 10), + bul: 0 + }, + { + pt: new Vector2(0, 0), + bul: 0 + } + ]); +} + +//切割测试 +{ + let pl = createTestPolyline(); + + test('多切刀', () => + { + //不闭合标志 + pl.CloseMark = false; + + //不包括0 + let cus = pl.GetSplitCurves([1.5, 2.5, 2.8, 2.8, 1.2, 2, 1.8, 1, 2.2]);// + + for (let cu of cus) + { + expect(cu.LineData).toMatchSnapshot(); + } + + //包括0 + let cus2 = pl.GetSplitCurves([1.5, 2.5, 2.8, 2.8, 1.2, 2, 1.8, 1, 2.2, 0]);// + + for (let cu of cus) + { + expect(cu.LineData).toMatchSnapshot(); + } + }); + + test('多切刀闭合', () => + { + + //闭合标志 + pl.CloseMark = true; + + //不包括0 + let cus = pl.GetSplitCurves([1.5, 2.5, 2.8, 2.8, 1.2, 2, 1.8, 1, 2.2]);// + + for (let cu of cus) + { + expect(cu.LineData).toMatchSnapshot(); + } + + //包括0 + let cus2 = pl.GetSplitCurves([1.5, 2.5, 2.8, 2.8, 1.2, 2, 1.8, 1, 2.2, 0]);// + + for (let cu of cus) + { + expect(cu.LineData).toMatchSnapshot(); + } + }); + + test('单刀', () => + { + for (let p of [0, 1.5, 2, 2.5, 3]) + { + let cus = pl.GetSplitCurves(p); + for (let cu of cus) + { + //该测试用于数值精度的问题经常造成测试失败.请刷新测试. + expect(cu.LineData).toMatchSnapshot(); + } + } + }); + + test('单刀闭合', () => + { + pl.CloseMark = true; + for (let p of [0, 1.5, 2, 2.5, 3]) + { + let cus = pl.GetSplitCurves(p); + for (let cu of cus) + { + expect(cu.LineData).toMatchSnapshot(); + } + } + }); +} + diff --git a/src/Add-on/DrawPolyline.ts b/src/Add-on/DrawPolyline.ts index 1c088d732..86529e140 100644 --- a/src/Add-on/DrawPolyline.ts +++ b/src/Add-on/DrawPolyline.ts @@ -1,9 +1,9 @@ import { Vector3 } from 'three'; import { app } from '../ApplicationServices/Application'; -import { getCircleAngle, rotateLine, Vec2DTo3D, Vec3DTo2D } from '../Common/CurveUtils'; +import { getArcAngle, rotateLine, Vec2DTo3D, Vec3DTo2D } from '../Common/CurveUtils'; import { Line } from '../DatabaseServices/Line'; -import { Polyline, PolylineData } from '../DatabaseServices/Polyline'; +import { Polyline, PolylineProps } from '../DatabaseServices/Polyline'; import { Command } from '../Editor/CommandMachine'; import { PromptStatus } from '../Editor/PromptResult'; @@ -27,18 +27,18 @@ export class DrawPolyline implements Command this.m_Model = PolylineModel.Line; - let p1 = ptRes.Value; + let basePt = ptRes.Value; //存储基点 - let BasePts = [p1]; + let BasePts = [basePt]; //多段线最终点 - let data: PolylineData = { - pt: Vec3DTo2D(p1), + let data: PolylineProps = { + pt: Vec3DTo2D(basePt), bul: 0 } //储存多段线数据 - let lineData = [data] + let lineProps = [data] - let polyline = new Polyline(lineData); + let polyline = new Polyline(lineProps); app.m_Database.ModelSpace.Append(polyline); // 切线 @@ -54,37 +54,37 @@ export class DrawPolyline implements Command //返回一步 let restore = () => { - lineData.pop(); - polyline.LineData = lineData; + lineProps.pop(); + polyline.LineData = lineProps; } // 更新多段线凸度 - let updateBul = (v, p1) => + let updateBul = (endPt: Vector3, startPt: Vector3) => { // 弦长矢量 - chord = v.clone().sub(p1); - cirAng = getCircleAngle(chord, tangentLine); + chord = endPt.clone().sub(startPt); + cirAng = getArcAngle(chord, tangentLine); if (cirAng) { //凸度 let bul = Math.tan(cirAng / 4); - lineData[lineData.length - 2].bul = bul + lineProps[lineProps.length - 2].bul = bul } } while (true) { data = { - pt: Vec3DTo2D(p1), + pt: Vec3DTo2D(basePt), bul: 0 } - if (lineData.length === 2) + if (lineProps.length === 2) { KeyWordList.push({ msg: "闭合", key: "C" }) } - lineData.push(data); + lineProps.push(data); app.m_Editor.m_CommandStore.Prompt("请输入点2:"); ptRes = await app.m_Editor.GetPoint({ Msg: "请输入点2:", - BasePoint: p1, + BasePoint: basePt, AllowDrawRubberBand: true, KeyWordList, Callback: (v) => @@ -93,8 +93,8 @@ export class DrawPolyline implements Command { if (!tangentLine) tangentLine = new Vector3(1, 0, 0); data.pt.set(v.x, v.y); - updateBul(v, p1); - polyline.LineData = lineData; + updateBul(v, basePt); + polyline.LineData = lineProps; } } }); @@ -105,17 +105,17 @@ export class DrawPolyline implements Command if (this.m_Model === 1) { //切线 - tangentLine = ptRes.Value.clone().sub(p1).normalize(); + tangentLine = ptRes.Value.clone().sub(basePt).normalize(); } else { - updateBul(ptRes.Value, p1); + updateBul(ptRes.Value, basePt); tangentLine = rotateLine(tangentLine, cirAng) } - polyline.LineData = lineData; - BasePts.push(p1); - p1 = ptRes.Value; + polyline.LineData = lineProps; + BasePts.push(basePt); + basePt = ptRes.Value; continue; } @@ -124,26 +124,26 @@ export class DrawPolyline implements Command //是否闭合曲线 if (ptRes.StringResult == "C") { - data.pt = lineData[0].pt; + data.pt = lineProps[0].pt; let endPt = Vec2DTo3D(data.pt); if (this.m_Model === PolylineModel.Arc) { polyline.CloseMark = true; - updateBul(endPt, p1); + updateBul(endPt, basePt); } - polyline.LineData = lineData; + polyline.LineData = lineProps; break; } if (ptRes.StringResult == "U") { - p1 = BasePts.pop(); - lineData.pop(); + basePt = BasePts.pop(); + lineProps.pop(); if (this.m_Model === 1) - tangentLine = p1.clone().sub(BasePts[BasePts.length - 1]).normalize(); + tangentLine = basePt.clone().sub(BasePts[BasePts.length - 1]).normalize(); else { - data = lineData[lineData.length - 2]; + data = lineProps[lineProps.length - 2]; cirAng = Math.atan(data.bul) * 4; tangentLine = rotateLine(tangentLine, -cirAng) } @@ -154,7 +154,7 @@ export class DrawPolyline implements Command } else if (ptRes.StringResult == "L") { - lineData[lineData.length - 2].bul = 0; + lineProps[lineProps.length - 2].bul = 0; this.m_Model = PolylineModel.Line; } restore(); diff --git a/src/Add-on/Export.ts b/src/Add-on/Export.ts new file mode 100644 index 000000000..2e2cf02fb --- /dev/null +++ b/src/Add-on/Export.ts @@ -0,0 +1,31 @@ +import { Command } from "../Editor/CommandMachine"; +import { SelectSet } from "../Editor/SelectSet"; +import { PromptStatus } from "../Editor/PromptResult"; +import { app } from "../ApplicationServices/Application"; + + +export class Command_Export implements Command +{ + async exec(ss: SelectSet) + { + if (ss.SelectEntityList.length === 0) + { + let ssRes = await app.m_Editor.GetSelection({ Msg: "请选择需要拷贝的实体:" }); + if (ssRes.Status != PromptStatus.OK) + return; + + ss = ssRes.SelectSet; + } + + for (let en of ss.SelectEntityList) + { + let ens = en.Export(); + en.Erase(); + + for (let e of ens) + { + app.m_Database.ModelSpace.Append(e); + } + } + } +} diff --git a/src/Add-on/Offset.ts b/src/Add-on/Offset.ts index 6c127363c..1765fe722 100644 --- a/src/Add-on/Offset.ts +++ b/src/Add-on/Offset.ts @@ -7,39 +7,80 @@ export class Command_Offset implements Command { async exec() { - let dis = await app.m_Editor.GetDistance({ Msg: "指定偏移距离:" }); - if (dis.Status == PromptStatus.OK) + if (dis.Status != PromptStatus.OK) return; + while (true) { let enRes = await app.m_Editor.GetEntity({ Msg: "选择要偏移的对象:" }); + if (enRes.Status != PromptStatus.OK) + break; + let pt = await app.m_Editor.GetPoint({ + Msg: "指定要偏移的那一侧的点" + }); - if (enRes.Status === PromptStatus.OK) + let cu = enRes.Entity; + + if (cu instanceof Curve) { + let ptClose = cu.GetClosestPointTo(pt.Value, false); + let toPtVec = pt.Value.clone().sub(ptClose); //点击处向量 + let d = cu.GetFistDeriv(cu.GetParamAtPoint(ptClose));//切线。 - let pt = await app.m_Editor.GetPoint({ - Msg: "指定要偏移的那一侧的点" - }); + let c = toPtVec.cross(d); - let cur = enRes.Entity; - // if (cur instanceof Line || cur instanceof Arc || cur instanceof Circle) - if (cur instanceof Curve) + let offCurs = cu.GetOffsetCurves(dis.Value * Math.sign(c.z)); + offCurs.forEach((offCur) => { - let ptClose = cur.GetClosestPointTo(pt.Value, true); - let toPtVec = pt.Value.clone().sub(ptClose); //点击处向量 - let d = cur.GetFistDeriv(cur.GetParamAtPoint(ptClose));//切线。 + app.m_Database.ModelSpace.Append(offCur); + }) + app.m_Viewer.m_bNeedUpdate = true; + } + } + } +} - let c = toPtVec.cross(d); - let offCur = cur.GetOffsetCurves(dis.Value * Math.sign(c.z))[0]; +export class Command_TestOffset implements Command +{ + async exec() + { + //禁用捕捉服务 + app.m_Editor.m_GetpointServices.snapServices.m_Disabled = true; + while (true) + { + let enRes = await app.m_Editor.GetEntity({ + Msg: "选择要偏移的对象:" + }); + if (enRes.Status != PromptStatus.OK) + break; + let cu = enRes.Entity as Curve; - app.m_Database.ModelSpace.Append(offCur); + let lastpls: Curve[]; + + await app.m_Editor.GetPoint({ + Msg: "指定要偏移的那一侧的点", + Callback: (p) => + { + if (lastpls) lastpls.forEach(cu => cu.Erase()); + + let ptClose = cu.GetClosestPointTo(p, false); + let toPtVec = p.clone().sub(ptClose); //点击处向量 + let d = cu.GetFistDeriv(cu.GetParamAtPoint(ptClose));//切线。 + let c = toPtVec.cross(d); + + lastpls = cu.GetOffsetCurves(p.distanceTo(cu.GetClosestPointTo(p, true)) * Math.sign(c.z)); + lastpls.forEach((offCur) => + { + app.m_Database.ModelSpace.Append(offCur); + }) app.m_Viewer.m_bNeedUpdate = true; + } - } + }); } } } diff --git a/src/Add-on/RevPl.ts b/src/Add-on/RevPl.ts index 9fe5363df..d5161e1dd 100644 --- a/src/Add-on/RevPl.ts +++ b/src/Add-on/RevPl.ts @@ -2,22 +2,21 @@ import { Command } from '../Editor/CommandMachine'; import { SelectSet } from '../Editor/SelectSet'; import { Polyline } from '../DatabaseServices/Polyline'; import { app } from '../ApplicationServices/Application'; +import { Curve } from '../DatabaseServices/Curve'; export class Command_RevPl implements Command { async exec(ss: SelectSet) { - let pls: Polyline[] = []; for (let en of ss.SelectEntityList) { - if (en instanceof Polyline) + if (en instanceof Curve) { - pls.push(en); en.Reverse(); + app.m_Editor.m_CommandStore.Prompt("成功翻转曲线"); } } - app.m_Editor.UpdateScreen(); } } diff --git a/src/Add-on/Save.ts b/src/Add-on/Save.ts index 1fc436890..d2e9be7da 100644 --- a/src/Add-on/Save.ts +++ b/src/Add-on/Save.ts @@ -13,7 +13,7 @@ export class Save implements Command let store = await IndexedDbStore.CADStore(); let fileId = store.m_CurrentFileId; app.m_Viewer.Render(); - let url = app.m_Viewer.m_Render.domElement.toDataURL() + let url = app.m_Viewer.m_Render.domElement.toDataURL("image/png", 1) let fileInfo: FileInfo; if (!fileId) diff --git a/src/Add-on/TestBox.ts b/src/Add-on/TestBox.ts new file mode 100644 index 000000000..85413177a --- /dev/null +++ b/src/Add-on/TestBox.ts @@ -0,0 +1,24 @@ +import { Command } from "../Editor/CommandMachine"; +import { app } from "../ApplicationServices/Application"; +import { PromptStatus } from "../Editor/PromptResult"; +import { Line } from "../DatabaseServices/Line"; + + +export class Command_TestBox implements Command +{ + async exec() + { + let ss = await app.m_Editor.GetSelection(); + if (ss.Status != PromptStatus.OK) + return; + + for (let en of ss.SelectSet.SelectEntityList) + { + let box = en.BoundingBox; + + let line = new Line(box.min, box.max); + + app.m_Database.ModelSpace.Append(line); + } + } +} diff --git a/src/Add-on/Trim.ts b/src/Add-on/Trim.ts index fb71794c3..9e59be2cd 100644 --- a/src/Add-on/Trim.ts +++ b/src/Add-on/Trim.ts @@ -90,6 +90,13 @@ export class Command_Trim implements Command cu.Erase(); continue; } + else + { + // for (let cu of splitCus) + // { + // app.m_Database.ModelSpace.Append(cu) + // } + } if (s instanceof SelectPick) { diff --git a/src/Add-on/closetest.ts b/src/Add-on/closetest.ts new file mode 100644 index 000000000..ef851e3d5 --- /dev/null +++ b/src/Add-on/closetest.ts @@ -0,0 +1,46 @@ +import { Command } from "../Editor/CommandMachine"; +import { app } from "../ApplicationServices/Application"; +import { Line } from "../DatabaseServices/Line"; +import { Curve, ExtendType } from "../DatabaseServices/Curve"; +import { PromptStatus } from "../Editor/PromptResult"; +import { Polyline } from "../DatabaseServices/Polyline"; + + +export class Command_ClosePt implements Command +{ + async exec() + { + + let cuRes = await app.m_Editor.GetEntity(); + + + if (cuRes.Entity instanceof Curve) + { + let cu = cuRes.Entity as Curve; + let line = new Line(); + app.m_Database.ModelSpace.Append(line); + + let extend = false; + while (true) + { + app.m_Editor.AddNoSnapEntity(line); + let p = await app.m_Editor.GetPoint({ + KeyWordList: [{ key: "C", msg: (extend ? "不" : "") + "延伸" }], + Callback: p => + { + line.StartPoint = p; + + line.EndPoint = cu.GetClosestPointTo(p, extend); + } + }) + if (p.Status === PromptStatus.Keyword) + { + extend = !extend; + } + if (p.Status === PromptStatus.Cancel) + return; + } + + } + } +} diff --git a/src/Add-on/instest.ts b/src/Add-on/instest.ts new file mode 100644 index 000000000..c0680d657 --- /dev/null +++ b/src/Add-on/instest.ts @@ -0,0 +1,40 @@ +import { app } from '../ApplicationServices/Application'; +import { Circle } from '../DatabaseServices/Circle'; +import { Curve } from '../DatabaseServices/Curve'; +import { Command } from '../Editor/CommandMachine'; +import { PromptStatus } from '../Editor/PromptResult'; +import { IntersectOption } from '../GraphicsSystem/IntersectWith'; + + +export class Command_INsTest implements Command +{ + async exec() + { + + let ss = await app.m_Editor.GetSelection(); + if (ss.Status != PromptStatus.OK) + return; + + let cus = ss.SelectSet.SelectEntityList.filter(e => e instanceof Curve); + + for (let i = 0; i < cus.length; i++) + { + let cu = cus[i]; + for (let j = i + 1; j < cus.length; j++) + { + let cu2 = cus[j]; + + let ins = cu.IntersectWith(cu2, IntersectOption.OnBothOperands); + + for (let p of ins) + { + let c = new Circle(p, 0.1); + app.m_Database.ModelSpace.Append(c); + } + } + } + + + app.m_Editor.UpdateScreen(); + } +} diff --git a/src/Add-on/polytest.ts b/src/Add-on/polytest.ts new file mode 100644 index 000000000..ffdb753bc --- /dev/null +++ b/src/Add-on/polytest.ts @@ -0,0 +1,270 @@ +import { Command } from "../Editor/CommandMachine"; +import { Polyline } from "../DatabaseServices/Polyline"; +import { Vector2, Vector3 } from "three"; +import { app } from "../ApplicationServices/Application"; +import { Circle } from "../DatabaseServices/Circle"; +import { Arc } from "../DatabaseServices/Arc"; +import { Move, polar } from "../Geometry/GeUtils"; +import { IntersectOption } from "../GraphicsSystem/IntersectWith"; +import { Line } from "../DatabaseServices/Line"; +import { ExtendType } from "../DatabaseServices/Curve"; + + +export class Command_PLTest implements Command +{ + async exec() + { + + //this.intersect(); + // this.splitPolyline(); + + this.splitPolyline(); + + // this.testGetPointAtParam(); + } + + + createPolyline() + { + + } + + + testClosePoint() + { + let pl = new Polyline([ + { + pt: new Vector2(0, 0), + bul: 0 + }, + { + pt: new Vector2(5, 0), + bul: 1 + }, + { + pt: new Vector2(5, 5), + bul: -1 + }, + { + pt: new Vector2(5, 10), + bul: 0 + }, + // { + // pt: new Vector2(0, 10), + // bul: 0 + // }, + // { + // pt: new Vector2(0, 0), + // bul: 0 + // } + ]); + + // pl.CloseMark = true; + + app.m_Database.ModelSpace.Append(pl); + + + let lines: Line[] = []; + let a = Math.PI / 180; + let center = new Vector3(2.5, 2.5) + for (let i = 0; i < 1; i++) + { + let p = polar(center.clone(), a * i, 3) as Vector3; + + let pc = pl.GetClosestPointTo(p, true); + + let line = new Line(p, pc); + + app.m_Database.ModelSpace.Append(line); + + lines.push(line); + } + + app.m_Editor.GetPoint({ + Callback: center => + { + for (let i = 0; i < 1; i++) + { + let p = polar(center.clone(), a * i, 0) as Vector3; + lines[i].StartPoint = p; + lines[i].EndPoint = pl.GetClosestPointTo2(p, ExtendType.Back); + } + } + }) + } + + + //TODO:[]多段线切割导致的数据错误,数据重用. + splitPolyline() + { + let pl = new Polyline([ + { + pt: new Vector2(0, 0), + bul: 0 + }, + { + pt: new Vector2(5, 0), + bul: 1 + }, + { + pt: new Vector2(5, 5), + bul: -1 + }, + { + pt: new Vector2(5, 10), + bul: 0 + }, + { + pt: new Vector2(0, 10), + bul: 0 + }, + { + pt: new Vector2(0, 0), + bul: 0 + } + ]); + + pl.CloseMark = true; + let c = 0; + for (let p of [7]) + // for (let p = -3; p < 7; p += 0.2) + { + // let pt = pl.GetPointAtParam(p); + // if (!pt) continue; + // let cir = new Circle(pt, 0.1); + // c++; + // cir.ColorIndex = c % 7 + 1; + // app.m_Database.ModelSpace.Append(cir); + // let d = pl.GetFistDeriv(p); + + // let line = new Line(pt, pt.clone().add(d)); + // line.ColorIndex = c % 7 + 1; + + // app.m_Database.ModelSpace.Append(line); + + for (let cu of pl.GetOffsetCurves(p)) + { + app.m_Database.ModelSpace.Append(cu); + } + } + app.m_Database.ModelSpace.Append(pl); + } + + testGetPointAtParam() + { + let pl = new Polyline([ + { + pt: new Vector2(0, 0), + bul: 0 + }, + { + pt: new Vector2(5, 0), + bul: 1 + }, + { + pt: new Vector2(5, 5), + bul: -1 + }, + { + pt: new Vector2(5, 10), + bul: 0 + }, + { + pt: new Vector2(0, 10), + bul: 0 + }, + { + pt: new Vector2(0, 0), + bul: 0 + } + ]); + + pl.CloseMark = true; + + console.log(pl.EndPoint); + + let c = 0; + + let v = pl.GetFistDeriv(7); + console.log(v); + + + let pt = app.m_Editor.GetPoint({ + + Callback: (pt) => + { + + } + }) + + // for (let p of [1.5, 2.5, 2.8, 2.8, 1.2, 2, 1.8, 1, 2.2, 0]) + for (let p = -3; p < 7; p += 0.2) + { + let pt = pl.GetPointAtParam(p); + if (!pt) continue; + let cir = new Circle(pt, 0.1); + c++; + cir.ColorIndex = c % 7 + 1; + app.m_Database.ModelSpace.Append(cir); + let d = pl.GetFistDeriv(p); + + let line = new Line(pt, pt.clone().add(d)); + + if (line.Length == 0) + { + console.log(1); + } + line.ColorIndex = c % 7 + 1; + + app.m_Database.ModelSpace.Append(line); + } + app.m_Database.ModelSpace.Append(pl); + } + + intersect() + { + let pl = new Polyline([ + { + pt: new Vector2(0, 0), + bul: 1 + }, + { + pt: new Vector2(0, 5), + bul: 0.32 + }, + ]) + let p2 = new Polyline([ + { + pt: new Vector2(-1, 0), + bul: -1 + }, + { + pt: new Vector2(4, 0), + bul: 0 + }, + ]) + let p3 = new Polyline([ + { + pt: new Vector2(0, 0), + bul: 0 + }, + { + pt: new Vector2(3, 3), + bul: 0 + }, + ]) + let p4 = new Polyline([ + { + pt: new Vector2(0, 0), + bul: 0 + }, + { + pt: new Vector2(1, 1), + bul: 0 + }, + ]) + app.m_Database.ModelSpace.Append(pl); + app.m_Database.ModelSpace.Append(p4); + console.log(pl.IntersectWith(p4, IntersectOption.ExtendArg)); + } +} diff --git a/src/ApplicationServices/mesh/createBoard.ts b/src/ApplicationServices/mesh/createBoard.ts index a2818838d..22d1b5cdb 100644 --- a/src/ApplicationServices/mesh/createBoard.ts +++ b/src/ApplicationServices/mesh/createBoard.ts @@ -1,6 +1,9 @@ -import { data } from '../../Add-on/data'; import * as THREE from 'three'; + +import { data } from '../../Add-on/data'; +import { polar } from '../../Geometry/GeUtils'; import { RotateUVs } from '../../Geometry/RotateUV'; + export namespace CreateBoardUtil { //解析二维圆弧类. @@ -28,8 +31,8 @@ export namespace CreateBoardUtil this.m_Center = p1.clone().add(p2); this.m_Center.multiplyScalar(0.5); - this.m_Center.x += Math.cos(an) * toDis; - this.m_Center.y += Math.sin(an) * toDis; + + polar(this.m_Center, an, toDis); this.m_StartAn = p1.clone().sub(this.m_Center).angle(); this.m_EndAn = p2.clone().sub(this.m_Center).angle(); @@ -46,9 +49,9 @@ export namespace CreateBoardUtil //创建轮廓 通过点表和凸度 export function createPath(pts: THREE.Vector2[], buls: number[], shapeOut?: THREE.Shape): THREE.Shape { - - var shape = shapeOut || new THREE.Shape(); + let shape = shapeOut || new THREE.Shape(); let firstPt = pts[0]; + shape.moveTo(firstPt.x, firstPt.y); for (let i = 0; i < pts.length - 1; i++) { @@ -59,12 +62,12 @@ export namespace CreateBoardUtil } else { - var pt = pts[i]; + let pt = pts[i]; //参考 //http://www.dorodnic.com/blog/tag/three-js/ 绘制一个齿轮 //https://www.kirupa.com/html5/drawing_circles_canvas.htm //html5 - var arc2 = new Arc2d(pt, nextPt, buls[i]); - var cen = arc2.m_Center; + let arc2 = new Arc2d(pt, nextPt, buls[i]); + let cen = arc2.m_Center; shape.absarc(cen.x, cen.y, arc2.m_Radius, arc2.m_StartAn, arc2.m_EndAn, buls[i] < 0); } } diff --git a/src/Common/CurveUtils.ts b/src/Common/CurveUtils.ts index ec0b4ac41..eacba360f 100644 --- a/src/Common/CurveUtils.ts +++ b/src/Common/CurveUtils.ts @@ -2,8 +2,14 @@ import { Vector2, Vector3 } from 'three'; import * as THREE from 'three'; import { CreateBoardUtil } from '../ApplicationServices/mesh/createBoard'; -import { angleTo } from '../Geometry/GeUtils'; +import { angleTo, equaln, equal } from '../Geometry/GeUtils'; +export enum ExtendDir +{ + Front = 0, + Later = 1, + Both = 2 +} // 旋转矢量 export function rotateLine(l: Vector3, ang: number) { @@ -14,7 +20,7 @@ export function rotateLine(l: Vector3, ang: number) //2点加凸度获取圆弧面积 export function getArcArea(startV: THREE.Vector2, endV: THREE.Vector2, bul: number) { - let arcData = getArcData(startV, endV, bul); + let arcData = getArcProps(startV, endV, bul); //圆心角 let circleAng = Math.atan(bul) * 4; //扇形面积 @@ -29,11 +35,11 @@ export function getArcArea(startV: THREE.Vector2, endV: THREE.Vector2, bul: numb } } //2点加凸度获取圆弧半径,圆心,起始线,终止线 -export function getArcData(startV: THREE.Vector2, endV: THREE.Vector2, bul: number) +export function getArcProps(startV: THREE.Vector2, endV: THREE.Vector2, bul: number) { let arc2d = new CreateBoardUtil.Arc2d(startV, endV, bul); let centerPt = arc2d.m_Center; - let rad = arc2d.m_Radius; + let rad = Math.abs(arc2d.m_Radius); //起始矢量 let startVec = startV.clone().sub(centerPt); //终止矢量 @@ -73,8 +79,10 @@ export function getCircleCenter(pt1: Vector3, pt2: Vector3, pt3: Vector3) return center; } -//3点获取凸度 -export function getArcAngle(startPt: Vector3, midPt: Vector3, endPt: Vector3) +/** + * 三点获取圆心角 + */ +export function getArcAngleBy3Pt(startPt: Vector3, midPt: Vector3, endPt: Vector3) { // 圆心 let center = getCircleCenter(startPt, midPt, endPt); @@ -99,7 +107,7 @@ export function getArcAngle(startPt: Vector3, midPt: Vector3, endPt: Vector3) return circleAng *= (-dir.z); } // 弦长+切线获取圆心角 -export function getCircleAngle(chord: Vector3, tangentLine: Vector3) +export function getArcAngle(chord: Vector3, tangentLine: Vector3) { let dir = tangentLine.clone().cross(chord).normalize(); @@ -120,7 +128,7 @@ export function getDeterminant(v1: Vector2, v2: Vector2): number return v1.x * v2.y - v1.y * v2.x; } // 获取曲线指定位置的点 -export function getPointAtParam(startPt: Vector2, endPt: Vector2, bul: number, segment: number) +export function getPtAtCurveParam(startPt: Vector2, endPt: Vector2, bul: number, segment: number) { let pt = new Vector3(); if (bul === 0) @@ -129,18 +137,15 @@ export function getPointAtParam(startPt: Vector2, endPt: Vector2, bul: number, s } else { - let arc2d = new CreateBoardUtil.Arc2d(startPt, endPt, bul); - let circlePt = arc2d.m_Center; - //起始矢量 - let startVec = startPt.clone().sub(circlePt); - // 将起始线终止线转3维 - let startLine = Vec2DTo3D(startVec); + let arcData = getArcProps(startPt, endPt, bul); + // 起始线 + let startLine = Vec2DTo3D(arcData.startVec); //圆心角 let circleAng = Math.atan(bul) * 4 * segment; if (Math.abs(circleAng) > 2 * Math.PI) - circleAng = 2 * Math.PI * (bul > 0 ? 1 : -1); + circleAng = 2 * Math.PI * Math.sign(bul); startLine = rotateLine(startLine, circleAng) - pt = Vec2DTo3D(circlePt); + pt = Vec2DTo3D(arcData.centerPt); pt.add(startLine); } return pt; @@ -157,7 +162,7 @@ export function getCurveLength(startPt: Vector2, endPt: Vector2, bul: number) } else { - let arcData = getArcData(startPt, endPt, bul); + let arcData = getArcProps(startPt, endPt, bul); // 圆心角 let cirAng = Math.atan(bul) * 4; dist = Math.abs(arcData.rad) * Math.abs(cirAng); @@ -165,50 +170,51 @@ export function getCurveLength(startPt: Vector2, endPt: Vector2, bul: number) return dist; } //点是否在圆弧上 -export function isAtArc(startPt: Vector2, endPt: Vector2, bul: number, pt: Vector3) +export function isPtOnArc(startPt: Vector2, endPt: Vector2, bul: number, pt: Vector3, isExt = false) { - let arcData = getArcData(startPt, endPt, bul); + let arcData = getArcProps(startPt, endPt, bul); let rad = Math.abs(arcData.rad); //圆心到输入点连线 let ptLine = pt.clone().sub(Vec2DTo3D(arcData.centerPt)); - if (Math.abs(ptLine.length() - rad) <= 0.000001) + if (equaln(ptLine.length(), rad, 1e-7)) { + if (isExt) return true; let startLine = Vec2DTo3D(arcData.startVec); let endLine = Vec2DTo3D(arcData.endVec); let oldCircleAngle = Math.abs(Math.atan(bul) * 4); - if (startLine.equals(ptLine) || endLine.equals(ptLine)) + if (equal(startLine, ptLine) || equal(endLine, ptLine)) return true; - let cirAng = getCirLineAngle(startLine, ptLine, bul); + let cirAng = getArcLineAngle(startLine, ptLine, bul); if (Math.abs(cirAng) < oldCircleAngle) return true; } return false; } -// 获得圆弧指定点的弧长 -export function getArcPtLenAngle(startPt: Vector2, endPt: Vector2, bul: number, pt: Vector3) +// 获得圆弧指定点的弧长和角度 +export function getArcPtLenAndAngle(startPt: Vector2, endPt: Vector2, bul: number, pt: Vector3) { - let arcData = getArcData(startPt, endPt, bul); + let arcData = getArcProps(startPt, endPt, bul); let rad = Math.abs(arcData.rad); //圆心到输入点连线 let ptLine = pt.clone().sub(Vec2DTo3D(arcData.centerPt)); let startLine = Vec2DTo3D(arcData.startVec); - let cirAng = getCirLineAngle(startLine, ptLine, bul); + let cirAng = getArcLineAngle(startLine, ptLine, bul); return { len: Math.abs(cirAng) * rad, angle: cirAng } } // 求圆弧上任一条线的圆心角 -export function getCirLineAngle(startLine: Vector3, ptLine: Vector3, bul: number) +export function getArcLineAngle(startLine: Vector3, ptLine: Vector3, bul: number) { - let cirAng = angleTo(startLine, ptLine); + if (cirAng * bul < 0) { - cirAng = (Math.PI * 2 - Math.abs(cirAng)) * (bul > 0 ? 1 : -1); + cirAng = (Math.PI * 2 - Math.abs(cirAng)) * Math.sign(bul); } return cirAng; @@ -223,7 +229,7 @@ export function Vec3DTo2D(pt: Vector3) return new Vector2(pt.x, pt.y); } //点到曲线上的最近点 -export function getClosestPt(startPt: Vector2, endPt: Vector2, bul: number, pt: Vector3, isExt: boolean = false) +export function getClosestPt(startPt: Vector2, endPt: Vector2, bul: number, pt: Vector3, isExt: boolean = false, extendDir: ExtendDir = ExtendDir.Both) { let closestPt: Vector3; let closestLen: number; @@ -249,17 +255,16 @@ export function getClosestPt(startPt: Vector2, endPt: Vector2, bul: number, pt: } else { - let arcData = getArcPtLenAngle(startPt, endPt, bul, pt); + let arcData = getArcPtLenAndAngle(startPt, endPt, bul, pt); let angle = arcData.angle if (Math.abs(angle) > Math.PI) angle -= (Math.PI * bul / Math.abs(bul)); segment = angle / (Math.atan(bul) * 4); } - if (segment > 1 || (segment < 0 && !isExt)) - { - return; - } - closestPt = getPointAtParam(startPt, endPt, bul, segment); + if (((segment > 1 || segment < -1e-7) && !isExt) || + (segment > 1 && isExt && extendDir === ExtendDir.Later) || + (segment < -1e-7 && isExt && extendDir === ExtendDir.Front)) return; + + closestPt = getPtAtCurveParam(startPt, endPt, bul, segment); closestLen = closestPt.distanceTo(pt); return { closestPt, closestLen } } - diff --git a/src/Common/KeyEnum.ts b/src/Common/KeyEnum.ts index 49d8a4c59..f9f276796 100644 --- a/src/Common/KeyEnum.ts +++ b/src/Common/KeyEnum.ts @@ -158,6 +158,7 @@ export enum KeyBoard NumpadEqual = 12, NumpadMultiply = 106, NumpadSubtract = 109, - NumpadDot = 110 + NumpadDot = 110, + NumpadDot1 = 190 } diff --git a/src/Common/Utils.ts b/src/Common/Utils.ts index 95859152f..8e3c3ed45 100644 --- a/src/Common/Utils.ts +++ b/src/Common/Utils.ts @@ -28,6 +28,11 @@ export function ArrayRemove(arr: Array, el: any) arr.splice(index, 1) } +export function Last(arr: Array) +{ + return arr[arr.length - 1]; +} + export function clamp(value, min, max) { @@ -76,3 +81,8 @@ export function isBetweenNums(v1, v2, v) { return v === v1 || v === v2 || (Math.max(v1, v2, v) !== v && Math.min(v1, v2, v) !== v); } +//深复制对象数组 +export function sliceDeep(arr: object[], start?: number, end?: number): object[] +{ + return arr.slice(start, end).map((obj) => Object.assign({}, obj)); +} diff --git a/src/DatabaseServices/Arc.ts b/src/DatabaseServices/Arc.ts index 3f444cabc..1a292ae10 100644 --- a/src/DatabaseServices/Arc.ts +++ b/src/DatabaseServices/Arc.ts @@ -1,16 +1,30 @@ import * as THREE from 'three'; -import { Box3, Matrix4, ShapeGeometry, Vector3, Object3D } from 'three'; +import { Box3, Matrix4, ShapeGeometry, Vector3, Object3D, Vector2 } from 'three'; import { ColorMaterial } from '../Common/ColorPalette'; -import { getArcAngle, isAtArc, rotateLine, Vec3DTo2D } from '../Common/CurveUtils'; -import { equal, equaln, polar, angle } from '../Geometry/GeUtils'; +import { getArcAngleBy3Pt, isPtOnArc, rotateLine, Vec3DTo2D, Vec2DTo3D } from '../Common/CurveUtils'; +import { equal, equaln, polar, angle, midPoint, angleTo2Pi } from '../Geometry/GeUtils'; import { RenderType } from '../GraphicsSystem/Enum'; -import { IntersectOption, IntersectArcAndArc, IntersectCircleAndArc, IntersectLineAndArc } from '../GraphicsSystem/IntersectWith'; +import { IntersectOption, IntersectArcAndArc, IntersectCircleAndArc, IntersectLineAndArc, reverseIntersectOption, IntersectPolylineAndCurve } from '../GraphicsSystem/IntersectWith'; import { Factory } from './CADFactory'; import { CADFile } from './CADFile'; import { Circle } from './Circle'; import { Curve } from './Curve'; import { Line } from './Line'; - +import { getCircleCenter } from './../Common/CurveUtils'; +import { Polyline } from './Polyline'; +/** + * 圆弧实体类 + * 与ACAD不同,这个类加入了时针变量,并且默认构造的圆弧为顺时针圆弧. + * + * 关于时针圆弧: + * 起始圆弧到终止圆弧总是在0-2PI之间.(一个完整的圆). + * 圆弧的绘制从起始圆弧绘制到终止圆弧. 按照时针绘制. + * 参考计算圆弧的完整角度方法查看该计算方式. + * + * @export + * @class Arc + * @extends {Curve} + */ @Factory export class Arc extends Curve { @@ -20,15 +34,22 @@ export class Arc extends Curve center && this.m_Center.copy(center); normal && this.m_Normal.copy(normal); this.m_Radius = radius || 0; - this.m_StartAngle = startAngle || 0; - this.m_EndAngle = endAngle || 0; + if (startAngle) this.m_StartAngle = angleTo2Pi(startAngle); + if (endAngle) this.m_EndAngle = angleTo2Pi(endAngle); } private m_Center = new Vector3(0, 0, 0); private m_Radius: number = 0; - private m_StartAngle: number; - private m_EndAngle: number; + private m_StartAngle: number = 0; + private m_EndAngle: number = 0; private m_Normal = new Vector3(0, 0, 1); - private m_Clockwise = true;//顺时针 + + /** + * 曲线为顺时针 + * + * @private + * @memberof Arc + */ + private m_Clockwise = true; get Center() { @@ -52,6 +73,21 @@ export class Arc extends Curve this.Update(); } + get Area(): number + { + return 0.5 * this.AllAngle * this.Radius * this.Radius; + } + //获得曲线的面积,逆时针为正,顺时针为负. + get Area2(): number + { + let clockwise = this.m_Clockwise ? -1 : 1; + return 0.5 * this.AllAngle * this.Radius * this.Radius * clockwise; + } + get IsClose(): boolean + { + return false; + } + get BoundingBox(): Box3 { let pts = [this.StartPoint, this.EndPoint]; @@ -94,7 +130,7 @@ export class Arc extends Curve set StartAngle(v: number) { this.WriteAllObjectRecord(); - this.m_StartAngle = v <= 0 ? 1e-19 : v; + this.m_StartAngle = v; this.Update(); } @@ -105,179 +141,158 @@ export class Arc extends Curve set EndAngle(v: number) { this.WriteAllObjectRecord(); - this.m_EndAngle = v <= 0 ? 1e-19 : v; + this.m_EndAngle = v; this.Update(); } //******************** Curve function start*****************// get StartPoint() { - let startPt = new Vector3(); - polar(startPt, this.m_StartAngle, this.m_Radius); - startPt = this.m_Center.clone().add(startPt); - return startPt; + return polar(this.Center, this.StartAngle, this.m_Radius) as Vector3; } get EndPoint() { - let endtPt = new Vector3(); - polar(endtPt, this.m_EndAngle, this.m_Radius); - endtPt = this.m_Center.clone().add(endtPt); - return endtPt; + return polar(this.Center, this.m_EndAngle, this.m_Radius) as Vector3; } get StartParam() { - let startPm: number = 0.0; - return startPm; + return 0; } get EndParam() { - let endPm: number = 1.0; - return endPm; + return 1; + } + get Length() + { + return this.AllAngle * this.m_Radius; } GetPointAtParam(param: number) { - if (0 <= param && param <= 1) - { - param = 1 - param; - let ptAtpm = new Vector3(); - let angle = this.GetParamAngle(param); - polar(ptAtpm, this.GetParamAngle(param), this.m_Radius); - ptAtpm = this.m_Center.clone().add(ptAtpm); - console.log(ptAtpm); - return ptAtpm; - } + let an = this.GetAngleAtParam(param); + return polar(this.Center, an, this.m_Radius) as Vector3; } GetPointAtDistance(distance: number) { - if (distance <= (Math.abs(this.getArcBul()) * this.m_Radius))//长度不能超过总弧长 - { - let ptAtDist = new Vector3(); - let propor = distance / this.getArcBul(); - polar(ptAtDist, Math.abs(this.getArcBul(propor)), this.m_Radius); - ptAtDist = this.m_Center.clone().add(ptAtDist); - return ptAtDist; - } + let len = this.Length; + if (len == 0) return; + return this.GetPointAtParam(distance / len); } GetDistAtParam(param: number) { - if (0 <= param && param <= 1) - { - let distAtPm: number = 0; - distAtPm = Math.abs(this.getArcBul(param)) * this.m_Radius; - return distAtPm; - } + return Math.abs(param * this.Length); } - GetDistAtPoint(pt?: Vector3) + GetDistAtPoint(pt: Vector3) { - if (!pt) - { - return; - } - let dist: number = 0; - //求出点1和点2的中点 - let midpt = new Vector3(0, 0, 0); - let startPt = new Vector3(0, 0, 0); - polar(startPt, this.m_StartAngle, this.m_Radius); - startPt = this.m_Center.clone().add(startPt); - midpt.x = (pt.x + startPt.x) / 2; - midpt.y = (pt.y + startPt.y) / 2; - let length = this.m_Center.distanceTo(midpt); - if (length) - { - dist = Math.acos(length / this.m_Radius) * 2 * this.m_Radius; - if (Math.abs(this.getArcBul()) > Math.PI) - dist = 2 * Math.PI * this.m_Radius - dist; - } - else - { - dist = Math.PI * this.m_Radius; - } - return dist; + let param = this.GetParamAtPoint(pt); + return this.GetDistAtParam(param); } GetParamAtPoint(pt: Vector3) { - if (!this.PtOnCurve(pt)) - { + if (this.m_Radius == 0 || + this.AllAngle == 0 || + !equaln(pt.distanceToSquared(this.m_Center), this.m_Radius * this.m_Radius, 1e-6)) return NaN; + //角度 + let an = angle(pt.clone().sub(this.m_Center)); + return this.GetParamAtAngle(an); + } + + /** + * 利用角度计算该角度在圆弧中代表的参数. + * 如果角度在圆弧内,那么返回0-1 + * 如果角度不在圆弧内,那么尝试返回离圆弧起始或者结束的较近的参数 + * + * @param {number} an + * @returns + * @memberof Arc + */ + GetParamAtAngle(an: number) + { + //如果以pt为终点,那么所有的角度为 + let ptAllAn = this.ComputeAnlge(an); + let allAn = this.AllAngle; + + //减去圆弧角度,剩余角度的一半 + let surplusAngleHalf = Math.PI - allAn / 2; + + if (ptAllAn > allAn + surplusAngleHalf)//返回负数 + { + return ((ptAllAn - allAn) - (surplusAngleHalf * 2)) / allAn; } - let pmAtPt: number = 0; - let length = this.GetDistAtPoint(pt); - pmAtPt = this.GetParamAtDist(length); - return pmAtPt; + else//返回正数 + return ptAllAn / allAn; } - GetSplitCurves(param: number[] | number) + + GetAngleAtParam(param: number) { - let anglelist = new Array(); - let curvelist = new Array(); - anglelist.push(this.m_StartAngle); + return this.m_StartAngle + param * this.AllAngle * (this.m_Clockwise ? -1 : 1); + } + + GetSplitCurves(param: number[] | number): Arc[] + { + //切割参数列表 + let params: number[]; + if (param instanceof Array) { - for (let pm of param) - { - anglelist.push(this.GetParamAngle(1 - pm)); - } + params = param.filter(param => !isNaN(param) && (param > 0 && param < 1)); + params.push(0, 1); + params.sort(); } else { - anglelist.push(this.GetParamAngle(1 - param)); + params = [0, param, 1]; } - anglelist.push(this.m_EndAngle); - for (let i = 0; i < anglelist.length - 1; i++) + + //角度列表 + let ans = params.map(p => this.GetAngleAtParam(p)); + + //返回圆弧表 + let arcs: Arc[] = []; + for (let i = 0; i < ans.length - 1; i++) { - if (!equaln(anglelist[i], anglelist[i + 1])) + if (!equaln(ans[i], ans[i + 1])) { - let arc = new Arc(this.m_Center, this.m_Radius, anglelist[i], anglelist[i + 1], this.m_Normal); - curvelist.push(arc); + let arc = this.Clone() as Arc; + arc.StartAngle = ans[i]; + arc.EndAngle = ans[i + 1]; + arcs.push(arc); } } - return curvelist; + return arcs; } - - PtOnCurve(pt: Vector3) + PtOnCurve(pt: Vector3): boolean { - let isOnArc = false; - let startPoint = new Vector3(); - let endPoint = new Vector3(); - polar(startPoint, this.m_StartAngle, this.m_Radius); - polar(endPoint, this.m_EndAngle, this.m_Radius); - startPoint = this.m_Center.clone().add(startPoint); - endPoint = this.m_Center.clone().add(endPoint); - if (equal(startPoint, pt) || equal(endPoint, pt))//如果是是起始点和终止点 - { - isOnArc = true; - return isOnArc; - } - isOnArc = isAtArc(Vec3DTo2D(startPoint), Vec3DTo2D(endPoint), Math.tan(this.getArcBul() / 4), pt); - return isOnArc; + let param = this.GetParamAtPoint(pt); + return !isNaN(param) && param >= 0 && param <= 1; } + GetOffsetCurves(offsetDist: number) { - let arcArr = new Array(); + if (this.m_Clockwise) offsetDist *= -1; if ((offsetDist + this.m_Radius) > 0) { - let arc = new Arc(this.m_Center, this.m_Radius + offsetDist, this.m_StartAngle, this.m_EndAngle, this.m_Normal); - arcArr.push(arc); + let arc = this.Clone() as Arc; + arc.Radius = offsetDist + this.m_Radius; + return [arc]; } - return arcArr; + return []; } Extend(newParam: number) { - if (0 > newParam || newParam > 1) + this.WriteAllObjectRecord(); + if (newParam < 0) { - if (newParam > 1) - { - newParam -= 1; - } - let allAngle = Math.abs(this.getArcBul(newParam)); - - if (allAngle + Math.abs(this.getArcBul()) < (2 * Math.PI))//原弧长+延伸<圆 - { - this.SetExtendPointAngle(newParam, allAngle); - } + this.m_StartAngle = this.GetAngleAtParam(newParam); + } + else if (newParam > 1) + { + this.m_EndAngle = this.GetAngleAtParam(newParam); } + this.Update(); } Reverse() @@ -295,92 +310,105 @@ export class Arc extends Curve } if (curve instanceof Line) { - return IntersectLineAndArc(curve, this, intType); + return IntersectLineAndArc(curve, this, reverseIntersectOption(intType)); } if (curve instanceof Circle) { - return IntersectCircleAndArc(curve, this, intType); + return IntersectCircleAndArc(curve, this, reverseIntersectOption(intType)); } + if (curve instanceof Polyline) + return IntersectPolylineAndCurve(curve, this, reverseIntersectOption(intType)) return []; } - //******************** Curve function end*****************// - SetExtendPointAngle(newParam: number, allAngle: number) + /** + * 计算出圆弧所包含的角度 + * + * @readonly + * @type {number} + * @memberof Arc + */ + get AllAngle(): number { - let pmXAngle: number = 0; - if (0 > newParam) + return this.ComputeAnlge(this.m_EndAngle); + } + + /** + * 计算所包含的角度 + * + * @private + * @param {number} endAngle 结束的角度 + * @returns + * @memberof Arc + */ + private ComputeAnlge(endAngle: number) + { + //顺时针 + if (this.m_Clockwise) { - if (this.m_StartAngle + allAngle > 2 * Math.PI) - this.m_StartAngle = this.m_StartAngle + allAngle - 2 * Math.PI; - else - this.m_StartAngle = this.m_StartAngle + allAngle; + if (this.m_StartAngle > endAngle) + return this.StartAngle - endAngle; + else //越过0点绘制圆弧 + return (Math.PI * 2) - (endAngle - this.m_StartAngle); } else { - if (this.m_EndAngle - allAngle >= 0) - this.m_EndAngle = this.m_EndAngle - allAngle; + if (endAngle > this.m_StartAngle) + return endAngle - this.m_StartAngle; else - this.m_EndAngle = this.m_EndAngle - allAngle + 2 * Math.PI; + return (Math.PI * 2) - (this.m_StartAngle - endAngle); } } - getArcBul(param: number = 1)//圆心角 + /** + * 解析两点和凸度所构成的圆弧 + * + * @param {THREE.Vector2} p1 + * @param {THREE.Vector2} p2 + * @param {number} bul 凸度,在cad中,凸度为 <(四分之一圆心角)的正切值> + * @memberof Arc + */ + ParseFromBul(p1: Vector3 | Vector2, p2: Vector3 | Vector2, bul: number): Arc { - let ptArr = this.GetStretchPoints(); - return getArcAngle(ptArr[0], ptArr[1], ptArr[2]) * param; - } + if (p1 instanceof Vector2) + p1 = Vec2DTo3D(p1); + if (p2 instanceof Vector2) + p2 = Vec2DTo3D(p2); - GetParamAngle(param: number)//返回相对于x轴正方向所形成的角度 - { - let pmAngle = 0; - if (this.m_EndAngle < this.m_StartAngle) - { - pmAngle = (this.m_StartAngle - this.m_EndAngle) * param + this.m_EndAngle; - } - else - { - pmAngle = (this.m_EndAngle - this.m_StartAngle) * param + this.m_StartAngle + Math.PI; - } - return pmAngle; + //弦向量 + let chordV = p2.clone().sub(p1); + //弦角度 + let chordAn = angle(chordV); + //弦长度/2 + let chordLengthHalf = chordV.length() / 2; + + let allAngle = Math.atan(bul) * 4; + let HalfAngle = allAngle * 0.5; + //半径 + this.m_Radius = chordLengthHalf / Math.sin(HalfAngle); + + //指向圆心的角度 + let toCenterAn = chordAn + Math.PI * 0.5;//弦角度转90 + + //圆心 + this.m_Center = midPoint(p1, p2); + polar(this.m_Center, toCenterAn, this.m_Radius - (bul * chordLengthHalf)); + + this.m_Radius = Math.abs(this.m_Radius); + + this.m_StartAngle = angle(p1.clone().sub(this.m_Center)); + this.m_EndAngle = angle(p2.clone().sub(this.m_Center)); + + this.m_Clockwise = bul < 0; + + return this; } FromThreePoint(pt1: Vector3, pt2: Vector3, pt3: Vector3) { if (!(pt1 && pt2 && pt3)) return; - - // 通过三个点到圆心距离相等建立方程: - // (2 * pt2.x - 2 * pt1.x) * center.x + (2 * pt1.y - 2 * pt2.y) * center.y=pt1.y2+pt2.x2-pt1.x2-pt2.y2 - // (2 * pt3.x - 2 * pt2.x) * center.x + (2 * pt2.y - 2 * pt3.y) * center.y=pt2.y2+pt3.x2-pt2.x2-pt3.y2 - // 令: - // a1 = 2 * pt2.x - 2 * pt1.x b1 = 2 * pt1.y - 2 * pt2.y c1 = pt1.y2+pt2.x2-pt1.x2-pt2.y2 - // a2 = 2 * pt3.x - 2 * pt2.x b2 = 2 * pt2.y - 2 * pt3.y c2 = pt2.y2+pt3.x2-pt2.x2-pt3.y2 - - // 则上述方程组变成一下形式: - // a1 * center.x + b1 * center.y=c1; - // a2 * center.x + b2 * center.y=c2 - // 联立以上方程组可以求出: - // center.x = (c1 * b2 - c2 * b1) / a1 * b2 - a2 * b1; - // center.y = (a1 * c2 - a2 * c1) / a1 * b2 - a2 * b1; - let a1 = pt1.x - pt2.x; - let b1 = pt1.y - pt2.y; - let c1 = (Math.pow(pt1.x, 2) - Math.pow(pt2.x, 2) + Math.pow(pt1.y, 2) - Math.pow(pt2.y, 2)) / 2; - let a2 = pt3.x - pt2.x; - let b2 = pt3.y - pt2.y; - let c2 = (Math.pow(pt3.x, 2) - Math.pow(pt2.x, 2) + Math.pow(pt3.y, 2) - Math.pow(pt2.y, 2)) / 2; - //令temp = A1*B2 - A2*B1 - let temp = a1 * b2 - a2 * b1; - //判断三点是否共线 - if (temp === 0) - { - return; - } - else - { - //不共线则求出圆心: - this.m_Center.x = (c1 * b2 - c2 * b1) / temp; - this.m_Center.y = (a1 * c2 - a2 * c1) / temp; - } + this.m_Center = getCircleCenter(pt1, pt2, pt3); //用圆心和其中一个点求距离得到半径: this.m_Radius = this.m_Center.distanceTo(pt1); //起始角度 端点角度 @@ -395,7 +423,7 @@ export class Arc extends Curve p2.y = pt3.y - pt1.y; //叉积 //this.m_Normal = p1.clone().cross(p2).normalize(); - let normal = Math.tan(getArcAngle(pt1, pt2, pt3) * 0.25); + let normal = Math.tan(getArcAngleBy3Pt(pt1, pt2, pt3) * 0.25); if (normal > 0) { let startAngle = this.m_StartAngle; @@ -452,18 +480,10 @@ export class Arc extends Curve } GetStretchPoints(): Array { - //用角度求出三个点位置 - let startPoint = new Vector3(); - let endPoint = new Vector3(); - let midPoint = new Vector3(); - polar(startPoint, this.m_StartAngle, this.m_Radius); - polar(endPoint, this.m_EndAngle, this.m_Radius); - polar(midPoint, this.GetParamAngle(0.5), this.m_Radius); - return [ - this.m_Center.clone().add(startPoint), - this.m_Center.clone().add(midPoint), - this.m_Center.clone().add(endPoint), + this.StartPoint, + this.GetPointAtParam(0.5), + this.EndPoint, this.m_Center.clone(), ] } @@ -493,47 +513,28 @@ export class Arc extends Curve GetParamAtDist(d: number) { - let pmAtDist: number = 0; - pmAtDist = d / this.GetDistAtParam(1); - return pmAtDist; + return d / this.Length; } GetFistDeriv(pt: number | Vector3) { + let an: number; if (typeof pt === "number") { - pt = this.GetPointAtParam(pt); + an = this.GetAngleAtParam(pt); } else - pt = pt.clone(); + an = angle(pt.sub(this.m_Center)); - let an = angle(pt.sub(this.Center)) + Math.PI * 0.5; - - let d = new Vector3(); - polar(d, an, 1); - return d; + an += Math.PI * 0.5 * (this.m_Clockwise ? -1 : 1); + return polar(new Vector3(), an, this.m_Radius) as Vector3; } GetClosestPointTo(pt: Vector3, extend: boolean): Vector3 { let l = new Line(this.Center, pt); - if (extend) - { - let pts = l.IntersectWith(this, IntersectOption.ExtendBoth); - return pt.distanceTo(pts[0]) < pt.distanceTo(pts[1]) ? pts[0] : pts[1]; - } - - //单向延伸可能有两个,一个,和0个交点 - let pts = l.IntersectWith(this, IntersectOption.ExtendThis); - switch (pts.length) - { - case 0: - return pt.distanceTo(this.StartPoint) < pt.distanceTo(this.EndPoint) ? this.StartPoint : this.EndPoint; - case 1: - return pts[0]; - case 2: - return pt.distanceTo(pts[0]) < pt.distanceTo(pts[1]) ? pts[0] : pts[1]; - default: - return; - } + let inPts: Vector3[] = this.IntersectWith(l, extend ? IntersectOption.ExtendBoth : IntersectOption.ExtendArg); + if (inPts.length < 2) + inPts.push(this.StartPoint, this.EndPoint); + return inPts.reduce((p1, p2) => p1.distanceToSquared(pt) < p2.distanceToSquared(pt) ? p1 : p2); } //#region -------------------------File------------------------- //对象应该实现dataIn和DataOut的方法,为了对象的序列化和反序列化 diff --git a/src/DatabaseServices/Circle.ts b/src/DatabaseServices/Circle.ts index 82eb9af28..bef838036 100644 --- a/src/DatabaseServices/Circle.ts +++ b/src/DatabaseServices/Circle.ts @@ -4,7 +4,7 @@ import { Box3, EllipseCurve, Geometry, Matrix4, Vector3, Object3D } from 'three' import { ColorMaterial } from '../Common/ColorPalette'; import { rotateLine } from '../Common/CurveUtils'; import { Arc } from '../DatabaseServices/Arc'; -import { angle, angleTo, equaln, polar } from '../Geometry/GeUtils'; +import { angle, angleTo, equaln, polar, angleTo2Pi } from '../Geometry/GeUtils'; import { RenderType } from '../GraphicsSystem/Enum'; import { @@ -12,11 +12,14 @@ import IntersectCircleAndArc, IntersectCircleAndCircle, IntersectLineAndCircle, + reverseIntersectOption, + IntersectPolylineAndCurve, } from '../GraphicsSystem/IntersectWith'; import { Factory } from './CADFactory'; import { CADFile } from './CADFile'; import { Curve } from './Curve'; import { Line } from './Line'; +import { Polyline } from './Polyline'; @Factory export class Circle extends Curve @@ -51,6 +54,27 @@ export class Circle extends Curve } //******************** Curve function start*****************// + get StartPoint(): Vector3 + { + let startPt = new Vector3(this.m_Radius, 0, 0); + this.m_Center.clone().add(startPt); + return startPt; + } + get StartParam(): number + { + return 0; + } + get EndPoint(): Vector3 + { + let endPt = new Vector3(this.m_Radius, 0, 0); + this.m_Center.clone().add(endPt); + return endPt; + } + get EndParam(): number + { + return 1; + } + get Area() { return Math.PI * Math.pow(this.m_Radius, 2); @@ -60,6 +84,11 @@ export class Circle extends Curve return Math.PI * 2 * this.m_Radius; } + get IsClose(): boolean + { + return true; + } + GetPointAtParam(param: number) { let ptAtPm = new Vector3(); @@ -100,56 +129,42 @@ export class Circle extends Curve GetSplitCurves(param: number[] | number) { - let anglelist = new Array(); - let curvelist = new Array(); + let anglelist: number[]; if (param instanceof Array) { - for (let pm of param) + if (param.length < 2) return []; + param.sort(); + + anglelist = []; + for (let p of param) { - anglelist.push(2 * Math.PI * pm); + if (!isNaN(p) && p >= 0 && p <= 1) + anglelist.push(Math.PI * 2 * p); } + anglelist.push(anglelist[0]); + anglelist.reverse(); } else { - anglelist.push(2 * Math.PI * param); + return []; } + + let curvelist = new Array(); for (let i = 0; i < anglelist.length - 1; i++) { let arc = new Arc(this.m_Center, this.m_Radius, anglelist[i], anglelist[i + 1]); curvelist.push(arc); } - - let arc = new Arc(this.m_Center, this.m_Radius, anglelist[anglelist.length - 1], anglelist[0]); - curvelist.push(arc); - return curvelist; } GetParamAtPoint(pt?: Vector3) { - if (!pt) + if (!this.PtOnCurve(pt)) { - return; + return NaN; } - let pmAtPt: number = 0; - let startPt = new Vector3(0, 0, 0); - polar(startPt, 0, this.m_Radius); - startPt = this.m_Center.clone().add(startPt); - //求出向量 - let p1 = new Vector3(0, 0, 0); - p1.x = pt.x - this.m_Center.x; - p1.y = pt.y - this.m_Center.y; - let p2 = new Vector3(0, 0, 0); - p2.x = startPt.x - this.m_Center.x; - p2.y = startPt.y - this.m_Center.y; - - pmAtPt = angleTo(p2, p1); - if (pmAtPt < 0) - { - pmAtPt = 2 * Math.PI + pmAtPt; - } - pmAtPt = pmAtPt / (2 * Math.PI); - return pmAtPt; + return angle(pt.clone().sub(this.m_Center)) / (Math.PI * 2); } PtOnCurve(pt: Vector3) @@ -181,15 +196,16 @@ export class Circle extends Curve } if (curve instanceof Line) { - return IntersectLineAndCircle(curve, this, intType); + return IntersectLineAndCircle(curve, this, reverseIntersectOption(intType)); } if (curve instanceof Circle) { - return IntersectCircleAndCircle(this, curve, intType); + return IntersectCircleAndCircle(this, curve); } + if (curve instanceof Polyline) + return IntersectPolylineAndCurve(curve, this, reverseIntersectOption(intType)) return []; } - //******************** Curve function end*****************// get BoundingBox(): Box3 @@ -292,9 +308,7 @@ export class Circle extends Curve let l = new Line(this.Center, pt); let pts = l.IntersectWith(this, IntersectOption.ExtendBoth); let ptIns = pt.distanceTo(pts[0]) < pt.distanceTo(pts[1]) ? pts[0] : pts[1]; - return ptIns; - } //#region -------------------------File------------------------- //对象应该实现dataIn和DataOut的方法,为了对象的序列化和反序列化 diff --git a/src/DatabaseServices/Curve.ts b/src/DatabaseServices/Curve.ts index a5a1ad1c9..44e775233 100644 --- a/src/DatabaseServices/Curve.ts +++ b/src/DatabaseServices/Curve.ts @@ -7,6 +7,27 @@ import { Factory } from './CADFactory'; import { Entity } from './Entity'; +export enum ExtendType +{ + /** + * 前后都不延伸 + */ + None = 0, + /** + * 只允许延伸前面 + */ + Front = 1, + /** + * 只允许延伸后面 + */ + Back = 2, + /** + * 前后延伸 + */ + Both = 3, +} + + /** * 曲线的基类,子类请实现以下方法. * @@ -67,7 +88,11 @@ export abstract class Curve extends Entity //翻转曲线.首尾调换. Reverse() { }; - PtOnCurve(pt: Vector3): boolean { return; } + //点在曲线内部 + PtOnCurve(pt: Vector3): boolean { return false; } + + //参数在曲线内部 + ParamOnCurve(param: number): boolean { return !isNaN(param) && param >= 0 && param <= this.EndParam; } GetOffsetCurves(offsetDist: number): Array { return; } GetClosestPointTo(pt: Vector3, extend: boolean): Vector3 { return; } diff --git a/src/DatabaseServices/Ellipse.ts b/src/DatabaseServices/Ellipse.ts index 4cd5b435d..b66cac1cc 100644 --- a/src/DatabaseServices/Ellipse.ts +++ b/src/DatabaseServices/Ellipse.ts @@ -1,11 +1,10 @@ -import { Factory } from "./CADFactory"; -import { Entity } from "./Entity"; -import { Vector3, Geometry, Matrix4 } from "three"; -import { RenderType } from "../GraphicsSystem/Enum"; -import { ColorMaterial } from "../Common/ColorPalette"; -import * as THREE from "three"; -import { cZAxis } from "../Geometry/GeUtils"; -import { CADFile } from "./CADFile"; +import { Geometry, Matrix4, Object3D, Vector3 } from 'three'; +import * as THREE from 'three'; + +import { ColorMaterial } from '../Common/ColorPalette'; +import { RenderType } from '../GraphicsSystem/Enum'; +import { Factory } from './CADFactory'; +import { CADFile } from './CADFile'; import { Curve } from './Curve'; @Factory @@ -79,33 +78,25 @@ export class Ellipse extends Curve this.m_Center.applyMatrix4(m); this.Update(); } - Draw(renderType: RenderType): THREE.Object3D - { - let obj = super.Draw(renderType); - if (obj) return obj; - - let curve = this.createCurve(); - let geometry = new Geometry().setFromPoints(curve.getPoints(60)); + InitDrawObject(renderType: RenderType = RenderType.Wireframe): Object3D + { + let geometry = new Geometry(); + this.UpdateGeometry(geometry); let ellipseObj = new THREE.Line(geometry, ColorMaterial.GetLineMaterial(this.m_Color)); - - this.m_DrawEntity.set(renderType, ellipseObj); - ellipseObj.userData = this; return ellipseObj; } - Update() + UpdateDrawObject(type: RenderType, en: Object3D) { - for (let [, obj] of this.m_DrawEntity) - { - let geo = obj["geometry"] as Geometry; - - let curve = this.createCurve(); - - geo.setFromPoints(curve.getPoints(60)); - - geo.verticesNeedUpdate = true; - geo.computeBoundingSphere(); - } + let geo = en["geometry"] as Geometry; + this.UpdateGeometry(geo); + } + //更新Geometry + private UpdateGeometry(geo: THREE.Geometry) + { + let curve = this.createCurve(); + geo.setFromPoints(curve.getPoints(60)); + geo.verticesNeedUpdate = true; } GetStretchPoints(): Array { diff --git a/src/DatabaseServices/Entity.ts b/src/DatabaseServices/Entity.ts index 2256ad822..23bc6f579 100644 --- a/src/DatabaseServices/Entity.ts +++ b/src/DatabaseServices/Entity.ts @@ -40,6 +40,14 @@ export class Entity extends CADObject return this.m_Color; } + /** + * 炸开实体 + * + * @returns {Entity[]} + * @memberof Entity + */ + Export(): Entity[] { return [] } + /** * 返回对象的包围框. * diff --git a/src/DatabaseServices/Line.ts b/src/DatabaseServices/Line.ts index 1c21ff848..5144f8f19 100644 --- a/src/DatabaseServices/Line.ts +++ b/src/DatabaseServices/Line.ts @@ -1,16 +1,23 @@ //直线对象 -import { Geometry, Matrix4, Object3D, Vector3 } from 'three'; import * as THREE from 'three'; +import { Geometry, Matrix4, Object3D, Vector3, Box3 } from 'three'; import { ColorMaterial } from '../Common/ColorPalette'; import { equal, polar } from '../Geometry/GeUtils'; import { RenderType } from '../GraphicsSystem/Enum'; -import { IntersectOption, IntersectLineAndArc, IntersectLineAndLine, IntersectLineAndCircle } from '../GraphicsSystem/IntersectWith'; +import +{ + IntersectLineAndArc, + IntersectLineAndCircle, + IntersectLineAndLine, + IntersectOption, + reverseIntersectOption, +} from '../GraphicsSystem/IntersectWith'; import { Arc } from './Arc'; import { Factory } from './CADFactory'; import { CADFile } from './CADFile'; -import { Curve } from './Curve'; import { Circle } from './Circle'; +import { Curve } from './Curve'; @Factory export class Line extends Curve @@ -185,7 +192,7 @@ export class Line extends Curve GetClosestPointTo(pt: Vector3, extend: boolean): Vector3 { let an = this.GetFistDerivAngle(0) + Math.PI * 0.5; - let line = new Line(pt, polar(pt.clone(), an, 1)); + let line = new Line(pt, polar(pt.clone(), an, 1) as Vector3); //交点 let pt_int = this.IntersectWith(line, IntersectOption.ExtendBoth)[0]; if (extend) return pt_int; @@ -219,10 +226,18 @@ export class Line extends Curve { let an = this.GetFistDerivAngle(0) - Math.PI * 0.5; let newLine = this.Clone() as Line; - newLine.StartPoint = polar(this.StartPoint, an, offsetDist); - newLine.EndPoint = polar(this.EndPoint, an, offsetDist); + newLine.StartPoint = polar(this.StartPoint, an, offsetDist) as Vector3; + newLine.EndPoint = polar(this.EndPoint, an, offsetDist) as Vector3; return [newLine]; } + get BoundingBox(): Box3 + { + let pts = [ + this.m_StartPoint, + this.m_EndPoint + ]; + return new Box3().setFromPoints(pts); + } get StartParam() { diff --git a/src/DatabaseServices/Polyline.ts b/src/DatabaseServices/Polyline.ts index 2b44e1031..0cd16f6a0 100644 --- a/src/DatabaseServices/Polyline.ts +++ b/src/DatabaseServices/Polyline.ts @@ -1,42 +1,51 @@ -import { Geometry, Matrix4, Object3D, Vector2, Vector3 } from 'three'; import * as THREE from 'three'; +import { Geometry, Matrix4, Object3D, Vector2, Vector3, Box3 } from 'three'; import { CreateBoardUtil } from '../ApplicationServices/mesh/createBoard'; import { ColorMaterial } from '../Common/ColorPalette'; import { - getArcAngle, + getArcAngleBy3Pt, getArcArea, - getArcData, - getArcPtLenAngle, + getArcProps, + getArcPtLenAndAngle, + getArcAngle, getClosestPt, getCurveLength, getDeterminant, - getPointAtParam, - isAtArc, + getPtAtCurveParam, + isPtOnArc, rotateLine, Vec2DTo3D, Vec3DTo2D, + ExtendDir, } from '../Common/CurveUtils'; -import { equal } from '../Geometry/GeUtils'; +import { equal, equaln } from '../Geometry/GeUtils'; import { RenderType } from '../GraphicsSystem/Enum'; import { Factory } from './CADFactory'; import { CADFile } from './CADFile'; -import { Curve } from './Curve'; +import { Curve, ExtendType } from './Curve'; +import { app } from '../ApplicationServices/Application'; +import { angleTo } from './../Geometry/GeUtils'; +import { IntersectOption, IntersectLineAndCircle, IntersectLAndL, IntersectPolylineAndCurve } from '../GraphicsSystem/IntersectWith'; +import { intercept } from 'mobx'; +import { Line } from './Line'; +import { Arc } from './Arc'; +import { FixIndex, ArrayRemove, Last } from '../Common/Utils'; +import { Circle } from './Circle'; -export interface PolylineData +export interface PolylineProps { pt: Vector2, bul: number } - @Factory export class Polyline extends Curve { //多段线构造数据 - private m_LineData: PolylineData[]; + private m_LineData: PolylineProps[]; private m_ClosedMark: boolean; - constructor(data?: PolylineData[]) + constructor(data?: PolylineProps[]) { super(); this.m_LineData = data || [{ pt: new Vector2(0, 0), bul: 0 }]; @@ -70,7 +79,7 @@ export class Polyline extends Curve } this.Update(); } - set LineData(data: PolylineData[]) + set LineData(data: PolylineProps[]) { this.WriteAllObjectRecord(); this.m_LineData = data; @@ -80,12 +89,41 @@ export class Polyline extends Curve { return this.m_LineData; } + //多段线起点 + get StartPoint() + { + if (this.m_LineData.length > 0) + return Vec2DTo3D(this.m_LineData[0].pt) + return new Vector3(); + } + get EndPoint() + { + if (this.m_ClosedMark) return this.StartPoint; + if (this.m_LineData.length > 0) + return Vec2DTo3D(this.m_LineData[this.EndParam].pt) + return new Vector3(); + } get StartParam() { return 0; } + + /** + * 表示最后一条曲线的终止参数,使用该参数可以直接遍历到多段线的所有子线段. for(i this.m_LineData.length - 1 || param < 0) - throw new Error("输入参数范围错误"); - // 在曲线的位置0~1之间 - let seg = param - Math.floor(param); - let startV; - let endV; - let pt: Vector3 = new Vector3(); - if (seg === 0) - { - startV = this.m_LineData[param]; - pt.set(startV.pt.x, startV.pt.y, 0); - } else + let cu: Curve = this.GetCurveAtParam(param); + if (cu) { - param = Math.floor(param); - startV = this.m_LineData[param]; - endV = this.m_LineData[param + 1]; - pt = getPointAtParam(startV.pt, endV.pt, startV.bul, seg); + return cu.GetPointAtParam(this.GetCurveParamAtParam(param)); } - return pt; + return undefined; } - //√ + GetDistAtParam(param: number): number { - if (param > this.m_LineData.length - 1 || param < 0) - throw new Error("输入参数范围错误"); - // 在曲线的位置0~1之间 - let seg = param - Math.floor(param); - let startV; - let endV; - let dist: number = 0; - for (let i = 0; i < Math.floor(param); i++) + if (this.m_ClosedMark && !this.ParamOnCurve(param)) + return NaN; + + //参数 整数 + let paramFloor = Math.floor(param); + //需要计算的曲线个数 + let cuCout = paramFloor > this.EndParam ? this.EndParam : paramFloor; + + let dist = 0; + //首先计算完整曲线的长度 + for (let i = 0; i < cuCout; i++) { - startV = this.m_LineData[i]; - endV = this.m_LineData[i + 1]; - dist += getCurveLength(startV.pt, endV.pt, startV.bul); + dist += this.GetCurveAtIndex(i).Length; } - if (seg > 0) + + //参数已经大于索引,证明参数在线外. + if (paramFloor != cuCout) + { + dist += this.GetCurveAtParam(param).GetDistAtParam(param - cuCout); + } + else if (param > paramFloor) { - startV = this.m_LineData[Math.floor(param)]; - endV = this.m_LineData[Math.floor(param) + 1]; - dist += getCurveLength(startV.pt, endV.pt, startV.bul) * seg; + let lastParam = param - paramFloor; + dist += this.GetCurveAtParam(param).GetDistAtParam(lastParam); } + return dist; } - //√ GetPointAtDistance(dist: number): Vector3 { - let param = this.GetParamAtDist(dist); - return this.GetPointAtParam(param); } - //√ + /** + * 返回参数所在的点. 如果曲线不闭合,会试图返回延伸点参数 + * + * @param {Vector3} pt + * @returns {number} + * @memberof Polyline + */ GetParamAtPoint(pt: Vector3): number { - let param: number; - let startV: PolylineData; - let endV: PolylineData; + let cus = this.Export(); + if (cus.length === 0) return NaN; + for (let i = 0; i < cus.length; i++) + { + let cu = cus[i]; + let param = cu.GetParamAtPoint(pt); + if (cu.ParamOnCurve(param)) + return i + param; //返回点在曲线内部的参数 + } - for (let i = 0; i < this.m_LineData.length - 1; i++) + //当曲线闭合时,不需要延伸首尾去判断参数 + if (this.m_ClosedMark) return NaN; + + //起点终点参数集合 + let seParams: number[] = []; + //点在第一条曲线上的参数 + let startParam = cus[0].GetParamAtPoint(pt); + if (!isNaN(startParam) && startParam < 0) + seParams.push(startParam); + //点在最后一条线上的参数 + let endParam = cus[cus.length - 1].GetParamAtPoint(pt); + if (!isNaN(endParam) && endParam > 0) + seParams.push(endParam + this.EndParam - 1); + + if (seParams.length == 1) { - startV = this.m_LineData[i]; - endV = this.m_LineData[i + 1]; - if (Vec3DTo2D(pt).equals(startV.pt)) - { - param = i; - break; - } - if (Vec3DTo2D(pt).equals(endV.pt)) - { - param = i + 1; - break; - } - if (startV.bul === 0) - { - let plLine = Vec2DTo3D(endV.pt).sub(Vec2DTo3D(startV.pt)); - let ptLine = pt.clone().sub(Vec2DTo3D(startV.pt)); - //点是否在线上 - if (plLine.angleTo(ptLine) === 0) - { - if (plLine.lengthSq() > ptLine.lengthSq()) - { - param = i + ptLine.length() / plLine.length(); - break; - } - else continue; - } - } else - { - //点是否在圆弧上 - if (isAtArc(startV.pt, endV.pt, startV.bul, pt)) - { - let lastLen = getCurveLength(startV.pt, endV.pt, startV.bul); - let arcLen = getArcPtLenAngle(startV.pt, endV.pt, startV.bul, pt).len; - if (lastLen - arcLen > 0) - { - param = i + arcLen / lastLen; - break; - } - } - } + return seParams[0]; } - // if (param === undefined) throw new Error("点不在曲线上") - return param; + else if (seParams.length == 2) + { + //返回较近的参数 + return pt.distanceToSquared(this.StartPoint) < pt.distanceToSquared(this.EndPoint) ? + startParam : endParam; + } + + return NaN; } GetParamAtDist(dist: number): number { - let totalDist = this.CreateCurve().getLength(); - if (dist < 0 || dist > totalDist) - throw new Error("输入参数范围错误"); - let param = 0; - let startV; - let endV; - let tmpDist = 0; - let lastDist = 0; - for (let i = 0; i < this.m_LineData.length - 1; i++) + let cus = this.Export(); + for (let i = 0; i < cus.length; i++) { - startV = this.m_LineData[i]; - endV = this.m_LineData[i + 1]; - lastDist = getCurveLength(startV.pt, endV.pt, startV.bul); - tmpDist += lastDist; - if (tmpDist >= dist) + let cu = cus[i]; + let len = cu.Length; + if (dist <= len) { - param = i + 1; - break; + return i + cu.GetParamAtDist(dist); } + dist -= len; } - if (tmpDist - dist > 0) - { - param -= (tmpDist - dist) / lastDist; - } - return param; + if (!this.m_ClosedMark) + return cus.length + cus[cus.length - 1].GetParamAtDist(dist); + + return NaN; } - //√ GetDistAtPoint(pt: Vector3): number { - if (!this.PtOnCurve) throw new Error("点不在线上"); - - return this.GetDistAtParam(this.GetParamAtPoint(pt)); + let param = this.GetParamAtPoint(pt); + if (!this.ParamOnCurve(param)) return NaN; + return this.GetDistAtParam(param); } - //一阶导数角度值 - GetFistDerivAngle(param: number | Vector3): number + + /** + * 返回曲线的一阶导数. + * 当曲线闭合(标志)且点不在曲线上. + * 或者曲线不闭合(标志) 且点不在曲线上也不在延伸上 + * + * @param {(number | Vector3)} param + * @returns {Vector3} + * @memberof Polyline + */ + GetFistDeriv(param: number | Vector3): Vector3 { - let pt: Vector3; if (param instanceof Vector3) - { - pt = param; param = this.GetParamAtPoint(param); - } else + + if (isNaN(param)) + return undefined; + + let cu = this.GetCurveAtParam(param); + + if (!cu) return undefined; + + return cu.GetFistDeriv(this.GetCurveParamAtParam(param)); + } + private copyPolyline(plData: PolylineProps[]): Polyline + { + let pl = this.Clone() as Polyline; + pl.LineData = plData; + return pl; + } + + + GetSplitCurves(param: number[] | number): Array + { + //参数需要转化为参数数组 + let params: number[]; + if (typeof param == "number") + params = [param]; + else + params = param; + + //校验参数在曲线中 + params = params.filter(p => this.ParamOnCurve(p)); + //排序 + params.sort((a, b) => a - b); + //必须加入最后一个参数,保证切割后的曲线完整 + params.push(this.EndParam); + params = [...new Set(params)]; + if (params.length === 0) + return []; + + //判断是否存在0参数 + let hasZeroParam = params[0] == 0; + if (hasZeroParam) + params.shift(); + + //点集和凸度集合 + let pts = this.m_LineData.map(d => d.pt.clone()); + let buls = this.m_LineData.map(d => d.bul); + + //返回的多段线集合 + let pls: Polyline[] = []; + + let len = 0;//已经走过的参数长度(整数) + + //上一个切割参数的位置 0-1 + let prePa = 0; + for (let pa of params) { - pt = this.GetPointAtParam(param); + //参数所在点 + let pt = Vec3DTo2D(this.GetPointAtParam(pa)); + pa -= len; + let pafloor = Math.floor(pa); + len += pafloor; + + let plData: PolylineProps[] = []; + + //添加点 + for (let i = 0; i < pafloor; i++) + { + if (i == 0 && buls[0] != 0) + { + buls[0] = Math.tan((1 - prePa) * Math.atan(buls[0])); + } + plData.push({ pt: pts[0], bul: buls[0] }); + pts.shift(); + buls.shift(); + } + + if (equaln(pa, pafloor))//如果pa在点上 + { + plData.push({ pt: pts[0].clone(), bul: buls[0] }); + } + else //在曲线上 + { + let bul: number = buls[0]; + if (bul != 0) + bul = Math.tan((pa - pafloor - (0 === pafloor ? prePa : 0)) * Math.atan(buls[0])); //->凸度 + + //加入顶点+凸度 + plData.push({ pt: pts[0].clone(), bul }); + //终点 + plData.push({ pt, bul: 0 }); + + //修正剩余的点表和凸度表 + pts[0].copy(pt); + } + + prePa = pa - pafloor; + pls.push(new Polyline(plData)); } - let startV = this.m_LineData[Math.floor(param)]; - let endV = this.m_LineData[Math.floor(param) + 1]; - if (param === this.m_LineData.length - 1) endV = this.m_LineData[0]; - let slope: number; - if (startV.bul === 0) + //当曲线为闭合曲线,并且不存在0切割参数时,首尾连接曲线 + if (this.m_ClosedMark && !hasZeroParam) { - let line = endV.pt.clone().sub(startV.pt); - slope = line.x === 0 ? 1 : line.y / line.x; + let lastPl = pls[pls.length - 1]; + lastPl.m_LineData.push(...pls[0].m_LineData); + + pls.shift(); } - else + return pls; + } + + Extend(newParam: number) + { + if (this.CloseMark || this.ParamOnCurve(newParam)) return; + + let ptIndex: number; + let bulIndex: number; + + if (newParam < 0) + { + ptIndex = 0; + bulIndex = 0; + } + else if (newParam > this.EndParam) { - let arc = getArcData(startV.pt, endV.pt, startV.bul); - let center = arc.centerPt; - slope = pt.y === center.y ? 1 : -((pt.x - center.x) / (pt.y - center.y)) + ptIndex = this.EndParam; + bulIndex = ptIndex - 1; } - return Math.atan(slope); + + //修改顶点 + this.m_LineData[ptIndex].pt = Vec3DTo2D(this.GetPointAtParam(newParam)); + + //修改凸度 + let oldBul = this.m_LineData[bulIndex].bul; + if (oldBul != 0) + this.m_LineData[bulIndex].bul = Math.tan(Math.atan(oldBul) * (1 + newParam - ptIndex)); + + this.Update(); } - GetFistDeriv(param: number | Vector3): Vector3 + PtOnCurve(pt: Vector3): boolean { - let fistDeriv = new Vector3(1, 0, 0); - let slope = this.GetFistDerivAngle(param); - rotateLine(fistDeriv, slope); - return fistDeriv.normalize(); - + let param = this.GetParamAtPoint(pt); + return this.ParamOnCurve(param); } - GetSplitCurves(param: number[] | number): Array + GetClosestPointTo(pt: Vector3, extend: boolean): Vector3 { - let plList: Array = []; - //合并前后封闭曲线数据 - const mergeCurveData = (par1, par2) => - { - let plDataList = this.spliteCurveData("later", par2); - plDataList.pop(); - plDataList.push(...this.spliteCurveData("front", par1)); - return plDataList; - } - if (Array.isArray(param)) + return this.GetClosestPointTo2(pt, extend ? ExtendType.Both : ExtendType.None); + } + GetClosestPointTo2(pt: Vector3, extType: ExtendType): Vector3 + { + //当曲线空时,返回空 + if (this.EndParam < 1) return undefined; + //当有闭合标志时,曲线在任何位置都不延伸 + if (this.m_ClosedMark) extType = ExtendType.None; + + //最近点 + let ptC = this.StartPoint; + //最近点的距离 + let ptCDist = ptC.distanceToSquared(pt); + + for (let i = 0; i < this.EndParam; i++) { - if (Math.max(...param) > this.m_LineData.length - 1 - || Math.min(...param) < 0) - return; - for (let i = 1; i < param.length; i++) + let cu = this.GetCurveAtIndex(i); + + //前延伸 + if (i === 0 && (extType & ExtendType.Front) > 0) { - plList.push(new Polyline(this.spliteCurveData("mid", param[i - 1], param[i]))); + let ptCFirst = cu.GetClosestPointTo(pt, true); + if (cu.GetParamAtPoint(ptCFirst) <= 1) + { + ptC = ptCFirst; + ptCDist = ptC.distanceToSquared(pt); + } + } + + let ptCloseNew: Vector3; //新的最近点 + + //后延伸 (此处与前延伸分开if 如果线只有一段,那么前后延伸都能同时触发) + if (i === (this.EndParam - 1) && (extType & ExtendType.Back) > 0) + { + let ptCLast = cu.GetClosestPointTo(pt, true); + if (cu.GetParamAtPoint(ptCLast) >= 0) + ptCloseNew = ptCLast; + else //如果延伸之后并不在曲线或者曲线的后延伸上 + ptCloseNew = cu.EndPoint; } - if (this.IsClose) + else if (i === 0) //如果i是首条线,并且又不存在后延伸,那么跳过该计算 { - plList.push(new Polyline(mergeCurveData(param[0], param[param.length - 1]))); + continue; } else { - plList.unshift(new Polyline(this.spliteCurveData("front", param[0]))); - plList.push(new Polyline(this.spliteCurveData("later", param[param.length - 1]))); + ptCloseNew = cu.GetClosestPointTo(pt, false); + } + + let newDist = ptCloseNew.distanceToSquared(pt); + if (newDist < ptCDist) + { + ptC = ptCloseNew; + ptCDist = newDist; } } - else + + return ptC; + } + + + //偏移 + GetOffsetCurves(offsetDist: number): Array + { + let plList: Array = []; + for (let i = 0; i < this.EndParam; i++) { - if (this.IsClose) - { - plList.push(new Polyline(mergeCurveData(param, param))); - } else - plList.push(new Polyline(this.spliteCurveData("front", param)), new Polyline(this.spliteCurveData("later", param))); + let pl = this.offestCurve(i, offsetDist); + pl && plList.push(pl); } - return plList; + //连接全部连接点 + let newPlList: Array = this.linkPolylineGroup(plList, offsetDist); + // //分离出自交的线 + let outputPls = this.removeSelfIntersect(newPlList, offsetDist); + newPlList = this.cuttingPolyLine(newPlList, offsetDist); + outputPls.push(...this.arrangePlineList(newPlList)); + + return outputPls; } - /* - *截取线段数据 - *par1:截取线段第一点 - *par2:截取线段第二点 - *type:前front 中mid 后later 线段 - */ - private spliteCurveData(type: string, par1: number, par2?: number, ) + //偏移曲线 + private offestCurve(param: number, dist: number) { - //多段线数据列表 - let plDataList: PolylineData[]; - let startV = this.m_LineData[Math.floor(par1)]; + let startV: PolylineProps = { + pt: this.m_LineData[param].pt, + bul: this.m_LineData[param].bul + } + let endV: PolylineProps = { + pt: this.m_LineData[param + 1].pt, + bul: this.m_LineData[param + 1].bul + } + if (equaln(startV.pt.distanceTo(endV.pt), 0)) return; + let tarLine = this.GetFistDeriv(param).normalize(); + //偏移向量 + let moveVec = rotateLine(tarLine, Math.PI / 2).multiplyScalar(-dist); + //偏移矩阵 + let mat = new Matrix4().makeTranslation(moveVec.x, moveVec.y, moveVec.z); + let originLine = Vec2DTo3D(endV.pt.clone().sub(startV.pt)); + + startV.pt = Vec3DTo2D(Vec2DTo3D(startV.pt).applyMatrix4(mat)); + if (startV.bul !== 0) + { + moveVec = rotateLine(moveVec, Math.atan(startV.bul) * 4); + } + mat.makeTranslation(moveVec.x, moveVec.y, moveVec.z); + endV.pt = Vec3DTo2D(Vec2DTo3D(endV.pt).applyMatrix4(mat)); - switch (type) + let finalLine = Vec2DTo3D(endV.pt.clone().sub(startV.pt)); + if (equaln(finalLine.angleTo(originLine), Math.PI)) + { + return; + } + return this.copyPolyline([startV, endV]); + } + /** + * 删除自交多段线 + * 遍历多段线数组,分离出自交的部分,包括起始和终止被切割的部分 + * @private + * @param {Array} plList + * @param {number} offsetDist + * @returns + * @memberof Polyline + */ + private removeSelfIntersect(plList: Polyline[], offsetDist: number) + { + let plLists: Polyline[] = []; + let deletePlList: Polyline[] = []; + let deleteCount = 0; + for (let i = 0; i < plList.length - 1; i++) { - //前面一段线构造数据 - case "front": - if (par1 !== Math.ceil(par1)) + //前一根线 + let frontLine = plList[i]; + //要删除自交线的索引 + let deleteIndex: number; + //截取到的自交线交点 + let insertPt = new Vector3(); + for (let j = i + 1; j < plList.length; j++) + { + // 后一根线 + let laterLine = plList[j]; + let intPts = frontLine.IntersectWith(laterLine, IntersectOption.OnBothOperands); + if (intPts.length === 2) { - plDataList = this.m_LineData.slice(0, Math.ceil(par1)); - plDataList.push(this.getSplitePtData(par1, plDataList, true)); - } else + intPts[0].distanceTo(frontLine.StartPoint) < intPts[1].distanceTo(frontLine.StartPoint) ? intPts.pop() : intPts.shift(); + } + if (intPts.length > 0 && !equal(intPts[0], laterLine.StartPoint) && !equal(intPts[0], laterLine.EndPoint)) { - plDataList = this.m_LineData.slice(0, Math.ceil(par1) + 1); + deleteIndex = j; + insertPt.copy(intPts[0]); } - break; - case "later": - plDataList = this.m_LineData.slice(Math.ceil(par1)); - if (par1 !== Math.ceil(par1)) - plDataList.unshift(this.getSplitePtData(par1, plDataList)); - break; - case "mid": - if (!par2) throw new Error("请传入第二个点位置"); - - plDataList = this.m_LineData.slice(Math.ceil(par1), Math.ceil(par2)); - - if (par1 !== Math.ceil(par1)) + } + if (deleteIndex) + { + // 删除的自交线 + let deleteLine = plList[deleteIndex]; + let clonedeleteLine = deleteLine.Clone() as Polyline; + let cloneStartLine = frontLine.Clone() as Polyline + + this.adjustFrontLine(frontLine.LineData[1], insertPt, frontLine.LineData[0]); + frontLine.LineData[1].pt = Vec3DTo2D(insertPt); + //留下剩余的 + this.adjustLaterLine(cloneStartLine.LineData[1], insertPt, cloneStartLine.LineData[0]); + + this.adjustLaterLine(deleteLine.LineData[1], insertPt, deleteLine.LineData[0]); + //留下剩余的 + this.adjustFrontLine(clonedeleteLine.LineData[1], insertPt, clonedeleteLine.LineData[0]); + clonedeleteLine.LineData[1].pt = Vec3DTo2D(insertPt); + + //分离出的线 + deletePlList = plList.splice(i + 1 - deleteCount, deleteIndex - i - 1); + if (deletePlList.length >= 2) { - //起点 - plDataList.unshift(this.getSplitePtData(par1, plDataList)); + //添加自交开始结束的部分 + deletePlList.unshift(cloneStartLine); + deletePlList.push(clonedeleteLine); + plLists.push(this.AssemblePolyline(this.handleRemoveLine(deletePlList))); } - if (par2 !== Math.ceil(par2)) + //已删除元素数量 + deleteCount += (deleteIndex - i - 1); + i = deleteIndex - 1; + } + } + return plLists; + } + //处理分离出的多段线,把相交的部分提取出来 + private handleRemoveLine(plList: Polyline[]) + { + let startIndex: number; + let endIndex: number; + let insertPt = new Vector3(); + for (let i = 0; i < plList.length - 1; i++) + { + //前一根线 + let frontLine = plList[i]; + //截取到的自交线交点 + for (let j = i + 1; j < plList.length; j++) + { + // 后一根线 + let laterLine = plList[j]; + let intPts = frontLine.IntersectWith(laterLine, IntersectOption.OnBothOperands); + if (intPts.length === 2) { - //终点 - plDataList.push(this.getSplitePtData(par2, plDataList, true)); - } else + intPts[0].distanceTo(laterLine.StartPoint) < intPts[1].distanceTo(laterLine.StartPoint) ? intPts.pop() : intPts.shift(); + } + if (intPts.length > 0 && !equal(intPts[0], laterLine.StartPoint) && !equal(intPts[0], laterLine.EndPoint)) { - plDataList = this.m_LineData.slice(Math.ceil(par1), Math.ceil(par2) + 1); + startIndex = i; + endIndex = j; + insertPt.copy(intPts[0]); } + } } - return plDataList; + if (startIndex !== undefined) + { + // 删除的自交线 + let startLine = plList[startIndex]; + let endLine = plList[endIndex]; + + this.adjustFrontLine(endLine.LineData[1], insertPt, endLine.LineData[0]); + endLine.LineData[1].pt = Vec3DTo2D(insertPt); + this.adjustLaterLine(startLine.LineData[1], insertPt, startLine.LineData[0]); + + return plList.slice(startIndex, endIndex + 1); + } else return plList } - //获得指定位置点参数,isFront表示是否修改前面点凸度值 - private getSplitePtData(par: number, plDataList: PolylineData[], isFront = false): PolylineData + // 根据交点调整前面线段的凸度 + private adjustFrontLine(endV: PolylineProps, insertPt: Vector3, startV: PolylineProps) { - let startV = this.m_LineData[Math.floor(par)]; - let newPt = this.GetPointAtParam(par); - //截取点数据参数 - let splitePtData = { - pt: Vec3DTo2D(newPt), - bul: 0 + if (startV.bul !== 0) + { + //获取前面线的圆心角 + let insertPtCirAngle = getArcPtLenAndAngle(startV.pt, endV.pt, startV.bul, insertPt).angle; + //前面线的凸度调整 + startV.bul = Math.tan(insertPtCirAngle / 4); } + } + // 根据交点调整后面线段的凸度和起始点 + private adjustLaterLine(endV: PolylineProps, interPt: Vector3, startV: PolylineProps) + { + let bul = 0; if (startV.bul !== 0) { - //总圆心角 - let cirAng = Math.atan(startV.bul) * 4; - let endV = this.m_LineData[Math.floor(par + 1)]; - //截取点圆心角 - let arcAng = getArcPtLenAngle(startV.pt, endV.pt, startV.bul, newPt).angle; - splitePtData.bul = Math.tan((cirAng - arcAng) / 4); - if (isFront) - { - plDataList.splice(plDataList.length - 1, 1, { - pt: plDataList[plDataList.length - 1].pt, - bul: Math.tan(arcAng / 4) - }) - } + //获取后面线的圆心角 + let intPtCirAng; + //圆心角 + let circleAngle = Math.atan(startV.bul) * 4; + + let arcData = getArcProps(startV.pt, endV.pt, startV.bul); + + //起始线 + let startLine = Vec2DTo3D(arcData.startVec); + //圆心到交点连线 + let interLine = interPt.clone().sub(Vec2DTo3D(arcData.centerPt)); + let ang = angleTo(startLine, interLine); + intPtCirAng = circleAngle - ang; + bul = Math.tan(intPtCirAng / 4); + } - return splitePtData; + // 调整后面线起始点和凸度 + startV.pt = Vec3DTo2D(interPt); + startV.bul = bul; } - //√ - Extend(newParam: number) + /** + * 分解 + * + * @memberof Polyline + */ + Export(): Curve[] { - let startV: PolylineData; - let endV: PolylineData; - let oldParam: number; - let newPt = new Vector3(); - //拉伸参数 - let exParam = 0; + let exportCus: Curve[] = []; + for (let i = 0; i < this.EndParam; i++) + { + exportCus.push(this.GetCurveAtIndex(i)); + } + return exportCus; + } - if (newParam < 0) + /** + * 根据参数得到参数所在的子曲线. + * + * 当曲线存在闭合标志时,参数必须在曲线内部,否则返回空. + * + * @param {number} param 参数值 + * @returns {Curve} 曲线(直线或者圆弧) 或空 + * @memberof Polyline + */ + GetCurveAtParam(param: number): Curve + { + if (this.m_ClosedMark && !this.ParamOnCurve(param)) + return undefined; + + if (param < 0) + return this.GetCurveAtIndex(0); + else if (param >= this.EndParam) + return this.GetCurveAtIndex(this.EndParam - 1); + else return this.GetCurveAtIndex(Math.floor(param)); + } + + /** + * 得到参数在子曲线中的表示 + * + * @param {number} param 参数在多段线中表示 + * @returns {number} 参数在子曲线中表示 + * @memberof Polyline + */ + GetCurveParamAtParam(param: number): number + { + if (param >= this.EndParam) param -= this.EndParam - 1; + else if (param > 0) param -= Math.floor(param); + + return param; + } + + /** + * 获得曲线,来自索引位置. + * + * @param {number} i 索引位置 整数 + * @returns {Curve} + * @memberof Polyline + */ + GetCurveAtIndex(i: number): Curve + { + if (!this.ParamOnCurve(i)) return undefined; + + let d1 = this.m_LineData[i]; + let d2 = this.m_LineData[FixIndex(i + 1, this.m_LineData)]; + if (d1.bul == 0) { - startV = this.m_LineData[0]; - endV = this.m_LineData[1]; - exParam = newParam; - newPt = getPointAtParam(startV.pt, endV.pt, startV.bul, exParam); - if (startV.bul !== 0) - { - startV.bul = Math.tan(getArcAngle(newPt, Vec2DTo3D(startV.pt), Vec2DTo3D(endV.pt)) / 4) - } - startV.pt = Vec3DTo2D(newPt); + return new Line(Vec2DTo3D(d1.pt), Vec2DTo3D(d2.pt)); } - else if (newParam > this.m_LineData.length - 1) + else { - oldParam = this.m_LineData.length - 1; - startV = this.m_LineData[oldParam - 1]; - endV = this.m_LineData[oldParam]; - - exParam = newParam - oldParam + 1; - newPt = getPointAtParam(startV.pt, endV.pt, startV.bul, exParam); - if (startV.bul !== 0) + return new Arc().ParseFromBul(d1.pt, d2.pt, d1.bul); + } + } + // 组合多段线数组组合为一多段线 + AssemblePolyline(pls: Array) + { + if (pls.length === 0) return; + let plDataList: PolylineProps[] = []; + plDataList.push(pls[0].LineData[0]); + for (let i = 0; i < pls.length - 1; i++) + { + let frontLine = pls[i]; + let laterLine = pls[i + 1]; + if (equal(frontLine.EndPoint, laterLine.StartPoint)) { - startV.bul = Math.tan(getArcAngle(Vec2DTo3D(startV.pt), Vec2DTo3D(endV.pt), newPt) / 4); - + plDataList.push(laterLine.LineData[0]); } - endV.pt = Vec3DTo2D(newPt); } - this.Update(); + plDataList.push(pls[pls.length - 1].LineData[1]); + + return new Polyline(plDataList); } - PtOnCurve(pt: Vector3): boolean + //整理多段线数组,把相连的组合成多段线,返回多段线数组 + private arrangePlineList(pls: Array) { - return this.GetParamAtPoint(pt) !== undefined; + if (pls.length === 0) return; + let plDataList: PolylineProps[] = []; + let plList: Polyline[] = []; + plDataList.push(pls[0].LineData[0]); + for (let i = 0; i < pls.length - 1; i++) + { + let frontLine = pls[i]; + let laterLine = pls[i + 1]; + if (equal(frontLine.EndPoint, laterLine.StartPoint)) + { + plDataList.push(laterLine.LineData[0]); + } + else + { + plDataList.push(frontLine.LineData[1]); + plList.push(new Polyline(plDataList)); + plDataList = [laterLine.LineData[0]]; + } + } + plDataList.push(pls[pls.length - 1].LineData[1]); + plList.push(new Polyline(plDataList)); + + return plList; } - //最近点 - GetClosestPointTo(pt: Vector3, extend: boolean): Vector3 + /** + * 连接多段线数组 + * 两两取交点,去除斜率相反线 + * 不相交添加圆弧连接 + * @private + * @param {Array} plList + * @param {number} [offsetDist] + * @returns + * @memberof Polyline + */ + private linkPolylineGroup(plList: Array, offsetDist?: number) { - let startV = this.m_LineData[0]; - let endV = this.m_LineData[1]; - //最近点数据,假设最近点在第一条弧上 - let closestData = getClosestPt(startV.pt, endV.pt, startV.bul, pt, !this.IsClose && extend); + if (plList.length === 1) + { + return plList; + } + let newPlList: Array = []; - for (let i = 1; i < this.m_LineData.length - 1; i++) + let startV = plList[0].LineData[0]; + //原先的斜率 + let oldSlope: Vector3; + //新斜率 + let newSlope: Vector3; + for (let i = 0; i < plList.length; i++) { - startV = this.m_LineData[i]; - endV = this.m_LineData[i + 1]; - let tmpClosestData = getClosestPt(startV.pt, endV.pt, startV.bul, pt); + //前面线 + let frontLine = plList[i]; + //原先的斜率 + oldSlope = frontLine.GetFistDeriv(0); + //后面线 + let laterLine = plList[i + 1]; + if (i === plList.length - 1) + { + if (this.IsClose) + laterLine = plList[0]; + else break; + } + //终点data + let endV = this.clonePlData(laterLine.LineData[0]); + //交点 + let interPt = Vec2DTo3D(endV.pt); + // 如果两线结合点不相等 + if (!equal(frontLine.EndPoint, laterLine.StartPoint)) + { + // 多段线交点数组 + let interPts = frontLine.IntersectWith(laterLine, IntersectOption.ExtendBoth); + + + //如果没有交点,则用圆弧连接 + if (interPts.length === 0 && offsetDist) + { + let centerPt; + //取圆心,圆心离后面线start点距离等于偏移距离 + for (let j = i; j < this.LineData.length; j++) + { + let pt = Vec2DTo3D(this.LineData[j].pt); + if (equaln(pt.distanceTo(laterLine.StartPoint), Math.abs(offsetDist))) + { + centerPt = pt; + break; + } + } + if (!centerPt) throw new Error("找不到圆心"); + // 圆心到前面线end点向量 + let startLine = frontLine.EndPoint.clone().sub(centerPt); + // 圆心到后面线start点向量 + let endLine = laterLine.StartPoint.clone().sub(centerPt); + let circleAngle; + //补圆弧的起始交点 + let intPt = Vec2DTo3D(frontLine.LineData[1].pt); + // 如果起始向量和终止向量相等,则都为半径 + if (equaln(startLine.lengthSq(), endLine.lengthSq())) + { + circleAngle = angleTo(startLine, endLine); + } + else + { + //半径矢量radLine,求交线段insertLine,半径线段 + let [radLine, insertLine] = startLine.lengthSq() > endLine.lengthSq() ? [startLine, laterLine] : [endLine, frontLine]; - if (i === this.m_LineData.length - 2) + // 以centerPt为圆心,偏移距离为为半径画圆 + let tmpPlLine = new Circle(centerPt, Math.abs(offsetDist)); + + let pts = tmpPlLine.IntersectWith(insertLine, IntersectOption.OnBothOperands); + intPt = pts[0]; + let insLine = intPt.clone().sub(centerPt); + circleAngle = angleTo(insLine, radLine); + // 如果前面矢量小于后面的则交点在前面线,调整前面线凸度 + if (startLine.lengthSq() <= endLine.lengthSq()) + { + this.adjustFrontLine(frontLine.LineData[1], intPt, startV); + } + else + { + //补圆弧交点在后面线,调整后面线点和凸度 + this.adjustLaterLine(laterLine.LineData[1], intPt, endV); + } + } + let tmpPlData = { + pt: Vec3DTo2D(intPt), + bul: Math.tan(circleAngle / 4) + }; + newPlList.push(new Polyline([ + startV, tmpPlData + ])) + startV = this.clonePlData(tmpPlData); + } + else + { + //是否存在同时存在2线上的交点 + let pts = frontLine.IntersectWith(laterLine, IntersectOption.OnBothOperands); + + interPt = pts.length > 0 ? pts[0] : this.selectPlInterPt(interPts, laterLine.StartPoint) + this.adjustFrontLine(frontLine.LineData[1], interPt, startV); + this.adjustLaterLine(laterLine.LineData[1], interPt, endV); + } + } + + let pl = new Polyline([startV, endV]) + newSlope = pl.GetFistDeriv(0); + startV = this.clonePlData(endV); + if (i === plList.length - 1) + { + this.adjustLaterLine(newPlList[0].LineData[1], interPt, newPlList[0].LineData[0]); + } + if (equal(pl.StartPoint, pl.EndPoint) || (pl.LineData[0].bul === 0 && equaln(newSlope.angleTo(oldSlope), Math.PI, 1e-7))) { - tmpClosestData = getClosestPt(startV.pt, endV.pt, startV.bul, pt, !this.IsClose && extend); + continue; } - if (tmpClosestData && (!closestData || tmpClosestData.closestLen - closestData.closestLen < -1e-8)) + + newPlList.push(pl); + } + if (!this.IsClose) + { + let frontLine = plList[plList.length - 1]; + let endV = this.clonePlData(frontLine.LineData[1]); + if (plList.length >= 3) { - closestData = tmpClosestData; + let laterLine = plList[0]; + let pts = frontLine.IntersectWith(laterLine, 0); + if (pts.length === 1) + { + this.adjustFrontLine(frontLine.LineData[1], pts[0], startV); + endV.pt = Vec3DTo2D(pts[0]); + if (newPlList.length > 0) + this.adjustLaterLine(newPlList[0].LineData[1], pts[0], newPlList[0].LineData[0]); + } } + let pl = new Polyline([startV, endV]); + newSlope = pl.GetFistDeriv(0); + if (!equaln(newSlope.angleTo(oldSlope), Math.PI, 1e-7)) + newPlList.push(pl); } - return closestData.closestPt; + return newPlList; } + /** + * 优化连接多段数组,去除无用线 + * //ToDo:保留优化算法 + * @private + * @param {Array} plList + * @returns + * @memberof Polyline + */ + private linkPolyline(plList: Array) + { + let isLine = false; + if (plList.length === 1) return plList; + for (let i = 0; i < plList.length - 1; i++) + { + let frontLine = plList[i]; + let laterLine = plList[i + 1]; + let interPt: Vector3; + if (equal(frontLine.EndPoint, laterLine.StartPoint)) + { + continue; + } + else + { + if (!isLine) + { + let oldSlope = frontLine.GetFistDeriv(0); + let newSlope; + let interpts = frontLine.IntersectWith(laterLine, IntersectOption.ExtendBoth) + do + { + interPt = this.selectPlInterPt(interpts, laterLine.StartPoint); - //偏移 - GetOffsetCurves(offsetDist: number): Array + while (!interPt) + { + plList.splice(i, 1); + i--; + if (i < 0) break; + frontLine = plList[i]; + oldSlope = frontLine.GetFistDeriv(0); + } + if (i === -1) break; + + this.adjustFrontLine(frontLine.LineData[1], interPt, frontLine.LineData[0]); + frontLine.LineData[1].pt = Vec3DTo2D(interPt); + newSlope = frontLine.GetFistDeriv(0); + if (!equaln(oldSlope.angleTo(newSlope), 0, 1e-7)) + { + plList.splice(i, 1); + i--; + if (i < 0) break; + frontLine = plList[i]; + oldSlope = frontLine.GetFistDeriv(0); + } + else + { + this.adjustLaterLine(laterLine.LineData[1], interPt, laterLine.LineData[0]); + break; + } + } while (true); + } + else + { + plList.splice(i - 1); + break; + } + + isLine = true; + } + } + return plList.length > 1 ? plList : []; + } + //选取合适交点 + private selectPlInterPt(pts: Vector3[], spt: Vector3) { - return; + let pt: Vector3; + // 多段线交点数组 + if (pts.length === 0) return; + else if (pts.length === 1) + { + pt = pts[0]; + } + else + { + // 在当前线上不存在交点,取离后面线startPt最近的交点; + pt = pts[0].distanceTo(spt) < pts[1].distanceTo(spt) ? pts[0] : pts[1]; + } + return pt; } - //偏移曲线 - private offestCurve(startPt: Vector2, endPt: Vector2, bul: number, dist: number) + /** + * 优化切割无效多段线 + * 源线段中各点画圆,半径为偏移距离 + * 若偏移线段在圆内,则切除 + * @private + * @param {Polyline[]} plList + * @param {number} rad + * @returns + * @memberof Polyline + */ + private cuttingPolyLine(plList: Polyline[], rad: number) { - if (bul === 0) + + rad = Math.abs(rad); + + // 每个原线段点画圆分割多段线 + for (let i = 0; i < this.LineData.length; i++) { + //圆心点 + let centerPt = Vec2DTo3D(this.LineData[i].pt); + let circle = new Circle(centerPt, rad); + for (let j = 0; j < plList.length; j++) + { + let pl = plList[j]; + let sDist = pl.StartPoint.distanceTo(centerPt); + let eDist = pl.EndPoint.distanceTo(centerPt); + // 如果线段在圆内,则为无效线 + if (sDist <= rad && eDist <= rad) + { + //该段多段线和切割圆弧是否重合 + if (pl.LineData[0].bul !== 0) + { + let center = (pl.GetCurveAtIndex(0) as Arc).Center; + if (equal(center, centerPt)) continue; + } + plList.splice(j, 1); + j--; + continue; + } + // 跟圆弧相交除非相切,否则都为2个交点 + let pts = pl.IntersectWith(circle, IntersectOption.ExtendBoth); + if (pts.length <= 1) continue; + // 过滤掉不在线上的点 + pts = pts.filter(p => plList[j].PtOnCurve(p)); - } + if (pts.length === 0) continue; + else if (pts.length === 1) + { + // 线段一端在圆上,另一端在圆外而且没有其他交点 + if ((equaln(sDist, rad) && eDist > rad) || (equaln(eDist, rad) && sDist > rad)) + { + continue; + } + if (sDist < rad) + this.adjustLaterLine(pl.LineData[1], pts[0], pl.LineData[0]) + else + { + this.adjustFrontLine(pl.LineData[1], pts[0], pl.LineData[0]) + pl.LineData[1].pt = Vec3DTo2D(pts[0]); + } + } + else + { + let dist = pl.StartPoint.distanceTo(pts[0]); + let dist1 = pl.StartPoint.distanceTo(pts[1]); + let [pt, pt1] = dist < dist1 ? [pts[0], pts[1]] : [pts[1], pts[0]] + let clonePl = pl.Clone() as Polyline; + this.adjustFrontLine(pl.LineData[1], pt, pl.LineData[0]); + pl.LineData[1].pt = Vec3DTo2D(pt) + this.adjustLaterLine(clonePl.LineData[1], pt1, clonePl.LineData[0]); + plList.splice(j + 1, 0, clonePl); + j++; + + } + } + } + return plList; + } + private clonePlData(pl: PolylineProps) + { + return { + pt: pl.pt, + bul: pl.bul + } + } + IntersectWith(curve: Curve, intType: IntersectOption): Vector3[] + { + return IntersectPolylineAndCurve(this, curve, intType); + } + get BoundingBox() + { + let box = new Box3(); + for (let i = 0; i < this.EndParam; i++) + { + let cu = this.GetCurveAtIndex(i); + box.union(cu.BoundingBox); + } + return box; } CreateCurve() { @@ -526,51 +1193,37 @@ export class Polyline extends Curve pts.push(data.pt); buls.push(data.bul); } + if (this.m_ClosedMark) + { + pts.push(pts[0]); + buls.push(0); + } let curve = CreateBoardUtil.createPath(pts, buls); return curve; } - Draw(renderType: RenderType): Object3D + InitDrawObject(renderType: RenderType = RenderType.Wireframe): THREE.Line { - let obj = super.Draw(renderType); - if (obj) return obj; let curve = this.CreateCurve(); let geometry = new Geometry().setFromPoints(curve.getPoints(50)); - obj = new THREE.Line(geometry, ColorMaterial.GetLineMaterial(this.m_Color)); - this.m_DrawEntity.set(renderType, obj); - obj.userData = this; - + let obj = new THREE.Line(geometry, ColorMaterial.GetLineMaterial(this.m_Color)); return obj; } - //多段线起点 - get StartPoint() - { - if (this.m_LineData.length > 0) - return new Vector3(this.m_LineData[0].pt.x, this.m_LineData[0].pt.y, 0); - return new Vector3(); - } - get EndPoint() - { - if (this.m_LineData.length > 0) - return new Vector3(this.m_LineData[this.m_LineData.length - 1].pt.x, this.m_LineData[this.m_LineData.length - 1].pt.y, 0); - return new Vector3(); - } - Update() + UpdateDrawObject(type: RenderType, en: Object3D) { - for (let [, obj] of this.m_DrawEntity) - { - let geo = obj["geometry"] as Geometry; + let plObj = en as THREE.Line; - geo.dispose(); - obj["geometry"] = new Geometry(); - geo = obj["geometry"]; + let geo = plObj.geometry as THREE.Geometry; - let curve = this.CreateCurve(); - geo.setFromPoints(curve.getPoints(50)); + geo.dispose(); + geo = new Geometry(); + plObj.geometry = new Geometry(); + geo = plObj.geometry; + let curve = this.CreateCurve(); + geo.setFromPoints(curve.getPoints(50)); - geo.verticesNeedUpdate = true; - geo.computeBoundingSphere(); - } + geo.verticesNeedUpdate = true; + geo.computeBoundingSphere(); } ApplyMatrix(m: THREE.Matrix4) { @@ -592,12 +1245,11 @@ export class Polyline extends Curve let ptList = []; for (let i = 0; i < this.m_LineData.length; i++) { - let endV = this.m_LineData[i]; if (i > 0) { let startV = this.m_LineData[i - 1]; - ptList.push(getPointAtParam(startV.pt, endV.pt, startV.bul, 0.5)); + ptList.push(getPtAtCurveParam(startV.pt, endV.pt, startV.bul, 0.5)); } ptList.push(Vec2DTo3D(endV.pt)); } @@ -615,10 +1267,10 @@ export class Polyline extends Curve { if (this.IsClose) { - this.m_LineData[this.m_LineData.length - 1].pt.add(moveVc); + this.m_LineData[this.EndParam].pt.add(moveVc); } } - //TODO:保持圆弧终点不变 + //TODO:保持圆弧中点不变 this.m_LineData[i].pt.add(moveVc); } else @@ -633,7 +1285,7 @@ export class Polyline extends Curve let startPt = Vec2DTo3D(startV.pt); // 终止点 let endPt = Vec2DTo3D(endV.pt); - startV.bul = Math.tan(getArcAngle(startPt, midPt, endPt) / 4); + startV.bul = Math.tan(getArcAngleBy3Pt(startPt, midPt, endPt) / 4); } else { @@ -642,7 +1294,6 @@ export class Polyline extends Curve } } this.Update(); - } ReadFile(file: CADFile) { @@ -658,8 +1309,6 @@ export class Polyline extends Curve this.m_LineData.push({ pt: v, bul: bul }); } this.Update(); - - } //对象将自身数据写入到文件. WriteFile(file: CADFile) diff --git a/src/Editor/CommandRegister.ts b/src/Editor/CommandRegister.ts index beaa7009f..425cde6e0 100644 --- a/src/Editor/CommandRegister.ts +++ b/src/Editor/CommandRegister.ts @@ -1,10 +1,12 @@ import { DrawAxis } from '../Add-on/AddAxis'; +import { Command_ClosePt } from '../Add-on/closetest'; import { Command_Copy } from '../Add-on/Copy'; import { CustomUcs } from '../Add-on/CostumUCS'; import { Union } from '../Add-on/CSGUnion'; import { DrawArc } from '../Add-on/DrawArc'; import { Command_DrawBoard } from '../Add-on/DrawBoard'; import { DrawAlignedDimension } from '../Add-on/DrawDim/DrawAlignedDimension'; +import { DrawLinearDimension } from '../Add-on/DrawDim/DrawLinearDimension'; import { DrawEllipse } from '../Add-on/DrawEllipse'; import { DrawFloor } from '../Add-on/DrawFloor'; import { DrawGripStretch } from '../Add-on/DrawGripStretch'; @@ -17,13 +19,16 @@ import { DrawRegTest } from '../Add-on/DrawTestReg'; import { DrawCircle0 } from '../Add-on/DrawZeroCircle'; import { Entsel } from '../Add-on/Entsel'; import { Command_Erase } from '../Add-on/Erase'; +import { Command_Export } from '../Add-on/Export'; import { Command_Extend } from '../Add-on/Extends'; import { CommandFillet } from '../Add-on/Fillet'; +import { Command_INsTest } from '../Add-on/instest'; import { Fbx } from '../Add-on/loadfbx'; import { LoadImg } from '../Add-on/LoadImg'; import { Command_Move } from '../Add-on/Move'; -import { Command_Offset } from '../Add-on/Offset'; +import { Command_Offset, Command_TestOffset } from '../Add-on/Offset'; import { Open } from '../Add-on/Open'; +import { Command_PLTest } from '../Add-on/polytest'; import { Command_RevPl } from '../Add-on/RevPl'; import { Command_Rotate } from '../Add-on/Rotate'; import { Save } from '../Add-on/Save'; @@ -32,6 +37,7 @@ import { Stretch } from '../Add-on/Stretch'; import { Command_SwitchCamera } from '../Add-on/SwitchCamera'; import { Command_SwitchPass } from '../Add-on/SwitchPass'; import { Test } from '../Add-on/test'; +import { Command_TestBox } from '../Add-on/TestBox'; import { Command_DrawBoard2 } from '../Add-on/TestDrawBoard'; import { TestDrawDirectionalLight } from '../Add-on/TestDrawDirectionalLight'; import { TestDrawPointLight } from '../Add-on/TestDrawPointLight'; @@ -40,7 +46,7 @@ import { Command_Trim } from '../Add-on/Trim'; import { Redo, Undo } from '../Add-on/Undo'; import { ViewToFront, ViewToRight, ViewToTop } from '../Add-on/ViewChange'; import { commandMachine } from './CommandMachine'; -import { DrawLinearDimension } from '../Add-on/DrawDim/DrawLinearDimension'; + // import { DrawFloor } from '../Add-on/DrawFloor'; // import { RevTarget, SaveTarget } from '../Add-on/RenderTarget'; export function registerCommand() @@ -132,6 +138,22 @@ export function registerCommand() commandMachine.RegisterCommand("dal", new DrawAlignedDimension()); commandMachine.RegisterCommand("dli", new DrawLinearDimension()); + commandMachine.RegisterCommand("tt", new Command_PLTest()); + + commandMachine.RegisterCommand("tt2", new Command_INsTest()); + + commandMachine.RegisterCommand("x", new Command_Export()); + + + commandMachine.RegisterCommand("close", new Command_ClosePt()); + + + //用于测试包围盒 + commandMachine.RegisterCommand("box", new Command_TestBox()); + + + commandMachine.RegisterCommand("testoffset", new Command_TestOffset()); + // commandMachine.RegisterCommand("st", new SaveTarget()) // commandMachine.RegisterCommand("rt", new RevTarget()) } diff --git a/src/Editor/SnapServices.ts b/src/Editor/SnapServices.ts index 48ae84bfb..b6b840c9b 100644 --- a/src/Editor/SnapServices.ts +++ b/src/Editor/SnapServices.ts @@ -4,7 +4,8 @@ import { app } from '../ApplicationServices/Application'; import { ColorMaterial } from '../Common/ColorPalette'; import { GetPointPrompt } from '../Common/InputState'; import { Entity } from '../DatabaseServices/Entity'; -import { equaln, fixAngle, Intersect, polar } from '../Geometry/GeUtils'; +import { equaln, fixAngle, polar } from '../Geometry/GeUtils'; +import { IntersectLAndL } from '../GraphicsSystem/IntersectWith'; import { PreViewer } from '../GraphicsSystem/PreViewer'; @@ -27,6 +28,7 @@ interface SnapIntersect //提供点捕捉的服务. export class SnapServices { + m_Disabled: boolean = false;//禁用捕捉 private preLines: THREE.Line[] = []; //前视图绘制的线表 notSnapEntity = new Set();//不参与捕捉的实体列表,这个属性由开发人员维护. private snapPoints: THREE.Vector3[] = [];//捕捉的点列表 @@ -102,7 +104,7 @@ export class SnapServices for (let j = i + 1; j < snapAxisList.length; j++) { let axis2 = snapAxisList[j]; - let insP = Intersect(axis1.BasePoint, axis1.SnapPoint, axis2.BasePoint, axis2.SnapPoint); + let insP = IntersectLAndL(axis1.BasePoint, axis1.SnapPoint, axis2.BasePoint, axis2.SnapPoint); if (insP) axisIntersectList.push({ IntersectPoint: insP, @@ -145,10 +147,11 @@ export class SnapServices //计算图形的捕捉点 如果有 则返回. private GetEntitySnapPoint() { + if (this.m_Disabled) return; let vcsP = app.m_Editor.m_MouseCtrl.m_CurMousePointVCS; for (let obj of app.m_Viewer.Scene.children) { - if (!this.notSnapEntity.has(obj) && obj.userData && obj.userData instanceof Entity) + if (!this.notSnapEntity.has(obj.userData) && obj.userData && obj.userData instanceof Entity) { for (let p of obj.userData.GetSnapPoints()) { diff --git a/src/Geometry/GeUtils.ts b/src/Geometry/GeUtils.ts index a763601c0..078c8f7f7 100644 --- a/src/Geometry/GeUtils.ts +++ b/src/Geometry/GeUtils.ts @@ -1,8 +1,7 @@ -import { Matrix4, Vector3 } from 'three'; +import { Matrix4, Vector2, Vector3 } from 'three'; import * as THREE from 'three'; -import { CreateBoardUtil } from '../ApplicationServices/mesh/createBoard'; -import { rotateLine } from './../Common/CurveUtils'; +import { rotateLine } from '../Common/CurveUtils'; export const cZeroVec = new THREE.Vector3(); export const cXAxis = new THREE.Vector3(1, 0, 0); @@ -15,7 +14,7 @@ export function equaln(v1: number, v2: number, fuzz = 1e-3) } export function equal(v1: THREE.Vector3, v2: THREE.Vector3) { - return v1.manhattanDistanceTo(v2) < 1e-8; + return v1.distanceToSquared(v2) < 1e-12; } export function fixAngle(an: number, fixAngle: number, fuzz: number = 0.1) @@ -36,16 +35,18 @@ export function fixAngle(an: number, fixAngle: number, fuzz: number = 0.1) } //改变向量v 不拷贝新向量 返回自身 -export function polar(v: THREE.Vector3, an: number, dis: number) +export function polar(v: Vector3 | Vector2, an: number, dis: number): Vector3 | Vector2 { v.x += Math.cos(an) * dis; v.y += Math.sin(an) * dis; return v; } -export function angle(v: THREE.Vector3) +export function angle(v: Vector3 | Vector2) { - return Math.atan2(v.y, v.x); + let angle = Math.atan2(v.y, v.x); + if (angle < 0) angle += Math.PI * 2; + return angle; } /** @@ -74,7 +75,7 @@ export function angleTo(v1: THREE.Vector3, v2: THREE.Vector3, ref: THREE.Vector3 if (v1.equals(cZeroVec) || v2.equals(cZeroVec)) return 0; let cv = new Vector3().crossVectors(v1, v2).normalize(); - return cv.z * v1.angleTo(v2); + return cv.z === 0 ? v1.angleTo(v2) : v1.angleTo(v2) * cv.z; } export function getLoocAtUpVec(dir: THREE.Vector3): THREE.Vector3 @@ -128,6 +129,11 @@ export function midPoint(v1: THREE.Vector3, v2: THREE.Vector3): THREE.Vector3 { return v1.clone().add(v2).multiplyScalar(0.5); } +export function midPoint2(v1: THREE.Vector2, v2: THREE.Vector2): THREE.Vector2 +{ + return v1.clone().add(v2).multiplyScalar(0.5); +} + export function midPtCir(v1: THREE.Vector3, v2: THREE.Vector3) { let baseline = new Vector3(1, 0, 0); @@ -191,37 +197,6 @@ export function MoveMatrix(v: THREE.Vector3): THREE.Matrix4 return mat; } -export function Intersect(p1: THREE.Vector3, p2: THREE.Vector3, p3: THREE.Vector3, p4: THREE.Vector3): THREE.Vector3 -{ - let dx1 = p1.x - p2.x; - let dx2 = p3.x - p4.x; - let dx3 = p4.x - p2.x; - let dy1 = p1.y - p2.y; - let dy2 = p3.y - p4.y; - let dy3 = p4.y - p2.y; - - let det = (dx2 * dy1) - (dy2 * dx1); - - let pt = new THREE.Vector3(0, 0, 0); - if (equaln(det, 0.0, 1e-5)) - { - if (equaln(dx2 * dy3, dy2 * dx3, 1e-5)) - { - if (p3.distanceTo(p2) < 1e-3) - { - return p2; - } - } - return; - } - - let ratio = ((dx1 * dy3) - (dy1 * dx3)) / det; - pt.x = (ratio * dx2) + p4.x; - pt.y = (ratio * dy2) + p4.y; - - return pt; -} - export function getProjectDist(v1: Vector3, v2: Vector3) { let ang = v1.angleTo(v2); @@ -231,3 +206,16 @@ export function getProjectDist(v1: Vector3, v2: Vector3) v: dist * Math.sin(ang) } } + +/** + * 将角度调整为0-2pi之间 + * + * @export + * @param {number} an + */ +export function angleTo2Pi(an: number) +{ + an = an % (Math.PI * 2); + if (an < 0) an += Math.PI * 2 + return an; +} diff --git a/src/GraphicsSystem/IntersectWith.ts b/src/GraphicsSystem/IntersectWith.ts index 825198423..55e64857e 100644 --- a/src/GraphicsSystem/IntersectWith.ts +++ b/src/GraphicsSystem/IntersectWith.ts @@ -1,10 +1,12 @@ import { Vector3 } from 'three'; + +import { getClosestPt, Vec3DTo2D } from '../Common/CurveUtils'; import { Arc } from '../DatabaseServices/Arc'; +import { Circle } from '../DatabaseServices/Circle'; import { Curve } from '../DatabaseServices/Curve'; import { Line } from '../DatabaseServices/Line'; -import { equal, equaln } from '../Geometry/GeUtils'; -import { Circle } from '../DatabaseServices/Circle'; -import { getClosestPt, Vec3DTo2D } from '../Common/CurveUtils'; +import { Polyline } from '../DatabaseServices/Polyline'; +import { equal, equaln, midPoint } from '../Geometry/GeUtils'; /** * 相交延伸选项. @@ -31,29 +33,48 @@ export enum IntersectOption */ ExtendBoth = 3, } - +//延伸自身还是参数反转 +export function reverseIntersectOption(intType: IntersectOption) +{ + if (intType === IntersectOption.ExtendThis) + intType = IntersectOption.ExtendArg; + else if (intType === IntersectOption.ExtendArg) + intType = IntersectOption.ExtendThis; + return intType; +} /** * 校验相交点是否满足延伸选项 * 算法会计算无限延伸状态下的曲线交点,调用该方法进行校验返回校验后的点表 * * @param {Vector3[]} intPts 相交点.曲线当作完全状态下的相交点 - * @param {Curve} c1 曲线1 - * @param {Curve} c2 曲线2 - * @param {Intersect} intType 延伸选项. - * @returns {Array} + * @param {Curve} c1 曲线1 由this参数传入 + * @param {Curve} c2 曲线2 由arg 参数传入 + * @param {Intersect} extType 延伸选项. + * @returns {Array} 校验完成后的点表 */ -function CheckPointOnCurve(intPts: Vector3[], c1: Curve, c2: Curve, intType: IntersectOption): Array +function CheckPointOnCurve(intPts: Vector3[], c1: Curve, c2: Curve, extType: IntersectOption): Array { return intPts.filter(p => { - return (intType & IntersectOption.ExtendThis || c1.PtOnCurve(p)) && (intType & IntersectOption.ExtendArg || c2.PtOnCurve(p)) + return (extType & IntersectOption.ExtendThis || c1.PtOnCurve(p)) && (extType & IntersectOption.ExtendArg || c2.PtOnCurve(p)) }) } - -//圆和圆(传入圆心和半径) -export function IntersectCircleAndCircleOrArc(center1?: Vector3, radius1?: number, center2?: Vector3, radius2?: number) +/** + * 计算圆与圆的交点,如果参数传入圆弧,那么也按照圆计算. + * + * @export + * @param {(Circle | Arc)} c1 圆或圆弧 + * @param {(Circle | Arc)} c2 圆或圆弧 + * @returns 交点集合 + */ +export function IntersectCircleAndCircle(c1: Circle | Arc, c2: Circle | Arc) { + let center1 = c1.Center; + let center2 = c2.Center; + let radius1 = c1.Radius; + let radius2 = c2.Radius; + let pts: Vector3[] = []; let dist = center2.distanceTo(center1); @@ -92,33 +113,56 @@ export function IntersectCircleAndCircleOrArc(center1?: Vector3, radius1?: numbe return pts; } -//圆与圆 -export function IntersectCircleAndCircle(circle1: Circle, circle2: Circle, intType: IntersectOption) -{ - return this.IntersectCircleAndCircleOrArc(circle1.Center, circle1.Radius, circle2.Center, circle2.Radius); -} -//圆与圆弧 -export function IntersectCircleAndArc(circle: Circle, arc2: Arc, intType: IntersectOption) +/** + * 计算圆与圆弧的交点. + * + * @export + * @param {Circle} circle 圆 + * @param {Arc} arc 圆弧 + * @param {IntersectOption} extType 延伸选项 + * @returns 交点集合 + */ +export function IntersectCircleAndArc(circle: Circle, arc: Arc, extType: IntersectOption) { - let ptArr = this.IntersectCircleAndCircleOrArc(circle.Center, circle.Radius, arc2.Center, arc2.Radius); - return CheckPointOnCurve(ptArr, circle, arc2, intType | IntersectOption.ExtendThis); + let pts = IntersectCircleAndCircle(circle, arc); + return CheckPointOnCurve(pts, circle, arc, extType | IntersectOption.ExtendThis); } -//圆弧与圆弧 -export function IntersectArcAndArc(arc1: Arc, arc2: Arc, intType: IntersectOption) +/** + * 计算圆弧与圆弧的交点 + * + * @export + * @param {Arc} arc1 圆弧 + * @param {Arc} arc2 圆弧 + * @param {IntersectOption} extType 延伸选项 + * @returns 交点集合 + */ +export function IntersectArcAndArc(arc1: Arc, arc2: Arc, extType: IntersectOption) { - let ptArr = this.IntersectCircleAndCircleOrArc(arc1.Center, arc1.Radius, arc2.Center, arc2.Radius); - return CheckPointOnCurve(ptArr, arc1, arc2, intType); + let pts = IntersectCircleAndCircle(arc1, arc2); + return CheckPointOnCurve(pts, arc1, arc2, extType); } -//直线和圆(传入圆心和半径) -export function IntersectLineAndCircleOrArc(line: Line, center?: Vector3, radius?: number) +/** + * 通用方法:计算直线与圆的交点,默认延伸全部 + * + * @export + * @param {Line} line 直线 + * @param {(Circle | Arc)} circle 圆或圆弧 + * @returns 交点集合 + */ +function IntersectLineAndCircleOrArc(line: Line, circle: Circle | Arc) { + let startPoint = line.StartPoint; + let endPoint = line.EndPoint; + let center = circle.Center; + let radius = circle.Radius; + let pts: Vector3[] = []; - if (equaln(line.EndPoint.x, line.StartPoint.x)) + if (equaln(endPoint.x, startPoint.x, 1e-7)) { - if (line.PtOnCurve(center)) + if (equaln(startPoint.x, center.x, 1e-7)) { let pt1 = new Vector3(0, radius); let pt2 = new Vector3(0, -radius); @@ -126,24 +170,24 @@ export function IntersectLineAndCircleOrArc(line: Line, center?: Vector3, radius pts.push(center.clone().add(pt2)); return pts; } - let closestArr = getClosestPt(Vec3DTo2D(line.StartPoint), Vec3DTo2D(line.EndPoint), 0, center); + let closestArr = getClosestPt(Vec3DTo2D(startPoint), Vec3DTo2D(endPoint), 0, center, true); if (closestArr.closestLen === radius) { pts.push(center.clone().add(closestArr.closestPt)); } - if (closestArr.closestLen < radius) + else if (closestArr.closestLen < radius) { let y = Math.sqrt(Math.pow(radius, 2) - Math.pow(closestArr.closestLen, 2)); - let pt1 = new Vector3(closestArr.closestPt.x, y); - let pt2 = new Vector3(closestArr.closestPt.x, -y); - pts.push(center.clone().add(pt1)); - pts.push(center.clone().add(pt2)); + let closePt = closestArr.closestPt; + let pt1 = closePt.clone().setY(closePt.y + y) + let pt2 = closePt.clone().setY(closePt.y - y) + pts.push(pt1, pt2); } } else { - let k = (line.EndPoint.y - line.StartPoint.y) / (line.EndPoint.x - line.StartPoint.x); - let b = line.EndPoint.y - k * line.EndPoint.x; + let k = (endPoint.y - startPoint.y) / (endPoint.x - startPoint.x); + let b = endPoint.y - k * endPoint.x; //列方程 let x1 = 0, y1 = 0, x2 = 0, y2 = 0; let c = Math.pow(center.x, 2) + Math.pow(b - center.y, 2) - Math.pow(radius, 2); @@ -168,26 +212,20 @@ export function IntersectLineAndCircleOrArc(line: Line, center?: Vector3, radius } //直线和圆 -export function IntersectLineAndCircle(line: Line, circle: Circle, intType: IntersectOption) +export function IntersectLineAndCircle(line: Line, circle: Circle, extType: IntersectOption) { - let ptArr = this.IntersectLineAndCircleOrArc(line, circle.Center, circle.Radius); - return CheckPointOnCurve(ptArr, line, circle, intType | IntersectOption.ExtendArg); + let ptArr = IntersectLineAndCircleOrArc(line, circle); + return CheckPointOnCurve(ptArr, line, circle, extType | IntersectOption.ExtendArg); } //直线和圆弧 -export function IntersectLineAndArc(line: Line, arc: Arc, intType: IntersectOption) +export function IntersectLineAndArc(line: Line, arc: Arc, extType: IntersectOption) { - let ptArr = this.IntersectLineAndCircleOrArc(line, arc.Center, arc.Radius); - return CheckPointOnCurve(ptArr, line, arc, intType); + let ptArr = IntersectLineAndCircleOrArc(line, arc); + return CheckPointOnCurve(ptArr, line, arc, extType); } //直线和直线 -export function IntersectLineAndLine(l1: Line, l2: Line, intType: IntersectOption) +export function IntersectLAndL(p1: Vector3, p2: Vector3, p3: Vector3, p4: Vector3): Vector3 { - let p1 = l1.StartPoint; - let p2 = l1.EndPoint; - - let p3 = l2.StartPoint; - let p4 = l2.EndPoint; - let dx1 = p1.x - p2.x; let dx2 = p3.x - p4.x; let dx3 = p4.x - p2.x; @@ -197,28 +235,100 @@ export function IntersectLineAndLine(l1: Line, l2: Line, intType: IntersectOptio let det = (dx2 * dy1) - (dy2 * dx1); - let res = []; - //直线平行 - if (equaln(det, 0, 1e-6)) + let pt = new Vector3(0, 0, 0); + if (equaln(det, 0.0, 1e-5)) { - //直线共线 if (equaln(dx2 * dy3, dy2 * dx3, 1e-5)) { - res.push(p2); + return midPoint(midPoint(p1, p2), midPoint(p3, p4)); } + return; } + + let ratio = ((dx1 * dy3) - (dy1 * dx3)) / det; + pt.x = (ratio * dx2) + p4.x; + pt.y = (ratio * dy2) + p4.y; + + return pt; +} + +//直线和直线 +export function IntersectLineAndLine(l1: Line, l2: Line, extType: IntersectOption) +{ + let pt = IntersectLAndL(l1.StartPoint, l1.EndPoint, l2.StartPoint, l2.EndPoint); + + return pt ? CheckPointOnCurve([pt], l1, l2, extType) : []; +} + +export function IntersectPolylineAndCurve(pl: Polyline, cu: Curve, extType: IntersectOption): Vector3[] +{ + let cus: Curve[] = pl.Export(); + let cus2: Curve[]; + + if (cu instanceof Polyline) + cus2 = cu.Export() else + cus2 = [cu]; + + let pts: Vector3[] = []; + + for (let i = 0; i < cus.length; i++) { - let ratio = ((dx1 * dy3) - (dy1 * dx3)) / det; - - res.push( - new Vector3( - (ratio * dx2) + p4.x, - (ratio * dy2) + p4.y, - 0 - )); + let cu1 = cus[i]; + for (let j = 0; j < cus2.length; j++) + { + let cu2 = cus2[j]; + let ext = extType; + + let isStart = i === 0; + let isEnd = i === cus.length - 1; + + let isStart2 = j === 0; + let isEnd2 = j === cus2.length - 1; + + //当曲线闭合时,或者当前的子曲线不是起始和不是结束,那么不延伸曲线. + if (pl.CloseMark || !(isStart || isEnd)) + ext = ext & ~IntersectOption.ExtendThis; + if ((cu instanceof Polyline && cu.CloseMark) || !(isStart2 || isEnd2)) + ext = ext & ~IntersectOption.ExtendArg; + + let ipts = cu1.IntersectWith(cu2, ext); + + //校验延伸 + if (IntersectOption.ExtendThis & ext) + { + //如果曲线是起始又是结束,那么不校验. + if (isStart && isEnd) + { + } + else if (isStart) + { + ipts = ipts.filter(p => cu1.GetParamAtPoint(p) <= 1); + } + else if (isEnd) + { + ipts = ipts.filter(p => cu1.GetParamAtPoint(p) >= 0); + } + } + if (IntersectOption.ExtendArg & ext) + { + //如果曲线是起始又是结束,那么不校验. + if (isStart2 && isEnd2) + { + } + else if (isStart2) + { + ipts = ipts.filter(p => cu2.GetParamAtPoint(p) <= cu2.EndParam); + } + else if (isEnd2) + { + ipts = ipts.filter(p => cu2.GetParamAtPoint(p) >= 0); + } + } + + pts.push(...ipts); + } } - return CheckPointOnCurve(res, l1, l2, intType); + return pts; } - diff --git a/src/GraphicsSystem/Viewer.ts b/src/GraphicsSystem/Viewer.ts index 36cc7b0e3..286766e09 100644 --- a/src/GraphicsSystem/Viewer.ts +++ b/src/GraphicsSystem/Viewer.ts @@ -126,9 +126,6 @@ export class Viewer this.m_Composer.addPass(this.m_effectFXAA); this.onSize(); - - - } onSize = (width?, height?) => diff --git a/src/UI/Components/Modal/ModalsManage.tsx b/src/UI/Components/Modal/ModalsManage.tsx index b6ed83e75..9a7126991 100644 --- a/src/UI/Components/Modal/ModalsManage.tsx +++ b/src/UI/Components/Modal/ModalsManage.tsx @@ -65,6 +65,7 @@ export class ModalManage //底部面板高度 let downHeight = document.getElementById("DownPanel").offsetHeight; let dragArea = document.getElementById("dragArea"); + if (!dragArea) return; dragArea.onmousedown = (e) => { //命令栏高度 diff --git a/src/UI/Components/SourceManage/FileItem.tsx b/src/UI/Components/SourceManage/FileItem.tsx index e05c17486..91e37ede2 100644 --- a/src/UI/Components/SourceManage/FileItem.tsx +++ b/src/UI/Components/SourceManage/FileItem.tsx @@ -38,16 +38,14 @@ export class FileItem extends React.Component{ fontWeight: "bold" } const imgStyle: React.CSSProperties = { - transform: "scale(10)", - width: "40px", - height: "40px" + filter: "invert(91%) grayscale(93%) sepia(50%)" } return (
  • @@ -56,7 +54,9 @@ export class FileItem extends React.Component{ style={{ width: 120, height: 120, - overflow: "hidden" + overflow: "hidden", + padding: "8px", + background: "#444444" }} >