diff --git a/__test__/EdgeSealing/__snapshots__/EdgeSealing.test.ts.snap b/__test__/EdgeSealing/__snapshots__/EdgeSealing.test.ts.snap index 938c30940..ff007119f 100644 --- a/__test__/EdgeSealing/__snapshots__/EdgeSealing.test.ts.snap +++ b/__test__/EdgeSealing/__snapshots__/EdgeSealing.test.ts.snap @@ -18,7 +18,7 @@ exports[`异型板件,常规坐标系 3`] = `2660261.483308105`; exports[`异型板件,常规坐标系 4`] = `2628158.6443366623`; -exports[`异型板件,常规坐标系 5`] = `2603082.551922608`; +exports[`异型板件,常规坐标系 5`] = `2603082.551922609`; exports[`异型板件,非常规坐标系 1`] = `75939516.39226122`; diff --git a/__test__/FeedingToolPath/FeedingToolPath.test.ts b/__test__/FeedingToolPath/FeedingToolPath.test.ts index ca27112f0..16e4f87dd 100644 --- a/__test__/FeedingToolPath/FeedingToolPath.test.ts +++ b/__test__/FeedingToolPath/FeedingToolPath.test.ts @@ -57,10 +57,10 @@ test("极限刀半径", () => data = [1, "Board", 2, 1, 0, false, 7, 0, [0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, -1045.5289925195948, 676.3547294712749, 0, 1], 0, 1, 1200, 600, 18, true, "Polyline", 2, 1, 0, false, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 0, 2, 4, [0, 0], 0, [600, 0], 0, [600, 1200], 0, [0, 1200], 0, true, 1, 1, 795.8575198929175, 511.55082631160246, 20, false, "Polyline", 2, 1, 0, false, 3, 0, [0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, -119.65811965811962, 526.6267506621481, 0, 1], 0, 2, 8, [-269.2307692307692, 119.65811965811966], 0, [-269.23076923076945, 631.2089459697221], 0, [526.6267506621481, 631.2089459697221], 0, [526.6267506621481, 119.65811965811963], 0, [466.6267506621481, 119.65811965811962], 0, [466.62675066214797, 571.2089459697221], 0, [-209.2307692307695, 571.2089459697221], 0, [-209.23076923076923, 119.65811965811966], 0, true, 0, 30, 0, [0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, -1252.7209932983192, 706.2274154410178, 0, 1], null, null, 1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], null, "", "{\"roomName\":\"\",\"cabinetName\":\"\",\"boardName\":\"\",\"material\":\"\",\"color\":\"\",\"lines\":0,\"bigHoleDir\":0,\"drillType\":\"three\",\"composingFace\":2,\"highSealed\":[],\"sealedUp\":\"1\",\"sealedDown\":\"1\",\"sealedLeft\":\"1\",\"sealedRight\":\"1\",\"knifeRad\":\"0\",\"grooveAddLength\":\"0\",\"grooveAddWidth\":\"0\",\"grooveAddDepth\":\"0\",\"spliteHeight\":\"\",\"spliteWidth\":\"\",\"spliteThickness\":\"\"}", 0] brs = LoadBoardsFromFileData(data); - testPathCount(brs[0], 3); + testPathCount(brs[0], 5); data = - [1, "Board", 2, 1, 0, false, 7, 0, [0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, -703.1898726073867, -3031.7293464532195, 0, 1], 0, 1, 1200, 600, 18, true, "Polyline", 2, 1, 0, false, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 0, 2, 4, [0, 0], 0, [600, 0], 0, [600, 1200], 0, [0, 1200], 0, true, 1, 1, 400, 120, 18, false, "Polyline", 2, 1, 0, false, 4, 0, [0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 202.2792022792023, -45.86894586894596, 0, 1], 0, 2, 6, [-445.8689458689459, -202.27920227920225], 0, [-445.8689458689459, -142.27920227920225], 0, [-245.8689458689459, -142.27920227920225], 0, [-245.8689458689459, -82.27920227920225], 0, [-45.8689458689459, -82.27920227920225], 0, [-45.86894586894589, -202.27920227920225], 0, true, 0, 30, 0, [0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 2033.3164816261324, -276.0044464373673, 0, 1], null, null, 1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], null, "", "{\"roomName\":\"\",\"cabinetName\":\"\",\"boardName\":\"\",\"material\":\"\",\"color\":\"\",\"lines\":0,\"bigHoleDir\":0,\"drillType\":\"three\",\"composingFace\":2,\"highSealed\":[],\"sealedUp\":\"1\",\"sealedDown\":\"1\",\"sealedLeft\":\"1\",\"sealedRight\":\"1\",\"knifeRad\":\"0\",\"grooveAddLength\":\"0\",\"grooveAddWidth\":\"0\",\"grooveAddDepth\":\"0\",\"spliteHeight\":\"\",\"spliteWidth\":\"\",\"spliteThickness\":\"\"}", 0] + [1, "Board", 5, 2, 103, false, 1, 7, 0, [0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, -2464.8536219638777, -3019.7114880500603, 0, 1], 0, 0, 2, 1200, 600, 18, true, "Polyline", 5, 2, 0, false, 0, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 0, 0, 2, 4, [0, 0], 0, [600, 0], 0, [600, 1200], 0, [0, 1200], 0, true, 1, 2, 400.00000000000006, 120, 18, false, "Polyline", 5, 2, 0, false, 0, 1, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -229.66939762350881, -293.05345437892123, 0, 1], 0, 0, 2, 6, [229.66939762350881, 293.05345437892123], 0, [349.6693976235088, 293.05345437892123], 0, [349.6693976235088, 493.05345437892123], 0, [289.6693976235088, 493.05345437892123], 0, [289.6693976235088, 693.0534543789213], 0, [229.66939762350881, 693.0534543789213], 0, true, 0, 30, 0, 0, 0, [0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, -2757.907076342799, -2790.0420904265516, 0, 1], null, null, 0, 0, 5, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -1761.6637493564908, 12.017858403159153, 0, 1], null, "", "", "", "", "", "", 0, 0, "三合一", 2, 0, "1", "1", "1", "1", "", "", "", 4, "三合一", "三合一", "三合一", "三合一", true, true, 0, 0, 0, 0, 0] brs = LoadBoardsFromFileData(data); testPathCount(brs[0], 3); @@ -115,15 +115,15 @@ test("造型的外框和内框厚度等于刀直径", () => let data = [1, "Board", 3, 2, 118, false, 1, 11, 0, [0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 25702.129700607577, -1144.6658743078003, 0, 1], 2, 1200, 600, 18, true, "Polyline", 3, 2, 0, false, 0, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 4, [0, 0], 0, [600, 0], 0, [600, 1200], 0, [0, 1200], 0, true, 1, 2, 416.58619999999996, 325.1405, 5, true, "Polyline", 3, 2, 0, false, 0, 1, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -1187.5114150409554, -619.5823942857144, 0, 1], 2, 4, [1187.5114150409554, 619.5823942857144], 0, [1512.6519150409554, 619.5823942857144], 0, [1512.6519150409554, 1036.1685942857143], 0, [1187.5114150409554, 1036.1685942857143], 0, true, 1, 2, 404.58619999999996, 313.1405, 5, true, "Polyline", 3, 2, 0, false, 0, 1, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -1193.5114150409554, -625.5823942857144, 0, 1], 2, 4, [1506.6519150409554, 1030.1685942857143], 0, [1193.5114150409554, 1030.1685942857143], 0, [1193.5114150409554, 625.5823942857144], 0, [1506.6519150409554, 625.5823942857144], 0, true, 0, 3, 0, 0, 0, [0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 25715.129700607577, -1015.7520587975966, 455.37831265306136, 1], 3, 0, 0, 0, [0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 25715.129700607577, -1021.7520587975966, 449.37831265306136, 1], 3, 0, 0, 0, 2, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -1686.3109561311285, 139.8723180005327, 0, 1], 1, "左侧板", "{\"roomName\":\"\",\"cabinetName\":\"\",\"boardName\":\"\",\"material\":\"\",\"color\":\"\",\"lines\":0,\"bigHoleDir\":0,\"drillType\":\"three\",\"composingFace\":2,\"highSealed\":[],\"sealedUp\":\"1\",\"sealedDown\":\"1\",\"sealedLeft\":\"1\",\"sealedRight\":\"1\",\"spliteHeight\":\"\",\"spliteWidth\":\"\",\"spliteThickness\":\"\",\"highDrill\":[\"three\",\"three\",\"three\",\"three\",\"three\",\"three\"]}", 0, 0] let brs = LoadBoardsFromFileData(data); - testPathCount(brs[0], 4); + testPathCount(brs[0], 7); }) test("#IYX1P", () => { let data = - [1, "Board", 5, 2, 101, false, 1, 11, 0, [0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 25627.96702118174, -1046.5797499058865, 0, 1], 0, 0, 2, 1200, 600, 18, true, "Polyline", 5, 2, 0, false, 0, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 0, 0, 2, 4, [0, 0], 0, [600, 0], 0, [600, 1200], 0, [0, 1200], 0, true, 1, 2, 416.58619999999996, 325.1405, 5, true, "Polyline", 5, 2, 0, false, 0, 1, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -1187.5114150409554, -619.5823942857144, 0, 1], 0, 0, 2, 4, [1187.5114150409554, 619.5823942857144], 0, [1512.6519150409554, 619.5823942857144], 0, [1512.6519150409554, 1036.1685942857143], 0, [1187.5114150409554, 1036.1685942857143], 0, true, 1, 2, 404.58619999999996, 313.1405, 5, false, "Polyline", 5, 2, 0, false, 0, 1, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -1193.5114150409554, -625.5823942857144, 0, 1], 0, 0, 2, 4, [1444.8769130439057, 968.3935922886646], 0, [1193.5114150409554, 1030.1685942857143], 0, [1193.5114150409554, 625.5823942857144], 0, [1506.6519150409554, 625.5823942857144], 0, true, 0, 3, 0, 0, 0, [0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 25640.96702118174, -917.6659343956826, 455.37831265306136, 1], 3, 0, 0, 0, [0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 25640.96702118174, -923.6659343956826, 449.37831265306136, 1], 3, 0, 0, 0, 3, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -1686.3109561311285, 160.2072462301978, 0, 1], 1, "左侧板", "", "", "", "", "", 0, 0, "three", 2, 0, "1", "1", "1", "1", "", "", "", 6, "three", "three", "three", "three", "three", "three", true, true, 0, 0]; + [1, "Board", 5, 2, 101, false, 1, 11, 0, [0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 25627.96702118174, -1046.5797499058865, 0, 1], 0, 0, 2, 1200, 600, 18, true, "Polyline", 5, 2, 0, false, 0, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 0, 0, 2, 4, [0, 0], 0, [600, 0], 0, [600, 1200], 0, [0, 1200], 0, true, 1, 2, 416.58619999999996, 325.1405, 5, true, "Polyline", 5, 2, 0, false, 0, 1, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -1187.5114150409554, -619.5823942857144, 0, 1], 0, 0, 2, 4, [1187.5114150409554, 619.5823942857144], 0, [1512.6519150409554, 619.5823942857144], 0, [1512.6519150409554, 1036.1685942857143], 0, [1187.5114150409554, 1036.1685942857143], 0, true, 1, 2, 404.58619999999996, 313.1405, 5, false, "Polyline", 5, 2, 0, false, 0, 1, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -1193.5114150409554, -625.5823942857144, 0, 1], 0, 0, 2, 4, [1444.8769130439057, 968.3935922886646], 0, [1193.5114150409554, 1030.1685942857143], 0, [1193.5114150409554, 625.5823942857144], 0, [1506.6519150409554, 625.5823942857144], 0, true, 0, 3, 0, 0, 0, [0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 25640.96702118174, -917.6659343956826, 455.37831265306136, 1], 3, 0, 0, 0, [0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 25640.96702118174, -923.6659343956826, 449.37831265306136, 1], 3, 0, 0, 0, 3, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -1686.3109561311285, 160.2072462301978, 0, 1], 1, "左侧板", "", "", "", "", "", 0, 0, "three", 2, 0, "1", "1", "1", "1", "", "", "", 6, "three", "three", "three", "three", "three", "three", true, true, 0, 0] let brs = LoadBoardsFromFileData(data); - testPathCount(brs[0], 5); + testPathCount(brs[0], 7); }) test("极限刀半径#I11UDE", () => @@ -131,5 +131,21 @@ test("极限刀半径#I11UDE", () => let data = [1, "Board", 5, 2, 101, false, 1, 2, 0, [0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, -2274.8106081003034, 1049.489754699042, 0, 1], 0, 0, 2, 1500, 996.4248716877983, 18, true, "Polyline", 5, 2, 0, false, 0, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 396.42487168779826, 0, 0, 1], 0, 0, 2, 4, [-396.42487168779826, 0], 0, [600, 0], 0, [600, 1500], 0, [-396.42487168779826, 1500], 0, true, 1, 2, 613.5945382529881, 504.5731587306118, 12, false, "Polyline", 5, 2, 0, false, 0, 1, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -286.0137526959925, -382.0303425189268, 0, 1], 0, 0, 2, 12, [656.1445063338533, 607.3988458450913], 0, [763.0711684959024, 607.3988458450913], 0, [763.0711684959024, 995.6248807719148], 0, [476.8367190159561, 995.6248807719148], 0, [476.8367190159561, 794.9317610216076], 0, [286.0137526959925, 794.9317610216076], 0, [286.0137526959925, 382.0303425189268], 0, [656.1445063338533, 382.0303425189268], 0, [656.1445063338533, 519.394335722528], 0, [790.5869114266043, 519.394335722528], 0, [790.5869114266043, 525.394335722528], 0, [656.1445063338533, 525.394335722528], 0, true, 1, 2, 601.5945382529881, 465.0574157999099, 12, false, "Polyline", 5, 2, 0, false, 0, 1, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -292.0137526959925, -388.0303425189268, 0, 1], 0, 0, 2, 12, [650.1445063338533, 525.394335722528], 0, [650.1445063338533, 613.3988458450913], 0, [757.0711684959024, 613.3988458450913], 0, [757.0711684959024, 989.6248807719148], 0, [482.8367190159561, 989.6248807719148], 0, [482.8367190159561, 788.9317610216076], 0, [292.0137526959925, 788.9317610216076], 0, [292.0137526959925, 388.0303425189268], 0, [650.1445063338533, 388.0303425189268], 0, [650.1445063338533, 519.394335722528], 0, [507.05781142660453, 519.394335722528], 0, [507.05781142660453, 525.394335722528], 0, true, 0, 3, 0, 0, 0, [0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, -2662.84095061923, 1341.5035073950344, 6, 1], 3, 0, 0, 0, [0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, -2656.84095061923, 1335.5035073950344, 6, 1], 3, 0, 0, 0, 5, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -2274.8106081003034, 1049.489754699042, 0, 1], 0, "底板", "主卧", "下柜", "", "", "", 0, 1, "三合一", 2, 0, "1", "1", "1", "1", "", "", "", 4, "三合一", "三合一", "三合一", "三合一", true, true, 0, 0, 0, 0, 0] let brs = LoadBoardsFromFileData(data); - testPathCount(brs[0], 4); + testPathCount(brs[0], 12); +}) + +test("复杂造型01", () => +{ + let data = + [1, "Board", 5, 2, 1702, false, 1, 2, 0, [0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 1335.7682619647353, 173.551637279597, 0, 1], 0, 0, 2, 1200, 600, 18, true, "Polyline", 5, 2, 0, false, 0, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 0, 0, 2, 4, [0, 0], 0, [600, 0], 0, [600, 1200], 0, [0, 1200], 0, true, 1, 2, 1036.2015113350126, 440.4613267262604, 10, false, "Polyline", 5, 2, 0, false, 0, 2, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 361.54936893772503, 969.0075566750625, 0, 1], 0, 0, 2, 33, [0, 67.19395465995012], 0, [-310.0352644836272, 67.19395465995012], -0.5981144268442652, [-286.17264943072985, -164.2679339848869], 0.7207592200561973, [-277.08949795465924, -385.7570892090673], 0, [-237.96207621158624, -301.21391008564115], 0, [-211.41132574307244, -520.6069534307294], 0, [-274.2946821158684, -469.60156437279466], 0, [-351.85082164231676, -629.6047711435754], 0, [-232.3724445340044, -591.1760533602005], 0, [-183.46316735516308, -735.1090690579331], 0, [-155.51500896725372, -663.1425612090666], 0, [-171.58520004030163, -863.6705976423159], 0, [-257.52578708312274, -751.8779640906787], 0, [-257.52578708312274, -890.2213481108301], 0, [-310.0352644836272, -905.4214599899233], 0, [-310.0352644836272, -969.0075566750625], 0, [0, -969.0075566750625], 0, [0, -957.9240668043744], -0.9999999999999999, [0, -864.5645981830307], 0, [0, -843.3902891140606], -0.9999999999999999, [0, -700.891826754957], 0, [0, -684.906801007558], 0.9999999999999999, [0, -583.5264483627197], 0, [0, -579.9195144635983], 0.9999999999999999, [0, -422.09559888652757], 0, [0, -409.0723084849551], -0.9999999999999999, [0, -312.3785731271355], 0, [0, -301.4871765134408], 0.9999999999999999, [0, -243.13750862509778], 0, [0, -223.97984886649738], -1.2314232880459324, [0, -77.80352644836466], 0, [0, -58.23046517367129], 0.9999999999999999, [0, 58.230465173671746], 0, true, 5, 2, 20.05062061227784, 15.41391459568868, 10, false, "Polyline", 5, 2, 0, false, 0, 2, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 207.52578708312274, 919.0075566750625, 0, 1], 0, 0, 2, 3, [-207.52578708312274, -898.9569360627846], 0, [-207.52578708312274, -919.0075566750625], 0, [-192.11187248743406, -919.0075566750625], 0, true, 0, 3, 3, 0, 0, [0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 1203.380352644835, 439.26514490680165, 8, 1], 2, 114.03848323053074, 43.29850598181545, 10, false, "Polyline", 5, 2, 0, false, 0, 2, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 125.8595682183174, 146.86649874055365, 0, 1], 0, 0, 2, 4, [-125.85956821831739, -146.86649874055365], 0, [-96.36754317036441, -146.86649874055365], -0.15820638151829505, [-82.56106223650193, -88.79778749503191], -0.13776363653390294, [-116.72059569461629, -32.828015510022965], 0, true, 0, 3, 3, 0, 0, [0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 1203.380352644835, 520.931363771607, 8, 1], 2, 118.14017720514198, 67.669551962062, 10, false, "Polyline", 5, 2, 0, false, 0, 2, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 311.54936893772503, 313.09561944640836, 0, 1], 0, 0, 2, 3, [-264.0938145218924, -209.53632699236087], 0.5176782102931564, [-298.55626262432344, -313.0956194464084], 0, [-243.879816975663, -194.95544224126644], -0.03426656432289884, true, 0, 3, 3, 0, 0, [0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 597.468415416181, 335.24156305219935, 8, 1], 2, 311.0762540509527, 138.91482988296556, 10, false, "Polyline", 5, 2, 0, false, 0, 2, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 110.00287209443024, 360.4181251057296, 0, 1], 0, 0, 2, 10, [-110.00287209443022, -360.4181251057296], -0.19710641679675492, [-42.513452087941566, -297.8639440751849], -0.25973952118910953, [-1.4337638048816683e-14, -274.1813602015127], 0.9999999999999999, [-2.0291827599733876e-14, -272.80100755667445], -0.41421356237309503, [-50.00000000000001, -222.80100755667445], 0, [-50.00000000000001, -219.19407365755296], -0.4142135623730949, [-2.6627322557224985e-14, -169.19407365755296], 0.9999999999999999, [-8.147194749383032e-15, -111.37015808048227], -0.25068130041493886, [-41.59378759840299, -89.11825410919994], -0.1533204796260371, [-85.07341619487701, -49.3418710547769], 0, true, 0, 3, 3, 0, 0, [0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 1005.5163618815475, 536.7880598954941, 8, 1], 2, 552.028541756849, 213.97641288072498, 10, false, "Polyline", 5, 2, 0, false, 0, 2, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 205.74594770705346, 534.8345870968991, 0, 1], 0, 0, 2, 9, [-28.565797815870887, 17.193954659949895], 0, [-193.0890787464058, 17.193954659949938], -0.24599915427853017, [-205.74594770705346, -151.24849135105575], 0, [-159.32470045118714, -534.8345870968991], 0, [-97.2910102382385, -375.09783479855645], -0.3264242677950859, [-43.25358703282456, -272.40084858481384], -0.805868213007247, [-40.3917540832408, -28.76003589144016], -0.23954788447860403, [-1.5119119245645884e-15, -8.230465173671519], 0.9999999999999999, [5.039706415215297e-16, 8.230465173671519], -0.15320924855818352, true, 0, 3, 3, 0, 0, [0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 819.2073830666715, 441.0449842828709, 8, 1], 3, 0, 0, 0, [0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 1253.380352644835, 285.24156305219935, 8, 1], 3, 3, 0, 0, 5, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1335.7682619647353, 173.551637279597, 0, 1], 0, "层板", "", "", "", "", "", 0, 0, "三合一", 2, 0, "1", "1", "1", "1", "", "", "", 4, "三合一", "三合一", "三合一", "三合一", true, true, 0, 0, 0, 0, 0] + let brs = LoadBoardsFromFileData(data); + testPathCount(brs[0], 19); +}) + +test("超级复杂造型01", () => +{ + let data = + [1, "Board", 5, 2, 101, false, 1, 2, 0, [0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 6906.166740982095, 2795.563292573672, 0, 1], 0, 0, 2, 1200, 1415.234920292799, 18, true, "Polyline", 5, 2, 0, false, 0, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 0, 0, 2, 4, [0, 0], 0, [1415.234920292799, 0], 0, [1415.234920292799, 1200], 0, [0, 1200], 0, true, 1, 2, 1009.455190928344, 1152.5635868634386, 10, false, "Polyline", 5, 2, 0, false, 0, 1, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -110.83262952939205, -162.2690102463998, 0, 1], 0, 0, 2, 114, [546.2122521131307, 463.635306848726], 0, [510.8885899443456, 402.4529292629924], 0, [394.8984909384251, 418.3551847777409], 0, [368.1657483508966, 388.13566332941673], 0, [337.2889958595888, 453.9374157055246], 0, [325.1593353846032, 361.8952118373195], 0, [410.02735788536114, 325.2772945269972], 0, [405.12171859588466, 343.585389598916], 0, [495.81323310527205, 376.3416452754878], 0, [445.8641031858455, 289.8272144611814], 0.8761891191134519, [386.8750623164795, 230.5090013972897], 1.2783184936630585, [461.58984505327504, 196.94778827662498], 1.9747112201322605, [477.4188180206925, 263.1047438862613], 0, [521.9427821342738, 340.2225118853565], 0.3709115830376364, [584.826271877211, 306.37895589000436], -1.5491311197323596, [580.3918588974802, 262.5116966947623], 1.4651381769765968, [637.668019748239, 301.4058663297494], 0.4977401596170422, [557.7450033961791, 402.2337781347992], 0, [581.4494574241467, 443.29109687691977], 0.22428912328962228, [792.7793884980764, 443.2910968769231], 0, [828.1030506668618, 382.1087192911876], 0, [756.3362439106579, 289.60947472196443], 0, [769.1407458813505, 251.3484798041734], 0, [696.7163804644547, 257.50930394838946], 0, [770.362436997133, 200.98360790367093], 0, [844.5084948719306, 256.17251270311425], 0, [826.2003998000088, 261.07815199258437], 0, [843.1784075059345, 355.99743530368556], 0, [893.1275374253611, 269.4830044893804], 0.8761891191134511, [915.0040964111065, 188.73789001968402], 1.2783184936630585, [981.4263509238239, 236.66218334765085], 1.9747112201322605, [932.0472332125469, 283.44895385807007], 0, [887.5232690989659, 360.56672185716536], 0.3709115830376364, [948.2743932168107, 398.1036434554911], -1.5491311197323587, [984.0473475844226, 372.32969956655154], 1.4651381769765963, [979.002089046801, 441.37939471204544], 0.4977401596170419, [851.7210478370612, 422.57798810660734], 0, [828.0165938090931, 463.63530684872876], 0.22428912328962483, [933.6815593460577, 646.6523957387673], 0, [1004.3288836836272, 646.6523957387673], 0, [1048.5521759333442, 538.2508956547937], 0, [1088.089420491564, 530.2094221853259], 0, [1046.5418075659773, 470.568493953435], 0, [1132.3175245736406, 506.08500177691997], 0, [1121.5955599476806, 597.8918238866873], 0, [1108.1931041652351, 584.4893681042378], 0, [1034.4795973617747, 646.6523957387673], 0, [1134.3778572006267, 646.6523957387673], 0.8761891191134517, [1215.2434570557384, 625.2254943329636], 1.2783184936630587, [1206.95092883166, 706.7110007815955], 1.9747112201322616, [1141.7428381529649, 687.3408156823781], 0, [1052.694909925804, 687.3408156823781], 0.37091158303763616, [1050.5625443007111, 758.7212932760559], -1.5491311197323598, [1090.7699116480535, 776.8146085823593], 1.4651381769765968, [1028.448492259673, 806.970134092866], 0.4977401596170421, [981.0904674019938, 687.3408156823781], 0, [933.6815593460577, 687.3408156823781], 0.22428912328962594, [828.0165938090908, 870.3579045724159], 0, [863.3402559778768, 931.5402821581505], 0, [979.3303549837976, 915.6380266434035], 0, [1006.0630975713249, 945.8575480917245], 0, [1036.939850062633, 880.0557957156182], 0, [1049.069510537618, 972.0979995838221], 0, [964.201488036861, 1008.7159168941471], 0, [969.1071273263376, 990.4078218222276], 0, [878.4156128169501, 957.6515661456574], 0, [928.3647427363758, 1044.1659969599623], 0.8761891191134513, [987.3537836057427, 1103.4842100238538], 1.2783184936630587, [912.6390008689478, 1137.0454231445192], 1.9747112201322605, [896.8100279015285, 1070.8884675348804], 0, [852.2860637879479, 993.7706995357853], 0.37091158303763616, [789.4025740450113, 1027.6142555311392], -1.5491311197323592, [793.8369870247419, 1071.4815147263803], 1.4651381769765968, [736.5608261739834, 1032.5873450913934], 0.4977401596170421, [816.4838425260439, 931.7594332863455], 0, [792.7793884980748, 890.7021145442221], 0.22428912328962286, [581.4494574241461, 890.7021145442203], 0, [546.1257952553613, 951.884492129954], 0, [617.8926020115647, 1044.383736699179], 0, [605.0881000408726, 1082.6447316169695], 0, [677.5124654577681, 1076.4839074727543], 0, [603.8664089250899, 1133.0096035174727], 0, [529.720351050293, 1077.8206987180288], 0, [548.028446122214, 1072.9150594285593], 0, [531.0504384162878, 977.9957761174608], 0, [481.1013084968621, 1064.5102069317625], 0.8761891191134513, [459.22474951111593, 1145.2553214014604], 1.2783184936630592, [392.80249499840016, 1097.3310280734913], 1.9747112201322605, [442.18161270967636, 1050.5442575630718], 0, [486.70557682325637, 973.4264895639778], 0.3709115830376359, [425.95445270541205, 935.8895679656524], -1.5491311197323592, [390.1814983378, 961.6635118545919], 1.4651381769765972, [395.2267568754221, 892.6138167090973], 0.49774015961704204, [522.5077980851614, 911.4152233145361], 0, [546.2122521131307, 870.3579045724123], 0.22428912328962355, [440.5472865761649, 687.3408156823771], 0, [369.89996223859544, 687.3408156823771], 0, [325.6766699888783, 795.7423157663507], 0, [286.13942543065855, 803.7837892358184], 0, [327.68703835624547, 863.4247174677093], 0, [241.91132134858208, 827.9082096442244], 0, [252.6332859745421, 736.101387534457], 0, [266.03574175698736, 749.5038433169066], 0, [339.749248560448, 687.3408156823771], 0, [239.85098872159597, 687.3408156823771], 0.8761891191134517, [158.98538886648407, 708.7677170881807], 1.2783184936630587, [167.27791709056282, 627.2822106395488], 1.9747112201322616, [232.48600776925764, 646.6523957387662], 0, [321.5339359964188, 646.6523957387662], 0.37091158303763616, [323.66630162151125, 575.2719181450884], -1.5491311197323603, [283.4589342741692, 557.1786028387851], 1.4651381769765968, [345.7803536625497, 527.0230773282783], 0.4977401596170421, [393.1383785202288, 646.6523957387662], 0, [440.547286576165, 646.6523957387662], 0.224289123289626, true, 7, 2, 163.4481707425291, 106.87718750820261, 10, false, "Polyline", 5, 2, 0, false, 0, 1, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -729.893240338891, -213.51854180465347, 0, 1], 0, 0, 2, 7, [767.5177608512217, 287.7079079401577], 0, [783.4520036364486, 240.09496808354942], 0, [729.893240338891, 244.65097793132043], 0, [770.4549903290309, 213.51854180465347], 0, [821.9664175414479, 251.8598823154323], 0, [814.7392201275863, 253.79640402601535], 0, [836.7704278470936, 376.96671254718257], 0, true, 0, 3, 3, 0, 0, [0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 6692.648199177442, 3525.4565329125626, 8, 1], 2, 76.13325827250429, 174.7079868241599, 10, false, "Polyline", 5, 2, 0, false, 0, 1, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -336.0611832435618, -342.6429909554271, 0, 1], 0, 0, 2, 7, [398.8424442686699, 407.7209236634632], 0, [365.57555019659924, 370.11499469308256], 0, [342.7417888158825, 418.7762492279314], 0, [336.0611832435618, 368.08252525118235], 0, [395.0214717472545, 342.6429909554271], 0, [393.084950036669, 349.87018836928695], 0, [510.7691700677217, 392.37575706872775], 0, true, 0, 3, 3, 0, 0, [0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 6563.523750026668, 3131.6244758172334, 8, 1], 2, 163.44817074253433, 106.87718750820511, 10, false, "Polyline", 5, 2, 0, false, 0, 1, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -537.4584180751272, -957.0264988739559, 0, 1], 0, 0, 2, 7, [606.7110850710009, 1046.2853034809857], 0, [590.7768422857748, 1093.8982433375932], 0, [644.3356055833323, 1089.3422334898228], 0, [603.7738555931919, 1120.4746696164902], 0, [552.2624283807759, 1082.133329105711], 0, [559.4896257946365, 1080.1968073951284], 0, [537.4584180751272, 957.0264988739559], 0, true, 0, 3, 3, 0, 0, [0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 5949.140242108138, 3333.021710648799, 8, 1], 2, 158.7162267750724, 108.39254930609923, 10, false, "Polyline", 5, 2, 0, false, 0, 1, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -1013.1156807404807, -492.8713344139586, 0, 1], 0, 0, 2, 7, [1055.7897395436635, 546.9835899872647], 0, [1104.9908764009592, 536.9765791010359], 0, [1074.265874484119, 492.8713344139586], 0, [1121.50823004658, 512.4326222640398], 0, [1114.0593687553044, 576.2134970705756], 0, [1108.768693052028, 570.9228213672977], 0, [1013.1156807404807, 651.587561189031], 0, true, 0, 3, 3, 0, 0, [0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 6413.295406568136, 3808.6789733141522, 8, 1], 2, 158.71622677507253, 108.39254930609934, 10, false, "Polyline", 5, 2, 0, false, 0, 1, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -252.7206158756427, -682.4056502321132, 0, 1], 0, 0, 2, 7, [318.43910637855913, 787.0096214338796], 0, [269.2379695212633, 797.0166323201084], 0, [299.96297143810364, 841.1218770071857], 0, [252.7206158756427, 821.5605891571046], 0, [260.1694771669182, 757.7797143505688], 0, [265.46015287019435, 763.0703900538466], 0, [361.11316518174203, 682.4056502321132], 0, true, 0, 3, 3, 0, 0, [0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 6223.761090749982, 3048.2839084493144, 8, 1], 2, 76.13325827250571, 174.7079868241641, 10, false, "Polyline", 5, 2, 0, false, 0, 1, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -863.4596758544952, -915.2169621932109, 0, 1], 0, 0, 2, 7, [975.386401653553, 926.272287757681], 0, [1008.6532957256223, 963.8782167280583], 0, [1031.487057106339, 915.2169621932109], 0, [1038.1676626786593, 965.9106861699595], 0, [979.2073741749676, 991.3502204657166], 0, [981.1438958855531, 984.1230230518564], 0, [863.4596758544952, 941.617454352416], 0, true, 0, 3, 3, 0, 0, [0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 5990.949778788884, 3659.022968428167, 8, 1], 2, 989.4551909283438, 1132.5635868634383, 10, false, "Polyline", 5, 2, 0, false, 0, 1, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -120.83262952939208, -172.26901024639977, 0, 1], 0, 0, 2, 78, [559.5663016834698, 466.76519919134637], 0, [447.74633707250223, 273.0873391845985], 1.2107755706482595, [401.06143830221106, 230.4458338517582], 1.476313731901473, [451.7497409126958, 198.72889762266607], -0.6338881701575324, [469.2210705418825, 203.41032628750173], 1.9747112201322594, [481.29856766807256, 253.88804476598756], -0.7187618369097628, [468.75856398284816, 268.10474388626136], 0, [531.9573840717943, 377.56831125871935], 0.6076270264192377, [582.2246887096073, 316.04815802383195], -1.056072725727382, [599.2028752747767, 249.91226972303474], 1.1990341256616792, [625.5901316489375, 296.4089461125296], 0.6262509181102476, [538.5891200323244, 389.05481488473947], 0, [577.4829989187975, 456.42098921954147], 0.2447235823095675, [796.745847003427, 456.4209892195423], 0, [908.5658116143933, 262.7431292127976], 1.2107755706482524, [922.1519891030973, 200.9920682381993], 1.4763137319014716, [974.9638129129447, 229.03095785904537], -0.6338881701575259, [979.6452415777857, 246.50228748823065], 1.9747112201322574, [941.9690036134315, 282.2005660528881], -0.7187618369097625, [923.3869791747024, 278.44895385807007], 0, [860.188159085755, 387.91252123053107], 0.6076270264192505, [938.5998269507871, 400.68520740920064], -1.0560727257274047, [1004.3642796037138, 382.320804134432], 1.199034125661666, [977.2906048459467, 428.4211766853746], 0.6262509181102482, [853.5564231252271, 399.3990248565476], 0, [814.6625442387541, 466.7651991913492], 0.24472358230957014, [924.2939682810685, 656.6523957387673], 0, [1147.933897503002, 656.6523957387673], 1.2107755706482537, [1208.2049737619973, 637.5428400970104], 1.4763137319014754, [1210.3284949613599, 697.298665946949], -0.6338881228918971, [1197.5385939970142, 710.0885669112987], 1.9747112201322616, [1147.7848589064697, 695.3091269974698], -0.7187618369097591, [1141.7428381529649, 677.3408156823781], 0, [1015.3451979750739, 677.3408156823781], 0.6076270264192353, [1043.4895612022924, 751.6336550959388], -1.0560727257273963, [1092.2758272900478, 799.4051401219672], 1.1990341256616788, [1038.81489615812, 799.0088362834151], 0.6262509181102486, [1002.0817260540146, 677.3408156823781], 0, [924.2939682810685, 677.3408156823781], 0.24472358230957122, [814.6625442387516, 867.2280122297954], 0, [926.4825088497191, 1060.9058722365453], 1.2107755706482608, [973.1674076200112, 1103.5473775693856], 1.476313731901471, [922.4791050095271, 1135.2643137984778], -0.633888170157537, [905.0077753803403, 1130.5828851336425], 1.9747112201322616, [892.9302782541487, 1080.105166655154], -0.7187618369097533, [905.470281939373, 1065.8884675348804], 0, [842.271461850423, 956.4249001624141], 0.6076270264193032, [792.0041572126152, 1017.9450533973115], -1.0560727257273785, [775.0259706474455, 1084.0809416981076], 1.199034125661683, [748.638714273285, 1037.5842653086133], 0.6262509181102495, [835.6397258898987, 944.9383965364054], 0, [796.7458470034247, 877.5722222016016], 0.24472358230956814, [577.4829989187964, 877.5722222015997], 0, [465.6630343078299, 1071.2500822083452], 1.2107755706482382, [452.07685681912545, 1133.0011431829453], 1.476313731901468, [399.26503300927914, 1104.962253562097], -0.6338881701575424, [394.5836043444382, 1087.4909239329115], 1.9747112201322594, [432.25984230879163, 1051.792645368254], -0.7187618369097573, [450.8418667475207, 1055.5442575630718], 0, [514.0406868364669, 946.0806901906126], 0.6076270264192496, [435.6290189714356, 933.3080040119426], -1.0560727257274019, [369.86456631850876, 951.6724072867113], 1.199034125661676, [396.9382410762763, 905.572034735768], 0.6262509181102498, [520.6724227969955, 934.594186564596], 0, [559.5663016834699, 867.2280122297917], 0.2447235823095691, [449.9348776411539, 677.3408156823771], 0, [226.2949484192206, 677.3408156823771], 1.2107755706482526, [166.02387216022493, 696.4503713241339], 1.4763137319014734, [163.90035096086265, 636.6945454741954], -0.6338881701575362, [176.6902519252084, 623.9046445098458], 1.9747112201322616, [226.44398701575287, 638.6840844236746], -0.7187618369097579, [232.48600776925764, 656.6523957387662], 0, [358.88364794715017, 656.6523957387662], 0.6076270264192456, [330.73928471993025, 582.3595563252055], -1.056072725727393, [281.9530186321748, 534.5880712991773], 1.1990341256616774, [335.41394976410254, 534.9843751377292], 0.6262509181102486, [372.14711986820805, 656.6523957387662], 0, [449.93487764115434, 656.6523957387662], 0.24472358230957142, true, 0, 3, 3, 0, 0, [0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 6733.897730735695, 2916.3959221030636, 8, 1], 3, 0, 0, 0, [0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 6743.897730735695, 2906.3959221030636, 8, 1], 3, 3, 0, 0, 5, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 6906.166740982095, 2795.563292573672, 0, 1], 0, "层板", "", "", "", "", "", 0, 0, "三合一", 2, 0, "1", "1", "1", "1", "", "", "", 4, "三合一", "三合一", "三合一", "三合一", true, true, 0, 0, 0, 0, 0] + let brs = LoadBoardsFromFileData(data); + testPathCount(brs[0]); }) diff --git a/__test__/FeedingToolPath/__snapshots__/FeedingToolPath.test.ts.snap b/__test__/FeedingToolPath/__snapshots__/FeedingToolPath.test.ts.snap index 12bb78940..26f45c223 100644 --- a/__test__/FeedingToolPath/__snapshots__/FeedingToolPath.test.ts.snap +++ b/__test__/FeedingToolPath/__snapshots__/FeedingToolPath.test.ts.snap @@ -1,20 +1,24 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`#IYX1P: 曲线长度 1`] = `1334.7992356906177`; +exports[`#IYX1P: 曲线长度 1`] = `1346.3292345344717`; -exports[`#IYX1P: 曲线长度 2`] = `7092.317327216775`; +exports[`#IYX1P: 曲线长度 2`] = `8468.604267178238`; -exports[`#IYX1P: 曲线长度 3`] = `3600`; +exports[`#IYX1P: 曲线长度 3`] = `10.71238898038469`; -exports[`#IYX1P: 曲线长度 4`] = `1483.4533999999999`; +exports[`#IYX1P: 曲线长度 4`] = `10.71238898038469`; -exports[`#IYX1P: 曲线长度 5`] = `1324.9044565737036`; +exports[`#IYX1P: 曲线长度 5`] = `3600`; -exports[`#IYX1P: 走刀数量 1`] = `2`; +exports[`#IYX1P: 曲线长度 6`] = `1483.4533999999999`; -exports[`刀切到外轮廓情况: 曲线长度 1`] = `22596.75011038597`; +exports[`#IYX1P: 曲线长度 7`] = `1324.9044565737036`; -exports[`刀切到外轮廓情况: 曲线长度 2`] = `6355.243980781998`; +exports[`#IYX1P: 走刀数量 1`] = `4`; + +exports[`刀切到外轮廓情况: 曲线长度 1`] = `22596.75011038598`; + +exports[`刀切到外轮廓情况: 曲线长度 2`] = `6355.243980782019`; exports[`刀切到外轮廓情况: 曲线长度 3`] = `3600`; @@ -22,115 +26,155 @@ exports[`刀切到外轮廓情况: 曲线长度 4`] = `1478.9393851461323`; exports[`刀切到外轮廓情况: 曲线长度 5`] = `729.5688477133849`; -exports[`刀切到外轮廓情况: 曲线长度 6`] = `939.4039853849376`; +exports[`刀切到外轮廓情况: 曲线长度 6`] = `14681.465974109033`; -exports[`刀切到外轮廓情况: 曲线长度 7`] = `13736.355649626326`; +exports[`刀切到外轮廓情况: 曲线长度 7`] = `14658.277022001026`; -exports[`刀切到外轮廓情况: 曲线长度 8`] = `1216.987577519942`; +exports[`刀切到外轮廓情况: 曲线长度 8`] = `14681.465974109033`; -exports[`刀切到外轮廓情况: 曲线长度 9`] = `13428.231939084195`; +exports[`刀切到外轮廓情况: 曲线长度 9`] = `14658.277022000973`; -exports[`刀切到外轮廓情况: 曲线长度 10`] = `939.4039853849374`; +exports[`刀切到外轮廓情况: 曲线长度 10`] = `3600`; -exports[`刀切到外轮廓情况: 曲线长度 11`] = `13736.355649626326`; +exports[`刀切到外轮廓情况: 曲线长度 11`] = `2683.281572999748`; -exports[`刀切到外轮廓情况: 曲线长度 12`] = `13428.23193908413`; +exports[`刀切到外轮廓情况: 曲线长度 12`] = `1800`; -exports[`刀切到外轮廓情况: 曲线长度 13`] = `1216.9875775199384`; +exports[`刀切到外轮廓情况: 走刀数量 1`] = `2`; -exports[`刀切到外轮廓情况: 曲线长度 14`] = `3600`; +exports[`刀切到外轮廓情况: 走刀数量 2`] = `4`; -exports[`刀切到外轮廓情况: 曲线长度 15`] = `2683.281572999748`; +exports[`复杂极限刀半径: 曲线长度 1`] = `232.80420650475034`; -exports[`刀切到外轮廓情况: 曲线长度 16`] = `1800`; +exports[`复杂极限刀半径: 曲线长度 2`] = `806.2513545258738`; -exports[`刀切到外轮廓情况: 走刀数量 1`] = `2`; +exports[`复杂极限刀半径: 曲线长度 3`] = `31170.805670163638`; + +exports[`复杂极限刀半径: 曲线长度 4`] = `2917.48021978714`; + +exports[`复杂极限刀半径: 曲线长度 5`] = `4434.591784188829`; + +exports[`复杂极限刀半径: 曲线长度 6`] = `4356.840832388074`; + +exports[`复杂极限刀半径: 曲线长度 7`] = `951.5402172137751`; + +exports[`复杂极限刀半径: 曲线长度 8`] = `3278.9179349887763`; + +exports[`复杂极限刀半径: 走刀数量 1`] = `5`; + +exports[`复杂造型01: 曲线长度 1`] = `59609.750635032455`; + +exports[`复杂造型01: 曲线长度 2`] = `1482.4552077856665`; + +exports[`复杂造型01: 曲线长度 3`] = `838.7907023816642`; + +exports[`复杂造型01: 曲线长度 4`] = `119.2450237058813`; + +exports[`复杂造型01: 曲线长度 5`] = `920.6205527518313`; -exports[`刀切到外轮廓情况: 走刀数量 2`] = `8`; +exports[`复杂造型01: 曲线长度 6`] = `136.38881122495832`; -exports[`复杂极限刀半径: 曲线长度 1`] = `1068.3190582501113`; +exports[`复杂造型01: 曲线长度 7`] = `40.76338989846492`; -exports[`复杂极限刀半径: 曲线长度 2`] = `35730.26757931215`; +exports[`复杂造型01: 曲线长度 8`] = `3.2524680966497335`; -exports[`复杂极限刀半径: 曲线长度 3`] = `2927.3167299028455`; +exports[`复杂造型01: 曲线长度 9`] = `301.66992978702626`; -exports[`复杂极限刀半径: 曲线长度 4`] = `4356.840832388074`; +exports[`复杂造型01: 曲线长度 10`] = `1749.8631881230112`; -exports[`复杂极限刀半径: 曲线长度 5`] = `951.5402172137751`; +exports[`复杂造型01: 曲线长度 11`] = `7.8285491298056655`; -exports[`复杂极限刀半径: 曲线长度 6`] = `3278.9179349887763`; +exports[`复杂造型01: 曲线长度 12`] = `2.5692483033658107`; -exports[`复杂极限刀半径: 走刀数量 1`] = `3`; +exports[`复杂造型01: 曲线长度 13`] = `3600`; + +exports[`复杂造型01: 曲线长度 14`] = `4316.136010511218`; + +exports[`复杂造型01: 曲线长度 15`] = `60.75516885168303`; + +exports[`复杂造型01: 曲线长度 16`] = `270.97161059159566`; + +exports[`复杂造型01: 曲线长度 17`] = `282.82481905047365`; + +exports[`复杂造型01: 曲线长度 18`] = `819.9411466147131`; + +exports[`复杂造型01: 曲线长度 19`] = `1463.6056529693449`; + +exports[`复杂造型01: 走刀数量 1`] = `12`; exports[`复杂造型测试: 曲线长度 1`] = `24373.250750763476`; -exports[`复杂造型测试: 曲线长度 2`] = `4285.071854430757`; +exports[`复杂造型测试: 曲线长度 2`] = `4285.071854430756`; -exports[`复杂造型测试: 曲线长度 3`] = `2418.1434517838106`; +exports[`复杂造型测试: 曲线长度 3`] = `2418.1434517838115`; exports[`复杂造型测试: 曲线长度 4`] = `2293.0762218537734`; -exports[`复杂造型测试: 曲线长度 5`] = `4096.105045378747`; +exports[`复杂造型测试: 曲线长度 5`] = `4096.105045378748`; -exports[`复杂造型测试: 曲线长度 6`] = `910.1341511193466`; +exports[`复杂造型测试: 曲线长度 6`] = `8.0486334855557`; -exports[`复杂造型测试: 曲线长度 7`] = `2841.1337227520216`; +exports[`复杂造型测试: 曲线长度 7`] = `875.5142132396979`; -exports[`复杂造型测试: 曲线长度 8`] = `1079.2736477434973`; +exports[`复杂造型测试: 曲线长度 8`] = `2841.1337227520225`; -exports[`复杂造型测试: 曲线长度 9`] = `227.8342135021163`; +exports[`复杂造型测试: 曲线长度 9`] = `1079.273647743498`; -exports[`复杂造型测试: 曲线长度 10`] = `16.405200898113836`; +exports[`复杂造型测试: 曲线长度 10`] = `227.8342135021163`; -exports[`复杂造型测试: 曲线长度 11`] = `696.1986486992679`; +exports[`复杂造型测试: 曲线长度 11`] = `16.405200898113836`; -exports[`复杂造型测试: 曲线长度 12`] = `639.7910377879329`; +exports[`复杂造型测试: 曲线长度 12`] = `696.1986486992679`; -exports[`复杂造型测试: 曲线长度 13`] = `2402.511185283596`; +exports[`复杂造型测试: 曲线长度 13`] = `639.7910377879329`; -exports[`复杂造型测试: 曲线长度 14`] = `1715.2225461089636`; +exports[`复杂造型测试: 曲线长度 14`] = `2402.511185283596`; -exports[`复杂造型测试: 曲线长度 15`] = `493.42887087968916`; +exports[`复杂造型测试: 曲线长度 15`] = `1715.2225461089636`; -exports[`复杂造型测试: 曲线长度 16`] = `352.7973262382525`; +exports[`复杂造型测试: 曲线长度 16`] = `493.42887087968916`; -exports[`复杂造型测试: 曲线长度 17`] = `342.70973636046426`; +exports[`复杂造型测试: 曲线长度 17`] = `352.7973262382525`; -exports[`复杂造型测试: 曲线长度 18`] = `476.0989607667295`; +exports[`复杂造型测试: 曲线长度 18`] = `342.70973636046426`; -exports[`复杂造型测试: 曲线长度 19`] = `1167.5479341842504`; +exports[`复杂造型测试: 曲线长度 19`] = `476.0989607667295`; -exports[`复杂造型测试: 曲线长度 20`] = `413.7195254587742`; +exports[`复杂造型测试: 曲线长度 20`] = `1167.5479341842504`; -exports[`复杂造型测试: 曲线长度 21`] = `275.9275697576068`; +exports[`复杂造型测试: 曲线长度 21`] = `413.7195254587742`; -exports[`复杂造型测试: 曲线长度 22`] = `99.71551046503953`; +exports[`复杂造型测试: 曲线长度 22`] = `275.9275697576068`; -exports[`复杂造型测试: 曲线长度 23`] = `35.25475681965266`; +exports[`复杂造型测试: 曲线长度 23`] = `99.71551046503953`; -exports[`复杂造型测试: 曲线长度 24`] = `169.22283273433305`; +exports[`复杂造型测试: 曲线长度 24`] = `35.25475681965266`; -exports[`复杂造型测试: 曲线长度 25`] = `162.171881370416`; +exports[`复杂造型测试: 曲线长度 25`] = `169.22283273433305`; -exports[`复杂造型测试: 曲线长度 26`] = `106446.82051696385`; +exports[`复杂造型测试: 曲线长度 26`] = `162.171881370416`; -exports[`复杂造型测试: 曲线长度 27`] = `5545.665343214347`; +exports[`复杂造型测试: 曲线长度 27`] = `104483.03471871806`; -exports[`复杂造型测试: 曲线长度 28`] = `3600`; +exports[`复杂造型测试: 曲线长度 28`] = `2279.1571138841996`; -exports[`复杂造型测试: 曲线长度 29`] = `2581.0848141151123`; +exports[`复杂造型测试: 曲线长度 29`] = `5545.665343214347`; -exports[`复杂造型测试: 曲线长度 30`] = `463.19933816470575`; +exports[`复杂造型测试: 曲线长度 30`] = `3600`; -exports[`复杂造型测试: 曲线长度 31`] = `713.891109728082`; +exports[`复杂造型测试: 曲线长度 31`] = `2581.0848141151123`; -exports[`复杂造型测试: 走刀数量 1`] = `12`; +exports[`复杂造型测试: 曲线长度 32`] = `463.19933816470575`; -exports[`复杂造型测试: 走刀数量 2`] = `2`; +exports[`复杂造型测试: 曲线长度 33`] = `713.891109728082`; -exports[`带孔造型板件: 曲线长度 1`] = `53389.1518227565`; +exports[`复杂造型测试: 走刀数量 1`] = `13`; -exports[`带孔造型板件: 曲线长度 2`] = `4667.086663355046`; +exports[`复杂造型测试: 走刀数量 2`] = `3`; + +exports[`带孔造型板件: 曲线长度 1`] = `54662.04598627183`; + +exports[`带孔造型板件: 曲线长度 2`] = `4678.35714568232`; exports[`带孔造型板件: 曲线长度 3`] = `3600`; @@ -138,9 +182,9 @@ exports[`带孔造型板件: 曲线长度 4`] = `2195.9741153279983`; exports[`带孔造型板件: 曲线长度 5`] = `1209.6929369796912`; -exports[`带孔造型板件: 曲线长度 6`] = `53389.1518227565`; +exports[`带孔造型板件: 曲线长度 6`] = `54662.04598627183`; -exports[`带孔造型板件: 曲线长度 7`] = `4667.086663355046`; +exports[`带孔造型板件: 曲线长度 7`] = `4678.35714568232`; exports[`带孔造型板件: 曲线长度 8`] = `3600`; @@ -152,17 +196,33 @@ exports[`带孔造型板件: 走刀数量 1`] = `2`; exports[`带孔造型板件: 走刀数量 2`] = `2`; -exports[`极限刀半径#I11UDE: 曲线长度 1`] = `2434.8330081057957`; +exports[`极限刀半径#I11UDE: 曲线长度 1`] = `2589.4683707776608`; + +exports[`极限刀半径#I11UDE: 曲线长度 2`] = `10.71238898038469`; + +exports[`极限刀半径#I11UDE: 曲线长度 3`] = `10.71238898038469`; + +exports[`极限刀半径#I11UDE: 曲线长度 4`] = `10.71238898038521`; + +exports[`极限刀半径#I11UDE: 曲线长度 5`] = `10.712388980384734`; + +exports[`极限刀半径#I11UDE: 曲线长度 6`] = `10.71238898038408`; -exports[`极限刀半径#I11UDE: 曲线长度 2`] = `4992.8497433755965`; +exports[`极限刀半径#I11UDE: 曲线长度 7`] = `10.7123889803843`; -exports[`极限刀半径#I11UDE: 曲线长度 3`] = `2450.188718291298`; +exports[`极限刀半径#I11UDE: 曲线长度 8`] = `10.712388980384993`; -exports[`极限刀半径#I11UDE: 曲线长度 4`] = `2419.4772979202935`; +exports[`极限刀半径#I11UDE: 曲线长度 9`] = `10.71238898038469`; -exports[`极限刀半径#I11UDE: 走刀数量 1`] = `1`; +exports[`极限刀半径#I11UDE: 曲线长度 10`] = `4992.8497433755965`; -exports[`极限刀半径: 曲线长度 1`] = `999.9999999999999`; +exports[`极限刀半径#I11UDE: 曲线长度 11`] = `2450.188718291298`; + +exports[`极限刀半径#I11UDE: 曲线长度 12`] = `2419.4772979202935`; + +exports[`极限刀半径#I11UDE: 走刀数量 1`] = `9`; + +exports[`极限刀半径: 曲线长度 1`] = `1314.2477796076937`; exports[`极限刀半径: 曲线长度 2`] = `3600`; @@ -174,33 +234,193 @@ exports[`极限刀半径: 曲线长度 5`] = `3600`; exports[`极限刀半径: 曲线长度 6`] = `1552.3359576397822`; -exports[`极限刀半径: 曲线长度 7`] = `1638.9591725161226`; +exports[`极限刀半径: 曲线长度 7`] = `1638.9591725161224`; + +exports[`极限刀半径: 曲线长度 8`] = `47.12388980384689`; -exports[`极限刀半径: 曲线长度 8`] = `3600`; +exports[`极限刀半径: 曲线长度 9`] = `47.12388980384689`; -exports[`极限刀半径: 曲线长度 9`] = `3517.9183450322453`; +exports[`极限刀半径: 曲线长度 10`] = `3600`; -exports[`极限刀半径: 曲线长度 10`] = `600`; +exports[`极限刀半径: 曲线长度 11`] = `3517.9183450322453`; -exports[`极限刀半径: 曲线长度 11`] = `3600`; +exports[`极限刀半径: 曲线长度 12`] = `617.1238898038469`; -exports[`极限刀半径: 曲线长度 12`] = `1040`; +exports[`极限刀半径: 曲线长度 13`] = `3600`; -exports[`极限刀半径: 曲线长度 13`] = `390`; +exports[`极限刀半径: 曲线长度 14`] = `1040`; -exports[`极限刀半径: 曲线长度 14`] = `3600`; +exports[`极限刀半径: 曲线长度 15`] = `390`; -exports[`极限刀半径: 曲线长度 15`] = `900`; +exports[`极限刀半径: 曲线长度 16`] = `23.56194490192345`; + +exports[`极限刀半径: 曲线长度 17`] = `3600`; + +exports[`极限刀半径: 曲线长度 18`] = `900`; exports[`极限刀半径: 走刀数量 1`] = `1`; exports[`极限刀半径: 走刀数量 2`] = `1`; -exports[`极限刀半径: 走刀数量 3`] = `1`; +exports[`极限刀半径: 走刀数量 3`] = `3`; exports[`极限刀半径: 走刀数量 4`] = `1`; -exports[`极限刀半径: 走刀数量 5`] = `1`; +exports[`极限刀半径: 走刀数量 5`] = `2`; + +exports[`超级复杂造型01: 曲线长度 1`] = `23310.391778382174`; + +exports[`超级复杂造型01: 曲线长度 2`] = `11849.91310995222`; + +exports[`超级复杂造型01: 曲线长度 3`] = `9.894843040787247`; + +exports[`超级复杂造型01: 曲线长度 4`] = `2.686492242389678`; + +exports[`超级复杂造型01: 曲线长度 5`] = `15.558634753572182`; + +exports[`超级复杂造型01: 曲线长度 6`] = `1.5023362215203946`; + +exports[`超级复杂造型01: 曲线长度 7`] = `36.738926324214475`; + +exports[`超级复杂造型01: 曲线长度 8`] = `2.345373451530522`; + +exports[`超级复杂造型01: 曲线长度 9`] = `23.179252903171008`; + +exports[`超级复杂造型01: 曲线长度 10`] = `34.11040843800545`; + +exports[`超级复杂造型01: 曲线长度 11`] = `3.00516024046907`; + +exports[`超级复杂造型01: 曲线长度 12`] = `3.005160240466534`; + +exports[`超级复杂造型01: 曲线长度 13`] = `3.0051602404694115`; + +exports[`超级复杂造型01: 曲线长度 14`] = `3.0051642696018828`; + +exports[`超级复杂造型01: 曲线长度 15`] = `23.17925136224735`; + +exports[`超级复杂造型01: 曲线长度 16`] = `2.3453734515378883`; + +exports[`超级复杂造型01: 曲线长度 17`] = `36.73892632422056`; + +exports[`超级复杂造型01: 曲线长度 18`] = `34.11040843800589`; + +exports[`超级复杂造型01: 曲线长度 19`] = `9.894843040789354`; + +exports[`超级复杂造型01: 曲线长度 20`] = `2.2726434483396147`; + +exports[`超级复杂造型01: 曲线长度 21`] = `2.6864922423941437`; + +exports[`超级复杂造型01: 曲线长度 22`] = `15.558634753573351`; + +exports[`超级复杂造型01: 曲线长度 23`] = `1.5023362215224114`; + +exports[`超级复杂造型01: 曲线长度 24`] = `23.17925136224733`; + +exports[`超级复杂造型01: 曲线长度 25`] = `2.345373451535995`; + +exports[`超级复杂造型01: 曲线长度 26`] = `36.73892632421837`; + +exports[`超级复杂造型01: 曲线长度 27`] = `34.110408438008804`; + +exports[`超级复杂造型01: 曲线长度 28`] = `3.005160240470314`; + +exports[`超级复杂造型01: 曲线长度 29`] = `3.0051602404691264`; + +exports[`超级复杂造型01: 曲线长度 30`] = `2.686492242389917`; + +exports[`超级复杂造型01: 曲线长度 31`] = `15.558634753574319`; + +exports[`超级复杂造型01: 曲线长度 32`] = `1.5023362215216194`; + +exports[`超级复杂造型01: 曲线长度 33`] = `9.894843040786107`; + +exports[`超级复杂造型01: 曲线长度 34`] = `2.272644014939738`; + +exports[`超级复杂造型01: 曲线长度 35`] = `23.179252903170394`; + +exports[`超级复杂造型01: 曲线长度 36`] = `2.3453734515314206`; + +exports[`超级复杂造型01: 曲线长度 37`] = `36.73892632421504`; + +exports[`超级复杂造型01: 曲线长度 38`] = `34.11040843800676`; + +exports[`超级复杂造型01: 曲线长度 39`] = `3.0051602404685336`; + +exports[`超级复杂造型01: 曲线长度 40`] = `3.0051630894960395`; + +exports[`超级复杂造型01: 曲线长度 41`] = `2.6864922423866937`; + +exports[`超级复杂造型01: 曲线长度 42`] = `15.558634753573163`; + +exports[`超级复杂造型01: 曲线长度 43`] = `1.5023362215210545`; + +exports[`超级复杂造型01: 曲线长度 44`] = `9.894843040790184`; + +exports[`超级复杂造型01: 曲线长度 45`] = `2.27264424963326`; + +exports[`超级复杂造型01: 曲线长度 46`] = `23.179252903170124`; + +exports[`超级复杂造型01: 曲线长度 47`] = `2.345373451550585`; + +exports[`超级复杂造型01: 曲线长度 48`] = `36.738926324216564`; + +exports[`超级复杂造型01: 曲线长度 49`] = `34.11040843800687`; + +exports[`超级复杂造型01: 曲线长度 50`] = `3.005160240469785`; + +exports[`超级复杂造型01: 曲线长度 51`] = `3.005164269599573`; + +exports[`超级复杂造型01: 曲线长度 52`] = `2.686492242390355`; + +exports[`超级复杂造型01: 曲线长度 53`] = `15.558634753572672`; + +exports[`超级复杂造型01: 曲线长度 54`] = `1.5023362215214884`; + +exports[`超级复杂造型01: 曲线长度 55`] = `9.894843040792889`; + +exports[`超级复杂造型01: 曲线长度 56`] = `2.272643448340335`; + +exports[`超级复杂造型01: 曲线长度 57`] = `23.17925136224723`; + +exports[`超级复杂造型01: 曲线长度 58`] = `2.345373451548128`; + +exports[`超级复杂造型01: 曲线长度 59`] = `36.73892632422722`; + +exports[`超级复杂造型01: 曲线长度 60`] = `34.11040843800603`; + +exports[`超级复杂造型01: 曲线长度 61`] = `3.0051602404692153`; + +exports[`超级复杂造型01: 曲线长度 62`] = `3.0051602404670064`; + +exports[`超级复杂造型01: 曲线长度 63`] = `2.686492242390764`; + +exports[`超级复杂造型01: 曲线长度 64`] = `15.558634753570397`; + +exports[`超级复杂造型01: 曲线长度 65`] = `1.5023362215189802`; + +exports[`超级复杂造型01: 曲线长度 66`] = `9.894843040791566`; + +exports[`超级复杂造型01: 曲线长度 67`] = `2.2726440149400053`; + +exports[`超级复杂造型01: 曲线长度 68`] = `5230.469840585598`; + +exports[`超级复杂造型01: 曲线长度 69`] = `11906.411531839705`; + +exports[`超级复杂造型01: 曲线长度 70`] = `464.88809827474097`; + +exports[`超级复杂造型01: 曲线长度 71`] = `464.8880982747457`; + +exports[`超级复杂造型01: 曲线长度 72`] = `464.8880982747495`; + +exports[`超级复杂造型01: 曲线长度 73`] = `464.888098274753`; + +exports[`超级复杂造型01: 曲线长度 74`] = `464.88809827475325`; + +exports[`超级复杂造型01: 曲线长度 75`] = `464.8880982747512`; + +exports[`超级复杂造型01: 曲线长度 76`] = `9277.910642188759`; + +exports[`超级复杂造型01: 走刀数量 1`] = `67`; exports[`通孔造型测试: 曲线长度 1`] = `1872.616834159402`; @@ -214,12 +434,18 @@ exports[`造型的外框和内框厚度小于刀半径厚度: 曲线长度 1`] = exports[`造型的外框和内框厚度小于刀半径厚度: 走刀数量 1`] = `0`; -exports[`造型的外框和内框厚度等于刀直径: 曲线长度 1`] = `1459.4533999999999`; +exports[`造型的外框和内框厚度等于刀直径: 曲线长度 1`] = `1468.0153449019233`; + +exports[`造型的外框和内框厚度等于刀直径: 曲线长度 2`] = `10.71238898038469`; + +exports[`造型的外框和内框厚度等于刀直径: 曲线长度 3`] = `10.712388980384869`; + +exports[`造型的外框和内框厚度等于刀直径: 曲线长度 4`] = `10.71238898038469`; -exports[`造型的外框和内框厚度等于刀直径: 曲线长度 2`] = `3600`; +exports[`造型的外框和内框厚度等于刀直径: 曲线长度 5`] = `3600`; -exports[`造型的外框和内框厚度等于刀直径: 曲线长度 3`] = `1483.4533999999999`; +exports[`造型的外框和内框厚度等于刀直径: 曲线长度 6`] = `1483.4533999999999`; -exports[`造型的外框和内框厚度等于刀直径: 曲线长度 4`] = `1435.4533999999999`; +exports[`造型的外框和内框厚度等于刀直径: 曲线长度 7`] = `1435.4533999999999`; -exports[`造型的外框和内框厚度等于刀直径: 走刀数量 1`] = `1`; +exports[`造型的外框和内框厚度等于刀直径: 走刀数量 1`] = `4`; diff --git a/__test__/Polyline/PtInPolylineDir.test.ts b/__test__/Polyline/PtInPolylineDir.test.ts index 9d44e40d0..05025a550 100644 --- a/__test__/Polyline/PtInPolylineDir.test.ts +++ b/__test__/Polyline/PtInPolylineDir.test.ts @@ -15,13 +15,13 @@ test('2个大圆中间', () => let isR = GetPointAtCurveDir(pl, new Vector3(110.19, 17.4)); - expect(isR).toBeFalsy(); + expect(isR).toBe(-1); let p = new Vector3().fromArray([84.89024786541306, 11.031154321671167, 0]); isR = GetPointAtCurveDir(pl, p); - expect(isR).toBeTruthy(); + expect(isR).toBe(1); }); test('点在端点且端点平行', () => @@ -64,7 +64,7 @@ test('点在端点上且点在圆心上', () => let p = new Vector3(19.48, 8.1097); let isR = GetPointAtCurveDir(pl, p); - expect(isR).toBeFalsy(); + expect(isR).toBe(-1); }); @@ -95,7 +95,7 @@ test('存在精度误差,并且点在圆内', () => let isR = GetPointAtCurveDir(pl, p); - expect(isR).toBeFalsy(); + expect(isR).toBe(-1); } }); @@ -112,7 +112,7 @@ test('大于1凸度的圆', () => let isR = GetPointAtCurveDir(pl, pt); - expect(isR).toBeFalsy(); + expect(isR).toBe(-1); }); test('盲区计算', () => @@ -127,7 +127,7 @@ test('盲区计算', () => let isR = GetPointAtCurveDir(pl, pt); - expect(isR).toBeFalsy(); + expect(isR).toBe(-1); pl.Reverse(); isR = GetPointAtCurveDir(pl, pt); @@ -146,7 +146,7 @@ test('参数点在终点上', () => let pl = f.ReadObject() as Polyline; let pt = new Vector3().fromArray([24.40481807693597, 4.679455426066854, 0]); let isR = GetPointAtCurveDir(pl, pt); - expect(isR).toBeFalsy(); + expect(isR).toBe(-1); pt = new Vector3().fromArray([30.314368267468268, 10.71117601112483, 0]); isR = GetPointAtCurveDir(pl, pt); @@ -154,7 +154,7 @@ test('参数点在终点上', () => pl.Reverse(); isR = GetPointAtCurveDir(pl, pt); - expect(isR).toBeFalsy(); + expect(isR).toBe(-1); pt = new Vector3().fromArray([24.40481807693597, 4.679455426066854, 0]); isR = GetPointAtCurveDir(pl, pt); @@ -173,7 +173,7 @@ test('点在小角内', () => let pt = new Vector3().fromArray([-45.25245903106504, 20.057300217471017, 0]); let isR = GetPointAtCurveDir(pl, pt); - expect(isR).toBeFalsy(); + expect(isR).toBe(-1); pl.Reverse(); isR = GetPointAtCurveDir(pl, pt); @@ -195,7 +195,7 @@ test('首尾点相等', () => pl.Reverse(); isR = GetPointAtCurveDir(pl, pt); - expect(isR).toBeFalsy(); + expect(isR).toBe(-1); }); @@ -209,7 +209,7 @@ test('点在圆弧的弦中心上', () => let pt = new Vector3().fromArray([4.999999999999999, 2.5, 0]); let isR = GetPointAtCurveDir(pl, pt); - expect(isR).toBeFalsy(); + expect(isR).toBe(-1); pt = new Vector3().fromArray([5, 9.5, 0]); isR = GetPointAtCurveDir(pl, pt); @@ -233,11 +233,11 @@ test('圆弧过大导致直线小角错误', () => let pt = new Vector3().fromArray([-2246.7733894227954, -220.1844621837422, 0]); let isR = GetPointAtCurveDir(pl, pt); - expect(isR).toBeFalsy(); + expect(isR).toBe(-1); pt = new Vector3().fromArray([-2184.668414731696, -221.35723534211996, 0]); //[1,["Circle",1,1,4,false,7,-1,[1,0,0,0,0,1,0,0,0,0,1,0,-2184,-221.357,0,1],1,1]] isR = GetPointAtCurveDir(pl, pt); - expect(isR).toBeFalsy(); + expect(isR).toBe(-1); }); diff --git a/__test__/Polyline/__snapshots__/offset.test.ts.snap b/__test__/Polyline/__snapshots__/offset.test.ts.snap index 311f952fa..4f8d2757a 100644 --- a/__test__/Polyline/__snapshots__/offset.test.ts.snap +++ b/__test__/Polyline/__snapshots__/offset.test.ts.snap @@ -16,33 +16,101 @@ exports[`中间区域需要圆裁剪 1`] = `1`; exports[`中间区域需要圆裁剪 2`] = `"24.71130"`; -exports[`圆求交错误导致的线丢失 1`] = `4148.6552839918695`; +exports[`假圆弧交点选点直连 1`] = `1`; -exports[`圆求交错误导致的线丢失 2`] = `4425.280774659357`; +exports[`假圆弧交点选点直连 2`] = `"903.79892"`; -exports[`圆求交错误导致的线丢失 3`] = `4021.9003332433485`; +exports[`判断点在线上错误导致的偏移错误 1`] = `1`; -exports[`圆求交错误导致的线丢失 4`] = `4581.2242286506635`; +exports[`判断点在线上错误导致的偏移错误 2`] = `"119778.26631"`; -exports[`圆求交错误导致的线丢失 5`] = `3900.607906945287`; +exports[`双圆偏移导致求延伸点错误 1`] = `1`; -exports[`圆求交错误导致的线丢失 6`] = `4757.46853225238`; +exports[`双圆偏移导致求延伸点错误 2`] = `"787.87800"`; -exports[`圆求交错误导致的线丢失 7`] = `3783.7486621001212`; +exports[`双圆偏移导致求延伸点错误 3`] = `1`; -exports[`圆求交错误导致的线丢失 8`] = `4972.012479701851`; +exports[`双圆偏移导致求延伸点错误 4`] = `"168.83973"`; -exports[`圆求交错误导致的线丢失 9`] = `1148.663268759687`; +exports[`双圆可能只有一个交点的问题 1`] = `1`; -exports[`圆求交错误导致的线丢失 10`] = `5979.881810920418`; +exports[`双圆可能只有一个交点的问题 2`] = `"6744.69470"`; -exports[`圆求交错误导致的线丢失 11`] = `1049.9599133172633`; +exports[`圆弧全丢时需要扇形切割 1`] = `1`; -exports[`圆求交错误导致的线丢失 12`] = `6051.226641876329`; +exports[`圆弧全丢时需要扇形切割 2`] = `"4844.93527"`; -exports[`圆求交错误导致的线丢失 13`] = `722.4732418587954`; +exports[`圆弧全部丢失 1`] = `1`; -exports[`圆求交错误导致的线丢失 14`] = `6316.980887212943`; +exports[`圆弧全部丢失 2`] = `"1623.41712"`; + +exports[`圆弧如果连接就自交,需要补圆弧才能解决 1`] = `1`; + +exports[`圆弧如果连接就自交,需要补圆弧才能解决 2`] = `"948.21488"`; + +exports[`圆弧连接后逆向 1`] = `1`; + +exports[`圆弧连接后逆向 2`] = `"4159.59625"`; + +exports[`圆弧连接成圆 1`] = `7`; + +exports[`圆弧连接成圆 2`] = `"139.57806"`; + +exports[`圆弧连接成圆 3`] = `"359.72091"`; + +exports[`圆弧连接成圆 4`] = `"486.59311"`; + +exports[`圆弧连接成圆 5`] = `"359.72091"`; + +exports[`圆弧连接成圆 6`] = `"423.15701"`; + +exports[`圆弧连接成圆 7`] = `"423.15701"`; + +exports[`圆弧连接成圆 8`] = `"486.59311"`; + +exports[`圆弧选点实例 1`] = `1`; + +exports[`圆弧选点实例 2`] = `"1.33642"`; + +exports[`圆弧错误的直连(需要验证是否可以连接,避免反向连接) 1`] = `1`; + +exports[`圆弧错误的直连(需要验证是否可以连接,避免反向连接) 2`] = `"3880.28257"`; + +exports[`圆弧错误的直连(需要验证是否可以连接,避免反向连接) 3`] = `1`; + +exports[`圆弧错误的直连(需要验证是否可以连接,避免反向连接) 4`] = `"3791.62583"`; + +exports[`圆弧错误连接 1`] = `1`; + +exports[`圆弧错误连接 2`] = `"3624.05703"`; + +exports[`圆求交错误导致的线丢失 1`] = `4148.655275462344`; + +exports[`圆求交错误导致的线丢失 2`] = `4425.280774659386`; + +exports[`圆求交错误导致的线丢失 3`] = `4021.90031602838`; + +exports[`圆求交错误导致的线丢失 4`] = `4581.224228650713`; + +exports[`圆求交错误导致的线丢失 5`] = `3900.6078799293045`; + +exports[`圆求交错误导致的线丢失 6`] = `4757.468532252452`; + +exports[`圆求交错误导致的线丢失 7`] = `3783.7486269390533`; + +exports[`圆求交错误导致的线丢失 8`] = `4972.0124797019525`; + +exports[`圆求交错误导致的线丢失 9`] = `1148.6626298786346`; + +exports[`圆求交错误导致的线丢失 10`] = `5979.881805331884`; + +exports[`圆求交错误导致的线丢失 11`] = `1049.959063092095`; + +exports[`圆求交错误导致的线丢失 12`] = `6051.226636287797`; + +exports[`圆求交错误导致的线丢失 13`] = `722.4732418587961`; + +exports[`圆求交错误导致的线丢失 14`] = `6316.980880964775`; exports[`复杂圆盘选点 1`] = `1`; @@ -84,6 +152,18 @@ exports[`拱门偏移 3`] = `1`; exports[`拱门偏移 4`] = `"6.82743"`; +exports[`极限刀半径偏移 1`] = `2`; + +exports[`极限刀半径偏移 2`] = `"500.00000"`; + +exports[`极限刀半径偏移 3`] = `"250.00000"`; + +exports[`正确的裁剪多段线 1`] = `2`; + +exports[`正确的裁剪多段线 2`] = `"1.81330"`; + +exports[`正确的裁剪多段线 3`] = `"4.43077"`; + exports[`海豚圆选点导致的错误 1`] = `1`; exports[`海豚圆选点导致的错误 2`] = `"1591.19822"`; @@ -92,13 +172,49 @@ exports[`海豚圆选点导致的错误 3`] = `1`; exports[`海豚圆选点导致的错误 4`] = `"1827.63524"`; +exports[`点在多段线内 1`] = `1`; + +exports[`点在多段线内 2`] = `"1589.94630"`; + exports[`简单图形因为点在线内算法错误导致的丢失 1`] = `8.675189454805244`; exports[`简单图形因为点在线内算法错误导致的丢失 2`] = `8.252841733482935`; -exports[`简单图形因为点在线内算法错误导致的丢失 3`] = `6.802689012735881`; +exports[`简单图形因为点在线内算法错误导致的丢失 3`] = `7.1494048498542835`; + +exports[`简单图形因为点在线内算法错误导致的丢失 4`] = `6.693604273021889`; + +exports[`精度过高导致无法连接 1`] = `"6721.53910"`; + +exports[`精度过高导致的曲线丢失 1`] = `1`; + +exports[`精度过高导致的曲线丢失 2`] = `"86945.68009"`; + +exports[`精度过高导致的曲线丢失 3`] = `1`; + +exports[`精度过高导致的曲线丢失 4`] = `"97661.61008"`; + +exports[`精度过高导致直连失败 1`] = `1`; + +exports[`精度过高导致直连失败 2`] = `"32040.01360"`; + +exports[`精度过高导致直连失败 3`] = `1`; + +exports[`精度过高导致直连失败 4`] = `"32045.24858"`; + +exports[`精度过高导致连接失败 1`] = `1`; -exports[`简单图形因为点在线内算法错误导致的丢失 4`] = `6.045609380056393`; +exports[`精度过高导致连接失败 2`] = `"75154.17850"`; + +exports[`精度过高导致连接失败 3`] = `1`; + +exports[`精度过高导致连接失败 4`] = `"91209.36327"`; + +exports[`精度问题导致的连接错误 1`] = `2`; + +exports[`精度问题导致的连接错误 2`] = `"19.40228"`; + +exports[`精度问题导致的连接错误 3`] = `"19.40228"`; exports[`纯圆生成的多段线偏移 1`] = `1`; @@ -108,9 +224,9 @@ exports[`纯圆生成的多段线偏移 3`] = `1`; exports[`纯圆生成的多段线偏移 4`] = `"6328.57819"`; -exports[`补充bug测试 1`] = `7385.123391644449`; +exports[`补充bug测试 1`] = `7385.123391644346`; -exports[`补充bug测试 2`] = `7455.861403941378`; +exports[`补充bug测试 2`] = `7455.861403941371`; exports[`补圆弧测试 补圆弧测试1 1`] = `1`; @@ -200,12 +316,36 @@ exports[`补圆弧测试 补圆弧测试1 43`] = `1`; exports[`补圆弧测试 补圆弧测试1 44`] = `"192.58327"`; -exports[`闭合多段线判断精度和重复交点参数导致偏移丢失 1`] = `54789.24964851234`; +exports[`被补圆弧的裁剪圆所裁剪导致的曲线丢失(和CAD一样) 1`] = `1`; + +exports[`被补圆弧的裁剪圆所裁剪导致的曲线丢失(和CAD一样) 2`] = `"1771.95957"`; + +exports[`连续丢圆弧后无法连接 1`] = `1`; + +exports[`连续丢圆弧后无法连接 2`] = `"1310.80545"`; + +exports[`连续丢圆弧后无法连接 3`] = `7`; + +exports[`连续丢圆弧后无法连接 4`] = `"574.66475"`; + +exports[`连续丢圆弧后无法连接 5`] = `"1182.81794"`; + +exports[`连续丢圆弧后无法连接 6`] = `"574.66475"`; + +exports[`连续丢圆弧后无法连接 7`] = `"574.66475"`; + +exports[`连续丢圆弧后无法连接 8`] = `"574.66475"`; + +exports[`连续丢圆弧后无法连接 9`] = `"574.66475"`; + +exports[`连续丢圆弧后无法连接 10`] = `"574.66475"`; + +exports[`闭合多段线判断精度和重复交点参数导致偏移丢失 1`] = `54789.24964851236`; -exports[`闭合多段线判断精度和重复交点参数导致偏移丢失 2`] = `54907.281737806145`; +exports[`闭合多段线判断精度和重复交点参数导致偏移丢失 2`] = `54907.281737806166`; -exports[`闭合多段线判断精度和重复交点参数导致偏移丢失 3`] = `55497.50212266897`; +exports[`闭合多段线判断精度和重复交点参数导致偏移丢失 3`] = `55497.502122668986`; -exports[`闭合多段线判断精度和重复交点参数导致偏移丢失 4`] = `56678.24106604482`; +exports[`闭合多段线判断精度和重复交点参数导致偏移丢失 4`] = `56678.24106604484`; -exports[`闭合多段线判断精度和重复交点参数导致偏移丢失 5`] = `57859.374439605526`; +exports[`闭合多段线判断精度和重复交点参数导致偏移丢失 5`] = `57859.37443960543`; diff --git a/__test__/Polyline/__snapshots__/offsetbug.test.ts.snap b/__test__/Polyline/__snapshots__/offsetbug.test.ts.snap index ddd62ed38..b826bb366 100644 --- a/__test__/Polyline/__snapshots__/offsetbug.test.ts.snap +++ b/__test__/Polyline/__snapshots__/offsetbug.test.ts.snap @@ -1,25 +1,25 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`补充bug测试#IKWGF 1`] = `1.1376403544773552`; +exports[`补充bug测试#IKWGF 1`] = `0.44573953230750973`; -exports[`补充bug测试#IKWGF 2`] = `0.44573953236152686`; +exports[`补充bug测试#IKWGF 2`] = `10.732981364094256`; -exports[`补充bug测试#IKWGF 3`] = `10.732981364094256`; +exports[`补充bug测试#IKWGF 3`] = `1.137640354477355`; -exports[`补充bug测试#IKWGF 4`] = `12.78691181488093`; +exports[`补充bug测试#IKWGF 4`] = `12.786911814880934`; -exports[`补充bug测试#IKWGF 5`] = `0.6246933440840137`; +exports[`补充bug测试#IKWGF 5`] = `10.586693841137812`; -exports[`补充bug测试#IKWGF 6`] = `10.586693752451833`; +exports[`补充bug测试#IKWGF 6`] = `0.624693344084014`; -exports[`补充bug测试#IKWGF 7`] = `14.067113755971711`; +exports[`补充bug测试#IKWGF 7`] = `14.067113755971715`; -exports[`补充bug测试#IKWGF 8`] = `2.168984971098264`; +exports[`补充bug测试#IKWGF 8`] = `11.891017922899252`; -exports[`补充bug测试#IKWGF 9`] = `11.89101792289927`; +exports[`补充bug测试#IKWGF 9`] = `2.168984971098264`; -exports[`补充bug测试#IKWGF 10`] = `1.0803374679586235`; +exports[`补充bug测试#IKWGF 10`] = `0.39474593983901435`; -exports[`补充bug测试#IKWGF 11`] = `0.39474593983890793`; +exports[`补充bug测试#IKWGF 11`] = `10.69886845125427`; -exports[`补充bug测试#IKWGF 12`] = `10.69886845125427`; +exports[`补充bug测试#IKWGF 12`] = `1.0803374679586233`; diff --git a/__test__/Polyline/offset.test.ts b/__test__/Polyline/offset.test.ts index 3d6550cb1..eac918e34 100644 --- a/__test__/Polyline/offset.test.ts +++ b/__test__/Polyline/offset.test.ts @@ -3,6 +3,7 @@ import { Curve } from "../../src/DatabaseServices/Entity/Curve"; import { Polyline } from "../../src/DatabaseServices/Entity/Polyline"; import { LoadEntityFromFileData } from "../Utils/LoadEntity.util"; import "../Utils/jest.util"; +import { OffsetPolyline } from "../../src/GraphicsSystem/OffsetPolyline"; Factory(Polyline); @@ -124,11 +125,11 @@ describe("闭合多段线", () => { expect(cus[0].GetOffsetCurves(i).length).toBe(1); } - for (let i = 0.4; i <= 0.6; i += 0.02) + for (let i = 0.4; i <= 0.6; i += 0.5) { expect(cus[0].GetOffsetCurves(-i).length).toBe(1); } - for (let i = 1; i <= 2; i += 0.2) + for (let i = 1; i <= 2; i += 0.5) { expect(cus[0].GetOffsetCurves(-i).length).toBe(0); } @@ -136,11 +137,11 @@ describe("闭合多段线", () => data = [1, "Polyline", 1, 1, 0, false, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2, 5, [22.178278439318607, -1.9155229050126357], 0, [22.83746943877066, -1.800164480108526], 0, [23.79329638797614, -6.11786552651948], -0.871731137783436, [23.348342463346004, -6.282663276382493], -0.7430788314178012, [22.903388538715866, -6.267501883395095], 0, true] cus = loadFile(data); - for (let i = 0.01; i <= 0.33; i += 0.03) + for (let i = 0.01; i <= 0.33; i += 0.08) { expect(cus[0].GetOffsetCurves(i).length).toBe(1); } - for (let i = 0.34; i <= 1; i += 0.1) + for (let i = 0.5; i <= 1; i += 0.2) { expect(cus[0].GetOffsetCurves(i).length).toBe(0); } @@ -271,7 +272,7 @@ describe("闭合多段线", () => { expect(cus[0].GetOffsetCurves(i).length).toBe(1); } - for (let i = 360; i <= 460; i += 50) + for (let i = 370; i <= 460; i += 50) { expect(cus[0].GetOffsetCurves(i).length).toBe(0); } @@ -280,7 +281,7 @@ describe("闭合多段线", () => { expect(cus[0].GetOffsetCurves(-i).length).toBe(1); } - for (let i = 360; i <= 460; i += 50) + for (let i = 370; i <= 460; i += 50) { expect(cus[0].GetOffsetCurves(-i).length).toBe(0); } @@ -519,15 +520,15 @@ describe("补圆弧测试", () => expect(cus[0].GetOffsetCurves(1.88).length).toBe(2); expect(cus[0].GetOffsetCurves(2.12).length).toBe(2); expect(cus[0].GetOffsetCurves(3.2).length).toBe(1); - for (let i = 0.5; i <= 3.5; i += 0.5) + for (let i = 0.5; i <= 4.5; i += 0.5) { expect(cus[0].GetOffsetCurves(-i).length).toBe(1); } - for (let i = 3.3; i <= 5.3; i += 0.5) + for (let i = 5.0; i <= 7.0; i += 0.5) { expect(cus[0].GetOffsetCurves(i).length).toBe(0); } - for (let i = 2.33; i <= 3.2; i += 0.2) + for (let i = 2.33; i <= 3.2; i += 0.5) { expect(cus[0].GetOffsetCurves(i).length).toBe(1); } @@ -717,7 +718,7 @@ test('提前丢失所有的线段', () => let cus = pl.GetOffsetCurves(-7.155086190577401); - expect(cus.length).toBe(0); + expect(cus.length).toBe(1);//是1也可以接受 }); @@ -882,3 +883,209 @@ test('多段线因为合并问题造成的错误', () => testOffset(pl, 37.8831); }); + +test("正确的裁剪多段线", () => +{ + let pl = loadFile( + { "file": [1, "Polyline", 5, 2, 177, false, 1, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 2507.5760599251325, -1024.118430461783, 0, 1], 0, 0, 2, 9, [0.1144508670519997, 0.411344685796422], 0, [0.1144508670519997, 0.9104046242774757], 0, [-0.9104046242774757, 0.9104046242774757], 0, [-0.9104046242774757, 0.2714179492914752], 0, [1.2674125167280863, -1.6184971098265635], 0, [1.8106024388006858, -1.6184971098265635], 0, [1.8106024388006858, 0.33236994219655003], 0, [0.268018046083057, 0.33236994219655003], 0.10216571300036134, [0.11445086705202812, 0.411344685796422], 0, false], "basePt": { "x": 2506.665655300855, "y": -1025.7369275716096, "z": 0 } } + )[0]; + + testOffset(pl, -0.3792); +}); + +test("极限刀半径偏移", () => +{ + let pl = loadFile( + { "file": [1, "Polyline", 5, 2, 101, false, 1, 2, 0, [0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 340.1517196254039, 192.68310636731692, 0, 1], 0, 0, 2, 8, [-269.23076923076917, -473.9316239316238], 0, [-519.2307692307692, -473.9316239316238], 0, [-519.2307692307692, -533.9316239316238], 0, [40.76923076923081, -533.9316239316239], 0, [40.7692307692308, -473.9316239316239], 0, [-209.2307692307692, -473.9316239316239], 0, [-209.23076923076923, -223.9316239316239], 0, [-269.2307692307692, -223.9316239316239], 0, true], "basePt": { "x": -193.77990430621998, "y": 151.91387559808612, "z": 0 } } + )[0]; + + testOffset(pl, -30); +}); + +test('双圆偏移导致求延伸点错误', () => +{ + let pl = loadFile( + { "file": [1, "Polyline", 5, 2, 101, false, 1, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 218.6045526504426, -252.49648981851198, 0, 1], 0, 0, 2, 3, [76.66953810162238, -86.81133085285757], -2.219258954152199, [71.33090803386779, 64.97443486580221], -3.5679817627813364, [76.66953810162238, -86.81133085285757], 0, false], "basePt": { "x": 124.11616995057648, "y": -405.14474387199533, "z": 0 } } + )[0]; + + testOffset(pl, 69.3565); + + testOffset(pl, 120); +}); + + +test('圆弧选点实例', () => +{ + let pl = loadFile( + { "file": [1, "Polyline", 5, 2, 101, false, 1, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 16.19344795796399, 135.0766710390067, 0, 1], 0, 0, 2, 5, [-6.203966005665723, -0.056657223796033884], 0, [-1.8834846458923415, -0.923353563739375], -1.4125691360015384, [-1.9069913201133035, -1.5932937790368253], 0, [-6.189801699716714, -2.2096317280453257], -2.3881275241710798, [-6.203966005665723, -0.056657223796033884], 0, true], "basePt": { "x": 7.425742574257429, "y": 132.42574257425747, "z": 0 } } + )[0]; + + testOffset(pl, 1.3); +}); + +test("圆弧连接后逆向", () => +{ + let pl = loadFile( + { "file": [1, "Polyline", 5, 2, 101, false, 1, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 597.8005954347436, 479.37954280316484, 0, 1], 0, 0, 2, 5, [167.98627715254565, -111.94253427447359], -2.235590494415529, [92.52712628683605, 179.4136315681265], 0.6826133878306185, [385.1692190172362, 136.47681103047847], -1.5346483158911062, [287.433293813986, -109.45380861449172], -0.17172709011725532, [167.98627715254565, -111.94253427447353], 0, false], "basePt": { "x": 395.9330143540669, "y": 277.5119617224881, "z": 0 } } + )[0]; + testOffset(pl, -360); +}); + +test("圆弧如果连接就自交,需要补圆弧才能解决", () => +{ + let pl = loadFile( + { "file": [1, "Polyline", 5, 2, 125, false, 1, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -207.54414497633752, -1556.5810873225296, 0, 1], 0, 0, 2, 5, [4603.757758938077, 593.6664091318919], -2.219258954152197, [4598.419128870322, 745.4521748505518], 0, [4760.538514402408, 884.9500449898966], 0, [4923.050442679999, 533.4110843473188], 0, [4603.757758938077, 593.6664091318919], 0, false], "basePt": { "x": 4225.055693160251, "y": -1023.1700029752108, "z": 0 } } + )[0]; + testOffset(pl, 57); +}); + + +test("被补圆弧的裁剪圆所裁剪导致的曲线丢失(和CAD一样)", () => +{ + let pl = loadFile( + { "file": [1, "Polyline", 5, 2, 103, false, 1, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1398.251881176373, 1411.2423837601018, 0, 1], 0, 0, 2, 5, [263.25649229242754, -496.3780796281579], -1.6515296725917887, [257.53512452479345, 499.3704419621269], -0.02322114634871773, [286.4951078605276, 482.68977986242965], -0.06010857523756142, [371.6713326415636, 496.2236762890787], -1.1581445685688583, [263.25649229242765, -496.3780796281578], 0, false], "basePt": { "x": 836.3843000956963, "y": 849.3748026794251, "z": 0 } } + )[0]; + testOffset(pl, 380); +}); + +test("圆弧错误的直连(需要验证是否可以连接,避免反向连接)", () => +{ + let pl = loadFile( + { "file": [1, "Polyline", 5, 2, 134, false, 1, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 6112.5678224459125, -1065.4659496101615, 0, 1], 0, 0, 2, 5, [263.25649229242754, -496.3780796281579], -1.7903397005665043, [296.5845834873048, 443.7572521059671], -0.010180473605896625, [267.31623288370463, 509.71120429495124], -0.10304286423691834, [371.6713326415636, 496.2236762890787], -1.1581445685688583, [263.25649229242765, -496.3780796281578], 0, false], "basePt": { "x": 5550.560765550236, "y": -1633.9291866028718, "z": 0 } } + )[0]; + testOffset(pl, 50); + + pl = loadFile( + { "file": [1, "Polyline", 5, 2, 147, false, 1, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1026.772157834298, 2130.88375223014, 0, 1], 0, 0, 2, 5, [286.302290657027, 503.78496132581995], 0.021527095370394104, [276.9071934869128, 525.7583449951944], -0.1030428642369184, [381.2622932447721, 512.2708169893212], -1.1581445685688583, [272.84745289563557, -480.33093892791567], -1.6900591615435467, [286.302290657027, 503.78496132581995], 0, false], "basePt": { "x": 474.6875180335993, "y": 1584.8751730829545, "z": 0 } } + )[0]; + testOffset(pl, 80); +}); + +test('圆弧错误连接', () => +{ + let pl = loadFile( + { "file": [1, "Polyline", 5, 2, 102, false, 1, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 2259.1441880926873, 773.1891257570742, 0, 1], 0, 0, 2, 5, [328.0439324263227, 451.7232922284297], -0.10340615467215077, [276.9071934869128, 525.7583449951944], 0.32399567200291585, [381.2622932447721, 512.2708169893212], 0.07052734499851136, [272.84745289563557, -480.33093892791567], -1.827918042325391, [328.0439324263227, 451.7232922284297], 0, false], "basePt": { "x": 1706.7609521238574, "y": 222.18579043452291, "z": 0 } } + )[0]; + testOffset(pl, -30); +}); + + +test('点在多段线内', () => +{ + let pl = loadFile( + { "file": [1, "Polyline", 5, 2, 143, false, 1, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 4555.272636134648, 288.86379442442706, 0, 1], 0, 0, 2, 7, [89.09718873801867, 12.715775988192085], 0.4432102328398421, [-21.370271340732355, 87.4260344681347], -2.031453439397569, [106.2882126486112, 376.2403174588135], -1.9534916059560468, [246.17792837185547, 84.84004156037321], 0.41942707445850347, [141.47128192655254, 10.514196006194956], 0.09632223217375552, [107.13355592506404, 11.671944350249753], 0.050311885391361756, [89.09718873801866, 12.7157759881921], 0, false], "basePt": { "x": 4287.368421052632, "y": 299.37799043062205, "z": 0 } } + )[0]; + testOffset(pl, 74); +}); + + +test('假圆弧交点选点直连', () => +{ + let pl = loadFile( + { "file": [1, "Polyline", 5, 2, 106, false, 1, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 4338.779773072596, 1478.769255552619, 0, 1], 0, 0, 2, 7, [-99.76976288377993, -489.9448891601117], 0.14694571746848875, [186.7216973960727, -463.82648449773677], 0.07092929978041122, [336.91679787003386, -592.2410724670758], -0.27040679117512567, [378.6368180205662, -672.9968518192081], -0.9540136739352206, [148.3191914428038, -786.0629656864282], 0.05251695815112128, [-211.9687804728832, -786.4458908902668], 0.04640002721980451, [-99.76976288378003, -489.9448891601119], 0, false], "basePt": { "x": 4126.810992599712, "y": 626.2335877788942, "z": 0 } } + )[0]; + testOffset(pl, 100); +}); + +test('圆弧连接成圆', () => +{ + let pl = loadFile( + { "file": [1, "Polyline", 5, 2, 101, false, 1, 7, 0, [0.5000000000000001, -0.8660254037844386, 0, 0, 0.8660254037844386, 0.5000000000000001, 0, 0, 0, 0, 1, 0, 389.42494481406175, 210.82148232183062, 0, 1], 0, 0, 2, 27, [-83.07073993499657, 0.8269354921289374], 0.10184605973644185, [-76.64483473264329, -32.04685576560943], 0.6522765349049682, [54.0010291988235, 45.75305414616944], 0.23596051205532206, [73.41540415096487, 57.21107588341927], -0.5914519010332271, [8.952266758064908, -92.64332512534449], 0.2140380409986856, [76.95983331150204, -92.19158268498886], 0.21403804099868534, [142.04794821690678, -72.47431923862268], -0.10329070701704057, [103.99885971414966, -72.42116385978626], 0.516142220984897, [74.90606688149397, 59.851009334915865], 0.2359605120553218, [74.69031645599186, 82.39336211069161], -0.4600557076424082, [180.59244300270308, -11.240294254991033], 0.10184605973644298, [205.8490287494348, 10.761598521427063], 0.6522765349049668, [73.14939838796012, 85.00428062955271], 0.2359605120553207, [53.51927301031667, 96.08861166807836], -0.591451901033227, [215.5285598492564, 115.1890975825626], 1.0068882499140974, [50.48769221175576, 96.05959673544288], 0.23596051205532112, [31.073317259614363, 84.60157499819303], -0.5914519010332269, [95.53645465251428, 234.45597600695686], 1.0068882499140976, [29.58265452908519, 81.96164154669648], 0.23596051205532054, [29.798404954587458, 59.419288770920865], -0.5914519010332271, [-67.74774449145258, 190.1732038652006], 0.2140380409986849, [-101.36030733885552, 131.0510523601852], 0.21403804099868418, [-116.82871375389443, 64.82445964448134], -0.1032907070170408, [-97.75813559409578, 97.74935918929305], 0.5161422209848976, [31.339323022619247, 56.80837025205961], 0.235960512055321, [50.96944840026263, 45.72403921353395], -0.4600557076424087, [-83.07073993499662, 0.8269354921289764], 0, false], "basePt": { "x": 313.6696051434847, "y": 37.93179334118034, "z": 0 } } + )[0]; + testOffset(pl, -3); +}); + +test('连续丢圆弧后无法连接', () => +{ + let pl = loadFile( + { "file": [1, "Polyline", 5, 2, 106, false, 1, 3, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -567.4063340972411, 1456.4847944096769, 0, 1], 0, 0, 2, 39, [838.6942638940667, -206.2489487883961], 0, [864.8377861332657, -206.2489487883961], 0, [864.8377861332657, -158.95474961566856], 0, [818.9312808604154, -158.95474961566856], 0, [818.9312808604153, -169.03321364032257], 0.37053452142155574, [783.6164871832165, -184.70060270846358], 0, [774.5059826252042, -184.70060270846358], 0, [774.5059826252037, -186.47136549762922], -0.037316682914943736, [771.2243918351782, -178.8695991954375], -0.11426681014922678, [756.1998142491512, -182.02097661656495], 0.7138529441383806, [746.9265548351201, -207.29436915460144], -0.01478368893153686, [748.4493542266122, -208.60883489652468], 0, [712.4399703545349, -208.60883489652474], 0, [712.4399703545349, -259.197556251971], 0.7966805802386544, [701.9499401116049, -324.42266262477676], 0, [701.9499401116046, -343.04631759286684], 0.18977471500526005, [687.327969050377, -358.82138332977365], 0, [668.3845930549477, -358.82138332977365], 0, [668.3845930549477, -415.7518591960502], 0, [696.7831905997194, -415.7518591960502], 0, [696.7831905997194, -392.77830740129156], 0.4762396892690236, [741.127921345345, -382.22429882660674], 0, [783.3405548225938, -382.22429882660674], 0, [783.3405548225938, -367.50784216202834], 0.5198330309007874, [811.7657015613546, -314.22928813809364], -0.09411712475346413, [809.818481883436, -307.48283334573034], 0, [846.0534057939268, -307.4828333457304], 0.5026102634669043, [855.0371645891342, -295.39979201396176], -0.5977564466489893, [857.8002629949973, -292.63669360809854], 0.5026102634669082, [869.883304326766, -283.6529348128912], 0, [869.883304326766, -282.5719852262679], 0.9999999999999999, [869.883304326766, -253.63108028534668], 0, [869.883304326766, -252.55013069872342], 0.49929486045458626, [857.8956516709469, -243.53823491123893], -0.5905845302049125, [854.6227110175462, -240.26529425783775], 0.4992948604545915, [845.6108152300616, -228.27764160201855], 0, [823.1152528270367, -228.2776416020185], 0, [823.1152528270367, -224.1993683522838], 0.2092099078281357, [838.6942638940667, -206.2489487883961], 0, false], "basePt": { "x": 100.97825895770654, "y": 1040.7329352136267, "z": 0 } } + )[0]; + testOffset(pl, 60); + + pl = loadFile( + { "file": [1, "Polyline", 5, 2, 104, false, 1, 2, 0, [0.5000000000000001, -0.8660254037844386, 0, 0, 0.8660254037844386, 0.5000000000000001, 0, 0, 0, 0, 1, 0, -1590.0719079709852, 9426.592260199775, 0, 1], 0, 0, 2, 103, [8515.314746566539, -556.3658219788067], 0, [8035.022676761735, -462.557424921436], -0.6635872795072744, [7894.752635321667, -322.28738348139086], 0.19560765654894927, [7894.752635321669, -190.71947164322228], -0.29882437827791913, [7923.759733994661, -43.40484909687257], 0.9898281059505385, [7845.440567577609, 34.91431732016645], -1.442946642283402, [7802.551500253992, 131.88090431270757], -0.8093239052680682, [8015.132094814551, 64.75019024095491], 0.832461880093909, [7977.8372536635725, 290.3839792043509], -0.3475847145489082, [8210.930010857164, 226.98274924769248], 0.7541136729398036, [8162.446717360899, 452.6165382110903], -0.820623571745973, [8413.608825238658, 252.6022904989277], -0.18075640268239695, [8442.84524728326, 186.35620817566087], -0.7264755735432326, [8553.91213051174, 23.99656238982425], -0.370975277556559, [8519.224956353799, -106.36973770577242], -0.3063671600538868, [8483.182351259278, -216.48611302460085], -0.1913456876589615, [8641.722006251419, -306.58984251603397], -0.09504975276320408, [8776.379586079263, -218.61724183962542], 0, [8617.474006116845, 244.23209037622564], -0.6635872795072751, [8668.816404673787, 435.844530373246], 0.19560765654894927, [8782.75755864851, 501.6284862923294], -0.2988243782779201, [8924.83931345906, 550.1649132246093], 0.9898281059505389, [8953.506117970912, 657.1508841535187], -1.4429466422834343, [9016.03711196292, 742.7771994966624], -0.8093239052680679, [9064.190505482868, 525.1116472197427], 0.8324618800939108, [9240.947678101818, 670.2268215682916], -0.3475847145489083, [9302.58698092497, 436.66195742215405], 0.7541136729398015, [9473.749927371273, 591.4666157307556], -0.8206235717459719, [9426.11356167259, 273.9467259844887], -0.18075640268239504, [9383.360982501748, 215.50420061646764], -0.7264755735432271, [9298.28684631601, 38.137635328523174], -0.3709752775565557, [9168.042731556867, 2.99445928699879], -0.3063671600538841, [9054.65785061084, -20.849916741992274], -0.1913456876589577, [9055.895559391609, -203.20115021811762], -0.09504975276320021, [9199.41085632828, -275.8317348229548], 0, [9520.797346170662, 93.2092003355292], -0.6635872795072741, [9712.409786167671, 144.5515988925008], 0.19560765654894882, [9826.350940142398, 78.76764297341651], -0.29882437827791875, [9939.425596279956, -20.01055264065235], 0.9898281059505387, [10046.41156720886, 8.656251871216227], -1.442946642283423, [10151.831628524482, -2.684019778182119], -0.8093239052680679, [9987.404427483874, -153.21885798334915], 0.8324618800939075, [10201.456441253802, -233.73747259819174], -0.3475847145489082, [10030.00298688336, -403.9011067876736], 0.7541136729398019, [10249.649226825934, -474.7302374424671], -0.8206235717459756, [9950.850753249484, -592.2358794765751], -0.1807564026823984, [9878.86175203404, -584.432322521332], -0.7264755735432308, [9682.720732619824, -599.4392420234362], -0.37097527755655973, [9587.163792018622, -504.21611796936577], -0.30636716005388875, [9509.821516167114, -417.94411867952476], -0.1913456876589582, [9352.519569955744, -510.1916226642252], -0.09504975276320335, [9361.377287064573, -670.7948079454719], 0, [9841.669356869374, -764.6032050028434], -0.6635872795072755, [9981.939398309443, -904.8732464428875], 0.19560765654894904, [9981.939398309441, -1036.4411582810562], -0.29882437827791863, [9952.932299636452, -1183.7557808274069], 0.9898281059505445, [10031.251466053503, -1262.074947244445], -1.4429466422834027, [10074.140533377118, -1359.0415342369859], -0.8093239052680687, [9861.559938816561, -1291.9108201652343], 0.8324618800939101, [9898.85477996754, -1517.5446091286303], -0.34758471454890855, [9665.762022773946, -1454.1433791719737], 0.7541136729397993, [9714.245316270215, -1679.777168135367], -0.8206235717459733, [9463.08320839245, -1479.7629204232062], -0.180756402682396, [9433.846786347849, -1413.5168380999412], -0.7264755735432326, [9322.77990311937, -1251.157192314104], -0.3709752775565557, [9357.467077277313, -1120.790892218508], -0.306367160053888, [9393.509682371832, -1010.674516899675], -0.19134568765895976, [9234.97002737969, -920.5707874082475], -0.09504975276319776, [9100.312447551856, -1008.5433880846549], 0, [9259.218027514278, -1471.3927203005096], -0.6635872795072755, [9207.875628957336, -1663.0051602975254], 0.19560765654894927, [9093.934474982607, -1728.7891162166106], -0.2988243782779215, [8951.85272017206, -1777.3255431488906], 0.9898281059505389, [8923.185915660208, -1884.3115140778018], -1.4429466422834172, [8860.654921668203, -1969.9378294209428], -0.8093239052680679, [8812.501528148252, -1752.2722771440249], 0.8324618800939076, [8635.744355529303, -1897.3874514925728], -0.34758471454890855, [8574.105052706149, -1663.8225873464353], 0.7541136729398008, [8402.942106259847, -1818.6272456550387], -0.8206235717459722, [8450.578471958532, -1501.10735590877], -0.18075640268239798, [8493.331051129375, -1442.6648305407462], -0.7264755735432308, [8578.405187315111, -1265.2982652528062], -0.37097527755656073, [8708.649302074255, -1230.1550892112791], -0.30636716005388875, [8822.034183020285, -1206.310713182289], -0.19134568765895688, [8820.796474239512, -1023.9594797061645], -0.09504975276320358, [8677.281177302835, -951.3288951013228], 0, [8355.894687460453, -1320.3698302598068], -0.6635872795072745, [8164.282247463445, -1371.7122288167784], 0.19560765654894882, [8050.341093488718, -1305.9282728976941], -0.29882437827791863, [7937.266437351161, -1207.1500772836253], 0.9898281059505387, [7830.280466422258, -1235.8168817954938], -1.4429466422834234, [7724.860405106635, -1224.4766101460964], -0.8093239052680679, [7889.287606147243, -1073.9417719409294], 0.8324618800939076, [7675.235592377316, -993.4231573260831], -0.3475847145489082, [7846.689046747755, -823.259523136604], 0.7541136729398019, [7627.042806805183, -752.4303924818114], -0.8206235717459756, [7925.841280381632, -634.9247504477025], -0.18075640268239826, [7997.8302815970765, -642.7283074029456], -0.7264755735432308, [8193.971301011292, -627.7213879008414], -0.3709752775565595, [8289.528241612494, -722.9445119549118], -0.306367160053889, [8366.870517464004, -809.2165112447528], -0.19134568765895826, [8524.172463675372, -716.9690072600524], -0.09504975276320324, [8515.314746566539, -556.3658219788058], 0, false], "basePt": { "x": 1033.8277511961717, "y": -2.918660287080783, "z": 0 } } + )[0]; + testOffset(pl, 250); +}); + +test('圆弧全部丢失', () => +{ + let pl = loadFile( + { "file": [1, "Polyline", 5, 2, 101, false, 1, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 632.4260201651778, 306.1636234424211, 0, 1], 0, 0, 2, 29, [36.37069437158061, 19.439752751377], -0.7123995667293839, [-16.602777874049934, -37.750220700952696], -0.38902776698602376, [-67.29233229320016, -60.930589109776975], -0.39575307788764214, [-120.13720350865697, -80.76110079474938], -0.2510519239370229, [-155.81796518401097, -96.40117872622181], -0.4401592563880412, [-213.05269426281666, -116.98744415455144], -0.5725845968148544, [-283.11590130257537, -104.70063313648416], -0.37443535464444794, [-318.38517803070135, -63.58302116645518], -0.270072747699035, [-342.68534646202534, -29.913752794033144], -0.30204918439048223, [-378.59967258530014, -1.7177518465878165], -0.4916711967603866, [-440.19726209747387, 20.006877568470372], -0.7200163954969004, [-440.5823529333029, 98.2276374813755], -0.9206339273151827, [-363.91719410161386, 127.87677205484283], -0.4244951536070515, [-304.917297798067, 134.15520223171188], -0.1914266417129986, [-280.2097502798788, 151.97195994686012], -0.16415950284336714, [-285.094390630813, 177.88469146695115], -0.45083830308595857, [-323.3160481272025, 226.4569828790743], -0.38920226900367944, [-334.0176218595334, 281.1770985710739], -0.5628842050977027, [-338.56134219477826, 351.5427658946892], -0.8667997782041291, [-261.6544519066483, 378.9492862585389], -0.48177976270290346, [-208.69938247126265, 342.1209188342277], -0.34120655338524586, [-167.1839625076027, 313.5162829666949], -0.3628510032688694, [-133.35254383027495, 272.8592107208947], -0.3623671695182369, [-94.22856638310259, 237.34650697847155], -0.5332799952050609, [-47.27862948352413, 187.47870916997203], -0.33367677879321517, [-30.595276514824945, 140.8444233640655], -0.09453880585667056, [-20.169534645436215, 129.43297905255963], -0.5685380908499404, [43.85863433804843, 99.03848179090187], -0.7781000001051073, [36.37069437158061, 19.43975275137609], 0, false], "basePt": { "x": 163.87559808612437, "y": 174.64114832535893, "z": 0 } } + )[0]; + testOffset(pl, 42); +}); + +test('判断点在线上错误导致的偏移错误', () => +{ + let pl = loadFile( + { "file": [1, "Polyline", 5, 2, 101, false, 1, 3, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -100734.86243186146, 44383.331635333445, 0, 1], 0, 0, 2, 39, [127277.81151293858, -36620.707373191544], 0, [130815.96109517067, -36620.707373191544], 0, [130815.96109517064, -35554.466705877174], 0.6887172212245157, [130291.21448189336, -31533.945897231803], -0.36193373148997876, [128773.59498831566, -29570.704146790635], 1.1796860042294097, [126333.40360075582, -30180.7519936806], -1.287135792508298, [124682.68589740657, -30180.751993680595], 0.779185042024048, [122637.23135195201, -29391.278309470064], 0.010799107353114023, [121201.82465338742, -31508.50318985285], -0.4776149778954755, [119335.79594525344, -31508.503189852843], 0.700515994329636, [116967.37489262187, -32549.173046312168], -0.9278840414420589, [114850.15001223912, -32549.173046312157], 1.4480326048631014, [112930.29355291484, -33751.32615636614], -1.029709203909742, [111764.02561032523, -34917.59409894375], 0.20000000000000107, [108749.67154333959, -33661.61323769973], -0.02277643035683432, [108838.49552612088, -31770.760827730846], 0.0001885101725321654, [106201.82465338672, -32333.86204152787], 2.006103958007126, [103941.05910314823, -32333.862041527485], 1.3816050810686566, [103941.05910314822, -33625.728070235615], -0.9878106970714999, [105096.05769331472, -36695.970088982445], 0, [105096.05769331472, -35189.64237915029], 0, [102417.0482599521, -35189.64237915029], 0, [102417.0482599521, -35889.67138518257], 1.0912246439015139, [102417.0482599521, -38825.899587824555], 0, [102417.0482599521, -41968.68279764475], 0, [105096.05769331472, -41968.68279764475], 0, [105096.05769331472, -40160.607321239266], 0.4212054214672999, [107282.06546869678, -39671.70329158335], 0, [107282.06546869678, -43462.81111910043], 0, [112473.92446810291, -43462.81111910043], 0, [112473.92446810291, -41805.547281515814], 0.1318356548905449, [113770.25347482559, -40928.81616704816], 0, [113770.25347482559, -44343.85795112292], 0, [119637.25821281743, -44343.85795112292], 0, [119637.25821281743, -41945.442740045866], 0, [124876.50952109811, -41945.442740045866], 0, [124876.50952109811, -38869.61336018733], 0, [127277.81151293858, -38869.61336018733], 0, [127277.81151293858, -36620.707373191544], 0, false], "basePt": { "x": 80.14354066985356, "y": 39.4736842105267, "z": 0 } } + )[0]; + testOffset(pl, 200); +}); + +test('精度过高导致无法连接', () => +{ + let pl = loadFile( + { "file": [1, "Polyline", 5, 2, 3986, false, 1, 1, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 6579.761024280382, -284.69386708033016, 0, 1], 0, 0, 2, 151, [26186.559895161856, 2340.8637086870967], 0, [26148.65538728819, 2360.408630292287], -1.3088618180444112, [26104.282532746754, 2363.9206686770012], -0.9123557287923755, [26123.961538895655, 2405.432722292411], -1.199317806271941, [26152.143230784444, 2369.8613078440985], 0, [26182.558878903546, 2354.177910501486], 0.2536687013302224, [26181.43883467805, 2390.150848623748], -3.0648492881772293, [26211.68095564566, 2390.150848623748], 0.33753088116466423, [26217.297836094946, 2344.7396718304008], 0, [26243.323590091964, 2370.7654258274824], -0.725559559863707, [26258.596943624292, 2402.3201933541477], -0.9663623936288359, [26290.610605573293, 2384.0609588973457], -1.2305179800917057, [26259.40903826917, 2365.91015672961], -0.09254370864724822, [26252.6417207249, 2365.9414208366916], 0, [26216.559895161856, 2329.8595952735586], 0, [26216.559895161856, 2278.967684202135], -0.020862027430925353, [26225.965463599274, 2276.905385992105], 0, [26235.503078112375, 2300.623249652883], -0.2495726219465555, [26228.37897043196, 2314.748894863499], -0.7668590421252343, [26238.59738628403, 2322.267186432391], -0.8431806725804747, [26255.879634904904, 2314.652667155984], -0.6994782626735623, [26259.160739936935, 2304.9561953985917], -0.24703433544859793, [26245.34549656838, 2297.5437996320193], 0, [26235.811644062163, 2273.835291221057], -0.15459540270989447, [26291.15753053891, 2231.43698383026], 0, [26343.625036429334, 2261.729112479804], 0, [26341.599181117566, 2304.327840018944], -1.3088618180444112, [26322.45426830708, 2344.5118784826163], -0.9123557287923755, [26368.244264375735, 2348.2253860441388], -1.199317806271941, [26351.529361759352, 2306.0336177226673], 0, [26353.154965302554, 2271.85119510765], 0.2536687013302224, [26383.74842145245, 2290.807650921421], -3.0648492881772293, [26398.869481936254, 2264.6172058991515], 0.33753088116466423, [26362.35068944211, 2237.047256343374], 0, [26397.902530554737, 2227.5211692278544], -0.725559559863707, [26432.866437609508, 2230.07144083121], -0.9663623936288359, [26433.06030769076, 2193.217179086808], -1.2305179800917057, [26401.74046826237, 2211.163127926199], -0.09254370864724822, [26398.383885001193, 2217.039428888558], 0, [26349.09519466708, 2230.246293659503], 0, [26305.021506832094, 2204.8003381237895], -0.02086202743092287, [26307.938288410736, 2195.623727814943], 0, [26333.24736812102, 2199.222843185479], -0.2495726219465555, [26341.918481878045, 2212.455324021329], -0.7668590421252343, [26353.538721295798, 2207.3650620914477], -0.8431806725804747, [26355.585478475263, 2188.5909361130443], -0.6994782626735623, [26348.828640122298, 2180.9011799241252], -0.24703433544859793, [26335.50169540127, 2189.1593337574686], 0, [26310.202598578424, 2185.5616380183064], -0.15459540270989144, [26301.15753053891, 2116.431540639078], 0, [26353.625036429334, 2086.1394119895313], 0, [26389.503688991234, 2109.193217923482], -1.3088618180444112, [26414.73163072218, 2145.865218002439], -0.9123557287923755, [26440.842620641935, 2108.0666719485525], -1.199317806271941, [26395.94602613676, 2101.4463180753937], 0, [26367.15598156086, 2082.947292802991], 0.2536687013302224, [26398.869481936254, 2065.9308104944976], -3.0648492881772293, [26383.74842145245, 2039.7403654722284], 0.33753088116466423, [26341.612748509022, 2057.5815927097983], 0, [26351.138835624628, 2022.0297515972006], -0.725559559863707, [26370.82938914707, 1993.025255673887], -0.9663623936288359, [26339.009597279324, 1974.4302283862867], -1.2305179800917057, [26338.89132515506, 2010.5269793934133], -0.09254370864724822, [26342.302059438156, 2016.372016248691], 0, [26329.09519466708, 2065.6607065827693], 0, [26285.021506832094, 2091.106662118481], -0.02086202743091419, [26278.532719973326, 2083.9923500196655], 0, [26294.304185170502, 2063.8736017294214], -0.24957262194655538, [26310.099406607947, 2062.9804373546544], -0.7668590421252341, [26311.50123017363, 2050.371883855883], -0.8431806725804747, [26296.26573873222, 2039.2122771538843], -0.6994782626735623, [26286.22779534722, 2041.2189927223576], -0.24703433544859793, [26286.71609399474, 2056.889542322273], 0, [26270.950849678124, 2077.0003549940766], -0.15459540270990305, [26206.559895161856, 2050.2685650056414], 0, [26206.559895161856, 1989.6843077065525], 0, [26244.464403035523, 1970.1393861013623], -1.3088618180444112, [26288.837257576957, 1966.6273477166478], -0.9123557287923755, [26269.158251428056, 1925.1152941012383], -1.199317806271941, [26240.976559539264, 1960.6867085495508], 0, [26210.56091142016, 1976.370105892163], 0.2536687013302224, [26211.68095564566, 1940.3971677699012], -3.0648492881772293, [26181.43883467805, 1940.3971677699012], 0.33753088116466423, [26175.821954228766, 1985.8083445632487], 0, [26149.796200231747, 1959.7825905661668], -0.725559559863707, [26134.52284669942, 1928.2278230395013], -0.9663623936288359, [26102.50918475042, 1946.4870574963034], -1.2305179800917057, [26133.710752054543, 1964.637859664039], -0.09254370864724822, [26140.478069598816, 1964.6065955569577], 0, [26176.559895161856, 2000.6884211200909], 0, [26176.559895161856, 2051.5803321915146], -0.02086202743092108, [26167.15432672444, 2053.6426304015445], 0, [26157.61671221134, 2029.9247667407633], -0.2495726219465555, [26164.74081989176, 2015.7991215301495], -0.7668590421252343, [26154.522404039686, 2008.2808299612575], -0.8431806725804747, [26137.240155418807, 2015.8953492376643], -0.6994782626735623, [26133.959050386777, 2025.5918209950569], -0.24703433544859793, [26147.77429375533, 2033.0042167616293], 0, [26157.30814626155, 2056.7127251725924], -0.15459540270989622, [26101.962259784803, 2099.11103256339], 0, [26049.494753894378, 2068.818903913848], 0, [26051.520609206145, 2026.2201763747062], -1.3088618180444112, [26070.665522016632, 1986.0361379110332], -0.9123557287923755, [26024.875525947973, 1982.3226303495103], -1.199317806271941, [26041.590428564363, 2024.5143986709818], 0, [26039.964825021158, 2058.696821286], 0.2536687013302224, [26009.371368871263, 2039.7403654722282], -3.0648492881772293, [25994.250308387458, 2065.9308104944976], 0.33753088116466423, [26030.7691008816, 2093.500760050275], 0, [25995.217259768975, 2103.0268471657937], -0.725559559863707, [25960.253352714204, 2100.476575562439], -0.9663623936288359, [25960.05948263295, 2137.330837306841], -1.2305179800917057, [25991.379322061337, 2119.3848884674503], -0.09254370864724822, [25994.735905322515, 2113.5085875050913], 0, [26044.02459565663, 2100.301722734147], 0, [26088.098283491618, 2125.7476782698604], -0.020862027430917966, [26085.18150191298, 2134.924288578707], 0, [26059.872422202694, 2131.3251732081694], -0.2495726219465555, [26051.201308445667, 2118.0926923723205], -0.7668590421252343, [26039.581069027914, 2123.1829543022013], -0.8431806725804747, [26037.53431184845, 2141.9570802806047], -0.6994782626735623, [26044.291150201414, 2149.646836469524], -0.24703433544859793, [26057.618094922444, 2141.388682636181], 0, [26082.917191745288, 2144.986378375343], -0.15459540270989405, [26091.962259784803, 2214.116475754572], 0, [26039.494753894378, 2244.4086044041187], 0, [26003.616101332478, 2221.35479847017], -1.3088618180444112, [25978.38815960153, 2184.68279839121], -0.9123557287923755, [25952.277169681776, 2222.4813444450965], -1.199317806271941, [25997.17376418695, 2229.1016983182553], 0, [26025.963808762852, 2247.6007235906627], 0.2536687013302224, [25994.250308387458, 2264.6172058991515], -3.0648492881772293, [26009.371368871263, 2290.8076509214206], 0.33753088116466423, [26051.50704181469, 2272.9664236838507], 0, [26041.980954699084, 2308.518264796453], -0.725559559863707, [26022.29040117664, 2337.5227607197626], -0.9663623936288359, [26054.110193044387, 2356.117788007363], -1.2305179800917057, [26054.228465168653, 2320.021037000236], -0.09254370864724822, [26050.817730885556, 2314.1760001449584], 0, [26064.02459565663, 2264.8873098108807], 0, [26108.098283491618, 2239.441354275171], -0.02086202743092352, [26114.587070350393, 2246.555666373988], 0, [26098.815605153213, 2266.6744146642295], -0.2495726219465555, [26083.020383715764, 2267.567579038996], -0.7668590421252343, [26081.61856015008, 2280.176132537769], -0.8431806725804747, [26096.85405159149, 2291.3357392397647], -0.6994782626735623, [26106.891994976486, 2289.3290236712915], -0.24703433544859793, [26106.403696328973, 2273.6584740713774], 0, [26122.16894064559, 2253.547661399576], -0.1545954027098919, [26186.559895161856, 2280.279451388008], 0, [26186.559895161856, 2340.8637086870967], 0, false], "basePt": { "x": 32522.109900548017, "y": 1609.359529229296, "z": 0 } } + )[0] as Polyline; + + let u = new OffsetPolyline(pl, 2, true); + u.Do(); + + expect(u._RetCurves[0].Length).toMatchNumberSnapshot(); +}); + +test('精度过高导致的曲线丢失', () => +{ + let pl = loadFile( + { "file": [1, "Polyline", 5, 2, 251, false, 1, 2, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 0, 0, 2, 13, [41568.41939449503, -16055.957031544558], 0, [41568.41939449503, -19085.900092302996], 0, [30759.326124901945, -19085.900092302996], -0.5620803766633276, [32250.53989507628, -17057.09381683477], 0, [32250.53989507628, -16357.06481080249], 0, [34929.549328438894, -16357.06481080249], 0, [34929.549328438894, -17863.39252063465], 0.987810697071495, [33774.55073827239, -14793.15050188782], -1.3816050810686162, [33774.55073827241, -13501.28447317968], -2.006103958007124, [36035.31628850903, -13501.284473179749], -0.0001885101725322209, [38671.98716124392, -12938.183259384707], 0.02277643035683432, [38583.16317846376, -14829.035669351935], -0.19748258058151022, [41568.41939449503, -16055.95703154455], 0, false], "basePt": { "x": 30648.49760765549, "y": -19085.900092302996, "z": 0 } } + )[0]; + testOffset(pl, -6353.8678); + testOffset(pl, -7108.8942); +}); + + +test('双圆可能只有一个交点的问题', () => +{ + let pl = loadFile( + { "file": [1, "Polyline", 5, 2, 636, false, 1, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 8816.790579978495, 1650.6512717161677, 0, 1], 0, 0, 2, 100, [-37.63997927032032, -122.31163856112178], -0.5850546209475238, [-84.92238785528671, 95.73449225818709], 0.00048018346906500295, [-85.27707472776136, 95.88824662159877], -0.10038125296941941, [-100.93665631505141, 106.79052252639573], -0.09978689253876652, [-131.76667746262092, 104.80702667339267], -0.12073301752491941, [-151.67431650500077, 73.37209505357924], -0.5147180077889115, [-232.0223308644795, 5.840987907604884], -0.4421725056265134, [-343.00499218797165, 38.35573246512353], -0.14690306216640125, [-364.26735878587374, 68.74797211310536], -0.0789057495185578, [-388.5254434655121, 72.31955396748418], -0.21282420582827116, [-433.18722338719715, 44.69096592404263], -0.06917535096525852, [-449.2439796725272, 30.35284996317626], -0.013050188065150235, [-448.05241473562984, 26.45089280427763], -0.34287563284334255, [-405.3000739317947, -40.144263097799424], -0.20891260124539257, [-381.7347890041258, -86.08606068332617], -0.2246373308823597, [-335.6246400076669, -134.5096752147314], -0.21813830679087096, [-266.9707266593898, -171.66583367022992], -0.20814567305857132, [-196.83037314615297, -206.35838746065957], -0.0488609763647568, [-183.43081949963988, -213.6216104956162], -0.5893114558987727, [-103.70193128809301, -265.8769545830993], 0.1365773165792166, [-79.95072251724413, -384.84437230537276], -0.5885213600554807, [-302.4576921365059, -361.220067129458], -0.06557799694475708, [-317.30556800997874, -369.17085995623484], -0.11621539070929156, [-325.0401583401413, -404.18065455827946], -0.12073301752494925, [-301.29556056580026, -432.8278724811278], -0.5147180077888068, [-261.89856296335944, -530.1116348661351], -0.44217250851076284, [-327.11745182745744, -625.6148095821012], -0.1469030525145038, [-362.59262098629074, -636.4448023523848], -0.07890575249105626, [-373.4855578748615, -658.4119332516439], -0.21282420513501799, [-361.01045814439436, -709.4255131431923], -0.06917535209620826, [-352.33590991267806, -729.1271175046942], -0.013050187963299782, [-348.25671434700826, -729.1996429900106], -0.34287562971868696, [-271.70975785893273, -709.1187856953593], -0.20891260202956674, [-220.73443821197503, -700.9036640077483], -0.31675246275620333, [-134.11031143157686, -676.4439632892754], -0.16230999968995205, [-85.91240781566471, -665.3936829062455], -0.12553096852905601, [-65.93014936543435, -632.3191768509196], -0.29664259727671044, [-38.161618560529064, -551.7160280205677], -0.5893113859543132, [36.17374838803935, -492.0371475290025], 0.13657730967860005, [156.6580059392573, -506.2113564430807], -0.573366330822081, [71.19636084103496, -709.8930956755739], -0.03690801267675709, [67.08632481074491, -716.7947085866487], -0.0403664415590649, [68.40492915087238, -727.1058474058361], -0.11621539027255794, [99.31110245603931, -745.2805014019764], -0.12073301752492402, [133.89370997215167, -731.5505241416072], -0.5147180082028758, [238.5904079584172, -724.1440887681127], -0.4421725039650299, [309.26557962310653, -815.6830412453354], -0.14690306099053752, [308.60308521759185, -852.768585009891], -0.07890574997172202, [326.1289649479008, -869.916599931916], -0.21282420582831063, [378.5007804971855, -873.8161382532904], -0.06917535096523136, [399.9187023140022, -871.6542833178032], -0.01305018806511863, [401.24821890322517, -867.7971493678833], -0.34287563390009135, [405.80449931746523, -788.7913408909262], -0.20891259829029268, [413.7436943971827, -737.7723193445075], -0.31675246318302686, [417.24946371877616, -647.82941579443], -0.16231000026306786, [421.6339936759038, -598.5757610995396], -0.12553097358493912, [396.35312614415346, -569.3509183300448], -0.29664257811819367, [328.27592627148056, -518.0337346310055], -0.5893113946164944, [294.48882837820696, -428.8948110258959], 0.1365773096786672, [345.200985267305, -318.6875442070351], -0.5760384593638737, [512.3147161695078, -463.91803280390724], -0.027762450863063955, [517.4394566611734, -468.911824478552], -0.041768197273778056, [528.0124297776388, -470.88135964102474], -0.11621539027254314, [554.8480856744687, -447.10411907709465], -0.12073301752493472, [552.4767147646883, -409.971308542578], -0.5147180082028519, [577.7858350729049, -308.1101172900079], -0.4421725037232871, [686.6843813901379, -269.18112667103946], -0.14690306179977608, [721.7501075357419, -281.27125954479726], -0.07890574972248751, [743.4746334847587, -269.9021855004115], -0.21282420621694662, [763.3670959161645, -221.29865259730752], -0.06917535033121872, [767.9295515459406, -200.26094870913468], -0.013050189132785087, [764.6720421240976, -197.8045831504546], -0.34287562914615266, [690.9410217478106, -169.0571658545639], -0.20891260217326688, [644.872394450502, -145.7407977893127], -0.3167524628946992, [560.4149523821089, -114.61272710126653], -0.16230999832660697, [514.9268376990387, -95.22257497271181], -0.12553097444531064, [479.3201426312775, -110.2351358549983], -0.2966425778523087, [409.4775890118797, -159.1225185178718], -0.5893113063750319, [314.26065493198496, -163.7105280567915], 0.13657731819301375, [225.11822645442106, -81.42446978963335], -0.5521520302060734, [406.60433937507884, 36.81315291034779], -0.047088274465754566, [418.17451838908585, 40.41883860776523], -0.04932881457566483, [423.2591444006404, 49.86141664669075], -0.09866801760096591, [412.0341636398682, 78.27886668585671], -0.12073301752494194, [375.9859683015703, 87.4982284336266], -0.5147180077888471, [286.9311668964115, 143.04547130452087], -0.4421725057028689, [283.55899816798757, 258.6438632019194], -0.14690306191037403, [305.8933031040614, 288.2572940179554], -0.07890574959740947, [301.7939188753185, 312.43178303838596], -0.21282420582828568, [261.71632118573507, 346.3699566262424], -0.06917535096525027, [243.1181520030554, 357.21011782274053], -0.013050188065110081, [239.77538403619326, 354.87110115149983], -0.34287563284336736, [189.65082691952335, 293.63217392634607], -0.20891260124541192, [153.23965447542747, 257.02345993147196], -0.3167524626595722, [97.5363151713131, 186.31876216651972], -0.0022449989277561824, [97.26309990631562, 185.67215126773345], -0.28667947844744857, [96.24805730936309, 48.61340648360716], -0.06367853269332903, [93.22543368129013, 29.01451546984611], -0.5893113794230874, [68.16522360588714, -62.95994473241845], 0.13657730967861118, [-37.639979270320296, -122.3116385611219], 0, false], "basePt": { "x": 8367.546600305966, "y": 776.8351334628773, "z": 0 } } + )[0]; + testOffset(pl, -12); +}); + + +test('精度过高导致连接失败', () => +{ + let pl = loadFile( + { "file": [1, "Polyline", 5, 2, 101, false, 1, 5, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 14518.613504172958, 18703.388772543934, 0, 1], 0, 0, 2, 33, [-2728.035021537973, -693.4012148813017], -0.3132583645586733, [-1601.8632919752708, 2314.522481497792], -0.03271654995069073, [-2273.419222591714, 2989.362495244932], -0.5625634539464556, [-3890.2801394762355, 3812.997524299488], 0.578639696480197, [-8788.605498322046, 960.1267108962238], -1.029709203909757, [-9954.873440911644, -206.14123168138758], 0.06337366142629626, [-10799.636417792484, 453.559442471018], 0.03792997284958775, [-9953.629162487545, -1660.1039329838386], -0.03406559295613797, [-10578.714309501978, -3162.773362526852], -0.026933451515028697, [-10332.24074169185, -3483.7939054907183], 0.00006795169607499043, [-11282.624637088404, -3687.0024757001956], 2.006103958007124, [-13543.3901873231, -3687.0024757005376], 1.3816050810686014, [-13543.390187323123, -4978.868504408674], -0.3636717333201528, [-12751.044634472513, -11523.955695998557], 0, [-9096.970935262972, -13685.493692909986], 0, [-9096.970935262972, -14046.280681946693], 0, [-8505.59719095358, -13657.009824881847], -0.3132583645586735, [-9631.768920516282, -16664.933521260944], -0.03271654995069073, [-8960.212989899832, -17339.773535008077], -0.5625634539464553, [-7343.352073015318, -18163.408564062644], 0.578639696480197, [-2445.0267141695076, -15310.537750659381], -1.0297092039097568, [-1278.758771579909, -14144.269808081766], 0.06337366142629626, [-433.9957946990762, -14803.970482234176], 0.03792997284958775, [-1280.0030500040084, -12690.307106779323], -0.03406559295613797, [-654.9179029895749, -11187.637677236302], -0.026933451515028697, [-901.3914707997028, -10866.617134272436], 0.00006795169607499043, [48.9924245969014, -10663.408564062645], 2.006103958007124, [2309.75797483154, -10663.408564062616], 1.3816050810686011, [2309.7579748315547, -9371.54253535448], -0.3636717333201528, [1517.41242198094, -2826.4553437645973], 0, [-2136.661277228579, -664.917346853168], 0, [-2136.661277228579, -304.1303578164607], 0, [-2728.0350215379567, -693.4012148813072], 0, false], "basePt": { "x": 82.79898218830704, "y": 105.03816793893884, "z": 0 } } + )[0]; + testOffset(pl, -700); + testOffset(pl, 3097.5341); +}); + + +test('精度过高导致直连失败', () => +{ + let pl = loadFile( + { "file": [1, "Polyline", 5, 2, 102, false, 1, 7, 0, [-0.9259244671528073, 0.37770872524710086, 0, 0, -0.37770872524710086, -0.9259244671528073, 0, 0, 0, 0, 1, 0, 6897.759879664679, 15205.352986914135, 0, 1], 0, 0, 2, 54, [-4354.152742830657, 13827.177939596737], 0, [-4262.7811479846705, 13409.171935420743], 0.4142135623731054, [-3949.382308443396, 13722.570774962005], -2.4142135623730643, [-3742.972460584606, 13516.160927103203], 0.41421356237309165, [-4056.371300125894, 13202.762087561938], 0, [-3.959206250088073, 14807.966978465562], 0, [374.86545725511814, 14627.059181391069], 0, [-308.3555283984747, 13943.838195737577], 0, [679.7597941901334, 13785.920221807895], -1.4592811343207486, [1009.1868138637083, 13733.272067978744], 0, [1505.5914256528936, 13653.937997601468], -1.1454616257969195, [1431.8308803096738, 13410.207502425372], 0.17647228147005975, [954.3937019885567, 13448.442761469398], 0.04501244263911578, [910.3672178888974, 12872.838967064557], 0.31352869106557485, [1254.453721297551, 12392.154572095944], 0.11606667962528619, [-769.1723201668815, 12475.541357089327], -0.4715020269053065, [-914.7290948999207, 12299.027686249425], 0.36270572632482756, [-1223.1098162314288, 12041.415740385853], -0.21031969189409624, [-1312.846126325028, 11908.417649155192], 0.18813889756470098, [-963.4449465315768, 11768.757856769267], 0.4991924773796846, [-1214.7276490074717, 11335.387842142274], -0.4715020269052786, [-1320.506481009447, 11132.521656284785], 0.362705726324842, [-1568.7468099597754, 10816.548045008172], -0.36230920816255674, [-1726.2154811248029, 10615.824015261507], 0.4243185463169048, [-1964.8264682160366, 10233.392254718088], 0, [-2265.5315916327377, 10110.726796713447], 0.41421356237309614, [-2437.3417689642583, 9702.169667027829], -2.41421356237314, [-2706.4244978711795, 9815.326794908384], 0.41421356237310153, [-2534.614320539642, 10223.883924594023], 0, [-2754.00600324702, 10761.706096363048], 0, [-3341.7022762014294, 10795.952557540084], 0.40448613781936477, [-3672.0207589378324, 10511.730420211165], -0.3283082854240908, [-3828.745250127082, 10335.177993847788], 0.42431854631690913, [-4067.356237218308, 9952.746233304364], 0, [-4368.061360635038, 9830.080775299726], 0.4142135623730961, [-4539.8715379665655, 9421.523645614097], -2.414213562373104, [-4808.954266873471, 9534.680773494647], 0.4142135623730893, [-4637.144089542, 9943.237903180267], 0, [-4856.535772249306, 10481.06007494932], 0, [-5275.629250369966, 10505.481649814608], 0, [-4901.076750834305, 11396.151204456679], 0, [-5875.6439010142485, 11169.151541429335], -1.4592811343207353, [-6200.554105740638, 11093.47229554728], 0, [-6690.152451994631, 10979.433299262762], -1.1454616257969006, [-6713.914892987609, 11232.969329692667], 0.17647228147005561, [-6257.402337098669, 11377.898555845191], 0.045012442639116336, [-6434.047713700185, 11927.493379656988], 0.3480949900000013, [-6998.304586811107, 12235.672947006504], 0.4991924773796818, [-6827.906275759371, 12706.753600113925], -0.4715020269052993, [-6759.802450275848, 12925.169990567034], 0.3627057263248343, [-6571.567474877286, 13280.177283417874], -0.36230920816254886, [-6452.2139365386165, 13505.657329990141], 0.2494829232648448, [-6264.109974726044, 13732.159080724145], -0.0032219232791951347, [-4354.152742830706, 13827.177939596728], 0, false], "basePt": { "x": 284.68899521531, "y": 124.40191387562407, "z": 0 } } + )[0]; + testOffset(pl, -488.7623); + testOffset(pl, -463.9361); +}); + +test('圆弧全丢时需要扇形切割', () => +{ + let pl = loadFile( + { "file": [1, "Polyline", 5, 2, 663, false, 1, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 6853.1135131705805, 836.8675810089517, 0, 1], 0, 0, 2, 27, [-16.65652680662606, -139.45855145395706], -0.07144822635709537, [-55.23422677371218, -129.1329069277308], -0.561450112948161, [-231.7482903492928, -291.4845802732408], -0.6533600789999746, [-488.9850632026728, -293.4891020338172], -0.09057099782999173, [-537.1231686572528, -278.3295686052045], -0.7618610483782836, [-785.3594189458317, -170.06019773383105], -0.5437626258582055, [-831.7965011168826, 61.09406785259716], -0.20989748425823024, [-821.5658136697248, 173.5739612523115], -0.44178467697699414, [-962.6165195283729, 325.9842596711035], -0.4640169462600465, [-930.7589203066564, 538.105200854457], -0.14150555348001248, [-884.1985938177158, 600.6057847806414], -0.3918412064449112, [-892.1911162706765, 791.273561468744], -1.2401869081054664, [-656.9329637971105, 932.7370024409249], -0.3780572143676024, [-511.23200314928545, 817.3911809150459], -0.15855910573440352, [-450.7514918718289, 755.0002355441181], -0.13423106558088388, [-390.0232449991963, 797.4190811206659], -0.37585301846721253, [-389.91032633598115, 982.4363154046794], -0.7527397478179146, [-220.4149163916445, 1192.5254581753811], -0.4657146279670491, [-14.69865666698206, 1130.0102224751936], -0.5121975123633337, [165.04952102208426, 989.8251327583196], -0.6686805682229583, [239.92044665198318, 741.2647937618274], -0.1190799996199453, [257.1716909424922, 677.5969246887876], -1.0785062605296105, [333.64851468926736, 408.14039255881926], -0.10448637020767436, [304.455989416344, 357.9457422079879], -0.8222462346235836, [242.6073012666575, 89.37100447247508], -0.13660899257896938, [192.97621867324324, 32.687778966786595], -1.304546181288702, [-16.65652680662606, -139.45855145395706], 0, false], "basePt": { "x": 5855.654258829502, "y": 460.34235664660923, "z": 0 } } + )[0]; + testOffset(pl, 141); +}); + +test('精度问题导致的连接错误', () => +{ + let pl = loadFile( + { "file": [1, "Polyline", 5, 2, 152, false, 1, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 0, 0, 2, 7, [20, 10], 0, [20, 0], 0, [10.000000000000004, 2.5000000000000018], 0, [0, 0], 0, [0, 10], 0, [10, 7.5], 0, [20, 10], 0, false], "basePt": { "x": 0, "y": 0, "z": 0 } } + )[0]; + testOffset(pl, 2.4254); +}); diff --git a/src/Add-on/CopyClip.ts b/src/Add-on/CopyClip.ts index 46c38a4f2..d7265ab76 100644 --- a/src/Add-on/CopyClip.ts +++ b/src/Add-on/CopyClip.ts @@ -6,6 +6,7 @@ import { GangDrill } from "../DatabaseServices/3DSolid/GangDrill"; import { CADFiler } from "../DatabaseServices/CADFiler"; import { Board } from "../DatabaseServices/Entity/Board"; import { PromptStatus } from "../Editor/PromptResult"; +import { deflate } from "../Common/SerializeMaterial"; export class CopyClip { @@ -43,9 +44,10 @@ export class CopyClip for (let e of ens) f.WriteObject(e); - copyTextToClipboard(JSON.stringify({ + let str = JSON.stringify({ file: f.Data, basePt, - })); + }); + copyTextToClipboard(str); } } diff --git a/src/Add-on/FilletUtils.ts b/src/Add-on/FilletUtils.ts index 992409d1e..45ca3e47f 100644 --- a/src/Add-on/FilletUtils.ts +++ b/src/Add-on/FilletUtils.ts @@ -724,7 +724,7 @@ export class FilletUtils let line = lineRes.Entity as Line; let arc = arcRes.Entity as Arc; - let dir = GetPointAtCurveDir(line, arc.Center) ? 1 : -1; + let dir = GetPointAtCurveDir(line, arc.Center); let lineO = line.GetOffsetCurves(this.FilletRadius * dir)[0]; let arcO = arc.GetOffsetCurves(this.FilletRadius * (arc.IsClockWise ? -1 : 1))[0];// tip:面积逆时针为正, 顺时针为负. diff --git a/src/Add-on/Offset.ts b/src/Add-on/Offset.ts index 725e54946..a31917cd6 100644 --- a/src/Add-on/Offset.ts +++ b/src/Add-on/Offset.ts @@ -2,10 +2,13 @@ import { Vector3 } from 'three'; import { app } from '../ApplicationServices/Application'; import { GetPointAtCurveDir } from '../Common/CurveUtils'; import { Curve } from '../DatabaseServices/Entity/Curve'; +import { Polyline } from '../DatabaseServices/Entity/Polyline'; import { Command } from '../Editor/CommandMachine'; import { JigUtils } from '../Editor/JigUtils'; import { PromptStatus } from '../Editor/PromptResult'; +const OffsetKey = "offset"; + //获取偏移距离的返回状态. type GetOffsetStatus = { Status: PromptStatus, offsetDist?: number }; @@ -13,22 +16,35 @@ type GetOffsetStatus = { Status: PromptStatus, offsetDist?: number }; export class Command_Offset implements Command { offsetDis: number = 1; + isDyn = false; + constructor() + { + let o = window.localStorage.getItem(OffsetKey); + if (o) + this.offsetDis = parseFloat(o) || this.offsetDis; + } async exec() { + this.isDyn = false; let disRes = await app.Editor.GetDistance({ Msg: "指定偏移距离:", KeyWordList: [{ msg: "通过:", key: "T" }], Default: this.offsetDis }); - let isDyn = false;//动态偏移. if (disRes.StringResult === "T") - isDyn = true; + this.isDyn = true; else if (disRes.Status === PromptStatus.OK) - this.offsetDis = disRes.Distance; + this.UpdateDistance(disRes.Distance); else return; + await this.Run(); + app.Viewer.OutlinePass.selectedObjects = []; + }//end exec + + async Run() + { let oldUCS = app.Editor.UCSMatrix; while (true) { @@ -49,7 +65,7 @@ export class Command_Offset implements Command { app.Viewer.OutlinePass.selectedObjects = [cu.DrawObject]; let state: GetOffsetStatus; - if (isDyn) + if (this.isDyn) state = await this.GetDynOffsetDist(cu); else state = await this.GetOffsetDir(cu); @@ -65,15 +81,19 @@ export class Command_Offset implements Command } app.Editor.UCSMatrix = oldUCS; - }//end exec + } + + UpdateDistance(offsetDist: number) + { + this.offsetDis = offsetDist || this.offsetDis; + window.localStorage.setItem(OffsetKey, this.offsetDis.toString()); + } //绘制偏移的对象 DrawOffset(cu: Curve, offsetDist: number) { - cu.GetOffsetCurves(offsetDist).forEach(c => - { + for (let c of cu.GetOffsetCurves(offsetDist)) app.Database.ModelSpace.Append(c); - }); } //单一对象,已经确定偏移距离的时候,用户选择偏移方向. @@ -87,7 +107,7 @@ export class Command_Offset implements Command Msg: "指定要偏移的那一侧的点", Callback: (p: Vector3) => { - let dir = GetPointAtCurveDir(cu, p) ? 1 : -1; + let dir = GetPointAtCurveDir(cu, p); if (dir !== oldDir) { JigUtils.Destroy(); @@ -101,7 +121,7 @@ export class Command_Offset implements Command let status = { Status: ptRes.Status, offsetDist: 0 }; if (ptRes.Status === PromptStatus.OK) { - let dir = GetPointAtCurveDir(cu, ptRes.Point) ? 1 : -1; + let dir = GetPointAtCurveDir(cu, ptRes.Point); status.offsetDist = this.offsetDis * dir; } return status; @@ -113,6 +133,9 @@ export class Command_Offset implements Command let basePoint: Vector3 = new Vector3(); let isMulti = false; + + let cuOcsInv = cu.OCSInv; + let cuOCs = cu.OCS; while (true) { let dir: number = 0; @@ -123,8 +146,9 @@ export class Command_Offset implements Command BasePoint: basePoint, CalcDistance: (baseP, p: Vector3) => { + p.applyMatrix4(cuOcsInv).setZ(0).applyMatrix4(cuOCs); basePoint.copy(cu.GetClosestPointTo(p, false)); - dir = GetPointAtCurveDir(cu, p) ? 1 : -1; + dir = GetPointAtCurveDir(cu, p); return p.distanceTo(basePoint) * dir; }, Callback: (dis: number) => @@ -133,7 +157,6 @@ export class Command_Offset implements Command cu.GetOffsetCurves(dis).forEach(c => JigUtils.Draw(c)); } }); - if (distRes.Status === PromptStatus.OK) { let offsetDist = distRes.Distance; @@ -156,3 +179,54 @@ export class Command_Offset implements Command } } } + +export class Command_DynOffset extends Command_Offset +{ + async exec() + { + this.isDyn = true; + await this.Run(); + app.Viewer.OutlinePass.selectedObjects = []; + } +} + +export class Command_DynOffsetToolPath +{ + async exec() + { + let enRes = await app.Editor.GetEntity({ Filter: { filterTypes: [Polyline] } }); + if (enRes.Status !== PromptStatus.OK) return; + + let pl = enRes.Entity as Polyline; + let basePoint: Vector3 = new Vector3(); + + let dir: number = 0; + let distRes = await app.Editor.GetDistance( + { + Msg: "指定通过点或输入偏移距离:", + BasePoint: basePoint, + CalcDistance: (baseP, p: Vector3) => + { + basePoint.copy(pl.GetClosestPointTo(p, false)); + dir = GetPointAtCurveDir(pl, p); + return p.distanceTo(basePoint) * dir; + }, + Callback: (dis: number) => + { + JigUtils.Destroy(); + pl.GetFeedingToolPath(dis).forEach(c => JigUtils.Draw(c)); + } + }); + + if (distRes.Status === PromptStatus.OK) + { + let offsetDist = distRes.Distance; + if (dir !== Math.sign(offsetDist)) + offsetDist = -offsetDist; + + let pls = pl.GetFeedingToolPath(offsetDist); + for (let pl of pls) + app.Database.ModelSpace.Append(pl); + } + } +} diff --git a/src/Add-on/OffsetX.ts b/src/Add-on/OffsetX.ts index aadd6fcd7..d3f3c13b5 100644 --- a/src/Add-on/OffsetX.ts +++ b/src/Add-on/OffsetX.ts @@ -1,82 +1,47 @@ import { app } from "../ApplicationServices/Application"; +import { Curve } from "../DatabaseServices/Entity/Curve"; import { Polyline } from "../DatabaseServices/Entity/Polyline"; import { Command } from "../Editor/CommandMachine"; import { PromptStatus } from "../Editor/PromptResult"; -import { Vector3 } from "three"; +import { HotCMD } from "../Hot/HotCommand"; +import { TestDraw } from "./test/TestUtil"; //无限内偏移 +@HotCMD export class OffsetX implements Command { offsetDis: number = 1; async exec() { - let ssRes = await app.Editor.GetEntity(); + let ssRes = await app.Editor.GetEntity({ Msg: "选择多段线进行偏移测试:", Filter: { filterTypes: [Polyline] } }); if (ssRes.Status != PromptStatus.OK) return; let pl = ssRes.Entity as Polyline; - if (!pl) return; - let dis: number, step: number; + let disRes = await app.Editor.GetDistance({ + Msg: "指定偏移距离:", + KeyWordList: [{ msg: "通过", key: "T" }], + Default: this.offsetDis + }); - if (window["autoDis"]) - { - this.offsetDis = 1.2 * Math.max(...pl.BoundingBox.getSize(new Vector3()).toArray()); - dis = -this.offsetDis; - step = this.offsetDis / 20; - } - else - { - let disRes = await app.Editor.GetDistance({ - Msg: "指定偏移距离:", - KeyWordList: [{ msg: "通过", key: "T" }], - Default: this.offsetDis - }); - - if (disRes.Status != PromptStatus.OK) return; - this.offsetDis = disRes.Distance; - dis = -this.offsetDis; - if (pl.IsClockWise) dis = -dis; - - let disRes1 = await app.Editor.GetDistance({ - Msg: "步长:", - KeyWordList: [{ msg: "通过", key: "T" }], - Default: 1 - }); - - if (disRes1.Status != PromptStatus.OK) return; - step = disRes1.Distance; - } - - // let step = 0.5; - let offRes: Polyline[] = []; - // offRes.push(...pl.GetOffsetCurves(dis) as Polyline[]); + let offsetDis = Math.abs(disRes.Distance); + TestDraw(pl.GetFeedingToolPath(offsetDis * Math.sign(pl.Area2)), 3);//外偏移 - // for (let i = 0; i < offRes.length; i++) - // { - // let offpl = offRes[i]; - // if (offpl.IsClose) - // { - // offRes.push(...offpl.GetOffsetCurves(dis) as Polyline[]); - // } - // } + let offsetQueue: Curve[] = [pl]; - if (step === 0) - { - app.Editor.Prompt("步长不能为0,已经帮你转换成" + dis / 10); - step = dis / 10; - } - let count = dis / step; - for (let i = 0; i < count; i++) + while (offsetQueue.length > 0) { - offRes.push(...pl.GetOffsetCurves(i * step) as Polyline[]); - offRes.push(...pl.GetOffsetCurves(-i * step) as Polyline[]); - - if (i > 50) + let pl = offsetQueue.pop() as Polyline; + let offsets = pl.GetFeedingToolPath(offsetDis * -Math.sign(pl.Area2)); + for (let c of offsets) { - alert("执行次数太多,怕你卡死,帮你停止了!"); - break; + if (c.IsClose) + { + TestDraw(c, 4); + offsetQueue.push(c); + } + else + TestDraw(c, 5); } } - - offRes.forEach(c => app.Database.ModelSpace.Append(c)); } } diff --git a/src/Add-on/PasteClip.ts b/src/Add-on/PasteClip.ts index 03e3e18b4..77b444c0f 100644 --- a/src/Add-on/PasteClip.ts +++ b/src/Add-on/PasteClip.ts @@ -1,5 +1,6 @@ import { Vector3 } from "three"; import { app } from "../ApplicationServices/Application"; +import { inflate } from "../Common/SerializeMaterial"; import { readClipboardText } from "../Common/Utils"; import { CADFiler } from "../DatabaseServices/CADFiler"; import { Entity } from "../DatabaseServices/Entity/Entity"; @@ -14,6 +15,8 @@ export class PasteClip try { let str = await readClipboardText(); + if (str.startsWith("zip:")) + str = inflate(str.slice(4)); data = JSON.parse(str); } catch (error) diff --git a/src/Add-on/Save.ts b/src/Add-on/Save.ts index 33fecef5f..f97c95277 100644 --- a/src/Add-on/Save.ts +++ b/src/Add-on/Save.ts @@ -9,6 +9,7 @@ import { RightPanelStore } from '../UI/Store/RightPanelStore/RightPanelStore'; export class Save implements Command { + NoHistory = true; async exec() { let fileServer = FileServer.GetInstance() as FileServer; diff --git a/src/Add-on/Undo.ts b/src/Add-on/Undo.ts index 81bef2972..70f5bf4fd 100644 --- a/src/Add-on/Undo.ts +++ b/src/Add-on/Undo.ts @@ -3,6 +3,7 @@ import { Command } from '../Editor/CommandMachine'; export class Undo implements Command { + NoHistory = true; async exec() { app.Database.hm.Undo(); @@ -12,6 +13,7 @@ export class Undo implements Command export class Redo implements Command { + NoHistory = true; async exec() { app.Database.hm.Redo(); diff --git a/src/Add-on/ViewChange.ts b/src/Add-on/ViewChange.ts index ccfe6589a..3da3d51ce 100644 --- a/src/Add-on/ViewChange.ts +++ b/src/Add-on/ViewChange.ts @@ -5,6 +5,7 @@ import { Orbit } from "../Geometry/Orbit"; export class ViewChange implements Command { + NoHistory = true; constructor(private viewDir: Vector3, private useWCS = false) { viewDir.normalize(); diff --git a/src/Add-on/closetest.ts b/src/Add-on/closetest.ts index 82c12a800..f7e9b5852 100644 --- a/src/Add-on/closetest.ts +++ b/src/Add-on/closetest.ts @@ -62,7 +62,7 @@ export class Command_ClosePt implements Command dyn.UpdatePrompt("点在线内外?:" + IsPointInPolyLine(cu, p)); closeCir.Center = p; - closeCir.ColorIndex = GetPointAtCurveDir(cu, p) ? 1 : 2; + closeCir.ColorIndex = GetPointAtCurveDir(cu, p) + 3; } } }) diff --git a/src/Add-on/test/TestOffset/OffsetTestUtil.ts b/src/Add-on/test/TestOffset/OffsetTestUtil.ts new file mode 100644 index 000000000..833cc4823 --- /dev/null +++ b/src/Add-on/test/TestOffset/OffsetTestUtil.ts @@ -0,0 +1,115 @@ +import { app } from "../../../ApplicationServices/Application"; +import { Arc } from "../../../DatabaseServices/Entity/Arc"; +import { Entity } from "../../../DatabaseServices/Entity/Entity"; +import { Point } from "../../../DatabaseServices/Entity/Point"; +import { Polyline } from "../../../DatabaseServices/Entity/Polyline"; +import { Region } from "../../../DatabaseServices/Entity/Region"; +import { OffsetPolyline } from "../../../GraphicsSystem/OffsetPolyline"; +import { TestDraw } from "../TestUtil"; + +export class OffsetTestUtil extends OffsetPolyline +{ + constructor(_Polyline: Polyline, _OffsetDist: number, _ToolPath = false) + { + super(_Polyline, _OffsetDist, _ToolPath) + } + + //----TEST + TestDrawPolyline() + { + this.OffsetSubCurves(); + app.Editor.Prompt("开始绘制多段线") + for (let i = 0; i < this._SubCurves.length; i++) + { + let c = this._SubCurves[i].Clone().ApplyMatrix(this._CacheOCS); + c.ColorIndex = i + 1; + + TestDraw(c); + for (let d of this._SubOffsetedCurves) + { + if (d.index === i) + { + let c2 = d.curve.Clone().ApplyMatrix(this._CacheOCS); + c2.ColorIndex = i + 1; + TestDraw(c2); + } + } + } + } + + TestDrawLinkSubCurve() + { + app.Editor.Prompt("开始显示曲线连接"); + for (let i = 0; i < this._SubOffsetedCurves.length; i++) + { + let d = this._SubOffsetedCurves[i]; + let c = d.curve.Clone(); + if (d.sp || d.ep) + { + if (d.sp) c.StartPoint = d.sp; + if (d.ep) c.EndPoint = d.ep; + } + c.ColorIndex = d.index + 1; + c.ApplyMatrix(this._CacheOCS); + TestDraw(c); + + if (d.paddingCurve) + { + for (let c of d.paddingCurve) + { + let arc = c.Clone().ApplyMatrix(this._CacheOCS) as Arc; + + let p = new Point(arc.Center); + TestDraw(p); + p.Erase(); + + arc.ColorIndex = d.index + 1; + TestDraw(arc); + } + } + } + } + + TestDrawTrimCircle() + { + app.Editor.Prompt("开始显示裁剪圆弧"); + for (let i = 0; i < this._TrimCircleContours.length; i++) + { + let c = this._TrimCircleContours[i].Clone().ApplyMatrix(this._CacheOCS); + let region = Region.CreateFromCurves([c]); + region.ColorIndex = i + 1; + TestDraw(region); + } + } + TestDrawTriContours() + { + app.Editor.Prompt("开始显示裁剪轮廓"); + for (let i = 0; i < this._TrimPolylineContours.length; i++) + { + let c = this._TrimPolylineContours[i].Curve.Clone().ApplyMatrix(this._CacheOCS); + let region = Region.CreateFromCurves([c]); + region.ColorIndex = i + 1; + TestDraw(region); + } + } + + TestDrawRetCurves() + { + app.Editor.Prompt("开始绘制最终结果"); + for (let i = 0; i < this._RetCurves.length; i++) + { + let c = this._RetCurves[i]; + TestDraw(c); + } + } + + TestTrimedCurve() + { + let i = 1; + for (let c of this._CurveTrimedTreeNodes) + { + TestDraw(c.curve.ApplyMatrix(this._CacheOCS), i); + i++ + } + } +} diff --git a/src/Add-on/test/TestOffset/TestOffset.ts b/src/Add-on/test/TestOffset/TestOffset.ts new file mode 100644 index 000000000..351231134 --- /dev/null +++ b/src/Add-on/test/TestOffset/TestOffset.ts @@ -0,0 +1,85 @@ +import { Box3 } from "three"; +import { begin } from "xaop"; +import { app } from "../../../ApplicationServices/Application"; +import { JigMoveEntity } from "../../../Common/JigMove"; +import { CADFiler } from "../../../DatabaseServices/CADFiler"; +import { Entity } from "../../../DatabaseServices/Entity/Entity"; +import { Polyline } from "../../../DatabaseServices/Entity/Polyline"; +import { ObjectSnapMode } from "../../../Editor/ObjectSnapMode"; +import { TestDraw } from "../TestUtil"; +import { OffsetTestUtil } from "./OffsetTestUtil"; + +export function LoadEntityFromFileData(data) +{ + if (!Array.isArray(data)) + data = data.file; + + let file = new CADFiler(); + file.Data = data; + let ens: Entity[] = []; + let count = file.Read(); + if (typeof count !== "number") + { + count = file.Data.length; + file.Reset(); + } + + for (let i = 0; i < count; i++) + { + ens.push(file.ReadObject() as Entity); + } + return ens; +} + +async function TestOffset(cud: Object, offsetDist: number | number[], count?: number) +{ + let ds = (typeof offsetDist === "number") ? [offsetDist] : offsetDist; + let ents: Entity[] = []; + let rm = begin(app.Database.ModelSpace, app.Database.ModelSpace.AppendEvent, (e: Entity) => + { + ents.push(e); + }); + + app.Editor.GetPointServices.snapServices.SnapModeEnable = ObjectSnapMode.Node; + + for (let d of ds) + { + let pl = LoadEntityFromFileData(cud)[0] as Polyline; + app.Editor.UpdateScreen(); + let u = new OffsetTestUtil(pl, d, true); + u.Do(); + + for (let step = 1; step < 6; step++) + { + u.Do(); + ents.length = 0; + TestDraw(pl.Clone()); + if (step === 1) + { + u.TestDrawPolyline(); + } + else if (step === 2) + { + u.TestDrawLinkSubCurve(); + } + else if (step === 3) + u.TestDrawTriContours(); + else if (step === 4) + u.TestTrimedCurve(); + else if (step === 5) + { + let i = 1; + for (let c of u._RetCurves) + { + TestDraw(c, i); + i++; + } + } + let b = new Box3(); + for (let e of ents) + b.union(e.BoundingBox); + await JigMoveEntity(ents, b.min) + } + } + rm(); +} diff --git a/src/Add-on/test/TestUtil.ts b/src/Add-on/test/TestUtil.ts new file mode 100644 index 000000000..8478f052b --- /dev/null +++ b/src/Add-on/test/TestUtil.ts @@ -0,0 +1,22 @@ +import { Object3D } from "three"; +import { app } from "../../ApplicationServices/Application"; +import { Entity } from "../../DatabaseServices/Entity/Entity"; + +export function TestDraw(en: Entity | Entity[] | Object3D, colorIndex = 0) +{ + if (en instanceof Object3D) + app.Viewer.Scene.add(en); + else if (en instanceof Entity) + { + if (colorIndex > 0) + en.ColorIndex = colorIndex; + app.Database.ModelSpace.Append(en); + } + else + for (let e of en) + { + if (colorIndex > 0) + e.ColorIndex = colorIndex; + app.Database.ModelSpace.Append(e); + } +} diff --git a/src/Add-on/testEntity/test.ts b/src/Add-on/testEntity/test.ts index 6d266e701..824324ca8 100644 --- a/src/Add-on/testEntity/test.ts +++ b/src/Add-on/testEntity/test.ts @@ -4,19 +4,24 @@ import { app } from "../../ApplicationServices/Application"; import { PromptStatus } from "../../Editor/PromptResult"; import { Board } from "../../DatabaseServices/Entity/Board"; import { Production } from "../../Production/Product"; +import { Polyline } from "../../DatabaseServices/Entity/Polyline"; +import { Matrix4 } from "three"; @HotCMD export class Test implements Command { async exec() { - let enRes = await app.Editor.GetEntity(); + let enRes = await app.Editor.GetSelection({}); if (enRes.Status === PromptStatus.OK) { - let en = enRes.Entity as Board; + let en = enRes.SelectSet.SelectEntityList as Polyline[]; - console.log(Production.GetBoardSplitOrderData(en)); + for (let e of en) + { + if (e.IsClockWise) e.ColorIndex = 1; + } } } } diff --git a/src/Common/CurveUtils.ts b/src/Common/CurveUtils.ts index 5df426745..b3538aa45 100644 --- a/src/Common/CurveUtils.ts +++ b/src/Common/CurveUtils.ts @@ -13,7 +13,7 @@ import { PlaneExt } from '../Geometry/Plane'; import { Stand } from '../Geometry/RegionParse'; import { IntersectOption } from '../GraphicsSystem/IntersectWith'; import { arrayLast, changeArrayStartIndex, equalArray } from './ArrayExt'; -import { FixIndex } from './Utils'; +import { OffsetPolyline } from '../GraphicsSystem/OffsetPolyline'; //3点获取圆心 export function getCircleCenter(pt1: Vector3, pt2: Vector3, pt3: Vector3) @@ -102,7 +102,7 @@ export function curveLinkGroup(cus: Curve[]): Array> if (cus.length === 0) return groupCus; //曲线节点图 let cuMap = new CurveMap(); - cus.forEach(c => cuMap.addCurveToMap(c)); + cus.forEach(c => cuMap.AddCurveToMap(c)); //曲线站点表 let stands = cuMap.Stands; @@ -266,121 +266,26 @@ export function equalCurve(cu1: Curve, cu2: Curve, tolerance = 1e-4) * * @param {Curve} cu * @param {Vector3} pt -* @returns {boolean} 左边为false,右边为true +* @returns {boolean} 左边为-1,右边为1 */ -export function GetPointAtCurveDir(cu: Curve, pt: Vector3): boolean +export function GetPointAtCurveDir(cu: Curve, pt: Vector3): number { if (cu instanceof Circle) - return !cu.PtInCurve(pt); - - //TODO: 当T字形多段线时,最近点将重叠,导致方向结果出错 - + return cu.PtInCurve(pt) ? -1 : 1; + else if (cu instanceof Polyline) + { + let u = new OffsetPolyline(cu, 1); + u.InitSubCurves(); + return u.GetPointAtCurveDir(pt.clone().applyMatrix4(cu.OCSInv).setZ(0)); + } //最近点 let cp = cu.GetClosestPointTo(pt, false); + if (equalv3(cp, pt, 1e-6)) return 0; //最近点参数 let cparam = cu.GetParamAtPoint(cp); - //归一化最近点参数 - let floorParam = Math.round(cparam); - - //当最近点在参数上时,可能产生退化,在这里重新计算合适的最近点和切线. - if ( - cu instanceof Polyline - && equaln(floorParam, cparam, 1e-2) - && - (cu.IsClose || (floorParam !== 0 && floorParam !== cu.EndParam)) - ) - { - let plVerCount = cu.NumberOfVertices; - if (equalv2(cu.GetPoint2dAt(0), cu.GetPoint2dAt(plVerCount - 1))) - plVerCount--; - - //分三点,本点,前一个点,后一个点 - if (floorParam === cu.EndParam) floorParam = 0; - let fIndex = FixIndex(floorParam - 1, plVerCount); - - let p = cu.GetPointAtParam(floorParam); - let cu1 = cu.GetCurveAtIndex(fIndex); - let cu2 = cu.GetCurveAtIndex(floorParam); - - let cu1Length = cu1.Length; - let cu2Length = cu2.Length; - let minLength = Math.min(cu1Length, cu2Length); - - - let fDer: Vector3; - let nDer: Vector3; - - if (equaln(cu.GetBuilgeAt(fIndex), 0)) - fDer = cu.GetFistDeriv(fIndex).normalize(); - else - { - let tp = cu1.GetPointAtDistance(cu1Length - minLength * 0.25); - fDer = tp.negate().add(p).normalize(); - } - - if (equaln(cu.GetBuilgeAt(floorParam), 0)) - nDer = cu.GetFistDeriv(floorParam).normalize(); - else - { - let tp = cu2.GetPointAtDistance(minLength * 0.25); - nDer = tp.sub(p).normalize(); - } - - let l1 = new Line(p.clone().sub(fDer.clone().multiplyScalar(300)), p); - l1.ColorIndex = 1; - let l2 = new Line(p, p.clone().add(nDer.clone().multiplyScalar(200))); - l2.ColorIndex = 2; - let cp1 = l1.GetClosestPointTo(pt, true); - let cp2 = l2.GetClosestPointTo(pt, true); - - // T 型曲线 - let nDerN = nDer.clone().negate(); - if (equalv3(fDer, nDerN)) - { - let frontParam = floorParam; - while (frontParam > 1) - { - let fp = cu.GetPointAtParam(frontParam - 1.2); - fDer.copy(p).sub(fp).normalize(); - if (!equalv3(fDer, nDerN)) - break; - - frontParam--; - } - - if (frontParam <= 1) - { - let nextParam = floorParam; - let endParam = cu.EndParam - 1; - while (nextParam < endParam) - { - let np = cu.GetPointAtParam(nextParam + 1.2); - nDer = np.sub(p).normalize(); - - if (!equalv3(fDer, nDerN)) - break; - - nextParam++; - } - } - } - if (equalv3(fDer, nDer)) - return fDer.cross(pt.clone().sub(cp1)).applyMatrix4(cu.OCSInv).z < 0; - - let adir = Math.sign(fDer.clone().cross(nDer).applyMatrix4(cu.OCSInv).z); - //判断点是否在小角内. - if ( - Math.sign(fDer.cross(pt.clone().sub(cp1)).applyMatrix4(cu.OCSInv).z) === adir - && Math.sign(nDer.cross(pt.clone().sub(cp2)).applyMatrix4(cu.OCSInv).z) === adir - ) - return adir < 0; - else - return adir > 0; - } - let dri = cu.GetFistDeriv(cparam); let cross = dri.cross(pt.clone().sub(cp)).applyMatrix4(cu.OCSInv); - return cross.z < 0; + return -Math.sign(cross.z); } /** diff --git a/src/Common/NumberDecimalAdjustment.ts b/src/Common/NumberDecimalAdjustment.ts new file mode 100644 index 000000000..d6d522816 --- /dev/null +++ b/src/Common/NumberDecimalAdjustment.ts @@ -0,0 +1,45 @@ +/** + * Decimal adjustment of a number. + * + * @param {String} type The type of adjustment. + * @param {Number} value The number. + * @param {Integer} exp The exponent (the 10 logarithm of the adjustment base). + * @returns {Number} The adjusted value. + */ +function decimalAdjust(type: string, value: number | (string | number)[], exp: number): number +{ + // If the exp is undefined or zero... + if (typeof exp === 'undefined' || +exp === 0) + { + return Math[type](value); + } + value = +value; + exp = +exp; + // If the value is not a number or the exp is not an integer... + if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0)) + { + return NaN; + } + // Shift + value = value.toString().split('e'); + value = Math[type](+(value[0] + 'e' + (value[1] ? (+value[1] - exp) : -exp))); + // Shift back + value = value.toString().split('e'); + return +(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp)); +} + +// Decimal round +export function round10(value: number, exp: number): number +{ + return decimalAdjust('round', value, exp); +}; +// Decimal floor +function floor10(value: number, exp: number): number +{ + return decimalAdjust('floor', value, exp); +}; +// Decimal ceil +function ceil10(value: number, exp: number): number +{ + return decimalAdjust('ceil', value, exp); +}; diff --git a/src/DatabaseServices/Entity/Arc.ts b/src/DatabaseServices/Entity/Arc.ts index 33dc6c6c7..d48ce127e 100644 --- a/src/DatabaseServices/Entity/Arc.ts +++ b/src/DatabaseServices/Entity/Arc.ts @@ -184,6 +184,18 @@ export class Arc extends Curve { return this.AllAngle * this.m_Radius; } + + GetParamAtPoint2(pt: Vector3): number + { + return this.GetParamAtAngle(this.GetAngleAtPoint(pt)); + } + //点在曲线上,已经确定点在曲线的延伸线上 + PtOnCurve3(p: Vector3, fuzz = 1e-6): boolean + { + let param = this.GetParamAtPoint2(p); + return this.ParamOnCurve(param, fuzz); + } + protected ApplyScaleMatrix(m: Matrix4): this { this.WriteAllObjectRecord(); @@ -232,7 +244,7 @@ export class Arc extends Curve { if (this.m_Radius == 0 || this.AllAngle == 0 || - !equaln(pt.distanceTo(this.Center), this.m_Radius, 1e-8)) + !equaln(pt.distanceTo(this.Center), this.m_Radius, 1e-6)) return NaN; return this.GetParamAtAngle(this.GetAngleAtPoint(pt)); diff --git a/src/DatabaseServices/Entity/Circle.ts b/src/DatabaseServices/Entity/Circle.ts index 439622da5..0456f0e94 100644 --- a/src/DatabaseServices/Entity/Circle.ts +++ b/src/DatabaseServices/Entity/Circle.ts @@ -35,14 +35,14 @@ export class Circle extends Curve { super(); center && this._Matrix.setPosition(center); - this.m_Radius = radius; + this._Radius = radius; } - private m_Radius: number; + private _Radius: number; get Shape() { let sp = new Shape(); - sp.ellipse(0, 0, this.m_Radius, this.m_Radius, 0, 2 * Math.PI, false, 0); + sp.ellipse(0, 0, this._Radius, this._Radius, 0, 2 * Math.PI, false, 0); return sp; } @@ -58,12 +58,12 @@ export class Circle extends Curve } get Radius() { - return this.m_Radius; + return this._Radius; } set Radius(v: number) { this.WriteAllObjectRecord(); - this.m_Radius = clamp(v, 1e-9, 1e19); + this._Radius = clamp(v, 1e-9, 1e19); this.Update(); } @@ -107,11 +107,15 @@ export class Circle extends Curve } get Area() { - return Math.PI * Math.pow(this.m_Radius, 2); + return Math.PI * this._Radius ** 2; + } + get Area2() + { + return Math.PI * this._Radius ** 2; } get Length() { - return Math.PI * 2 * this.m_Radius; + return Math.PI * 2 * this._Radius; } get IsClose(): boolean @@ -119,20 +123,23 @@ export class Circle extends Curve return true; } + //曲线为顺时针 + get IsClockWise(): boolean { return false; } + GetPointAtParam(param: number) { - return (polar(new Vector3(), param * 2 * Math.PI, this.m_Radius) as Vector3).applyMatrix4(this._Matrix); + return (polar(new Vector3(), param * 2 * Math.PI, this._Radius) as Vector3).applyMatrix4(this._Matrix); } GetPointAtDistance(distance: number) { - let param = distance / (Math.PI * 2 * this.m_Radius); + let param = distance / (Math.PI * 2 * this._Radius); return this.GetPointAtParam(param); } GetDistAtParam(param: number) { - return Math.PI * 2 * this.m_Radius * param; + return Math.PI * 2 * this._Radius * param; } GetDistAtPoint(pt: Vector3) @@ -143,7 +150,7 @@ export class Circle extends Curve GetParamAtDist(d: number) { - return d / (Math.PI * 2 * this.m_Radius); + return d / (Math.PI * 2 * this._Radius); } GetSplitCurves(param: number[] | number) @@ -171,7 +178,7 @@ export class Circle extends Curve let ea = anglelist[i + 1]; if (!equaln(sa, ea, 1e-6)) { - let arc = new Arc(new Vector3(), this.m_Radius, sa, ea); + let arc = new Arc(new Vector3(), this._Radius, sa, ea); arc.ApplyMatrix(this.OCS); curvelist.push(arc); } @@ -190,14 +197,14 @@ export class Circle extends Curve PtOnCurve(pt: Vector3) { - return equaln(pt.distanceToSquared(this.Center), this.m_Radius * this.m_Radius, 1e-5); + return equaln(pt.distanceToSquared(this.Center), this._Radius * this._Radius, 1e-5); } GetOffsetCurves(offsetDist: number) { - if ((offsetDist + this.m_Radius) > 0) + if ((offsetDist + this._Radius) > 0) { let circle = this.Clone(); - circle.Radius = this.m_Radius + offsetDist; + circle.Radius = this._Radius + offsetDist; return [circle]; } return [] @@ -241,7 +248,7 @@ export class Circle extends Curve } UpdateDrawObject(type: RenderType, obj: Object3D) { - obj.children[0].scale.set(this.m_Radius, this.m_Radius, this.m_Radius); + obj.children[0].scale.set(this._Radius, this._Radius, this._Radius); obj.children[0].updateMatrix(); } UpdateDrawObjectMaterial(type: RenderType, obj: Object3D, material: Material) @@ -262,10 +269,10 @@ export class Circle extends Curve { let pts = [ new Vector3(), - new Vector3(0, this.m_Radius), - new Vector3(0, -this.m_Radius), - new Vector3(-this.m_Radius, 0), - new Vector3(this.m_Radius, 0), + new Vector3(0, this._Radius), + new Vector3(0, -this._Radius), + new Vector3(-this._Radius, 0), + new Vector3(this._Radius, 0), ]; let ocs = this.OCS; @@ -382,14 +389,14 @@ export class Circle extends Curve { super._ReadFile(file); let ver = file.Read(); - this.m_Radius = file.Read(); + this._Radius = file.Read(); } //对象将自身数据写入到文件. WriteFile(file: CADFiler) { super.WriteFile(file); file.Write(1); - file.Write(this.m_Radius); + file.Write(this._Radius); } //#endregion } diff --git a/src/DatabaseServices/Entity/Curve.ts b/src/DatabaseServices/Entity/Curve.ts index b9ec973b8..5db87bb18 100644 --- a/src/DatabaseServices/Entity/Curve.ts +++ b/src/DatabaseServices/Entity/Curve.ts @@ -69,6 +69,8 @@ export abstract class Curve extends Entity GetDistAtParam(param: number): number { return; } GetDistAtPoint(pt: Vector3): number { return; } GetParamAtPoint(pt: Vector3): number { return; } + GetParamAtPoint2(pt: Vector3): number { return this.GetParamAtPoint(pt); } + GetParamAtDist(d: number): number { return; } /** @@ -140,6 +142,12 @@ export abstract class Curve extends Entity return !(equalv3(this.StartPoint, pt, 1e-6) || equalv3(this.EndPoint, pt, 1e-6)) && this.ParamOnCurve(this.GetParamAtPoint(pt), 0); } + //点在曲线上,已经确定点在曲线的延伸线上 + PtOnCurve3(p: Vector3, fuzz = 1e-6): boolean + { + return this.PtOnCurve(p, fuzz); + } + //参数在曲线上 容差,1e-6 ParamOnCurve(param: number, fuzz = 1e-6): boolean { return !isNaN(param) && param >= -fuzz && param <= this.EndParam + fuzz; } GetOffsetCurves(offsetDist: number): Array { return; } diff --git a/src/DatabaseServices/Entity/Entity.ts b/src/DatabaseServices/Entity/Entity.ts index d3c9ee8b9..b2f8109de 100644 --- a/src/DatabaseServices/Entity/Entity.ts +++ b/src/DatabaseServices/Entity/Entity.ts @@ -210,7 +210,7 @@ export class Entity extends CADObject } UpdateRenderType(type: RenderType) { - if (this.OnlyRenderType || !this.Visible) return; + if ((this.OnlyRenderType && this.DrawObject.children.length > 0) || !this.Visible) return; Object3DRemoveAll(this.DrawObject); let obj = this.GetDrawObjectFromRenderType(type); if (obj) this.DrawObject.add(obj); diff --git a/src/DatabaseServices/Entity/Extrude.ts b/src/DatabaseServices/Entity/Extrude.ts index 771a6f080..96e6f0a1c 100644 --- a/src/DatabaseServices/Entity/Extrude.ts +++ b/src/DatabaseServices/Entity/Extrude.ts @@ -73,7 +73,7 @@ export class ExtrudeSolid extends Entity protected grooves: ExtrudeSolid[] = []; protected knifeRadius: number = 3; - protected groovesAddLength: number = 3; + protected groovesAddLength: number = 0; protected groovesAddWidth: number = 0; protected groovesAddDepth: number = 0; diff --git a/src/DatabaseServices/Entity/Line.ts b/src/DatabaseServices/Entity/Line.ts index 71b3fcd7b..21c0c168f 100644 --- a/src/DatabaseServices/Entity/Line.ts +++ b/src/DatabaseServices/Entity/Line.ts @@ -227,6 +227,19 @@ export class Line extends Curve return ret; } + GetParamAtPoint2(pt: Vector3): number + { + let { param } = this.GetClosestAtPoint(pt, true); + return param; + } + + //点在曲线上,已经确定点在曲线的延伸线上 + PtOnCurve3(p: Vector3, fuzz = 1e-6): boolean + { + let { param } = this.GetClosestAtPoint(p, true); + return this.ParamOnCurve(param, fuzz); + } + GetClosestAtPoint(pt: Vector3, extend: boolean): { closestPt: Vector3, param: number } { let sp = this.StartPoint; diff --git a/src/DatabaseServices/Entity/Polyline.ts b/src/DatabaseServices/Entity/Polyline.ts index 33d5d9f86..7988ce384 100644 --- a/src/DatabaseServices/Entity/Polyline.ts +++ b/src/DatabaseServices/Entity/Polyline.ts @@ -10,7 +10,7 @@ import { ObjectSnapMode } from '../../Editor/ObjectSnapMode'; import { BufferGeometryUtils } from '../../Geometry/BufferGeometryUtils'; import { AsVector2, AsVector3, equaln, equalv2, equalv3, updateGeometry } from '../../Geometry/GeUtils'; import { IntersectOption, IntersectPolylineAndCurve } from '../../GraphicsSystem/IntersectWith'; -import { PolyOffsetUtil } from '../../GraphicsSystem/OffsetPolyline'; +import { OffsetPolyline } from '../../GraphicsSystem/OffsetPolyline'; import { RenderType } from '../../GraphicsSystem/RenderType'; import { Factory } from '../CADFactory'; import { CADFiler } from '../CADFiler'; @@ -877,9 +877,27 @@ export class Polyline extends Curve PtOnCurve(pt: Vector3): boolean { - let param = this.GetParamAtPoint(pt); - return this.ParamOnCurve(param); + for (let i = 0; i < this.EndParam; i++) + { + let c = this.GetCurveAtIndex(i); + if (c.PtOnCurve(pt)) + return true; + } + return false; } + + //点在曲线上,已经确定点在曲线的延伸线上 + PtOnCurve3(p: Vector3, fuzz = 1e-6): boolean + { + for (let i = 0; i < this.EndParam; i++) + { + let c = this.GetCurveAtIndex(i); + if (c.PtOnCurve3(p, fuzz)) + return true; + } + return false; + } + PtInCurve(pt: Vector3) { return this.IsClose && IsPointInPolyLine(this, pt); @@ -946,13 +964,15 @@ export class Polyline extends Curve //偏移 GetOffsetCurves(offsetDist: number): Array { - let polyOffestUtil = new PolyOffsetUtil(this, offsetDist); - return polyOffestUtil.GetOffsetCurves(); + if (equaln(offsetDist, 0)) return []; + let polyOffestUtil = new OffsetPolyline(this, offsetDist); + return polyOffestUtil.Do(); } GetFeedingToolPath(offsetDist: number): Array { - let polyOffestUtil = new PolyOffsetUtil(this, offsetDist); - return polyOffestUtil.GetOffsetCurves(true); + if (equaln(offsetDist, 0)) return []; + let polyOffestUtil = new OffsetPolyline(this, offsetDist, true); + return polyOffestUtil.Do(); } /** * 分解 @@ -1280,7 +1300,7 @@ export class Polyline extends Curve arc.MoveGripPoints([2], moveVec); this.m_LineData[frontIndex].bul = arc.Bul; } - if (this.GetBuilgeAt(cuIndex)) + if ((cuIndex !== ptCout - 1) && this.GetBuilgeAt(cuIndex)) { let arc = this.GetCurveAtIndex(cuIndex) as Arc; arc.MoveGripPoints([0], moveVec); diff --git a/src/DatabaseServices/ObjectCollection.ts b/src/DatabaseServices/ObjectCollection.ts index 75c75c730..0bbab214a 100644 --- a/src/DatabaseServices/ObjectCollection.ts +++ b/src/DatabaseServices/ObjectCollection.ts @@ -67,7 +67,8 @@ export class ObjectCollection extends CADObject undoRec.WriteObjectHistoryPath(this, hisRec); } - obj.GoodBye(); + if (obj) + obj.GoodBye(); } //#region -----------------------------File----------------------------- diff --git a/src/DatabaseServices/PointInPolyline.ts b/src/DatabaseServices/PointInPolyline.ts index 463dc8aa3..77a4a6cf2 100644 --- a/src/DatabaseServices/PointInPolyline.ts +++ b/src/DatabaseServices/PointInPolyline.ts @@ -126,7 +126,6 @@ export function IsPointInPolyLine(pl: Polyline, pt: Vector3): boolean } continue; } - if (equaln(sp.x, pt.x) && sp.y > pt.y) { let der = arc.GetFistDeriv(0); @@ -142,7 +141,7 @@ export function IsPointInPolyLine(pl: Polyline, pt: Vector3): boolean for (let pti of arc.IntersectWith(insLine, IntersectOption.ExtendArg)) { - if (pti.y < pt.y || equalv3(sp, pti) || equalv3(ep, pti)) + if (pti.y < pt.y || equalv3(sp, pti, 1e-5) || equalv3(ep, pti, 1e-5)) continue; let der = arc.GetFistDeriv(pti); diff --git a/src/Editor/CommandMachine.ts b/src/Editor/CommandMachine.ts index c05d5420a..94fd00b34 100644 --- a/src/Editor/CommandMachine.ts +++ b/src/Editor/CommandMachine.ts @@ -5,6 +5,7 @@ import { CommandState } from './CommandState'; import { JigUtils } from './JigUtils'; export interface Command { + NoHistory?: boolean; exec: Function;//函数可以返回true,实现放弃命令的任何操作. } @@ -24,9 +25,10 @@ class CommandMachine arrayRemoveOnce(app.Editor.CommandStore.historyCmdList, cmdName) app.Editor.CommandStore.historyCmdList.push(cmdName); - if (cmdName === "U" || cmdName === "REDO") + let cmd = this.CommandMap.get(cmdName); + if (cmd.NoHistory) { - await this.CommandMap.get(cmdName).exec(); + await cmd.exec(); app.Editor.UpdateScreen(); return; } @@ -36,7 +38,7 @@ class CommandMachine let abort: boolean = true; try { - abort = await this.CommandMap.get(cmdName).exec(); + abort = await cmd.exec(); } catch (error) { diff --git a/src/Editor/CommandRegister.ts b/src/Editor/CommandRegister.ts index 7dcd30665..c28cf9922 100644 --- a/src/Editor/CommandRegister.ts +++ b/src/Editor/CommandRegister.ts @@ -92,12 +92,13 @@ import { Fbx } from "../Add-on/loadfbx"; import { LookOverBoardInfos } from "../Add-on/LookOverBoardInfos"; import { MirrorCommand } from "../Add-on/Mirror"; import { Command_Move } from "../Add-on/Move"; -import { Command_Offset } from "../Add-on/Offset"; +import { Command_DynOffset, Command_DynOffsetToolPath, Command_Offset } from "../Add-on/Offset"; import { OffsetX } from "../Add-on/OffsetX"; import { Open } from "../Add-on/Open"; import { PasteClip } from "../Add-on/PasteClip"; import { Pedit } from "../Add-on/Pedit"; import { Command_PLTest } from "../Add-on/polytest"; +import { Command_Purge } from "../Add-on/Purge"; import { Command_RestoreColor } from "../Add-on/RestoreColor"; import { Command_Reverse } from "../Add-on/Reverse"; import { Command_Rotate } from "../Add-on/Rotate"; @@ -134,7 +135,6 @@ import { CommandServer } from '../DatabaseServices/CommandServer'; import { AutoTempateSizeAction } from '../DatabaseServices/Template/TemplateTest'; import { ICommand } from '../UI/Components/CommandPanel/CommandList'; import { commandMachine } from './CommandMachine'; -import { Command_Purge } from "../Add-on/Purge"; export function registerCommand() { @@ -236,6 +236,9 @@ export function registerCommand() commandMachine.RegisterCommand("testFilletCode", new TestFillet()); commandMachine.RegisterCommand("O", new Command_Offset()); + commandMachine.RegisterCommand("OT", new Command_DynOffset()); + commandMachine.RegisterCommand("TO", new Command_DynOffsetToolPath()); + commandMachine.RegisterCommand("Length", new Command_Length()); //绘制灯 diff --git a/src/Geometry/Box.ts b/src/Geometry/Box.ts index 2f4872ae0..aea1fb74c 100644 --- a/src/Geometry/Box.ts +++ b/src/Geometry/Box.ts @@ -52,11 +52,15 @@ export class Box3Ext extends Box3 interBox.max.setComponent(splitType, Math.max(this.min.getComponent(splitType), b2.min.getComponent(splitType))); return interBox; } - intersectsBox(box: this, fuzz = 1e-8) + intersectsBox(box: this, fuzz = 1e-8): boolean { - // 重载three.js的相交判断,加入误差 - return box.max.x < this.min.x - fuzz || box.min.x > this.max.x + fuzz || - box.max.y < this.min.y - fuzz || box.min.y > this.max.y + fuzz || - box.max.z < this.min.z - fuzz || box.min.z > this.max.z + fuzz ? false : true; + return IntersectsBox(this, box, fuzz); } } + +export function IntersectsBox(box1: Box3, box2: Box3, fuzz = 1e-6): boolean +{ + return box2.max.x < box1.min.x - fuzz || box2.min.x > box1.max.x + fuzz || + box2.max.y < box1.min.y - fuzz || box2.min.y > box1.max.y + fuzz || + box2.max.z < box1.min.z - fuzz || box2.min.z > box1.max.z + fuzz ? false : true; +} diff --git a/src/Geometry/CurveMap.ts b/src/Geometry/CurveMap.ts index b5c604f18..ecddec5a1 100644 --- a/src/Geometry/CurveMap.ts +++ b/src/Geometry/CurveMap.ts @@ -34,12 +34,14 @@ export class CurveMap return stands; } - addCurveToMap(cu: Curve) + AddCurveToMap(cu: Curve) { - let startS = this.GetStand(cu.StartPoint); - let endS = this.GetStand(cu.EndPoint); - let routeS2E: Route = { curve: cu, to: endS }; - let routeE2S: Route = { curve: cu, to: startS }; + let sp = cu.StartPoint; + let ep = cu.EndPoint; + let startS = this.GetStand(sp); + let endS = this.GetStand(ep); + let routeS2E: Route = { curve: cu, to: endS, s: sp, e: ep }; + let routeE2S: Route = { curve: cu, to: startS, s: ep, e: sp }; startS.routes.push(routeS2E); endS.routes.push(routeE2S); } diff --git a/src/Geometry/GeUtils.ts b/src/Geometry/GeUtils.ts index 2086978e7..dbcd9ca6d 100644 --- a/src/Geometry/GeUtils.ts +++ b/src/Geometry/GeUtils.ts @@ -1,6 +1,7 @@ import { Box3, BufferGeometry, Geometry, Line, Matrix4, Mesh, Object3D, Vector, Vector2, Vector3 } from 'three'; import { ToFixed } from '../Common/Utils'; +export const IdentityMtx4 = new Matrix4(); export const ZeroVec = new Vector3(); export const XAxis = new Vector3(1, 0, 0); export const YAxis = new Vector3(0, 1, 0); @@ -374,3 +375,14 @@ export function SnapPoint(sqCenter: Vector3, snapPt: Vector3, size: number) return Math.abs(sqCenter.x - snapPt.x) < size && Math.abs(sqCenter.y - snapPt.y) < size; } + +export function SelectNearP(pts: Vector3[], refPt: Vector3): Vector3 +{ + if (pts.length > 1) + { + let dist1 = refPt.distanceToSquared(pts[0]); + let dist2 = refPt.distanceToSquared(pts[1]); + return dist1 <= dist2 ? pts[0] : pts[1]; + } + return pts[0]; +} diff --git a/src/Geometry/RegionParse.ts b/src/Geometry/RegionParse.ts index 83ffe0423..1ccefbc2e 100644 --- a/src/Geometry/RegionParse.ts +++ b/src/Geometry/RegionParse.ts @@ -12,6 +12,8 @@ export interface Route { curve: Curve; //路线的曲线 to: Stand; //终点的点 + s: Vector3; + e: Vector3; } @@ -238,12 +240,12 @@ export class RegionParse let arcs = this.BreakArc(cu); if (arcs.length > 1) { - arcs.forEach(a => curveMap.addCurveToMap(a)); + arcs.forEach(a => curveMap.AddCurveToMap(a)); this.ExpLineMap.set(cu, arcs); continue; } } - curveMap.addCurveToMap(cu); + curveMap.AddCurveToMap(cu); } //排序,根据角度逆时针排序. diff --git a/src/GraphicsSystem/CalcEdgeSealing.ts b/src/GraphicsSystem/CalcEdgeSealing.ts index 4a24dc76a..159c4b6e9 100644 --- a/src/GraphicsSystem/CalcEdgeSealing.ts +++ b/src/GraphicsSystem/CalcEdgeSealing.ts @@ -6,9 +6,8 @@ import { Circle } from "../DatabaseServices/Entity/Circle"; import { Curve } from "../DatabaseServices/Entity/Curve"; import { Line } from "../DatabaseServices/Entity/Line"; import { Polyline } from "../DatabaseServices/Entity/Polyline"; -import { angle, equaln, equalv3, isParallelTo } from "../Geometry/GeUtils"; +import { angle, equaln, equalv3, isParallelTo, SelectNearP } from "../Geometry/GeUtils"; import { IntersectOption } from "./IntersectWith"; -import { PolyOffsetUtil } from "./OffsetPolyline"; /** *曲线列表分段 @@ -132,7 +131,7 @@ export function CalcEdgeSealing(cus: Curve[]) && laterLine.PtOnCurve(p) ); - let iPt = PolyOffsetUtil.SelectFitInterPt(tPts.length > 0 ? tPts : iPts, frontLine.EndPoint); + let iPt = SelectNearP(tPts.length > 0 ? tPts : iPts, frontLine.EndPoint); frontLine.EndPoint = iPt; laterLine.StartPoint = iPt; diff --git a/src/GraphicsSystem/IntersectWith.ts b/src/GraphicsSystem/IntersectWith.ts index 41763e1d1..6adafcfc0 100644 --- a/src/GraphicsSystem/IntersectWith.ts +++ b/src/GraphicsSystem/IntersectWith.ts @@ -56,7 +56,14 @@ function CheckPointOnCurve(intPts: Vector3[], c1: Curve, c2: Curve, extType: Int { return intPts.filter(p => { - return (extType & IntersectOption.ExtendThis || c1.PtOnCurve(p, tolerance)) && (extType & IntersectOption.ExtendArg || c2.PtOnCurve(p, tolerance)) + if (!(extType & IntersectOption.ExtendThis)) + if (!c1.PtOnCurve3(p, tolerance)) + return false; + + if (!(extType & IntersectOption.ExtendArg)) + if (!c2.PtOnCurve3(p, tolerance)) + return false; + return true; }); } diff --git a/src/GraphicsSystem/LinkSelft.ts b/src/GraphicsSystem/LinkSelft.ts index 35f4cce9e..6eafec658 100644 --- a/src/GraphicsSystem/LinkSelft.ts +++ b/src/GraphicsSystem/LinkSelft.ts @@ -11,7 +11,7 @@ export class LinkSelf private curveIndexData: WeakMap = new WeakMap(); sealCus: Set[] = []; noSealCus: Curve[][] = []; - private m_Count; + private m_Count: number; private cuMap: CurveMap; constructor(cus: Curve[]) { @@ -279,7 +279,7 @@ export class LinkSelf GenerateCurveMap(breakCus: Curve[]) { let cuMap = new CurveMap(); - breakCus.forEach(c => cuMap.addCurveToMap(c)); + breakCus.forEach(c => cuMap.AddCurveToMap(c)); //所有的站点 逆序排序. for (let [, stand] of cuMap.m_NodeMap) { diff --git a/src/GraphicsSystem/OffsetPolyline.ts b/src/GraphicsSystem/OffsetPolyline.ts index f8c040a53..c8bed95a1 100644 --- a/src/GraphicsSystem/OffsetPolyline.ts +++ b/src/GraphicsSystem/OffsetPolyline.ts @@ -1,693 +1,779 @@ -import { Box3, Vector3, Matrix4 } from "three"; -import { arrayLast, arrayRemoveDuplicateBySort, arrayRemoveIf, arraySortByNumber } from "../Common/ArrayExt"; -import { curveLinkGroup, GetPointAtCurveDir } from "../Common/CurveUtils"; +import { Box3, Matrix4, Vector3 } from "three"; +import { arrayLast } from "../Common/ArrayExt"; +import { ConverCircleToPolyline } from "../Common/CurveUtils"; import { Status } from "../Common/Status"; import { FixIndex } from "../Common/Utils"; +import { Contour } from "../DatabaseServices/Contour"; import { Arc } from "../DatabaseServices/Entity/Arc"; import { Circle } from "../DatabaseServices/Entity/Circle"; -import { Contour } from '../DatabaseServices/Contour'; import { Curve } from "../DatabaseServices/Entity/Curve"; import { Line } from "../DatabaseServices/Entity/Line"; -import { Polyline } from '../DatabaseServices/Entity/Polyline'; -import { equaln, equalv2, equalv3 } from "../Geometry/GeUtils"; -import { EBox, SortEntityByBox } from "../Geometry/SortEntityByBox"; -import { IsPtsAllOutOrOnReg } from "./BoolOperateUtils"; -import { IntersectOption } from "./IntersectWith"; +import { Polyline } from "../DatabaseServices/Entity/Polyline"; +import { IntersectsBox } from "../Geometry/Box"; +import { CurveMap } from "../Geometry/CurveMap"; +import { angle, equaln, equalv2, equalv3, IdentityMtx4, SelectNearP } from "../Geometry/GeUtils"; +import { Route, Stand } from "../Geometry/RegionParse"; +import { SortEntityByBox } from "../Geometry/SortEntityByBox"; +import { IntersectOption } from "../GraphicsSystem/IntersectWith"; interface IOffsetResult { index: number; curve: Curve; + sp?: Vector3; + preArc?: Curve; + ep?: Vector3; + nextArc?: Curve; + paddingCurve?: Curve[]; } -export class PolyOffsetUtil +class CurveTreeNode { - private _Polyline: Polyline; - private _OffsetDist: number; - private _Contours: Contour[] = [];//构建的轮廓 - private _RetCurves: Curve[] = [];//第一步修剪的数组 - //偏移距离平方值 - private _Dist2: number; - //偏移距离绝对值 - private _AbsDist: number; - //不用裁剪的线段 - private _UnNeedCutCus: Curve[] = []; - //源线段点数量 - private _PtCount: number; - constructor(pl: Polyline, offset: number) + children: CurveTreeNode[]; + box: Box3; + used: boolean; + constructor(public curve: Curve, box?: Box3) { - this._Polyline = pl.Clone(); - this._OffsetDist = offset; - this._Dist2 = Math.pow(offset, 2); - this._AbsDist = Math.abs(this._OffsetDist); - this._PtCount = pl.EndParam; + this.box = box || curve.BoundingBox; } - /** - * @param [isCalcPath=false] - */ - GetOffsetCurves(isCalcPath = false): Curve[] + TrimBy(contour: Contour, box: Box3) { - if (equaln(this._OffsetDist, 0)) return []; - - const originOCS = this._Polyline.OCS; - this._Polyline.OCS = new Matrix4(); - - let expCus = this._Polyline.Explode(); - let offres = this.OffestCurve(expCus); - //不闭合曲线传入首尾点构建圆轮廓 - if (!this._Polyline.IsClose) + if (IntersectsBox(box, this.box)) { - let cir1 = new Circle(this._Polyline.StartPoint, this._AbsDist); - let cir2 = new Circle(this._Polyline.EndPoint, this._AbsDist); - this._Contours.push(Contour.CreateContour([cir1])); - this._Contours.push(Contour.CreateContour([cir2])); - } - //连接修剪并构建轮廓 - this.TrimAndBuildContour(offres); + if (this.children !== undefined) + { + for (let c of this.children) + c.TrimBy(contour, box); + } + else + { + if (contour.Curve instanceof Circle && this.curve instanceof Arc) + { + if (equalv3(contour.Curve.Center, this.curve.Center)) + { + if (contour.Curve.Radius > this.curve.Radius + 1e-4) + this.children = []; - //裁剪并优化的曲线 - let boxCurves = this.TrimByContours(); - //优化删除无效和连接共线,必须执行上一步 - this.OptimizeCus(boxCurves); - this.LinkCurves(); + return; + } + } - if (!isCalcPath) - { - //如果源线段闭合只保留闭合的部分(理论上可以删除这个判断) - if (this._Polyline.IsClose) - this._RetCurves = this._RetCurves.filter(c => c.IsClose); + //交点参数列表 + let iParams = this.curve.IntersectWith(contour.Curve, IntersectOption.OnBothOperands) + .map(p => this.curve.GetParamAtPoint2(p)); - if (this._Polyline.CloseMark) - this._RetCurves.forEach(pl => (pl).CloseMark = true); + let cus = this.curve.GetSplitCurves(iParams); + if (cus.length === 0) + { + let p = this.curve.GetPointAtParam(0.5); + if ((contour.Curve.PtInCurve(p) && !contour.Curve.PtOnCurve(p))) + this.children = []; + } + else + { + this.children = []; + for (let c of cus) + { + let p = c.GetPointAtParam(0.5); + if (c.Length > 1e-5 && (!contour.Curve.PtInCurve(p) || contour.Curve.PtOnCurve(p))) + this.children.push(new CurveTreeNode(c)); + } + if (this.children.length === cus.length) + this.children = undefined; + } + } } + } - return this._RetCurves.map(pl => pl.ApplyMatrix(originOCS)); + get Nodes() + { + if (!this.children) return [this]; + else + { + let cus: CurveTreeNode[] = []; + for (let c of this.children) + cus.push(...c.Nodes); + return cus; + } } +} - private CheckPointDir(pt: Vector3) +export class OffsetPolyline +{ + //多段线信息 + _CacheOCS: Matrix4; + _Vertexs: Vector3[]; + _SubCurves: Curve[]; + _Circles: Circle[]; + + //偏移子曲线 + _SubOffsetedCurves: IOffsetResult[]; + //用于裁剪的曲线节点 + _CurveTreeNodes: CurveTreeNode[]; + //裁剪完的曲线节点 + _CurveTrimedTreeNodes: CurveTreeNode[]; + + //裁剪轮廓 + _TrimPolylineContours: Contour[]; + _TrimCircleContours: Circle[]; + _TrimArcContours: Contour[]; + + //结果曲线 + _RetCurves: Polyline[]; + + _IsClose: boolean; + _OffsetDistSign: number; + + constructor(public _Polyline: Polyline, public _OffsetDist: number, public _ToolPath = false) { - let dir = GetPointAtCurveDir(this._Polyline, pt) ? 1 : -1; - return dir === Math.sign(this._OffsetDist); } - /** - * 优化裁剪后的曲线(删除没意义的线),合并共线 - * @param {Map} boxCurves 曲线对应的包围盒列表 - */ - private OptimizeCus(boxCurves: Map): void + Do() { - //过滤掉无效的线段 - this._RetCurves = this._RetCurves.filter(c => - { - //与源线段自交 - if (equaln(c.Length, 0, 1e-6) || c.IntersectWith(this._Polyline, IntersectOption.OnBothOperands).length !== 0) - return false; - //删除在反方向的无效线段 - return this.CheckPointDir(c.StartPoint) || this.CheckPointDir(c.EndPoint); - }); - - //处理自交的线段,先根据包围盒排序 - this._RetCurves.sort((e1, e2) => - { - let b1 = boxCurves.get(e1); - let b2 = boxCurves.get(e2); - if (!equaln(b1.min.x, b2.min.x)) - return b1.min.x - b2.min.x; - else - return b2.min.y - b1.min.y; - }); + this._OffsetDistSign = Math.sign(this._OffsetDist); + this._IsClose = this._Polyline.IsClose; + this._TrimPolylineContours = []; + this._TrimCircleContours = []; + this._TrimArcContours = []; - // 寻找自交线段 - for (let i = 0; i < this._RetCurves.length; i++) - { - let c1 = this._RetCurves[i]; - let c1b = boxCurves.get(c1); + this._RetCurves = []; + this._CurveTreeNodes = []; - for (let j = i + 1; j < this._RetCurves.length; j++) - { - let c2 = this._RetCurves[j]; - let c2b = boxCurves.get(c2); + this.InitSubCurves(); + if (this._SubCurves.length === 0) + return this._RetCurves; - //过滤掉不需要计算的曲线 - if (c2b.min.x - 1e-6 > c1b.max.x) - break; - if (c2b.min.y - 1e-6 > c1b.max.y) - continue; + this.GeneralCirclesAndVertexs(); + this.OffsetSubCurves(); + this.LinkSubCurves(); - //有共线部分才允许合并. - if (c2.PtOnCurve2(c1.StartPoint) || c2.PtOnCurve2(c1.EndPoint) - || c1.PtOnCurve2(c2.StartPoint) || c1.PtOnCurve2(c2.EndPoint) - || (c1.PtOnCurve(c2.StartPoint) && c1.PtOnCurve(c2.EndPoint)) - ) - if (c1.Join(c2) === Status.True) - { - this._RetCurves.splice(j, 1); - c1b = c1.BoundingBox; - boxCurves.set(c1, c1b); - j--; - } - } + if (this._SubOffsetedCurves.length === 0) + { + this._SubOffsetedCurves.push({ curve: this._Circles[0], index: 0, paddingCurve: this._Circles.slice(1) }); + + this._TrimPolylineContours.push( + ...this._Circles.map(c => Contour.CreateContour(c, false)), + ...this._SubCurves.map(c => Contour.CreateContour([c, new Line(c.StartPoint, c.EndPoint)], false)) + ); } + else + this.GeneralTrimContours(); + this.TrimByContours(); + this.FilterInvalidCurve(); + this.JoinCollinear(); + this.LinkResultPolyline(); + return this._RetCurves; } - //偏移曲线 - private OffestCurve(pls: Curve[]): IOffsetResult[] + InitSubCurves() { - return pls.map((cu, index) => - { - let curve = cu.GetOffsetCurves(this._OffsetDist)[0]; - return { curve, index }; - }); + this._CacheOCS = this._Polyline.OCS; + this._Polyline.OCS = IdentityMtx4; + this._SubCurves = this._Polyline.Explode().filter(c => c.Length > 1e-4); + this._Polyline.OCS = this._CacheOCS; + } + + protected GeneralCirclesAndVertexs() + { + this._Vertexs = this._SubCurves.map(c => c.StartPoint); + let lastCu = arrayLast(this._SubCurves); + if (!equalv3(lastCu.EndPoint, this._Vertexs[0], 1e-3)) + this._Vertexs.push(lastCu.EndPoint); + + let radius = Math.abs(this._OffsetDist); + this._Circles = this._Vertexs.map(p => new Circle(p, radius)); } - /** - * 根据2曲线或者一曲线一点构造轮廓 - * @private - * @param {Curve} cu - * @param {Curve} [cuOrPt] - * @returns - */ - private BuildContour(cu: Curve, cuOrPt: Curve | Vector3): Contour + protected OffsetSubCurves() { - if (cuOrPt instanceof Curve) + this._SubOffsetedCurves = []; + for (let index = 0; index < this._SubCurves.length; index++) { - let l1 = new Line(cu.StartPoint, cuOrPt.StartPoint); - let l2 = new Line(cu.EndPoint, cuOrPt.EndPoint); + let curveOld = this._SubCurves[index]; + if (curveOld.Length > 1e-6) + { + let curve = curveOld.GetOffsetCurves(this._OffsetDist)[0]; + if (curve) + this._SubOffsetedCurves.push({ curve, index }); + else + this._TrimArcContours.push(Contour.CreateContour([curveOld, new Line(curveOld.StartPoint, curveOld.EndPoint)], false)); + } + } + } - //若2曲线都是圆弧,构建轮廓可能裁剪掉圆弧,把被裁剪掉的圆弧存入数组跳过后续运算 - if (cu instanceof Arc && cuOrPt instanceof Arc) + //连接(延伸)曲线,或者补(圆弧,直线) + protected LinkSubCurves() + { + let count = this._SubOffsetedCurves.length; + if (!this._IsClose) count--; + + for (let i = 0; i < count; i++) + { + let curveResNow = this._SubOffsetedCurves[i]; + let iNext = FixIndex(i + 1, this._SubOffsetedCurves); + let curveResNext = this._SubOffsetedCurves[iNext]; + let curveNow = curveResNow.curve; + let curveNext = curveResNext.curve; + let isNeighbor = FixIndex(curveResNow.index + 1, this._SubCurves) === curveResNext.index; + + if (isNeighbor) { - //被起点连线裁剪放入前面那段,被终点连线裁剪放入后面那段 - [l1, l2].forEach((l, i) => + let sp = curveNow.EndPoint; + let ep = curveNext.StartPoint; + //直连 + if (equalv3(sp, ep, 1e-3)) + continue; + + let iPts = curveNow.IntersectWith(curveNext, IntersectOption.ExtendBoth); + let tPts = iPts.filter(p => curveNow.PtOnCurve3(p) && curveNext.PtOnCurve3(p)); + + let code = EntityEncode2(curveNow, curveNext); + + let tp: Vector3; + if (code === 1) { - let pts = l.IntersectWith(cuOrPt, 0); - if (pts.length === 2) + if (tPts.length > 0)//不走刀或者有真交点 this._ToolPath === false || + tp = iPts[0]; + else { - let splitCus = cuOrPt.GetSplitCurvesByPts(pts); - this._UnNeedCutCus.push(splitCus[i]); + if (iPts.length > 0 && curveNow.GetParamAtPoint(iPts[0]) > 1) + { + if (this._ToolPath) + { + let refP = this._Vertexs[curveResNext.index]; + curveResNow.paddingCurve = [this.CreateArc(refP, sp, ep)]; + this._TrimCircleContours.push(this._Circles[curveResNext.index]); + } + else + tp = iPts[0]; + } + // else + // curveResNow.paddingCurve = [new Line(sp, ep)]; } - }) + } + else + { + let refP = this._Vertexs[curveResNext.index]; + if (tPts.length > 0) //ipts = 1 or ipts = 2 + tp = SelectNearP(iPts, refP); + else //补单圆 或者尝试连接 + { + let arc = this.CreateArc(refP, sp, ep); + + if (iPts.length > 0 && !this._ToolPath && this.IsSharpCorner(curveResNow, curveResNext, refP)) + { + //设置新的连接点,并且备份旧点 + let oldp: Vector3; + if (curveResNow.sp) + { + oldp = curveNow.StartPoint; + curveNow.StartPoint = curveResNow.sp; + } + let oldp2: Vector3; + if (curveResNext.ep) + { + oldp2 = curveNext.EndPoint; + curveNext.EndPoint = curveResNext.ep; + } + + let p: Vector3; + + if (code === 2 && iPts.length === 2) + { + let c = curveNow as Arc; + let minArc = new Arc(c.Center, c.Radius, c.EndAngle, 0, c.IsClockWise); + + let p1 = iPts[0]; + let a1 = minArc.GetAngleAtPoint(p1); + let anAll1 = c.ParamOnCurve(c.GetParamAtAngle(a1)) ? Infinity : minArc.ComputeAnlge(a1); + + let p2 = iPts[1]; + let a2 = minArc.GetAngleAtPoint(p2); + let anAll2 = c.ParamOnCurve(c.GetParamAtAngle(a2)) ? Infinity : minArc.ComputeAnlge(a2); + + if (anAll2 < anAll1) + p = p2; + else + p = p1; + } + else + p = SelectNearP(iPts, refP); + + let onPre: boolean; + let param = curveNow.GetParamAtPoint2(p); + if (curveNow instanceof Line) + onPre = param > 1; + else + onPre = param < 0 || param > 1; + + let onNext: boolean = false; + if (onPre) + { + let param2 = curveNext.GetParamAtPoint2(p); + if (curveNext instanceof Line) + onNext = param2 < 0; + else + onNext = param2 < 0 || param2 > 1; + } + + if (curveResNow.sp) + curveNow.StartPoint = oldp; + if (curveResNext.ep) + curveNext.EndPoint = oldp2; + + if (onPre && onNext) + tp = p; + else + curveResNow.paddingCurve = [arc]; + } + else + curveResNow.paddingCurve = [arc]; + + this._TrimCircleContours.push(this._Circles[curveResNext.index]); + } + } + if (tp) + { + curveResNow.ep = tp; + curveResNext.sp = tp; + + curveResNow.nextArc = curveNext; + curveResNext.preArc = curveNow; + } } - //防止轮廓自交 - if (l1.IntersectWith(l2, 0).length > 0) + else { - l1 = new Line(cu.StartPoint, cuOrPt.EndPoint); - l2 = new Line(cu.EndPoint, cuOrPt.StartPoint); + let padCirs: Circle[] = []; + for (let s = FixIndex(curveResNow.index + 1, this._Circles); ; s = FixIndex(s + 1, this._Circles)) + { + let c = this._Circles[s]; + this._TrimCircleContours.push(c); + padCirs.push(c); + if (s === curveResNext.index) + break; + } + curveResNow.paddingCurve = padCirs; } - return Contour.CreateContour([ - cu.Clone() as Curve, - cuOrPt.Clone() as Curve, - l1, - l2 - ]); - } - else - { - let l1 = new Line(cu.StartPoint, cuOrPt); - let l2 = new Line(cu.EndPoint, cuOrPt); - return Contour.CreateContour([ - cu, - l1, - l2 - ]); + } + } - /** - *通过源线段索引或者点构建圆轮廓 - * @param {(number | Vector3)} iV 源线段索引或者圆心 - * @param {Contour[]} cons - */ - private BuildCircleContour(iV: number | Vector3, cons: Contour[]) + private IsSharpCorner(curveResNow: IOffsetResult, curveResNext: IOffsetResult, refP: Vector3): boolean { - let center: Vector3; - if (iV instanceof Vector3) - center = iV; - else - center = this._Polyline.GetPointAtParam(iV); - - let cir = new Circle(center, this._AbsDist) - cons.push(Contour.CreateContour([cir])); + let v1 = this._SubCurves[curveResNow.index].GetPointAtParam(0.9); + let v2 = this._SubCurves[curveResNext.index].GetPointAtParam(0.1); + v1.subVectors(refP, v1); + v2.sub(refP); + v1.cross(v2); + return Math.sign(v1.z) === this._OffsetDistSign; } - /** - * 连接修剪相邻曲线,并构造修剪轮廓 - */ - private TrimAndBuildContour(offResList: IOffsetResult[]) + protected GeneralTrimContours() { - arrayRemoveIf(offResList, r => !r.curve || equaln(r.curve.Length, 0, 1e-6)); - - if (offResList.length <= 1) + for (let d of this._SubOffsetedCurves) { - this._RetCurves = offResList.map(r => r.curve); - return; + let cu2 = d.curve; + if (d.sp && d.ep) + { + let param1 = cu2.GetParamAtPoint(d.sp); + let param2 = cu2.GetParamAtPoint(d.ep); + + if (cu2.ParamOnCurve(param1) && cu2.ParamOnCurve(param2) && param1 > param2) + [d.sp, d.ep] = [d.ep, d.sp]; + } + if (d.sp) cu2.StartPoint = d.sp; + if (d.ep) cu2.EndPoint = d.ep; } - let cirContours: Contour[] = []; - //下一线段起始点 - let nextStartPt: Vector3 = offResList[0].curve.StartPoint; - for (let i = 0; i < offResList.length; i++) + for (let d of this._SubOffsetedCurves) { - //源线段对应索引 - let startIndex = offResList[i].index; - //后面线对应源线段索引 - let endIndex = offResList[FixIndex(i + 1, offResList)].index; + let cu1 = this._SubCurves[d.index]; + let cu2 = d.curve; - //前面线 - let frontLine = offResList[i].curve; - //后面线 - let laterLine: Curve; + let [p1, p2, p3, p4] = [cu1.StartPoint, cu2.StartPoint, cu1.EndPoint, cu2.EndPoint]; + let l1 = new Line(p1, p2); + let l2 = new Line(p3, p4); - if (i === 0 && !this._Polyline.IsClose) + let ipts = l1.IntersectWith(l2, IntersectOption.OnBothOperands, 1e-8); + if (ipts.length > 0) { - if (startIndex !== 0) + let p = ipts[0]; + l1.EndPoint = p; + l2.EndPoint = p; + let cus = [cu1, l1, l2]; + let contour = Contour.CreateContour(cus, false); + if (contour) { - this.BuildCircleContour(1, cirContours); + this._TrimPolylineContours.push(contour); + continue; } - } - - //3.如果曲线不不闭合,那么最后一段时候退出,如果最后一段丢失,添加圆轮廓 - if (i === offResList.length - 1 && !this._Polyline.IsClose) - { - if (startIndex !== this._PtCount - 1) + else { - this.BuildCircleContour(startIndex + 1, cirContours); + console.error("未预料到的错误,构建轮廓失败" + this._OffsetDist); } - this.AppendNewCuAndContour(frontLine, nextStartPt, frontLine.EndPoint, startIndex); - break; } - laterLine = offResList[FixIndex(i + 1, offResList)].curve; - - - //#region 1.中间丢失线段的情况下且循环到尾部,补圆弧. - let isFillArc = !equalv2( - this._Polyline.GetPoint2dAt(FixIndex(startIndex + 1, this._PtCount)), - this._Polyline.GetPoint2dAt(endIndex) - ); - if (isFillArc) + //真理1:针脚线不可能同时被两个圆弧所切割 + let l1Intact = true; + let l2Intact = true; + if (cu2 instanceof Arc) { - //在丢失圆的地方构建圆轮廓 - for (let i = startIndex + 1; ; i++) - { - let index = FixIndex(i, this._PtCount); - this.BuildCircleContour(index, cirContours); - if (index === endIndex) break; - } - //丢失圆弧时在丢失圆弧的起点构造一个圆 - if (startIndex > endIndex) + if (Math.sign(cu2.Bul) !== this._OffsetDistSign) { - this.FillArc(startIndex, endIndex, nextStartPt, frontLine, laterLine); - continue; + let ipts1 = cu2.IntersectWith(l1, IntersectOption.OnBothOperands); + let ipts2 = cu2.IntersectWith(l2, IntersectOption.OnBothOperands); + + let sp: Vector3; + let ep: Vector3; + if (ipts1.length === 2) + sp = SelectNearP(ipts1, p1); + if (ipts2.length === 2) + ep = SelectNearP(ipts2, p3); + + if (sp || ep) cu2 = cu2.Clone(); + if (sp) + { + l1.EndPoint = sp; + cu2.StartPoint = sp; + l1Intact = false; + } + if (ep) + { + l2.EndPoint = ep; + cu2.EndPoint = ep; + l2Intact = false; + } } } - //#endregion - - //#region 2.修剪延伸,根据真假交点 - let iPts: Vector3[]; //延伸交点 - let tPts: Vector3[]; //都在两条线上的为真交点 - if (equalv3(frontLine.EndPoint, laterLine.StartPoint)) - tPts = [frontLine.EndPoint]; - else + let l1PadArc: Arc; + let l2PadArc: Arc; + //真理2:隔壁的圆弧不可能破坏当前的圆弧,只能破坏当前的针脚 + if (l1Intact && d.preArc && d.preArc instanceof Arc) { - iPts = frontLine.IntersectWith(laterLine, IntersectOption.ExtendBoth); - //过滤掉交点为laterline终点的交点 - tPts = iPts.filter(p => - frontLine.PtOnCurve(p) - && laterLine.PtOnCurve(p) - && !equalv3(laterLine.EndPoint, p, 1e-4) - ); - } - - if (tPts.length > 0)//存在真交点情况下直接修剪 - { - let iPt = PolyOffsetUtil.SelectFitInterPt(tPts, frontLine.EndPoint); - if (isFillArc) + let a = d.preArc; + if (Math.sign(a.Bul) !== this._OffsetDistSign) { - //用丢失圆弧和交点构建扇形轮廓 - for (let i = startIndex + 1; ; i++) + let ipts = a.IntersectWith(l1, IntersectOption.OnBothOperands); + if (ipts.length === 2) { - let index = FixIndex(i, this._PtCount); - let cu = this._Polyline.GetCurveAtParam(index); - cirContours.push(this.BuildContour(cu, iPt)); - - if (index === endIndex - 1) break; + let sp = SelectNearP(ipts, p1); + l1.EndPoint = sp; + l1PadArc = a.Clone(); + l1PadArc.StartPoint = sp; } } - this.AppendNewCuAndContour(frontLine, nextStartPt, iPt, startIndex); - } - else if (isFillArc || iPts.length === 0)//连交点都没或者圆弧丢失补圆弧 - { - this.FillArc(startIndex, endIndex, nextStartPt, frontLine, laterLine); } - else //iPts.length > 0 有交点,但是都是假交点. + if (l2Intact && d.nextArc && d.nextArc instanceof Arc) { - let iPt = PolyOffsetUtil.SelectFitInterPt(iPts, frontLine.EndPoint); - //通过真假交点连接 - this.CheckCuAndAppendList(frontLine, laterLine, iPt, nextStartPt, startIndex, endIndex); + let a = d.nextArc; + if (Math.sign(a.Bul) !== this._OffsetDistSign) + { + let ipts = a.IntersectWith(l2, IntersectOption.OnBothOperands); + if (ipts.length === 2) + { + let ep = SelectNearP(ipts, p3); + l2.EndPoint = ep; + l2PadArc = a.Clone(); + l2PadArc.EndPoint = ep; + } + } } - //#endregion + + let pl = new Polyline(); + let cus = [cu1, l1]; + if (l1PadArc) cus.push(l1PadArc); + cus.push(cu2, l2); + if (l2PadArc) cus.push(l2PadArc); + + for (let c of cus) + pl.Join(c); + + let contour = Contour.CreateContour(pl, false); + if (contour) + this._TrimPolylineContours.push(contour); + else + console.error("未预料到的错误,构建轮廓失败" + this._OffsetDist); } - //曲线闭合的时,修改第一条的起点,更新第一个轮廓 - if (this._Polyline.IsClose) + if (!this._IsClose) { - this._RetCurves[0].StartPoint = nextStartPt; - this._Contours[0] = this.BuildContour( - this._Polyline.GetCurveAtParam(offResList[0].index), - this._RetCurves[0]); - }; - cirContours = cirContours.filter(cir => cir !== undefined); - this._Contours.push(...cirContours); - } + if (this._TrimCircleContours[0] !== this._Circles[0]) + this._TrimCircleContours.push(this._Circles[0]); + let lastTrimCircle = arrayLast(this._TrimCircleContours); + let lastCircle = arrayLast(this._Circles); + if (lastTrimCircle !== lastCircle) + this._TrimCircleContours.push(lastCircle); + if (this._SubOffsetedCurves[0].index !== 0) + this._TrimCircleContours.push(this._Circles[this._SubOffsetedCurves[0].index]); + + let lastIndex = this._Circles.length - 1; + let lastD = arrayLast(this._SubOffsetedCurves); + if (lastIndex !== lastD.index) + this._TrimCircleContours.push(this._Circles[lastD.index + 1]); + } - /** - * 将线段拷贝并修改,加入到结果数组里面 - * 构建轮廓加入轮廓数组. - * - * @param {Curve} offsetedCurve 偏移后的曲线 - * @param {Vector3} startPoint 修改曲线的起点,修改后将起点设置为终点 - * @param {Vector3} endPoint 修改曲线的中点 - * @param {number} index 偏移前该线段的索引 - */ - AppendNewCuAndContour(offsetedCurve: Curve, - startPoint: Vector3, - endPoint: Vector3, - index: number - ) - { - //复制一条新曲线,修改起始点和终止点,并修改下一段的起始点 - let newCu = offsetedCurve.Clone() as Curve; - newCu.StartPoint = startPoint; - newCu.EndPoint = endPoint; - startPoint.copy(endPoint); - this._RetCurves.push(newCu); - let originCu = this._Polyline.GetCurveAtParam(index); - this._Contours.push(this.BuildContour(originCu, newCu)); + this._TrimPolylineContours.push( + ...this._TrimCircleContours.map(c => Contour.CreateContour(c, false)), + ...this._TrimArcContours + ); } - /** - * 检测偏移线段是否有效并加入结果曲线数组 - * 已经排除点都是真交点的情况 - * @param {Curve} frontLine - * @param {Curve} laterLine - * @param {Vector3} intPt - * @param {Vector3} nextPt - * @param {number} endIndex - */ - private CheckCuAndAppendList(frontLine: Curve, laterLine: Curve, intPt: Vector3, nextPt: Vector3, startIndex: number, endIndex: number) + // 通过构建的轮廓对偏移曲线进行裁剪 + protected TrimByContours() { - let par1 = frontLine.GetParamAtPoint(intPt); + for (let d of this._SubOffsetedCurves) + { + let c = d.curve; + this._CurveTreeNodes.push(new CurveTreeNode(c)); + if (d.paddingCurve) + this._CurveTreeNodes.push(...d.paddingCurve.map(c => new CurveTreeNode(c))); + } + let boxContours = SortEntityByBox(this._TrimPolylineContours, false); - //2段都是圆弧和其他情况分开判断 - if (frontLine instanceof Arc && laterLine instanceof Arc) + for (let i = 0; i < this._TrimPolylineContours.length; i++) { - let isOnFline = frontLine.PtOnCurve(intPt); - let isOnLline = laterLine.PtOnCurve(intPt); - //交点均不在2圆弧上,直接加入结果数组,否则补圆弧连接 - if (!isOnFline && !isOnLline) //可能 isOnFline || isOnLline + let c = this._TrimPolylineContours[i]; + for (let curveNode of this._CurveTreeNodes) { - this.AppendNewCuAndContour(frontLine, nextPt, intPt, startIndex); + curveNode.TrimBy(c, boxContours.get(c)); } - else + } + } + + //过滤方向相反和0长度线 + private FilterInvalidCurve() + { + this._CurveTrimedTreeNodes = []; + for (let n of this._CurveTreeNodes) + { + let ns = n.Nodes; + for (let sn of ns) { - this.FillArc(startIndex, endIndex, nextPt, frontLine, laterLine); + let p = sn.curve.GetPointAtParam(0.5); + if (sn.curve.Length > 1e-5 && this.CheckPointDir(p)) + this._CurveTrimedTreeNodes.push(sn); } } - else + } + + //合并共线 + private JoinCollinear() + { + for (let i = 0; i < this._CurveTrimedTreeNodes.length; i++) { - let par2 = laterLine.GetParamAtPoint(intPt); - if (par1 > 1) + let n = this._CurveTrimedTreeNodes[i]; + if (n.used) continue; + let sp = n.curve.StartPoint; + for (let j = i + 1; j < this._CurveTrimedTreeNodes.length; j++) { - //laterline是圆弧且都是正假交点,补圆弧,否则连接 - if (par2 > 0 && laterLine instanceof Arc) + let n2 = this._CurveTrimedTreeNodes[j]; + if (n2.used) continue; + let status = n.curve.Join(n2.curve); + if (status === Status.ConverToCircle) { - this.FillArc(startIndex, endIndex, nextPt, frontLine, laterLine); + n.used = true; + n2.used = true; + let circle = new Circle((n.curve).Center, (n.curve).Radius) + n.curve = circle; + this._RetCurves.push(ConverCircleToPolyline(circle).ApplyMatrix(this._CacheOCS)); } - else + else if (status === Status.True) { - this.AppendNewCuAndContour(frontLine, nextPt, intPt, startIndex); + if (equalv3(sp, n.curve.StartPoint)) + n2.used = true; + else + { + n.used = true; + n2.curve = n.curve; + break; + } } } - else if (frontLine instanceof Arc) - { - //其余情况如果frontline是Arc,补圆弧,否则补直线 - this.FillArc(startIndex, endIndex, nextPt, frontLine, laterLine); - } - else//frontLine is Line - { - this.AppendNewCuAndContour(frontLine, nextPt, frontLine.EndPoint, startIndex); - this._RetCurves.push(new Line(frontLine.EndPoint, laterLine.StartPoint)); - nextPt.copy(laterLine.StartPoint); - } } } - /** - * 补圆弧 - * @param {number} startIndex 源线段索引 - * @param {number} endIndex 源线段索引 - * @param {Vector3} nextPt 修改曲线的起点,修改后将起点设置为终点 - * @param {Curve} frontLine - * @param {Curve} laterLine - */ - FillArc(startIndex: number, endIndex: number, - nextPt: Vector3, - frontLine: Curve, laterLine: Curve - ) + //连接结果曲线,返回最终多段线 + private LinkResultPolyline() { - let cirs: Circle[] = []; //需要补的圆列表 - for (let i = startIndex + 1; ; i++) + let used = new Set(); + let cuMap = new CurveMap(1); + for (let n of this._CurveTrimedTreeNodes) { - let index = FixIndex(i, this._PtCount); - let center = this._Polyline.GetPointAtParam(index); - if (cirs.length === 0 || !equalv3(arrayLast(cirs).Center, center, 1e-8)) - cirs.push(new Circle(center, this._AbsDist)); - - if (index === endIndex) break; - } - //找到和frontline存在离源线段距离大于偏移距离的交点的圆,跳过这个圆前面的圆计算 - let iPts: Vector3[]; - let index = 1; - for (; index < cirs.length; index++) - { - //#I1264R - let pts = frontLine.IntersectWith(cirs[index], 1).filter(p => - { - let dist = p.distanceToSquared(this._Polyline.GetClosestPointTo(p, false)); - return dist + 1e-3 > this._Dist2; - }); - if (pts.length === 0) - { - break; - } - else - iPts = pts; + if (!n.used) + cuMap.AddCurveToMap(n.curve); } - if (iPts) - cirs.splice(0, index - 1); - else - iPts = [frontLine.EndPoint]; - let iPt = PolyOffsetUtil.SelectFitInterPt(iPts, frontLine.EndPoint); - this.AppendNewCuAndContour(frontLine, nextPt, iPt, startIndex); + let preP: Vector3; - //连接剩下的圆. - //可能的情况 (|)()(|)() 竖线为直线 - for (let index = 0; index < cirs.length; index++) + let searchNext = (s: Stand, pl: Polyline): Stand => { - let c1 = cirs[index];//已经计算过的圆 - - let iPtsLater: Vector3[]; - if (index === cirs.length - 1) - iPtsLater = [laterLine.StartPoint]; - else + let minDist = Infinity; + let minR: Route; + for (let r of s.routes) { - //和前面圆的交点需要大于偏移距离才能提前相交 - iPtsLater = c1.IntersectWith(laterLine, 0).filter(p => + if (used.has(r.curve)) continue; + + if (preP) { - let dist = p.distanceToSquared(this._Polyline.GetClosestPointTo(p, false)); - return dist + 1e-3 > this._Dist2; - }); + let d = r.s.distanceToSquared(preP); + if (d < minDist) + { + minR = r; + minDist = d; + } + } + else + { + minR = r; + break; + } } - if (iPtsLater.length > 0)//直接和最后一条连接 + if (minR) { - let iPt = PolyOffsetUtil.SelectFitInterPt(iPtsLater, nextPt); - this.BuildArcJoinList(c1, nextPt, iPt, FixIndex(startIndex + 1, this._PtCount) === endIndex); - return; + used.add(minR.curve); + preP = minR.e; + let status = pl.Join(minR.curve, false, 1e-3); + if (status !== Status.True) + console.warn("连接失败"); + return minR.to; } + }; - let c2 = cirs[index + 1]; - - let selectPts: Vector3[] = []; - let iPts = c1.IntersectWith(c2, 0); - //#I1264R 第一条补圆弧并且frontline是直线,尽量让圆弧方向和直线一致 - if (index === 0 && frontLine instanceof Line) + for (let s of cuMap.Stands) + { + preP = undefined; + let pl = new Polyline(); + let ss = s; + while (ss) + ss = searchNext(ss, pl); + ss = s; + while (ss) + ss = searchNext(ss, pl); + + if (pl.NumberOfVertices > 0) { - let derv = frontLine.GetFistDeriv(1); - selectPts = iPts.filter(p => p.clone().sub(nextPt).angleTo(derv) < Math.PI / 2); + let d = pl.LineData; + let ld = arrayLast(d); + if (equalv2(d[0].pt, ld.pt, 1e-2)) + ld.pt.copy(d[0].pt); + this._RetCurves.push(pl.ApplyMatrix(this._CacheOCS)); } - - let iPt = PolyOffsetUtil.SelectFitInterPt(selectPts.length > 0 ? selectPts : iPts, nextPt); - this.BuildArcJoinList(c1, nextPt, iPt, FixIndex(startIndex + 1, this._PtCount) === endIndex); } } - /** - * 构建补圆弧 - * @param {Circle} cir 补圆 - * @param {Vector3} startPt 补圆的切割点1 - * @param {Vector3} endPt 补圆的切割点2 - * @param {boolean} isbuildCir 是否构建圆轮廓 - */ - BuildArcJoinList(cir: Circle, startPt: Vector3, endPt: Vector3, isbuildCir: boolean) + CheckPointDir(pt: Vector3): boolean { - let splitCus = cir.GetSplitCurvesByPts([startPt, endPt]); - - startPt.copy(endPt); + return this.GetPointAtCurveDir(pt) === this._OffsetDistSign; + } - if (splitCus.length === 2) //2圆相交应该有2段,否则相切 + GetPointAtCurveDir(pt: Vector3): number + { + let minIndex = Infinity; + let minDist = Infinity; + let minCp: Vector3; + for (let i = 0; i < this._SubCurves.length; i++) { - let arc1 = splitCus[0] as Arc; - let arc2 = splitCus[1] as Arc; + let c = this._SubCurves[i]; + let cp = c.GetClosestPointTo(pt, false); + if (equalv3(cp, pt)) return 0; - let tmpPts = cir.IntersectWith(this._Polyline, IntersectOption.OnBothOperands); - let onCu0Pts = tmpPts.filter(p => arc1.PtOnCurve(p)); - let onCu1Pts = tmpPts.filter(p => arc2.PtOnCurve(p)); + let dist = cp.distanceToSquared(pt); + if (dist < minDist) + { + minDist = dist; + minIndex = i; + minCp = cp; + } + } - let lastCu = arrayLast(this._RetCurves); + let c = this._SubCurves[minIndex]; + let param = c.GetParamAtPoint(minCp); - //让圆弧保持和最后一段首尾相连 - if (!equalv3(arc1.StartPoint, lastCu.EndPoint)) - arc1.Reverse(); - if (!equalv3(arc2.StartPoint, lastCu.EndPoint)) - arc2.Reverse(); + if (equaln(param, 0) && ((minIndex === 0) ? this._IsClose : true)) + { + let preIndex = FixIndex(minIndex - 1, this._SubCurves); + let preCurve = this._SubCurves[preIndex]; - //优先选择和源线段不想交的圆弧,如果都相交或者都不相交,选择和最后一段切线接近的圆弧 - let cu: Arc; - if (onCu0Pts.length === onCu1Pts.length) - { - let derv = lastCu.GetFistDeriv(1); - let derv1 = arc1.GetFistDeriv(0); - let derv2 = arc2.GetFistDeriv(0); - cu = derv.angleTo(derv1) < derv.angleTo(derv2) ? arc1 : arc2; - } - else + if (!equalv3(c.GetFistDeriv(0).normalize(), preCurve.GetFistDeriv(1).normalize())) { - cu = onCu0Pts.length < onCu1Pts.length ? arc1 : arc2; - } + let p = c.StartPoint; + let l1 = c.Length; + let l2 = preCurve.Length; + let minLength = Math.min(l1, l2) * 0.2; + + let nextP: Vector3; + let preP: Vector3; + if (c instanceof Arc) + nextP = c.GetPointAtDistance(minLength); + else + nextP = c.EndPoint; - this._RetCurves.push(cu); + if (preCurve instanceof Arc) + preP = preCurve.GetPointAtDistance(l2 - minLength); + else + preP = preCurve.StartPoint; - isbuildCir && this.BuildCircleContour(cu.Center, this._Contours); - } - } + let arc = new Arc(p, 1, angle(preP.sub(p)), angle(nextP.sub(p))); - // 通过构建的轮廓对偏移曲线进行裁剪 - private TrimByContours() - { - let boxContours = SortEntityByBox(this._Contours, false); - let boxCurves = SortEntityByBox(this._RetCurves, false); - this._Contours.forEach(c => + let dir = arc.PtOnCurve3(pt) ? -1 : 1; + return dir; + } + } + else if (equaln(param, 1) && ((minIndex === this._SubCurves.length - 1) ? this._IsClose : true)) { - let tmpCus: Curve[] = []; - let outline = c.Curve; - for (let l of this._RetCurves) + let nextIndex = FixIndex(minIndex + 1, this._SubCurves); + let nextCurve = this._SubCurves[nextIndex]; + + if (!equalv3(c.GetFistDeriv(1).normalize(), nextCurve.GetFistDeriv(0).normalize())) { - if (boxCurves.get(l).min.x > boxContours.get(c).max.x - || boxCurves.get(l).max.x < boxContours.get(c).min.x) - { - tmpCus.push(l); - continue; - } + let p = c.EndPoint; - //交点参数列表 - let iParams = l.IntersectWith(outline, IntersectOption.OnBothOperands) - .map(p => l.GetParamAtPoint(p)); - arraySortByNumber(iParams); - arrayRemoveDuplicateBySort(iParams, equaln); - - //需要计算的点列表 - let needCaclPts: Vector3[] = []; - if (iParams.length === 0) - needCaclPts = [l.StartPoint]; - else - { - for (let i = 0; i < iParams.length - 1; i++) - { - needCaclPts.push(l.GetPointAtParam((iParams[i] + iParams[i + 1]) / 2)); - } - //如果交点不是首尾点,就加入首尾点 - if (!equaln(iParams[0], 0, 1e-6)) - needCaclPts.unshift(l.StartPoint); - if (!equaln(arrayLast(iParams), 1, 1e-6)) - needCaclPts.push(l.EndPoint); - } + let l1 = c.Length; + let l2 = nextCurve.Length; + let minLength = Math.min(l1, l2) * 0.2; - //切割曲线,缓存切割后曲线包围盒 - if (IsPtsAllOutOrOnReg(outline, needCaclPts)) - { - tmpCus.push(l); - } + let nextP: Vector3; + let preP: Vector3; + if (c instanceof Arc) + preP = c.GetPointAtDistance(l1 - minLength); else - { - let cus = l.GetSplitCurves(iParams); - - //移除0长度线和在轮廓内的线. - arrayRemoveIf(cus, cu => - equaln(cu.Length, 0, 1e-6) - || outline.PtInCurve(cu.GetPointAtParam(0.5)) - ); - cus.forEach(c => boxCurves.set(c, c.BoundingBox)) - tmpCus.push(...cus); - } - } - this._RetCurves = tmpCus; - }) + preP = c.StartPoint; - //最后也加入优化数组,避免出错 - this._UnNeedCutCus.forEach(cu => - { - boxCurves.set(cu, cu.BoundingBox); - this._RetCurves.push(cu); - }); + if (nextCurve instanceof Arc) + nextP = nextCurve.GetPointAtDistance(minLength); + else + nextP = nextCurve.EndPoint; - return boxCurves; - } + let arc = new Arc(p, 1, angle(preP.sub(p)), angle(nextP.sub(p))); - /** - * 连接最终曲线 - * @param {Curve[]} cus - */ - private LinkCurves() - { - let groups = curveLinkGroup(this._RetCurves); - let resultPls: Polyline[] = []; - for (let g of groups) - { - let pl = new Polyline(); - for (let cu of g) - pl.Join(cu); - resultPls.push(pl); + let dir = arc.PtOnCurve3(pt) ? -1 : 1; + return dir; + } } - this._RetCurves = resultPls; + + let dri = c.GetFistDeriv(param); + let cross = dri.cross(pt.clone().sub(minCp)); + return -Math.sign(cross.z); } - /** - * 选择合适的交点 - * @param {Vector3[]} pts - * @param {Vector3} refPt - */ - static SelectFitInterPt(pts: Vector3[], refPt: Vector3) + protected CreateArc(center: Vector3, startP: Vector3, endP?: Vector3) { - if (pts.length > 1) - { - let dist1 = refPt.distanceToSquared(pts[0]); - let dist2 = refPt.distanceToSquared(pts[1]); - return dist1 <= dist2 ? pts[0] : pts[1]; - } - return pts[0]; + let sa = angle(startP.clone().sub(center)); + let ea = endP ? angle(endP.clone().sub(center)) : sa; + let arc = new Arc(center, Math.abs(this._OffsetDist), sa, ea, this._OffsetDist < 0); + return arc; } } + +function EntityEncode(c: Curve) +{ + if (c instanceof Line) return 1; + else return 2; +} +function EntityEncode2(c1: Curve, c2: Curve) +{ + return EntityEncode(c1) & EntityEncode(c2); +} diff --git a/src/GraphicsSystem/ToolPath/FeedingToolPath.ts b/src/GraphicsSystem/ToolPath/FeedingToolPath.ts index 01251b9d9..6796f7242 100644 --- a/src/GraphicsSystem/ToolPath/FeedingToolPath.ts +++ b/src/GraphicsSystem/ToolPath/FeedingToolPath.ts @@ -1,16 +1,16 @@ +import { Vector3 } from "three"; +import { IsRect, equalCurve } from "../../Common/CurveUtils"; import { Singleton } from "../../Common/Singleton"; +import { Contour } from "../../DatabaseServices/Contour"; import { Board, IModeling } from "../../DatabaseServices/Entity/Board"; import { Circle } from "../../DatabaseServices/Entity/Circle"; -import { Contour } from "../../DatabaseServices/Contour"; import { Curve } from "../../DatabaseServices/Entity/Curve"; import { Polyline } from "../../DatabaseServices/Entity/Polyline"; import { Shape } from "../../DatabaseServices/Shape"; import { ShapeManager } from "../../DatabaseServices/ShapeManager"; -import { BoolOpeartionType } from "../BoolOperateUtils"; -import { OptimizeToolPath } from "./OptimizeToolPath"; -import { equalCurve, IsRect } from "../../Common/CurveUtils"; -import { Vector3 } from "three"; -import { RegionParse } from "../../Geometry/RegionParse"; +import { RegionParse, Route } from "../../Geometry/RegionParse"; +import { BoolOpeartionType, isTargetCurInOrOnSourceCur } from "../BoolOperateUtils"; +import { GetCurveToInDir, OptimizeToolPath, GetOffsetCurves } from "./OptimizeToolPath"; /** *计算走刀工具类 @@ -27,40 +27,30 @@ export class FeedingToolPath extends Singleton { let outline = shape.Outline.Curve.Clone(); - let dir = this.GetCurveToInDir(outline); + let dir = GetCurveToInDir(outline); let offsetCus: Curve[] = [outline]; - //偏移后不闭合的走刀路径 - let uncloseCurves: Curve[] = []; //获得形状外孔轮廓 let holes: Contour[] = []; + /**用于判断孤岛是否与外轮廓相交 */ + let holeOffsetCus: Curve[] = []; + for (let h of shape.Holes) { if (!isOut) holes.push(h.Clone()); else { - let dir = -this.GetCurveToInDir(h.Curve); - let tmpCus: Curve[]; - if (h.Curve instanceof Polyline) - { - tmpCus = h.Curve.GetFeedingToolPath(knifRadius * dir); - if (tmpCus[0] instanceof Polyline && !tmpCus[0].IsClose) - { - uncloseCurves.push(tmpCus[0]); - let reg = new RegionParse(tmpCus[0].Explode() as Curve[], 3); - tmpCus.length = 0; - for (let routes of reg.RegionsOutline) - for (let r of routes) - tmpCus.push(r.curve); - } - } + let dir = -GetCurveToInDir(h.Curve); + let cus: Curve[]; + if (h.Curve instanceof Circle) + cus = h.Curve.GetOffsetCurves(knifRadius * dir); else - tmpCus = h.Curve.GetOffsetCurves(knifRadius * dir); + cus = h.Curve.GetFeedingToolPath(knifRadius * dir); + + holeOffsetCus.push(...h.Curve.GetOffsetCurves(knifRadius * dir).filter(c => c.IsClose)); - let con = Contour.CreateContour(tmpCus); - if (con) - holes.push(con); + holes.push(...this.GetContours(cus as Polyline[], offsetCus)); } } @@ -71,7 +61,7 @@ export class FeedingToolPath extends Singleton offsetDist += knifRadius; let retCus: Curve[] = []; - if (outline instanceof Polyline && isOut && offsetDist === knifRadius) + if (outline instanceof Polyline) retCus.push(...outline.GetFeedingToolPath(offsetDist * dir)); else retCus.push(...outline.GetOffsetCurves(offsetDist * dir)); @@ -82,12 +72,11 @@ export class FeedingToolPath extends Singleton let isInt = false; for (let c of retCus) { - if (holes.length > 0 && c.IsClose) + if (holes.length > 0) { isInt = holes.some(h => h.Curve.IntersectWith(c, 0).length > 0 || h.CuInOutline(c)); if (isInt) break; } - c.ColorIndex = outline.ColorIndex; offsetCus.push(c); } @@ -97,7 +86,8 @@ export class FeedingToolPath extends Singleton let holesMg = new ShapeManager(); holesMg.AppendShapeList(holes.map(h => new Shape(h))); let shapeMg = new ShapeManager(); - shapeMg.AppendShapeList(retCus.map(c => new Shape(Contour.CreateContour([c])))); + let cons = this.GetContours(retCus as Polyline[], offsetCus); + shapeMg.AppendShapeList(cons.map(c => new Shape(c))); shapeMg.BoolOper(holesMg, BoolOpeartionType.Subtract); for (let s of shapeMg.ShapeList) { @@ -107,54 +97,48 @@ export class FeedingToolPath extends Singleton break; } } + let vailHoles: Contour[] = []; - for (let h of holes) + for (let i = 0; i < holes.length; i++) { + let h = holes[i] //如果加工洞外圈和最外轮廓相交,则去掉 if (h.Curve.IntersectWith(outline, 0).length > 0) continue; - let isVail = true; //若最外轮廓内偏移一个刀半径的曲线 和最内轮廓相交或者被包含,则去掉.且不与洞曲线相等 if (isOut) { - let tmpCus = outline.GetOffsetCurves(dir * offsetDist); - for (let c of tmpCus) + let outlineOffsetCus = outline.GetOffsetCurves(dir * knifRadius).filter(c => c.IsClose); + let outlineCus = GetOffsetCurves(outline, dir * knifRadius); + for (let j = 0; j < outlineOffsetCus.length; j++) { - if (h.Curve.IntersectWith(c, 0).length > 0) + let c = outlineOffsetCus[j]; + let ho = holeOffsetCus[i]; + if (h.Curve.IntersectWith(outlineCus[j], 0).length > 0) { - if (!(offsetDist === knifRadius && equalCurve(h.Curve, c))) + if (!(equalCurve(ho, c) || isTargetCurInOrOnSourceCur(c as Polyline, h.Curve))) { isVail = false; break; } } - else if (h.Area > c.Area) + else if (ho.Area > c.Area) { isVail = false; break; } } - } if (isVail) - offsetCus.push(h.Curve); + vailHoles.push(h); } + if (isOut) + vailHoles = Shape.mergeContours(vailHoles); - offsetCus.push(...uncloseCurves); - + offsetCus.push(...vailHoles.map(h => h.Curve)); return offsetCus; } - /** - * 获得曲线内偏移方向 - */ - private GetCurveToInDir(cu: Curve): number - { - let dir = -Math.sign(cu.Area2); - if (cu instanceof Circle) - dir = -1; - return dir; - } /**用于测试走刀路径 */ TestCalcPath(br: Board) { @@ -211,7 +195,7 @@ export class FeedingToolPath extends Singleton { //通孔只切一刀 let outline = shape.Outline.Curve; - let dir = this.GetCurveToInDir(outline); + let dir = GetCurveToInDir(outline); let paths: Curve[]; if (outline instanceof Circle) paths = outline.GetOffsetCurves(dir * knifeRadius); @@ -256,4 +240,45 @@ export class FeedingToolPath extends Singleton } } } + private GetContours(cus: (Polyline | Circle)[], retCus: Curve[]) + { + let cons: Contour[] = []; + for (let c of cus) + { + if (c.IsClose) + { + cons.push(Contour.CreateContour(c)); + } + else + { + let expCus = c.Explode() as Curve[]; + let regParse = new RegionParse(expCus); + + //分析封闭包围区域 + const parseRoute = (routeSet: Set[]) => + { + for (let routes of routeSet) + { + let cs: Curve[] = []; + for (let r of routes) + cs.push(r.curve); + let c = Contour.CreateContour(cs, false); + if (c && c.Area > 1e-3) + cons.push(c); + } + } + parseRoute(regParse.RegionsOutline); + parseRoute(regParse.RegionsInternal); + for (let c of expCus) + { + if (!regParse.GetCueveUsed(c)) + { + retCus.push(c); + } + } + + } + } + return cons; + } } diff --git a/src/GraphicsSystem/ToolPath/OptimizeToolPath.ts b/src/GraphicsSystem/ToolPath/OptimizeToolPath.ts index 7661c32f1..9a5931e4b 100644 --- a/src/GraphicsSystem/ToolPath/OptimizeToolPath.ts +++ b/src/GraphicsSystem/ToolPath/OptimizeToolPath.ts @@ -1,12 +1,12 @@ -import { Curve } from "../../DatabaseServices/Entity/Curve"; -import { Shape } from "../../DatabaseServices/Shape"; +import { arrayRemoveIf } from "../../Common/ArrayExt"; +import { ConverCircleToPolyline, curveLinkGroup, equalCurve } from "../../Common/CurveUtils"; import { matrixAlignCoordSys } from "../../Common/Matrix4Utils"; -import { curveLinkGroup, ConverCircleToPolyline, equalCurve } from "../../Common/CurveUtils"; -import { Line } from "../../DatabaseServices/Entity/Line"; import { Circle } from "../../DatabaseServices/Entity/Circle"; +import { Curve } from "../../DatabaseServices/Entity/Curve"; +import { Line } from "../../DatabaseServices/Entity/Line"; import { Polyline } from "../../DatabaseServices/Entity/Polyline"; -import { comparePoint, AsVector3, AsVector2 } from "../../Geometry/GeUtils"; -import { arrayLast, arrayRemoveIf } from "../../Common/ArrayExt"; +import { Shape } from "../../DatabaseServices/Shape"; +import { AsVector2, AsVector3, comparePoint } from "../../Geometry/GeUtils"; /** * 优化走刀路径,连接偏移后的曲线数组 @@ -15,7 +15,7 @@ import { arrayLast, arrayRemoveIf } from "../../Common/ArrayExt"; * @param rad 刀半径 * @returns tool path */ -export function OptimizeToolPath(offsetCus: Curve[], originShape: Shape, rad: number, isTest = false): Curve[] +export function OptimizeToolPath(offsetCus: Curve[], originShape: Shape, rad: number): Curve[] { // 去掉最外轮廓 let outline = offsetCus.shift(); @@ -46,7 +46,13 @@ export function OptimizeToolPath(offsetCus: Curve[], originShape: Shape, rad: nu if (noCloseCus.length > 0) { let culist: Curve[] = []; - noCloseCus.forEach(c => culist.push(...c.Explode() as Curve[])); + noCloseCus.forEach(c => + { + if (c instanceof Polyline) + culist.push(...c.Explode() as Curve[]); + else + culist.push(c); + }); //移除相等的曲线避免重复走刀 RempveEqualCurves(culist); let groups = curveLinkGroup(culist); @@ -61,8 +67,10 @@ export function OptimizeToolPath(offsetCus: Curve[], originShape: Shape, rad: nu plList.push(pl); } } + let dir = GetCurveToInDir(outline); + let cantIntCur: Curve[] = []; + cantIntCur.push(...GetOffsetCurves(outline, rad * dir)); - let cantIntCur: Curve[] = [outline]; if (originShape.Holes.length > 0) { for (let h of originShape.Holes) @@ -70,7 +78,7 @@ export function OptimizeToolPath(offsetCus: Curve[], originShape: Shape, rad: nu let dir = Math.sign(h.Curve.Area2); if (h.Curve instanceof Circle) dir = 1; - cantIntCur.push(...h.Curve.GetOffsetCurves(rad * dir)); + cantIntCur.push(...GetOffsetCurves(h.Curve, rad * dir)); } } @@ -91,7 +99,7 @@ export function OptimizeToolPath(offsetCus: Curve[], originShape: Shape, rad: nu let isDisVail = false; - isDisVail = cantIntCur.some(c => c.IntersectWith(refLine, 0).length > 0); + isDisVail = cantIntCur.some(c => c.IntersectWith(refLine, 0).length > 1); if (isDisVail) { @@ -170,43 +178,42 @@ function ChangePlListStartPt(plList: Polyline[]) } } } + /** * 排序多段线数组,按照起点之间的距离 - * @param plList */ -function SortPlByStartPt(plList: Polyline[]) +function SortPlByStartPt(pls: Polyline[]): Polyline[] { - if (plList.length <= 1) return plList; + if (pls.length <= 1) return pls; - let result = [plList[0]]; - let usedPl = new WeakSet([plList[0]]); + let result = [pls[0]]; + let usedPl = new WeakSet([pls[0]]); + let p = pls[0].StartPoint; while (true) { - if (plList.length === result.length) + if (pls.length === result.length) break; - let refPt = arrayLast(result).StartPoint; let vaildPl: Polyline; - let refDist: number; - for (let pl of plList) + let minDist: number = Infinity; + for (let pl of pls) { if (usedPl.has(pl)) continue; - let sPt = pl.StartPoint; - - if (!refDist || sPt.distanceToSquared(refPt) < refDist) + let dist = pl.StartPoint.distanceToSquared(p); + if (dist < minDist) { - refDist = sPt.distanceToSquared(refPt); + minDist = dist; vaildPl = pl; } } - + p = vaildPl.StartPoint; result.push(vaildPl); usedPl.add(vaildPl); } - plList.length = 0; - plList.push(...result); + pls.length = 0; + pls.push(...result); } function RempveEqualCurves(cus: Curve[]) @@ -228,3 +235,17 @@ function RempveEqualCurves(cus: Curve[]) } arrayRemoveIf(cus, (c) => needRemoveCurve.has(c)); } + +export function GetOffsetCurves(cu: Curve, dist: number): Curve[] +{ + if (cu instanceof Polyline) + return cu.GetFeedingToolPath(dist); + else + return cu.GetOffsetCurves(dist); +} + +/** 获得曲线内偏移方向*/ +export function GetCurveToInDir(cu: Curve): number +{ + return cu.IsClockWise ? 1 : -1; +}