diff --git a/__test__/Booloperate/__snapshots__/bool5.test.ts.snap b/__test__/Booloperate/__snapshots__/bool5.test.ts.snap index 85f2c3b84..d891f08f9 100644 --- a/__test__/Booloperate/__snapshots__/bool5.test.ts.snap +++ b/__test__/Booloperate/__snapshots__/bool5.test.ts.snap @@ -12,6 +12,6 @@ exports[`弧形板差集 1`] = `"165548.36110"`; exports[`弧形板差集 2`] = `"331151.31924"`; -exports[`弧形板差集2 1`] = `"165548.36023"`; +exports[`弧形板差集2 1`] = `"165548.36110"`; exports[`弧形板差集2 2`] = `"331151.31924"`; diff --git a/__test__/FeedingToolPath/FeedingToolPath.test.ts b/__test__/FeedingToolPath/FeedingToolPath.test.ts index de54f28e5..1f58f7bb3 100644 --- a/__test__/FeedingToolPath/FeedingToolPath.test.ts +++ b/__test__/FeedingToolPath/FeedingToolPath.test.ts @@ -181,3 +181,12 @@ test('精度不一致导致的错误', () => let brs = LoadBoardsFromFileData(d); testPathCount(brs[0]); }); + +test('重复点过多导致的布尔错误', () => +{ + let d = + { "file": [1, "Board", 8, 2, 136, false, 1, 2, 0, [0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 1542.6178010471249, -3757.536467706971, 295.8115183248293, 1], 0, 0, true, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1542.6178010471249, -3757.536467706971, 295.8115183248293, 1], 0, 3, 940.000000000005, 2350.0000000000005, 15, false, "Polyline", 8, 2, 0, false, 0, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 0, 0, true, [0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 3749.7485095917887, 3196.3743455497456, -295.8115183247719, 1], 0, 2, 5, [4.547473508864641e-13, 5.002220859751105e-12], 0, [2120.0000000000005, 0], 0, [2350.0000000000005, 470], 0, [2119.999999999999, 940.0000000000018], 0, [0, 940.000000000005], 0, true, 1, 3, 860.0000238166186, 1812.0534983379844, 6, false, "Polyline", 8, 2, 0, false, 0, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -490.0437608700008, -39.999988091681296, 0, 1], 0, 0, true, [0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 3259.704748721788, 3156.3743574580644, -295.8115183247719, 1], 0, 2, 10, [490.04376087000173, 70.00000001851413], 0.41421356237309515, [520.0437608891084, 40.000000000005], 0, [2076.0437608563307, 40.00000000000682], 0.28638958411744386, [2103.043760858855, 56.8134140582747], 0, [2299.043760864549, 456.8134140698744], 0.23156094812233494, [2299.0437608753277, 483.186585909139], 0, [2103.0437608687926, 883.1865859224918], 0.2863895839754242, [2076.043760888381, 900.000000000005], 0, [520.0437608891084, 899.9999999999914], 0.41421356237309503, [490.0437608700008, 869.9999999808838], 0, true, 1, 3, 835.0035209518353, 1787.7812073629661, 6, false, "Polyline", 8, 2, 0, false, 0, 7, 0, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -502.0437608700008, -52.49823952408596, 0, 1], 0, 0, true, [0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 3247.704748721788, 3143.8761060256597, -295.8115183247719, 1], 0, 2, 10, [520.0437608700017, 52.500000000005], 0, [2076.043760871718, 52.500000000005], 0.2863895839882779, [2092.0437608700017, 62.30782488000614], 0, [2288.043760862396, 462.3078248655029], 0.23156094827558482, [2288.0437608700017, 477.69217512000387], 0, [2092.043760870679, 877.6921751186296], 0.28638958402109244, [2076.0437608700017, 887.500000000005], 0, [520.0437608699726, 887.5000000000032], 0.4142135620001939, [502.04376087000173, 869.9999999999468], 0, [502.0437608700008, 70.00000000003229], 0.41421356200142434, true, 0, 3, 0, 0, 0, 0, 0, [0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 1490.119561523039, -3255.4927068369702, 304.8115183248293, 1], 3, 0, 0, 0, 0, 0, [0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 1502.6178129554437, -3267.4927068369702, 304.8115183248293, 1], 3, 0, 0, 0, 0, 0, 10, 0, "层板", "", "", "", "", "", 1, 0, "三合一", 2, 0, "1", "1", "1", "1", "", "", "", 5, "三合一", "三合一", "三合一", "三合一", "三合一", true, true, 0, 0, 0, 0, 0, 0, 0, 0, true, 0, 0], "basePt": { "x": 602.6178010471199, "y": -3757.536467706971, "z": 295.8115183248293 }, "ucs": [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1542.6178010471249, -3757.536467706971, 295.8115183248293, 1] }; + + let brs = LoadBoardsFromFileData(d); + testPathCount(brs[0]); +}); diff --git a/__test__/FeedingToolPath/__snapshots__/FeedingToolPath.test.ts.snap b/__test__/FeedingToolPath/__snapshots__/FeedingToolPath.test.ts.snap index 900181526..b7a447b3b 100644 --- a/__test__/FeedingToolPath/__snapshots__/FeedingToolPath.test.ts.snap +++ b/__test__/FeedingToolPath/__snapshots__/FeedingToolPath.test.ts.snap @@ -304,6 +304,10 @@ exports[`造型的外框和内框厚度等于刀直径 1`] = `"1459.45340"`; exports[`造型的外框和内框厚度等于刀直径: 走刀数量 1`] = `1`; +exports[`重复点过多导致的布尔错误 1`] = `"23133.26713"`; + +exports[`重复点过多导致的布尔错误: 走刀数量 1`] = `1`; + exports[`门字部分 1`] = `"1.76759"`; exports[`门字部分 2`] = `"8.75659"`; diff --git a/__test__/FeedingToolPath/__snapshots__/qiannianzhou_lvzhijia.test.ts.snap b/__test__/FeedingToolPath/__snapshots__/qiannianzhou_lvzhijia.test.ts.snap index 50dc0ee88..b5d5d8aa1 100644 --- a/__test__/FeedingToolPath/__snapshots__/qiannianzhou_lvzhijia.test.ts.snap +++ b/__test__/FeedingToolPath/__snapshots__/qiannianzhou_lvzhijia.test.ts.snap @@ -88,7 +88,7 @@ exports[`千年舟 绿色健康之家 43`] = `"127.53520"`; exports[`千年舟 绿色健康之家 44`] = `"130.77685"`; -exports[`千年舟 绿色健康之家 45`] = `"112.29087"`; +exports[`千年舟 绿色健康之家 45`] = `"112.29088"`; exports[`千年舟 绿色健康之家 46`] = `"141.29953"`; diff --git a/src/DatabaseServices/Contour.ts b/src/DatabaseServices/Contour.ts index 3b76d0d56..a4e0a8fd2 100644 --- a/src/DatabaseServices/Contour.ts +++ b/src/DatabaseServices/Contour.ts @@ -6,7 +6,7 @@ import { FixIndex } from "../Common/Utils"; import { IntersectBox2 } from "../Geometry/Box"; import { CreateContour2 } from "../Geometry/CreateContour2"; import { Route } from "../Geometry/CurveMap"; -import { equaln, equalv2, equalv3 } from "../Geometry/GeUtils"; +import { ComparePointFnGenerate, equaln, equalv2, equalv3 } from "../Geometry/GeUtils"; import { RegionParse } from "../Geometry/RegionParse"; import { isTargetCurInOrOnSourceCur } from "../GraphicsSystem/BoolOperateUtils"; import { IntersectOption } from "../GraphicsSystem/IntersectWith"; @@ -424,7 +424,7 @@ export class Contour let subtractList: Polyline[] = []; let holes: Polyline[] = []; let intPars: number[] = []; - let cuMap = new Map(); + let curveIntParamsMap = new Map(); let outBox = sourceOutline.BoundingBox; @@ -451,59 +451,61 @@ export class Contour } else { + let fn = ComparePointFnGenerate("xyz", 1e-4); + pts.sort((p1, p2) => fn(p1.pt, p2.pt)); + arrayRemoveDuplicateBySort(pts, (p1, p2) => equalv2(p1.pt, p2.pt, 1e-4)); intPars.push(...pts.map(r => r.thisParam)); - cuMap.set(targetOutline, pts.map(r => r.argParam)); + curveIntParamsMap.set(targetOutline, pts.map(r => r.argParam)); } } - intPars.sort((a, b) => a - b); - arrayRemoveDuplicateBySort(intPars, (e1, e2) => equaln(e1, e2, 1e-8)); - let sourceCus = sourceOutline.GetSplitCurves(intPars) as Polyline[]; - let targetCus: Polyline[] = []; - let targetMap = new WeakMap(); + let sourceSplitCurves = sourceOutline.GetSplitCurves(intPars) as Polyline[]; + let targetSplitCurves: Polyline[] = []; - let isEqualNormal: boolean; + let targetSplitCurve_CurvesMap = new WeakMap();//分裂后->原始曲线 映射 - for (let [c, pars] of cuMap) + for (let [curve, intParams] of curveIntParamsMap) { - let cus = c.GetSplitCurves(pars) as Polyline[]; - cus.forEach(cu => targetMap.set(cu, c)); - targetCus.push(...cus); + + let splitCurves = curve.GetSplitCurves(intParams) as Polyline[]; + for (let splitCurve of splitCurves) + { + targetSplitCurve_CurvesMap.set(splitCurve, curve); + targetSplitCurves.push(splitCurve); + } } - for (let pl of sourceCus) + for (let sourceSplitcu of sourceSplitCurves) { - let plMidParam = pl.MidParam; - let plDir = pl.GetFistDeriv(plMidParam).normalize(); + let sourceDir = sourceSplitcu.GetFistDeriv(sourceSplitcu.MidParam).normalize(); - let index = targetCus.findIndex(cu => fastEqualCurve(cu, pl, 0.05)); + let index = targetSplitCurves.findIndex(cu => fastEqualCurve(cu, sourceSplitcu, 0.05)); if (index !== -1) { - let cu = targetCus[index]; - isEqualNormal = equalv3(sourceOutline.Normal, targetMap.get(cu).Normal, 1e-3); - let cuMidParam = cu.MidParam; - let cuDir = cu.GetFistDeriv(cuMidParam).normalize(); + let targetSplitcu = targetSplitCurves[index]; + let isEqualNormal = equalv3(sourceOutline.Normal, targetSplitCurve_CurvesMap.get(targetSplitcu).Normal, 1e-3); + let targetDir = targetSplitcu.GetFistDeriv(targetSplitcu.MidParam).normalize(); - if (isEqualNormal === !equalv3(cuDir, plDir, 1e-3))//不同向 - subtractList.push(pl); + if (isEqualNormal === !equalv3(targetDir, sourceDir, 1e-3))//不同向 + subtractList.push(sourceSplitcu); - targetCus.splice(index, 1); + targetSplitCurves.splice(index, 1); continue; } - if (targets.every(t => !fastCurveInCurve(t.Curve as Polyline, pl))) - subtractList.push(pl); + if (targets.every(t => !fastCurveInCurve(t.Curve as Polyline, sourceSplitcu))) + subtractList.push(sourceSplitcu); } //源对象没有被破坏 - let sourceNotBreak = subtractList.length === sourceCus.length; + let sourceNotBreak = subtractList.length === sourceSplitCurves.length; - for (let pl of targetCus) + for (let pl of targetSplitCurves) if (fastCurveInCurve(sourceOutline, pl)) subtractList.push(pl); - if (sourceNotBreak && subtractList.length === sourceCus.length) + if (sourceNotBreak && subtractList.length === sourceSplitCurves.length) return { subtractList: [sourceOutline], holes }; return { subtractList, holes }; diff --git a/src/Geometry/GeUtils.ts b/src/Geometry/GeUtils.ts index 01d2ff6b0..473c80618 100644 --- a/src/Geometry/GeUtils.ts +++ b/src/Geometry/GeUtils.ts @@ -335,7 +335,7 @@ const comparePointCache: Map = new Map(); * @param {string} sortKey * @returns {compareVectorFn} */ -export function ComparePointFnGenerate(sortKey: string): compareVectorFn +export function ComparePointFnGenerate(sortKey: string, fuzz = 1e-8): compareVectorFn { if (comparePointCache.has(sortKey)) return comparePointCache.get(sortKey); @@ -360,7 +360,7 @@ export function ComparePointFnGenerate(sortKey: string): compareVectorFn { let vv1 = v1.getComponent(s[0]); let vv2 = v2.getComponent(s[0]); - if (equaln(vv1, vv2)) continue; + if (equaln(vv1, vv2, fuzz)) continue; if (vv2 > vv1) return s[1]; else return -s[1]; }