From d25da19efff79fca923e574b66e225d65c5c9beb Mon Sep 17 00:00:00 2001 From: ChenX Date: Tue, 11 Jul 2023 02:55:06 +0000 Subject: [PATCH] =?UTF-8?q?!2287=20=E4=BF=AE=E5=A4=8D:=E5=9C=86=E5=BC=A7?= =?UTF-8?q?=E5=81=8F=E7=A7=BB=E8=B7=9D=E7=A6=BB=E4=B8=8D=E4=B8=80=E8=87=B4?= =?UTF-8?q?=E6=97=B6,=E6=97=A0=E6=B3=95=E8=AE=A1=E7=AE=97=E5=B0=81?= =?UTF-8?q?=E8=BE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../__snapshots__/seal.test.ts.snap | 20 +++++++++ __test__/EdgeSealing/seal.test.ts | 20 +++++++++ __test__/Polyline/offset.test.ts | 1 + src/Add-on/TestFb.ts | 5 ++- src/Add-on/test/TestUtil.ts | 2 + src/Common/Log.ts | 1 + src/Common/Toaster.ts | 7 +++ src/GraphicsSystem/CalcEdgeSealing.ts | 44 ++++++++++++++++--- src/GraphicsSystem/OffsetPolyline.ts | 36 +++++++++++---- .../ToolPath/FeedingToolPath.ts | 5 +-- 10 files changed, 123 insertions(+), 18 deletions(-) diff --git a/__test__/EdgeSealing/__snapshots__/seal.test.ts.snap b/__test__/EdgeSealing/__snapshots__/seal.test.ts.snap index f9c6b87cc..b7beeff75 100644 --- a/__test__/EdgeSealing/__snapshots__/seal.test.ts.snap +++ b/__test__/EdgeSealing/__snapshots__/seal.test.ts.snap @@ -1,5 +1,25 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`圆弧连接,连接失败了强行连接 1`] = `"420668.28959"`; + +exports[`圆弧连接,连接失败了强行连接 2`] = `"421170.51803"`; + +exports[`圆弧连接,连接失败了强行连接 3`] = `"5"`; + +exports[`圆弧连接,连接失败了强行连接 4`] = `"5"`; + +exports[`圆弧连接,连接失败了强行连接 5`] = `"5"`; + +exports[`圆弧连接,连接失败了强行连接 6`] = `"173013.57414"`; + +exports[`圆弧连接,连接失败了强行连接 7`] = `"175223.47125"`; + +exports[`圆弧连接,连接失败了强行连接 8`] = `"6"`; + +exports[`圆弧连接,连接失败了强行连接 9`] = `"5"`; + +exports[`圆弧连接,连接失败了强行连接 10`] = `"5"`; + exports[`封边 1`] = `"3274.96050"`; exports[`封边 2`] = `"3282.89002"`; diff --git a/__test__/EdgeSealing/seal.test.ts b/__test__/EdgeSealing/seal.test.ts index 3cee05c7a..490e8fd14 100644 --- a/__test__/EdgeSealing/seal.test.ts +++ b/__test__/EdgeSealing/seal.test.ts @@ -64,3 +64,23 @@ test('特殊链接 圆弧间', () => expect(seald.highSeals.length).toMatchNumberSnapshot(0); }); + + +test('圆弧连接,连接失败了强行连接', () => +{ + + let d = + { "file": [2, "Board", 10, 2, 250, 0, 1, 2, 71, [0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 5420.396189184161, -2536.8980307174484, 0, 1], 0, 0, 1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5420.396189184161, -2536.8980307174484, 0, 1], 0, 0, 1, 3, 827.7272727272722, 600.0000000000002, 18, false, "Polyline", 10, 2, 0, 0, 0, 7, 71, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 0, 0, 1, [0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, -172.0808080808082, 47706.26352358669, 4737.41794856498, 1], 0, 0, 1, 2, 5, [363.08080808080774, 0], 0, [600.0000000000001, 0], 0, [600.0000000000002, 827.7272727272721], 0, [1.4210854715202004e-13, 827.7272727272721], 0, [0, 326.3131313131307], -0.20262143281721134, true, 0, 3, 0, 0, 0, 0, 0, 11, 0, "层板", "", "", "", "", "", 0, 0, "三合一", 2, 5, 0, 0, 0, 0, 1, "0", "0", "0", "0", "", "", "", 5, "三合一", "三合一", "三合一", "三合一", "三合一", true, true, 1, "1", "1", 0, 0, 0, 0, 0, 0, 0, true, 0, 0, null, "Board", 10, 2, 445, 0, 1, 2, 71, [0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 1480.3203606069178, 844.0742138083208, 0, 1], 0, 0, 1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1480.3203606069178, 844.0742138083208, 0, 1], 0, 0, 1, 3, 705.3016287401363, 763.5607321131454, 18, false, "Polyline", 10, 2, 0, 0, 0, 7, 71, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 0, 0, 1, [0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, -1363.0853726921553, -1423.7469138504698, 0, 1], 0, 0, 1, 2, 5, [763.5607321131454, -2.2737367544323206e-13], 0, [600.0000000000007, 705.301628740136], 0, [600.0000000000007, 301.23270721914173], 0.3784142003682244, [440.4202016404272, 480.2205344191484], 0, [0, 359.0682196339435], 0, true, 0, 3, 0, 0, 0, 0, 0, 11, 0, "层板", "", "", "", "", "", 0, 0, "三合一", 2, 5, 0, 0, 2, 0, 2, "0", "2", "2", "0", "", "", "", 5, "三合一", "三合一", "三合一", "三合一", "三合一", true, true, 0, 0, 0, 0, 0, 0, 0, 0, true, 0, 0, null], "basePt": { "x": 775.0187318667815, "y": -2536.8980307174484, "z": 0 }, "ucs": [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1] }; + let brs = LoadEntityFromFileData(d) as Board[]; + for (let br of brs) + { + let seald = GetSealedBoardContour(br); + expect(seald.sealedContour.Area2).toMatchNumberSnapshot(); + expect(seald.brContour.Area2).toMatchNumberSnapshot(); + + expect(seald.sealedContour.EndParam).toMatchNumberSnapshot(0); + expect(seald.brContour.EndParam).toMatchNumberSnapshot(0); + + expect(seald.highSeals.length).toMatchNumberSnapshot(0); + } +}); diff --git a/__test__/Polyline/offset.test.ts b/__test__/Polyline/offset.test.ts index c335bb40e..d6cab8a11 100644 --- a/__test__/Polyline/offset.test.ts +++ b/__test__/Polyline/offset.test.ts @@ -884,6 +884,7 @@ test('多段线因为合并问题造成的错误', () => testOffset(pl, 37.8831); }); +//TODO: 这么小的测试用例似乎是没有意义的 test("正确的裁剪多段线", () => { let pl = loadFile( diff --git a/src/Add-on/TestFb.ts b/src/Add-on/TestFb.ts index 51722495f..45ccc0f92 100644 --- a/src/Add-on/TestFb.ts +++ b/src/Add-on/TestFb.ts @@ -1,5 +1,6 @@ import { Vector3 } from "three"; import { app } from "../ApplicationServices/Application"; +import { Log } from "../Common/Log"; import { Intent, ToasterShowEntityMsg } from "../Common/Toaster"; import { FixedNotZero } from "../Common/Utils"; import { Board } from "../DatabaseServices/Entity/Board"; @@ -39,7 +40,7 @@ export class TestFb implements Command if (sealData) { let { brContour: brCon, sealedContour: sealedCon } = sealData; - sealedCon.ColorIndex = 8;//红色 扣封边的 + sealedCon.ColorIndex = 1;//红色 扣封边的 showCus.push(brCon, sealedCon); brSealMap.set(brCon, sealData); } @@ -69,6 +70,8 @@ export class TestFb implements Command let moveDist = 0;//x move let moveV = new Vector3();// + Log("红色为扣完封边的轮廓!"); + for (let i = 0; i < showCus.length; i++) { let curve = showCus[i]; diff --git a/src/Add-on/test/TestUtil.ts b/src/Add-on/test/TestUtil.ts index 1bee3e40e..d1769cd36 100644 --- a/src/Add-on/test/TestUtil.ts +++ b/src/Add-on/test/TestUtil.ts @@ -3,6 +3,8 @@ import { Entity } from "../../DatabaseServices/Entity/Entity"; export async function TestDraw(en: Entity | Entity[] | Object3D | Object3D[], colorIndex = 0) { + if (!(globalThis.document && globalThis.document.getElementById("Webgl"))) return; + let app = (await import("../../ApplicationServices/Application"))?.app; if (!app) return; diff --git a/src/Common/Log.ts b/src/Common/Log.ts index e0b200c55..da3b306bd 100644 --- a/src/Common/Log.ts +++ b/src/Common/Log.ts @@ -19,6 +19,7 @@ export function Log(message?: any, ...optionalParams: any[]): void export const _LogInjectInteractionFunctions: LogFunction[] = []; +//InteractionLog([{ msg: "警告:" }, { msg: `板件${br.Name}`, entity: [br, cyHole] }, { msg: "侧孔与板无交点,无法加工该侧孔!" }], LogType.Warning); export function InteractionLog(message?: any, ...optionalParams: any[]): void { for (let f of _LogInjectInteractionFunctions) diff --git a/src/Common/Toaster.ts b/src/Common/Toaster.ts index 9da2ea584..ac062a0e7 100644 --- a/src/Common/Toaster.ts +++ b/src/Common/Toaster.ts @@ -1,5 +1,7 @@ //为了避免Core对UI库的依赖,导致测试用例失败,导致外部项目引用失败,我们分离了这个函数 +import { InteractionLog, LogType } from "./Log"; + export enum Intent { NONE = "none", @@ -47,4 +49,9 @@ export function ToasterShowEntityMsg(option: { { for (let f of ToasterShowEntityMsgInjectFunctions) f(option); + + let logMsgs = [{ msg: option.msg }] as any[]; + if (option.ent) + logMsgs.push({ msg: "点击查看", entity: Array.isArray(option.ent) ? option.ent : [option.ent] }); + InteractionLog(logMsgs, LogType.Warning); } diff --git a/src/GraphicsSystem/CalcEdgeSealing.ts b/src/GraphicsSystem/CalcEdgeSealing.ts index bca175ca1..b95cb972a 100644 --- a/src/GraphicsSystem/CalcEdgeSealing.ts +++ b/src/GraphicsSystem/CalcEdgeSealing.ts @@ -2,6 +2,8 @@ import { Vector3 } from "three"; import { arrayRemoveIf } from "../Common/ArrayExt"; import { EBoardKeyList } from "../Common/BoardKeyList"; import { MergeCurvelist } from "../Common/CurveUtils"; +import { InteractionLog, LogType } from "../Common/Log"; +import { Intent, Toaster } from "../Common/Toaster"; import { FixIndex } from "../Common/Utils"; import { Contour } from "../DatabaseServices/Contour"; import { Board } from "../DatabaseServices/Entity/Board"; @@ -282,7 +284,26 @@ class OffsetPolyline2 extends OffsetPolyline /** - * 计算封边轮廓 + * 获取板件的轮廓(没有扣封边)(拆单时表现) + * 在拆单的时候 我们用这个轮廓(为了数据对应准确性) +*/ +export function GetBoardContour(br: Board): ExtrudeContourCurve | undefined +{ + if (Math.abs(br.ContourCurve.Area) < 10) + return; + + let curves = GetBoardSealingCurves(br); + + if (curves.length === 1 && curves[0] instanceof Circle) + return curves[0]; + + let brContour = Polyline.Combine(curves, 1e-3); + return brContour; +} + + +/** + * 获取板件(扣封边后的)轮廓(拆单时) */ export function GetSealedBoardContour(br: Board): BrSealedData | undefined { @@ -342,14 +363,16 @@ export function GetSealedBoardContour(br: Board): BrSealedData | undefined polylineOffset._SubCurves.push(c);//sub //trim Circle - polylineOffset._Circles.push(new Circle(c.StartPoint, j === 0 ? Math.min(preSeal.size, seal.size) : seal.size)); + if (seal.size && (j || seal.size === preSeal.size)) + polylineOffset._Circles.push(new Circle(c.StartPoint, seal.size)); //offset let offsetC = c.GetOffsetCurves(dir * -seal.size)[0]; if (offsetC) polylineOffset._SubOffsetedCurves.push({ index: subIndex, - curve: offsetC + curve: offsetC, + dist: seal.size, }); else polylineOffset._TrimArcContours.push(Contour.CreateContour([c, new Line(c.StartPoint, c.EndPoint)], false)); @@ -364,14 +387,16 @@ export function GetSealedBoardContour(br: Board): BrSealedData | undefined polylineOffset._SubCurves.push(curve);//sub //trim Circle - polylineOffset._Circles.push(new Circle(curve.StartPoint, Math.min(preSeal.size, seal.size))); + if (seal.size && seal.size === preSeal.size) + polylineOffset._Circles.push(new Circle(curve.StartPoint, seal.size)); //offset let offsetC = curve.GetOffsetCurves(dir * -seal.size)[0]; if (offsetC) polylineOffset._SubOffsetedCurves.push({ index: subIndex, - curve: offsetC + curve: offsetC, + dist: seal.size, }); else polylineOffset._TrimArcContours.push(Contour.CreateContour([curve, new Line(curve.StartPoint, curve.EndPoint)], false)); @@ -388,6 +413,15 @@ export function GetSealedBoardContour(br: Board): BrSealedData | undefined //如果有多个 取最大 if (sealedContours.length > 1) { + Toaster({ + message: `有板计算封边异常,请检查!(点击左下角提示可以查看该板)`, + timeout: 15000, + intent: Intent.WARNING, + key: "sealerror" + }); + + InteractionLog([{ msg: "警告:" }, { msg: `板:${br.Name}`, entity: [br] }, { msg: `在扣除封边计算中,得到了${sealedContours.length}条轮廓,请检查!` }], LogType.Warning); + let areas = sealedContours.map(p => p.Area); let maxIndex = Max(areas, (a1, a2) => a2 > a1); sealedContours = [sealedContours[maxIndex]]; diff --git a/src/GraphicsSystem/OffsetPolyline.ts b/src/GraphicsSystem/OffsetPolyline.ts index d2eb1e35b..c3fcbf306 100644 --- a/src/GraphicsSystem/OffsetPolyline.ts +++ b/src/GraphicsSystem/OffsetPolyline.ts @@ -18,6 +18,8 @@ interface IOffsetResult { index: number; curve: Curve; + /**偏移距离(仅在局部偏移时提供) */ + dist?: number; sp?: Vector3; ep?: Vector3; preCurve?: Curve; @@ -273,8 +275,9 @@ export class OffsetPolyline 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 iPtsP = curveNow.IntersectWith2(curveNext, IntersectOption.ExtendBoth, 1e-6); + let iPts = iPtsP.map(p => p.pt); + let tPts = iPtsP.filter(p => curveNow.ParamOnCurve(p.thisParam) && curveNext.ParamOnCurve(p.argParam)).map(p => p.pt); let code = EntityEncode2(curveNow, curveNext); @@ -285,7 +288,7 @@ export class OffsetPolyline tp = iPts[0]; else { - if (iPts.length > 0 && curveNow.GetParamAtPoint(iPts[0]) > 1) + if (iPts.length > 0 && iPtsP[0].thisParam > 1) { let refP = this._Vertexs[curveResNext.index]; let distSq = iPts[0].distanceToSquared(refP); @@ -304,8 +307,21 @@ export class OffsetPolyline else { let refP = this._Vertexs[curveResNext.index]; + + //在局部偏移中,当偏移距离不一致时,我们总是倾向于直接连接 + if (this._IsTopoOffset && tPts.length === 0 && curveResNow.dist !== curveResNext.dist) + { + if (iPts.length) + tPts = iPts; + else + { + curveResNow.paddingCurve = [new Line(sp, ep)];//补直线 + continue; + } + } + if (tPts.length > 0) //ipts = 1 or ipts = 2 - tp = SelectNearP(iPts, refP); + tp = SelectNearP(tPts, refP); else //补圆弧 或者尝试连接 { if (iPts.length > 0 && !this._ToolPath && this.IsSharpCorner(curveResNow, curveResNext, refP))//非加工刀路 并且尖角化时 @@ -369,7 +385,7 @@ export class OffsetPolyline if (curveResNext.ep) curveNext.EndPoint = oldp2; - if (this._IsTopoOffset || onPre && onNext) + if (onPre && onNext) tp = p; else curveResNow.paddingCurve = [this.CreateArc(refP, sp, ep)];//补圆弧 @@ -377,7 +393,8 @@ export class OffsetPolyline else curveResNow.paddingCurve = [this.CreateArc(refP, sp, ep)];//补圆弧 - this._TrimCircleContours.push(this._Circles[curveResNext.index]); + let circle = this._Circles[curveResNext.index]; + if (circle) this._TrimCircleContours.push(circle);//因为局部偏移可能未提供圆 } } if (tp) @@ -394,9 +411,10 @@ export class OffsetPolyline 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); + let circle = this._Circles[s]; + if (!circle) continue;//因为局部偏移可能未提供圆 + this._TrimCircleContours.push(circle); + padCirs.push(circle); if (s === curveResNext.index) break; } diff --git a/src/GraphicsSystem/ToolPath/FeedingToolPath.ts b/src/GraphicsSystem/ToolPath/FeedingToolPath.ts index d9c3fd1af..24e554673 100644 --- a/src/GraphicsSystem/ToolPath/FeedingToolPath.ts +++ b/src/GraphicsSystem/ToolPath/FeedingToolPath.ts @@ -22,7 +22,7 @@ import { RegionParse } from "../../Geometry/RegionParse"; import { FixIndex } from "../../Nest/Common/Util"; import { FaceDirection } from "../../UI/Store/BoardInterface"; import { BoolOpeartionType, isTargetCurInOrOnSourceCur } from "../BoolOperateUtils"; -import { GetSealedBoardContour } from "../CalcEdgeSealing"; +import { GetBoardContour } from "../CalcEdgeSealing"; import { GetCurveToInDir, GetOffsetCurves, OptimizeToolPath } from "./OptimizeToolPath"; /** @@ -502,8 +502,7 @@ export class FeedingToolPath extends Singleton export function GetModelingFromCustomDrill(br: Board) { let normal = br.Normal; - let sealedData = GetSealedBoardContour(br); - let outline = sealedData.brContour; + let outline = GetBoardContour(br); let modeling: (IModeling & { originEn: ExtrudeHole; })[] = []; let sideModeling: (IModeling & { originEn: ExtrudeHole; })[] = [];