From 9d62a5df385843fa92640e010ef2685ee1d8f043 Mon Sep 17 00:00:00 2001 From: ChenX Date: Sun, 25 Jun 2023 08:26:21 +0000 Subject: [PATCH] =?UTF-8?q?!2260=20=E4=BC=98=E5=8C=96:=E5=88=A4=E6=96=ADIs?= =?UTF-8?q?Rect=E7=9A=84=E4=BB=A3=E7=A0=81,=E6=94=AF=E6=8C=81=E5=AE=B9?= =?UTF-8?q?=E5=B7=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PolylineSpliteRect.test.ts.snap | 2 +- .../FeedingToolPath/FeedingToolPath.test.ts | 8 + .../FeedingToolPath.test.ts.snap | 4 + .../__snapshots__/rectOffset.test.ts.snap | 262 +++++++++++++++--- __test__/Polyline/rectOffset.test.ts | 28 +- src/Add-on/Viewport/OneKeyLayout.ts | 8 +- src/Add-on/testEntity/Cmd_Test_IsRect.ts | 26 ++ src/Common/CurveUtils.ts | 160 ++++++++--- src/Editor/CommandRegister.ts | 3 + .../ToolPath/FeedingToolPath.ts | 14 +- .../ToolPath/OptimizeToolPath.ts | 16 +- 11 files changed, 431 insertions(+), 100 deletions(-) create mode 100644 src/Add-on/testEntity/Cmd_Test_IsRect.ts diff --git a/__test__/CurveUtils/__snapshots__/PolylineSpliteRect.test.ts.snap b/__test__/CurveUtils/__snapshots__/PolylineSpliteRect.test.ts.snap index 96f78ae63..b0e28d3b5 100644 --- a/__test__/CurveUtils/__snapshots__/PolylineSpliteRect.test.ts.snap +++ b/__test__/CurveUtils/__snapshots__/PolylineSpliteRect.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`封闭多段线分割矩形测试 交点参数为负数? 1`] = `20916.000000000233`; +exports[`封闭多段线分割矩形测试 交点参数为负数? 1`] = `20915.968910871656`; exports[`封闭多段线分割矩形测试 轮廓1 1`] = `333239.8526794412`; diff --git a/__test__/FeedingToolPath/FeedingToolPath.test.ts b/__test__/FeedingToolPath/FeedingToolPath.test.ts index 1f58f7bb3..4d92492c2 100644 --- a/__test__/FeedingToolPath/FeedingToolPath.test.ts +++ b/__test__/FeedingToolPath/FeedingToolPath.test.ts @@ -190,3 +190,11 @@ test('重复点过多导致的布尔错误', () => let brs = LoadBoardsFromFileData(d); testPathCount(brs[0]); }); + +test('判断为不是矩形导致无法槽加宽', () => +{ + let d = + { "file": [1, "Board", 10, 2, 87004, 0, 1, 2, 71, [0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, -911.4661169474057, -16630.679370175498, 0, 1], 0, 0, 1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -911.4661169474057, -16630.679370175498, 0, 1], 0, 0, 1, 3, 2080, 329, 18, true, "Polyline", 10, 2, 0, 0, 0, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 0, 0, 1, [0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, -1595.2199999999998, -50.82822461578962, 0, 1], 0, 0, 1, 2, 4, [0, 0], 0, [329, 0], 0, [329, 2080], 0, [0, 2080], 0, true, 1, 3, 2030.0000066750217, 9, 8, true, "Polyline", 10, 2, 0, 0, 0, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -310, 2030.0000066750217, 0, 1], 0, 0, 1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -310, 2030.0000066750217, 0, 1], 0, 0, 1, 2, 4, [319, 0], 0, [310, -0.000006675021722912788], 0, [310, -2030.0000066750217], 0, [319, -2030.0000066750217], 0, true, 0, 5, 10, 1, 1, 0, 0, [0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, -901.4661169474057, -16320.679370175498, 49.99999332497828, 1], 3, 0, 0, 0, 0, 0, 11, 1, "左侧板开缺", "", "14 男孩房展示柜", "万华禾香板柠檬绸", "万华禾香板", "柠檬绸", 0, 0, "**多种**", 2, 0, "1", "1", "1", "1", "", "", "", 4, "不排", "不排", "三合一", "三合一", true, true, 0, 0, 0, 0, 0, 0, 0, 0, true, 0, 0, null], "basePt": { "x": -911.4661169474057, "y": -16630.679370175498, "z": 0 }, "ucs": [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1] }; + let brs = LoadBoardsFromFileData(d); + testPathCount(brs[0]); +}); diff --git a/__test__/FeedingToolPath/__snapshots__/FeedingToolPath.test.ts.snap b/__test__/FeedingToolPath/__snapshots__/FeedingToolPath.test.ts.snap index 0e9b27d02..e9d591161 100644 --- a/__test__/FeedingToolPath/__snapshots__/FeedingToolPath.test.ts.snap +++ b/__test__/FeedingToolPath/__snapshots__/FeedingToolPath.test.ts.snap @@ -34,6 +34,10 @@ exports[`刀切到外轮廓情况: 走刀数量 1`] = `2`; exports[`刀切到外轮廓情况: 走刀数量 2`] = `4`; +exports[`判断为不是矩形导致无法槽加宽 1`] = `"2030.00001"`; + +exports[`判断为不是矩形导致无法槽加宽: 走刀数量 1`] = `1`; + exports[`包含刀路丢失#I2CW2U 1`] = `"3096.00000"`; exports[`包含刀路丢失#I2CW2U 2`] = `"436.00000"`; diff --git a/__test__/Polyline/__snapshots__/rectOffset.test.ts.snap b/__test__/Polyline/__snapshots__/rectOffset.test.ts.snap index 1b1a737a7..c47b18182 100644 --- a/__test__/Polyline/__snapshots__/rectOffset.test.ts.snap +++ b/__test__/Polyline/__snapshots__/rectOffset.test.ts.snap @@ -1,24 +1,202 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`矩形偏移 isrect 1`] = ` +Object { + "OCS": Matrix4 { + "elements": Array [ + 0.7071067811865474, + 0.7071067811865476, + 0, + 0, + -0.7071067811865476, + 0.7071067811865474, + 0, + 0, + 0, + 0, + 1, + 0, + 667.9517737972537, + 248.9700940733262, + 0, + 1, + ], + }, + "box": Box3 { + "max": Vector3 { + "x": 932.0360172380435, + "y": 323.35943455197435, + "z": 0, + }, + "min": Vector3 { + "x": -2.842170943040401e-14, + "y": -5.684341886080802e-14, + "z": 0, + }, + }, + "size": Vector3 { + "x": 932.0360172380435, + "y": 323.3594345519744, + "z": 0, + }, +} +`; + +exports[`矩形偏移 isrect 2`] = ` +Array [ + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 0, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 659.0489880991222, + "y": 659.0489880991224, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 430.39933916677364, + "y": 887.6986370314712, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": -228.64964893234873, + "y": 228.64964893234855, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 0, + }, + }, +] +`; + +exports[`矩形偏移 isrect_p0 1`] = ` +Object { + "OCS": Matrix4 { + "elements": Array [ + -0.7428079605957125, + 0.6695045434316621, + 0, + 0, + -0.6695045434316621, + -0.7428079605957125, + 0, + 0, + 0, + 0, + 1, + 0, + 446.3180609256271, + 738.920133175647, + 0, + 1, + ], + }, + "box": Box3 { + "max": Vector3 { + "x": 144.64212978369372, + "y": 397.7658569051579, + "z": 0, + }, + "min": Vector3 { + "x": -2.2737367544323206e-13, + "y": -0, + "z": 0, + }, + }, + "size": Vector3 { + "x": 144.64212978369395, + "y": 397.7658569051579, + "z": 0, + }, +} +`; + +exports[`矩形偏移 isrect_p0 2`] = ` +Array [ + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 0, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 92.43681019536899, + "y": 102.55762882989848, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 156.26222675883798, + "y": 173.37122968863787, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 48.82090131799208, + "y": 270.20979275045295, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": -217.48514710199936, + "y": -25.25385221187355, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": -110.04382166115346, + "y": -122.09241527368857, + }, + }, + Object { + "bul": 0, + "pt": Vector2 { + "x": 0, + "y": 0, + }, + }, +] +`; + exports[`矩形偏移 其他视图旋转矩形 1`] = `50`; exports[`矩形偏移 其他视图旋转矩形 2`] = ` Array [ - 0.7789093282833537, + 0.7789093282833541, 0, - 0.6271365547575544, + 0.6271365547575537, 0, - -0.6271365547575544, + -0.6271365547575537, 0, - 0.7789093282833537, + 0.7789093282833541, 0, 0, -1, 0, 0, + -1062.1715399995587, 0, - 0, - 0, + 0.21291538503150775, 1, ] `; @@ -27,21 +205,21 @@ exports[`矩形偏移 其他视图旋转矩形 3`] = `89.99993930803612`; exports[`矩形偏移 其他视图旋转矩形 4`] = ` Array [ - 0.7789093282833537, + 0.7789093282833541, 0, - 0.6271365547575544, + 0.6271365547575537, 0, - -0.6271365547575544, + -0.6271365547575537, 0, - 0.7789093282833537, + 0.7789093282833541, 0, 0, -1, 0, 0, + -1062.1715399995587, 0, - 0, - 0, + 0.21291538503150775, 1, ] `; @@ -50,21 +228,21 @@ exports[`矩形偏移 其他视图旋转矩形 5`] = `15.00001517299097`; exports[`矩形偏移 其他视图旋转矩形 6`] = ` Array [ - 0.7789093282833537, + 0.7789093282833541, 0, - 0.6271365547575544, + 0.6271365547575537, 0, - -0.6271365547575544, + -0.6271365547575537, 0, - 0.7789093282833537, + 0.7789093282833541, 0, 0, -1, 0, 0, + -1062.1715399995587, 0, - 0, - 0, + 0.21291538503150775, 1, ] `; @@ -85,8 +263,8 @@ Array [ 0, 1, 0, - 0, - 0, + -1327.419794987397, + 40.97675544794174, 0, 1, ] @@ -108,8 +286,8 @@ Array [ 0, 1, 0, - 0, - 0, + -1327.419794987397, + 40.97675544794174, 0, 1, ] @@ -131,8 +309,8 @@ Array [ 0, 1, 0, - 0, - 0, + -1327.419794987397, + 40.97675544794174, 0, 1, ] @@ -142,20 +320,20 @@ exports[`矩形偏移 旋转矩形 1`] = `50`; exports[`矩形偏移 旋转矩形 2`] = ` Array [ - 0.7789093282833537, - 0.6271365547575543, + 0.7789093282833541, + 0.6271365547575537, 0, 0, - -0.6271365547575543, - 0.7789093282833537, + -0.6271365547575537, + 0.7789093282833541, 0, 0, 0, 0, 1, 0, - 0, - 0, + -1281.8810060380358, + 34.63108438909671, 0, 1, ] @@ -165,20 +343,20 @@ exports[`矩形偏移 旋转矩形 3`] = `89.99993930803612`; exports[`矩形偏移 旋转矩形 4`] = ` Array [ - 0.7789093282833537, - 0.6271365547575543, + 0.7789093282833541, + 0.6271365547575537, 0, 0, - -0.6271365547575543, - 0.7789093282833537, + -0.6271365547575537, + 0.7789093282833541, 0, 0, 0, 0, 1, 0, - 0, - 0, + -1281.8810060380358, + 34.63108438909671, 0, 1, ] @@ -188,20 +366,20 @@ exports[`矩形偏移 旋转矩形 5`] = `15.00001517299097`; exports[`矩形偏移 旋转矩形 6`] = ` Array [ - 0.7789093282833537, - 0.6271365547575543, + 0.7789093282833541, + 0.6271365547575537, 0, 0, - -0.6271365547575543, - 0.7789093282833537, + -0.6271365547575537, + 0.7789093282833541, 0, 0, 0, 0, 1, 0, - 0, - 0, + -1281.8810060380358, + 34.63108438909671, 0, 1, ] diff --git a/__test__/Polyline/rectOffset.test.ts b/__test__/Polyline/rectOffset.test.ts index d09a7bafa..377e68a54 100644 --- a/__test__/Polyline/rectOffset.test.ts +++ b/__test__/Polyline/rectOffset.test.ts @@ -7,7 +7,8 @@ describe("矩形偏移", () => { test("常规矩形", () => { - let d = { "file": [1, "Polyline", 8, 2, 102, false, 1, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -1327.419794987397, 40.97675544794174, 0, 1], 0, 0, true, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -1875.419794987397, -2248.0232597250492, 0, 1], 0, 2, 5, [0, 0], 0, [25, 0], 0, [25, 9.99998482700903], 0, [0, 9.99998482700903], 0, [0, 0], 0, false], "basePt": { "x": -1327.419794987397, "y": 40.97675544794174, "z": 0 }, "ucs": [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1] }; + let d = + { "file": [1, "Polyline", 8, 2, 102, false, 1, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -1327.419794987397, 40.97675544794174, 0, 1], 0, 0, true, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -1875.419794987397, -2248.0232597250492, 0, 1], 0, 2, 5, [0, 0], 0, [25, 0], 0, [25, 9.99998482700903], 0, [0, 9.99998482700903], 0, [0, 0], 0, false], "basePt": { "x": -1327.419794987397, "y": 40.97675544794174, "z": 0 }, "ucs": [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1] }; let pl = LoadEntityFromFileData(d)[0] as Polyline; @@ -49,7 +50,8 @@ describe("矩形偏移", () => }); test("其他视图旋转矩形", () => { - let d = { "file": [1, "Polyline", 8, 2, 113, false, 1, 7, 0, [0.7789093282833541, 0, 0.6271365547575537, 0, -0.6271365547575537, 0, 0.7789093282833541, 0, 0, -1, 0, 0, -1062.1715399995587, 0, 0.21291538503150775, 1], 0, 0, true, [0.7789093282833541, 0, 0.6271365547575537, 0, -0.6271365547575537, 0, 0.7789093282833541, 0, 0, -1, 0, 0, -53.4982685432592, 0, -2126.381380881089, 1], 0, 2, 5, [0, 0], 0, [25, 0], 0, [25, 9.99998482700903], 0, [0, 9.99998482700903], 0, [0, 0], 0, false], "basePt": { "x": -1068.442896031597, "y": 0, "z": 0.21291538503150775 }, "ucs": [1, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1] }; + let d = + { "file": [1, "Polyline", 8, 2, 113, false, 1, 7, 0, [0.7789093282833541, 0, 0.6271365547575537, 0, -0.6271365547575537, 0, 0.7789093282833541, 0, 0, -1, 0, 0, -1062.1715399995587, 0, 0.21291538503150775, 1], 0, 0, true, [0.7789093282833541, 0, 0.6271365547575537, 0, -0.6271365547575537, 0, 0.7789093282833541, 0, 0, -1, 0, 0, -53.4982685432592, 0, -2126.381380881089, 1], 0, 2, 5, [0, 0], 0, [25, 0], 0, [25, 9.99998482700903], 0, [0, 9.99998482700903], 0, [0, 0], 0, false], "basePt": { "x": -1068.442896031597, "y": 0, "z": 0.21291538503150775 }, "ucs": [1, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1] }; let pl = LoadEntityFromFileData(d)[0] as Polyline; @@ -68,4 +70,26 @@ describe("矩形偏移", () => expect(l).toBeUndefined(); } }); + + test('isrect', () => + { + let d = + { "file": [1, "Polyline", 10, 2, 114, 0, 1, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 667.9517737972537, 248.9700940733262, 0, 1], 0, 0, 1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 0, 0, 1, 2, 5, [0, 0], 0, [659.0489880991222, 659.0489880991224], 0, [430.39933916677364, 887.6986370314712], 0, [-228.64964893234873, 228.64964893234855], 0, [0, 0], 0, false], "basePt": { "x": 439.302124864905, "y": 248.9700940733262, "z": 0 }, "ucs": [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1] }; + let pl = LoadEntityFromFileData(d)[0] as Polyline; + + let rectInfo = IsRect(pl); + expect(rectInfo).toMatchSnapshot(); + expect(pl.LineData).toMatchSnapshot(); + }); + + test('isrect_p0', () => + { + let d = + { "file": [1, "Polyline", 10, 2, 125, 0, 1, 7, 71, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 290.0558341667891, 565.5489034870092, 0, 1], 0, 0, 1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 0, 0, 1, 2, 7, [0, 0], 0, [92.43681019536899, 102.55762882989848], 0, [156.26222675883798, 173.37122968863787], 0, [48.82090131799208, 270.20979275045295], 0, [-217.48514710199936, -25.25385221187355], 0, [-110.04382166115346, -122.09241527368857], 0, [0, 0], 0, false], "basePt": { "x": 72.57068706478975, "y": 443.4564882133206, "z": 0 }, "ucs": [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1] }; + + let pl = LoadEntityFromFileData(d)[0] as Polyline; + let rectInfo = IsRect(pl); + expect(rectInfo).toMatchSnapshot(); + expect(pl.LineData).toMatchSnapshot(); + }); }); diff --git a/src/Add-on/Viewport/OneKeyLayout.ts b/src/Add-on/Viewport/OneKeyLayout.ts index 3fd93748f..2be62c03f 100644 --- a/src/Add-on/Viewport/OneKeyLayout.ts +++ b/src/Add-on/Viewport/OneKeyLayout.ts @@ -6,11 +6,11 @@ import { EBoardKeyList } from "../../Common/BoardKeyList"; import { IRectInfo, IsRect } from "../../Common/CurveUtils"; import { GroupEntitysByBox } from "../../Common/GroupEntitysByBox"; import { ToplineUrls } from "../../Common/HostUrl"; +import { inflateBase64 } from "../../Common/inflate"; import { KeyWord } from "../../Common/InputState"; import { PostJson, RequestStatus } from "../../Common/Request"; import { GroupFileIn } from "../../Common/SerializeMaterial"; import { Sleep } from "../../Common/Sleep"; -import { inflateBase64 } from "../../Common/inflate"; import { Hole } from "../../DatabaseServices/3DSolid/Hole"; import { SweepSolid } from "../../DatabaseServices/3DSolid/SweepSolid"; import { AlignedDimension } from "../../DatabaseServices/Dimension/AlignedDimension"; @@ -550,11 +550,11 @@ export class OneKeyLayout implements Command { if (en instanceof Polyline) { - let res = IsRect(en); - if (res.isRect && res.size.x > 50 && res.size.y > 50) + let rectInfo = IsRect(en); + if (rectInfo && rectInfo.size.x > 50 && rectInfo.size.y > 50) { this._cacheRect.add(en); - vpRects.push(res); + vpRects.push(rectInfo); } } else if (en instanceof Text) diff --git a/src/Add-on/testEntity/Cmd_Test_IsRect.ts b/src/Add-on/testEntity/Cmd_Test_IsRect.ts new file mode 100644 index 000000000..2ae1053ef --- /dev/null +++ b/src/Add-on/testEntity/Cmd_Test_IsRect.ts @@ -0,0 +1,26 @@ +import { app } from "../../ApplicationServices/Application"; +import { IsRect } from "../../Common/CurveUtils"; +import { Polyline } from "../../DatabaseServices/Entity/Polyline"; +import { Command } from "../../Editor/CommandMachine"; +import { PromptStatus } from "../../Editor/PromptResult"; +import { TestDraw } from "../test/TestUtil"; + +export class Command_Test_IsRect implements Command +{ + async exec() + { + let enRes = await app.Editor.GetEntity({ Filter: { filterTypes: [Polyline] } }); + if (enRes.Status !== PromptStatus.OK) return; + let pl = enRes.Entity as Polyline; + + let rectInfo = IsRect(pl); + + if (rectInfo) + { + let pl = new Polyline().Rectangle(rectInfo.size.x, rectInfo.size.y); + pl.Move(rectInfo.box.min); + pl.ApplyMatrix(rectInfo.OCS); + TestDraw(pl, 1); + } + } +} diff --git a/src/Common/CurveUtils.ts b/src/Common/CurveUtils.ts index 3f693e914..0c6337a9c 100644 --- a/src/Common/CurveUtils.ts +++ b/src/Common/CurveUtils.ts @@ -1,16 +1,17 @@ -import { Box3, Line3, Matrix3, Matrix4, Vec2, Vector2, Vector3 } from 'three'; +import { Box2, Box3, Line3, Matrix3, Matrix4, Vec2, Vector2, Vector3 } from 'three'; import { Arc } from '../DatabaseServices/Entity/Arc'; import { Circle } from '../DatabaseServices/Entity/Circle'; import { Curve } from '../DatabaseServices/Entity/Curve'; import { Ellipse } from '../DatabaseServices/Entity/Ellipse'; import { Line } from '../DatabaseServices/Entity/Line'; -import { Polyline } from '../DatabaseServices/Entity/Polyline'; +import { BUL_IS_LINE_FUZZ, Polyline } from '../DatabaseServices/Entity/Polyline'; import { IsPointInBowArc } from '../DatabaseServices/PointInPolyline'; import { Spline } from '../DatabaseServices/Spline'; import { Count } from '../Geometry/Count'; import { CurveMap, Vertice } from '../Geometry/CurveMap'; -import { AsVector2, AsVector3, equaln, equalv2, equalv3, isIntersect, isParallelTo, isPerpendicularityTo, XAxis, YAxis, ZeroVec } from '../Geometry/GeUtils'; +import { AsVector2, AsVector3, equaln, equalv2, equalv3, isIntersect, isParallelTo, isPerpendicularityTo, XAxis, YAxis, ZAxis, ZeroVec } from '../Geometry/GeUtils'; import { Vec3 } from '../Geometry/IVec3'; +import { Matrix2 } from '../Geometry/Matrix2'; import { Orbit } from '../Geometry/Orbit'; import { PlaneExt } from '../Geometry/Plane'; import { IntersectOption, IntersectResult } from '../GraphicsSystem/IntersectWith'; @@ -500,56 +501,143 @@ export function getTanPtsOnEllipse(cu: Ellipse, lastPoint: Vector3) export interface IRectInfo { - isRect: boolean; - size?: Vector3; - box?: Box3; - OCS?: Matrix4; + size: Vector3; + box: Box3; + OCS: Matrix4; } -export function IsRect(cu: Curve): IRectInfo +/** + * 判断多段线是不是矩形 + * 因为用户画的垃圾图,所以我们会给容差 + * 1.简化点表成4个点 + * -得到x向量,构建二维旋转矩阵 + * -所有的点旋转 + * 2.构建box + * 3.4个点都在盒子里,面积是矩形 + * @param cu + */ +export function IsRect(cu: Curve): IRectInfo | undefined { if (cu instanceof Polyline) { - if (!cu.IsClose) return { isRect: false }; + //如果不封闭(就不是矩形) + if (!cu.IsClose) return; - let pts = cu.GetStretchPoints(); + //如果点个数小于4(就不是矩形) + if (cu.LineData.length < 4) return; - if (pts.length < 4) return { isRect: false }; - - let xVec: Vector3; - let p1 = pts[0]; - for (let i = 1; i < pts.length; i++) + //如果有圆弧(就不是矩形) + for (let i = 0; i < cu.LineData.length; i++) { - xVec = pts[i].clone().sub(p1).normalize(); - if (!equalv3(xVec, ZeroVec)) - break; + let d = cu.LineData[i]; + if (equaln(d.bul, 0, BUL_IS_LINE_FUZZ)) + continue; + let next = FixIndex(i + 1, cu.LineData); + if (equalv2(d.pt, cu.LineData[next].pt)) + continue; + return; } - if (!xVec) return { isRect: false }; + let pts2d = cu.LineData.map(d => d.pt); - let zVec = cu.Normal; - let yVec = zVec.clone().cross(xVec).normalize(); + //去除重复点 + arrayRemoveDuplicateBySort(pts2d, (p1, p2) => equalv2(p1, p2)); + if (equalv2(pts2d[0], pts2d[pts2d.length - 1])) + pts2d.pop(); - let rectOCS = new Matrix4().makeBasis(xVec, yVec, zVec); - let rectOCSInv = new Matrix4().getInverse(rectOCS); + //这里我们判断它是不是有4个90度的角,并且有4个点 + let preV = pts2d[0].clone().sub(pts2d[pts2d.length - 1]).negate();//preVector + let preL = preV.length();//preLength + let nowV = new Vector2;//nowVector + let crossV = 0;//永远相同方向的90度,如果不是(就不是矩形) - for (let p of pts) - p.applyMatrix4(rectOCSInv); + let pts4: Vector2[] = [];//简化成4个点 - let box = new Box3().setFromPoints(pts); + for (let i = 0; i < pts2d.length; i++) + { + nowV.subVectors(pts2d[FixIndex(i + 1, pts2d.length)], pts2d[i]); - let size = box.getSize(new Vector3); - if (equaln(size.x * size.y, cu.Area, 0.1)) + let cross = preV.cross(nowV) / preL; + + let nowL = nowV.length();//nowLength + + if (equaln(cross, 0, 0.01))//平行 此时的cross = 三角形的高(其中preL是三角形的底边) 我们认为它移动了0.01是可以接受的 + continue;//TODOX:我们可能要合并这条线? 把preV preL更新一下? + + cross /= nowL;//此时的cross = sin@ + + //如果不等于90度(就不是矩形) + if (!equaln(Math.abs(cross), 1, 1e-5)) + return; + + cross = Math.sign(cross); + + if (!crossV) + crossV = cross; + else if (crossV !== cross)//如果方向不一致(没有绕着90度)(就不是矩形) + return; + + pts4.push(pts2d[i]); + if (pts4.length > 4)//如果超过4个点(就不是矩形) + return; + + preL = nowL; + preV.copy(nowV).negate();//翻转它 以便下一次计算 + } + + if (pts4.length === 4 && !crossV)//没有90度 (就不是矩形) + return; + + let rectOCS: Matrix4; + + preV.subVectors(pts4[1], pts4[0]); + let box = new Box2; + if (equaln(preV.x, 0, 1e-3) || equaln(preV.y, 0, 1e-3))//判断是不是与X轴平行或者与Y轴平行,精度容差在0.001 看起来没问题 { - return { - isRect: true, - size, - box, - OCS: rectOCS, - }; + rectOCS = cu.OCS; + box.setFromPoints(pts4); } + else//如果矩形不与X轴平行,我们旋转这个点表,然后变换它 + { + let a = Math.atan2(preV.y, preV.x); + let r = new Matrix2().setRotate(-a); + + let p0 = pts4[0]; + pts4 = pts4.map(p => + { + p = p.clone().sub(p0); + r.applyVector(p); + return p; + }); + box.setFromPoints(pts4); + + nowV.set(-preV.y, preV.x);//旋转90度 + + rectOCS = new Matrix4().makeBasis( + AsVector3(preV.normalize()), + AsVector3(nowV.normalize()), + ZAxis, + ).setPosition(p0.x, p0.y, 0); + + rectOCS.multiplyMatrices(cu.OCSNoClone, rectOCS); + } + + //4个点都在角上 + if (!pts4.every(p => + { + return (equaln(p.x, box.min.x, 0.01) || equaln(p.x, box.max.x, 0.01)) + && (equaln(p.y, box.min.y, 0.01) || equaln(p.y, box.max.y, 0.01)); + })) + return; + + let size = box.getSize(new Vector2); + + return { + size: AsVector3(size), + box: new Box3(AsVector3(box.min), AsVector3(box.max)), + OCS: rectOCS, + }; } - return { isRect: false }; } /**用4个矩形点构造矩形 */ @@ -819,7 +907,7 @@ const PolylineSpliteRectFuzz = 1e-3; /**封闭多段线 分割成矩形 */ export function PolylineSpliteRect(outline: Polyline): Polyline[] { - if (!outline.IsClose || IsRect(outline).isRect) + if (!outline.IsClose || IsRect(outline)) return [outline]; let firstDerv = outline.GetFistDeriv(0).normalize(); diff --git a/src/Editor/CommandRegister.ts b/src/Editor/CommandRegister.ts index 90c92d0b6..06734f50b 100644 --- a/src/Editor/CommandRegister.ts +++ b/src/Editor/CommandRegister.ts @@ -216,6 +216,7 @@ import { Command_TemplateSearch } from "../Add-on/TemplateSearch"; import { TestIntersect } from "../Add-on/test/testIntersect"; import { Command_TestParseEdgeSealDir } from "../Add-on/test/TestParseEdgeSealDir"; import { Command_TestTape } from "../Add-on/test/TestTape"; +import { Command_Test_IsRect } from "../Add-on/testEntity/Cmd_Test_IsRect"; import { Command_UpdateLight } from "../Add-on/testEntity/CMD_UpdateLight"; import { Command_DebugTemplateAssocCount } from "../Add-on/testEntity/DebugShowTemplateAssocEntityCount"; import { Test } from "../Add-on/testEntity/test"; @@ -330,6 +331,8 @@ export function registerCommand() commandMachine.RegisterCommand("testRegionParse", new Command_TestRegionParse()); commandMachine.RegisterCommand("TestBoundaryBox", new Command_TestBoundaryBox()); commandMachine.RegisterCommand("TestSweepMaxLength", new Command_TestSweepMaxLength()); + + commandMachine.RegisterCommand("isrect", new Command_Test_IsRect()); } //插入图纸 diff --git a/src/GraphicsSystem/ToolPath/FeedingToolPath.ts b/src/GraphicsSystem/ToolPath/FeedingToolPath.ts index 1cf40ad68..5fdfbf1de 100644 --- a/src/GraphicsSystem/ToolPath/FeedingToolPath.ts +++ b/src/GraphicsSystem/ToolPath/FeedingToolPath.ts @@ -75,7 +75,7 @@ export class FeedingToolPath extends Singleton while (true) { - if ((!isOut || offsetDist >= knifRadius) && rectInfo.isRect) + if ((!isOut || offsetDist >= knifRadius) && rectInfo) offsetDist += knifRadius * 2; else offsetDist += knifRadius; @@ -91,7 +91,7 @@ export class FeedingToolPath extends Singleton retCus.push(...tempOffsetCus); //最后一次内偏移如果是矩形,需在偏移一个刀半径避免没切到中心 - if (retCus.length === 0 && rectInfo.isRect && offsetDist > knifRadius) + if (retCus.length === 0 && rectInfo && offsetDist > knifRadius) { offsetDist -= knifRadius; retCus.push(...GetOffsetCurves(outline, offsetDist * dir, rectInfo)); @@ -273,11 +273,11 @@ export class FeedingToolPath extends Singleton //若是矩形,应用槽加长 if (addLen > 0 || addWidth > 0) { - let curveData = IsRect(shape.Outline.Curve); - if (curveData.isRect) + let rectInfo = IsRect(shape.Outline.Curve); + if (rectInfo) { - let box = curveData.box; - let size = curveData.size; + let box = rectInfo.box; + let size = rectInfo.size; if (size.x > size.y) { box.max.add(new Vector3(addLen / 2, addWidth / 2)); @@ -288,7 +288,7 @@ export class FeedingToolPath extends Singleton box.max.add(new Vector3(addWidth / 2, addLen / 2)); box.min.add(new Vector3(-addWidth / 2, -addLen / 2)); } - let pl = new Polyline().RectangleFrom2Pt(box.min, box.max).ApplyMatrix(curveData.OCS); + let pl = new Polyline().RectangleFrom2Pt(box.min, box.max).ApplyMatrix(rectInfo.OCS); shape.Outline = Contour.CreateContour(pl); } } diff --git a/src/GraphicsSystem/ToolPath/OptimizeToolPath.ts b/src/GraphicsSystem/ToolPath/OptimizeToolPath.ts index e1d45091a..6fc8f87f9 100644 --- a/src/GraphicsSystem/ToolPath/OptimizeToolPath.ts +++ b/src/GraphicsSystem/ToolPath/OptimizeToolPath.ts @@ -247,7 +247,7 @@ export function GetOffsetCurves(cu: Curve, dist: number, rectInfo?: IRectInfo): { if (cu instanceof Polyline) { - if (rectInfo?.isRect) + if (rectInfo) { let r = RectOffset(cu, rectInfo, Math.abs(dist)); return r ? [r] : []; @@ -265,12 +265,12 @@ export function GetCurveToInDir(cu: Curve): number } /**矩形偏移,正为内偏移 */ -export function RectOffset(rect: Polyline, res: IRectInfo, dist: number) +export function RectOffset(rect: Polyline, rectInfo: IRectInfo, dist: number) { - if (!res.isRect || equaln(dist, 0)) return; + if (!rectInfo || equaln(dist, 0)) return; - let box = res.box; - let size = res.size; + let box = rectInfo.box; + let size = rectInfo.size; let min = box.min.clone(); let max = box.max.clone(); @@ -281,19 +281,19 @@ export function RectOffset(rect: Polyline, res: IRectInfo, dist: number) let x = (box.min.x + box.max.x) * 0.5; let sPt = new Vector3(x, box.min.y + dist); let ePt = new Vector3(x, box.max.y - dist); - return new Polyline([{ pt: AsVector2(sPt), bul: 0 }, { pt: AsVector2(ePt), bul: 0 }]).ApplyMatrix(res.OCS); + return new Polyline([{ pt: AsVector2(sPt), bul: 0 }, { pt: AsVector2(ePt), bul: 0 }]).ApplyMatrix(rectInfo.OCS); } else if (equaln(size.y / 2, dist, 1e-5)) { let y = (box.min.y + box.max.y) * 0.5; let sPt = new Vector3(box.min.x + dist, y); let ePt = new Vector3(box.max.x - dist, y); - return new Polyline([{ pt: AsVector2(sPt), bul: 0 }, { pt: AsVector2(ePt), bul: 0 }]).ApplyMatrix(res.OCS); + return new Polyline([{ pt: AsVector2(sPt), bul: 0 }, { pt: AsVector2(ePt), bul: 0 }]).ApplyMatrix(rectInfo.OCS); } else { min.add(new Vector3(dist, dist)); max.add(new Vector3(-dist, -dist)); - return new Polyline().RectangleFrom2Pt(min, max).ApplyMatrix(res.OCS); + return new Polyline().RectangleFrom2Pt(min, max).ApplyMatrix(rectInfo.OCS); } }