@yumiai/chat-widget 0.2.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +1 -1
  3. package/dist/ExcelCore-EAXQMKZT.js +10 -0
  4. package/dist/{ExcelViewer-3YLLYYIQ.js → ExcelViewer-OGWM52ZT.js} +2 -3
  5. package/dist/{ExcelViewer-3YLLYYIQ.js.map → ExcelViewer-OGWM52ZT.js.map} +1 -1
  6. package/dist/{GerberViewerA2UI-X5FWAD5M.js → GerberViewerA2UI-AORHOCF6.js} +2 -3
  7. package/dist/{GerberViewerA2UI-X5FWAD5M.js.map → GerberViewerA2UI-AORHOCF6.js.map} +1 -1
  8. package/dist/{GraphStatsLegend-D5bPeXB_.d.cts → GraphStatsLegend-CV0Y3-cP.d.cts} +39 -0
  9. package/dist/{GraphStatsLegend-D5bPeXB_.d.ts → GraphStatsLegend-CV0Y3-cP.d.ts} +39 -0
  10. package/dist/JsonRenderStandalone-L5ROJ6XP.js +17 -0
  11. package/dist/{KicadViewer-GV6ZC4AQ.js → KicadViewer-H6YY6WVC.js} +3 -4
  12. package/dist/{KicadViewer-GV6ZC4AQ.js.map → KicadViewer-H6YY6WVC.js.map} +1 -1
  13. package/dist/KicadViewerCore-XVJE2FTQ.js +10 -0
  14. package/dist/{PdfViewer-CHPDRK46.js → PdfViewer-GKVDDNCZ.js} +9 -10
  15. package/dist/{PdfViewer-CHPDRK46.js.map → PdfViewer-GKVDDNCZ.js.map} +1 -1
  16. package/dist/{PdfViewerCore-HJPEHSRA.js → PdfViewerCore-SUVXHXYO.js} +24 -11
  17. package/dist/PdfViewerCore-SUVXHXYO.js.map +1 -0
  18. package/dist/PowerPointCore-IZ4G6HEQ.js +10 -0
  19. package/dist/{PowerPointViewer-LQTO6UCU.js → PowerPointViewer-5R2KSWWJ.js} +2 -3
  20. package/dist/{PowerPointViewer-LQTO6UCU.js.map → PowerPointViewer-5R2KSWWJ.js.map} +1 -1
  21. package/dist/{StepViewerCore-7W3L3R4E.js → StepViewerCore-RORWXIRU.js} +2 -3
  22. package/dist/{StepViewerCore-7W3L3R4E.js.map → StepViewerCore-RORWXIRU.js.map} +1 -1
  23. package/dist/{ThreeViewerCore-N3QJD5QI.js → ThreeViewerCore-GTUZKD5V.js} +2 -3
  24. package/dist/{ThreeViewerCore-N3QJD5QI.js.map → ThreeViewerCore-GTUZKD5V.js.map} +1 -1
  25. package/dist/WordCore-QFG5HTYD.js +10 -0
  26. package/dist/{WordViewer-ZHCQMHOH.js → WordViewer-7XUQFS4A.js} +2 -3
  27. package/dist/{WordViewer-ZHCQMHOH.js.map → WordViewer-7XUQFS4A.js.map} +1 -1
  28. package/dist/{chunk-QLVPIM6R.js → chunk-3CNQONCV.js} +79 -1
  29. package/dist/chunk-3CNQONCV.js.map +1 -0
  30. package/dist/{chunk-2UC7YLVX.js → chunk-3LOSHCSH.js} +3 -3
  31. package/dist/chunk-5VUKEGFC.js +108 -0
  32. package/dist/chunk-5VUKEGFC.js.map +1 -0
  33. package/dist/chunk-AO4YUJQT.js +479 -0
  34. package/dist/chunk-AO4YUJQT.js.map +1 -0
  35. package/dist/{chunk-KQV7IKET.js → chunk-ASV4TISB.js} +2 -2
  36. package/dist/{chunk-CFKGNAJM.js → chunk-AT6VLLOO.js} +15 -15
  37. package/dist/{chunk-56WRZM3R.js → chunk-EYWNUJVZ.js} +3 -3
  38. package/dist/{chunk-K4KGNVL5.js → chunk-EZ46FGQ6.js} +3 -3
  39. package/dist/{chunk-GYXTSY22.js → chunk-KXPR6SRW.js} +4 -4
  40. package/dist/{chunk-7S67DOHQ.js → chunk-MTN6SUUQ.js} +2 -2
  41. package/dist/chunk-Q5PLT3AI.js +29 -0
  42. package/dist/chunk-Q5PLT3AI.js.map +1 -0
  43. package/dist/{chunk-PZXSASDY.js → chunk-R5LHMOAC.js} +3 -3
  44. package/dist/chunk-X67V7257.js +238 -0
  45. package/dist/chunk-X67V7257.js.map +1 -0
  46. package/dist/citationContext-CILHTO2Z.js +25 -0
  47. package/dist/components/JsonRender/standalone.cjs +56 -9753
  48. package/dist/components/JsonRender/standalone.cjs.map +1 -1
  49. package/dist/components/JsonRender/standalone.js +10 -11
  50. package/dist/components/JsonRender/standalone.js.map +1 -1
  51. package/dist/{gerber-2d-entry-OQ4SQRBY.js → gerber-2d-entry-HEFXQGBK.js} +5 -9
  52. package/dist/{gerber-2d-entry-OQ4SQRBY.js.map → gerber-2d-entry-HEFXQGBK.js.map} +1 -1
  53. package/dist/{gerber-3d-entry-DEHDBOO2.js → gerber-3d-entry-KVTONA37.js} +5 -9
  54. package/dist/{gerber-3d-entry-DEHDBOO2.js.map → gerber-3d-entry-KVTONA37.js.map} +1 -1
  55. package/dist/{gerber-simulation-entry-EBDX72XE.js → gerber-simulation-entry-GZ62QX5H.js} +5 -9
  56. package/dist/{gerber-simulation-entry-EBDX72XE.js.map → gerber-simulation-entry-GZ62QX5H.js.map} +1 -1
  57. package/dist/index.cjs +6690 -13472
  58. package/dist/index.cjs.map +1 -1
  59. package/dist/index.css +776 -4
  60. package/dist/index.css.map +1 -1
  61. package/dist/index.d.cts +979 -26
  62. package/dist/index.d.ts +979 -26
  63. package/dist/index.js +4350 -1859
  64. package/dist/index.js.map +1 -1
  65. package/dist/provenance/index.cjs +78 -0
  66. package/dist/provenance/index.cjs.map +1 -1
  67. package/dist/provenance/index.d.cts +2 -2
  68. package/dist/provenance/index.d.ts +2 -2
  69. package/dist/provenance/index.js +2 -3
  70. package/dist/{resolveToArrayBuffer-AQIDZHSQ.js → resolveToArrayBuffer-PVSVIAII.js} +1 -3
  71. package/dist/{resolveToArrayBuffer-AQIDZHSQ.js.map → resolveToArrayBuffer-PVSVIAII.js.map} +1 -1
  72. package/dist/sseAdapter-LFXYGYC4.js +8 -0
  73. package/dist/sseAdapter-LFXYGYC4.js.map +1 -0
  74. package/package.json +2 -1
  75. package/dist/ExcelCore-DJOIVQMI.js +0 -11
  76. package/dist/JsonRenderStandalone-EIZM62JU.js +0 -18
  77. package/dist/KicadViewerCore-U7BWZHKJ.js +0 -11
  78. package/dist/PdfViewerCore-HJPEHSRA.js.map +0 -1
  79. package/dist/PowerPointCore-FPDR2BL4.js +0 -11
  80. package/dist/WordCore-JKSXK2XD.js +0 -11
  81. package/dist/chunk-7A4FY6FK.js +0 -10226
  82. package/dist/chunk-7A4FY6FK.js.map +0 -1
  83. package/dist/chunk-7D4SUZUM.js +0 -38
  84. package/dist/chunk-QLVPIM6R.js.map +0 -1
  85. package/dist/chunk-VXJWGLZ7.js +0 -21
  86. package/dist/chunk-VXJWGLZ7.js.map +0 -1
  87. /package/dist/{ExcelCore-DJOIVQMI.js.map → ExcelCore-EAXQMKZT.js.map} +0 -0
  88. /package/dist/{JsonRenderStandalone-EIZM62JU.js.map → JsonRenderStandalone-L5ROJ6XP.js.map} +0 -0
  89. /package/dist/{KicadViewerCore-U7BWZHKJ.js.map → KicadViewerCore-XVJE2FTQ.js.map} +0 -0
  90. /package/dist/{PowerPointCore-FPDR2BL4.js.map → PowerPointCore-IZ4G6HEQ.js.map} +0 -0
  91. /package/dist/{WordCore-JKSXK2XD.js.map → WordCore-QFG5HTYD.js.map} +0 -0
  92. /package/dist/{chunk-2UC7YLVX.js.map → chunk-3LOSHCSH.js.map} +0 -0
  93. /package/dist/{chunk-KQV7IKET.js.map → chunk-ASV4TISB.js.map} +0 -0
  94. /package/dist/{chunk-CFKGNAJM.js.map → chunk-AT6VLLOO.js.map} +0 -0
  95. /package/dist/{chunk-56WRZM3R.js.map → chunk-EYWNUJVZ.js.map} +0 -0
  96. /package/dist/{chunk-K4KGNVL5.js.map → chunk-EZ46FGQ6.js.map} +0 -0
  97. /package/dist/{chunk-GYXTSY22.js.map → chunk-KXPR6SRW.js.map} +0 -0
  98. /package/dist/{chunk-7S67DOHQ.js.map → chunk-MTN6SUUQ.js.map} +0 -0
  99. /package/dist/{chunk-PZXSASDY.js.map → chunk-R5LHMOAC.js.map} +0 -0
  100. /package/dist/{chunk-7D4SUZUM.js.map → citationContext-CILHTO2Z.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/jetPaveGerberViewer/src/viewer-src/3dPage/js/main.js","../src/components/jetPaveGerberViewer/src/viewer-src/3dPage/js/gerber-parser-direct.js"],"sourcesContent":["import * as THREE from 'three';\nimport { OrbitControls } from 'three/addons/controls/OrbitControls.js';\nimport JSZip from 'jszip';\nimport earcut from 'earcut';\nimport { GerberOutlineParser } from './gerber-parser-direct.js';\nimport { GerberParser } from './gerber-parser.js';\nimport { extractRar } from '../../common/archiveExtractor.js';\nimport { parse, plot, renderSVG } from 'web-gerber';\nimport { parseUrlId, parseUrlFileUrl, fetchFileById, fetchFileByUrl } from '../../common/gerber-common.js';\n\n// 调试模式开关 - 设为 false 可禁用所有调试日志,提升性能\nconst DEBUG_MODE = true;\nconst debugLog = DEBUG_MODE ? console.log.bind(console) : () => {};\nconst debugWarn = DEBUG_MODE ? console.warn.bind(console) : () => {};\n\n/**\n * 将线段拼接成闭合形状(优化版)\n * 使用链式拼接算法,更适合异形轮廓的拼接\n * 优化点:1.使用数值key替代字符串 2.使用平方距离避免sqrt 3.使用双端队列避免unshift\n * @param {Array<{start:{x,y}, end:{x,y}}>} segments 线段数组\n * @returns {Array<THREE.Shape>} 形状数组\n */\nfunction stitchSegmentsToShapes(segments) {\n if (!segments || segments.length === 0) return [];\n \n const startTime = performance.now();\n \n // 🎯 第一步:线段去重(使用数值key优化)\n const PRECISION = 10000; // 0.0001mm 精度\n const seen = new Set();\n const uniqueSegments = [];\n \n for (let i = 0; i < segments.length; i++) {\n const seg = segments[i];\n // 使用有序坐标生成唯一key,避免正反向重复\n const sx = Math.round(seg.start.x * PRECISION);\n const sy = Math.round(seg.start.y * PRECISION);\n const ex = Math.round(seg.end.x * PRECISION);\n const ey = Math.round(seg.end.y * PRECISION);\n \n // 确保key有序(小的在前)\n let key;\n if (sx < ex || (sx === ex && sy < ey)) {\n key = `${sx},${sy}|${ex},${ey}`;\n } else {\n key = `${ex},${ey}|${sx},${sy}`;\n }\n \n if (!seen.has(key)) {\n seen.add(key);\n uniqueSegments.push(seg);\n }\n }\n \n console.log(`[stitchSegmentsToShapes] 线段去重: ${segments.length} -> ${uniqueSegments.length}`);\n \n if (uniqueSegments.length === 0) return [];\n \n // 早期退出:线段过多时跳过拼接\n const MAX_SEGMENTS = 150000;\n if (uniqueSegments.length > MAX_SEGMENTS) {\n console.warn(`[stitchSegmentsToShapes] ⚠️ 线段过多 (${uniqueSegments.length} > ${MAX_SEGMENTS}),跳过拼接`);\n return [];\n }\n \n // 计算容差和边界(单次遍历)\n let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;\n const n = uniqueSegments.length;\n for (let i = 0; i < n; i++) {\n const seg = uniqueSegments[i];\n const s = seg.start, e = seg.end;\n if (s.x < minX) minX = s.x;\n if (s.x > maxX) maxX = s.x;\n if (e.x < minX) minX = e.x;\n if (e.x > maxX) maxX = e.x;\n if (s.y < minY) minY = s.y;\n if (s.y > maxY) maxY = s.y;\n if (e.y < minY) minY = e.y;\n if (e.y > maxY) maxY = e.y;\n }\n \n const boardSize = Math.max(maxX - minX, maxY - minY);\n const TOLERANCE = boardSize > 100 ? 0.5 : boardSize > 50 ? 0.25 : 0.1;\n const TOLERANCE_SQ = TOLERANCE * TOLERANCE; // 平方容差,避免sqrt\n \n // 构建空间网格(使用数值key)\n const cellSize = TOLERANCE;\n const invCellSize = 1 / cellSize;\n const grid = new Map();\n \n // 创建pool items并添加到网格\n const poolItems = new Array(n);\n for (let i = 0; i < n; i++) {\n const seg = uniqueSegments[i];\n const item = { seg, used: false, idx: i };\n poolItems[i] = item;\n \n // 使用整数key\n const cx1 = Math.floor(seg.start.x * invCellSize);\n const cy1 = Math.floor(seg.start.y * invCellSize);\n const k1 = (cx1 << 16) ^ cy1; // 简单hash\n \n if (!grid.has(k1)) grid.set(k1, []);\n grid.get(k1).push(item);\n \n const cx2 = Math.floor(seg.end.x * invCellSize);\n const cy2 = Math.floor(seg.end.y * invCellSize);\n const k2 = (cx2 << 16) ^ cy2;\n \n if (k1 !== k2) {\n if (!grid.has(k2)) grid.set(k2, []);\n grid.get(k2).push(item);\n }\n }\n \n // 平方距离(避免sqrt)\n const distSq = (p1, p2) => {\n const dx = p1.x - p2.x;\n const dy = p1.y - p2.y;\n return dx * dx + dy * dy;\n };\n \n // 获取候选线段(优化:减少临时对象,预计算keys)\n const getCandidates = (x, y) => {\n const cx = Math.floor(x * invCellSize);\n const cy = Math.floor(y * invCellSize);\n const results = [];\n \n // 展开嵌套循环,减少迭代开销\n for (let dy = -1; dy <= 1; dy++) {\n const ccy = cy + dy;\n for (let dx = -1; dx <= 1; dx++) {\n const k = ((cx + dx) << 16) ^ ccy;\n const list = grid.get(k);\n if (list) {\n for (let i = 0, len = list.length; i < len; i++) {\n const item = list[i];\n if (!item.used) results.push(item);\n }\n }\n }\n }\n return results;\n };\n \n const chains = [];\n \n // 拼线(使用双端队列避免unshift)\n for (let startIdx = 0; startIdx < n; startIdx++) {\n const startItem = poolItems[startIdx];\n if (startItem.used) continue;\n \n startItem.used = true;\n \n // 使用两个数组模拟双端队列:front存反向元素,back存正向元素\n const front = []; // 反向添加的点(最后需要reverse)\n const back = [startItem.seg.start, startItem.seg.end]; // 正向添加的点\n \n let tail = startItem.seg.end;\n let head = startItem.seg.start;\n \n // 向后搜索(添加到back,内联优化)\n let finding = true;\n let tx = tail.x, ty = tail.y; // 缓存坐标\n while (finding) {\n finding = false;\n const candidates = getCandidates(tx, ty);\n \n let bestNext = null;\n let minDstSq = TOLERANCE_SQ;\n let isReverse = false;\n \n for (let i = 0, len = candidates.length; i < len; i++) {\n const item = candidates[i];\n const seg = item.seg;\n \n // 内联距离计算\n let dx = seg.start.x - tx;\n let dy = seg.start.y - ty;\n let d1 = dx * dx + dy * dy;\n if (d1 < minDstSq) {\n minDstSq = d1;\n bestNext = item;\n isReverse = false;\n }\n \n dx = seg.end.x - tx;\n dy = seg.end.y - ty;\n let d2 = dx * dx + dy * dy;\n if (d2 < minDstSq) {\n minDstSq = d2;\n bestNext = item;\n isReverse = true;\n }\n }\n \n if (bestNext) {\n bestNext.used = true;\n if (isReverse) {\n tail = bestNext.seg.start;\n tx = tail.x;\n ty = tail.y;\n back.push(tail);\n } else {\n tail = bestNext.seg.end;\n tx = tail.x;\n ty = tail.y;\n back.push(tail);\n }\n finding = true;\n }\n }\n \n // 向前搜索(添加到front,最后reverse,内联优化)\n finding = true;\n let hx = head.x, hy = head.y; // 缓存坐标\n while (finding) {\n finding = false;\n const candidates = getCandidates(hx, hy);\n \n let bestPrev = null;\n let minDstSq = TOLERANCE_SQ;\n let isReverse = false;\n \n for (let i = 0, len = candidates.length; i < len; i++) {\n const item = candidates[i];\n const seg = item.seg;\n \n // 内联距离计算\n let dx = seg.end.x - hx;\n let dy = seg.end.y - hy;\n let d1 = dx * dx + dy * dy;\n if (d1 < minDstSq) {\n minDstSq = d1;\n bestPrev = item;\n isReverse = false;\n }\n \n dx = seg.start.x - hx;\n dy = seg.start.y - hy;\n let d2 = dx * dx + dy * dy;\n if (d2 < minDstSq) {\n minDstSq = d2;\n bestPrev = item;\n isReverse = true;\n }\n }\n \n if (bestPrev) {\n bestPrev.used = true;\n if (isReverse) {\n head = bestPrev.seg.end;\n hx = head.x;\n hy = head.y;\n front.push(head);\n } else {\n head = bestPrev.seg.start;\n hx = head.x;\n hy = head.y;\n front.push(head);\n }\n finding = true;\n }\n }\n \n // 合并front(需要reverse)和back\n const chain = front.length > 0 ? front.reverse().concat(back) : back;\n chains.push(chain);\n }\n \n // 将链转换为 THREE.Shape\n const shapes = [];\n for (let c = 0; c < chains.length; c++) {\n const chain = chains[c];\n if (chain.length < 3) continue;\n \n // 检查闭合性(使用平方距离)\n const first = chain[0];\n const last = chain[chain.length - 1];\n const gapSq = distSq(first, last);\n const gap = Math.sqrt(gapSq);\n \n let forcedClose = false;\n if (gap > 10.0) forcedClose = true;\n if (gap > 1000.0) continue; // 间隙过大,放弃\n \n // 创建 THREE.Shape\n const shape = new THREE.Shape();\n shape.moveTo(chain[0].x, chain[0].y);\n for (let i = 1; i < chain.length; i++) {\n shape.lineTo(chain[i].x, chain[i].y);\n }\n if (gap > 0.001) {\n shape.lineTo(first.x, first.y);\n }\n shape.closePath();\n \n shape.userData = { forcedClose };\n shapes.push(shape);\n }\n \n const elapsed = performance.now() - startTime;\n console.log(`[stitchSegmentsToShapes] 拼接完成: ${shapes.length} 个形状,耗时 ${elapsed.toFixed(1)}ms`);\n \n return shapes;\n}\n\n// Constants\nconst COLORS = {\n OUTLINE: 0x1C590B, // 基材 (用户指定: #1C590B)\n OUTLINE_EDGE: 0x000000, // 边框线(黑色)\n COPPER: 0x40721E, // 线路 (用户指定: #40721E)\n GOLD: 0xD4AF37, // 焊盘 (金色 Gold)\n DRILL: 0x000000, // 钻孔 (黑色 Black)\n SILKSCREEN: 0xeeeeee, // 丝印 (白色 White)\n SOLDER_MASK: 0x1C590B, // 阻焊 (同基材)\n PASTE: 0x999999 // 锡膏 (灰色 Gray)\n};\n\n// Files to ignore (do NOT render, do NOT let them affect bbox/board size)\n// NOTE: compared in a case-insensitive way against the basename (no path).\nconst IGNORED_GERBER_BASENAMES_UPPER = new Set([\n 'PZT_Core-v1.0.GM15',\n 'PZT_Core-v1.0.GM2',\n 'PZT_Core-v1.0.GM3',\n 'PZT_Core-v1.0.GM4',\n 'PZT_Core-v1.0.GM5',\n 'PZT_Core-v1.0.GM6',\n 'PZT_Core-v1.0.GM8',\n 'PZT_Core-v1.0.GM13'\n].map(s => s.toUpperCase()));\n\n// Fixed Dimensions (in mm)\nconst FIXED_DIMENSIONS = {\n // BOARD_THICKNESS will be adaptive\n COPPER_HEIGHT: 0.035, \n SILKSCREEN_HEIGHT: 0.02, \n SOLDER_MASK_HEIGHT: 0.01, \n DRILL_PROTRUSION: 0.005 \n};\n\n// 初始厚度(会被自适应逻辑覆盖)\nlet BOARD_THICKNESS = 1.6; // mm\n\nclass Viewer3D {\n constructor() {\n this.scene = null;\n this.camera = null;\n this.renderer = null;\n this.controls = null;\n this.baseGroup = new THREE.Group();\n this.materialCache = new Map();\n \n this.initThree();\n this.initEvents();\n this.checkUrlParams();\n }\n\n initThree() {\n this.scene = new THREE.Scene();\n this.scene.background = new THREE.Color(0x000000);\n\n /** React 壳内 #viewer3d-canvas-host 存在时按容器尺寸渲染,避免 canvas 挂到 body 导致整页高度 > 100vh */\n const getViewportSize = () => {\n const host = document.getElementById('viewer3d-canvas-host');\n if (host && host.clientWidth > 0 && host.clientHeight > 0) {\n return { w: host.clientWidth, h: host.clientHeight };\n }\n return { w: window.innerWidth, h: window.innerHeight };\n };\n\n const { w: vw, h: vh } = getViewportSize();\n const safeW = Math.max(vw, 1);\n const safeH = Math.max(vh, 1);\n\n this.camera = new THREE.PerspectiveCamera(45, safeW / safeH, 0.1, 2000);\n this.camera.position.set(0, 0, 30);\n\n this.renderer = new THREE.WebGLRenderer({ antialias: true, logarithmicDepthBuffer: true });\n const pr = Math.min(window.devicePixelRatio || 1, 2);\n this.renderer.setPixelRatio(pr);\n this.renderer.setSize(safeW, safeH);\n\n const canvasHost = document.getElementById('viewer3d-canvas-host');\n (canvasHost || document.body).appendChild(this.renderer.domElement);\n\n this.controls = new OrbitControls(this.camera, this.renderer.domElement);\n this.controls.enableDamping = true;\n\n // Lights\n const ambientLight = new THREE.AmbientLight(0xffffff, 1.8); \n this.scene.add(ambientLight);\n\n const dirLight = new THREE.DirectionalLight(0xffffff, 1.2);\n dirLight.position.set(50, 50, 100); \n this.scene.add(dirLight);\n\n const fillLight = new THREE.DirectionalLight(0xffffff, 1.0);\n fillLight.position.set(-50, -50, 100); \n this.scene.add(fillLight);\n\n const backLight = new THREE.DirectionalLight(0xffffff, 0.8);\n backLight.position.set(0, 0, -100); \n this.scene.add(backLight);\n\n this.scene.add(this.baseGroup);\n\n const applyResize = () => {\n const { w, h } = getViewportSize();\n const W = Math.max(w, 1);\n const H = Math.max(h, 1);\n this.camera.aspect = W / H;\n this.camera.updateProjectionMatrix();\n this.renderer.setSize(W, H);\n };\n\n window.addEventListener('resize', applyResize);\n if (canvasHost && typeof ResizeObserver !== 'undefined') {\n this._canvasHostResizeObserver = new ResizeObserver(() => applyResize());\n this._canvasHostResizeObserver.observe(canvasHost);\n }\n\n requestAnimationFrame(() => applyResize());\n\n this.animate();\n }\n\n animate() {\n requestAnimationFrame(() => this.animate());\n this.controls.update();\n this.renderer.render(this.scene, this.camera);\n }\n\n initEvents() {\n const fileInput = document.getElementById('file-input');\n fileInput.addEventListener('change', (e) => this.handleFileSelect(e));\n const baseUrl = import.meta.env.BASE_URL || '/';\n const buildPageUrl = (path) => `${baseUrl}${path.replace(/^\\/+/, '')}`;\n \n // 绑定关闭按钮,跳转回 2d 页面\n const closeBtn = document.getElementById('close-btn');\n if (closeBtn) {\n closeBtn.addEventListener('click', () => {\n const id = parseUrlId();\n if (id) {\n window.location.href = `${buildPageUrl('/2dPage')}?id=${encodeURIComponent(id)}`;\n return;\n }\n const url = parseUrlFileUrl();\n if (url) {\n window.location.href = `${buildPageUrl('/2dPage')}?url=${encodeURIComponent(url)}`;\n return;\n }\n window.location.href = buildPageUrl('/2dPage');\n });\n }\n }\n \n async checkUrlParams() { \n console.log('[性能] checkUrlParams 开始')\n const startTime = performance.now()\n \n // 使用公共函数从 URL 中提取 ID(支持 ?id=xx 和 ?object={\"id\":\"xx\"} 格式)\n const id = parseUrlId();\n const url = parseUrlFileUrl();\n \n if (id) {\n const loadingEl = document.getElementById('loading');\n if (loadingEl) {\n loadingEl.textContent = '正在处理中...';\n loadingEl.style.display = 'flex';\n }\n \n try {\n // 使用公共函数 fetchFileById 获取文件(已包含性能监控)\n console.log('[3D-new] 使用 fetchFileById 获取文件...')\n await fetchFileById(\n id,\n async (files) => {\n // 文件获取成功,处理文件\n console.log('[3D-new] 收到文件,开始处理...')\n await this.processFiles(files);\n \n // 渲染完成后隐藏 loading\n if (loadingEl) {\n loadingEl.style.display = 'none';\n }\n \n const endTime = performance.now()\n const totalTime = (endTime - startTime) / 1000\n console.log(`[性能] ========== checkUrlParams 完成,总耗时: ${totalTime.toFixed(2)}秒 ==========`)\n },\n (message, type) => {\n // 状态更新回调(可选)\n console.log(`[3D-new] 状态: ${message}`)\n }\n );\n } catch (error) {\n const endTime = performance.now()\n const totalTime = (endTime - startTime) / 1000\n console.error(`[错误] checkUrlParams 失败 (耗时: ${totalTime.toFixed(2)}秒):`, error)\n \n if (loadingEl) {\n loadingEl.style.display = 'none';\n }\n alert('获取文件失败: ' + error.message);\n }\n } else if (url) {\n const loadingEl = document.getElementById('loading');\n if (loadingEl) {\n loadingEl.textContent = '正在处理中...';\n loadingEl.style.display = 'flex';\n }\n\n try {\n console.log('[3D-new] 使用 fetchFileByUrl 获取文件...')\n await fetchFileByUrl(\n url,\n async (files) => {\n console.log('[3D-new] 收到文件,开始处理...')\n await this.processFiles(files);\n if (loadingEl) {\n loadingEl.style.display = 'none';\n }\n const endTime = performance.now()\n const totalTime = (endTime - startTime) / 1000\n console.log(`[性能] ========== checkUrlParams 完成,总耗时: ${totalTime.toFixed(2)}秒 ==========`)\n },\n (message, type) => {\n console.log(`[3D-new] 状态: ${message}`)\n }\n );\n } catch (error) {\n const endTime = performance.now()\n const totalTime = (endTime - startTime) / 1000\n console.error(`[错误] checkUrlParams 失败 (耗时: ${totalTime.toFixed(2)}秒):`, error)\n if (loadingEl) {\n loadingEl.style.display = 'none';\n }\n alert('获取文件失败: ' + error.message);\n }\n } else {\n console.log('[3D-new] URL 中没有 ID 参数')\n }\n }\n\n async handleFileSelect(event) {\n console.log('[性能] handleFileSelect 开始')\n const startTime = performance.now()\n \n const files = event.target.files;\n if (!files || files.length === 0) return;\n document.getElementById('loading').style.display = 'flex';\n try {\n await this.processFiles(files);\n \n const endTime = performance.now()\n const totalTime = (endTime - startTime) / 1000\n console.log(`[性能] ========== 文件处理完成,总耗时: ${totalTime.toFixed(2)}秒 ==========`)\n } catch (e) {\n const endTime = performance.now()\n const totalTime = (endTime - startTime) / 1000\n console.error(`[错误] 文件处理失败 (耗时: ${totalTime.toFixed(2)}秒):`, e);\n alert('处理文件时出错: ' + e.message);\n } finally {\n document.getElementById('loading').style.display = 'none';\n event.target.value = '';\n }\n }\n\n async processFiles(fileList) {\n console.log(`[性能] processFiles 开始,文件数: ${fileList.length}`)\n const startTimeTotal = performance.now()\n \n // 🚀 首先清空上次渲染的场景和状态\n this.clearScene();\n this.outlineBbox = null; // 重置轮廓边界框\n \n // Hide scene during rendering to avoid flickering\n if (this.renderer && this.renderer.domElement) {\n this.renderer.domElement.style.visibility = 'hidden';\n }\n \n // 1. Extract Files\n console.log('[性能] 开始解压文件...')\n const startTimeExtract = performance.now()\n const gerberFiles = [];\n for (const file of fileList) {\n const ext = file.name.split('.').pop().toLowerCase();\n if (ext === 'zip') {\n console.log(`[性能] 解压 ZIP: ${file.name}`)\n const startTimeZip = performance.now()\n const zip = await JSZip.loadAsync(file);\n for (const filename in zip.files) {\n if (zip.files[filename].dir) continue;\n const content = await zip.files[filename].async('blob');\n gerberFiles.push(new File([content], filename));\n }\n const endTimeZip = performance.now()\n console.log(`[性能] ZIP 解压完成,耗时: ${(endTimeZip - startTimeZip).toFixed(2)}ms`)\n } else if (ext === 'rar') {\n console.log(`[性能] 解压 RAR: ${file.name}`)\n const startTimeRar = performance.now()\n const extracted = await extractRar(file);\n const endTimeRar = performance.now()\n console.log(`[性能] RAR 解压完成,耗时: ${(endTimeRar - startTimeRar).toFixed(2)}ms`)\n gerberFiles.push(...extracted);\n } else {\n gerberFiles.push(file);\n }\n }\n const endTimeExtract = performance.now()\n console.log(`[性能] 文件解压总耗时: ${(endTimeExtract - startTimeExtract).toFixed(2)}ms, 解压后文件数: ${gerberFiles.length}`)\n\n // 1.1 Filter ignored files (so they don't get classified/rendered and don't affect bbox)\n if (IGNORED_GERBER_BASENAMES_UPPER.size > 0 && gerberFiles.length > 0) {\n const kept = [];\n const ignored = [];\n for (const f of gerberFiles) {\n const base = (f.name.split(/[/\\\\]/).pop() || '').toUpperCase();\n if (IGNORED_GERBER_BASENAMES_UPPER.has(base)) {\n ignored.push(f.name);\n } else {\n kept.push(f);\n }\n }\n if (ignored.length > 0) {\n debugWarn(`[3D-new] 已忽略 ${ignored.length} 个文件(不参与渲染/不影响基材尺寸):`, ignored);\n }\n gerberFiles.length = 0;\n gerberFiles.push(...kept);\n }\n \n // Debug: Log all extracted files\n // debugLog(`[File Extraction] 提取到的所有文件 (${gerberFiles.length} 个):`, gerberFiles.map(f => f.name));\n\n console.log(`[3D-new] 开始解析文件,共 ${gerberFiles.length} 个文件:`, gerberFiles.map(f => f.name));\n \n console.log('[性能] 开始文件分类...')\n const startTimeClassify = performance.now()\n \n // 2. Identify Layers using the same logic as 2d-direct\n // 2.1 预处理 .pho 前缀分组:用于判定\"最小编号为上层,其余为下层\"\n const buildPhoGroups = (files) => {\n const groups = new Map(); // prefix -> {min:number}\n const add = (prefix, num) => {\n if (!groups.has(prefix)) {\n groups.set(prefix, { min: num });\n } else {\n groups.get(prefix).min = Math.min(groups.get(prefix).min, num);\n }\n };\n files.forEach(f => {\n const nameOnly = f.name.split(/[/\\\\]/).pop() || '';\n const ext = '.' + nameOnly.split('.').pop().toLowerCase();\n if (ext !== '.pho') return;\n const upper = nameOnly.toUpperCase();\n let prefix = null;\n let num = 0;\n if (upper.startsWith('SST')) {\n prefix = 'sst';\n const m = upper.match(/^SST(\\d+)/);\n num = m ? parseInt(m[1], 10) : 0;\n } else if (upper.startsWith('SMD')) {\n prefix = 'smd';\n const m = upper.match(/^SMD(\\d+)/);\n num = m ? parseInt(m[1], 10) : 0;\n } else if (upper.startsWith('SM')) {\n prefix = 'sm';\n const m = upper.match(/^SM(\\d+)/);\n num = m ? parseInt(m[1], 10) : 0;\n } else if (upper.startsWith('ART')) {\n prefix = 'art';\n const m = upper.match(/^ART(\\d+)/);\n num = m ? parseInt(m[1], 10) : 0;\n }\n if (prefix) add(prefix, num);\n });\n return groups;\n };\n const phoGroups = buildPhoGroups(gerberFiles);\n\n const getLayerType = (fileName) => {\n const fileNameOnly = fileName.split(/[/\\\\]/).pop();\n const fileExtension = '.' + fileNameOnly.split('.').pop().toUpperCase();\n const fileNameUpper = fileNameOnly.toUpperCase();\n const nameLower = fileNameOnly.toLowerCase();\n \n // .gbr 文件:根据文件名模式识别图层类型(必须在通用后缀匹配之前)\n if (fileExtension === '.GBR') {\n // 先检查文件名(去掉扩展名)是否直接是标准图层类型(如 GKO.gbr, GTL.gbr 等)\n const nameWithoutExt = fileNameOnly.substring(0, fileNameOnly.lastIndexOf('.')).toUpperCase();\n if (nameWithoutExt === 'GKO' || nameWithoutExt === 'GTL' || nameWithoutExt === 'GTO' || \n nameWithoutExt === 'GTS' || nameWithoutExt === 'GBL' || nameWithoutExt === 'GBS' || \n nameWithoutExt === 'GBP' || nameWithoutExt === 'GBO' || nameWithoutExt === 'GTP') {\n return nameWithoutExt;\n }\n \n // BoardOutline / Outline -> GKO (优先匹配)\n if (nameLower.includes('outline') || nameLower.includes('boardoutline')) {\n return 'GKO';\n }\n \n // TopMask / TopSolder / SolderTop -> GTS\n if (nameLower.includes('topmask') || nameLower.includes('topsolder') || \n nameLower.includes('soldertop') || nameLower.includes('maskstop')) {\n return 'GTS';\n }\n \n // BottomMask / BottomSolder / SolderBottom -> GBS\n if (nameLower.includes('bottommask') || nameLower.includes('bottomsolder') || \n nameLower.includes('solderbottom') || nameLower.includes('masksbot')) {\n return 'GBS';\n }\n \n // TopSilk / SilkTop / TopLegend -> GTO\n if (nameLower.includes('topsilk') || nameLower.includes('silktop') || \n nameLower.includes('toplegend') || nameLower.includes('legendtop')) {\n return 'GTO';\n }\n \n // BottomSilk / SilkBottom / BottomLegend -> GBO\n if (nameLower.includes('bottomsilk') || nameLower.includes('silkbottom') || \n nameLower.includes('bottomlegend') || nameLower.includes('legendbottom')) {\n return 'GBO';\n }\n \n // TopPaste / PasteTop -> GTP\n if (nameLower.includes('toppaste') || nameLower.includes('pastetop')) {\n return 'GTP';\n }\n \n // BottomPaste / PasteBottom -> GBP\n if (nameLower.includes('bottompaste') || nameLower.includes('pastebottom')) {\n return 'GBP';\n }\n \n // L1 / Layer1 / Top (铜层) -> GTL\n if (nameLower.includes('l1') || nameLower.includes('layer1') || \n (nameLower.includes('top') && !nameLower.includes('paste') && !nameLower.includes('mask') && !nameLower.includes('silk'))) {\n return 'GTL';\n }\n \n // L4 / Layer4 / Bottom (铜层) -> GBL\n if (nameLower.includes('l4') || nameLower.includes('layer4') || \n (nameLower.includes('bottom') && !nameLower.includes('paste') && !nameLower.includes('mask') && !nameLower.includes('silk'))) {\n return 'GBL';\n }\n \n // legend_Top / Legend_Top -> GTO (保留兼容性)\n if (nameLower.includes('legend_top') || \n (nameLower.includes('legend') && nameLower.includes('top') && !nameLower.includes('signal'))) {\n return 'GTO';\n }\n \n // Paste_Top -> GTP (保留兼容性)\n if (nameLower.includes('paste_top')) return 'GTP';\n \n // Paste_Bot -> GBP (保留兼容性)\n if (nameLower.includes('paste_bot')) return 'GBP';\n \n // soldermask_Top / Soldermask_Top -> GTS (保留兼容性)\n if (nameLower.includes('soldermask_top')) return 'GTS';\n \n // soldermask_Bot / Soldermask_Bot -> GBS (保留兼容性)\n if (nameLower.includes('soldermask_bot')) return 'GBS';\n \n // signal_1 -> SIG2, signal_2 -> SIG3, 依次类推 (包括 Copper_Signal_1, Copper_Signal_2)\n // 注意:这个匹配必须在 signal_Top/Bot 之前,避免误匹配\n const signalMatch = nameLower.match(/(?:copper_)?signal[_\\s](\\d+)/i);\n if (signalMatch) {\n const number = parseInt(signalMatch[1], 10);\n const displayNumber = number + 1;\n return 'SIG' + displayNumber;\n }\n \n // signal_Top -> GTL (包括 Copper_Signal_Top)\n if (nameLower.includes('signal_top') || nameLower.includes('copper_signal_top')) return 'GTL';\n \n // signal_Bot -> GBL (包括 Copper_Signal_Bot)\n if (nameLower.includes('signal_bot') || nameLower.includes('copper_signal_bot')) return 'GBL';\n \n // Profile -> GKO (保留兼容性)\n if (fileNameUpper.includes('PROFILE')) return 'GKO';\n \n // WX -> GKO (轮廓层,常见于 CAM350 等工具)\n if (nameWithoutExt === 'WX' || fileNameUpper.includes('WX')) return 'GKO';\n \n // L2 / Layer2 / Inner1 -> SIG2 (内层)\n if (nameLower.includes('l2') || nameLower.includes('layer2') || nameLower.includes('inner 1') || nameLower.includes('inner1')) {\n return 'SIG2';\n }\n \n // L3 / Layer3 / Inner2 -> SIG3 (内层)\n if (nameLower.includes('l3') || nameLower.includes('layer3') || nameLower.includes('inner 2') || nameLower.includes('inner2')) {\n return 'SIG3';\n }\n \n // ZH-TOP -> GTS (保留兼容性)\n if (fileNameUpper.startsWith('ZH-TOP') || fileNameUpper.includes('ZH-TOP')) return 'GTS';\n // ZH-BOT -> GBS (保留兼容性)\n if (fileNameUpper.startsWith('ZH-BOT') || fileNameUpper.includes('ZH-BOT')) return 'GBS';\n // XL-TOP -> GTL (保留兼容性)\n if (fileNameUpper.startsWith('XL-TOP') || fileNameUpper.includes('XL-TOP')) return 'GTL';\n // XL-BOT -> GBL (保留兼容性)\n if (fileNameUpper.startsWith('XL-BOT') || fileNameUpper.includes('XL-BOT')) return 'GBL';\n\n // KiCad 命名(与 2D 一致):Edge_Cuts / F.Cu / B.Cu / InN.Cu\n if (/EDGE[._-]CUTS/i.test(fileNameUpper)) return 'GKO';\n if (/F[._-]CU\\b/i.test(fileNameUpper)) return 'GTL';\n if (/B[._-]CU\\b/i.test(fileNameUpper)) return 'GBL';\n const inCuGbr = fileNameUpper.match(/IN(\\d+)[._-]CU/i);\n if (inCuGbr) return 'SIG' + (parseInt(inCuGbr[1], 10) + 1);\n \n // 检查是否包含特定关键词,如果包含则显示关键词部分\n const keywords = ['_Drawing', '_Drillmap', '_NPTH', '_Pads', '_PTH'];\n for (const keyword of keywords) {\n if (fileNameOnly.includes(keyword)) {\n // 提取关键词及其后面的部分(包含扩展名)\n const keywordIndex = fileNameOnly.indexOf(keyword);\n return fileNameOnly.substring(keywordIndex);\n }\n }\n \n // 其他 .gbr 文件显示完整文件名(包含扩展名)\n return fileNameOnly;\n }\n \n // .pho 文件:根据文件名前缀和数字大小识别图层类型\n if (fileExtension === '.PHO') {\n if (fileNameUpper.startsWith('SST')) return 'GTO';\n const pickByGroup = (prefix, topType, botType, defaultType = null) => {\n const m = fileNameUpper.match(new RegExp(`^${prefix}(\\\\d+)`));\n const num = m ? parseInt(m[1], 10) : 0;\n const g = phoGroups.get(prefix.toLowerCase());\n if (g) {\n return num === g.min ? topType : botType;\n }\n return defaultType || topType;\n };\n if (fileNameUpper.startsWith('SMD')) {\n return pickByGroup('SMD', 'GTP', 'GBP', 'GTP');\n }\n if (fileNameUpper.startsWith('SM')) {\n return pickByGroup('SM', 'GTS', 'GBS', 'GTS');\n }\n if (fileNameUpper.startsWith('ART')) {\n return pickByGroup('ART', 'GTL', 'GBL', 'GTL');\n }\n if (fileNameUpper.startsWith('SSB')) return 'GBO';\n }\n \n // 检查文件名后缀模式\n if (fileNameUpper.endsWith('_SST') || fileNameUpper.includes('_SST.')) return 'GTO';\n if (fileNameUpper.endsWith('_PMT') || fileNameUpper.includes('_PMT.')) return 'GTP';\n if (fileNameUpper.endsWith('_SMT') || fileNameUpper.includes('_SMT.')) return 'GTS';\n if (fileNameUpper.endsWith('_TOP') || fileNameUpper.includes('_TOP.')) return 'GTL';\n if (fileNameUpper.endsWith('_SMB') || fileNameUpper.includes('_SMB.')) return 'GBS';\n if (fileNameUpper.endsWith('_PMB') || fileNameUpper.includes('_PMB.')) return 'GBP';\n if (fileNameUpper.endsWith('_SSB') || fileNameUpper.includes('_SSB.')) return 'GBO';\n if (fileNameUpper.includes('OUTLINE')) return 'GKO';\n \n // _INT+数字\n if (/.*_INT\\d+$/i.test(fileNameUpper) || /.*_INT\\d+\\./i.test(fileNameUpper)) return fileNameOnly;\n \n // 标准扩展名\n if (fileExtension === '.GTO') return 'GTO';\n if (fileExtension === '.GTP') return 'GTP';\n if (fileExtension === '.GTS') return 'GTS';\n if (fileExtension === '.GTL') return 'GTL';\n if (fileExtension === '.GBL') return 'GBL';\n if (fileExtension === '.GBS') return 'GBS';\n if (fileExtension === '.GBP') return 'GBP';\n if (fileExtension === '.GBO') return 'GBO';\n if (fileExtension === '.GKO' || fileNameUpper.includes('PROFILE')) return 'GKO';\n // GM+数字:只有 GM1, GM2 可以作为轮廓层,GM3 及以上不渲染\n if (fileExtension === '.GM1' || fileExtension === '.GM2') return 'GKO';\n if (fileExtension === '.GM' || fileExtension === '.GML' || fileExtension === '.OUTLINE' || fileExtension === '.OUT' || fileExtension === '.OLN') return 'GKO';\n \n // 检查扩展名\n if (fileExtension === '.D' || fileExtension === '.DRL' || fileExtension === '.DRI') {\n // 特殊命名:np.drl(非金属化孔)与 p.drl(金属化孔)\n if (fileNameUpper === 'NP.DRL' || fileNameUpper === 'NP.D') return 'DRL2';\n if (fileNameUpper === 'P.DRL' || fileNameUpper === 'P.D') return 'DRL';\n return 'DRL';\n }\n if (fileExtension === '.ROU') return 'rout';\n \n // CAM350 等软件导出的扩展名映射\n if (fileExtension === '.BOT') return 'GBL'; // 底层铜\n if (fileExtension === '.TOP') return 'GTL'; // 顶层铜\n if (fileExtension === '.SOB') return 'GBS'; // 底层阻焊 (Solder mask Bottom)\n if (fileExtension === '.SOT') return 'GTS'; // 顶层阻焊 (Solder mask Top)\n if (fileExtension === '.SST') return 'GTO'; // 顶层丝印 (Silkscreen Top)\n if (fileExtension === '.SSB') return 'GBO'; // 底层丝印 (Silkscreen Bottom)\n if (fileExtension === '.SMT') return 'GTS'; // 顶层阻焊 (Solder Mask Top)\n if (fileExtension === '.SMB') return 'GBS'; // 底层阻焊 (Solder Mask Bottom)\n if (fileExtension === '.PMT') return 'GTP'; // 顶层锡膏 (Paste Mask Top)\n if (fileExtension === '.PMB') return 'GBP'; // 底层锡膏 (Paste Mask Bottom)\n // CAM350: .SER 通常是丝印(Top),统一按 GTO 渲染\n if (fileExtension === '.SER') return 'GTO'; // 丝印层 (Silkscreen Top)\n if (fileExtension === '.ART') {\n // .art 文件:按文件名(不含扩展名)映射为标准层类型\n // SST -> GTO, SMT -> GTS, Top -> GTL, Bot -> GBL, SMB -> GBS, SSB -> GBO, OUT -> GKO\n // LAY2/LAY3/... -> 中间层(SIG2, SIG3, ...)\n const dot = fileNameOnly.lastIndexOf('.');\n const stemUpper = (dot > 0 ? fileNameOnly.substring(0, dot) : fileNameOnly).toUpperCase();\n if (stemUpper === 'SST') return 'GTO';\n if (stemUpper === 'SMT') return 'GTS';\n if (stemUpper === 'TOP') return 'GTL';\n if (stemUpper === 'BOT') return 'GBL';\n if (stemUpper === 'SMB') return 'GBS';\n if (stemUpper === 'SSB') return 'GBO';\n if (stemUpper === 'OUT') return 'GKO';\n // LAY2, LAY3, ... -> SIG2, SIG3, ...(中间铜层)\n const layMatch = stemUpper.match(/^LAY(\\d+)$/);\n if (layMatch) {\n const layerNum = parseInt(layMatch[1], 10);\n return 'SIG' + layerNum;\n }\n // 其余 .art:保持文件名展示(但不强行映射为某个标准层)\n return fileNameOnly;\n }\n\n // KiCad/Protel:内层铜 .g1/.g2/.g3…(文件名常带 InN_Cu)\n const gExtMatch = fileExtension.match(/^\\.G(\\d+)$/i);\n if (gExtMatch) {\n const inCu = fileNameUpper.match(/IN(\\d+)[._-]CU/i);\n if (inCu) return 'SIG' + (parseInt(inCu[1], 10) + 1);\n const gn = parseInt(gExtMatch[1], 10);\n return 'SIG' + (gn + 1);\n }\n const gpExtMatch = fileExtension.match(/^\\.GP(\\d+)$/i);\n if (gpExtMatch) {\n return 'GP' + parseInt(gpExtMatch[1], 10);\n }\n \n return null;\n };\n \n // 分类文件\n const outlineFiles = [];\n const topCopperFiles = [];\n const bottomCopperFiles = [];\n const topMaskFiles = [];\n const bottomMaskFiles = [];\n const topPasteFiles = [];\n const bottomPasteFiles = [];\n const topSilkFiles = [];\n const bottomSilkFiles = [];\n const innerCopperFiles = [];\n \n for (const file of gerberFiles) {\n // 检查是否是 .pho 文件,如果是则跳过(pho文件会单独处理)\n const fileNameOnly = file.name.split(/[/\\\\]/).pop() || '';\n const fileExtension = '.' + fileNameOnly.split('.').pop().toUpperCase();\n if (fileExtension === '.PHO') {\n continue; // pho文件会通过 renderPhoFiles 单独处理\n }\n\n const layerType = getLayerType(file.name);\n if (layerType === 'GKO') {\n outlineFiles.push(file);\n } else if (layerType === 'GTL') {\n topCopperFiles.push(file);\n } else if (layerType === 'GBL') {\n bottomCopperFiles.push(file);\n } else if (layerType === 'GTS') {\n topMaskFiles.push(file);\n } else if (layerType === 'GBS') {\n bottomMaskFiles.push(file);\n } else if (layerType === 'GTP') {\n topPasteFiles.push(file);\n } else if (layerType === 'GBP') {\n bottomPasteFiles.push(file);\n } else if (layerType === 'GTO') {\n topSilkFiles.push(file);\n } else if (layerType === 'GBO') {\n bottomSilkFiles.push(file);\n } else if (layerType && /^SIG\\d+$/i.test(layerType)) {\n innerCopperFiles.push(file);\n }\n }\n \n // 降级策略:如果找不到标准轮廓层,尝试使用 GM2(GM3 及以上不渲染)\n if (outlineFiles.length === 0) {\n const fallbackFiles = gerberFiles.filter(f => {\n const name = f.name.toLowerCase();\n return name.endsWith('.gm2');\n });\n if (fallbackFiles.length > 0) {\n outlineFiles.push(...fallbackFiles);\n // debugLog('No GKO/GM1 found, falling back to:', fallbackFiles.map(f => f.name));\n }\n }\n\n // 2.2 轮廓层兜底选择:避免某个异常“轮廓/机械层”文件把基材 bbox 撑爆\n // 策略:\n // - 列出所有被识别为轮廓层(GKO)的文件及其 bbox\n // - 若存在参考层(优先铜层/丝印/阻焊),选择与参考 bbox 最匹配的轮廓文件\n // - 其余轮廓候选直接忽略(不参与基材尺寸计算)\n const pickBestOutlineFiles = async () => {\n if (!outlineFiles || outlineFiles.length <= 1) return { files: outlineFiles || [], refBbox: null };\n\n const baseNameUpper = (name) => (name.split(/[/\\\\]/).pop() || '').toUpperCase();\n const isExt = (nameUpper, extUpper) => nameUpper.endsWith(extUpper);\n const outlineCandidates = [...outlineFiles];\n\n // 选一个参考层 bbox(用于判断哪个轮廓是“真正的板外形”)\n const pickReferenceFile = () => {\n return (\n topCopperFiles[0] ||\n bottomCopperFiles[0] ||\n topSilkFiles[0] ||\n bottomSilkFiles[0] ||\n topMaskFiles[0] ||\n bottomMaskFiles[0] ||\n topPasteFiles[0] ||\n bottomPasteFiles[0] ||\n null\n );\n };\n\n const getReferenceBbox = async () => {\n const refFile = pickReferenceFile();\n if (!refFile) return null;\n try {\n const res = await GerberParser.parseFile(refFile, '#ffffff');\n if (!res || !res.data) return null;\n const bbox = this.calculateLayerBbox([res.data]);\n if (!bbox || bbox.isEmpty()) return null;\n let scale = 1.0;\n if (res.units === 'in' || res.units === 'inch') scale = 25.4;\n bbox.min.multiplyScalar(scale);\n bbox.max.multiplyScalar(scale);\n return { bbox, refFileName: refFile.name, scale, units: res.units };\n } catch (e) {\n return null;\n }\n };\n\n const computeOutlineBbox = async (file) => {\n const nameUpper = baseNameUpper(file.name);\n const parser = new GerberOutlineParser();\n const text = await file.text();\n const { shapes, strokes } = parser.parse(text);\n\n let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;\n let pointCount = 0;\n\n const pushXY = (x, y) => {\n if (!Number.isFinite(x) || !Number.isFinite(y)) return;\n if (x < minX) minX = x;\n if (x > maxX) maxX = x;\n if (y < minY) minY = y;\n if (y > maxY) maxY = y;\n pointCount++;\n };\n\n // Prefer curves endpoints (cheap) over getPoints (alloc-heavy)\n const consumeShape = (s) => {\n const curves = s?.curves || [];\n if (curves.length > 0) {\n for (const c of curves) {\n if (c?.isLineCurve) {\n const v1 = c.v1;\n const v2 = c.v2;\n if (v1) pushXY(v1.x, v1.y);\n if (v2) pushXY(v2.x, v2.y);\n } else {\n const p0 = c?.getPoint?.(0);\n const p1 = c?.getPoint?.(1);\n if (p0) pushXY(p0.x, p0.y);\n if (p1) pushXY(p1.x, p1.y);\n }\n }\n return;\n }\n // Fallback (rare)\n const pts = s?.getPoints?.() || [];\n for (const p of pts) pushXY(p.x, p.y);\n };\n\n if (shapes && shapes.length > 0) {\n for (const s of shapes) consumeShape(s);\n }\n\n if (pointCount === 0 && strokes && strokes.length > 0) {\n for (const seg of strokes) {\n pushXY(seg.start.x, seg.start.y);\n pushXY(seg.end.x, seg.end.y);\n }\n }\n\n const valid = Number.isFinite(minX) && Number.isFinite(maxX) && Number.isFinite(minY) && Number.isFinite(maxY) &&\n maxX > minX && maxY > minY;\n if (!valid) {\n return {\n file,\n name: file.name,\n nameUpper,\n valid: false,\n shapesCount: shapes?.length || 0,\n strokesCount: strokes?.length || 0\n };\n }\n\n const bbox = new THREE.Box3(\n new THREE.Vector3(minX, minY, 0),\n new THREE.Vector3(maxX, maxY, 0)\n );\n const size = bbox.getSize(new THREE.Vector3());\n const center = bbox.getCenter(new THREE.Vector3());\n const area = size.x * size.y;\n\n return {\n file,\n name: file.name,\n nameUpper,\n valid: true,\n bbox,\n size,\n center,\n area,\n shapesCount: shapes?.length || 0,\n strokesCount: strokes?.length || 0\n };\n };\n\n const ref = await getReferenceBbox();\n const infos = [];\n for (const f of outlineCandidates) {\n try {\n infos.push(await computeOutlineBbox(f));\n } catch (e) {\n infos.push({ file: f, name: f.name, nameUpper: baseNameUpper(f.name), valid: false });\n }\n }\n\n // 打印候选(帮助定位到底哪个文件把 bbox 撑大)\n try {\n const logList = infos.map(i => {\n if (!i.valid) {\n return { file: i.name, valid: false, shapes: i.shapesCount || 0, strokes: i.strokesCount || 0 };\n }\n return {\n file: i.name,\n valid: true,\n w: Number(i.size.x.toFixed(2)),\n h: Number(i.size.y.toFixed(2)),\n area: Number(i.area.toFixed(2)),\n cx: Number(i.center.x.toFixed(2)),\n cy: Number(i.center.y.toFixed(2)),\n shapes: i.shapesCount || 0,\n strokes: i.strokesCount || 0\n };\n });\n debugWarn('[3D-new][OutlineCandidates] 轮廓候选文件 bbox 列表:', logList);\n if (ref?.bbox) {\n const refSize = ref.bbox.getSize(new THREE.Vector3());\n const refCenter = ref.bbox.getCenter(new THREE.Vector3());\n debugWarn('[3D-new][OutlineCandidates] 参考层:', {\n file: ref.refFileName,\n units: ref.units,\n scale: ref.scale,\n w: Number(refSize.x.toFixed(2)),\n h: Number(refSize.y.toFixed(2)),\n cx: Number(refCenter.x.toFixed(2)),\n cy: Number(refCenter.y.toFixed(2))\n });\n }\n } catch (e) {\n // ignore log errors\n }\n\n const validInfos = infos.filter(i => i.valid);\n if (validInfos.length === 0) return { files: outlineFiles, refBbox: ref?.bbox || null };\n\n const hasGko = validInfos.some(i => isExt(i.nameUpper, '.GKO'));\n\n const scoreInfo = (i) => {\n let score = 0;\n\n // Prefer .GKO when present (GM1/GM2 经常是机械层而不是板外形)\n if (hasGko && !isExt(i.nameUpper, '.GKO')) score += 3.0;\n if (isExt(i.nameUpper, '.GM2') || isExt(i.nameUpper, '.GM1')) score += 0.5;\n\n // Prefer candidates that actually produced closed shapes\n if ((i.shapesCount || 0) === 0 && (i.strokesCount || 0) > 0) score += 0.5;\n if ((i.shapesCount || 0) === 0 && (i.strokesCount || 0) === 0) score += 10.0;\n\n if (ref?.bbox) {\n const refBox = ref.bbox;\n const refSize = refBox.getSize(new THREE.Vector3());\n const refCenter = refBox.getCenter(new THREE.Vector3());\n\n const expandedRef = refBox.clone().expandByScalar(Math.max(10, Math.max(refSize.x, refSize.y) * 0.05)); // 5% 或至少 10mm 容错\n if (!expandedRef.intersectsBox(i.bbox)) score += 1000.0;\n\n // Size similarity\n const rx = i.size.x / Math.max(1e-9, refSize.x);\n const ry = i.size.y / Math.max(1e-9, refSize.y);\n score += Math.abs(Math.log(rx)) + Math.abs(Math.log(ry));\n\n // Center proximity\n const dist = i.center.distanceTo(refCenter);\n const maxDim = Math.max(refSize.x, refSize.y);\n score += dist / Math.max(1e-9, maxDim);\n } else {\n // No reference: avoid extreme outliers by preferring median-ish area\n // (handled after)\n }\n\n return score;\n };\n\n let chosen = null;\n let bestScore = Infinity;\n for (const i of validInfos) {\n const s = scoreInfo(i);\n if (s < bestScore) {\n bestScore = s;\n chosen = i;\n }\n }\n\n if (!chosen) return { files: outlineFiles, refBbox: ref?.bbox || null };\n\n const chosenFile = chosen.file;\n const chosenNameUpper = (chosenFile.name || '').toUpperCase();\n \n // 如果选中的是GKO,也保留GM1用于合并(与home 2D仿真一致)\n const filesToKeep = [chosenFile];\n if (chosenNameUpper.endsWith('.GKO')) {\n const gm1Files = outlineCandidates.filter(f => {\n const nameUpper = (f.name || '').toUpperCase();\n return nameUpper.endsWith('.GM1') && f !== chosenFile;\n });\n if (gm1Files.length > 0) {\n filesToKeep.push(...gm1Files);\n debugLog('[3D-new][OutlineCandidates] 🔗 发现GM1层,将与GKO合并生成完整轮廓');\n }\n }\n \n const ignored = outlineCandidates.filter(f => !filesToKeep.includes(f)).map(f => f.name);\n if (ignored.length > 0) {\n debugLog('[3D-new][OutlineCandidates] 轮廓层已选择:', filesToKeep.map(f => f.name).join(' + '), ';忽略其余:', ignored);\n } else {\n debugLog('[3D-new][OutlineCandidates] 轮廓层已选择:', filesToKeep.map(f => f.name).join(' + '));\n }\n // 🎯 返回选择的文件和参考层bbox(用于后续选择正确的外轮廓)\n return { files: filesToKeep, refBbox: ref?.bbox || null };\n };\n\n const pickResult = await pickBestOutlineFiles();\n const referenceBbox = pickResult.refBbox; // 🎯 保存参考层bbox,用于选择正确的外轮廓\n outlineFiles.splice(0, outlineFiles.length, ...pickResult.files);\n \n // 排除 Status Report.Txt 等非钻孔的文本文件\n const drillFiles = gerberFiles.filter(f => {\n const name = f.name.toLowerCase();\n return name.match(/(\\.drl|\\.dri|\\.txt|\\.drd)/i) && \n !name.includes('status report') &&\n !name.includes('.rep') &&\n !name.includes('.log') &&\n !name.includes('.apr');\n });\n \n // Debug: Log identified files\n // debugLog(`[Layer Identification] 识别到的图层文件:`);\n // debugLog(` - 轮廓层: ${outlineFiles.length} 个`);\n // debugLog(` - 顶层铜层: ${topCopperFiles.length} 个`, topCopperFiles.map(f => f.name));\n // debugLog(` - 底层铜层: ${bottomCopperFiles.length} 个`, bottomCopperFiles.map(f => f.name));\n // debugLog(` - 顶层阻焊: ${topMaskFiles.length} 个`, topMaskFiles.map(f => f.name));\n // debugLog(` - 底层阻焊: ${bottomMaskFiles.length} 个`, bottomMaskFiles.map(f => f.name));\n // debugLog(` - 顶层锡膏: ${topPasteFiles.length} 个`, topPasteFiles.map(f => f.name));\n // debugLog(` - 底层锡膏: ${bottomPasteFiles.length} 个`, bottomPasteFiles.map(f => f.name));\n // debugLog(` - 顶层丝印: ${topSilkFiles.length} 个`, topSilkFiles.map(f => f.name));\n // debugLog(` - 底层丝印: ${bottomSilkFiles.length} 个`, bottomSilkFiles.map(f => f.name));\n // debugLog(` - 钻孔文件: ${drillFiles.length} 个`, drillFiles.map(f => f.name));\n \n const endTimeClassify = performance.now()\n console.log(`[性能] 文件分类完成,耗时: ${(endTimeClassify - startTimeClassify).toFixed(2)}ms`)\n\n console.log('[性能] 开始渲染轮廓层...')\n const startTimeOutline = performance.now()\n \n // 3. Render Outline First (Base)\n let hasOutline = false;\n let fallbackLayerForCamera = null; // Store layer data for camera fitting if no outline\n const outlineStrokes = []; // 兜底线段,可视化未闭合的 G01/G02/G03\n let usedBboxOutlineFallback = false; // 标记是否用 bbox 实心板兜底(此时需要用线条描边还原异形外形)\n \n // 轮廓层阈值常量\n const OUTLINE_MIN_AREA_RATIO = 0.3; // 最小面积比(相对于bbox)\n const OUTLINE_TOTAL_AREA_RATIO = 0.5; // 总面积比阈值\n const OUTLINE_SHAPE_COUNT_LIMIT = 50; // 碎片化形状数量阈值\n const OUTLINE_FORCED_RATIO_LIMIT = 0.5; // 强制闭合比例阈值\n const OUTLINE_MERGE_TOLERANCE = 0.2; // 线段合并容差(mm)\n \n if (outlineFiles.length > 0) {\n const parser = new GerberOutlineParser();\n let shapes = [];\n \n // 解析所有轮廓文件\n for (const file of outlineFiles) {\n const text = await file.text();\n const { shapes: fileShapes, strokes } = parser.parse(text);\n if (fileShapes?.length > 0) {\n for (const s of fileShapes) shapes.push(s);\n }\n if (strokes?.length > 0) {\n for (const seg of strokes) outlineStrokes.push(seg);\n }\n }\n \n // 多文件合并:使用所有线段重新拼接成完整轮廓\n // 🎯 使用链式拼接算法(参考 home 模块),更适合异形轮廓\n if (outlineFiles.length > 1 && outlineStrokes.length > 0) {\n debugLog(`[轮廓层] 🔗 合并 ${outlineFiles.length} 个文件,线段数: ${outlineStrokes.length}`);\n const mergedShapes = stitchSegmentsToShapes(outlineStrokes);\n if (mergedShapes?.length > 0) {\n debugLog(`[轮廓层] ✅ 合并成功,生成 ${mergedShapes.length} 个形状`);\n // 按面积排序,取最大的几个形状\n mergedShapes.sort((a, b) => {\n const areaA = Math.abs(THREE.ShapeUtils.area(a.getPoints()));\n const areaB = Math.abs(THREE.ShapeUtils.area(b.getPoints()));\n return areaB - areaA;\n });\n shapes = mergedShapes; // 替换为合并后的完整形状\n }\n }\n\n debugLog(`[轮廓层] 形状: ${shapes.length}, 线段: ${outlineStrokes.length}`);\n \n // 🚀 对复杂形状进行点简化(参考home 2D仿真)\n // 使用更保守的简化策略,保留异形轮廓的细节\n const MAX_POINTS_PER_SHAPE = 3000; // 放宽限制,使用earcut三角化代替ExtrudeGeometry\n const simplifyDouglasPeucker = (points, epsilon) => {\n if (!points || points.length < 3) return points || [];\n const sq = (v) => v * v;\n const distPointToSegSq = (p, a, b) => {\n const vx = b.x - a.x;\n const vy = b.y - a.y;\n const wx = p.x - a.x;\n const wy = p.y - a.y;\n const c1 = vx * wx + vy * wy;\n if (c1 <= 0) return sq(p.x - a.x) + sq(p.y - a.y);\n const c2 = vx * vx + vy * vy;\n if (c2 <= c1) return sq(p.x - b.x) + sq(p.y - b.y);\n const t = c1 / c2;\n const px = a.x + t * vx;\n const py = a.y + t * vy;\n return sq(p.x - px) + sq(p.y - py);\n };\n const epsSq = epsilon * epsilon;\n const keep = new Array(points.length).fill(false);\n keep[0] = true;\n keep[points.length - 1] = true;\n const stack = [[0, points.length - 1]];\n while (stack.length) {\n const [s, e] = stack.pop();\n let maxD = 0;\n let idx = -1;\n const a = points[s];\n const b = points[e];\n for (let i = s + 1; i < e; i++) {\n const d = distPointToSegSq(points[i], a, b);\n if (d > maxD) {\n maxD = d;\n idx = i;\n }\n }\n if (idx >= 0 && maxD > epsSq) {\n keep[idx] = true;\n stack.push([s, idx], [idx, e]);\n }\n }\n const out = [];\n for (let i = 0; i < points.length; i++) if (keep[i]) out.push(points[i]);\n return out;\n };\n \n // 对点数过多的shapes进行保守简化\n for (let i = 0; i < shapes.length; i++) {\n const shape = shapes[i];\n let currentPoints = shape.getPoints();\n \n if (currentPoints.length > MAX_POINTS_PER_SHAPE) {\n // 计算边界尺寸\n let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;\n for (const p of currentPoints) {\n minX = Math.min(minX, p.x); maxX = Math.max(maxX, p.x);\n minY = Math.min(minY, p.y); maxY = Math.max(maxY, p.y);\n }\n const boardSize = Math.max(maxX - minX, maxY - minY);\n \n // 使用保守的容差进行简化(0.05mm,保留曲线细节)\n const targetPoints = 2000;\n // 使用固定的小容差,避免过度简化\n const epsilon = Math.max(0.05, boardSize * 0.0003); // 最小0.05mm容差\n const simplified = simplifyDouglasPeucker(currentPoints, epsilon);\n \n debugLog(`[轮廓层] 简化形状 ${i}: ${currentPoints.length} -> ${simplified.length} 点 (容差=${epsilon.toFixed(4)}mm)`);\n \n if (simplified.length >= 4) {\n // 用简化后的点创建新的Shape\n const newShape = new THREE.Shape();\n newShape.moveTo(simplified[0].x, simplified[0].y);\n for (let j = 1; j < simplified.length; j++) {\n newShape.lineTo(simplified[j].x, simplified[j].y);\n }\n newShape.closePath();\n newShape.userData = shape.userData; // 保留原有userData\n shapes[i] = newShape;\n }\n }\n }\n\n // ✅ 关键修复:为轮廓层自动“挂孔洞”\n // GerberOutlineParser 会把内轮廓(孔/开窗)解析为独立 shape,但默认不会把它们放到 outerShape.holes。\n // 这样在只渲染外轮廓 shape 时,孔洞会“缺失”(看起来像被填死/没镂空)。\n // 这里参考 2D 仿真/3dPage silkscreen 的思路:把明显位于外轮廓内部的小 shape 挂到 parent.holes。\n const attachOutlineHoles = (inputShapes, referenceBbox) => {\n if (!inputShapes || inputShapes.length <= 1) return inputShapes || [];\n\n const isPointInShape = (pt, shape) => {\n const points = shape.getPoints();\n if (!points || points.length < 3) return false;\n let inside = false;\n for (let i = 0, j = points.length - 1; i < points.length; j = i++) {\n const xi = points[i].x, yi = points[i].y;\n const xj = points[j].x, yj = points[j].y;\n if (((yi > pt.y) !== (yj > pt.y)) && (pt.x < (xj - xi) * (pt.y - yi) / (yj - yi) + xi)) inside = !inside;\n }\n return inside;\n };\n\n const signedArea = (pts) => {\n // Three.ShapeUtils.area is signed (based on winding)\n return THREE.ShapeUtils.area(pts);\n };\n\n const bboxOfShape = (s) => {\n const pts = s.getPoints();\n let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;\n for (const p of pts) {\n if (p.x < minX) minX = p.x;\n if (p.x > maxX) maxX = p.x;\n if (p.y < minY) minY = p.y;\n if (p.y > maxY) maxY = p.y;\n }\n const valid = isFinite(minX) && isFinite(maxX) && isFinite(minY) && isFinite(maxY) && maxX > minX && maxY > minY;\n if (!valid) return null;\n return { minX, minY, maxX, maxY, w: (maxX - minX), h: (maxY - minY), area: (maxX - minX) * (maxY - minY) };\n };\n\n const bboxContains = (outer, inner, pad = 0.2) => {\n return inner.minX >= outer.minX - pad &&\n inner.maxX <= outer.maxX + pad &&\n inner.minY >= outer.minY - pad &&\n inner.maxY <= outer.maxY + pad;\n };\n\n const refArea = referenceBbox && !referenceBbox.isEmpty()\n ? (referenceBbox.getSize(new THREE.Vector3()).x * referenceBbox.getSize(new THREE.Vector3()).y)\n : 0;\n\n const items = inputShapes.map(s => {\n const pts = s.getPoints();\n const area = Math.abs(THREE.ShapeUtils.area(pts));\n const bbox = bboxOfShape(s);\n let cx = 0, cy = 0;\n for (const p of pts) { cx += p.x; cy += p.y; }\n const n = Math.max(1, pts.length);\n const center = { x: cx / n, y: cy / n };\n return { shape: s, area, bbox, center };\n }).filter(i => i.area > 0.001 && i.bbox);\n\n if (items.length <= 1) return inputShapes;\n\n // 小孔阈值:对齐 home(0.005% 的板面积)\n const largestArea = items.reduce((m, it) => Math.max(m, it.area), 0);\n const minHoleArea = Math.max(0.05, largestArea * 0.00005); // 至少 0.05mm²,避免抖动碎片\n\n // 防止把“板子/拼板子块”当孔:若有参考层,则孔洞面积不能超过 refArea 的 30%\n const maxHoleAreaByRef = (refArea > 0) ? (refArea * 0.30) : Infinity;\n\n // attach: small -> large\n items.sort((a, b) => a.area - b.area);\n const isHole = new Set();\n\n for (const child of items) {\n if (child.area < minHoleArea) continue;\n if (child.area > maxHoleAreaByRef) continue;\n\n // 找最小的可包含 parent(避免把孔挂到更外层的大框上)\n let bestParent = null;\n let bestParentArea = Infinity;\n for (const parent of items) {\n if (parent === child) continue;\n if (parent.area <= child.area) continue;\n if (!bboxContains(parent.bbox, child.bbox, 0.2)) continue;\n // 额外限制:孔洞面积不能太接近 parent(防止“内层板子”被当孔)\n if ((child.area / Math.max(1e-9, parent.area)) > 0.60) continue;\n if (!isPointInShape(child.center, parent.shape)) continue;\n if (parent.area < bestParentArea) {\n bestParent = parent;\n bestParentArea = parent.area;\n }\n }\n if (bestParent) {\n // ✅ Three.js 对 holes 更“挑剔”:holes 最稳妥的是 THREE.Path,\n // 且 hole 的绕序应与外轮廓相反,否则容易出现“holes 被填死/不生效”。\n const parentPts = bestParent.shape.getPoints();\n const childPts0 = child.shape.getPoints();\n if (parentPts && parentPts.length >= 3 && childPts0 && childPts0.length >= 3) {\n let childPts = childPts0.slice();\n const parentA = signedArea(parentPts);\n const childA = signedArea(childPts);\n if (parentA * childA > 0) {\n childPts = childPts.slice().reverse();\n }\n const holePath = new THREE.Path();\n holePath.moveTo(childPts[0].x, childPts[0].y);\n for (let k = 1; k < childPts.length; k++) {\n holePath.lineTo(childPts[k].x, childPts[k].y);\n }\n holePath.closePath();\n\n bestParent.shape.holes = bestParent.shape.holes || [];\n bestParent.shape.holes.push(holePath);\n }\n isHole.add(child.shape);\n }\n }\n\n const roots = inputShapes.filter(s => !isHole.has(s));\n const holeCount = inputShapes.length - roots.length;\n if (holeCount > 0) {\n debugLog(`[Outline] ✅ 已挂孔洞: holes=${holeCount}, roots=${roots.length}`);\n }\n return roots;\n };\n\n shapes = attachOutlineHoles(shapes, referenceBbox);\n \n if (shapes.length > 0) {\n // 🎯 使用参考层中心点选择正确的外轮廓(参考home模块的逻辑)\n // 这是解决异形轮廓渲染问题的关键\n const isPointInShape = (pt, shape) => {\n const points = shape.getPoints();\n if (!points || points.length < 3) return false;\n let inside = false;\n for (let i = 0, j = points.length - 1; i < points.length; j = i++) {\n const xi = points[i].x, yi = points[i].y;\n const xj = points[j].x, yj = points[j].y;\n if (((yi > pt.y) !== (yj > pt.y)) && (pt.x < (xj - xi) * (pt.y - yi) / (yj - yi) + xi)) {\n inside = !inside;\n }\n }\n return inside;\n };\n \n // 如果有参考层bbox,使用bbox重叠度来选择正确的外轮廓(更鲁棒,不依赖中心点)\n let selectedOuterShape = null;\n let selectedOuterMeta = null; // { bbox:{minX,maxX,minY,maxY,w,h,area}, polyArea:number, overlapRatio:number }\n if (referenceBbox && !referenceBbox.isEmpty()) {\n const refCenter = referenceBbox.getCenter(new THREE.Vector3());\n const focusCenter = { x: refCenter.x, y: refCenter.y };\n const refSize = referenceBbox.getSize(new THREE.Vector3());\n const refMinX = refCenter.x - refSize.x / 2;\n const refMaxX = refCenter.x + refSize.x / 2;\n const refMinY = refCenter.y - refSize.y / 2;\n const refMaxY = refCenter.y + refSize.y / 2;\n const refArea = refSize.x * refSize.y;\n \n // ✅ 新策略:计算每个轮廓的bbox与参考层bbox的重叠面积\n const MIN_OUTER_AREA = 1.0; // mm²,过滤掉碎片/噪点\n const candidates = [];\n for (const s of shapes) {\n const area = Math.abs(THREE.ShapeUtils.area(s.getPoints()));\n if (area < MIN_OUTER_AREA) continue;\n try {\n // 计算形状bbox\n const pts = s.getPoints();\n let sMinX = Infinity, sMaxX = -Infinity, sMinY = Infinity, sMaxY = -Infinity;\n for (const p of pts) {\n if (p.x < sMinX) sMinX = p.x; if (p.x > sMaxX) sMaxX = p.x;\n if (p.y < sMinY) sMinY = p.y; if (p.y > sMaxY) sMaxY = p.y;\n }\n // 计算bbox重叠区域\n const overlapMinX = Math.max(refMinX, sMinX);\n const overlapMaxX = Math.min(refMaxX, sMaxX);\n const overlapMinY = Math.max(refMinY, sMinY);\n const overlapMaxY = Math.min(refMaxY, sMaxY);\n const overlapW = Math.max(0, overlapMaxX - overlapMinX);\n const overlapH = Math.max(0, overlapMaxY - overlapMinY);\n const overlapArea = overlapW * overlapH;\n const overlapRatio = refArea > 0 ? (overlapArea / refArea) : 0;\n \n const sW = sMaxX - sMinX;\n const sH = sMaxY - sMinY;\n const sBboxArea = sW * sH;\n\n // 如果重叠面积 > 参考层面积的30%,认为是候选\n if (overlapRatio > 0.3) {\n candidates.push({\n shape: s,\n area,\n overlapRatio,\n shapeBbox: { minX: sMinX, maxX: sMaxX, minY: sMinY, maxY: sMaxY, w: sW, h: sH, area: sBboxArea }\n });\n }\n } catch (_) { /* ignore */ }\n }\n \n if (candidates.length > 0) {\n // ✅ 改进选择策略:当多个候选 overlap 都很高时,优先选“bbox面积最接近参考层bbox”的那一个\n // (避免大外框/工艺边:它 overlap 也会很高,但 bbox 会明显更大)\n // 过滤出overlap足够高的候选(>80%)\n const highOverlapCandidates = candidates.filter(c => c.overlapRatio > 0.8);\n \n const refSize = referenceBbox.getSize(new THREE.Vector3());\n const refArea = refSize.x * refSize.y;\n \n let selectedCandidate;\n if (highOverlapCandidates.length > 1) {\n // 多个高overlap候选:优先选择 bbox 面积接近 refArea 且不小于 refArea*0.8 的\n const validBboxCandidates = highOverlapCandidates\n .filter(c => (c?.shapeBbox?.area || 0) >= refArea * 0.8);\n\n const pool = validBboxCandidates.length > 0 ? validBboxCandidates : highOverlapCandidates;\n pool.sort((a, b) => {\n const aB = a?.shapeBbox?.area || 0;\n const bB = b?.shapeBbox?.area || 0;\n return Math.abs(aB - refArea) - Math.abs(bB - refArea);\n });\n selectedCandidate = pool[0];\n debugLog(`[Outline] 🔍 多个高overlap候选,选择bbox最接近参考层的: bbox=${(selectedCandidate.shapeBbox?.area || 0).toFixed(2)}mm² (参考=${refArea.toFixed(2)}mm²), poly=${selectedCandidate.area.toFixed(2)}mm²`);\n } else {\n // 选择overlap最高的候选\n candidates.sort((a, b) => b.overlapRatio - a.overlapRatio);\n selectedCandidate = candidates[0];\n }\n \n const selectedArea = selectedCandidate.area;\n selectedOuterMeta = {\n bbox: selectedCandidate.shapeBbox || null,\n polyArea: selectedArea,\n overlapRatio: selectedCandidate.overlapRatio || 0\n };\n \n // 🎯 检查是否需要使用所有形状(拼板检测)\n \n // 如果最高重叠候选的面积明显小于参考层,且有多个候选,可能是拼板\n if (selectedArea < refArea * 0.5 && candidates.length > 1) {\n // 计算所有候选的总面积\n const totalArea = candidates.reduce((sum, c) => sum + c.area, 0);\n \n // 如果总面积接近参考层,使用所有候选(拼板模式)\n if (totalArea > refArea * 0.6) {\n debugLog(`[Outline] 🔗 检测到拼板:最高重叠=${selectedArea.toFixed(2)}mm² (overlap=${(selectedCandidate.overlapRatio * 100).toFixed(1)}%),总面积=${totalArea.toFixed(2)}mm²,使用 ${candidates.length} 个候选`);\n selectedOuterShape = null; // 不选择单个,让后续处理所有形状\n } else {\n selectedOuterShape = selectedCandidate.shape;\n debugLog(`[Outline] 🎯 使用bbox重叠选择外轮廓: 面积=${selectedArea.toFixed(2)}mm², overlap=${(selectedCandidate.overlapRatio * 100).toFixed(1)}%, 候选数=${candidates.length}`);\n }\n } else {\n selectedOuterShape = selectedCandidate.shape;\n debugLog(`[Outline] 🎯 使用bbox重叠选择外轮廓: 面积=${selectedArea.toFixed(2)}mm², overlap=${(selectedCandidate.overlapRatio * 100).toFixed(1)}%, 候选数=${candidates.length}`);\n }\n } else {\n // 🎯 参考层中心点未命中,尝试使用最大面积的形状(参考home模块逻辑)\n // 计算所有形状的面积并排序\n const shapesWithArea = shapes.map(s => ({\n shape: s,\n area: Math.abs(THREE.ShapeUtils.area(s.getPoints()))\n })).filter(item => item.area >= 1.0); // 过滤掉面积小于1mm²的碎片\n \n if (shapesWithArea.length > 0) {\n shapesWithArea.sort((a, b) => b.area - a.area);\n const maxShape = shapesWithArea[0];\n \n // 计算参考层的面积\n const refSize = referenceBbox.getSize(new THREE.Vector3());\n const refArea = refSize.x * refSize.y;\n \n // 如果最大形状面积超过参考层面积的30%,认为它是有效的外轮廓\n if (maxShape.area > refArea * 0.3) {\n selectedOuterShape = maxShape.shape;\n debugLog(`[Outline] 🎯 使用最大面积形状作为外轮廓: 面积=${maxShape.area.toFixed(2)}mm² (参考层面积=${refArea.toFixed(2)}mm²)`);\n } else {\n debugWarn(`[Outline] ⚠️ 最大形状面积过小 (${maxShape.area.toFixed(2)}mm² < ${(refArea * 0.3).toFixed(2)}mm²),回退到碎片化处理`);\n }\n } else {\n debugWarn('[Outline] ⚠️ 没有有效形状(面积>=1mm²),回退到碎片化处理');\n }\n }\n }\n \n // 如果成功选择了外轮廓,直接使用它,跳过碎片化检测\n if (selectedOuterShape) {\n // ✅ 额外兜底:如果选中外轮廓的“多边形面积”明显小于它的 bbox 面积,\n // 说明该轮廓很可能不是一个可靠的实心外形(常见于拼线/自交/半轮廓),会导致基材出现镂空/缺面。\n // 此时用 bbox 生成实心板材更稳定,同时开启线段描边以保留真实外形视觉。\n if (selectedOuterMeta?.bbox?.area && selectedOuterMeta?.polyArea) {\n const ratio = selectedOuterMeta.polyArea / Math.max(1e-9, selectedOuterMeta.bbox.area);\n // ⚠️ 只有当 poly/bbox 明显偏小(通常意味着拼线/自交/半轮廓,容易出现“基材镂空/缺面”)才做兜底。\n // 经验阈值:<60% 才认为不可靠;像 79% 这种常见异形/圆角矩形不要强制退化成矩形。\n if (ratio < 0.60) {\n // 优先使用凸包(保留异形),否则再用 bbox(矩形最稳)\n const hullShape = (outlineStrokes && outlineStrokes.length > 0)\n ? this.buildHullShapeFromSegments(outlineStrokes)\n : null;\n if (hullShape) {\n selectedOuterShape = hullShape;\n usedBboxOutlineFallback = true;\n debugWarn(`[Outline] ⚠️ 选中外形多边形面积偏小(poly/bbox=${(ratio * 100).toFixed(1)}%),改用凸包实心板兜底`);\n } else {\n const bb = selectedOuterMeta.bbox;\n const rectShape = new THREE.Shape();\n rectShape.moveTo(bb.minX, bb.minY);\n rectShape.lineTo(bb.maxX, bb.minY);\n rectShape.lineTo(bb.maxX, bb.maxY);\n rectShape.lineTo(bb.minX, bb.maxY);\n rectShape.closePath();\n selectedOuterShape = rectShape;\n usedBboxOutlineFallback = true;\n debugWarn(`[Outline] ⚠️ 选中外形多边形面积偏小(poly/bbox=${(ratio * 100).toFixed(1)}%),改用bbox实心板兜底`);\n }\n }\n }\n\n this.renderOutlineBoard([selectedOuterShape], !usedBboxOutlineFallback);\n hasOutline = true;\n debugLog('[Outline] ✅ 使用参考层选择的异形外轮廓渲染基材');\n } else {\n // 没有选择到正确的外轮廓,使用原有的碎片化检测逻辑\n \n // 预计算每个形状的面积(避免重复调用getPoints)\n const shapeInfos = shapes.map(s => ({\n shape: s,\n area: Math.abs(THREE.ShapeUtils.area(s.getPoints())),\n forcedClose: s.userData?.forcedClose || false\n }));\n \n // 统计信息\n const maxInfo = shapeInfos.reduce((max, cur) => cur.area > max.area ? cur : max);\n const forcedCount = shapeInfos.filter(info => info.forcedClose).length;\n const totalArea = shapeInfos.reduce((sum, info) => sum + info.area, 0);\n \n // 构建多种兜底形状:凸包(保留异形)和 bbox(简单矩形)\n const shapeBboxShape = this.buildBBoxShapeFromShapes(shapes);\n const strokeBboxShape = outlineStrokes.length > 0 ? this.buildBBoxShapeFromSegments(outlineStrokes) : null;\n const strokeHullShape = outlineStrokes.length > 0 ? this.buildHullShapeFromSegments(outlineStrokes) : null;\n \n // 计算各形状面积\n const shapeBboxArea = shapeBboxShape ? Math.abs(THREE.ShapeUtils.area(shapeBboxShape.getPoints())) : 0;\n const strokeBboxArea = strokeBboxShape ? Math.abs(THREE.ShapeUtils.area(strokeBboxShape.getPoints())) : 0;\n const strokeHullArea = strokeHullShape ? Math.abs(THREE.ShapeUtils.area(strokeHullShape.getPoints())) : 0;\n \n // 选择面积更大的bbox用于面积比较\n const bboxShape = strokeBboxArea > shapeBboxArea ? strokeBboxShape : shapeBboxShape;\n const bboxArea = Math.max(shapeBboxArea, strokeBboxArea);\n \n // 🎯 异形优先:当有凸包时,优先使用凸包作为碎片化兜底(保留异形轮廓)\n const fallbackShape = strokeHullShape && strokeHullArea > 0 ? strokeHullShape : bboxShape;\n const fallbackType = strokeHullShape && strokeHullArea > 0 ? '凸包' : '矩形';\n \n if (strokeHullShape && strokeHullArea > 0) {\n debugLog(`[Outline] 凸包可用于异形兜底(面积=${strokeHullArea.toFixed(2)}mm²)`);\n }\n \n let finalShapes = shapes;\n // 额外兜底:如果最大形状是“强制闭合”的(forcedClose),说明拼线没有形成可靠闭环,\n // Three.js 三角化很容易出现大片缺失(你截图里的“斜三角缺口/缺一块板”就是典型症状)。\n // ✅ 改进策略:\n // - forcedClose 的最大轮廓必须“接近参考外形面积”(凸包优先,其次 bbox),否则强制回退\n // - 如果存在 non-forcedClose 的大轮廓,也优先选它(避免 forcedClose 造成缺口)\n if (bboxShape && bboxArea > 0) {\n let maxShape = null;\n let maxArea = 0;\n let forcedCount = 0;\n let bestNonForced = null;\n let bestNonForcedArea = 0;\n for (const s of shapes) {\n const a = Math.abs(THREE.ShapeUtils.area(s.getPoints()));\n const isForced = !!s?.userData?.forcedClose;\n if (isForced) forcedCount++;\n if (!isForced && a > bestNonForcedArea) {\n bestNonForcedArea = a;\n bestNonForced = s;\n }\n if (a > maxArea) {\n maxArea = a;\n maxShape = s;\n }\n }\n \n // 参考面积:优先凸包(更接近外轮廓),否则 bbox\n const refAreaForOutline = strokeHullArea > 0 ? strokeHullArea : bboxArea;\n const forcedAreaRatio = refAreaForOutline > 0 ? (maxArea / refAreaForOutline) : 0;\n const forcedLooksGood = forcedAreaRatio >= 0.85; // forcedClose 仍可接受的最低比例\n\n if (maxShape?.userData?.forcedClose) {\n // 如果存在非 forcedClose 的大轮廓,优先它(避免 forcedClose 导致的缺口)\n if (bestNonForced && bestNonForcedArea > 0 && bestNonForcedArea >= refAreaForOutline * 0.6) {\n finalShapes = [bestNonForced];\n debugWarn(`[Outline] 最大轮廓为强制闭合,改用非强制闭合外轮廓 (area=${bestNonForcedArea.toFixed(2)}mm²)`);\n } else if (!forcedLooksGood) {\n // forcedClose 面积明显偏小:强制回退凸包/矩形,避免“缺一块板”\n finalShapes = [fallbackShape];\n debugWarn(`[Outline] 最大轮廓为强制闭合且面积偏小(ratio=${(forcedAreaRatio * 100).toFixed(1)}%),使用${fallbackType}兜底`);\n } else if (maxArea < bboxArea * OUTLINE_MIN_AREA_RATIO) {\n // 极端小面积:仍走原有兜底\n finalShapes = [fallbackShape];\n debugWarn(`[Outline] 最大轮廓为强制闭合且面积过小,使用${fallbackType}兜底`);\n } else {\n // forcedClose 但面积接近参考:保留异形\n debugLog(`[Outline] 最大轮廓为强制闭合但面积接近参考(ratio=${(forcedAreaRatio * 100).toFixed(1)}%),使用异形轮廓`);\n }\n } else if (maxArea < bboxArea * OUTLINE_MIN_AREA_RATIO && (shapes.length > OUTLINE_SHAPE_COUNT_LIMIT || (forcedCount / Math.max(1, shapes.length)) > OUTLINE_FORCED_RATIO_LIMIT)) {\n // 典型拼板/网格轮廓:会产生大量小闭环(单块板/开槽等),但缺少“单一的大外轮廓”。\n // 🎯 改进:使用凸包保留异形外轮廓,而不是简单的矩形\n finalShapes = [fallbackShape];\n const forcedRatio = forcedCount / Math.max(1, shapes.length);\n debugWarn(`[Outline] 轮廓碎片化(面积=${maxArea.toFixed(2)}mm²,形状数=${shapes.length},强制闭合比=${forcedRatio.toFixed(2)}),使用${fallbackType}兜底`);\n } else {\n const localTotalArea = shapes.reduce((acc, s) => acc + Math.abs(THREE.ShapeUtils.area(s.getPoints())), 0);\n if (localTotalArea < bboxArea * OUTLINE_TOTAL_AREA_RATIO) {\n finalShapes = [fallbackShape];\n debugLog(`[Outline] 总面积过小,使用${fallbackType}兜底`);\n }\n }\n }\n // 若退化成凸包/bbox:不要画边框,后面用真实轮廓线段描边;\n // 否则直接在板体上绘制黑色边框线。\n const usedBboxSolid = fallbackShape && finalShapes.length === 1 && finalShapes[0] === fallbackShape;\n usedBboxOutlineFallback = usedBboxSolid;\n this.renderOutlineBoard(finalShapes, !usedBboxSolid);\n hasOutline = true;\n } // 关闭 else { ... } 分支(selectedOuterShape 未选中时的碎片化处理)\n } else if (outlineStrokes.length > 0) {\n // 如果没有闭合形状但有线段,计算线段的外接矩形作为 bbox\n const strokeBboxShape = this.buildBBoxShapeFromSegments(outlineStrokes);\n if (strokeBboxShape) {\n // 计算 bbox\n const allPoints = strokeBboxShape.getPoints().map(p => new THREE.Vector3(p.x, p.y, 0));\n const bbox = new THREE.Box3().setFromPoints(allPoints);\n this.outlineBbox = bbox.clone();\n debugLog(`[轮廓层] 使用线段外接矩形作为bbox: ${bbox.getSize(new THREE.Vector3()).x.toFixed(2)} x ${bbox.getSize(new THREE.Vector3()).y.toFixed(2)}`);\n }\n // debugWarn('未从轮廓层提取到闭合形状,跳过轮廓层渲染,继续渲染其他图层。');\n } else {\n // 🚀 轮廓层解析失败(无形状无线段),使用其他层计算外接矩形作为基材\n debugWarn('[3D-new] 轮廓层解析失败(无形状无线段),尝试从其他层计算外接矩形作为基材...');\n const fallbackFilesForOutline = [...topMaskFiles, ...bottomMaskFiles, ...topCopperFiles, ...bottomCopperFiles];\n \n if (fallbackFilesForOutline.length > 0) {\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;\n let hasValidBounds = false;\n \n for (const file of fallbackFilesForOutline) {\n try {\n const res = await GerberParser.parseFile(file, '#ffffff');\n \n if (res && res.data && res.data.vertices && res.data.vertices.length > 0) {\n let scale = 1.0;\n if (res.units === 'in' || res.units === 'inch') {\n scale = 25.4;\n }\n \n for (let i = 0; i < res.data.vertices.length; i += 3) {\n const x = res.data.vertices[i] * scale;\n const y = -res.data.vertices[i + 1] * scale;\n if (x < minX) minX = x;\n if (x > maxX) maxX = x;\n if (y < minY) minY = y;\n if (y > maxY) maxY = y;\n }\n hasValidBounds = true;\n }\n } catch (e) {\n debugWarn(`[3D-new] 从 ${file.name} 计算边界失败:`, e.message);\n }\n }\n \n if (hasValidBounds && isFinite(minX) && isFinite(maxX) && isFinite(minY) && isFinite(maxY)) {\n const width = maxX - minX;\n const height = maxY - minY;\n \n debugLog(`[3D-new] 轮廓解析失败回退:计算得到外接矩形: ${width.toFixed(2)} x ${height.toFixed(2)}`);\n \n const padding = Math.max(width, height) * 0.02;\n const rectShape = new THREE.Shape();\n rectShape.moveTo(minX - padding, minY - padding);\n rectShape.lineTo(maxX + padding, minY - padding);\n rectShape.lineTo(maxX + padding, maxY + padding);\n rectShape.lineTo(minX - padding, maxY + padding);\n rectShape.lineTo(minX - padding, minY - padding);\n \n this.renderOutlineBoard([rectShape], false);\n hasOutline = true;\n \n // 设置 outlineBbox\n const bboxPoints = rectShape.getPoints().map(p => new THREE.Vector3(p.x, p.y, 0));\n this.outlineBbox = new THREE.Box3().setFromPoints(bboxPoints);\n }\n }\n }\n } else {\n // 尝试从其他层的外接矩形创建基材\n debugWarn('[3D-new] 未找到轮廓层文件,尝试从其他层计算外接矩形作为基材...');\n const fallbackFiles = [...topMaskFiles, ...bottomMaskFiles, ...topCopperFiles, ...bottomCopperFiles];\n \n if (fallbackFiles.length > 0) {\n // 解析所有文件并计算总外接矩形\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;\n let hasValidBounds = false;\n \n for (const file of fallbackFiles) {\n try {\n const res = await GerberParser.parseFile(file, '#ffffff');\n \n if (res && res.data && res.data.vertices && res.data.vertices.length > 0) {\n // 计算缩放比例(inch -> mm)\n let scale = 1.0;\n if (res.units === 'in' || res.units === 'inch') {\n scale = 25.4;\n }\n \n // 遍历所有顶点 (vertices 是 Float32Array,每3个为一组:x, y, z)\n for (let i = 0; i < res.data.vertices.length; i += 3) {\n const x = res.data.vertices[i] * scale;\n const y = -res.data.vertices[i + 1] * scale; // Y轴翻转\n if (x < minX) minX = x;\n if (x > maxX) maxX = x;\n if (y < minY) minY = y;\n if (y > maxY) maxY = y;\n }\n hasValidBounds = true;\n debugLog(`[3D-new] 从 ${file.name} 提取边界: minX=${minX.toFixed(2)}, maxX=${maxX.toFixed(2)}, minY=${minY.toFixed(2)}, maxY=${maxY.toFixed(2)}`);\n }\n } catch (e) {\n debugWarn(`[3D-new] 从 ${file.name} 计算边界失败:`, e.message);\n }\n }\n \n // 如果计算到了有效边界,创建矩形基材\n if (hasValidBounds && isFinite(minX) && isFinite(maxX) && isFinite(minY) && isFinite(maxY)) {\n const width = maxX - minX;\n const height = maxY - minY;\n const centerX = (minX + maxX) / 2;\n const centerY = (minY + maxY) / 2;\n \n debugLog(`[3D-new] 计算得到外接矩形: ${width.toFixed(2)} x ${height.toFixed(2)}, 中心=(${centerX.toFixed(2)}, ${centerY.toFixed(2)})`);\n \n // 添加小边距(2%)\n const padding = Math.max(width, height) * 0.02;\n const rectShape = new THREE.Shape();\n rectShape.moveTo(minX - padding, minY - padding);\n rectShape.lineTo(maxX + padding, minY - padding);\n rectShape.lineTo(maxX + padding, maxY + padding);\n rectShape.lineTo(minX - padding, maxY + padding);\n rectShape.lineTo(minX - padding, minY - padding);\n \n this.renderOutlineBoard([rectShape], false);\n hasOutline = true;\n } else {\n debugWarn('[3D-new] 无法计算有效边界');\n }\n }\n \n if (!hasOutline) {\n // 如果仍然没有轮廓,设置默认厚度并清空场景\n debugWarn('[3D-new] 无法从任何层提取轮廓,跳过基材渲染');\n BOARD_THICKNESS = 1.6; // 默认1.6mm\n this.clearScene();\n \n // Store first available layer for camera fitting (priority: GTO > GTL)\n if (topSilkFiles.length > 0) {\n fallbackLayerForCamera = { type: 'GTO', files: topSilkFiles };\n } else if (topCopperFiles.length > 0) {\n fallbackLayerForCamera = { type: 'GTL', files: topCopperFiles };\n }\n }\n }\n\n // 轮廓描边:当轮廓层被兜底成“实心矩形”时,用真实轮廓线段绘制黑色描边,\n // 这样即使基材是矩形,也能看出异形外轮廓。\n if (outlineStrokes.length > 0) {\n const MAX_STROKES_FOR_BORDER = 200000;\n if (outlineStrokes.length > MAX_STROKES_FOR_BORDER) {\n debugWarn(`[Outline] 线段数量过多(${outlineStrokes.length}),跳过黑色描边以避免性能问题`);\n } else if (usedBboxOutlineFallback) {\n BOARD_THICKNESS = BOARD_THICKNESS || 1.6;\n const zTop = BOARD_THICKNESS / 2 + 0.05;\n const zBottom = -BOARD_THICKNESS / 2 - 0.05 + 0.001;\n this.renderOutlineStrokes(outlineStrokes, 0.10, COLORS.OUTLINE_EDGE, zTop);\n this.renderOutlineStrokes(outlineStrokes, 0.10, COLORS.OUTLINE_EDGE, zBottom);\n } else if (!hasOutline) {\n // 没有闭合面但有线段:至少渲染线框作为轮廓提示\n BOARD_THICKNESS = BOARD_THICKNESS || 1.6;\n const zTop = BOARD_THICKNESS / 2 + 0.05;\n const zBottom = -BOARD_THICKNESS / 2 - 0.05 + 0.001;\n this.renderOutlineStrokes(outlineStrokes, 0.10, COLORS.OUTLINE_EDGE, zTop);\n this.renderOutlineStrokes(outlineStrokes, 0.10, COLORS.OUTLINE_EDGE, zBottom);\n hasOutline = true;\n }\n }\n \n const endTimeOutline = performance.now()\n console.log(`[性能] 轮廓层渲染完成,耗时: ${(endTimeOutline - startTimeOutline).toFixed(2)}ms`)\n\n console.log('[性能] 开始渲染其他图层...')\n const startTimeOtherLayers = performance.now()\n \n // 4. Render Other Layers\n console.log(`[3D-new] 开始渲染其他图层,文件分组情况:`,\n `轮廓: ${outlineFiles.length}`, \n `顶铜: ${topCopperFiles.length}`,\n `内层铜: ${innerCopperFiles.length}`,\n `底铜: ${bottomCopperFiles.length}`,\n `顶阻焊: ${topMaskFiles.length}`,\n `底阻焊: ${bottomMaskFiles.length}`,\n `顶丝印: ${topSilkFiles.length}`,\n `底丝印: ${bottomSilkFiles.length}`,\n `钻孔: ${drillFiles.length}`\n );\n \n // Helper to parse regular layers\n const parseLayer = async (file) => {\n const res = await GerberParser.parseFile(file, '#ffffff');\n return res; // Return full result object with units\n };\n\n const processLayerGroup = async (files, renderer, z, isTop) => {\n for (const file of files) {\n try {\n console.log(`[3D-new] 正在解析文件: ${file.name}`);\n const res = await parseLayer(file);\n if (res && res.data) {\n console.log(`[3D-new] 解析成功: ${file.name}, 单位: ${res.units}`);\n // Check units for scaling\n let scale = 1.0;\n // Outline is always in MM. If this layer is in Inch, scale by 25.4.\n if (res.units === 'in' || res.units === 'inch') {\n scale = 25.4;\n }\n // 🎯 传入整个 res 对象,包含 data 和 plotResult\n renderer.call(this, [res], z, isTop, scale);\n } else {\n console.warn(`[3D-new] 解析失败或无数据: ${file.name}`);\n }\n } catch (e) {\n console.error(`[3D-new] 解析图层出错: ${file.name}`, e);\n console.error(`[3D-new] 错误堆栈:`, e.stack);\n }\n }\n };\n\n const halfThick = BOARD_THICKNESS / 2;\n // Increase spacing to prevent Z-fighting\n const layerSpacing = 0.05; \n\n const zTopCu = halfThick + layerSpacing;\n const zBotCu = -halfThick - layerSpacing;\n await processLayerGroup(topCopperFiles, this.renderCopperLayer, zTopCu, true);\n\n innerCopperFiles.sort((a, b) => {\n const sa = getLayerType(a.name) || '';\n const sb = getLayerType(b.name) || '';\n const ma = sa.match(/^SIG(\\d+)$/i);\n const mb = sb.match(/^SIG(\\d+)$/i);\n return (ma ? parseInt(ma[1], 10) : 0) - (mb ? parseInt(mb[1], 10) : 0);\n });\n const nInner = innerCopperFiles.length;\n for (let i = 0; i < nInner; i++) {\n const t = (i + 1) / (nInner + 1);\n const zInner = zTopCu - t * (zTopCu - zBotCu);\n await processLayerGroup([innerCopperFiles[i]], this.renderCopperLayer, zInner, zInner >= 0);\n }\n\n await processLayerGroup(bottomCopperFiles, this.renderCopperLayer, zBotCu, false);\n \n await processLayerGroup(topMaskFiles, this.renderMaskLayer, halfThick + layerSpacing * 2, true);\n await processLayerGroup(bottomMaskFiles, this.renderMaskLayer, -halfThick - layerSpacing * 2, false);\n\n await processLayerGroup(topPasteFiles, this.renderPasteLayer, halfThick + layerSpacing * 2.5, true);\n await processLayerGroup(bottomPasteFiles, this.renderPasteLayer, -halfThick - layerSpacing * 2.5, false);\n\n await processLayerGroup(topSilkFiles, this.renderSilkscreenLayer, halfThick + layerSpacing * 3, true);\n await processLayerGroup(bottomSilkFiles, this.renderSilkscreenLayer, -halfThick - layerSpacing * 3, false);\n\n // Render PHO files separately\n await this.renderPhoFiles(gerberFiles, halfThick, layerSpacing);\n\n // Drills\n // 若钻孔层与板子范围(轮廓/已渲染层)明显错位,则跳过渲染钻孔层,避免“漂移钻孔”污染视图\n let drillRefBbox = null;\n if (this.outlineBbox && !this.outlineBbox.isEmpty()) {\n drillRefBbox = this.outlineBbox.clone();\n } else if (this.baseGroup.children.length > 0) {\n drillRefBbox = new THREE.Box3().setFromObject(this.baseGroup);\n }\n const expandedDrillRefBbox = drillRefBbox ? drillRefBbox.clone().expandByScalar(20) : null; // 20mm 容错\n\n for (const file of drillFiles) {\n try {\n const res = await parseLayer(file);\n if (res && res.data) {\n let scale = 1.0;\n if (res.units === 'in' || res.units === 'inch') {\n scale = 25.4;\n // debugLog(`[Unit Scale] Scaling drill ${file.name} by 25.4 (Inch -> MM)`);\n }\n\n // 明显错位检测与修正\n if (expandedDrillRefBbox) {\n debugLog(`[Drill] 处理 ${file.name}...`);\n \n // 应用钻孔对齐修正\n const fixResult = this.fixDrillLayerAlignment(res.data, scale, drillRefBbox);\n scale = fixResult.scale;\n \n if (!fixResult.success || !fixResult.bbox) {\n debugWarn(`[Drill] ${file.name} 修正失败,跳过渲染`);\n continue;\n }\n \n const drillBbox = fixResult.bbox;\n\n // 验证修正后的钻孔层位置\n if (!this.validateDrillBbox(drillBbox, drillRefBbox, expandedDrillRefBbox, file.name)) {\n continue;\n }\n }\n\n this.renderDrillLayer([res.data], scale);\n }\n } catch (e) {\n console.error(`Error processing drill ${file.name}:`, e);\n }\n }\n \n const endTimeOtherLayers = performance.now()\n console.log(`[性能] 其他图层渲染完成,耗时: ${(endTimeOtherLayers - startTimeOtherLayers).toFixed(2)}ms`)\n\n console.log('[性能] 开始相机适配...')\n const startTimeCamera = performance.now()\n \n // Fit camera to all rendered objects\n // Priority: 1. Outline layer bbox (if valid), 2. GTO/GTL layer bbox (if outline is missing or differs significantly), 3. All layers\n if (this.baseGroup.children.length > 0) {\n let finalBbox = null;\n \n // 调试:检查outlineBbox状态\n if (this.outlineBbox) {\n if (this.outlineBbox.isEmpty()) {\n debugLog('[Camera] outlineBbox存在但为空');\n } else {\n const size = this.outlineBbox.getSize(new THREE.Vector3());\n const center = this.outlineBbox.getCenter(new THREE.Vector3());\n debugLog(`[Camera] outlineBbox状态: 尺寸=${size.x.toFixed(2)} x ${size.y.toFixed(2)}, 中心=(${center.x.toFixed(2)}, ${center.y.toFixed(2)})`);\n }\n } else {\n debugLog('[Camera] outlineBbox不存在');\n }\n \n // 优先使用轮廓层bbox(如果有且有效)\n if (this.outlineBbox && !this.outlineBbox.isEmpty()) {\n finalBbox = this.outlineBbox;\n const size = finalBbox.getSize(new THREE.Vector3());\n const center = finalBbox.getCenter(new THREE.Vector3());\n debugLog(`[Camera] 使用轮廓层bbox进行自适应: 尺寸=${size.x.toFixed(2)} x ${size.y.toFixed(2)}, 中心=(${center.x.toFixed(2)}, ${center.y.toFixed(2)})`);\n this.fitCameraToBbox(finalBbox);\n } else {\n // 没有轮廓层bbox,计算GTL和GBL层的bbox(用于自适应判断)\n let gtlBbox = null;\n let gblBbox = null;\n \n // 计算GTL层bbox(顶层铜层)\n if (topCopperFiles.length > 0) {\n try {\n const res = await parseLayer(topCopperFiles[0]);\n if (res && res.data) {\n gtlBbox = this.calculateLayerBbox([res.data]);\n }\n } catch (e) {\n // Ignore errors\n }\n }\n \n // 计算GBL层bbox(底层铜层)\n if (bottomCopperFiles.length > 0) {\n try {\n const res = await parseLayer(bottomCopperFiles[0]);\n if (res && res.data) {\n gblBbox = this.calculateLayerBbox([res.data]);\n }\n } catch (e) {\n // Ignore errors\n }\n }\n \n // 选择GTL或GBL的bbox(优先GTL)\n const referenceBbox = gtlBbox && !gtlBbox.isEmpty() ? gtlBbox : (gblBbox && !gblBbox.isEmpty() ? gblBbox : null);\n \n if (referenceBbox) {\n finalBbox = referenceBbox;\n const size = finalBbox.getSize(new THREE.Vector3());\n const center = finalBbox.getCenter(new THREE.Vector3());\n const layerName = gtlBbox && !gtlBbox.isEmpty() ? 'GTL' : 'GBL';\n debugLog(`[Camera] 无轮廓层,使用${layerName}层bbox进行自适应: 尺寸=${size.x.toFixed(2)} x ${size.y.toFixed(2)}, 中心=(${center.x.toFixed(2)}, ${center.y.toFixed(2)})`);\n this.fitCameraToBbox(finalBbox);\n } else if (fallbackLayerForCamera) {\n // 计算fallback层的bbox\n try {\n const res = await parseLayer(fallbackLayerForCamera.files[0]);\n if (res && res.data) {\n const bbox = this.calculateLayerBbox([res.data]);\n if (bbox && !bbox.isEmpty()) {\n finalBbox = bbox;\n const size = finalBbox.getSize(new THREE.Vector3());\n const center = finalBbox.getCenter(new THREE.Vector3());\n debugLog(`[Camera] 使用${fallbackLayerForCamera.type}层bbox进行自适应: 尺寸=${size.x.toFixed(2)} x ${size.y.toFixed(2)}, 中心=(${center.x.toFixed(2)}, ${center.y.toFixed(2)})`);\n this.fitCameraToBbox(finalBbox);\n } else {\n debugLog('[Camera] 未找到有效bbox,使用所有图层进行自适应');\n this.fitCameraToObject(this.baseGroup);\n }\n } else {\n debugLog('[Camera] 未找到有效bbox,使用所有图层进行自适应');\n this.fitCameraToObject(this.baseGroup);\n }\n } catch (e) {\n debugLog('[Camera] 未找到有效bbox,使用所有图层进行自适应');\n this.fitCameraToObject(this.baseGroup);\n }\n } else {\n // Final fallback: use all layers\n debugLog('[Camera] 未找到有效bbox,使用所有图层进行自适应');\n this.fitCameraToObject(this.baseGroup);\n }\n }\n \n const endTimeCamera = performance.now()\n console.log(`[性能] 相机适配完成,耗时: ${(endTimeCamera - startTimeCamera).toFixed(2)}ms`)\n \n // Show scene after rendering is complete\n if (this.renderer && this.renderer.domElement) {\n this.renderer.domElement.style.visibility = 'visible';\n }\n \n const endTimeTotal = performance.now()\n const totalProcessTime = (endTimeTotal - startTimeTotal) / 1000\n console.log(`[性能] ========== processFiles 完成,总耗时: ${totalProcessTime.toFixed(2)}秒 ==========`)\n console.log(`[性能] 详细耗时:解压=${((endTimeExtract-startTimeExtract)/1000).toFixed(2)}秒, 分类=${((endTimeClassify-startTimeClassify)/1000).toFixed(2)}秒, 轮廓=${((endTimeOutline-startTimeOutline)/1000).toFixed(2)}秒, 其他图层=${((endTimeOtherLayers-startTimeOtherLayers)/1000).toFixed(2)}秒, 相机=${((endTimeCamera-startTimeCamera)/1000).toFixed(2)}秒`)\n console.log(`[3D-new] 渲染完成,场景中共有 ${this.baseGroup.children.length} 个对象`);\n } else {\n console.warn('[3D-new] 没有渲染任何图层,baseGroup 为空');\n // Show scene even if nothing rendered\n if (this.renderer && this.renderer.domElement) {\n this.renderer.domElement.style.visibility = 'visible';\n }\n \n const endTimeTotal = performance.now()\n const totalProcessTime = (endTimeTotal - startTimeTotal) / 1000\n console.log(`[性能] ========== processFiles 完成(无渲染),总耗时: ${totalProcessTime.toFixed(2)}秒 ==========`)\n }\n }\n\n clearScene() {\n while (this.baseGroup.children.length) {\n const obj = this.baseGroup.children.pop();\n obj.geometry?.dispose?.();\n obj.material?.dispose?.();\n }\n }\n\n renderOutlineBoard(shapes, showEdges = true) {\n this.clearScene();\n\n // 先计算所有形状的 bbox(包括小形状),用于相机适配\n const allPointsForBbox = [];\n shapes.forEach(shape => {\n const points = shape.getPoints();\n if (points && points.length > 0) {\n allPointsForBbox.push(...points.map(p => new THREE.Vector3(p.x, p.y, 0)));\n }\n });\n \n if (allPointsForBbox.length > 0) {\n const bbox = new THREE.Box3().setFromPoints(allPointsForBbox);\n // Store outline bbox for camera fitting (即使没有有效形状也要设置)\n this.outlineBbox = bbox.clone();\n if (!this.outlineBbox.isEmpty()) {\n const size = this.outlineBbox.getSize(new THREE.Vector3());\n const center = this.outlineBbox.getCenter(new THREE.Vector3());\n debugLog(`[轮廓层] 设置outlineBbox: 尺寸=${size.x.toFixed(2)} x ${size.y.toFixed(2)}, 中心=(${center.x.toFixed(2)}, ${center.y.toFixed(2)})`);\n } else {\n debugWarn('[轮廓层] outlineBbox为空,可能无法正确自适应');\n }\n }\n\n // 过滤极小形状(用于渲染)\n const validShapes = shapes.filter(s => {\n const area = THREE.ShapeUtils.area(s.getPoints());\n return Math.abs(area) > 0.001; \n });\n\n if (validShapes.length === 0) {\n // debugWarn('所有提取的形状面积过小,无法渲染轮廓层,继续渲染其他图层。');\n return;\n }\n\n // 自适应单位/厚度 - 使用有效形状计算厚度\n const allPoints = [];\n validShapes.forEach(shape => {\n allPoints.push(...shape.getPoints().map(p => new THREE.Vector3(p.x, p.y, 0)));\n });\n const bbox = new THREE.Box3().setFromPoints(allPoints);\n\n const size = new THREE.Vector3();\n bbox.getSize(size);\n const maxDim = Math.max(size.x, size.y);\n \n // Adaptive thickness based on size\n if (maxDim < 20.0) {\n BOARD_THICKNESS = 0.063 * 25.4; // Assume the board IS small (mm), so use 1.6mm approx\n // Wait, if OutlineParser always returns MM, maxDim < 20.0 means the board is < 20mm. \n // A 20mm board is plausible.\n // If the file was INCH but processed as MM, a 5x5 inch board would be 5x5 mm.\n // But GerberOutlineParser converts INCH to MM. So maxDim IS in MM.\n \n // Standard PCB Thickness is usually 1.6mm.\n BOARD_THICKNESS = 1.6;\n } else {\n BOARD_THICKNESS = 1.6; // mm\n }\n // debugLog(`Board Max Dim (MM): ${maxDim.toFixed(2)}, Thickness set to ${BOARD_THICKNESS}mm`);\n\n const material = this.getCachedMaterial('outline-fill', () =>\n new THREE.MeshPhysicalMaterial({\n color: COLORS.OUTLINE,\n metalness: 0.0,\n roughness: 0.8,\n side: THREE.DoubleSide\n })\n );\n\n const edgeMat = this.getCachedMaterial('outline-edge', () =>\n new THREE.MeshBasicMaterial({ color: COLORS.OUTLINE_EDGE, side: THREE.DoubleSide })\n );\n\n // 辅助函数:将点序列转换为有宽度的矩形 Mesh(确保线条可见)\n const createThickLineLoop = (points, z, width = 0.10) => {\n if (points.length < 2) return null;\n \n // 检查点序列是否已经闭合(首尾点是否相同或非常接近)\n const first = points[0];\n const last = points[points.length - 1];\n const isClosed = Math.hypot(first.x - last.x, first.y - last.y) < 1e-4;\n \n // 如果已经闭合,去掉最后一个重复点,避免重复连接\n const workingPoints = isClosed && points.length > 2 ? points.slice(0, -1) : points;\n if (workingPoints.length < 2) return null;\n \n const vertices = [];\n const indices = [];\n let baseIndex = 0;\n \n // 处理所有相邻点对,最后一个点连接到第一个点(形成闭合环)\n for (let i = 0; i < workingPoints.length; i++) {\n const p1 = workingPoints[i];\n const p2 = workingPoints[(i + 1) % workingPoints.length];\n \n const dx = p2.x - p1.x;\n const dy = p2.y - p1.y;\n const len = Math.sqrt(dx * dx + dy * dy);\n if (len < 1e-6) continue; // 跳过零长度线段\n \n const perpX = -dy / len * (width / 2);\n const perpY = dx / len * (width / 2);\n \n const p1x = p1.x + perpX;\n const p1y = p1.y + perpY;\n const p2x = p1.x - perpX;\n const p2y = p1.y - perpY;\n const p3x = p2.x - perpX;\n const p3y = p2.y - perpY;\n const p4x = p2.x + perpX;\n const p4y = p2.y + perpY;\n \n vertices.push(p1x, p1y, z);\n vertices.push(p2x, p2y, z);\n vertices.push(p3x, p3y, z);\n vertices.push(p4x, p4y, z);\n \n indices.push(baseIndex, baseIndex + 1, baseIndex + 2);\n indices.push(baseIndex, baseIndex + 2, baseIndex + 3);\n baseIndex += 4;\n }\n \n if (vertices.length === 0) return null;\n \n const geo = new THREE.BufferGeometry();\n geo.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));\n geo.setIndex(indices);\n geo.computeVertexNormals();\n \n return new THREE.Mesh(geo, edgeMat);\n };\n\n // 🚀 使用earcut三角化代替ExtrudeGeometry,支持更多点数的复杂轮廓\n const triangulateWithEarcut = (shape) => {\n const points = shape.getPoints();\n if (points.length < 3) return null;\n \n // 准备earcut输入\n const vertices = [];\n for (const pt of points) {\n vertices.push(pt.x, pt.y);\n }\n \n // 处理孔洞\n const holeIndices = [];\n if (shape.holes && shape.holes.length > 0) {\n for (const hole of shape.holes) {\n const holePts = hole.getPoints();\n if (holePts.length >= 3) {\n holeIndices.push(vertices.length / 2);\n for (const pt of holePts) {\n vertices.push(pt.x, pt.y);\n }\n }\n }\n }\n \n // 调用earcut\n let triangleIndices;\n try {\n triangleIndices = earcut(vertices, holeIndices.length > 0 ? holeIndices : null, 2);\n } catch (err) {\n debugWarn('[Outline] earcut失败:', err.message);\n return null;\n }\n \n if (!triangleIndices || triangleIndices.length === 0) {\n return null;\n }\n \n // 构建3D几何体(顶面、底面、侧面)\n const topZ = BOARD_THICKNESS / 2;\n const bottomZ = -BOARD_THICKNESS / 2;\n \n // 顶点数组:顶面 + 底面\n const positions = [];\n const indices = [];\n const numVertices2D = vertices.length / 2;\n \n // 添加顶面和底面顶点\n for (let i = 0; i < numVertices2D; i++) {\n const x = vertices[i * 2];\n const y = vertices[i * 2 + 1];\n // 顶面顶点\n positions.push(x, y, topZ);\n }\n for (let i = 0; i < numVertices2D; i++) {\n const x = vertices[i * 2];\n const y = vertices[i * 2 + 1];\n // 底面顶点\n positions.push(x, y, bottomZ);\n }\n \n // 顶面三角形索引\n for (let i = 0; i < triangleIndices.length; i += 3) {\n indices.push(triangleIndices[i], triangleIndices[i + 1], triangleIndices[i + 2]);\n }\n \n // 底面三角形索引(反向绕序)\n for (let i = 0; i < triangleIndices.length; i += 3) {\n const a = triangleIndices[i] + numVertices2D;\n const b = triangleIndices[i + 1] + numVertices2D;\n const c = triangleIndices[i + 2] + numVertices2D;\n indices.push(a, c, b); // 反向\n }\n \n // 侧面:只处理外轮廓边缘(不处理孔洞边缘以简化)\n const outerPointCount = holeIndices.length > 0 ? holeIndices[0] : numVertices2D;\n for (let i = 0; i < outerPointCount; i++) {\n const next = (i + 1) % outerPointCount;\n const topA = i;\n const topB = next;\n const bottomA = i + numVertices2D;\n const bottomB = next + numVertices2D;\n // 两个三角形组成一个矩形侧面\n indices.push(topA, bottomA, topB);\n indices.push(topB, bottomA, bottomB);\n }\n \n const geometry = new THREE.BufferGeometry();\n geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));\n geometry.setIndex(indices);\n geometry.computeVertexNormals();\n \n return geometry;\n };\n \n // 渲染所有形状\n const MAX_POINTS_FOR_EXTRUDE = 500; // ExtrudeGeometry的限制\n const MAX_POINTS_FOR_EARCUT = 5000; // earcut的限制(与home 2D仿真一致)\n let renderedCount = 0;\n let skippedComplexCount = 0;\n \n validShapes.forEach(shape => {\n try {\n const points = shape.getPoints();\n \n // 根据点数选择不同的渲染方式\n if (points.length <= MAX_POINTS_FOR_EXTRUDE) {\n // 点数少,使用ExtrudeGeometry(效果更好)\n const geo = new THREE.ExtrudeGeometry(shape, { depth: BOARD_THICKNESS, bevelEnabled: false });\n geo.translate(0, 0, -BOARD_THICKNESS / 2);\n const mesh = new THREE.Mesh(geo, material);\n this.baseGroup.add(mesh);\n renderedCount++;\n } else if (points.length <= MAX_POINTS_FOR_EARCUT) {\n // 点数较多,使用earcut三角化\n const geo = triangulateWithEarcut(shape);\n if (geo) {\n const mesh = new THREE.Mesh(geo, material);\n this.baseGroup.add(mesh);\n renderedCount++;\n debugLog(`[Outline] 使用earcut渲染复杂形状(${points.length}点)`);\n } else {\n skippedComplexCount++;\n }\n } else {\n debugWarn(`[Outline] 形状过于复杂(${points.length}点 > ${MAX_POINTS_FOR_EARCUT}),跳过`);\n skippedComplexCount++;\n return;\n }\n\n // 边框线(若是强制闭合的形状,不画边框以避免长对角线视觉干扰)\n if (showEdges && !shape.userData?.forcedClose) {\n const EDGE_Z_TOP = BOARD_THICKNESS / 2 + 0.05;\n const EDGE_Z_BOTTOM = -BOARD_THICKNESS / 2 - 0.05 + 0.001;\n const pts2 = shape.getPoints();\n const thickTop = createThickLineLoop(pts2, EDGE_Z_TOP);\n const thickBottom = createThickLineLoop(pts2, EDGE_Z_BOTTOM);\n if (thickTop) this.baseGroup.add(thickTop);\n if (thickBottom) this.baseGroup.add(thickBottom);\n }\n\n // 渲染孔洞边框\n if (showEdges && shape.holes && shape.holes.length > 0) {\n shape.holes.forEach(path => {\n const EDGE_Z_TOP = BOARD_THICKNESS / 2 + 0.05;\n const EDGE_Z_BOTTOM = -BOARD_THICKNESS / 2 - 0.05 + 0.001;\n const hPts2 = path.getPoints();\n const thickHoleTop = createThickLineLoop(hPts2, EDGE_Z_TOP);\n const thickHoleBottom = createThickLineLoop(hPts2, EDGE_Z_BOTTOM);\n if (thickHoleTop) this.baseGroup.add(thickHoleTop);\n if (thickHoleBottom) this.baseGroup.add(thickHoleBottom);\n });\n }\n } catch (err) {\n debugWarn(`[Outline] 渲染失败:`, err.message);\n skippedComplexCount++;\n }\n });\n \n // 显示跳过的形状数量\n if (skippedComplexCount > 0) {\n debugWarn(`[Outline] 跳过了 ${skippedComplexCount} 个形状`);\n }\n \n // 如果所有形状都被跳过,使用bbox兜底\n if (renderedCount === 0 && validShapes.length > 0) {\n debugWarn('[Outline] 所有形状都被跳过,使用bbox兜底');\n const bboxShape = this.buildBBoxShapeFromShapes(validShapes);\n if (bboxShape) {\n try {\n const geo = new THREE.ExtrudeGeometry(bboxShape, { depth: BOARD_THICKNESS, bevelEnabled: false });\n geo.translate(0, 0, -BOARD_THICKNESS / 2);\n const mesh = new THREE.Mesh(geo, material);\n this.baseGroup.add(mesh);\n } catch (err) {\n debugWarn('[Outline] bbox兜底也失败:', err.message);\n }\n }\n }\n\n // Store outline bbox for camera fitting (will be used after all layers are rendered)\n // Don't fit camera here, wait until all layers are rendered\n }\n\n // 基于线段点集求凸包,生成单一 Shape 兜底\n buildHullShapeFromSegments(segments) {\n if (!segments || segments.length === 0) return null;\n const pts = [];\n for (const seg of segments) {\n pts.push(new THREE.Vector2(seg.start.x, seg.start.y));\n pts.push(new THREE.Vector2(seg.end.x, seg.end.y));\n }\n if (pts.length < 3) return null;\n\n pts.sort((a, b) => (a.x === b.x ? a.y - b.y : a.x - b.x));\n const cross = (o, a, b) => (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x);\n const lower = [];\n for (const p of pts) {\n while (lower.length >= 2 && cross(lower[lower.length - 2], lower[lower.length - 1], p) <= 0) {\n lower.pop();\n }\n lower.push(p);\n }\n const upper = [];\n for (let i = pts.length - 1; i >= 0; i--) {\n const p = pts[i];\n while (upper.length >= 2 && cross(upper[upper.length - 2], upper[upper.length - 1], p) <= 0) {\n upper.pop();\n }\n upper.push(p);\n }\n upper.pop();\n lower.pop();\n const hull = lower.concat(upper);\n if (hull.length < 3) return null;\n\n const shape = new THREE.Shape();\n shape.moveTo(hull[0].x, hull[0].y);\n for (let i = 1; i < hull.length; i++) shape.lineTo(hull[i].x, hull[i].y);\n shape.closePath();\n return shape;\n }\n\n // 基于已存在的闭合 shapes 计算外接矩形,作为兜底\n buildBBoxShapeFromShapes(shapes) {\n if (!shapes || shapes.length === 0) return null;\n let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;\n for (const s of shapes) {\n const pts = s.getPoints();\n for (const p of pts) {\n if (p.x < minX) minX = p.x;\n if (p.x > maxX) maxX = p.x;\n if (p.y < minY) minY = p.y;\n if (p.y > maxY) maxY = p.y;\n }\n }\n if (!isFinite(minX) || !isFinite(maxX) || !isFinite(minY) || !isFinite(maxY)) return null;\n const shape = new THREE.Shape();\n shape.moveTo(minX, minY);\n shape.lineTo(maxX, minY);\n shape.lineTo(maxX, maxY);\n shape.lineTo(minX, maxY);\n shape.closePath();\n return shape;\n }\n\n // 基于线段集合计算外接矩形,用于兜底渲染和相机适配\n buildBBoxShapeFromSegments(segments) {\n if (!segments || segments.length === 0) return null;\n let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;\n for (const seg of segments) {\n if (seg.start.x < minX) minX = seg.start.x;\n if (seg.start.x > maxX) maxX = seg.start.x;\n if (seg.start.y < minY) minY = seg.start.y;\n if (seg.start.y > maxY) maxY = seg.start.y;\n if (seg.end.x < minX) minX = seg.end.x;\n if (seg.end.x > maxX) maxX = seg.end.x;\n if (seg.end.y < minY) minY = seg.end.y;\n if (seg.end.y > maxY) maxY = seg.end.y;\n }\n if (!isFinite(minX) || !isFinite(maxX) || !isFinite(minY) || !isFinite(maxY)) return null;\n const shape = new THREE.Shape();\n shape.moveTo(minX, minY);\n shape.lineTo(maxX, minY);\n shape.lineTo(maxX, maxY);\n shape.lineTo(minX, maxY);\n shape.closePath();\n return shape;\n }\n\n // 兜底:用线段直接画轮廓(G01/G02/G03 离散后),不做布尔运算\n renderOutlineStrokes(segments, lineWidth = 0.10, color = COLORS.OUTLINE_EDGE, zOverride = null) {\n if (!segments || segments.length === 0) return;\n\n // 计算 bbox,用于相机适配\n const points = [];\n segments.forEach(seg => {\n points.push(new THREE.Vector3(seg.start.x, seg.start.y, 0));\n points.push(new THREE.Vector3(seg.end.x, seg.end.y, 0));\n });\n if (points.length > 0) {\n const bbox = new THREE.Box3().setFromPoints(points);\n if (!this.outlineBbox || this.outlineBbox.isEmpty()) {\n this.outlineBbox = bbox.clone();\n }\n }\n\n const key = `outline-stroke-${color.toString(16)}-${lineWidth}`;\n const edgeMat = this.getCachedMaterial(key, () =>\n new THREE.MeshBasicMaterial({ color, side: THREE.DoubleSide })\n );\n\n // 将线段转换为有宽度的矩形 Mesh(确保可见)\n const LINE_WIDTH = lineWidth; // 可调宽度\n const vertices = [];\n const indices = [];\n let baseIndex = 0;\n const z = (typeof zOverride === 'number') ? zOverride : (BOARD_THICKNESS / 2 + 0.05); // 默认绘制在顶面上方\n\n for (const seg of segments) {\n const x1 = seg.start.x;\n const y1 = seg.start.y;\n const x2 = seg.end.x;\n const y2 = seg.end.y;\n \n const dx = x2 - x1;\n const dy = y2 - y1;\n const len = Math.sqrt(dx * dx + dy * dy);\n if (len < 1e-6) continue;\n \n const perpX = -dy / len * (LINE_WIDTH / 2);\n const perpY = dx / len * (LINE_WIDTH / 2);\n \n const p1x = x1 + perpX;\n const p1y = y1 + perpY;\n const p2x = x1 - perpX;\n const p2y = y1 - perpY;\n const p3x = x2 - perpX;\n const p3y = y2 - perpY;\n const p4x = x2 + perpX;\n const p4y = y2 + perpY;\n \n vertices.push(p1x, p1y, z);\n vertices.push(p2x, p2y, z);\n vertices.push(p3x, p3y, z);\n vertices.push(p4x, p4y, z);\n \n indices.push(baseIndex, baseIndex + 1, baseIndex + 2);\n indices.push(baseIndex, baseIndex + 2, baseIndex + 3);\n baseIndex += 4;\n }\n \n if (vertices.length === 0) return;\n \n const geo = new THREE.BufferGeometry();\n geo.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));\n geo.setIndex(indices);\n geo.computeVertexNormals();\n \n const mesh = new THREE.Mesh(geo, edgeMat);\n this.baseGroup.add(mesh);\n }\n\n // ==================== OTHER LAYER RENDERING ====================\n\n renderCopperLayer(layers, z, isTop, scale = 1.0) {\n // 从 lineStrips 提取所有形状(包括孔洞)\n const allShapes = [];\n \n for (const layer of layers) {\n const webglData = layer.data || layer;\n \n if (webglData.lineStrips && webglData.vertices) {\n for (const strip of webglData.lineStrips) {\n if (strip.count < 2) continue;\n\n const pts = [];\n for (let j = 0; j < strip.count; j++) {\n const ptr = (strip.start + j) * 3;\n pts.push(new THREE.Vector2(webglData.vertices[ptr], -webglData.vertices[ptr + 1]));\n }\n if (pts.length < 2) continue;\n\n const first = pts[0];\n const last = pts[pts.length - 1];\n const isClosed = first.distanceTo(last) < 0.001;\n\n if (!isClosed) continue; // 铜层只处理闭合形状\n\n // Remove duplicated closing point if present\n if (pts.length > 2 && first.distanceTo(last) < 1e-9) {\n pts.pop();\n }\n if (pts.length < 3) continue;\n\n const shape = new THREE.Shape();\n shape.moveTo(pts[0].x, pts[0].y);\n for (let i = 1; i < pts.length; i++) {\n shape.lineTo(pts[i].x, pts[i].y);\n }\n shape.closePath();\n \n allShapes.push(shape);\n }\n }\n }\n \n if (allShapes.length === 0) return;\n\n // ⚠️ 重要:铜层不能复用丝印的“嵌套=孔洞”启发式。\n // 原因:铜层大量“包含关系”只是重叠/靠近(焊盘/走线/覆铜),不是孔洞。\n // 用 processSilkscreenHoles 会把这些内部形状误当孔洞,导致“错误的形状/缺块/反相”。\n // 铜层如果要支持 Gerber 的 clear polarity(避空/开窗),需要基于 plotResult.polarity 做布尔/模板,\n // 这里先保证几何不被误挖空:直接渲染所有闭合形状即可(叠加效果正确、不会出现假孔洞)。\n const shapesToRender = allShapes;\n\n // 计算所有形状的面积并找出最大面积\n const shapesWithArea = shapesToRender.map((shape, idx) => {\n const pts = shape.getPoints();\n const area = Math.abs(THREE.ShapeUtils.area(pts));\n return { shape, area, idx, pointCount: pts.length };\n });\n \n // 按面积排序(降序)\n shapesWithArea.sort((a, b) => b.area - a.area);\n \n // 找出最大面积\n const maxArea = shapesWithArea[0]?.area || 0;\n \n // 过滤:跳过面积超过总形状面积 40% 的\"铜皮\"形状\n // 这些通常是覆盖整个板子的 ground plane\n // 🎯 暂时禁用此过滤,因为可能会误过滤掉正常的大铜皮区域\n // const totalArea = shapesWithArea.reduce((sum, s) => sum + s.area, 0);\n // const areaThreshold = totalArea * 0.4;\n \n // const filteredShapes = shapesWithArea.filter(s => {\n // const isGroundPlane = s.area > areaThreshold && s.area === maxArea;\n // return !isGroundPlane;\n // });\n \n const filteredShapes = shapesWithArea; // 不过滤,渲染所有形状\n \n if (filteredShapes.length === 0) return;\n\n const shapes = filteredShapes.map(s => s.shape);\n\n const material = this.getCachedMaterial(isTop ? 'copper-top' : 'copper-bot', () =>\n new THREE.MeshPhysicalMaterial({\n color: COLORS.COPPER,\n metalness: 0.3,\n roughness: 0.5,\n side: THREE.DoubleSide\n })\n );\n\n this.renderShapesInChunks(shapes, material, z, scale, 2000, isTop ? 'GTL' : 'GBL');\n }\n\n renderMaskLayer(layers, z, isTop, scale = 1.0) {\n const shapes = this.collectStandardShapes(layers);\n if (shapes.length === 0) return;\n\n // Render Openings as Gold (exposed copper)\n const material = this.getCachedMaterial('mask-opening', () =>\n new THREE.MeshPhysicalMaterial({\n color: COLORS.GOLD,\n metalness: 0.8,\n roughness: 0.2,\n side: THREE.DoubleSide\n })\n );\n\n // Raise slightly above copper\n this.renderShapesInChunks(shapes, material, z + 0.001, scale);\n }\n\n renderPasteLayer(layers, z, isTop, scale = 1.0) {\n const shapes = this.collectStandardShapes(layers);\n if (shapes.length === 0) return;\n\n const material = this.getCachedMaterial('paste', () =>\n new THREE.MeshPhysicalMaterial({\n color: COLORS.PASTE, // Gray color for solder paste\n metalness: 0.3,\n roughness: 0.7,\n side: THREE.DoubleSide\n })\n );\n\n this.renderShapesInChunks(shapes, material, z, scale);\n }\n\n renderSilkscreenLayer(layers, z, isTop, scale = 1.0) {\n // 重要:silkscreen 的 lineStrips 里混有两类数据:\n // 1) 真实“填充区域”的边界(例如某些文字/标注是 region/flash 的外轮廓)→ 应该填充\n // 2) “描边轨迹”的中心线(圆形标注/字符描边环等)→ 不应该填充,否则会把环内部填死\n //\n // 解决:对闭合 polyline 做一次轻量分类:\n // - 近似圆/椭圆的闭合环:按 stroke ribbon 渲染(保持中空)\n // - 其余闭合轮廓:按填充 Shape 渲染,并用 processSilkscreenHoles 保持字洞\n const openPolylines = [];\n const strokeLoops = []; // closed but should be treated as stroke\n const fillShapes = []; // closed and should be filled\n\n for (const layer of layers) {\n // 兼容两种格式:layer 可能是 res.data(旧) 或 res(新,带 plotResult)\n const webglData = layer.data || layer;\n \n // 从 lineStrips 提取所有闭合和开放路径\n if (webglData.lineStrips && webglData.vertices) {\n for (const strip of webglData.lineStrips) {\n if (strip.count < 2) continue;\n\n const pts = [];\n for (let j = 0; j < strip.count; j++) {\n const ptr = (strip.start + j) * 3;\n pts.push(new THREE.Vector2(webglData.vertices[ptr], -webglData.vertices[ptr + 1]));\n }\n if (pts.length < 2) continue;\n const first = pts[0];\n const last = pts[pts.length - 1];\n const isClosed = first.distanceTo(last) < 0.001;\n\n if (!isClosed) {\n openPolylines.push(pts);\n continue;\n }\n\n // Remove duplicated closing point if present\n if (pts.length > 2 && first.distanceTo(last) < 1e-9) {\n pts.pop();\n }\n if (pts.length < 3) continue;\n\n // 1) 优先使用 parser 标记的 kind(来自 SVG fill/stroke 属性)\n // - fill:进入填充形状(文字/实心标注等)\n // - stroke:进入描边细带(圆环/描边字体/轨迹等)\n if (strip.kind === 'stroke') {\n strokeLoops.push(pts);\n continue;\n }\n if (strip.kind === 'fill') {\n const shape = new THREE.Shape();\n shape.moveTo(pts[0].x, pts[0].y);\n for (let i = 1; i < pts.length; i++) shape.lineTo(pts[i].x, pts[i].y);\n shape.closePath();\n fillShapes.push(shape);\n continue;\n }\n\n // 2) 回退:没有 kind 时才用几何启发式\n // --- classify ellipse-like loops as stroke ---\n // quick ellipse-likeness: normalize by bbox radii, expect r≈1 with small std\n let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;\n for (const p of pts) {\n if (p.x < minX) minX = p.x;\n if (p.x > maxX) maxX = p.x;\n if (p.y < minY) minY = p.y;\n if (p.y > maxY) maxY = p.y;\n }\n const w = maxX - minX;\n const h = maxY - minY;\n const cx = (minX + maxX) / 2;\n const cy = (minY + maxY) / 2;\n const rx = w / 2;\n const ry = h / 2;\n\n let ellipseLike = false;\n if (rx > 1e-6 && ry > 1e-6) {\n let sum = 0;\n let sumSq = 0;\n let n = 0;\n for (const p of pts) {\n const nx = (p.x - cx) / rx;\n const ny = (p.y - cy) / ry;\n const r = Math.sqrt(nx * nx + ny * ny);\n if (!Number.isFinite(r)) continue;\n sum += r;\n sumSq += r * r;\n n++;\n }\n if (n >= 8) {\n const mean = sum / n;\n const varR = Math.max(0, sumSq / n - mean * mean);\n const std = Math.sqrt(varR);\n // mean≈1 且 std 很小 → 近似椭圆/圆\n ellipseLike = (mean > 0.90 && mean < 1.10 && std < 0.03);\n }\n }\n\n if (ellipseLike) {\n strokeLoops.push(pts);\n continue;\n }\n\n // otherwise treat as fill shape\n const shape = new THREE.Shape();\n shape.moveTo(pts[0].x, pts[0].y);\n for (let i = 1; i < pts.length; i++) {\n shape.lineTo(pts[i].x, pts[i].y);\n }\n shape.closePath();\n fillShapes.push(shape);\n }\n }\n }\n\n if (fillShapes.length === 0 && strokeLoops.length === 0 && openPolylines.length === 0) return;\n\n const material = this.getCachedMaterial('silkscreen', () =>\n new THREE.MeshPhysicalMaterial({\n color: COLORS.SILKSCREEN,\n side: THREE.DoubleSide\n })\n );\n\n // 1) Fill shapes (with hole post-processing to keep text counters hollow)\n if (fillShapes.length > 0) {\n const shapesWithHoles = this.processSilkscreenHoles(fillShapes);\n if (shapesWithHoles.length > 0) {\n this.renderShapesInChunks(shapesWithHoles, material, z, scale, 2000, isTop ? 'GTO' : 'GBO');\n }\n }\n\n // 2) Stroke ribbons (open polylines + ellipse-like closed loops)\n // 让描边字/描边圆看起来“更实心”(与 2D Gerber 观感更接近)\n const desiredWidthMm = 0.20;\n const widthInLayerUnits = desiredWidthMm / (scale || 1.0);\n\n const strokeShapes = [];\n const allStrokePolylines = openPolylines.concat(strokeLoops);\n for (const pts of allStrokePolylines) {\n if (pts.length < 2) continue;\n\n const first = pts[0];\n const last = pts[pts.length - 1];\n const isClosed = first.distanceTo(last) < 0.001;\n const n = (isClosed && pts.length > 2 && first.distanceTo(last) < 1e-9) ? (pts.length - 1) : pts.length;\n const segCount = isClosed ? n : (n - 1);\n\n for (let i = 0; i < segCount; i++) {\n const p1 = pts[i];\n const p2 = (isClosed && i === n - 1) ? pts[0] : pts[i + 1];\n const dx = p2.x - p1.x;\n const dy = p2.y - p1.y;\n const len = Math.hypot(dx, dy);\n if (len < 1e-8) continue;\n\n const nx = (-dy / len) * (widthInLayerUnits / 2);\n const ny = (dx / len) * (widthInLayerUnits / 2);\n\n const s = new THREE.Shape();\n s.moveTo(p1.x + nx, p1.y + ny);\n s.lineTo(p2.x + nx, p2.y + ny);\n s.lineTo(p2.x - nx, p2.y - ny);\n s.lineTo(p1.x - nx, p1.y - ny);\n s.closePath();\n strokeShapes.push(s);\n }\n }\n\n if (strokeShapes.length > 0) {\n const zOffset = isTop ? 0.001 : -0.001;\n this.renderShapesInChunks(strokeShapes, material, z + zOffset, scale, 2000, isTop ? 'GTO' : 'GBO');\n }\n }\n\n renderDrillLayer(layers, scale = 1.0) {\n const shapes = this.collectStandardShapes(layers);\n // debugLog(`[Drill Layer] 收集到 ${shapes.length} 个钻孔形状`);\n \n if (shapes.length === 0) {\n // debugWarn('[Drill Layer] 没有收集到钻孔形状,检查数据格式');\n // Debug: Check layer data structure\n // layers.forEach((layer, idx) => {\n // debugLog(`[Drill Layer] Layer ${idx}:`, {\n // hasLineStrips: !!layer.lineStrips,\n // lineStripsCount: layer.lineStrips?.length || 0,\n // hasChildren: !!layer.children,\n // childrenCount: layer.children?.length || 0,\n // verticesCount: layer.vertices?.length || 0\n // });\n // });\n return;\n }\n\n // Render drills as black cylinders passing through the board\n const material = this.getCachedMaterial('drill', () =>\n new THREE.MeshBasicMaterial({ \n color: COLORS.DRILL,\n depthWrite: true,\n depthTest: true\n })\n );\n\n const extrusionSettings = {\n depth: BOARD_THICKNESS + 0.35, // Slightly longer than thickness for visibility, must exceed paste layer\n bevelEnabled: false\n };\n\n const geo = new THREE.ExtrudeGeometry(shapes, extrusionSettings);\n geo.translate(0, 0, -BOARD_THICKNESS / 2 - 0.175); // Center it Z-wise, slightly below board, must exceed paste layer\n\n const mesh = new THREE.Mesh(geo, material);\n mesh.scale.set(scale, scale, 1);\n mesh.renderOrder = 10; // Ensure drills render on top to avoid Z-fighting with paste layer\n this.baseGroup.add(mesh);\n // debugLog(`[Drill Layer] 成功渲染 ${shapes.length} 个钻孔`);\n debugLog(`[Drill Layer] 提取到 ${shapes.length} 个钻孔形状,scale=${scale}`);\n }\n\n /**\n * 专门渲染 .pho 文件的函数\n * 根据文件名前缀和数字识别图层类型,并调用对应的渲染函数\n */\n async renderPhoFiles(gerberFiles, halfThick, layerSpacing) {\n // 筛选出所有 .pho 文件\n const phoFiles = gerberFiles.filter(file => {\n const fileNameOnly = file.name.split(/[/\\\\]/).pop() || '';\n const fileExtension = '.' + fileNameOnly.split('.').pop().toUpperCase();\n return fileExtension === '.PHO';\n });\n\n if (phoFiles.length === 0) return;\n\n // 预处理 .pho 前缀分组:用于判定\"最小编号为上层,其余为下层\"\n const buildPhoGroups = (files) => {\n const groups = new Map(); // prefix -> {min:number}\n const add = (prefix, num) => {\n if (!groups.has(prefix)) {\n groups.set(prefix, { min: num });\n } else {\n groups.get(prefix).min = Math.min(groups.get(prefix).min, num);\n }\n };\n files.forEach(f => {\n const nameOnly = f.name.split(/[/\\\\]/).pop() || '';\n const upper = nameOnly.toUpperCase();\n let prefix = null;\n let num = 0;\n if (upper.startsWith('SST')) {\n prefix = 'sst';\n const m = upper.match(/^SST(\\d+)/);\n num = m ? parseInt(m[1], 10) : 0;\n } else if (upper.startsWith('SMD')) {\n prefix = 'smd';\n const m = upper.match(/^SMD(\\d+)/);\n num = m ? parseInt(m[1], 10) : 0;\n } else if (upper.startsWith('SM')) {\n prefix = 'sm';\n const m = upper.match(/^SM(\\d+)/);\n num = m ? parseInt(m[1], 10) : 0;\n } else if (upper.startsWith('ART')) {\n prefix = 'art';\n const m = upper.match(/^ART(\\d+)/);\n num = m ? parseInt(m[1], 10) : 0;\n } else if (upper.startsWith('SSB')) {\n prefix = 'ssb';\n num = 0;\n } else if (upper.startsWith('DRL')) {\n prefix = 'drl';\n num = 0;\n } else if (upper.startsWith('DD')) {\n prefix = 'dd';\n num = 0;\n }\n if (prefix) add(prefix, num);\n });\n return groups;\n };\n\n const phoGroups = buildPhoGroups(phoFiles);\n\n // 获取图层类型的辅助函数\n const getPhoLayerType = (fileName) => {\n const fileNameOnly = fileName.split(/[/\\\\]/).pop() || '';\n const fileNameUpper = fileNameOnly.toUpperCase();\n \n if (fileNameUpper.startsWith('SST')) return 'GTO';\n \n const pickByGroup = (prefix, topType, botType, defaultType = null) => {\n const m = fileNameUpper.match(new RegExp(`^${prefix}(\\\\d+)`));\n const num = m ? parseInt(m[1], 10) : 0;\n const g = phoGroups.get(prefix.toLowerCase());\n if (g) {\n return num === g.min ? topType : botType;\n }\n return defaultType || topType;\n };\n \n if (fileNameUpper.startsWith('SMD')) {\n return pickByGroup('SMD', 'GTP', 'GBP', 'GTP');\n }\n if (fileNameUpper.startsWith('SM')) {\n return pickByGroup('SM', 'GTS', 'GBS', 'GTS');\n }\n if (fileNameUpper.startsWith('ART')) {\n return pickByGroup('ART', 'GTL', 'GBL', 'GTL');\n }\n if (fileNameUpper.startsWith('SSB')) return 'GBO';\n if (fileNameUpper.startsWith('DRL')) return 'DRL';\n \n return null;\n };\n\n // 按图层类型分组渲染\n for (const file of phoFiles) {\n try {\n const layerType = getPhoLayerType(file.name);\n if (!layerType) continue;\n\n // 使用 GerberParser 解析 pho 文件(它内部使用 web-gerber)\n const res = await GerberParser.parseFile(file, '#ffffff');\n if (!res || !res.data) continue;\n\n // 检查单位并缩放\n let scale = 1.0;\n if (res.units === 'in' || res.units === 'inch') {\n scale = 25.4;\n }\n\n // 根据图层类型调用对应的渲染函数\n switch (layerType) {\n case 'GTL':\n this.renderCopperLayer([res.data], halfThick + layerSpacing, true, scale);\n break;\n case 'GBL':\n this.renderCopperLayer([res.data], -halfThick - layerSpacing, false, scale);\n break;\n case 'GTS':\n this.renderMaskLayer([res.data], halfThick + layerSpacing * 2, true, scale);\n break;\n case 'GBS':\n this.renderMaskLayer([res.data], -halfThick - layerSpacing * 2, false, scale);\n break;\n case 'GTP':\n this.renderPasteLayer([res.data], halfThick + layerSpacing * 2.5, true, scale);\n break;\n case 'GBP':\n this.renderPasteLayer([res.data], -halfThick - layerSpacing * 2.5, false, scale);\n break;\n case 'GTO':\n this.renderSilkscreenLayer([res], halfThick + layerSpacing * 3, true, scale);\n break;\n case 'GBO':\n this.renderSilkscreenLayer([res], -halfThick - layerSpacing * 3, false, scale);\n break;\n case 'DRL':\n this.renderDrillLayer([res.data], scale);\n break;\n }\n } catch (e) {\n console.error(`Error processing PHO file ${file.name}:`, e);\n }\n }\n }\n\n // ==================== HELPERS ====================\n\n collectStandardShapes(layers) {\n const shapes = [];\n for (const layer of layers) {\n // 🎯 兼容两种格式:layer 可能是 res(带 .data) 或 res.data\n const webglData = layer.data || layer;\n \n // 1. LineStrips (Polygons/Paths from SVG)\n if (webglData.lineStrips && webglData.vertices) {\n for (const strip of webglData.lineStrips) {\n if (strip.count < 2) continue;\n \n // 收集所有点\n const points = [];\n for (let j = 0; j < strip.count; j++) {\n const ptr = (strip.start + j) * 3;\n points.push({\n x: webglData.vertices[ptr],\n y: -webglData.vertices[ptr + 1] // Y轴翻转\n });\n }\n \n if (points.length < 2) continue;\n \n // 检查路径是否闭合\n const first = points[0];\n const last = points[points.length - 1];\n const closeDist = Math.sqrt(\n Math.pow(first.x - last.x, 2) + \n Math.pow(first.y - last.y, 2)\n );\n const isClosed = closeDist < 0.001;\n \n // 只处理闭合路径或点数足够多的路径(扩展后的走线)\n if (isClosed || points.length >= 4) {\n const shape = new THREE.Shape();\n shape.moveTo(points[0].x, points[0].y);\n \n for (let j = 1; j < points.length; j++) {\n shape.lineTo(points[j].x, points[j].y);\n }\n \n // 确保形状闭合\n if (!isClosed) {\n shape.lineTo(points[0].x, points[0].y);\n }\n \n // 检查面积是否有效\n const area = Math.abs(THREE.ShapeUtils.area(shape.getPoints()));\n if (area > 0.0001) {\n shapes.push(shape);\n }\n }\n }\n }\n\n // 2. Segments (Standard Gerber primitives)\n if (layer.children) {\n const segments = [];\n for (const child of layer.children) {\n if (child.type === 'imagePath' && child.segments) {\n segments.push(...child.segments);\n }\n }\n if (segments.length > 0) {\n const stitched = this.buildShapesFromSegments(segments);\n shapes.push(...stitched);\n }\n }\n }\n return shapes;\n }\n\n buildShapesFromSegments(segments) {\n if (segments.length === 0) return [];\n \n // Optimization: Pre-compute all points to avoid repeated calculations\n const pool = segments.map(s => ({\n start: new THREE.Vector2(s.start[0], -s.start[1]), // Flip Y for WebGL\n end: new THREE.Vector2(s.end[0], -s.end[1]), // Flip Y\n original: s,\n used: false\n }));\n\n const shapes = [];\n const EPSILON = 0.01;\n const EPSILON_SQ = EPSILON * EPSILON; // Use squared distance for faster comparison\n\n while (true) {\n const startSeg = pool.find(s => !s.used);\n if (!startSeg) break;\n\n startSeg.used = true;\n const currentPath = new THREE.Shape();\n \n currentPath.moveTo(startSeg.start.x, startSeg.start.y);\n this.addSegmentToPath(currentPath, startSeg);\n\n let currentPoint = startSeg.end;\n let loopClosed = false;\n let segmentCount = 0;\n const MAX_SEGMENTS = 10000; // Safety limit to prevent infinite loops\n\n while (!loopClosed && segmentCount < MAX_SEGMENTS) {\n segmentCount++;\n \n // Optimization: Use squared distance comparison (faster)\n let nextSeg = null;\n let minDistSq = EPSILON_SQ;\n \n for (let i = 0; i < pool.length; i++) {\n if (pool[i].used) continue;\n const distSq = currentPoint.distanceToSquared(pool[i].start);\n if (distSq < minDistSq) {\n minDistSq = distSq;\n nextSeg = pool[i];\n }\n }\n \n if (!nextSeg) {\n // Check if we can close the loop\n if (currentPoint.distanceToSquared(startSeg.start) < EPSILON_SQ) {\n loopClosed = true;\n } else {\n break; // Open path, stop\n }\n } else {\n nextSeg.used = true;\n this.addSegmentToPath(currentPath, nextSeg);\n currentPoint = nextSeg.end;\n \n if (currentPoint.distanceToSquared(startSeg.start) < EPSILON_SQ) {\n loopClosed = true;\n }\n }\n }\n \n if (loopClosed) {\n shapes.push(currentPath);\n }\n }\n\n return shapes;\n }\n\n addSegmentToPath(path, seg) {\n const s = seg.original;\n if (s.type === 'line') {\n path.lineTo(seg.end.x, seg.end.y);\n } else if (s.type === 'arc') {\n const cx = s.center[0];\n const cy = -s.center[1]; // Flip Y\n const r = s.radius;\n path.lineTo(seg.end.x, seg.end.y); \n }\n }\n\n // --- Silkscreen helper: attach inner contours as holes to keep text counters hollow ---\n processSilkscreenHoles(shapes) {\n const items = shapes\n .map(s => {\n const points = s.getPoints();\n if (!points || points.length < 3) return null;\n\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;\n for (const p of points) {\n if (p.x < minX) minX = p.x;\n if (p.y < minY) minY = p.y;\n if (p.x > maxX) maxX = p.x;\n if (p.y > maxY) maxY = p.y;\n }\n\n const area = Math.abs(THREE.ShapeUtils.area(points));\n if (!isFinite(area) || area <= 1e-6) return null;\n \n // Convert area from square inches to square millimeters\n // 1 inch = 25.4 mm, so 1 inch² = 645.16 mm²\n const areaInMm2 = area * 645.16;\n\n return { shape: s, points, minX, minY, maxX, maxY, area: areaInMm2, isHole: false };\n })\n .filter(Boolean);\n\n if (items.length === 0) return [];\n\n // Largest first (outer contours first)\n items.sort((a, b) => b.area - a.area);\n\n const roots = [];\n\n for (let i = 0; i < items.length; i++) {\n const child = items[i];\n let parent = null;\n\n // Find the smallest containing parent among larger shapes (already processed earlier in list)\n for (let j = i - 1; j >= 0; j--) {\n const potential = items[j];\n\n // bbox containment quick check\n if (child.minX >= potential.minX && child.maxX <= potential.maxX &&\n child.minY >= potential.minY && child.maxY <= potential.maxY) {\n // point-in-polygon check using child's first point\n if (this.isPointInPolygon(child.points[0], potential.points)) {\n parent = potential;\n break;\n }\n }\n }\n\n if (parent) {\n const ratio = child.area / parent.area;\n \n // 🎯 如果子形状几乎和父形状一样大(ratio > 0.90),这个包含关系很可能是误判\n // 不应该建立这个父子关系,让子形状继续寻找其他可能的父形状\n if (ratio > 0.90) {\n // 不使用当前的parent,继续检查是否有其他更大的父形状\n // 如果找不到其他父形状,子形状会被作为根形状处理\n parent = null;\n }\n }\n \n if (parent) {\n const ratio = child.area / parent.area;\n \n // 🎯 自适应面积比限制:根据子形状的绝对面积调整阈值\n let adaptiveMaxRatio;\n if (child.area > 50) {\n // 大形状(>50mm²):允许高达45%的孔洞(大铜皮挖空)\n // 这些通常是clear极性的挖空区域\n adaptiveMaxRatio = 0.45;\n } else if (child.area > 10) {\n // 中等形状(10-50mm²):最大20%\n adaptiveMaxRatio = 0.20;\n } else if (child.area > 1) {\n // 小形状(1-10mm²):允许高达65%(字符孔洞)\n adaptiveMaxRatio = 0.65;\n } else {\n // 极小形状(<1mm²):允许高达90%(字符孔洞如 \"0\" 的内圆)\n // 提高到90%以匹配全局的\"几乎同大小\"规则\n adaptiveMaxRatio = 0.90;\n }\n \n // Filter out extremely tiny artifacts (noise)\n if (ratio < 0.0005) {\n roots.push(child.shape);\n continue;\n }\n \n // Filter out overly large shapes to prevent large graphics from being treated as holes\n if (ratio > adaptiveMaxRatio) {\n console.log(`[3D孔洞拒绝] ✗ 形状面积=${child.area.toFixed(2)}mm², ratio=${ratio.toFixed(4)} > maxRatio=${adaptiveMaxRatio.toFixed(2)}, 父面积=${parent.area.toFixed(2)}mm²`);\n roots.push(child.shape);\n continue;\n }\n\n if (parent.isHole) {\n // island inside a hole -> treat as new solid root (Three.js doesn't support nested islands in one shape well)\n roots.push(child.shape);\n } else {\n parent.shape.holes.push(child.shape);\n child.isHole = true;\n }\n } else {\n roots.push(child.shape);\n }\n }\n\n return roots;\n }\n\n isPointInPolygon(point, vs) {\n // Ray-casting algorithm for point-in-polygon\n const x = point.x, y = point.y;\n let inside = false;\n for (let i = 0, j = vs.length - 1; i < vs.length; j = i++) {\n const xi = vs[i].x, yi = vs[i].y;\n const xj = vs[j].x, yj = vs[j].y;\n\n const intersect = ((yi > y) !== (yj > y)) &&\n (x < (xj - xi) * (y - yi) / ((yj - yi) || 1e-12) + xi);\n if (intersect) inside = !inside;\n }\n return inside;\n }\n\n renderShapesInChunks(shapes, material, zPosition, scale = 1.0, chunkSize = 2000, layerType = null) {\n if (shapes.length === 0) return [];\n \n const meshes = [];\n \n // Optimization: Adaptive chunk size based on total count\n // Smaller chunks for very large batches to reduce memory pressure\n let optimizedChunkSize = chunkSize;\n if (shapes.length > 20000) {\n optimizedChunkSize = 200; // Further reduced for very large batches\n } else if (shapes.length > 10000) {\n optimizedChunkSize = 400;\n } else if (shapes.length > 5000) {\n optimizedChunkSize = 800;\n }\n \n const useAsync = shapes.length > 3000; // Lower threshold for async rendering\n \n if (useAsync) {\n // Async rendering for large batches to avoid blocking\n this.renderShapesAsync(shapes, material, zPosition, scale, optimizedChunkSize, layerType);\n return []; // Async rendering doesn't return meshes immediately\n } else {\n // Synchronous rendering for smaller batches\n for (let i = 0; i < shapes.length; i += optimizedChunkSize) {\n const chunk = shapes.slice(i, i + optimizedChunkSize);\n // OPTIMIZATION: Reduce curveSegments from default 12 to 3 for better performance\n // This drastically reduces triangle count for text and pads\n const geometry = new THREE.ShapeGeometry(chunk, 3); \n const mesh = new THREE.Mesh(geometry, material);\n mesh.position.z = zPosition;\n mesh.scale.set(scale, scale, 1);\n // Mark layer type for camera fitting\n if (layerType) {\n mesh.userData = { layerType: layerType };\n }\n this.baseGroup.add(mesh);\n meshes.push(mesh);\n }\n }\n \n return meshes;\n }\n\n renderShapesAsync(shapes, material, zPosition, scale, chunkSize, layerType = null) {\n let index = 0;\n const totalChunks = Math.ceil(shapes.length / chunkSize);\n let renderedChunks = 0;\n \n const renderNextChunk = () => {\n if (index >= shapes.length) {\n // debugLog(`[Performance] Rendered ${renderedChunks} chunks asynchronously`);\n return;\n }\n \n // Render multiple chunks per iteration for better performance\n const chunksPerFrame = 5; // Increased from 3 to 5\n for (let i = 0; i < chunksPerFrame && index < shapes.length; i++) {\n const chunk = shapes.slice(index, index + chunkSize);\n // OPTIMIZATION: Reduce curveSegments to 3 for better performance\n const geometry = new THREE.ShapeGeometry(chunk, 3);\n const mesh = new THREE.Mesh(geometry, material);\n mesh.position.z = zPosition;\n mesh.scale.set(scale, scale, 1);\n // Mark layer type for camera fitting\n if (layerType) {\n mesh.userData = { layerType: layerType };\n }\n this.baseGroup.add(mesh);\n \n index += chunkSize;\n renderedChunks++;\n }\n \n // Use requestAnimationFrame to avoid blocking the main thread\n if (index < shapes.length) {\n requestAnimationFrame(renderNextChunk);\n }\n };\n \n renderNextChunk();\n }\n\n getCachedMaterial(key, creator) {\n if (!this.materialCache.has(key)) {\n this.materialCache.set(key, creator());\n }\n return this.materialCache.get(key);\n }\n\n fitCameraToObject(object) {\n const box = new THREE.Box3().setFromObject(object);\n if (box.isEmpty()) return;\n this.fitCameraToBbox(box);\n }\n\n fitCameraToBbox(box) {\n if (box.isEmpty()) return;\n const center = box.getCenter(new THREE.Vector3());\n const size = box.getSize(new THREE.Vector3());\n const maxDim = Math.max(size.x, size.y);\n const fov = this.camera.fov * (Math.PI / 180);\n let distance = (maxDim / 2) / Math.tan(fov / 2);\n // Reduce distance multiplier to make objects appear larger (1.4 -> 1.1)\n distance *= 1.1;\n this.camera.position.set(center.x, center.y, center.z + distance);\n this.camera.near = distance / 100;\n this.camera.far = distance * 100;\n this.camera.updateProjectionMatrix();\n this.controls.target.copy(center);\n this.controls.update();\n }\n\n /**\n * 检测并修正钻孔层的坐标缩放问题\n * \n * 常见问题:\n * - 10倍问题:mil被当作inch解析\n * - 25.4倍问题:inch被当作mm解析\n * \n * @param {Object} layerData - 钻孔层数据(包含vertices和lineStrips)\n * @param {number} scale - 单位转换因子(inch -> mm 时为25.4)\n * @param {THREE.Box3} referenceBbox - 参考层边界\n * @returns {{ scale: number, bbox: THREE.Box3|null, success: boolean }}\n */\n fixDrillLayerAlignment(layerData, scale, referenceBbox) {\n if (!layerData?.vertices || !referenceBbox) {\n return { scale, bbox: null, success: false };\n }\n\n // 1. 计算原始钻孔bbox(转换单位)\n let drillBbox = this.calculateLayerBbox([layerData]);\n if (!drillBbox || drillBbox.isEmpty()) {\n return { scale, bbox: null, success: false };\n }\n \n drillBbox.min.multiplyScalar(scale);\n drillBbox.max.multiplyScalar(scale);\n\n // 2. 检查坐标是否已在合理范围内(±10%容差)\n const refSize = referenceBbox.getSize(new THREE.Vector3());\n const tolerance = 0.1;\n const inRangeX = drillBbox.min.x >= referenceBbox.min.x - refSize.x * tolerance && \n drillBbox.max.x <= referenceBbox.max.x + refSize.x * tolerance;\n const inRangeY = drillBbox.min.y >= referenceBbox.min.y - refSize.y * tolerance && \n drillBbox.max.y <= referenceBbox.max.y + refSize.y * tolerance;\n\n if (inRangeX && inRangeY) {\n debugLog('[Drill] 坐标已在范围内,无需修正');\n return { scale, bbox: drillBbox, success: true };\n }\n\n // 3. 检测缩放错误类型\n const drillSize = drillBbox.getSize(new THREE.Vector3());\n const avgSizeRatio = (drillSize.x / refSize.x + drillSize.y / refSize.y) / 2;\n \n let scaleFix = 1.0;\n if (avgSizeRatio > 5 && avgSizeRatio < 15) {\n scaleFix = 10.0; // mil被当作inch\n } else if (avgSizeRatio > 20 && avgSizeRatio < 30) {\n scaleFix = 25.4; // inch被当作mm\n } else if (avgSizeRatio > 1.5) {\n scaleFix = avgSizeRatio; // 其他缩放问题\n }\n\n if (scaleFix === 1.0) {\n debugLog('[Drill] 未检测到常见缩放问题');\n return { scale, bbox: drillBbox, success: true };\n }\n\n debugLog(`[Drill] 检测到${scaleFix.toFixed(1)}倍缩放问题,开始修正...`);\n\n // 4. 应用缩放修正(只缩放孔位,保持孔径)\n const { vertices, lineStrips } = layerData;\n if (lineStrips?.length > 0) {\n this.applyDrillScaleFix(vertices, lineStrips, scale, scaleFix);\n } else {\n // 回退:没有lineStrips,直接缩放所有顶点(孔径也会被缩放)\n debugWarn('[Drill] 缺少lineStrips,孔径会被缩放');\n for (let i = 0; i < vertices.length; i += 3) {\n vertices[i] = vertices[i] * scale / scaleFix;\n vertices[i + 1] = vertices[i + 1] * scale / scaleFix;\n }\n }\n\n // 5. 重新计算修正后的bbox\n drillBbox = this.calculateLayerBbox([layerData]);\n if (!drillBbox || drillBbox.isEmpty()) {\n return { scale: 1.0, bbox: null, success: false };\n }\n\n debugLog(`[Drill] 修正后bbox: (${drillBbox.min.x.toFixed(2)}, ${drillBbox.min.y.toFixed(2)}) - (${drillBbox.max.x.toFixed(2)}, ${drillBbox.max.y.toFixed(2)})`);\n return { scale: 1.0, bbox: drillBbox, success: true };\n }\n\n /**\n * 应用缩放修正,只移动孔位中心,保持孔径不变\n * \n * 原理:每个lineStrip代表一个钻孔圆,通过计算圆心位置并只平移顶点,\n * 可以实现\"缩放位置但保持孔径\"的效果。\n * \n * @param {Float32Array} vertices - 顶点数组\n * @param {Array} lineStrips - 线段描述数组(每个代表一个圆)\n * @param {number} scale - 单位转换因子(inch -> mm)\n * @param {number} scaleFix - 缩放修正因子(如10.0表示除以10)\n */\n applyDrillScaleFix(vertices, lineStrips, scale, scaleFix) {\n let processedCount = 0;\n \n for (const strip of lineStrips) {\n if (strip.count < 3) continue;\n \n // 1. 计算圆心(转mm并翻转Y,与calculateLayerBbox一致)\n let sumX = 0, sumY = 0;\n for (let i = 0; i < strip.count; i++) {\n const idx = (strip.start + i) * 3;\n sumX += vertices[idx];\n sumY += vertices[idx + 1];\n }\n const centerX = sumX / strip.count * scale;\n const centerY = -sumY / strip.count * scale; // Y翻转\n \n // 2. 计算位置偏移(只移动位置,不改变大小)\n const deltaX = centerX / scaleFix - centerX;\n const deltaY = centerY / scaleFix - centerY;\n \n // 3. 平移所有顶点(vertices是未翻转的Y,所以deltaY反向)\n for (let i = 0; i < strip.count; i++) {\n const idx = (strip.start + i) * 3;\n vertices[idx] = vertices[idx] * scale + deltaX;\n vertices[idx + 1] = vertices[idx + 1] * scale - deltaY;\n }\n processedCount++;\n }\n \n debugLog(`[Drill] 已修正 ${processedCount} 个钻孔,孔径保持不变`);\n }\n\n /**\n * 验证钻孔层边界是否在合理范围内\n * \n * @param {THREE.Box3} drillBbox - 钻孔层边界\n * @param {THREE.Box3} referenceBbox - 参考层边界\n * @param {THREE.Box3} expandedReferenceBbox - 扩展后的参考层边界(含容差)\n * @param {string} fileName - 文件名(用于日志)\n * @returns {boolean} 是否通过验证\n */\n validateDrillBbox(drillBbox, referenceBbox, expandedReferenceBbox, fileName) {\n // 检查 1:与板子范围(放大 20mm)无交集\n if (!expandedReferenceBbox.intersectsBox(drillBbox)) {\n debugWarn(`[Drill] ${fileName} 与板子范围无交集(容错20mm),跳过渲染`);\n return false;\n }\n\n if (!referenceBbox) return true;\n\n const refSize = referenceBbox.getSize(new THREE.Vector3());\n const drillSize = drillBbox.getSize(new THREE.Vector3());\n\n // 检查 2:尺寸偏差\n const maxRatio = 1.3; // 允许一定余量(如工艺边/靠边孔)\n const minRatio = 0.2; // 极端偏小通常是单位/格式问题\n \n if (drillSize.x > refSize.x * maxRatio || drillSize.y > refSize.y * maxRatio) {\n debugWarn(`[Drill] ${fileName} 钻孔范围过大(>${maxRatio}x),跳过渲染`);\n return false;\n }\n if (drillSize.x < refSize.x * minRatio && drillSize.y < refSize.y * minRatio) {\n debugWarn(`[Drill] ${fileName} 钻孔范围过小(<${minRatio}x),跳过渲染`);\n return false;\n }\n\n // 检查 3:中心偏移过大\n const centerRef = referenceBbox.getCenter(new THREE.Vector3());\n const centerDrill = drillBbox.getCenter(new THREE.Vector3());\n const maxDim = Math.max(refSize.x, refSize.y);\n const centerThreshold = Math.max(maxDim * 0.15, 25); // 15% 或至少 25mm\n const centerDist = centerRef.distanceTo(centerDrill);\n \n // ✅ 关键修复:对“小范围钻孔文件”(只在板子某一角/某一排连接器区域打孔)不做中心偏移淘汰,\n // 否则像 SlotHoles.TXT 这种局部孔会被误杀(你日志里正是 34.6mm 被跳过)。\n const sizeRatioX = drillSize.x / Math.max(1e-9, refSize.x);\n const sizeRatioY = drillSize.y / Math.max(1e-9, refSize.y);\n const localized = (Math.max(sizeRatioX, sizeRatioY) < 0.60);\n\n if (!localized && centerDist > centerThreshold) {\n debugWarn(`[Drill] ${fileName} 中心偏移过大(${centerDist.toFixed(1)}mm),跳过渲染`);\n return false;\n }\n\n return true;\n }\n\n /**\n * 将线段拼接成THREE.Shape对象(用于多轮廓文件合并)\n * @param {Array<{start:{x,y}, end:{x,y}}>} segments 线段数组\n * @returns {Array<THREE.Shape>} 形状数组\n */\n stitchSegmentsToShapes3D(segments) {\n if (!segments || segments.length === 0) return [];\n \n // 计算容差\n let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;\n for (const seg of segments) {\n minX = Math.min(minX, seg.start.x, seg.end.x);\n maxX = Math.max(maxX, seg.start.x, seg.end.x);\n minY = Math.min(minY, seg.start.y, seg.end.y);\n maxY = Math.max(maxY, seg.start.y, seg.end.y);\n }\n const boardSize = Math.max(maxX - minX, maxY - minY);\n const TOLERANCE = boardSize > 100 ? 0.2 : boardSize > 50 ? 0.1 : 0.05;\n \n // 构建空间网格\n const cellSize = TOLERANCE;\n const grid = new Map();\n const getCell = (pt) => `${Math.floor(pt.x / cellSize)},${Math.floor(pt.y / cellSize)}`;\n \n const poolItems = segments.map(s => ({ seg: s, used: false }));\n \n const addToGrid = (item) => {\n const k1 = getCell(item.seg.start);\n const k2 = getCell(item.seg.end);\n if (!grid.has(k1)) grid.set(k1, []);\n grid.get(k1).push(item);\n if (k1 !== k2) {\n if (!grid.has(k2)) grid.set(k2, []);\n grid.get(k2).push(item);\n }\n };\n \n poolItems.forEach(addToGrid);\n \n const distanceTo = (p1, p2) => Math.sqrt((p1.x - p2.x) ** 2 + (p1.y - p2.y) ** 2);\n \n const getCandidates = (pt) => {\n const cx = Math.floor(pt.x / cellSize);\n const cy = Math.floor(pt.y / cellSize);\n const results = new Set();\n for (let dx = -1; dx <= 1; dx++) {\n for (let dy = -1; dy <= 1; dy++) {\n const k = `${cx + dx},${cy + dy}`;\n const list = grid.get(k);\n if (list) {\n for (const item of list) results.add(item);\n }\n }\n }\n return results;\n };\n \n const chains = [];\n \n // 拼线\n for (const startItem of poolItems) {\n if (startItem.used) continue;\n \n startItem.used = true;\n const chain = [startItem.seg.start, startItem.seg.end];\n let tail = startItem.seg.end;\n let head = startItem.seg.start;\n \n // 向后搜索\n let finding = true;\n while (finding) {\n finding = false;\n const candidates = getCandidates(tail);\n \n let bestNext = null;\n let minDst = Infinity;\n let isReverse = false;\n \n for (const item of candidates) {\n if (item.used) continue;\n \n const d1 = distanceTo(item.seg.start, tail);\n if (d1 < TOLERANCE && d1 < minDst) {\n minDst = d1;\n bestNext = item;\n isReverse = false;\n }\n const d2 = distanceTo(item.seg.end, tail);\n if (d2 < TOLERANCE && d2 < minDst) {\n minDst = d2;\n bestNext = item;\n isReverse = true;\n }\n }\n \n if (bestNext) {\n bestNext.used = true;\n if (isReverse) {\n chain.push(bestNext.seg.start);\n tail = bestNext.seg.start;\n } else {\n chain.push(bestNext.seg.end);\n tail = bestNext.seg.end;\n }\n finding = true;\n }\n }\n \n // 向前搜索\n finding = true;\n while (finding) {\n finding = false;\n const candidates = getCandidates(head);\n \n let bestPrev = null;\n let minDst = Infinity;\n let isReverse = false;\n \n for (const item of candidates) {\n if (item.used) continue;\n \n const d1 = distanceTo(item.seg.end, head);\n if (d1 < TOLERANCE && d1 < minDst) {\n minDst = d1;\n bestPrev = item;\n isReverse = false;\n }\n const d2 = distanceTo(item.seg.start, head);\n if (d2 < TOLERANCE && d2 < minDst) {\n minDst = d2;\n bestPrev = item;\n isReverse = true;\n }\n }\n \n if (bestPrev) {\n bestPrev.used = true;\n if (isReverse) {\n chain.unshift(bestPrev.seg.end);\n head = bestPrev.seg.end;\n } else {\n chain.unshift(bestPrev.seg.start);\n head = bestPrev.seg.start;\n }\n finding = true;\n }\n }\n \n chains.push(chain);\n }\n \n // 将链转换为THREE.Shape\n const shapes = [];\n const MIN_AREA = 0.01;\n \n for (const chain of chains) {\n if (chain.length < 3) continue;\n \n // 检查是否闭合\n const headPt = chain[0];\n const tailPt = chain[chain.length - 1];\n const isClosed = distanceTo(headPt, tailPt) < TOLERANCE;\n \n if (!isClosed) continue; // 只保留闭合路径\n \n // 计算面积\n let area = 0;\n for (let i = 0; i < chain.length; i++) {\n const p1 = chain[i];\n const p2 = chain[(i + 1) % chain.length];\n area += p1.x * p2.y - p2.x * p1.y;\n }\n area = Math.abs(area) / 2;\n \n if (area < MIN_AREA) continue;\n \n // 创建THREE.Shape\n const shape = new THREE.Shape();\n shape.moveTo(chain[0].x, chain[0].y);\n for (let i = 1; i < chain.length; i++) {\n shape.lineTo(chain[i].x, chain[i].y);\n }\n shape.closePath();\n \n shape.userData = { forcedClose: false, area };\n shapes.push(shape);\n }\n \n return shapes;\n }\n\n calculateLayerBbox(layers) {\n const allPoints = [];\n for (const layer of layers) {\n // Collect points from lineStrips\n if (layer.lineStrips && layer.vertices) {\n for (const strip of layer.lineStrips) {\n for (let j = 0; j < strip.count; j++) {\n const ptr = (strip.start + j) * 3;\n allPoints.push(new THREE.Vector3(\n layer.vertices[ptr],\n -layer.vertices[ptr + 1],\n 0\n ));\n }\n }\n }\n // Collect points from children/segments\n if (layer.children) {\n for (const child of layer.children) {\n if (child.type === 'imagePath' && child.segments) {\n for (const seg of child.segments) {\n allPoints.push(new THREE.Vector3(seg.start[0], -seg.start[1], 0));\n allPoints.push(new THREE.Vector3(seg.end[0], -seg.end[1], 0));\n }\n }\n }\n }\n }\n \n if (allPoints.length === 0) return null;\n return new THREE.Box3().setFromPoints(allPoints);\n }\n}\n\nwindow.onload = () => new Viewer3D();","/**\n * 专门用于提取轮廓层(GKO/GM1等)的 Gerber 解析器\n * 基于 2d-direct/js/gerber-parser-direct.js 修改\n * 重点在于解析 G36/G37 区域并直接生成 THREE.Shape\n * 同时也支持标准线段定义的轮廓(非 G36/G37)并进行拼线\n */\nimport * as THREE from 'three';\n\nexport class GerberOutlineParser {\n constructor() {\n this.shapes = []; // 存储生成的 THREE.Shape 对象\n this.strokeSegments = []; // 兜底渲染用的线段集合(G01/G02/G03 离散后)\n \n this.state = {\n x: 0,\n y: 0,\n i: 0,\n j: 0,\n d: 0,\n lastD: null, // 🚀 Modal D-code\n g: 1, // 1: linear, 2: cw, 3: ccw, 36: region start, 37: region end\n interpolation: 'linear',\n regionMode: false,\n quadrant: 'multi',\n unit: 'mm',\n format: {\n integer: 2,\n decimal: 4,\n zero: 'L'\n }\n };\n\n // 区域路径缓存 (G36/G37)\n this.currentRegionContours = [];\n this._currentRegionContour = null;\n\n // 非区域线段缓存 (G01/G02/G03)\n this.segments = []; \n }\n\n parse(content) {\n this.shapes = [];\n this.segments = []; // 清空之前的段\n this.currentRegionContours = [];\n this.strokeSegments = [];\n \n const lines = content.split(/[\\n\\r]+/);\n const MAX_SEGMENTS_DURING_PARSE = 300000; // 🚀 进一步放宽限制,支持复杂圆形等异形轮廓(209K段的圆形板)\n let abortedDueToSize = false;\n \n for (let line of lines) {\n // 🚀 在解析过程中检查,避免无谓处理\n if (this.segments.length > MAX_SEGMENTS_DURING_PARSE || this.strokeSegments.length > MAX_SEGMENTS_DURING_PARSE) {\n abortedDueToSize = true;\n break;\n }\n \n line = line.trim();\n if (!line) continue;\n \n if (line.startsWith('%') && line.endsWith('%')) {\n this.parseExtendedCommand(line.substring(1, line.length - 1));\n continue;\n }\n \n const commands = line.split('*');\n for (let cmd of commands) {\n cmd = cmd.trim();\n if (!cmd) continue;\n this.parseCommand(cmd);\n }\n }\n \n if (abortedDueToSize) {\n console.warn(`[GerberOutline] 解析中止:线段数量过多 (segments=${this.segments.length}, strokes=${this.strokeSegments.length}),跳过复杂解析`);\n return { shapes: [], strokes: [] };\n }\n\n // 1. 处理 G36/G37 区域\n if (this.currentRegionContours.length > 0) {\n this.processRegions();\n }\n\n // 2. 处理标准线段 (如果有)\n if (this.segments.length > 0) {\n this.stitchSegmentsToShapes();\n }\n\n // 3. 移除外接矩形兜底逻辑,避免将异形板误判为矩形\n // 如果需要兜底可视化,使用 strokes 在 Three.js 中单独渲染线框\n if (this.strokeSegments.length >= 100000) {\n // 完全禁用日志输出以提高性能\n // console.warn(`[GerberOutline] 线段数量过多 (${this.strokeSegments.length}),跳过兜底渲染以避免性能问题`);\n }\n\n // 返回面与线两种结果,面用于厚板,线用于兜底可视化\n return {\n shapes: this.shapes,\n strokes: this.strokeSegments\n };\n }\n\n parseExtendedCommand(cmd) {\n if (cmd.startsWith('FS')) {\n const match = cmd.match(/FS([LT])?[AI]X(\\d)(\\d)Y(\\d)(\\d)/);\n if (match) {\n this.state.format.zero = match[1] || 'L';\n this.state.format.integer = parseInt(match[2]);\n this.state.format.decimal = parseInt(match[3]);\n }\n } else if (cmd.startsWith('MO')) {\n this.state.unit = cmd.includes('IN') ? 'inch' : 'mm';\n }\n }\n\n parseCommand(cmd) {\n if (cmd.startsWith('G')) {\n const gCode = parseInt(cmd.substring(1, 3));\n if (gCode === 1) this.state.interpolation = 'linear';\n if (gCode === 2) this.state.interpolation = 'cw';\n if (gCode === 3) this.state.interpolation = 'ccw';\n if (gCode === 36) {\n this.state.regionMode = true;\n this.currentRegionContours = [];\n this._currentRegionContour = null;\n }\n if (gCode === 37) {\n this.state.regionMode = false;\n this.finishRegion(); \n }\n if (cmd.length > 3) this.parseCoordinate(cmd.substring(3));\n return;\n }\n\n // D01/D02/D03\n if (cmd.startsWith('D') && parseInt(cmd.substring(1)) >= 10) {\n return;\n }\n\n this.parseCoordinate(cmd);\n }\n\n parseCoordinate(cmd) {\n let x = this.state.x;\n let y = this.state.y;\n let iOffset = 0;\n let jOffset = 0;\n let d = null;\n\n const xMatch = cmd.match(/X([-+]?\\d+)/);\n if (xMatch) x = this.parseValue(xMatch[1]);\n\n const yMatch = cmd.match(/Y([-+]?\\d+)/);\n if (yMatch) y = this.parseValue(yMatch[1]);\n \n const iMatch = cmd.match(/I([-+]?\\d+)/);\n if (iMatch) iOffset = this.parseValue(iMatch[1]);\n\n const jMatch = cmd.match(/J([-+]?\\d+)/);\n if (jMatch) jOffset = this.parseValue(jMatch[1]);\n\n const dMatch = cmd.match(/D(\\d+)/);\n if (dMatch) {\n d = parseInt(dMatch[1]);\n // 更新模态 D-code\n if (d === 1 || d === 2) {\n this.state.lastD = d;\n }\n } else {\n // 如果没有 D-code,尝试使用模态 D-code\n if ((xMatch || yMatch || iMatch || jMatch) && this.state.lastD) {\n d = this.state.lastD;\n }\n }\n\n const prevX = this.state.x;\n const prevY = this.state.y;\n this.state.x = x;\n this.state.y = y;\n\n if (d !== null) {\n if (d === 1) { // Draw\n if (this.state.regionMode) {\n if (this.state.interpolation === 'linear') {\n if (!this._currentRegionContour) this._startRegionContour(prevX, prevY);\n this._currentRegionContour.push({ x, y });\n } else {\n if (!this._currentRegionContour) this._startRegionContour(prevX, prevY);\n this.addArcToRegion(prevX, prevY, x, y, iOffset, jOffset, this.state.interpolation === 'cw');\n }\n } else {\n // 非 Region 模式:收集线段用于拼线\n this.addSegment(prevX, prevY, x, y, iOffset, jOffset, this.state.interpolation);\n }\n } else if (d === 2) { // Move\n if (this.state.regionMode) {\n this._startRegionContour(x, y);\n }\n }\n }\n }\n\n parseValue(str) {\n let scale = Math.pow(10, this.state.format.decimal);\n let val = parseFloat(str) / scale;\n // 内部转换单位为mm(与home/simulation3d保持一致)\n if (this.state.unit === 'inch') val *= 25.4;\n return val;\n }\n\n // --- Region Logic ---\n\n _startRegionContour(x, y) {\n const contour = [{ x, y }];\n this.currentRegionContours.push(contour);\n this._currentRegionContour = contour;\n }\n\n addArcToRegion(x1, y1, x2, y2, iOffset, jOffset, isCw) {\n const pts = this.discretizeArc(x1, y1, x2, y2, iOffset, jOffset, isCw);\n for (let i = 1; i < pts.length; i++) {\n if (this._currentRegionContour) {\n this._currentRegionContour.push(pts[i]);\n }\n }\n }\n\n finishRegion() {\n if (this.currentRegionContours.length > 0) {\n // 将当前块的 region 轮廓转为 shapes\n // 这里为了支持多个 Region 块,我们将它们全部转为 Shape 存入\n const newShapes = this.contoursToShapes(this.currentRegionContours);\n this.shapes.push(...newShapes);\n this.currentRegionContours = [];\n }\n this._currentRegionContour = null;\n }\n\n processRegions() {\n if (this.currentRegionContours.length > 0) {\n const newShapes = this.contoursToShapes(this.currentRegionContours);\n this.shapes.push(...newShapes);\n this.currentRegionContours = [];\n }\n }\n\n contoursToShapes(rawContours) {\n // 简单清洗并转换为 Shape,不进行任何包含关系计算/布尔运算\n const shapes = [];\n for (const rawPts of rawContours) {\n // 清洗:去除重复点\n const pts = [];\n let last = null;\n for (const p of rawPts) {\n if (!last || Math.hypot(p.x - last.x, p.y - last.y) > 1e-4) {\n pts.push(p);\n last = p;\n }\n }\n \n // 检查闭合性:如果首尾距离过大,说明可能未闭合。\n // 业务诉求:宁可强行闭合,也不要丢面,因此只在超大间隙时才放弃。\n let forcedClose = false;\n if (pts.length > 2) {\n const first = pts[0];\n const end = pts[pts.length - 1];\n const gap = Math.hypot(first.x - end.x, first.y - end.y);\n\n const WARN_GAP = 10.0; // 提示用\n const MAX_GAP = 1000.0; // 仅超大异常才丢弃\n\n if (gap > WARN_GAP) {\n // 完全禁用日志输出以提高性能\n // if (gap > 100.0) {\n // console.warn(`[GerberOutline] 未闭合路径间隙: ${gap.toFixed(3)}mm,尝试强制闭合`);\n // }\n forcedClose = true;\n }\n if (gap > MAX_GAP) {\n // 完全禁用日志输出以提高性能\n // console.warn(`[GerberOutline] 间隙过大,放弃闭合: ${gap.toFixed(3)}mm`);\n continue;\n }\n\n if (gap > 0.001) {\n pts.push({ x: first.x, y: first.y });\n }\n } else {\n continue;\n }\n\n if (pts.length >= 3) {\n const shape = new THREE.Shape();\n shape.moveTo(pts[0].x, pts[0].y);\n for (let i = 1; i < pts.length; i++) {\n shape.lineTo(pts[i].x, pts[i].y);\n }\n shape.closePath();\n // 标记强制闭合的形状,用于避免绘制对角线边框\n shape.userData = { forcedClose };\n \n // 完全禁用日志输出以提高性能\n // const area = THREE.ShapeUtils.area(shape.getPoints());\n // if (Math.abs(area) < 0.001) {\n // console.warn(`[GerberOutline] 生成的形状面积过小: ${area.toFixed(6)} mm², 点数: ${pts.length}`);\n // }\n shapes.push(shape);\n } else {\n // 完全禁用日志输出以提高性能\n // console.warn(`[GerberOutline] 跳过点数不足的轮廓: ${pts.length} 个点`);\n }\n }\n return shapes;\n }\n\n // --- Non-Region Segment Logic ---\n\n addSegment(x1, y1, x2, y2, iOffset, jOffset, mode) {\n if (mode === 'linear') {\n this.segments.push({ \n start: new THREE.Vector2(x1, y1), \n end: new THREE.Vector2(x2, y2) \n });\n } else {\n // Arc\n const pts = this.discretizeArc(x1, y1, x2, y2, iOffset, jOffset, mode === 'cw');\n for (let i = 0; i < pts.length - 1; i++) {\n this.segments.push({\n start: new THREE.Vector2(pts[i].x, pts[i].y),\n end: new THREE.Vector2(pts[i+1].x, pts[i+1].y)\n });\n }\n }\n }\n\n discretizeArc(x1, y1, x2, y2, iOffset, jOffset, isCw) {\n const cx = x1 + iOffset;\n const cy = y1 + jOffset;\n const radius = Math.sqrt(iOffset * iOffset + jOffset * jOffset);\n\n if (radius < 0.0001) return [{x: x1, y: y1}, {x: x2, y: y2}];\n\n let startAngle = Math.atan2(y1 - cy, x1 - cx);\n let endAngle = Math.atan2(y2 - cy, x2 - cx);\n\n if (isCw) {\n if (endAngle >= startAngle) endAngle -= 2 * Math.PI;\n } else {\n if (endAngle <= startAngle) endAngle += 2 * Math.PI;\n }\n\n const arcLength = Math.abs(endAngle - startAngle) * radius;\n const angleSpan = Math.abs(endAngle - startAngle);\n \n // 优化弧线精度:统一处理,确保所有圆角一致\n // 对于小圆角(半径 < 10mm),使用统一的高精度;对于大圆弧,使用更粗精度\n let segmentSize;\n let minSegments;\n \n // 判断是否为小圆角(半径 < 10mm)\n const isSmallCorner = radius < 10;\n \n if (isSmallCorner) {\n // 小圆角:统一使用高精度,确保所有圆角一致和平滑\n segmentSize = 0.003; // 统一使用0.003mm精度\n // 根据角度跨度计算最少段数:90度圆角至少32段,180度至少64段\n minSegments = Math.max(32, Math.ceil(angleSpan / (Math.PI / 2) * 32));\n } else if (arcLength > 100) {\n segmentSize = 0.02; // 大圆弧:0.02mm精度\n minSegments = 12;\n } else if (arcLength > 10) {\n segmentSize = 0.01; // 中等圆弧:0.01mm精度\n minSegments = 16;\n } else {\n segmentSize = 0.005; // 小圆弧:0.005mm精度\n minSegments = 20;\n }\n \n const segments = Math.max(minSegments, Math.ceil(arcLength / segmentSize)); \n\n const pts = [];\n pts.push({x: x1, y: y1}); \n\n for (let k = 1; k <= segments; k++) {\n const t = k / segments;\n const angle = startAngle + (endAngle - startAngle) * t;\n pts.push({\n x: cx + radius * Math.cos(angle),\n y: cy + radius * Math.sin(angle)\n });\n }\n // 强制最后一点精确等于 x2, y2\n pts[pts.length - 1] = { x: x2, y: y2 };\n return pts;\n }\n\n stitchSegmentsToShapes() {\n // 1. 线段去重 (O(N))\n const uniqueSegments = [];\n const seen = new Set();\n // 0.01um precision for deduplication key (提高精度)\n const keyFn = (p) => `${Math.round(p.x * 100000)},${Math.round(p.y * 100000)}`; \n \n for (const seg of this.segments) {\n // 生成双向 Key 以确保无视方向去重\n const k1 = keyFn(seg.start) + \"|\" + keyFn(seg.end);\n const k2 = keyFn(seg.end) + \"|\" + keyFn(seg.start);\n if (!seen.has(k1) && !seen.has(k2)) {\n seen.add(k1);\n uniqueSegments.push(seg);\n }\n }\n \n // 动态计算容差:根据线段范围自动调整,避免容差过小导致拼接失败\n if (uniqueSegments.length === 0) return;\n \n // 计算所有线段的范围\n let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;\n for (const seg of uniqueSegments) {\n minX = Math.min(minX, seg.start.x, seg.end.x);\n maxX = Math.max(maxX, seg.start.x, seg.end.x);\n minY = Math.min(minY, seg.start.y, seg.end.y);\n maxY = Math.max(maxY, seg.start.y, seg.end.y);\n }\n const boardSize = Math.max(maxX - minX, maxY - minY);\n \n // 根据板子尺寸动态调整容差:大板子用更大的容差\n // 对于大板子(>100mm),使用0.5mm容差;中等板子(>50mm)使用0.25mm;小板子使用0.1mm\n let TOLERANCE;\n if (boardSize > 100) {\n TOLERANCE = 0.5;\n } else if (boardSize > 50) {\n TOLERANCE = 0.25;\n } else {\n TOLERANCE = 0.1;\n }\n const cellSize = TOLERANCE;\n \n // 2. 构建 Spatial Grid (O(N))\n // Map<CellKey, Array<PoolItem>>\n const grid = new Map();\n const getCell = (pt) => `${Math.floor(pt.x / cellSize)},${Math.floor(pt.y / cellSize)}`;\n \n // 保存去重后的线段,供兜底线框渲染\n this.strokeSegments = uniqueSegments.map(s => ({\n start: s.start.clone(),\n end: s.end.clone()\n }));\n\n const poolItems = uniqueSegments.map(s => ({ seg: s, used: false }));\n \n const addToGrid = (item) => {\n const k1 = getCell(item.seg.start);\n const k2 = getCell(item.seg.end);\n \n if (!grid.has(k1)) grid.set(k1, []);\n grid.get(k1).push(item);\n \n // 如果跨越 cell,都加上,反正查询时会去重\n if (k1 !== k2) {\n if (!grid.has(k2)) grid.set(k2, []);\n grid.get(k2).push(item);\n }\n };\n \n poolItems.forEach(addToGrid);\n \n const getCandidates = (pt) => {\n const cx = Math.floor(pt.x / cellSize);\n const cy = Math.floor(pt.y / cellSize);\n const results = new Set(); \n \n for (let dx = -1; dx <= 1; dx++) {\n for (let dy = -1; dy <= 1; dy++) {\n const k = `${cx + dx},${cy + dy}`;\n const list = grid.get(k);\n if (list) {\n for (const item of list) results.add(item);\n }\n }\n }\n return results;\n };\n\n const chains = [];\n\n // 3. 拼线 (O(N))\n for (const startItem of poolItems) {\n if (startItem.used) continue;\n\n startItem.used = true;\n const chain = [startItem.seg.start, startItem.seg.end];\n let tail = startItem.seg.end;\n let head = startItem.seg.start;\n \n // 向后搜索 (Tail)\n let finding = true;\n while (finding) {\n finding = false;\n const candidates = getCandidates(tail);\n \n let bestNext = null;\n let minDst = Infinity; \n let isReverse = false;\n\n for (const item of candidates) {\n if (item.used) continue;\n \n const d1 = item.seg.start.distanceTo(tail);\n if (d1 < TOLERANCE && d1 < minDst) {\n minDst = d1;\n bestNext = item;\n isReverse = false;\n }\n const d2 = item.seg.end.distanceTo(tail);\n if (d2 < TOLERANCE && d2 < minDst) {\n minDst = d2;\n bestNext = item;\n isReverse = true;\n }\n }\n\n if (bestNext) {\n bestNext.used = true;\n if (isReverse) {\n chain.push(bestNext.seg.start); \n tail = bestNext.seg.start;\n } else {\n chain.push(bestNext.seg.end);\n tail = bestNext.seg.end;\n }\n finding = true;\n }\n }\n\n // 向前搜索 (Head)\n finding = true;\n while (finding) {\n finding = false;\n const candidates = getCandidates(head);\n \n let bestPrev = null;\n let minDst = Infinity;\n let isReverse = false;\n\n for (const item of candidates) {\n if (item.used) continue;\n \n const d1 = item.seg.end.distanceTo(head);\n if (d1 < TOLERANCE && d1 < minDst) {\n minDst = d1;\n bestPrev = item;\n isReverse = false; \n }\n \n const d2 = item.seg.start.distanceTo(head);\n if (d2 < TOLERANCE && d2 < minDst) {\n minDst = d2;\n bestPrev = item;\n isReverse = true;\n }\n }\n\n if (bestPrev) {\n bestPrev.used = true;\n if (isReverse) {\n chain.unshift(bestPrev.seg.end);\n head = bestPrev.seg.end;\n } else {\n chain.unshift(bestPrev.seg.start);\n head = bestPrev.seg.start;\n }\n finding = true;\n }\n }\n\n chains.push(chain);\n }\n\n // 将 Chains 转为 Shapes\n const contours = [];\n for (const chain of chains) {\n if (chain.length < 3) {\n // 完全禁用日志输出以提高性能\n // console.warn(`[GerberOutline] 跳过过短的链: ${chain.length} 个点`);\n continue;\n }\n const pts = chain.map(p => ({ x: p.x, y: p.y }));\n contours.push(pts);\n }\n\n // 减少日志输出以提高性能\n const newShapes = this.contoursToShapes(contours);\n this.shapes.push(...newShapes);\n\n // 4. 兜底:在存在分叉/网格的情况下再尝试从线段图提取闭合环\n // 逻辑:基于去重后的线段构建无向图,按边遍历找到回到起点的环,避免被分叉打断。\n if (uniqueSegments.length > 0) {\n const fallbackShapes = this.buildLoopsFromSegments(uniqueSegments, TOLERANCE); // 使用相同的容差\n if (fallbackShapes.length > 0) {\n this.shapes.push(...fallbackShapes);\n }\n }\n }\n\n /**\n * 从无向线段集合中提取简单闭合环,适用于拼板网格等分叉场景。\n * 算法:构建邻接表,遍历未使用的边,沿邻接边走到回到起点即认为闭合。\n */\n buildLoopsFromSegments(segments, tol = 0.2) {\n const keyFn = (p) => `${Math.round(p.x / tol)},${Math.round(p.y / tol)}`;\n const nodes = new Map(); // key -> {pt, neighbors:Set<key>}\n\n const addNode = (p) => {\n const k = keyFn(p);\n if (!nodes.has(k)) {\n nodes.set(k, { pt: p.clone(), neighbors: new Set() });\n }\n return k;\n };\n\n const edges = new Map(); // sortedKey -> {aKey, bKey, used}\n const edgeKey = (aKey, bKey) => (aKey < bKey ? `${aKey}|${bKey}` : `${bKey}|${aKey}`);\n\n for (const seg of segments) {\n const aKey = addNode(seg.start);\n const bKey = addNode(seg.end);\n const ek = edgeKey(aKey, bKey);\n if (edges.has(ek)) continue; // 已存在\n edges.set(ek, { aKey, bKey, used: false });\n nodes.get(aKey).neighbors.add(bKey);\n nodes.get(bKey).neighbors.add(aKey);\n }\n\n const loops = [];\n\n for (const [ek, edge] of edges) {\n if (edge.used) continue;\n\n // 选定一条边开始走\n const pathKeys = [];\n let prevKey = edge.aKey;\n let currKey = edge.bKey;\n edge.used = true;\n pathKeys.push(prevKey, currKey);\n\n let closed = false;\n const MAX_STEPS = segments.length * 4; // 安全上限\n let steps = 0;\n\n while (steps < MAX_STEPS) {\n steps++;\n const currNode = nodes.get(currKey);\n if (!currNode) break;\n\n // 找到一条未使用的邻接边\n let nextKey = null;\n for (const nbKey of currNode.neighbors) {\n if (nbKey === prevKey) continue;\n const nk = edgeKey(currKey, nbKey);\n const e = edges.get(nk);\n if (e && !e.used) {\n nextKey = nbKey;\n e.used = true;\n break;\n }\n }\n\n if (nextKey === null) {\n // 尝试用容差判断回到起点\n const startNode = nodes.get(pathKeys[0]);\n const currNodePt = nodes.get(currKey)?.pt;\n if (startNode && currNodePt) {\n const gap = startNode.pt.distanceTo(currNodePt);\n if (gap <= tol && pathKeys.length > 2) {\n closed = true;\n }\n }\n break;\n }\n\n pathKeys.push(nextKey);\n prevKey = currKey;\n currKey = nextKey;\n\n if (currKey === pathKeys[0] && pathKeys.length > 3) {\n closed = true;\n break;\n }\n }\n\n if (closed) {\n // 去重: 量化点映射到原始 pt,生成 Shape\n const pts = [];\n pathKeys.forEach(k => {\n const n = nodes.get(k);\n if (n) pts.push({ x: n.pt.x, y: n.pt.y });\n });\n // 去掉首尾重复点\n if (pts.length > 1 && Math.hypot(pts[0].x - pts[pts.length - 1].x, pts[0].y - pts[pts.length - 1].y) < 1e-6) {\n pts.pop();\n }\n if (pts.length >= 3) {\n const shape = new THREE.Shape();\n shape.moveTo(pts[0].x, pts[0].y);\n for (let i = 1; i < pts.length; i++) {\n shape.lineTo(pts[i].x, pts[i].y);\n }\n shape.closePath();\n loops.push(shape);\n }\n }\n }\n\n return loops;\n }\n\n // 根据线框生成外接矩形兜底面(修复堆栈溢出:使用循环而不是展开运算符)\n buildBBoxShapeFromStrokes(segments) {\n if (!segments || segments.length === 0) return null;\n \n // 使用循环计算最大最小值,避免堆栈溢出\n let minX = Infinity, maxX = -Infinity;\n let minY = Infinity, maxY = -Infinity;\n \n for (let i = 0; i < segments.length; i++) {\n const seg = segments[i];\n if (seg.start.x < minX) minX = seg.start.x;\n if (seg.start.x > maxX) maxX = seg.start.x;\n if (seg.start.y < minY) minY = seg.start.y;\n if (seg.start.y > maxY) maxY = seg.start.y;\n if (seg.end.x < minX) minX = seg.end.x;\n if (seg.end.x > maxX) maxX = seg.end.x;\n if (seg.end.y < minY) minY = seg.end.y;\n if (seg.end.y > maxY) maxY = seg.end.y;\n }\n \n if (!isFinite(minX) || !isFinite(maxX) || !isFinite(minY) || !isFinite(maxY)) return null;\n const shape = new THREE.Shape();\n shape.moveTo(minX, minY);\n shape.lineTo(maxX, minY);\n shape.lineTo(maxX, maxY);\n shape.lineTo(minX, maxY);\n shape.closePath();\n return shape;\n }\n}"],"mappings":"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","names":["THREE","JSZip","referenceBbox","refSize","refArea","forcedCount","bbox","size","shape"]}
1
+ {"version":3,"sources":["../src/components/jetPaveGerberViewer/src/viewer-src/3dPage/js/main.js","../src/components/jetPaveGerberViewer/src/viewer-src/3dPage/js/gerber-parser-direct.js"],"sourcesContent":["import * as THREE from 'three';\nimport { OrbitControls } from 'three/addons/controls/OrbitControls.js';\nimport JSZip from 'jszip';\nimport earcut from 'earcut';\nimport { GerberOutlineParser } from './gerber-parser-direct.js';\nimport { GerberParser } from './gerber-parser.js';\nimport { extractRar } from '../../common/archiveExtractor.js';\nimport { parse, plot, renderSVG } from 'web-gerber';\nimport { parseUrlId, parseUrlFileUrl, fetchFileById, fetchFileByUrl } from '../../common/gerber-common.js';\n\n// 调试模式开关 - 设为 false 可禁用所有调试日志,提升性能\nconst DEBUG_MODE = true;\nconst debugLog = DEBUG_MODE ? console.log.bind(console) : () => {};\nconst debugWarn = DEBUG_MODE ? console.warn.bind(console) : () => {};\n\n/**\n * 将线段拼接成闭合形状(优化版)\n * 使用链式拼接算法,更适合异形轮廓的拼接\n * 优化点:1.使用数值key替代字符串 2.使用平方距离避免sqrt 3.使用双端队列避免unshift\n * @param {Array<{start:{x,y}, end:{x,y}}>} segments 线段数组\n * @returns {Array<THREE.Shape>} 形状数组\n */\nfunction stitchSegmentsToShapes(segments) {\n if (!segments || segments.length === 0) return [];\n \n const startTime = performance.now();\n \n // 🎯 第一步:线段去重(使用数值key优化)\n const PRECISION = 10000; // 0.0001mm 精度\n const seen = new Set();\n const uniqueSegments = [];\n \n for (let i = 0; i < segments.length; i++) {\n const seg = segments[i];\n // 使用有序坐标生成唯一key,避免正反向重复\n const sx = Math.round(seg.start.x * PRECISION);\n const sy = Math.round(seg.start.y * PRECISION);\n const ex = Math.round(seg.end.x * PRECISION);\n const ey = Math.round(seg.end.y * PRECISION);\n \n // 确保key有序(小的在前)\n let key;\n if (sx < ex || (sx === ex && sy < ey)) {\n key = `${sx},${sy}|${ex},${ey}`;\n } else {\n key = `${ex},${ey}|${sx},${sy}`;\n }\n \n if (!seen.has(key)) {\n seen.add(key);\n uniqueSegments.push(seg);\n }\n }\n \n console.log(`[stitchSegmentsToShapes] 线段去重: ${segments.length} -> ${uniqueSegments.length}`);\n \n if (uniqueSegments.length === 0) return [];\n \n // 早期退出:线段过多时跳过拼接\n const MAX_SEGMENTS = 150000;\n if (uniqueSegments.length > MAX_SEGMENTS) {\n console.warn(`[stitchSegmentsToShapes] ⚠️ 线段过多 (${uniqueSegments.length} > ${MAX_SEGMENTS}),跳过拼接`);\n return [];\n }\n \n // 计算容差和边界(单次遍历)\n let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;\n const n = uniqueSegments.length;\n for (let i = 0; i < n; i++) {\n const seg = uniqueSegments[i];\n const s = seg.start, e = seg.end;\n if (s.x < minX) minX = s.x;\n if (s.x > maxX) maxX = s.x;\n if (e.x < minX) minX = e.x;\n if (e.x > maxX) maxX = e.x;\n if (s.y < minY) minY = s.y;\n if (s.y > maxY) maxY = s.y;\n if (e.y < minY) minY = e.y;\n if (e.y > maxY) maxY = e.y;\n }\n \n const boardSize = Math.max(maxX - minX, maxY - minY);\n const TOLERANCE = boardSize > 100 ? 0.5 : boardSize > 50 ? 0.25 : 0.1;\n const TOLERANCE_SQ = TOLERANCE * TOLERANCE; // 平方容差,避免sqrt\n \n // 构建空间网格(使用数值key)\n const cellSize = TOLERANCE;\n const invCellSize = 1 / cellSize;\n const grid = new Map();\n \n // 创建pool items并添加到网格\n const poolItems = new Array(n);\n for (let i = 0; i < n; i++) {\n const seg = uniqueSegments[i];\n const item = { seg, used: false, idx: i };\n poolItems[i] = item;\n \n // 使用整数key\n const cx1 = Math.floor(seg.start.x * invCellSize);\n const cy1 = Math.floor(seg.start.y * invCellSize);\n const k1 = (cx1 << 16) ^ cy1; // 简单hash\n \n if (!grid.has(k1)) grid.set(k1, []);\n grid.get(k1).push(item);\n \n const cx2 = Math.floor(seg.end.x * invCellSize);\n const cy2 = Math.floor(seg.end.y * invCellSize);\n const k2 = (cx2 << 16) ^ cy2;\n \n if (k1 !== k2) {\n if (!grid.has(k2)) grid.set(k2, []);\n grid.get(k2).push(item);\n }\n }\n \n // 平方距离(避免sqrt)\n const distSq = (p1, p2) => {\n const dx = p1.x - p2.x;\n const dy = p1.y - p2.y;\n return dx * dx + dy * dy;\n };\n \n // 获取候选线段(优化:减少临时对象,预计算keys)\n const getCandidates = (x, y) => {\n const cx = Math.floor(x * invCellSize);\n const cy = Math.floor(y * invCellSize);\n const results = [];\n \n // 展开嵌套循环,减少迭代开销\n for (let dy = -1; dy <= 1; dy++) {\n const ccy = cy + dy;\n for (let dx = -1; dx <= 1; dx++) {\n const k = ((cx + dx) << 16) ^ ccy;\n const list = grid.get(k);\n if (list) {\n for (let i = 0, len = list.length; i < len; i++) {\n const item = list[i];\n if (!item.used) results.push(item);\n }\n }\n }\n }\n return results;\n };\n \n const chains = [];\n \n // 拼线(使用双端队列避免unshift)\n for (let startIdx = 0; startIdx < n; startIdx++) {\n const startItem = poolItems[startIdx];\n if (startItem.used) continue;\n \n startItem.used = true;\n \n // 使用两个数组模拟双端队列:front存反向元素,back存正向元素\n const front = []; // 反向添加的点(最后需要reverse)\n const back = [startItem.seg.start, startItem.seg.end]; // 正向添加的点\n \n let tail = startItem.seg.end;\n let head = startItem.seg.start;\n \n // 向后搜索(添加到back,内联优化)\n let finding = true;\n let tx = tail.x, ty = tail.y; // 缓存坐标\n while (finding) {\n finding = false;\n const candidates = getCandidates(tx, ty);\n \n let bestNext = null;\n let minDstSq = TOLERANCE_SQ;\n let isReverse = false;\n \n for (let i = 0, len = candidates.length; i < len; i++) {\n const item = candidates[i];\n const seg = item.seg;\n \n // 内联距离计算\n let dx = seg.start.x - tx;\n let dy = seg.start.y - ty;\n let d1 = dx * dx + dy * dy;\n if (d1 < minDstSq) {\n minDstSq = d1;\n bestNext = item;\n isReverse = false;\n }\n \n dx = seg.end.x - tx;\n dy = seg.end.y - ty;\n let d2 = dx * dx + dy * dy;\n if (d2 < minDstSq) {\n minDstSq = d2;\n bestNext = item;\n isReverse = true;\n }\n }\n \n if (bestNext) {\n bestNext.used = true;\n if (isReverse) {\n tail = bestNext.seg.start;\n tx = tail.x;\n ty = tail.y;\n back.push(tail);\n } else {\n tail = bestNext.seg.end;\n tx = tail.x;\n ty = tail.y;\n back.push(tail);\n }\n finding = true;\n }\n }\n \n // 向前搜索(添加到front,最后reverse,内联优化)\n finding = true;\n let hx = head.x, hy = head.y; // 缓存坐标\n while (finding) {\n finding = false;\n const candidates = getCandidates(hx, hy);\n \n let bestPrev = null;\n let minDstSq = TOLERANCE_SQ;\n let isReverse = false;\n \n for (let i = 0, len = candidates.length; i < len; i++) {\n const item = candidates[i];\n const seg = item.seg;\n \n // 内联距离计算\n let dx = seg.end.x - hx;\n let dy = seg.end.y - hy;\n let d1 = dx * dx + dy * dy;\n if (d1 < minDstSq) {\n minDstSq = d1;\n bestPrev = item;\n isReverse = false;\n }\n \n dx = seg.start.x - hx;\n dy = seg.start.y - hy;\n let d2 = dx * dx + dy * dy;\n if (d2 < minDstSq) {\n minDstSq = d2;\n bestPrev = item;\n isReverse = true;\n }\n }\n \n if (bestPrev) {\n bestPrev.used = true;\n if (isReverse) {\n head = bestPrev.seg.end;\n hx = head.x;\n hy = head.y;\n front.push(head);\n } else {\n head = bestPrev.seg.start;\n hx = head.x;\n hy = head.y;\n front.push(head);\n }\n finding = true;\n }\n }\n \n // 合并front(需要reverse)和back\n const chain = front.length > 0 ? front.reverse().concat(back) : back;\n chains.push(chain);\n }\n \n // 将链转换为 THREE.Shape\n const shapes = [];\n for (let c = 0; c < chains.length; c++) {\n const chain = chains[c];\n if (chain.length < 3) continue;\n \n // 检查闭合性(使用平方距离)\n const first = chain[0];\n const last = chain[chain.length - 1];\n const gapSq = distSq(first, last);\n const gap = Math.sqrt(gapSq);\n \n let forcedClose = false;\n if (gap > 10.0) forcedClose = true;\n if (gap > 1000.0) continue; // 间隙过大,放弃\n \n // 创建 THREE.Shape\n const shape = new THREE.Shape();\n shape.moveTo(chain[0].x, chain[0].y);\n for (let i = 1; i < chain.length; i++) {\n shape.lineTo(chain[i].x, chain[i].y);\n }\n if (gap > 0.001) {\n shape.lineTo(first.x, first.y);\n }\n shape.closePath();\n \n shape.userData = { forcedClose };\n shapes.push(shape);\n }\n \n const elapsed = performance.now() - startTime;\n console.log(`[stitchSegmentsToShapes] 拼接完成: ${shapes.length} 个形状,耗时 ${elapsed.toFixed(1)}ms`);\n \n return shapes;\n}\n\n// Constants\nconst COLORS = {\n OUTLINE: 0x1C590B, // 基材 (用户指定: #1C590B)\n OUTLINE_EDGE: 0x000000, // 边框线(黑色)\n COPPER: 0x40721E, // 线路 (用户指定: #40721E)\n GOLD: 0xD4AF37, // 焊盘 (金色 Gold)\n DRILL: 0x000000, // 钻孔 (黑色 Black)\n SILKSCREEN: 0xeeeeee, // 丝印 (白色 White)\n SOLDER_MASK: 0x1C590B, // 阻焊 (同基材)\n PASTE: 0x999999 // 锡膏 (灰色 Gray)\n};\n\n// Files to ignore (do NOT render, do NOT let them affect bbox/board size)\n// NOTE: compared in a case-insensitive way against the basename (no path).\nconst IGNORED_GERBER_BASENAMES_UPPER = new Set([\n 'PZT_Core-v1.0.GM15',\n 'PZT_Core-v1.0.GM2',\n 'PZT_Core-v1.0.GM3',\n 'PZT_Core-v1.0.GM4',\n 'PZT_Core-v1.0.GM5',\n 'PZT_Core-v1.0.GM6',\n 'PZT_Core-v1.0.GM8',\n 'PZT_Core-v1.0.GM13'\n].map(s => s.toUpperCase()));\n\n// Fixed Dimensions (in mm)\nconst FIXED_DIMENSIONS = {\n // BOARD_THICKNESS will be adaptive\n COPPER_HEIGHT: 0.035, \n SILKSCREEN_HEIGHT: 0.02, \n SOLDER_MASK_HEIGHT: 0.01, \n DRILL_PROTRUSION: 0.005 \n};\n\n// 初始厚度(会被自适应逻辑覆盖)\nlet BOARD_THICKNESS = 1.6; // mm\n\nclass Viewer3D {\n constructor() {\n this.scene = null;\n this.camera = null;\n this.renderer = null;\n this.controls = null;\n this.baseGroup = new THREE.Group();\n this.materialCache = new Map();\n \n this.initThree();\n this.initEvents();\n this.checkUrlParams();\n }\n\n initThree() {\n this.scene = new THREE.Scene();\n this.scene.background = new THREE.Color(0x000000);\n\n /** React 壳内 #viewer3d-canvas-host 存在时按容器尺寸渲染,避免 canvas 挂到 body 导致整页高度 > 100vh */\n const getViewportSize = () => {\n const host = document.getElementById('viewer3d-canvas-host');\n if (host && host.clientWidth > 0 && host.clientHeight > 0) {\n return { w: host.clientWidth, h: host.clientHeight };\n }\n return { w: window.innerWidth, h: window.innerHeight };\n };\n\n const { w: vw, h: vh } = getViewportSize();\n const safeW = Math.max(vw, 1);\n const safeH = Math.max(vh, 1);\n\n this.camera = new THREE.PerspectiveCamera(45, safeW / safeH, 0.1, 2000);\n this.camera.position.set(0, 0, 30);\n\n this.renderer = new THREE.WebGLRenderer({ antialias: true, logarithmicDepthBuffer: true });\n const pr = Math.min(window.devicePixelRatio || 1, 2);\n this.renderer.setPixelRatio(pr);\n this.renderer.setSize(safeW, safeH);\n\n const canvasHost = document.getElementById('viewer3d-canvas-host');\n (canvasHost || document.body).appendChild(this.renderer.domElement);\n\n this.controls = new OrbitControls(this.camera, this.renderer.domElement);\n this.controls.enableDamping = true;\n\n // Lights\n const ambientLight = new THREE.AmbientLight(0xffffff, 1.8); \n this.scene.add(ambientLight);\n\n const dirLight = new THREE.DirectionalLight(0xffffff, 1.2);\n dirLight.position.set(50, 50, 100); \n this.scene.add(dirLight);\n\n const fillLight = new THREE.DirectionalLight(0xffffff, 1.0);\n fillLight.position.set(-50, -50, 100); \n this.scene.add(fillLight);\n\n const backLight = new THREE.DirectionalLight(0xffffff, 0.8);\n backLight.position.set(0, 0, -100); \n this.scene.add(backLight);\n\n this.scene.add(this.baseGroup);\n\n const applyResize = () => {\n const { w, h } = getViewportSize();\n const W = Math.max(w, 1);\n const H = Math.max(h, 1);\n this.camera.aspect = W / H;\n this.camera.updateProjectionMatrix();\n this.renderer.setSize(W, H);\n };\n\n window.addEventListener('resize', applyResize);\n if (canvasHost && typeof ResizeObserver !== 'undefined') {\n this._canvasHostResizeObserver = new ResizeObserver(() => applyResize());\n this._canvasHostResizeObserver.observe(canvasHost);\n }\n\n requestAnimationFrame(() => applyResize());\n\n this.animate();\n }\n\n animate() {\n requestAnimationFrame(() => this.animate());\n this.controls.update();\n this.renderer.render(this.scene, this.camera);\n }\n\n initEvents() {\n const fileInput = document.getElementById('file-input');\n fileInput.addEventListener('change', (e) => this.handleFileSelect(e));\n const baseUrl = import.meta.env.BASE_URL || '/';\n const buildPageUrl = (path) => `${baseUrl}${path.replace(/^\\/+/, '')}`;\n \n // 绑定关闭按钮,跳转回 2d 页面\n const closeBtn = document.getElementById('close-btn');\n if (closeBtn) {\n closeBtn.addEventListener('click', () => {\n const id = parseUrlId();\n if (id) {\n window.location.href = `${buildPageUrl('/2dPage')}?id=${encodeURIComponent(id)}`;\n return;\n }\n const url = parseUrlFileUrl();\n if (url) {\n window.location.href = `${buildPageUrl('/2dPage')}?url=${encodeURIComponent(url)}`;\n return;\n }\n window.location.href = buildPageUrl('/2dPage');\n });\n }\n }\n \n async checkUrlParams() { \n console.log('[性能] checkUrlParams 开始')\n const startTime = performance.now()\n \n // 使用公共函数从 URL 中提取 ID(支持 ?id=xx 和 ?object={\"id\":\"xx\"} 格式)\n const id = parseUrlId();\n const url = parseUrlFileUrl();\n \n if (id) {\n const loadingEl = document.getElementById('loading');\n if (loadingEl) {\n loadingEl.textContent = '正在处理中...';\n loadingEl.style.display = 'flex';\n }\n \n try {\n // 使用公共函数 fetchFileById 获取文件(已包含性能监控)\n console.log('[3D-new] 使用 fetchFileById 获取文件...')\n await fetchFileById(\n id,\n async (files) => {\n // 文件获取成功,处理文件\n console.log('[3D-new] 收到文件,开始处理...')\n await this.processFiles(files);\n \n // 渲染完成后隐藏 loading\n if (loadingEl) {\n loadingEl.style.display = 'none';\n }\n \n const endTime = performance.now()\n const totalTime = (endTime - startTime) / 1000\n console.log(`[性能] ========== checkUrlParams 完成,总耗时: ${totalTime.toFixed(2)}秒 ==========`)\n },\n (message, type) => {\n // 状态更新回调(可选)\n console.log(`[3D-new] 状态: ${message}`)\n }\n );\n } catch (error) {\n const endTime = performance.now()\n const totalTime = (endTime - startTime) / 1000\n console.error(`[错误] checkUrlParams 失败 (耗时: ${totalTime.toFixed(2)}秒):`, error)\n \n if (loadingEl) {\n loadingEl.style.display = 'none';\n }\n alert('获取文件失败: ' + error.message);\n }\n } else if (url) {\n const loadingEl = document.getElementById('loading');\n if (loadingEl) {\n loadingEl.textContent = '正在处理中...';\n loadingEl.style.display = 'flex';\n }\n\n try {\n console.log('[3D-new] 使用 fetchFileByUrl 获取文件...')\n await fetchFileByUrl(\n url,\n async (files) => {\n console.log('[3D-new] 收到文件,开始处理...')\n await this.processFiles(files);\n if (loadingEl) {\n loadingEl.style.display = 'none';\n }\n const endTime = performance.now()\n const totalTime = (endTime - startTime) / 1000\n console.log(`[性能] ========== checkUrlParams 完成,总耗时: ${totalTime.toFixed(2)}秒 ==========`)\n },\n (message, type) => {\n console.log(`[3D-new] 状态: ${message}`)\n }\n );\n } catch (error) {\n const endTime = performance.now()\n const totalTime = (endTime - startTime) / 1000\n console.error(`[错误] checkUrlParams 失败 (耗时: ${totalTime.toFixed(2)}秒):`, error)\n if (loadingEl) {\n loadingEl.style.display = 'none';\n }\n alert('获取文件失败: ' + error.message);\n }\n } else {\n console.log('[3D-new] URL 中没有 ID 参数')\n }\n }\n\n async handleFileSelect(event) {\n console.log('[性能] handleFileSelect 开始')\n const startTime = performance.now()\n \n const files = event.target.files;\n if (!files || files.length === 0) return;\n document.getElementById('loading').style.display = 'flex';\n try {\n await this.processFiles(files);\n \n const endTime = performance.now()\n const totalTime = (endTime - startTime) / 1000\n console.log(`[性能] ========== 文件处理完成,总耗时: ${totalTime.toFixed(2)}秒 ==========`)\n } catch (e) {\n const endTime = performance.now()\n const totalTime = (endTime - startTime) / 1000\n console.error(`[错误] 文件处理失败 (耗时: ${totalTime.toFixed(2)}秒):`, e);\n alert('处理文件时出错: ' + e.message);\n } finally {\n document.getElementById('loading').style.display = 'none';\n event.target.value = '';\n }\n }\n\n async processFiles(fileList) {\n console.log(`[性能] processFiles 开始,文件数: ${fileList.length}`)\n const startTimeTotal = performance.now()\n \n // 🚀 首先清空上次渲染的场景和状态\n this.clearScene();\n this.outlineBbox = null; // 重置轮廓边界框\n \n // Hide scene during rendering to avoid flickering\n if (this.renderer && this.renderer.domElement) {\n this.renderer.domElement.style.visibility = 'hidden';\n }\n \n // 1. Extract Files\n console.log('[性能] 开始解压文件...')\n const startTimeExtract = performance.now()\n const gerberFiles = [];\n for (const file of fileList) {\n const ext = file.name.split('.').pop().toLowerCase();\n if (ext === 'zip') {\n console.log(`[性能] 解压 ZIP: ${file.name}`)\n const startTimeZip = performance.now()\n const zip = await JSZip.loadAsync(file);\n for (const filename in zip.files) {\n if (zip.files[filename].dir) continue;\n const content = await zip.files[filename].async('blob');\n gerberFiles.push(new File([content], filename));\n }\n const endTimeZip = performance.now()\n console.log(`[性能] ZIP 解压完成,耗时: ${(endTimeZip - startTimeZip).toFixed(2)}ms`)\n } else if (ext === 'rar') {\n console.log(`[性能] 解压 RAR: ${file.name}`)\n const startTimeRar = performance.now()\n const extracted = await extractRar(file);\n const endTimeRar = performance.now()\n console.log(`[性能] RAR 解压完成,耗时: ${(endTimeRar - startTimeRar).toFixed(2)}ms`)\n gerberFiles.push(...extracted);\n } else {\n gerberFiles.push(file);\n }\n }\n const endTimeExtract = performance.now()\n console.log(`[性能] 文件解压总耗时: ${(endTimeExtract - startTimeExtract).toFixed(2)}ms, 解压后文件数: ${gerberFiles.length}`)\n\n // 1.1 Filter ignored files (so they don't get classified/rendered and don't affect bbox)\n if (IGNORED_GERBER_BASENAMES_UPPER.size > 0 && gerberFiles.length > 0) {\n const kept = [];\n const ignored = [];\n for (const f of gerberFiles) {\n const base = (f.name.split(/[/\\\\]/).pop() || '').toUpperCase();\n if (IGNORED_GERBER_BASENAMES_UPPER.has(base)) {\n ignored.push(f.name);\n } else {\n kept.push(f);\n }\n }\n if (ignored.length > 0) {\n debugWarn(`[3D-new] 已忽略 ${ignored.length} 个文件(不参与渲染/不影响基材尺寸):`, ignored);\n }\n gerberFiles.length = 0;\n gerberFiles.push(...kept);\n }\n \n // Debug: Log all extracted files\n // debugLog(`[File Extraction] 提取到的所有文件 (${gerberFiles.length} 个):`, gerberFiles.map(f => f.name));\n\n console.log(`[3D-new] 开始解析文件,共 ${gerberFiles.length} 个文件:`, gerberFiles.map(f => f.name));\n \n console.log('[性能] 开始文件分类...')\n const startTimeClassify = performance.now()\n \n // 2. Identify Layers using the same logic as 2d-direct\n // 2.1 预处理 .pho 前缀分组:用于判定\"最小编号为上层,其余为下层\"\n const buildPhoGroups = (files) => {\n const groups = new Map(); // prefix -> {min:number}\n const add = (prefix, num) => {\n if (!groups.has(prefix)) {\n groups.set(prefix, { min: num });\n } else {\n groups.get(prefix).min = Math.min(groups.get(prefix).min, num);\n }\n };\n files.forEach(f => {\n const nameOnly = f.name.split(/[/\\\\]/).pop() || '';\n const ext = '.' + nameOnly.split('.').pop().toLowerCase();\n if (ext !== '.pho') return;\n const upper = nameOnly.toUpperCase();\n let prefix = null;\n let num = 0;\n if (upper.startsWith('SST')) {\n prefix = 'sst';\n const m = upper.match(/^SST(\\d+)/);\n num = m ? parseInt(m[1], 10) : 0;\n } else if (upper.startsWith('SMD')) {\n prefix = 'smd';\n const m = upper.match(/^SMD(\\d+)/);\n num = m ? parseInt(m[1], 10) : 0;\n } else if (upper.startsWith('SM')) {\n prefix = 'sm';\n const m = upper.match(/^SM(\\d+)/);\n num = m ? parseInt(m[1], 10) : 0;\n } else if (upper.startsWith('ART')) {\n prefix = 'art';\n const m = upper.match(/^ART(\\d+)/);\n num = m ? parseInt(m[1], 10) : 0;\n }\n if (prefix) add(prefix, num);\n });\n return groups;\n };\n const phoGroups = buildPhoGroups(gerberFiles);\n\n const getLayerType = (fileName) => {\n const fileNameOnly = fileName.split(/[/\\\\]/).pop();\n const fileExtension = '.' + fileNameOnly.split('.').pop().toUpperCase();\n const fileNameUpper = fileNameOnly.toUpperCase();\n const nameLower = fileNameOnly.toLowerCase();\n \n // .gbr 文件:根据文件名模式识别图层类型(必须在通用后缀匹配之前)\n if (fileExtension === '.GBR') {\n // 先检查文件名(去掉扩展名)是否直接是标准图层类型(如 GKO.gbr, GTL.gbr 等)\n const nameWithoutExt = fileNameOnly.substring(0, fileNameOnly.lastIndexOf('.')).toUpperCase();\n if (nameWithoutExt === 'GKO' || nameWithoutExt === 'GTL' || nameWithoutExt === 'GTO' || \n nameWithoutExt === 'GTS' || nameWithoutExt === 'GBL' || nameWithoutExt === 'GBS' || \n nameWithoutExt === 'GBP' || nameWithoutExt === 'GBO' || nameWithoutExt === 'GTP') {\n return nameWithoutExt;\n }\n \n // BoardOutline / Outline -> GKO (优先匹配)\n if (nameLower.includes('outline') || nameLower.includes('boardoutline')) {\n return 'GKO';\n }\n \n // TopMask / TopSolder / SolderTop -> GTS\n if (nameLower.includes('topmask') || nameLower.includes('topsolder') || \n nameLower.includes('soldertop') || nameLower.includes('maskstop')) {\n return 'GTS';\n }\n \n // BottomMask / BottomSolder / SolderBottom -> GBS\n if (nameLower.includes('bottommask') || nameLower.includes('bottomsolder') || \n nameLower.includes('solderbottom') || nameLower.includes('masksbot')) {\n return 'GBS';\n }\n \n // TopSilk / SilkTop / TopLegend -> GTO\n if (nameLower.includes('topsilk') || nameLower.includes('silktop') || \n nameLower.includes('toplegend') || nameLower.includes('legendtop')) {\n return 'GTO';\n }\n \n // BottomSilk / SilkBottom / BottomLegend -> GBO\n if (nameLower.includes('bottomsilk') || nameLower.includes('silkbottom') || \n nameLower.includes('bottomlegend') || nameLower.includes('legendbottom')) {\n return 'GBO';\n }\n \n // TopPaste / PasteTop -> GTP\n if (nameLower.includes('toppaste') || nameLower.includes('pastetop')) {\n return 'GTP';\n }\n \n // BottomPaste / PasteBottom -> GBP\n if (nameLower.includes('bottompaste') || nameLower.includes('pastebottom')) {\n return 'GBP';\n }\n \n // L1 / Layer1 / Top (铜层) -> GTL\n if (nameLower.includes('l1') || nameLower.includes('layer1') || \n (nameLower.includes('top') && !nameLower.includes('paste') && !nameLower.includes('mask') && !nameLower.includes('silk'))) {\n return 'GTL';\n }\n \n // L4 / Layer4 / Bottom (铜层) -> GBL\n if (nameLower.includes('l4') || nameLower.includes('layer4') || \n (nameLower.includes('bottom') && !nameLower.includes('paste') && !nameLower.includes('mask') && !nameLower.includes('silk'))) {\n return 'GBL';\n }\n \n // legend_Top / Legend_Top -> GTO (保留兼容性)\n if (nameLower.includes('legend_top') || \n (nameLower.includes('legend') && nameLower.includes('top') && !nameLower.includes('signal'))) {\n return 'GTO';\n }\n \n // Paste_Top -> GTP (保留兼容性)\n if (nameLower.includes('paste_top')) return 'GTP';\n \n // Paste_Bot -> GBP (保留兼容性)\n if (nameLower.includes('paste_bot')) return 'GBP';\n \n // soldermask_Top / Soldermask_Top -> GTS (保留兼容性)\n if (nameLower.includes('soldermask_top')) return 'GTS';\n \n // soldermask_Bot / Soldermask_Bot -> GBS (保留兼容性)\n if (nameLower.includes('soldermask_bot')) return 'GBS';\n \n // signal_1 -> SIG2, signal_2 -> SIG3, 依次类推 (包括 Copper_Signal_1, Copper_Signal_2)\n // 注意:这个匹配必须在 signal_Top/Bot 之前,避免误匹配\n const signalMatch = nameLower.match(/(?:copper_)?signal[_\\s](\\d+)/i);\n if (signalMatch) {\n const number = parseInt(signalMatch[1], 10);\n const displayNumber = number + 1;\n return 'SIG' + displayNumber;\n }\n \n // signal_Top -> GTL (包括 Copper_Signal_Top)\n if (nameLower.includes('signal_top') || nameLower.includes('copper_signal_top')) return 'GTL';\n \n // signal_Bot -> GBL (包括 Copper_Signal_Bot)\n if (nameLower.includes('signal_bot') || nameLower.includes('copper_signal_bot')) return 'GBL';\n \n // Profile -> GKO (保留兼容性)\n if (fileNameUpper.includes('PROFILE')) return 'GKO';\n \n // WX -> GKO (轮廓层,常见于 CAM350 等工具)\n if (nameWithoutExt === 'WX' || fileNameUpper.includes('WX')) return 'GKO';\n \n // L2 / Layer2 / Inner1 -> SIG2 (内层)\n if (nameLower.includes('l2') || nameLower.includes('layer2') || nameLower.includes('inner 1') || nameLower.includes('inner1')) {\n return 'SIG2';\n }\n \n // L3 / Layer3 / Inner2 -> SIG3 (内层)\n if (nameLower.includes('l3') || nameLower.includes('layer3') || nameLower.includes('inner 2') || nameLower.includes('inner2')) {\n return 'SIG3';\n }\n \n // ZH-TOP -> GTS (保留兼容性)\n if (fileNameUpper.startsWith('ZH-TOP') || fileNameUpper.includes('ZH-TOP')) return 'GTS';\n // ZH-BOT -> GBS (保留兼容性)\n if (fileNameUpper.startsWith('ZH-BOT') || fileNameUpper.includes('ZH-BOT')) return 'GBS';\n // XL-TOP -> GTL (保留兼容性)\n if (fileNameUpper.startsWith('XL-TOP') || fileNameUpper.includes('XL-TOP')) return 'GTL';\n // XL-BOT -> GBL (保留兼容性)\n if (fileNameUpper.startsWith('XL-BOT') || fileNameUpper.includes('XL-BOT')) return 'GBL';\n\n // KiCad 命名(与 2D 一致):Edge_Cuts / F.Cu / B.Cu / InN.Cu\n if (/EDGE[._-]CUTS/i.test(fileNameUpper)) return 'GKO';\n if (/F[._-]CU\\b/i.test(fileNameUpper)) return 'GTL';\n if (/B[._-]CU\\b/i.test(fileNameUpper)) return 'GBL';\n const inCuGbr = fileNameUpper.match(/IN(\\d+)[._-]CU/i);\n if (inCuGbr) return 'SIG' + (parseInt(inCuGbr[1], 10) + 1);\n \n // 检查是否包含特定关键词,如果包含则显示关键词部分\n const keywords = ['_Drawing', '_Drillmap', '_NPTH', '_Pads', '_PTH'];\n for (const keyword of keywords) {\n if (fileNameOnly.includes(keyword)) {\n // 提取关键词及其后面的部分(包含扩展名)\n const keywordIndex = fileNameOnly.indexOf(keyword);\n return fileNameOnly.substring(keywordIndex);\n }\n }\n \n // 其他 .gbr 文件显示完整文件名(包含扩展名)\n return fileNameOnly;\n }\n \n // .pho 文件:根据文件名前缀和数字大小识别图层类型\n if (fileExtension === '.PHO') {\n if (fileNameUpper.startsWith('SST')) return 'GTO';\n const pickByGroup = (prefix, topType, botType, defaultType = null) => {\n const m = fileNameUpper.match(new RegExp(`^${prefix}(\\\\d+)`));\n const num = m ? parseInt(m[1], 10) : 0;\n const g = phoGroups.get(prefix.toLowerCase());\n if (g) {\n return num === g.min ? topType : botType;\n }\n return defaultType || topType;\n };\n if (fileNameUpper.startsWith('SMD')) {\n return pickByGroup('SMD', 'GTP', 'GBP', 'GTP');\n }\n if (fileNameUpper.startsWith('SM')) {\n return pickByGroup('SM', 'GTS', 'GBS', 'GTS');\n }\n if (fileNameUpper.startsWith('ART')) {\n return pickByGroup('ART', 'GTL', 'GBL', 'GTL');\n }\n if (fileNameUpper.startsWith('SSB')) return 'GBO';\n }\n \n // 检查文件名后缀模式\n if (fileNameUpper.endsWith('_SST') || fileNameUpper.includes('_SST.')) return 'GTO';\n if (fileNameUpper.endsWith('_PMT') || fileNameUpper.includes('_PMT.')) return 'GTP';\n if (fileNameUpper.endsWith('_SMT') || fileNameUpper.includes('_SMT.')) return 'GTS';\n if (fileNameUpper.endsWith('_TOP') || fileNameUpper.includes('_TOP.')) return 'GTL';\n if (fileNameUpper.endsWith('_SMB') || fileNameUpper.includes('_SMB.')) return 'GBS';\n if (fileNameUpper.endsWith('_PMB') || fileNameUpper.includes('_PMB.')) return 'GBP';\n if (fileNameUpper.endsWith('_SSB') || fileNameUpper.includes('_SSB.')) return 'GBO';\n if (fileNameUpper.includes('OUTLINE')) return 'GKO';\n \n // _INT+数字\n if (/.*_INT\\d+$/i.test(fileNameUpper) || /.*_INT\\d+\\./i.test(fileNameUpper)) return fileNameOnly;\n \n // 标准扩展名\n if (fileExtension === '.GTO') return 'GTO';\n if (fileExtension === '.GTP') return 'GTP';\n if (fileExtension === '.GTS') return 'GTS';\n if (fileExtension === '.GTL') return 'GTL';\n if (fileExtension === '.GBL') return 'GBL';\n if (fileExtension === '.GBS') return 'GBS';\n if (fileExtension === '.GBP') return 'GBP';\n if (fileExtension === '.GBO') return 'GBO';\n if (fileExtension === '.GKO' || fileNameUpper.includes('PROFILE')) return 'GKO';\n // GM+数字:只有 GM1, GM2 可以作为轮廓层,GM3 及以上不渲染\n if (fileExtension === '.GM1' || fileExtension === '.GM2') return 'GKO';\n if (fileExtension === '.GM' || fileExtension === '.GML' || fileExtension === '.OUTLINE' || fileExtension === '.OUT' || fileExtension === '.OLN') return 'GKO';\n \n // 检查扩展名\n if (fileExtension === '.D' || fileExtension === '.DRL' || fileExtension === '.DRI') {\n // 特殊命名:np.drl(非金属化孔)与 p.drl(金属化孔)\n if (fileNameUpper === 'NP.DRL' || fileNameUpper === 'NP.D') return 'DRL2';\n if (fileNameUpper === 'P.DRL' || fileNameUpper === 'P.D') return 'DRL';\n return 'DRL';\n }\n if (fileExtension === '.ROU') return 'rout';\n \n // CAM350 等软件导出的扩展名映射\n if (fileExtension === '.BOT') return 'GBL'; // 底层铜\n if (fileExtension === '.TOP') return 'GTL'; // 顶层铜\n if (fileExtension === '.SOB') return 'GBS'; // 底层阻焊 (Solder mask Bottom)\n if (fileExtension === '.SOT') return 'GTS'; // 顶层阻焊 (Solder mask Top)\n if (fileExtension === '.SST') return 'GTO'; // 顶层丝印 (Silkscreen Top)\n if (fileExtension === '.SSB') return 'GBO'; // 底层丝印 (Silkscreen Bottom)\n if (fileExtension === '.SMT') return 'GTS'; // 顶层阻焊 (Solder Mask Top)\n if (fileExtension === '.SMB') return 'GBS'; // 底层阻焊 (Solder Mask Bottom)\n if (fileExtension === '.PMT') return 'GTP'; // 顶层锡膏 (Paste Mask Top)\n if (fileExtension === '.PMB') return 'GBP'; // 底层锡膏 (Paste Mask Bottom)\n // CAM350: .SER 通常是丝印(Top),统一按 GTO 渲染\n if (fileExtension === '.SER') return 'GTO'; // 丝印层 (Silkscreen Top)\n if (fileExtension === '.ART') {\n // .art 文件:按文件名(不含扩展名)映射为标准层类型\n // SST -> GTO, SMT -> GTS, Top -> GTL, Bot -> GBL, SMB -> GBS, SSB -> GBO, OUT -> GKO\n // LAY2/LAY3/... -> 中间层(SIG2, SIG3, ...)\n const dot = fileNameOnly.lastIndexOf('.');\n const stemUpper = (dot > 0 ? fileNameOnly.substring(0, dot) : fileNameOnly).toUpperCase();\n if (stemUpper === 'SST') return 'GTO';\n if (stemUpper === 'SMT') return 'GTS';\n if (stemUpper === 'TOP') return 'GTL';\n if (stemUpper === 'BOT') return 'GBL';\n if (stemUpper === 'SMB') return 'GBS';\n if (stemUpper === 'SSB') return 'GBO';\n if (stemUpper === 'OUT') return 'GKO';\n // LAY2, LAY3, ... -> SIG2, SIG3, ...(中间铜层)\n const layMatch = stemUpper.match(/^LAY(\\d+)$/);\n if (layMatch) {\n const layerNum = parseInt(layMatch[1], 10);\n return 'SIG' + layerNum;\n }\n // 其余 .art:保持文件名展示(但不强行映射为某个标准层)\n return fileNameOnly;\n }\n\n // KiCad/Protel:内层铜 .g1/.g2/.g3…(文件名常带 InN_Cu)\n const gExtMatch = fileExtension.match(/^\\.G(\\d+)$/i);\n if (gExtMatch) {\n const inCu = fileNameUpper.match(/IN(\\d+)[._-]CU/i);\n if (inCu) return 'SIG' + (parseInt(inCu[1], 10) + 1);\n const gn = parseInt(gExtMatch[1], 10);\n return 'SIG' + (gn + 1);\n }\n const gpExtMatch = fileExtension.match(/^\\.GP(\\d+)$/i);\n if (gpExtMatch) {\n return 'GP' + parseInt(gpExtMatch[1], 10);\n }\n \n return null;\n };\n \n // 分类文件\n const outlineFiles = [];\n const topCopperFiles = [];\n const bottomCopperFiles = [];\n const topMaskFiles = [];\n const bottomMaskFiles = [];\n const topPasteFiles = [];\n const bottomPasteFiles = [];\n const topSilkFiles = [];\n const bottomSilkFiles = [];\n const innerCopperFiles = [];\n \n for (const file of gerberFiles) {\n // 检查是否是 .pho 文件,如果是则跳过(pho文件会单独处理)\n const fileNameOnly = file.name.split(/[/\\\\]/).pop() || '';\n const fileExtension = '.' + fileNameOnly.split('.').pop().toUpperCase();\n if (fileExtension === '.PHO') {\n continue; // pho文件会通过 renderPhoFiles 单独处理\n }\n\n const layerType = getLayerType(file.name);\n if (layerType === 'GKO') {\n outlineFiles.push(file);\n } else if (layerType === 'GTL') {\n topCopperFiles.push(file);\n } else if (layerType === 'GBL') {\n bottomCopperFiles.push(file);\n } else if (layerType === 'GTS') {\n topMaskFiles.push(file);\n } else if (layerType === 'GBS') {\n bottomMaskFiles.push(file);\n } else if (layerType === 'GTP') {\n topPasteFiles.push(file);\n } else if (layerType === 'GBP') {\n bottomPasteFiles.push(file);\n } else if (layerType === 'GTO') {\n topSilkFiles.push(file);\n } else if (layerType === 'GBO') {\n bottomSilkFiles.push(file);\n } else if (layerType && /^SIG\\d+$/i.test(layerType)) {\n innerCopperFiles.push(file);\n }\n }\n \n // 降级策略:如果找不到标准轮廓层,尝试使用 GM2(GM3 及以上不渲染)\n if (outlineFiles.length === 0) {\n const fallbackFiles = gerberFiles.filter(f => {\n const name = f.name.toLowerCase();\n return name.endsWith('.gm2');\n });\n if (fallbackFiles.length > 0) {\n outlineFiles.push(...fallbackFiles);\n // debugLog('No GKO/GM1 found, falling back to:', fallbackFiles.map(f => f.name));\n }\n }\n\n // 2.2 轮廓层兜底选择:避免某个异常“轮廓/机械层”文件把基材 bbox 撑爆\n // 策略:\n // - 列出所有被识别为轮廓层(GKO)的文件及其 bbox\n // - 若存在参考层(优先铜层/丝印/阻焊),选择与参考 bbox 最匹配的轮廓文件\n // - 其余轮廓候选直接忽略(不参与基材尺寸计算)\n const pickBestOutlineFiles = async () => {\n if (!outlineFiles || outlineFiles.length <= 1) return { files: outlineFiles || [], refBbox: null };\n\n const baseNameUpper = (name) => (name.split(/[/\\\\]/).pop() || '').toUpperCase();\n const isExt = (nameUpper, extUpper) => nameUpper.endsWith(extUpper);\n const outlineCandidates = [...outlineFiles];\n\n // 选一个参考层 bbox(用于判断哪个轮廓是“真正的板外形”)\n const pickReferenceFile = () => {\n return (\n topCopperFiles[0] ||\n bottomCopperFiles[0] ||\n topSilkFiles[0] ||\n bottomSilkFiles[0] ||\n topMaskFiles[0] ||\n bottomMaskFiles[0] ||\n topPasteFiles[0] ||\n bottomPasteFiles[0] ||\n null\n );\n };\n\n const getReferenceBbox = async () => {\n const refFile = pickReferenceFile();\n if (!refFile) return null;\n try {\n const res = await GerberParser.parseFile(refFile, '#ffffff');\n if (!res || !res.data) return null;\n const bbox = this.calculateLayerBbox([res.data]);\n if (!bbox || bbox.isEmpty()) return null;\n let scale = 1.0;\n if (res.units === 'in' || res.units === 'inch') scale = 25.4;\n bbox.min.multiplyScalar(scale);\n bbox.max.multiplyScalar(scale);\n return { bbox, refFileName: refFile.name, scale, units: res.units };\n } catch (e) {\n return null;\n }\n };\n\n const computeOutlineBbox = async (file) => {\n const nameUpper = baseNameUpper(file.name);\n const parser = new GerberOutlineParser();\n const text = await file.text();\n const { shapes, strokes } = parser.parse(text);\n\n let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;\n let pointCount = 0;\n\n const pushXY = (x, y) => {\n if (!Number.isFinite(x) || !Number.isFinite(y)) return;\n if (x < minX) minX = x;\n if (x > maxX) maxX = x;\n if (y < minY) minY = y;\n if (y > maxY) maxY = y;\n pointCount++;\n };\n\n // Prefer curves endpoints (cheap) over getPoints (alloc-heavy)\n const consumeShape = (s) => {\n const curves = s?.curves || [];\n if (curves.length > 0) {\n for (const c of curves) {\n if (c?.isLineCurve) {\n const v1 = c.v1;\n const v2 = c.v2;\n if (v1) pushXY(v1.x, v1.y);\n if (v2) pushXY(v2.x, v2.y);\n } else {\n const p0 = c?.getPoint?.(0);\n const p1 = c?.getPoint?.(1);\n if (p0) pushXY(p0.x, p0.y);\n if (p1) pushXY(p1.x, p1.y);\n }\n }\n return;\n }\n // Fallback (rare)\n const pts = s?.getPoints?.() || [];\n for (const p of pts) pushXY(p.x, p.y);\n };\n\n if (shapes && shapes.length > 0) {\n for (const s of shapes) consumeShape(s);\n }\n\n if (pointCount === 0 && strokes && strokes.length > 0) {\n for (const seg of strokes) {\n pushXY(seg.start.x, seg.start.y);\n pushXY(seg.end.x, seg.end.y);\n }\n }\n\n const valid = Number.isFinite(minX) && Number.isFinite(maxX) && Number.isFinite(minY) && Number.isFinite(maxY) &&\n maxX > minX && maxY > minY;\n if (!valid) {\n return {\n file,\n name: file.name,\n nameUpper,\n valid: false,\n shapesCount: shapes?.length || 0,\n strokesCount: strokes?.length || 0\n };\n }\n\n const bbox = new THREE.Box3(\n new THREE.Vector3(minX, minY, 0),\n new THREE.Vector3(maxX, maxY, 0)\n );\n const size = bbox.getSize(new THREE.Vector3());\n const center = bbox.getCenter(new THREE.Vector3());\n const area = size.x * size.y;\n\n return {\n file,\n name: file.name,\n nameUpper,\n valid: true,\n bbox,\n size,\n center,\n area,\n shapesCount: shapes?.length || 0,\n strokesCount: strokes?.length || 0\n };\n };\n\n const ref = await getReferenceBbox();\n const infos = [];\n for (const f of outlineCandidates) {\n try {\n infos.push(await computeOutlineBbox(f));\n } catch (e) {\n infos.push({ file: f, name: f.name, nameUpper: baseNameUpper(f.name), valid: false });\n }\n }\n\n // 打印候选(帮助定位到底哪个文件把 bbox 撑大)\n try {\n const logList = infos.map(i => {\n if (!i.valid) {\n return { file: i.name, valid: false, shapes: i.shapesCount || 0, strokes: i.strokesCount || 0 };\n }\n return {\n file: i.name,\n valid: true,\n w: Number(i.size.x.toFixed(2)),\n h: Number(i.size.y.toFixed(2)),\n area: Number(i.area.toFixed(2)),\n cx: Number(i.center.x.toFixed(2)),\n cy: Number(i.center.y.toFixed(2)),\n shapes: i.shapesCount || 0,\n strokes: i.strokesCount || 0\n };\n });\n debugWarn('[3D-new][OutlineCandidates] 轮廓候选文件 bbox 列表:', logList);\n if (ref?.bbox) {\n const refSize = ref.bbox.getSize(new THREE.Vector3());\n const refCenter = ref.bbox.getCenter(new THREE.Vector3());\n debugWarn('[3D-new][OutlineCandidates] 参考层:', {\n file: ref.refFileName,\n units: ref.units,\n scale: ref.scale,\n w: Number(refSize.x.toFixed(2)),\n h: Number(refSize.y.toFixed(2)),\n cx: Number(refCenter.x.toFixed(2)),\n cy: Number(refCenter.y.toFixed(2))\n });\n }\n } catch (e) {\n // ignore log errors\n }\n\n const validInfos = infos.filter(i => i.valid);\n if (validInfos.length === 0) return { files: outlineFiles, refBbox: ref?.bbox || null };\n\n const hasGko = validInfos.some(i => isExt(i.nameUpper, '.GKO'));\n\n const scoreInfo = (i) => {\n let score = 0;\n\n // Prefer .GKO when present (GM1/GM2 经常是机械层而不是板外形)\n if (hasGko && !isExt(i.nameUpper, '.GKO')) score += 3.0;\n if (isExt(i.nameUpper, '.GM2') || isExt(i.nameUpper, '.GM1')) score += 0.5;\n\n // Prefer candidates that actually produced closed shapes\n if ((i.shapesCount || 0) === 0 && (i.strokesCount || 0) > 0) score += 0.5;\n if ((i.shapesCount || 0) === 0 && (i.strokesCount || 0) === 0) score += 10.0;\n\n if (ref?.bbox) {\n const refBox = ref.bbox;\n const refSize = refBox.getSize(new THREE.Vector3());\n const refCenter = refBox.getCenter(new THREE.Vector3());\n\n const expandedRef = refBox.clone().expandByScalar(Math.max(10, Math.max(refSize.x, refSize.y) * 0.05)); // 5% 或至少 10mm 容错\n if (!expandedRef.intersectsBox(i.bbox)) score += 1000.0;\n\n // Size similarity\n const rx = i.size.x / Math.max(1e-9, refSize.x);\n const ry = i.size.y / Math.max(1e-9, refSize.y);\n score += Math.abs(Math.log(rx)) + Math.abs(Math.log(ry));\n\n // Center proximity\n const dist = i.center.distanceTo(refCenter);\n const maxDim = Math.max(refSize.x, refSize.y);\n score += dist / Math.max(1e-9, maxDim);\n } else {\n // No reference: avoid extreme outliers by preferring median-ish area\n // (handled after)\n }\n\n return score;\n };\n\n let chosen = null;\n let bestScore = Infinity;\n for (const i of validInfos) {\n const s = scoreInfo(i);\n if (s < bestScore) {\n bestScore = s;\n chosen = i;\n }\n }\n\n if (!chosen) return { files: outlineFiles, refBbox: ref?.bbox || null };\n\n const chosenFile = chosen.file;\n const chosenNameUpper = (chosenFile.name || '').toUpperCase();\n \n // 如果选中的是GKO,也保留GM1用于合并(与home 2D仿真一致)\n const filesToKeep = [chosenFile];\n if (chosenNameUpper.endsWith('.GKO')) {\n const gm1Files = outlineCandidates.filter(f => {\n const nameUpper = (f.name || '').toUpperCase();\n return nameUpper.endsWith('.GM1') && f !== chosenFile;\n });\n if (gm1Files.length > 0) {\n filesToKeep.push(...gm1Files);\n debugLog('[3D-new][OutlineCandidates] 🔗 发现GM1层,将与GKO合并生成完整轮廓');\n }\n }\n \n const ignored = outlineCandidates.filter(f => !filesToKeep.includes(f)).map(f => f.name);\n if (ignored.length > 0) {\n debugLog('[3D-new][OutlineCandidates] 轮廓层已选择:', filesToKeep.map(f => f.name).join(' + '), ';忽略其余:', ignored);\n } else {\n debugLog('[3D-new][OutlineCandidates] 轮廓层已选择:', filesToKeep.map(f => f.name).join(' + '));\n }\n // 🎯 返回选择的文件和参考层bbox(用于后续选择正确的外轮廓)\n return { files: filesToKeep, refBbox: ref?.bbox || null };\n };\n\n const pickResult = await pickBestOutlineFiles();\n const referenceBbox = pickResult.refBbox; // 🎯 保存参考层bbox,用于选择正确的外轮廓\n outlineFiles.splice(0, outlineFiles.length, ...pickResult.files);\n \n // 排除 Status Report.Txt 等非钻孔的文本文件\n const drillFiles = gerberFiles.filter(f => {\n const name = f.name.toLowerCase();\n return name.match(/(\\.drl|\\.dri|\\.txt|\\.drd)/i) && \n !name.includes('status report') &&\n !name.includes('.rep') &&\n !name.includes('.log') &&\n !name.includes('.apr');\n });\n \n // Debug: Log identified files\n // debugLog(`[Layer Identification] 识别到的图层文件:`);\n // debugLog(` - 轮廓层: ${outlineFiles.length} 个`);\n // debugLog(` - 顶层铜层: ${topCopperFiles.length} 个`, topCopperFiles.map(f => f.name));\n // debugLog(` - 底层铜层: ${bottomCopperFiles.length} 个`, bottomCopperFiles.map(f => f.name));\n // debugLog(` - 顶层阻焊: ${topMaskFiles.length} 个`, topMaskFiles.map(f => f.name));\n // debugLog(` - 底层阻焊: ${bottomMaskFiles.length} 个`, bottomMaskFiles.map(f => f.name));\n // debugLog(` - 顶层锡膏: ${topPasteFiles.length} 个`, topPasteFiles.map(f => f.name));\n // debugLog(` - 底层锡膏: ${bottomPasteFiles.length} 个`, bottomPasteFiles.map(f => f.name));\n // debugLog(` - 顶层丝印: ${topSilkFiles.length} 个`, topSilkFiles.map(f => f.name));\n // debugLog(` - 底层丝印: ${bottomSilkFiles.length} 个`, bottomSilkFiles.map(f => f.name));\n // debugLog(` - 钻孔文件: ${drillFiles.length} 个`, drillFiles.map(f => f.name));\n \n const endTimeClassify = performance.now()\n console.log(`[性能] 文件分类完成,耗时: ${(endTimeClassify - startTimeClassify).toFixed(2)}ms`)\n\n console.log('[性能] 开始渲染轮廓层...')\n const startTimeOutline = performance.now()\n \n // 3. Render Outline First (Base)\n let hasOutline = false;\n let fallbackLayerForCamera = null; // Store layer data for camera fitting if no outline\n const outlineStrokes = []; // 兜底线段,可视化未闭合的 G01/G02/G03\n let usedBboxOutlineFallback = false; // 标记是否用 bbox 实心板兜底(此时需要用线条描边还原异形外形)\n \n // 轮廓层阈值常量\n const OUTLINE_MIN_AREA_RATIO = 0.3; // 最小面积比(相对于bbox)\n const OUTLINE_TOTAL_AREA_RATIO = 0.5; // 总面积比阈值\n const OUTLINE_SHAPE_COUNT_LIMIT = 50; // 碎片化形状数量阈值\n const OUTLINE_FORCED_RATIO_LIMIT = 0.5; // 强制闭合比例阈值\n const OUTLINE_MERGE_TOLERANCE = 0.2; // 线段合并容差(mm)\n \n if (outlineFiles.length > 0) {\n const parser = new GerberOutlineParser();\n let shapes = [];\n \n // 解析所有轮廓文件\n for (const file of outlineFiles) {\n const text = await file.text();\n const { shapes: fileShapes, strokes } = parser.parse(text);\n if (fileShapes?.length > 0) {\n for (const s of fileShapes) shapes.push(s);\n }\n if (strokes?.length > 0) {\n for (const seg of strokes) outlineStrokes.push(seg);\n }\n }\n \n // 多文件合并:使用所有线段重新拼接成完整轮廓\n // 🎯 使用链式拼接算法(参考 home 模块),更适合异形轮廓\n if (outlineFiles.length > 1 && outlineStrokes.length > 0) {\n debugLog(`[轮廓层] 🔗 合并 ${outlineFiles.length} 个文件,线段数: ${outlineStrokes.length}`);\n const mergedShapes = stitchSegmentsToShapes(outlineStrokes);\n if (mergedShapes?.length > 0) {\n debugLog(`[轮廓层] ✅ 合并成功,生成 ${mergedShapes.length} 个形状`);\n // 按面积排序,取最大的几个形状\n mergedShapes.sort((a, b) => {\n const areaA = Math.abs(THREE.ShapeUtils.area(a.getPoints()));\n const areaB = Math.abs(THREE.ShapeUtils.area(b.getPoints()));\n return areaB - areaA;\n });\n shapes = mergedShapes; // 替换为合并后的完整形状\n }\n }\n\n debugLog(`[轮廓层] 形状: ${shapes.length}, 线段: ${outlineStrokes.length}`);\n \n // 🚀 对复杂形状进行点简化(参考home 2D仿真)\n // 使用更保守的简化策略,保留异形轮廓的细节\n const MAX_POINTS_PER_SHAPE = 3000; // 放宽限制,使用earcut三角化代替ExtrudeGeometry\n const simplifyDouglasPeucker = (points, epsilon) => {\n if (!points || points.length < 3) return points || [];\n const sq = (v) => v * v;\n const distPointToSegSq = (p, a, b) => {\n const vx = b.x - a.x;\n const vy = b.y - a.y;\n const wx = p.x - a.x;\n const wy = p.y - a.y;\n const c1 = vx * wx + vy * wy;\n if (c1 <= 0) return sq(p.x - a.x) + sq(p.y - a.y);\n const c2 = vx * vx + vy * vy;\n if (c2 <= c1) return sq(p.x - b.x) + sq(p.y - b.y);\n const t = c1 / c2;\n const px = a.x + t * vx;\n const py = a.y + t * vy;\n return sq(p.x - px) + sq(p.y - py);\n };\n const epsSq = epsilon * epsilon;\n const keep = new Array(points.length).fill(false);\n keep[0] = true;\n keep[points.length - 1] = true;\n const stack = [[0, points.length - 1]];\n while (stack.length) {\n const [s, e] = stack.pop();\n let maxD = 0;\n let idx = -1;\n const a = points[s];\n const b = points[e];\n for (let i = s + 1; i < e; i++) {\n const d = distPointToSegSq(points[i], a, b);\n if (d > maxD) {\n maxD = d;\n idx = i;\n }\n }\n if (idx >= 0 && maxD > epsSq) {\n keep[idx] = true;\n stack.push([s, idx], [idx, e]);\n }\n }\n const out = [];\n for (let i = 0; i < points.length; i++) if (keep[i]) out.push(points[i]);\n return out;\n };\n \n // 对点数过多的shapes进行保守简化\n for (let i = 0; i < shapes.length; i++) {\n const shape = shapes[i];\n let currentPoints = shape.getPoints();\n \n if (currentPoints.length > MAX_POINTS_PER_SHAPE) {\n // 计算边界尺寸\n let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;\n for (const p of currentPoints) {\n minX = Math.min(minX, p.x); maxX = Math.max(maxX, p.x);\n minY = Math.min(minY, p.y); maxY = Math.max(maxY, p.y);\n }\n const boardSize = Math.max(maxX - minX, maxY - minY);\n \n // 使用保守的容差进行简化(0.05mm,保留曲线细节)\n const targetPoints = 2000;\n // 使用固定的小容差,避免过度简化\n const epsilon = Math.max(0.05, boardSize * 0.0003); // 最小0.05mm容差\n const simplified = simplifyDouglasPeucker(currentPoints, epsilon);\n \n debugLog(`[轮廓层] 简化形状 ${i}: ${currentPoints.length} -> ${simplified.length} 点 (容差=${epsilon.toFixed(4)}mm)`);\n \n if (simplified.length >= 4) {\n // 用简化后的点创建新的Shape\n const newShape = new THREE.Shape();\n newShape.moveTo(simplified[0].x, simplified[0].y);\n for (let j = 1; j < simplified.length; j++) {\n newShape.lineTo(simplified[j].x, simplified[j].y);\n }\n newShape.closePath();\n newShape.userData = shape.userData; // 保留原有userData\n shapes[i] = newShape;\n }\n }\n }\n\n // ✅ 关键修复:为轮廓层自动“挂孔洞”\n // GerberOutlineParser 会把内轮廓(孔/开窗)解析为独立 shape,但默认不会把它们放到 outerShape.holes。\n // 这样在只渲染外轮廓 shape 时,孔洞会“缺失”(看起来像被填死/没镂空)。\n // 这里参考 2D 仿真/3dPage silkscreen 的思路:把明显位于外轮廓内部的小 shape 挂到 parent.holes。\n const attachOutlineHoles = (inputShapes, referenceBbox) => {\n if (!inputShapes || inputShapes.length <= 1) return inputShapes || [];\n\n const isPointInShape = (pt, shape) => {\n const points = shape.getPoints();\n if (!points || points.length < 3) return false;\n let inside = false;\n for (let i = 0, j = points.length - 1; i < points.length; j = i++) {\n const xi = points[i].x, yi = points[i].y;\n const xj = points[j].x, yj = points[j].y;\n if (((yi > pt.y) !== (yj > pt.y)) && (pt.x < (xj - xi) * (pt.y - yi) / (yj - yi) + xi)) inside = !inside;\n }\n return inside;\n };\n\n const signedArea = (pts) => {\n // Three.ShapeUtils.area is signed (based on winding)\n return THREE.ShapeUtils.area(pts);\n };\n\n const bboxOfShape = (s) => {\n const pts = s.getPoints();\n let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;\n for (const p of pts) {\n if (p.x < minX) minX = p.x;\n if (p.x > maxX) maxX = p.x;\n if (p.y < minY) minY = p.y;\n if (p.y > maxY) maxY = p.y;\n }\n const valid = isFinite(minX) && isFinite(maxX) && isFinite(minY) && isFinite(maxY) && maxX > minX && maxY > minY;\n if (!valid) return null;\n return { minX, minY, maxX, maxY, w: (maxX - minX), h: (maxY - minY), area: (maxX - minX) * (maxY - minY) };\n };\n\n const bboxContains = (outer, inner, pad = 0.2) => {\n return inner.minX >= outer.minX - pad &&\n inner.maxX <= outer.maxX + pad &&\n inner.minY >= outer.minY - pad &&\n inner.maxY <= outer.maxY + pad;\n };\n\n const refArea = referenceBbox && !referenceBbox.isEmpty()\n ? (referenceBbox.getSize(new THREE.Vector3()).x * referenceBbox.getSize(new THREE.Vector3()).y)\n : 0;\n\n const items = inputShapes.map(s => {\n const pts = s.getPoints();\n const area = Math.abs(THREE.ShapeUtils.area(pts));\n const bbox = bboxOfShape(s);\n let cx = 0, cy = 0;\n for (const p of pts) { cx += p.x; cy += p.y; }\n const n = Math.max(1, pts.length);\n const center = { x: cx / n, y: cy / n };\n return { shape: s, area, bbox, center };\n }).filter(i => i.area > 0.001 && i.bbox);\n\n if (items.length <= 1) return inputShapes;\n\n // 小孔阈值:对齐 home(0.005% 的板面积)\n const largestArea = items.reduce((m, it) => Math.max(m, it.area), 0);\n const minHoleArea = Math.max(0.05, largestArea * 0.00005); // 至少 0.05mm²,避免抖动碎片\n\n // 防止把“板子/拼板子块”当孔:若有参考层,则孔洞面积不能超过 refArea 的 30%\n const maxHoleAreaByRef = (refArea > 0) ? (refArea * 0.30) : Infinity;\n\n // attach: small -> large\n items.sort((a, b) => a.area - b.area);\n const isHole = new Set();\n\n for (const child of items) {\n if (child.area < minHoleArea) continue;\n if (child.area > maxHoleAreaByRef) continue;\n\n // 找最小的可包含 parent(避免把孔挂到更外层的大框上)\n let bestParent = null;\n let bestParentArea = Infinity;\n for (const parent of items) {\n if (parent === child) continue;\n if (parent.area <= child.area) continue;\n if (!bboxContains(parent.bbox, child.bbox, 0.2)) continue;\n // 额外限制:孔洞面积不能太接近 parent(防止“内层板子”被当孔)\n if ((child.area / Math.max(1e-9, parent.area)) > 0.60) continue;\n if (!isPointInShape(child.center, parent.shape)) continue;\n if (parent.area < bestParentArea) {\n bestParent = parent;\n bestParentArea = parent.area;\n }\n }\n if (bestParent) {\n // ✅ Three.js 对 holes 更“挑剔”:holes 最稳妥的是 THREE.Path,\n // 且 hole 的绕序应与外轮廓相反,否则容易出现“holes 被填死/不生效”。\n const parentPts = bestParent.shape.getPoints();\n const childPts0 = child.shape.getPoints();\n if (parentPts && parentPts.length >= 3 && childPts0 && childPts0.length >= 3) {\n let childPts = childPts0.slice();\n const parentA = signedArea(parentPts);\n const childA = signedArea(childPts);\n if (parentA * childA > 0) {\n childPts = childPts.slice().reverse();\n }\n const holePath = new THREE.Path();\n holePath.moveTo(childPts[0].x, childPts[0].y);\n for (let k = 1; k < childPts.length; k++) {\n holePath.lineTo(childPts[k].x, childPts[k].y);\n }\n holePath.closePath();\n\n bestParent.shape.holes = bestParent.shape.holes || [];\n bestParent.shape.holes.push(holePath);\n }\n isHole.add(child.shape);\n }\n }\n\n const roots = inputShapes.filter(s => !isHole.has(s));\n const holeCount = inputShapes.length - roots.length;\n if (holeCount > 0) {\n debugLog(`[Outline] ✅ 已挂孔洞: holes=${holeCount}, roots=${roots.length}`);\n }\n return roots;\n };\n\n shapes = attachOutlineHoles(shapes, referenceBbox);\n \n if (shapes.length > 0) {\n // 🎯 使用参考层中心点选择正确的外轮廓(参考home模块的逻辑)\n // 这是解决异形轮廓渲染问题的关键\n const isPointInShape = (pt, shape) => {\n const points = shape.getPoints();\n if (!points || points.length < 3) return false;\n let inside = false;\n for (let i = 0, j = points.length - 1; i < points.length; j = i++) {\n const xi = points[i].x, yi = points[i].y;\n const xj = points[j].x, yj = points[j].y;\n if (((yi > pt.y) !== (yj > pt.y)) && (pt.x < (xj - xi) * (pt.y - yi) / (yj - yi) + xi)) {\n inside = !inside;\n }\n }\n return inside;\n };\n \n // 如果有参考层bbox,使用bbox重叠度来选择正确的外轮廓(更鲁棒,不依赖中心点)\n let selectedOuterShape = null;\n let selectedOuterMeta = null; // { bbox:{minX,maxX,minY,maxY,w,h,area}, polyArea:number, overlapRatio:number }\n if (referenceBbox && !referenceBbox.isEmpty()) {\n const refCenter = referenceBbox.getCenter(new THREE.Vector3());\n const focusCenter = { x: refCenter.x, y: refCenter.y };\n const refSize = referenceBbox.getSize(new THREE.Vector3());\n const refMinX = refCenter.x - refSize.x / 2;\n const refMaxX = refCenter.x + refSize.x / 2;\n const refMinY = refCenter.y - refSize.y / 2;\n const refMaxY = refCenter.y + refSize.y / 2;\n const refArea = refSize.x * refSize.y;\n \n // ✅ 新策略:计算每个轮廓的bbox与参考层bbox的重叠面积\n const MIN_OUTER_AREA = 1.0; // mm²,过滤掉碎片/噪点\n const candidates = [];\n for (const s of shapes) {\n const area = Math.abs(THREE.ShapeUtils.area(s.getPoints()));\n if (area < MIN_OUTER_AREA) continue;\n try {\n // 计算形状bbox\n const pts = s.getPoints();\n let sMinX = Infinity, sMaxX = -Infinity, sMinY = Infinity, sMaxY = -Infinity;\n for (const p of pts) {\n if (p.x < sMinX) sMinX = p.x; if (p.x > sMaxX) sMaxX = p.x;\n if (p.y < sMinY) sMinY = p.y; if (p.y > sMaxY) sMaxY = p.y;\n }\n // 计算bbox重叠区域\n const overlapMinX = Math.max(refMinX, sMinX);\n const overlapMaxX = Math.min(refMaxX, sMaxX);\n const overlapMinY = Math.max(refMinY, sMinY);\n const overlapMaxY = Math.min(refMaxY, sMaxY);\n const overlapW = Math.max(0, overlapMaxX - overlapMinX);\n const overlapH = Math.max(0, overlapMaxY - overlapMinY);\n const overlapArea = overlapW * overlapH;\n const overlapRatio = refArea > 0 ? (overlapArea / refArea) : 0;\n \n const sW = sMaxX - sMinX;\n const sH = sMaxY - sMinY;\n const sBboxArea = sW * sH;\n\n // 如果重叠面积 > 参考层面积的30%,认为是候选\n if (overlapRatio > 0.3) {\n candidates.push({\n shape: s,\n area,\n overlapRatio,\n shapeBbox: { minX: sMinX, maxX: sMaxX, minY: sMinY, maxY: sMaxY, w: sW, h: sH, area: sBboxArea }\n });\n }\n } catch (_) { /* ignore */ }\n }\n \n if (candidates.length > 0) {\n // ✅ 改进选择策略:当多个候选 overlap 都很高时,优先选“bbox面积最接近参考层bbox”的那一个\n // (避免大外框/工艺边:它 overlap 也会很高,但 bbox 会明显更大)\n // 过滤出overlap足够高的候选(>80%)\n const highOverlapCandidates = candidates.filter(c => c.overlapRatio > 0.8);\n \n const refSize = referenceBbox.getSize(new THREE.Vector3());\n const refArea = refSize.x * refSize.y;\n \n let selectedCandidate;\n if (highOverlapCandidates.length > 1) {\n // 多个高overlap候选:优先选择 bbox 面积接近 refArea 且不小于 refArea*0.8 的\n const validBboxCandidates = highOverlapCandidates\n .filter(c => (c?.shapeBbox?.area || 0) >= refArea * 0.8);\n\n const pool = validBboxCandidates.length > 0 ? validBboxCandidates : highOverlapCandidates;\n pool.sort((a, b) => {\n const aB = a?.shapeBbox?.area || 0;\n const bB = b?.shapeBbox?.area || 0;\n return Math.abs(aB - refArea) - Math.abs(bB - refArea);\n });\n selectedCandidate = pool[0];\n debugLog(`[Outline] 🔍 多个高overlap候选,选择bbox最接近参考层的: bbox=${(selectedCandidate.shapeBbox?.area || 0).toFixed(2)}mm² (参考=${refArea.toFixed(2)}mm²), poly=${selectedCandidate.area.toFixed(2)}mm²`);\n } else {\n // 选择overlap最高的候选\n candidates.sort((a, b) => b.overlapRatio - a.overlapRatio);\n selectedCandidate = candidates[0];\n }\n \n const selectedArea = selectedCandidate.area;\n selectedOuterMeta = {\n bbox: selectedCandidate.shapeBbox || null,\n polyArea: selectedArea,\n overlapRatio: selectedCandidate.overlapRatio || 0\n };\n \n // 🎯 检查是否需要使用所有形状(拼板检测)\n \n // 如果最高重叠候选的面积明显小于参考层,且有多个候选,可能是拼板\n if (selectedArea < refArea * 0.5 && candidates.length > 1) {\n // 计算所有候选的总面积\n const totalArea = candidates.reduce((sum, c) => sum + c.area, 0);\n \n // 如果总面积接近参考层,使用所有候选(拼板模式)\n if (totalArea > refArea * 0.6) {\n debugLog(`[Outline] 🔗 检测到拼板:最高重叠=${selectedArea.toFixed(2)}mm² (overlap=${(selectedCandidate.overlapRatio * 100).toFixed(1)}%),总面积=${totalArea.toFixed(2)}mm²,使用 ${candidates.length} 个候选`);\n selectedOuterShape = null; // 不选择单个,让后续处理所有形状\n } else {\n selectedOuterShape = selectedCandidate.shape;\n debugLog(`[Outline] 🎯 使用bbox重叠选择外轮廓: 面积=${selectedArea.toFixed(2)}mm², overlap=${(selectedCandidate.overlapRatio * 100).toFixed(1)}%, 候选数=${candidates.length}`);\n }\n } else {\n selectedOuterShape = selectedCandidate.shape;\n debugLog(`[Outline] 🎯 使用bbox重叠选择外轮廓: 面积=${selectedArea.toFixed(2)}mm², overlap=${(selectedCandidate.overlapRatio * 100).toFixed(1)}%, 候选数=${candidates.length}`);\n }\n } else {\n // 🎯 参考层中心点未命中,尝试使用最大面积的形状(参考home模块逻辑)\n // 计算所有形状的面积并排序\n const shapesWithArea = shapes.map(s => ({\n shape: s,\n area: Math.abs(THREE.ShapeUtils.area(s.getPoints()))\n })).filter(item => item.area >= 1.0); // 过滤掉面积小于1mm²的碎片\n \n if (shapesWithArea.length > 0) {\n shapesWithArea.sort((a, b) => b.area - a.area);\n const maxShape = shapesWithArea[0];\n \n // 计算参考层的面积\n const refSize = referenceBbox.getSize(new THREE.Vector3());\n const refArea = refSize.x * refSize.y;\n \n // 如果最大形状面积超过参考层面积的30%,认为它是有效的外轮廓\n if (maxShape.area > refArea * 0.3) {\n selectedOuterShape = maxShape.shape;\n debugLog(`[Outline] 🎯 使用最大面积形状作为外轮廓: 面积=${maxShape.area.toFixed(2)}mm² (参考层面积=${refArea.toFixed(2)}mm²)`);\n } else {\n debugWarn(`[Outline] ⚠️ 最大形状面积过小 (${maxShape.area.toFixed(2)}mm² < ${(refArea * 0.3).toFixed(2)}mm²),回退到碎片化处理`);\n }\n } else {\n debugWarn('[Outline] ⚠️ 没有有效形状(面积>=1mm²),回退到碎片化处理');\n }\n }\n }\n \n // 如果成功选择了外轮廓,直接使用它,跳过碎片化检测\n if (selectedOuterShape) {\n // ✅ 额外兜底:如果选中外轮廓的“多边形面积”明显小于它的 bbox 面积,\n // 说明该轮廓很可能不是一个可靠的实心外形(常见于拼线/自交/半轮廓),会导致基材出现镂空/缺面。\n // 此时用 bbox 生成实心板材更稳定,同时开启线段描边以保留真实外形视觉。\n if (selectedOuterMeta?.bbox?.area && selectedOuterMeta?.polyArea) {\n const ratio = selectedOuterMeta.polyArea / Math.max(1e-9, selectedOuterMeta.bbox.area);\n // ⚠️ 只有当 poly/bbox 明显偏小(通常意味着拼线/自交/半轮廓,容易出现“基材镂空/缺面”)才做兜底。\n // 经验阈值:<60% 才认为不可靠;像 79% 这种常见异形/圆角矩形不要强制退化成矩形。\n if (ratio < 0.60) {\n // 优先使用凸包(保留异形),否则再用 bbox(矩形最稳)\n const hullShape = (outlineStrokes && outlineStrokes.length > 0)\n ? this.buildHullShapeFromSegments(outlineStrokes)\n : null;\n if (hullShape) {\n selectedOuterShape = hullShape;\n usedBboxOutlineFallback = true;\n debugWarn(`[Outline] ⚠️ 选中外形多边形面积偏小(poly/bbox=${(ratio * 100).toFixed(1)}%),改用凸包实心板兜底`);\n } else {\n const bb = selectedOuterMeta.bbox;\n const rectShape = new THREE.Shape();\n rectShape.moveTo(bb.minX, bb.minY);\n rectShape.lineTo(bb.maxX, bb.minY);\n rectShape.lineTo(bb.maxX, bb.maxY);\n rectShape.lineTo(bb.minX, bb.maxY);\n rectShape.closePath();\n selectedOuterShape = rectShape;\n usedBboxOutlineFallback = true;\n debugWarn(`[Outline] ⚠️ 选中外形多边形面积偏小(poly/bbox=${(ratio * 100).toFixed(1)}%),改用bbox实心板兜底`);\n }\n }\n }\n\n this.renderOutlineBoard([selectedOuterShape], !usedBboxOutlineFallback);\n hasOutline = true;\n debugLog('[Outline] ✅ 使用参考层选择的异形外轮廓渲染基材');\n } else {\n // 没有选择到正确的外轮廓,使用原有的碎片化检测逻辑\n \n // 预计算每个形状的面积(避免重复调用getPoints)\n const shapeInfos = shapes.map(s => ({\n shape: s,\n area: Math.abs(THREE.ShapeUtils.area(s.getPoints())),\n forcedClose: s.userData?.forcedClose || false\n }));\n \n // 统计信息\n const maxInfo = shapeInfos.reduce((max, cur) => cur.area > max.area ? cur : max);\n const forcedCount = shapeInfos.filter(info => info.forcedClose).length;\n const totalArea = shapeInfos.reduce((sum, info) => sum + info.area, 0);\n \n // 构建多种兜底形状:凸包(保留异形)和 bbox(简单矩形)\n const shapeBboxShape = this.buildBBoxShapeFromShapes(shapes);\n const strokeBboxShape = outlineStrokes.length > 0 ? this.buildBBoxShapeFromSegments(outlineStrokes) : null;\n const strokeHullShape = outlineStrokes.length > 0 ? this.buildHullShapeFromSegments(outlineStrokes) : null;\n \n // 计算各形状面积\n const shapeBboxArea = shapeBboxShape ? Math.abs(THREE.ShapeUtils.area(shapeBboxShape.getPoints())) : 0;\n const strokeBboxArea = strokeBboxShape ? Math.abs(THREE.ShapeUtils.area(strokeBboxShape.getPoints())) : 0;\n const strokeHullArea = strokeHullShape ? Math.abs(THREE.ShapeUtils.area(strokeHullShape.getPoints())) : 0;\n \n // 选择面积更大的bbox用于面积比较\n const bboxShape = strokeBboxArea > shapeBboxArea ? strokeBboxShape : shapeBboxShape;\n const bboxArea = Math.max(shapeBboxArea, strokeBboxArea);\n \n // 🎯 异形优先:当有凸包时,优先使用凸包作为碎片化兜底(保留异形轮廓)\n const fallbackShape = strokeHullShape && strokeHullArea > 0 ? strokeHullShape : bboxShape;\n const fallbackType = strokeHullShape && strokeHullArea > 0 ? '凸包' : '矩形';\n \n if (strokeHullShape && strokeHullArea > 0) {\n debugLog(`[Outline] 凸包可用于异形兜底(面积=${strokeHullArea.toFixed(2)}mm²)`);\n }\n \n let finalShapes = shapes;\n // 额外兜底:如果最大形状是“强制闭合”的(forcedClose),说明拼线没有形成可靠闭环,\n // Three.js 三角化很容易出现大片缺失(你截图里的“斜三角缺口/缺一块板”就是典型症状)。\n // ✅ 改进策略:\n // - forcedClose 的最大轮廓必须“接近参考外形面积”(凸包优先,其次 bbox),否则强制回退\n // - 如果存在 non-forcedClose 的大轮廓,也优先选它(避免 forcedClose 造成缺口)\n if (bboxShape && bboxArea > 0) {\n let maxShape = null;\n let maxArea = 0;\n let forcedCount = 0;\n let bestNonForced = null;\n let bestNonForcedArea = 0;\n for (const s of shapes) {\n const a = Math.abs(THREE.ShapeUtils.area(s.getPoints()));\n const isForced = !!s?.userData?.forcedClose;\n if (isForced) forcedCount++;\n if (!isForced && a > bestNonForcedArea) {\n bestNonForcedArea = a;\n bestNonForced = s;\n }\n if (a > maxArea) {\n maxArea = a;\n maxShape = s;\n }\n }\n \n // 参考面积:优先凸包(更接近外轮廓),否则 bbox\n const refAreaForOutline = strokeHullArea > 0 ? strokeHullArea : bboxArea;\n const forcedAreaRatio = refAreaForOutline > 0 ? (maxArea / refAreaForOutline) : 0;\n const forcedLooksGood = forcedAreaRatio >= 0.85; // forcedClose 仍可接受的最低比例\n\n if (maxShape?.userData?.forcedClose) {\n // 如果存在非 forcedClose 的大轮廓,优先它(避免 forcedClose 导致的缺口)\n if (bestNonForced && bestNonForcedArea > 0 && bestNonForcedArea >= refAreaForOutline * 0.6) {\n finalShapes = [bestNonForced];\n debugWarn(`[Outline] 最大轮廓为强制闭合,改用非强制闭合外轮廓 (area=${bestNonForcedArea.toFixed(2)}mm²)`);\n } else if (!forcedLooksGood) {\n // forcedClose 面积明显偏小:强制回退凸包/矩形,避免“缺一块板”\n finalShapes = [fallbackShape];\n debugWarn(`[Outline] 最大轮廓为强制闭合且面积偏小(ratio=${(forcedAreaRatio * 100).toFixed(1)}%),使用${fallbackType}兜底`);\n } else if (maxArea < bboxArea * OUTLINE_MIN_AREA_RATIO) {\n // 极端小面积:仍走原有兜底\n finalShapes = [fallbackShape];\n debugWarn(`[Outline] 最大轮廓为强制闭合且面积过小,使用${fallbackType}兜底`);\n } else {\n // forcedClose 但面积接近参考:保留异形\n debugLog(`[Outline] 最大轮廓为强制闭合但面积接近参考(ratio=${(forcedAreaRatio * 100).toFixed(1)}%),使用异形轮廓`);\n }\n } else if (maxArea < bboxArea * OUTLINE_MIN_AREA_RATIO && (shapes.length > OUTLINE_SHAPE_COUNT_LIMIT || (forcedCount / Math.max(1, shapes.length)) > OUTLINE_FORCED_RATIO_LIMIT)) {\n // 典型拼板/网格轮廓:会产生大量小闭环(单块板/开槽等),但缺少“单一的大外轮廓”。\n // 🎯 改进:使用凸包保留异形外轮廓,而不是简单的矩形\n finalShapes = [fallbackShape];\n const forcedRatio = forcedCount / Math.max(1, shapes.length);\n debugWarn(`[Outline] 轮廓碎片化(面积=${maxArea.toFixed(2)}mm²,形状数=${shapes.length},强制闭合比=${forcedRatio.toFixed(2)}),使用${fallbackType}兜底`);\n } else {\n const localTotalArea = shapes.reduce((acc, s) => acc + Math.abs(THREE.ShapeUtils.area(s.getPoints())), 0);\n if (localTotalArea < bboxArea * OUTLINE_TOTAL_AREA_RATIO) {\n finalShapes = [fallbackShape];\n debugLog(`[Outline] 总面积过小,使用${fallbackType}兜底`);\n }\n }\n }\n // 若退化成凸包/bbox:不要画边框,后面用真实轮廓线段描边;\n // 否则直接在板体上绘制黑色边框线。\n const usedBboxSolid = fallbackShape && finalShapes.length === 1 && finalShapes[0] === fallbackShape;\n usedBboxOutlineFallback = usedBboxSolid;\n this.renderOutlineBoard(finalShapes, !usedBboxSolid);\n hasOutline = true;\n } // 关闭 else { ... } 分支(selectedOuterShape 未选中时的碎片化处理)\n } else if (outlineStrokes.length > 0) {\n // 如果没有闭合形状但有线段,计算线段的外接矩形作为 bbox\n const strokeBboxShape = this.buildBBoxShapeFromSegments(outlineStrokes);\n if (strokeBboxShape) {\n // 计算 bbox\n const allPoints = strokeBboxShape.getPoints().map(p => new THREE.Vector3(p.x, p.y, 0));\n const bbox = new THREE.Box3().setFromPoints(allPoints);\n this.outlineBbox = bbox.clone();\n debugLog(`[轮廓层] 使用线段外接矩形作为bbox: ${bbox.getSize(new THREE.Vector3()).x.toFixed(2)} x ${bbox.getSize(new THREE.Vector3()).y.toFixed(2)}`);\n }\n // debugWarn('未从轮廓层提取到闭合形状,跳过轮廓层渲染,继续渲染其他图层。');\n } else {\n // 🚀 轮廓层解析失败(无形状无线段),使用其他层计算外接矩形作为基材\n debugWarn('[3D-new] 轮廓层解析失败(无形状无线段),尝试从其他层计算外接矩形作为基材...');\n const fallbackFilesForOutline = [...topMaskFiles, ...bottomMaskFiles, ...topCopperFiles, ...bottomCopperFiles];\n \n if (fallbackFilesForOutline.length > 0) {\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;\n let hasValidBounds = false;\n \n for (const file of fallbackFilesForOutline) {\n try {\n const res = await GerberParser.parseFile(file, '#ffffff');\n \n if (res && res.data && res.data.vertices && res.data.vertices.length > 0) {\n let scale = 1.0;\n if (res.units === 'in' || res.units === 'inch') {\n scale = 25.4;\n }\n \n for (let i = 0; i < res.data.vertices.length; i += 3) {\n const x = res.data.vertices[i] * scale;\n const y = -res.data.vertices[i + 1] * scale;\n if (x < minX) minX = x;\n if (x > maxX) maxX = x;\n if (y < minY) minY = y;\n if (y > maxY) maxY = y;\n }\n hasValidBounds = true;\n }\n } catch (e) {\n debugWarn(`[3D-new] 从 ${file.name} 计算边界失败:`, e.message);\n }\n }\n \n if (hasValidBounds && isFinite(minX) && isFinite(maxX) && isFinite(minY) && isFinite(maxY)) {\n const width = maxX - minX;\n const height = maxY - minY;\n \n debugLog(`[3D-new] 轮廓解析失败回退:计算得到外接矩形: ${width.toFixed(2)} x ${height.toFixed(2)}`);\n \n const padding = Math.max(width, height) * 0.02;\n const rectShape = new THREE.Shape();\n rectShape.moveTo(minX - padding, minY - padding);\n rectShape.lineTo(maxX + padding, minY - padding);\n rectShape.lineTo(maxX + padding, maxY + padding);\n rectShape.lineTo(minX - padding, maxY + padding);\n rectShape.lineTo(minX - padding, minY - padding);\n \n this.renderOutlineBoard([rectShape], false);\n hasOutline = true;\n \n // 设置 outlineBbox\n const bboxPoints = rectShape.getPoints().map(p => new THREE.Vector3(p.x, p.y, 0));\n this.outlineBbox = new THREE.Box3().setFromPoints(bboxPoints);\n }\n }\n }\n } else {\n // 尝试从其他层的外接矩形创建基材\n debugWarn('[3D-new] 未找到轮廓层文件,尝试从其他层计算外接矩形作为基材...');\n const fallbackFiles = [...topMaskFiles, ...bottomMaskFiles, ...topCopperFiles, ...bottomCopperFiles];\n \n if (fallbackFiles.length > 0) {\n // 解析所有文件并计算总外接矩形\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;\n let hasValidBounds = false;\n \n for (const file of fallbackFiles) {\n try {\n const res = await GerberParser.parseFile(file, '#ffffff');\n \n if (res && res.data && res.data.vertices && res.data.vertices.length > 0) {\n // 计算缩放比例(inch -> mm)\n let scale = 1.0;\n if (res.units === 'in' || res.units === 'inch') {\n scale = 25.4;\n }\n \n // 遍历所有顶点 (vertices 是 Float32Array,每3个为一组:x, y, z)\n for (let i = 0; i < res.data.vertices.length; i += 3) {\n const x = res.data.vertices[i] * scale;\n const y = -res.data.vertices[i + 1] * scale; // Y轴翻转\n if (x < minX) minX = x;\n if (x > maxX) maxX = x;\n if (y < minY) minY = y;\n if (y > maxY) maxY = y;\n }\n hasValidBounds = true;\n debugLog(`[3D-new] 从 ${file.name} 提取边界: minX=${minX.toFixed(2)}, maxX=${maxX.toFixed(2)}, minY=${minY.toFixed(2)}, maxY=${maxY.toFixed(2)}`);\n }\n } catch (e) {\n debugWarn(`[3D-new] 从 ${file.name} 计算边界失败:`, e.message);\n }\n }\n \n // 如果计算到了有效边界,创建矩形基材\n if (hasValidBounds && isFinite(minX) && isFinite(maxX) && isFinite(minY) && isFinite(maxY)) {\n const width = maxX - minX;\n const height = maxY - minY;\n const centerX = (minX + maxX) / 2;\n const centerY = (minY + maxY) / 2;\n \n debugLog(`[3D-new] 计算得到外接矩形: ${width.toFixed(2)} x ${height.toFixed(2)}, 中心=(${centerX.toFixed(2)}, ${centerY.toFixed(2)})`);\n \n // 添加小边距(2%)\n const padding = Math.max(width, height) * 0.02;\n const rectShape = new THREE.Shape();\n rectShape.moveTo(minX - padding, minY - padding);\n rectShape.lineTo(maxX + padding, minY - padding);\n rectShape.lineTo(maxX + padding, maxY + padding);\n rectShape.lineTo(minX - padding, maxY + padding);\n rectShape.lineTo(minX - padding, minY - padding);\n \n this.renderOutlineBoard([rectShape], false);\n hasOutline = true;\n } else {\n debugWarn('[3D-new] 无法计算有效边界');\n }\n }\n \n if (!hasOutline) {\n // 如果仍然没有轮廓,设置默认厚度并清空场景\n debugWarn('[3D-new] 无法从任何层提取轮廓,跳过基材渲染');\n BOARD_THICKNESS = 1.6; // 默认1.6mm\n this.clearScene();\n \n // Store first available layer for camera fitting (priority: GTO > GTL)\n if (topSilkFiles.length > 0) {\n fallbackLayerForCamera = { type: 'GTO', files: topSilkFiles };\n } else if (topCopperFiles.length > 0) {\n fallbackLayerForCamera = { type: 'GTL', files: topCopperFiles };\n }\n }\n }\n\n // 轮廓描边:当轮廓层被兜底成“实心矩形”时,用真实轮廓线段绘制黑色描边,\n // 这样即使基材是矩形,也能看出异形外轮廓。\n if (outlineStrokes.length > 0) {\n const MAX_STROKES_FOR_BORDER = 200000;\n if (outlineStrokes.length > MAX_STROKES_FOR_BORDER) {\n debugWarn(`[Outline] 线段数量过多(${outlineStrokes.length}),跳过黑色描边以避免性能问题`);\n } else if (usedBboxOutlineFallback) {\n BOARD_THICKNESS = BOARD_THICKNESS || 1.6;\n const zTop = BOARD_THICKNESS / 2 + 0.05;\n const zBottom = -BOARD_THICKNESS / 2 - 0.05 + 0.001;\n this.renderOutlineStrokes(outlineStrokes, 0.10, COLORS.OUTLINE_EDGE, zTop);\n this.renderOutlineStrokes(outlineStrokes, 0.10, COLORS.OUTLINE_EDGE, zBottom);\n } else if (!hasOutline) {\n // 没有闭合面但有线段:至少渲染线框作为轮廓提示\n BOARD_THICKNESS = BOARD_THICKNESS || 1.6;\n const zTop = BOARD_THICKNESS / 2 + 0.05;\n const zBottom = -BOARD_THICKNESS / 2 - 0.05 + 0.001;\n this.renderOutlineStrokes(outlineStrokes, 0.10, COLORS.OUTLINE_EDGE, zTop);\n this.renderOutlineStrokes(outlineStrokes, 0.10, COLORS.OUTLINE_EDGE, zBottom);\n hasOutline = true;\n }\n }\n \n const endTimeOutline = performance.now()\n console.log(`[性能] 轮廓层渲染完成,耗时: ${(endTimeOutline - startTimeOutline).toFixed(2)}ms`)\n\n console.log('[性能] 开始渲染其他图层...')\n const startTimeOtherLayers = performance.now()\n \n // 4. Render Other Layers\n console.log(`[3D-new] 开始渲染其他图层,文件分组情况:`,\n `轮廓: ${outlineFiles.length}`, \n `顶铜: ${topCopperFiles.length}`,\n `内层铜: ${innerCopperFiles.length}`,\n `底铜: ${bottomCopperFiles.length}`,\n `顶阻焊: ${topMaskFiles.length}`,\n `底阻焊: ${bottomMaskFiles.length}`,\n `顶丝印: ${topSilkFiles.length}`,\n `底丝印: ${bottomSilkFiles.length}`,\n `钻孔: ${drillFiles.length}`\n );\n \n // Helper to parse regular layers\n const parseLayer = async (file) => {\n const res = await GerberParser.parseFile(file, '#ffffff');\n return res; // Return full result object with units\n };\n\n const processLayerGroup = async (files, renderer, z, isTop) => {\n for (const file of files) {\n try {\n console.log(`[3D-new] 正在解析文件: ${file.name}`);\n const res = await parseLayer(file);\n if (res && res.data) {\n console.log(`[3D-new] 解析成功: ${file.name}, 单位: ${res.units}`);\n // Check units for scaling\n let scale = 1.0;\n // Outline is always in MM. If this layer is in Inch, scale by 25.4.\n if (res.units === 'in' || res.units === 'inch') {\n scale = 25.4;\n }\n // 🎯 传入整个 res 对象,包含 data 和 plotResult\n renderer.call(this, [res], z, isTop, scale);\n } else {\n console.warn(`[3D-new] 解析失败或无数据: ${file.name}`);\n }\n } catch (e) {\n console.error(`[3D-new] 解析图层出错: ${file.name}`, e);\n console.error(`[3D-new] 错误堆栈:`, e.stack);\n }\n }\n };\n\n const halfThick = BOARD_THICKNESS / 2;\n // Increase spacing to prevent Z-fighting\n const layerSpacing = 0.05; \n\n const zTopCu = halfThick + layerSpacing;\n const zBotCu = -halfThick - layerSpacing;\n await processLayerGroup(topCopperFiles, this.renderCopperLayer, zTopCu, true);\n\n innerCopperFiles.sort((a, b) => {\n const sa = getLayerType(a.name) || '';\n const sb = getLayerType(b.name) || '';\n const ma = sa.match(/^SIG(\\d+)$/i);\n const mb = sb.match(/^SIG(\\d+)$/i);\n return (ma ? parseInt(ma[1], 10) : 0) - (mb ? parseInt(mb[1], 10) : 0);\n });\n const nInner = innerCopperFiles.length;\n for (let i = 0; i < nInner; i++) {\n const t = (i + 1) / (nInner + 1);\n const zInner = zTopCu - t * (zTopCu - zBotCu);\n await processLayerGroup([innerCopperFiles[i]], this.renderCopperLayer, zInner, zInner >= 0);\n }\n\n await processLayerGroup(bottomCopperFiles, this.renderCopperLayer, zBotCu, false);\n \n await processLayerGroup(topMaskFiles, this.renderMaskLayer, halfThick + layerSpacing * 2, true);\n await processLayerGroup(bottomMaskFiles, this.renderMaskLayer, -halfThick - layerSpacing * 2, false);\n\n await processLayerGroup(topPasteFiles, this.renderPasteLayer, halfThick + layerSpacing * 2.5, true);\n await processLayerGroup(bottomPasteFiles, this.renderPasteLayer, -halfThick - layerSpacing * 2.5, false);\n\n await processLayerGroup(topSilkFiles, this.renderSilkscreenLayer, halfThick + layerSpacing * 3, true);\n await processLayerGroup(bottomSilkFiles, this.renderSilkscreenLayer, -halfThick - layerSpacing * 3, false);\n\n // Render PHO files separately\n await this.renderPhoFiles(gerberFiles, halfThick, layerSpacing);\n\n // Drills\n // 若钻孔层与板子范围(轮廓/已渲染层)明显错位,则跳过渲染钻孔层,避免“漂移钻孔”污染视图\n let drillRefBbox = null;\n if (this.outlineBbox && !this.outlineBbox.isEmpty()) {\n drillRefBbox = this.outlineBbox.clone();\n } else if (this.baseGroup.children.length > 0) {\n drillRefBbox = new THREE.Box3().setFromObject(this.baseGroup);\n }\n const expandedDrillRefBbox = drillRefBbox ? drillRefBbox.clone().expandByScalar(20) : null; // 20mm 容错\n\n for (const file of drillFiles) {\n try {\n const res = await parseLayer(file);\n if (res && res.data) {\n let scale = 1.0;\n if (res.units === 'in' || res.units === 'inch') {\n scale = 25.4;\n // debugLog(`[Unit Scale] Scaling drill ${file.name} by 25.4 (Inch -> MM)`);\n }\n\n // 明显错位检测与修正\n if (expandedDrillRefBbox) {\n debugLog(`[Drill] 处理 ${file.name}...`);\n \n // 应用钻孔对齐修正\n const fixResult = this.fixDrillLayerAlignment(res.data, scale, drillRefBbox);\n scale = fixResult.scale;\n \n if (!fixResult.success || !fixResult.bbox) {\n debugWarn(`[Drill] ${file.name} 修正失败,跳过渲染`);\n continue;\n }\n \n const drillBbox = fixResult.bbox;\n\n // 验证修正后的钻孔层位置\n if (!this.validateDrillBbox(drillBbox, drillRefBbox, expandedDrillRefBbox, file.name)) {\n continue;\n }\n }\n\n this.renderDrillLayer([res.data], scale);\n }\n } catch (e) {\n console.error(`Error processing drill ${file.name}:`, e);\n }\n }\n \n const endTimeOtherLayers = performance.now()\n console.log(`[性能] 其他图层渲染完成,耗时: ${(endTimeOtherLayers - startTimeOtherLayers).toFixed(2)}ms`)\n\n console.log('[性能] 开始相机适配...')\n const startTimeCamera = performance.now()\n \n // Fit camera to all rendered objects\n // Priority: 1. Outline layer bbox (if valid), 2. GTO/GTL layer bbox (if outline is missing or differs significantly), 3. All layers\n if (this.baseGroup.children.length > 0) {\n let finalBbox = null;\n \n // 调试:检查outlineBbox状态\n if (this.outlineBbox) {\n if (this.outlineBbox.isEmpty()) {\n debugLog('[Camera] outlineBbox存在但为空');\n } else {\n const size = this.outlineBbox.getSize(new THREE.Vector3());\n const center = this.outlineBbox.getCenter(new THREE.Vector3());\n debugLog(`[Camera] outlineBbox状态: 尺寸=${size.x.toFixed(2)} x ${size.y.toFixed(2)}, 中心=(${center.x.toFixed(2)}, ${center.y.toFixed(2)})`);\n }\n } else {\n debugLog('[Camera] outlineBbox不存在');\n }\n \n // 优先使用轮廓层bbox(如果有且有效)\n if (this.outlineBbox && !this.outlineBbox.isEmpty()) {\n finalBbox = this.outlineBbox;\n const size = finalBbox.getSize(new THREE.Vector3());\n const center = finalBbox.getCenter(new THREE.Vector3());\n debugLog(`[Camera] 使用轮廓层bbox进行自适应: 尺寸=${size.x.toFixed(2)} x ${size.y.toFixed(2)}, 中心=(${center.x.toFixed(2)}, ${center.y.toFixed(2)})`);\n this.fitCameraToBbox(finalBbox);\n } else {\n // 没有轮廓层bbox,计算GTL和GBL层的bbox(用于自适应判断)\n let gtlBbox = null;\n let gblBbox = null;\n \n // 计算GTL层bbox(顶层铜层)\n if (topCopperFiles.length > 0) {\n try {\n const res = await parseLayer(topCopperFiles[0]);\n if (res && res.data) {\n gtlBbox = this.calculateLayerBbox([res.data]);\n }\n } catch (e) {\n // Ignore errors\n }\n }\n \n // 计算GBL层bbox(底层铜层)\n if (bottomCopperFiles.length > 0) {\n try {\n const res = await parseLayer(bottomCopperFiles[0]);\n if (res && res.data) {\n gblBbox = this.calculateLayerBbox([res.data]);\n }\n } catch (e) {\n // Ignore errors\n }\n }\n \n // 选择GTL或GBL的bbox(优先GTL)\n const referenceBbox = gtlBbox && !gtlBbox.isEmpty() ? gtlBbox : (gblBbox && !gblBbox.isEmpty() ? gblBbox : null);\n \n if (referenceBbox) {\n finalBbox = referenceBbox;\n const size = finalBbox.getSize(new THREE.Vector3());\n const center = finalBbox.getCenter(new THREE.Vector3());\n const layerName = gtlBbox && !gtlBbox.isEmpty() ? 'GTL' : 'GBL';\n debugLog(`[Camera] 无轮廓层,使用${layerName}层bbox进行自适应: 尺寸=${size.x.toFixed(2)} x ${size.y.toFixed(2)}, 中心=(${center.x.toFixed(2)}, ${center.y.toFixed(2)})`);\n this.fitCameraToBbox(finalBbox);\n } else if (fallbackLayerForCamera) {\n // 计算fallback层的bbox\n try {\n const res = await parseLayer(fallbackLayerForCamera.files[0]);\n if (res && res.data) {\n const bbox = this.calculateLayerBbox([res.data]);\n if (bbox && !bbox.isEmpty()) {\n finalBbox = bbox;\n const size = finalBbox.getSize(new THREE.Vector3());\n const center = finalBbox.getCenter(new THREE.Vector3());\n debugLog(`[Camera] 使用${fallbackLayerForCamera.type}层bbox进行自适应: 尺寸=${size.x.toFixed(2)} x ${size.y.toFixed(2)}, 中心=(${center.x.toFixed(2)}, ${center.y.toFixed(2)})`);\n this.fitCameraToBbox(finalBbox);\n } else {\n debugLog('[Camera] 未找到有效bbox,使用所有图层进行自适应');\n this.fitCameraToObject(this.baseGroup);\n }\n } else {\n debugLog('[Camera] 未找到有效bbox,使用所有图层进行自适应');\n this.fitCameraToObject(this.baseGroup);\n }\n } catch (e) {\n debugLog('[Camera] 未找到有效bbox,使用所有图层进行自适应');\n this.fitCameraToObject(this.baseGroup);\n }\n } else {\n // Final fallback: use all layers\n debugLog('[Camera] 未找到有效bbox,使用所有图层进行自适应');\n this.fitCameraToObject(this.baseGroup);\n }\n }\n \n const endTimeCamera = performance.now()\n console.log(`[性能] 相机适配完成,耗时: ${(endTimeCamera - startTimeCamera).toFixed(2)}ms`)\n \n // Show scene after rendering is complete\n if (this.renderer && this.renderer.domElement) {\n this.renderer.domElement.style.visibility = 'visible';\n }\n \n const endTimeTotal = performance.now()\n const totalProcessTime = (endTimeTotal - startTimeTotal) / 1000\n console.log(`[性能] ========== processFiles 完成,总耗时: ${totalProcessTime.toFixed(2)}秒 ==========`)\n console.log(`[性能] 详细耗时:解压=${((endTimeExtract-startTimeExtract)/1000).toFixed(2)}秒, 分类=${((endTimeClassify-startTimeClassify)/1000).toFixed(2)}秒, 轮廓=${((endTimeOutline-startTimeOutline)/1000).toFixed(2)}秒, 其他图层=${((endTimeOtherLayers-startTimeOtherLayers)/1000).toFixed(2)}秒, 相机=${((endTimeCamera-startTimeCamera)/1000).toFixed(2)}秒`)\n console.log(`[3D-new] 渲染完成,场景中共有 ${this.baseGroup.children.length} 个对象`);\n } else {\n console.warn('[3D-new] 没有渲染任何图层,baseGroup 为空');\n // Show scene even if nothing rendered\n if (this.renderer && this.renderer.domElement) {\n this.renderer.domElement.style.visibility = 'visible';\n }\n \n const endTimeTotal = performance.now()\n const totalProcessTime = (endTimeTotal - startTimeTotal) / 1000\n console.log(`[性能] ========== processFiles 完成(无渲染),总耗时: ${totalProcessTime.toFixed(2)}秒 ==========`)\n }\n }\n\n clearScene() {\n while (this.baseGroup.children.length) {\n const obj = this.baseGroup.children.pop();\n obj.geometry?.dispose?.();\n obj.material?.dispose?.();\n }\n }\n\n renderOutlineBoard(shapes, showEdges = true) {\n this.clearScene();\n\n // 先计算所有形状的 bbox(包括小形状),用于相机适配\n const allPointsForBbox = [];\n shapes.forEach(shape => {\n const points = shape.getPoints();\n if (points && points.length > 0) {\n allPointsForBbox.push(...points.map(p => new THREE.Vector3(p.x, p.y, 0)));\n }\n });\n \n if (allPointsForBbox.length > 0) {\n const bbox = new THREE.Box3().setFromPoints(allPointsForBbox);\n // Store outline bbox for camera fitting (即使没有有效形状也要设置)\n this.outlineBbox = bbox.clone();\n if (!this.outlineBbox.isEmpty()) {\n const size = this.outlineBbox.getSize(new THREE.Vector3());\n const center = this.outlineBbox.getCenter(new THREE.Vector3());\n debugLog(`[轮廓层] 设置outlineBbox: 尺寸=${size.x.toFixed(2)} x ${size.y.toFixed(2)}, 中心=(${center.x.toFixed(2)}, ${center.y.toFixed(2)})`);\n } else {\n debugWarn('[轮廓层] outlineBbox为空,可能无法正确自适应');\n }\n }\n\n // 过滤极小形状(用于渲染)\n const validShapes = shapes.filter(s => {\n const area = THREE.ShapeUtils.area(s.getPoints());\n return Math.abs(area) > 0.001; \n });\n\n if (validShapes.length === 0) {\n // debugWarn('所有提取的形状面积过小,无法渲染轮廓层,继续渲染其他图层。');\n return;\n }\n\n // 自适应单位/厚度 - 使用有效形状计算厚度\n const allPoints = [];\n validShapes.forEach(shape => {\n allPoints.push(...shape.getPoints().map(p => new THREE.Vector3(p.x, p.y, 0)));\n });\n const bbox = new THREE.Box3().setFromPoints(allPoints);\n\n const size = new THREE.Vector3();\n bbox.getSize(size);\n const maxDim = Math.max(size.x, size.y);\n \n // Adaptive thickness based on size\n if (maxDim < 20.0) {\n BOARD_THICKNESS = 0.063 * 25.4; // Assume the board IS small (mm), so use 1.6mm approx\n // Wait, if OutlineParser always returns MM, maxDim < 20.0 means the board is < 20mm. \n // A 20mm board is plausible.\n // If the file was INCH but processed as MM, a 5x5 inch board would be 5x5 mm.\n // But GerberOutlineParser converts INCH to MM. So maxDim IS in MM.\n \n // Standard PCB Thickness is usually 1.6mm.\n BOARD_THICKNESS = 1.6;\n } else {\n BOARD_THICKNESS = 1.6; // mm\n }\n // debugLog(`Board Max Dim (MM): ${maxDim.toFixed(2)}, Thickness set to ${BOARD_THICKNESS}mm`);\n\n const material = this.getCachedMaterial('outline-fill', () =>\n new THREE.MeshPhysicalMaterial({\n color: COLORS.OUTLINE,\n metalness: 0.0,\n roughness: 0.8,\n side: THREE.DoubleSide\n })\n );\n\n const edgeMat = this.getCachedMaterial('outline-edge', () =>\n new THREE.MeshBasicMaterial({ color: COLORS.OUTLINE_EDGE, side: THREE.DoubleSide })\n );\n\n // 辅助函数:将点序列转换为有宽度的矩形 Mesh(确保线条可见)\n const createThickLineLoop = (points, z, width = 0.10) => {\n if (points.length < 2) return null;\n \n // 检查点序列是否已经闭合(首尾点是否相同或非常接近)\n const first = points[0];\n const last = points[points.length - 1];\n const isClosed = Math.hypot(first.x - last.x, first.y - last.y) < 1e-4;\n \n // 如果已经闭合,去掉最后一个重复点,避免重复连接\n const workingPoints = isClosed && points.length > 2 ? points.slice(0, -1) : points;\n if (workingPoints.length < 2) return null;\n \n const vertices = [];\n const indices = [];\n let baseIndex = 0;\n \n // 处理所有相邻点对,最后一个点连接到第一个点(形成闭合环)\n for (let i = 0; i < workingPoints.length; i++) {\n const p1 = workingPoints[i];\n const p2 = workingPoints[(i + 1) % workingPoints.length];\n \n const dx = p2.x - p1.x;\n const dy = p2.y - p1.y;\n const len = Math.sqrt(dx * dx + dy * dy);\n if (len < 1e-6) continue; // 跳过零长度线段\n \n const perpX = -dy / len * (width / 2);\n const perpY = dx / len * (width / 2);\n \n const p1x = p1.x + perpX;\n const p1y = p1.y + perpY;\n const p2x = p1.x - perpX;\n const p2y = p1.y - perpY;\n const p3x = p2.x - perpX;\n const p3y = p2.y - perpY;\n const p4x = p2.x + perpX;\n const p4y = p2.y + perpY;\n \n vertices.push(p1x, p1y, z);\n vertices.push(p2x, p2y, z);\n vertices.push(p3x, p3y, z);\n vertices.push(p4x, p4y, z);\n \n indices.push(baseIndex, baseIndex + 1, baseIndex + 2);\n indices.push(baseIndex, baseIndex + 2, baseIndex + 3);\n baseIndex += 4;\n }\n \n if (vertices.length === 0) return null;\n \n const geo = new THREE.BufferGeometry();\n geo.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));\n geo.setIndex(indices);\n geo.computeVertexNormals();\n \n return new THREE.Mesh(geo, edgeMat);\n };\n\n // 🚀 使用earcut三角化代替ExtrudeGeometry,支持更多点数的复杂轮廓\n const triangulateWithEarcut = (shape) => {\n const points = shape.getPoints();\n if (points.length < 3) return null;\n \n // 准备earcut输入\n const vertices = [];\n for (const pt of points) {\n vertices.push(pt.x, pt.y);\n }\n \n // 处理孔洞\n const holeIndices = [];\n if (shape.holes && shape.holes.length > 0) {\n for (const hole of shape.holes) {\n const holePts = hole.getPoints();\n if (holePts.length >= 3) {\n holeIndices.push(vertices.length / 2);\n for (const pt of holePts) {\n vertices.push(pt.x, pt.y);\n }\n }\n }\n }\n \n // 调用earcut\n let triangleIndices;\n try {\n triangleIndices = earcut(vertices, holeIndices.length > 0 ? holeIndices : null, 2);\n } catch (err) {\n debugWarn('[Outline] earcut失败:', err.message);\n return null;\n }\n \n if (!triangleIndices || triangleIndices.length === 0) {\n return null;\n }\n \n // 构建3D几何体(顶面、底面、侧面)\n const topZ = BOARD_THICKNESS / 2;\n const bottomZ = -BOARD_THICKNESS / 2;\n \n // 顶点数组:顶面 + 底面\n const positions = [];\n const indices = [];\n const numVertices2D = vertices.length / 2;\n \n // 添加顶面和底面顶点\n for (let i = 0; i < numVertices2D; i++) {\n const x = vertices[i * 2];\n const y = vertices[i * 2 + 1];\n // 顶面顶点\n positions.push(x, y, topZ);\n }\n for (let i = 0; i < numVertices2D; i++) {\n const x = vertices[i * 2];\n const y = vertices[i * 2 + 1];\n // 底面顶点\n positions.push(x, y, bottomZ);\n }\n \n // 顶面三角形索引\n for (let i = 0; i < triangleIndices.length; i += 3) {\n indices.push(triangleIndices[i], triangleIndices[i + 1], triangleIndices[i + 2]);\n }\n \n // 底面三角形索引(反向绕序)\n for (let i = 0; i < triangleIndices.length; i += 3) {\n const a = triangleIndices[i] + numVertices2D;\n const b = triangleIndices[i + 1] + numVertices2D;\n const c = triangleIndices[i + 2] + numVertices2D;\n indices.push(a, c, b); // 反向\n }\n \n // 侧面:只处理外轮廓边缘(不处理孔洞边缘以简化)\n const outerPointCount = holeIndices.length > 0 ? holeIndices[0] : numVertices2D;\n for (let i = 0; i < outerPointCount; i++) {\n const next = (i + 1) % outerPointCount;\n const topA = i;\n const topB = next;\n const bottomA = i + numVertices2D;\n const bottomB = next + numVertices2D;\n // 两个三角形组成一个矩形侧面\n indices.push(topA, bottomA, topB);\n indices.push(topB, bottomA, bottomB);\n }\n \n const geometry = new THREE.BufferGeometry();\n geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));\n geometry.setIndex(indices);\n geometry.computeVertexNormals();\n \n return geometry;\n };\n \n // 渲染所有形状\n const MAX_POINTS_FOR_EXTRUDE = 500; // ExtrudeGeometry的限制\n const MAX_POINTS_FOR_EARCUT = 5000; // earcut的限制(与home 2D仿真一致)\n let renderedCount = 0;\n let skippedComplexCount = 0;\n \n validShapes.forEach(shape => {\n try {\n const points = shape.getPoints();\n \n // 根据点数选择不同的渲染方式\n if (points.length <= MAX_POINTS_FOR_EXTRUDE) {\n // 点数少,使用ExtrudeGeometry(效果更好)\n const geo = new THREE.ExtrudeGeometry(shape, { depth: BOARD_THICKNESS, bevelEnabled: false });\n geo.translate(0, 0, -BOARD_THICKNESS / 2);\n const mesh = new THREE.Mesh(geo, material);\n this.baseGroup.add(mesh);\n renderedCount++;\n } else if (points.length <= MAX_POINTS_FOR_EARCUT) {\n // 点数较多,使用earcut三角化\n const geo = triangulateWithEarcut(shape);\n if (geo) {\n const mesh = new THREE.Mesh(geo, material);\n this.baseGroup.add(mesh);\n renderedCount++;\n debugLog(`[Outline] 使用earcut渲染复杂形状(${points.length}点)`);\n } else {\n skippedComplexCount++;\n }\n } else {\n debugWarn(`[Outline] 形状过于复杂(${points.length}点 > ${MAX_POINTS_FOR_EARCUT}),跳过`);\n skippedComplexCount++;\n return;\n }\n\n // 边框线(若是强制闭合的形状,不画边框以避免长对角线视觉干扰)\n if (showEdges && !shape.userData?.forcedClose) {\n const EDGE_Z_TOP = BOARD_THICKNESS / 2 + 0.05;\n const EDGE_Z_BOTTOM = -BOARD_THICKNESS / 2 - 0.05 + 0.001;\n const pts2 = shape.getPoints();\n const thickTop = createThickLineLoop(pts2, EDGE_Z_TOP);\n const thickBottom = createThickLineLoop(pts2, EDGE_Z_BOTTOM);\n if (thickTop) this.baseGroup.add(thickTop);\n if (thickBottom) this.baseGroup.add(thickBottom);\n }\n\n // 渲染孔洞边框\n if (showEdges && shape.holes && shape.holes.length > 0) {\n shape.holes.forEach(path => {\n const EDGE_Z_TOP = BOARD_THICKNESS / 2 + 0.05;\n const EDGE_Z_BOTTOM = -BOARD_THICKNESS / 2 - 0.05 + 0.001;\n const hPts2 = path.getPoints();\n const thickHoleTop = createThickLineLoop(hPts2, EDGE_Z_TOP);\n const thickHoleBottom = createThickLineLoop(hPts2, EDGE_Z_BOTTOM);\n if (thickHoleTop) this.baseGroup.add(thickHoleTop);\n if (thickHoleBottom) this.baseGroup.add(thickHoleBottom);\n });\n }\n } catch (err) {\n debugWarn(`[Outline] 渲染失败:`, err.message);\n skippedComplexCount++;\n }\n });\n \n // 显示跳过的形状数量\n if (skippedComplexCount > 0) {\n debugWarn(`[Outline] 跳过了 ${skippedComplexCount} 个形状`);\n }\n \n // 如果所有形状都被跳过,使用bbox兜底\n if (renderedCount === 0 && validShapes.length > 0) {\n debugWarn('[Outline] 所有形状都被跳过,使用bbox兜底');\n const bboxShape = this.buildBBoxShapeFromShapes(validShapes);\n if (bboxShape) {\n try {\n const geo = new THREE.ExtrudeGeometry(bboxShape, { depth: BOARD_THICKNESS, bevelEnabled: false });\n geo.translate(0, 0, -BOARD_THICKNESS / 2);\n const mesh = new THREE.Mesh(geo, material);\n this.baseGroup.add(mesh);\n } catch (err) {\n debugWarn('[Outline] bbox兜底也失败:', err.message);\n }\n }\n }\n\n // Store outline bbox for camera fitting (will be used after all layers are rendered)\n // Don't fit camera here, wait until all layers are rendered\n }\n\n // 基于线段点集求凸包,生成单一 Shape 兜底\n buildHullShapeFromSegments(segments) {\n if (!segments || segments.length === 0) return null;\n const pts = [];\n for (const seg of segments) {\n pts.push(new THREE.Vector2(seg.start.x, seg.start.y));\n pts.push(new THREE.Vector2(seg.end.x, seg.end.y));\n }\n if (pts.length < 3) return null;\n\n pts.sort((a, b) => (a.x === b.x ? a.y - b.y : a.x - b.x));\n const cross = (o, a, b) => (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x);\n const lower = [];\n for (const p of pts) {\n while (lower.length >= 2 && cross(lower[lower.length - 2], lower[lower.length - 1], p) <= 0) {\n lower.pop();\n }\n lower.push(p);\n }\n const upper = [];\n for (let i = pts.length - 1; i >= 0; i--) {\n const p = pts[i];\n while (upper.length >= 2 && cross(upper[upper.length - 2], upper[upper.length - 1], p) <= 0) {\n upper.pop();\n }\n upper.push(p);\n }\n upper.pop();\n lower.pop();\n const hull = lower.concat(upper);\n if (hull.length < 3) return null;\n\n const shape = new THREE.Shape();\n shape.moveTo(hull[0].x, hull[0].y);\n for (let i = 1; i < hull.length; i++) shape.lineTo(hull[i].x, hull[i].y);\n shape.closePath();\n return shape;\n }\n\n // 基于已存在的闭合 shapes 计算外接矩形,作为兜底\n buildBBoxShapeFromShapes(shapes) {\n if (!shapes || shapes.length === 0) return null;\n let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;\n for (const s of shapes) {\n const pts = s.getPoints();\n for (const p of pts) {\n if (p.x < minX) minX = p.x;\n if (p.x > maxX) maxX = p.x;\n if (p.y < minY) minY = p.y;\n if (p.y > maxY) maxY = p.y;\n }\n }\n if (!isFinite(minX) || !isFinite(maxX) || !isFinite(minY) || !isFinite(maxY)) return null;\n const shape = new THREE.Shape();\n shape.moveTo(minX, minY);\n shape.lineTo(maxX, minY);\n shape.lineTo(maxX, maxY);\n shape.lineTo(minX, maxY);\n shape.closePath();\n return shape;\n }\n\n // 基于线段集合计算外接矩形,用于兜底渲染和相机适配\n buildBBoxShapeFromSegments(segments) {\n if (!segments || segments.length === 0) return null;\n let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;\n for (const seg of segments) {\n if (seg.start.x < minX) minX = seg.start.x;\n if (seg.start.x > maxX) maxX = seg.start.x;\n if (seg.start.y < minY) minY = seg.start.y;\n if (seg.start.y > maxY) maxY = seg.start.y;\n if (seg.end.x < minX) minX = seg.end.x;\n if (seg.end.x > maxX) maxX = seg.end.x;\n if (seg.end.y < minY) minY = seg.end.y;\n if (seg.end.y > maxY) maxY = seg.end.y;\n }\n if (!isFinite(minX) || !isFinite(maxX) || !isFinite(minY) || !isFinite(maxY)) return null;\n const shape = new THREE.Shape();\n shape.moveTo(minX, minY);\n shape.lineTo(maxX, minY);\n shape.lineTo(maxX, maxY);\n shape.lineTo(minX, maxY);\n shape.closePath();\n return shape;\n }\n\n // 兜底:用线段直接画轮廓(G01/G02/G03 离散后),不做布尔运算\n renderOutlineStrokes(segments, lineWidth = 0.10, color = COLORS.OUTLINE_EDGE, zOverride = null) {\n if (!segments || segments.length === 0) return;\n\n // 计算 bbox,用于相机适配\n const points = [];\n segments.forEach(seg => {\n points.push(new THREE.Vector3(seg.start.x, seg.start.y, 0));\n points.push(new THREE.Vector3(seg.end.x, seg.end.y, 0));\n });\n if (points.length > 0) {\n const bbox = new THREE.Box3().setFromPoints(points);\n if (!this.outlineBbox || this.outlineBbox.isEmpty()) {\n this.outlineBbox = bbox.clone();\n }\n }\n\n const key = `outline-stroke-${color.toString(16)}-${lineWidth}`;\n const edgeMat = this.getCachedMaterial(key, () =>\n new THREE.MeshBasicMaterial({ color, side: THREE.DoubleSide })\n );\n\n // 将线段转换为有宽度的矩形 Mesh(确保可见)\n const LINE_WIDTH = lineWidth; // 可调宽度\n const vertices = [];\n const indices = [];\n let baseIndex = 0;\n const z = (typeof zOverride === 'number') ? zOverride : (BOARD_THICKNESS / 2 + 0.05); // 默认绘制在顶面上方\n\n for (const seg of segments) {\n const x1 = seg.start.x;\n const y1 = seg.start.y;\n const x2 = seg.end.x;\n const y2 = seg.end.y;\n \n const dx = x2 - x1;\n const dy = y2 - y1;\n const len = Math.sqrt(dx * dx + dy * dy);\n if (len < 1e-6) continue;\n \n const perpX = -dy / len * (LINE_WIDTH / 2);\n const perpY = dx / len * (LINE_WIDTH / 2);\n \n const p1x = x1 + perpX;\n const p1y = y1 + perpY;\n const p2x = x1 - perpX;\n const p2y = y1 - perpY;\n const p3x = x2 - perpX;\n const p3y = y2 - perpY;\n const p4x = x2 + perpX;\n const p4y = y2 + perpY;\n \n vertices.push(p1x, p1y, z);\n vertices.push(p2x, p2y, z);\n vertices.push(p3x, p3y, z);\n vertices.push(p4x, p4y, z);\n \n indices.push(baseIndex, baseIndex + 1, baseIndex + 2);\n indices.push(baseIndex, baseIndex + 2, baseIndex + 3);\n baseIndex += 4;\n }\n \n if (vertices.length === 0) return;\n \n const geo = new THREE.BufferGeometry();\n geo.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));\n geo.setIndex(indices);\n geo.computeVertexNormals();\n \n const mesh = new THREE.Mesh(geo, edgeMat);\n this.baseGroup.add(mesh);\n }\n\n // ==================== OTHER LAYER RENDERING ====================\n\n renderCopperLayer(layers, z, isTop, scale = 1.0) {\n // 从 lineStrips 提取所有形状(包括孔洞)\n const allShapes = [];\n \n for (const layer of layers) {\n const webglData = layer.data || layer;\n \n if (webglData.lineStrips && webglData.vertices) {\n for (const strip of webglData.lineStrips) {\n if (strip.count < 2) continue;\n\n const pts = [];\n for (let j = 0; j < strip.count; j++) {\n const ptr = (strip.start + j) * 3;\n pts.push(new THREE.Vector2(webglData.vertices[ptr], -webglData.vertices[ptr + 1]));\n }\n if (pts.length < 2) continue;\n\n const first = pts[0];\n const last = pts[pts.length - 1];\n const isClosed = first.distanceTo(last) < 0.001;\n\n if (!isClosed) continue; // 铜层只处理闭合形状\n\n // Remove duplicated closing point if present\n if (pts.length > 2 && first.distanceTo(last) < 1e-9) {\n pts.pop();\n }\n if (pts.length < 3) continue;\n\n const shape = new THREE.Shape();\n shape.moveTo(pts[0].x, pts[0].y);\n for (let i = 1; i < pts.length; i++) {\n shape.lineTo(pts[i].x, pts[i].y);\n }\n shape.closePath();\n \n allShapes.push(shape);\n }\n }\n }\n \n if (allShapes.length === 0) return;\n\n // ⚠️ 重要:铜层不能复用丝印的“嵌套=孔洞”启发式。\n // 原因:铜层大量“包含关系”只是重叠/靠近(焊盘/走线/覆铜),不是孔洞。\n // 用 processSilkscreenHoles 会把这些内部形状误当孔洞,导致“错误的形状/缺块/反相”。\n // 铜层如果要支持 Gerber 的 clear polarity(避空/开窗),需要基于 plotResult.polarity 做布尔/模板,\n // 这里先保证几何不被误挖空:直接渲染所有闭合形状即可(叠加效果正确、不会出现假孔洞)。\n const shapesToRender = allShapes;\n\n // 计算所有形状的面积并找出最大面积\n const shapesWithArea = shapesToRender.map((shape, idx) => {\n const pts = shape.getPoints();\n const area = Math.abs(THREE.ShapeUtils.area(pts));\n return { shape, area, idx, pointCount: pts.length };\n });\n \n // 按面积排序(降序)\n shapesWithArea.sort((a, b) => b.area - a.area);\n \n // 找出最大面积\n const maxArea = shapesWithArea[0]?.area || 0;\n \n // 过滤:跳过面积超过总形状面积 40% 的\"铜皮\"形状\n // 这些通常是覆盖整个板子的 ground plane\n // 🎯 暂时禁用此过滤,因为可能会误过滤掉正常的大铜皮区域\n // const totalArea = shapesWithArea.reduce((sum, s) => sum + s.area, 0);\n // const areaThreshold = totalArea * 0.4;\n \n // const filteredShapes = shapesWithArea.filter(s => {\n // const isGroundPlane = s.area > areaThreshold && s.area === maxArea;\n // return !isGroundPlane;\n // });\n \n const filteredShapes = shapesWithArea; // 不过滤,渲染所有形状\n \n if (filteredShapes.length === 0) return;\n\n const shapes = filteredShapes.map(s => s.shape);\n\n const material = this.getCachedMaterial(isTop ? 'copper-top' : 'copper-bot', () =>\n new THREE.MeshPhysicalMaterial({\n color: COLORS.COPPER,\n metalness: 0.3,\n roughness: 0.5,\n side: THREE.DoubleSide\n })\n );\n\n this.renderShapesInChunks(shapes, material, z, scale, 2000, isTop ? 'GTL' : 'GBL');\n }\n\n renderMaskLayer(layers, z, isTop, scale = 1.0) {\n const shapes = this.collectStandardShapes(layers);\n if (shapes.length === 0) return;\n\n // Render Openings as Gold (exposed copper)\n const material = this.getCachedMaterial('mask-opening', () =>\n new THREE.MeshPhysicalMaterial({\n color: COLORS.GOLD,\n metalness: 0.8,\n roughness: 0.2,\n side: THREE.DoubleSide\n })\n );\n\n // Raise slightly above copper\n this.renderShapesInChunks(shapes, material, z + 0.001, scale);\n }\n\n renderPasteLayer(layers, z, isTop, scale = 1.0) {\n const shapes = this.collectStandardShapes(layers);\n if (shapes.length === 0) return;\n\n const material = this.getCachedMaterial('paste', () =>\n new THREE.MeshPhysicalMaterial({\n color: COLORS.PASTE, // Gray color for solder paste\n metalness: 0.3,\n roughness: 0.7,\n side: THREE.DoubleSide\n })\n );\n\n this.renderShapesInChunks(shapes, material, z, scale);\n }\n\n renderSilkscreenLayer(layers, z, isTop, scale = 1.0) {\n // 重要:silkscreen 的 lineStrips 里混有两类数据:\n // 1) 真实“填充区域”的边界(例如某些文字/标注是 region/flash 的外轮廓)→ 应该填充\n // 2) “描边轨迹”的中心线(圆形标注/字符描边环等)→ 不应该填充,否则会把环内部填死\n //\n // 解决:对闭合 polyline 做一次轻量分类:\n // - 近似圆/椭圆的闭合环:按 stroke ribbon 渲染(保持中空)\n // - 其余闭合轮廓:按填充 Shape 渲染,并用 processSilkscreenHoles 保持字洞\n const openPolylines = [];\n const strokeLoops = []; // closed but should be treated as stroke\n const fillShapes = []; // closed and should be filled\n\n for (const layer of layers) {\n // 兼容两种格式:layer 可能是 res.data(旧) 或 res(新,带 plotResult)\n const webglData = layer.data || layer;\n \n // 从 lineStrips 提取所有闭合和开放路径\n if (webglData.lineStrips && webglData.vertices) {\n for (const strip of webglData.lineStrips) {\n if (strip.count < 2) continue;\n\n const pts = [];\n for (let j = 0; j < strip.count; j++) {\n const ptr = (strip.start + j) * 3;\n pts.push(new THREE.Vector2(webglData.vertices[ptr], -webglData.vertices[ptr + 1]));\n }\n if (pts.length < 2) continue;\n const first = pts[0];\n const last = pts[pts.length - 1];\n const isClosed = first.distanceTo(last) < 0.001;\n\n if (!isClosed) {\n openPolylines.push(pts);\n continue;\n }\n\n // Remove duplicated closing point if present\n if (pts.length > 2 && first.distanceTo(last) < 1e-9) {\n pts.pop();\n }\n if (pts.length < 3) continue;\n\n // 1) 优先使用 parser 标记的 kind(来自 SVG fill/stroke 属性)\n // - fill:进入填充形状(文字/实心标注等)\n // - stroke:进入描边细带(圆环/描边字体/轨迹等)\n if (strip.kind === 'stroke') {\n strokeLoops.push(pts);\n continue;\n }\n if (strip.kind === 'fill') {\n const shape = new THREE.Shape();\n shape.moveTo(pts[0].x, pts[0].y);\n for (let i = 1; i < pts.length; i++) shape.lineTo(pts[i].x, pts[i].y);\n shape.closePath();\n fillShapes.push(shape);\n continue;\n }\n\n // 2) 回退:没有 kind 时才用几何启发式\n // --- classify ellipse-like loops as stroke ---\n // quick ellipse-likeness: normalize by bbox radii, expect r≈1 with small std\n let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;\n for (const p of pts) {\n if (p.x < minX) minX = p.x;\n if (p.x > maxX) maxX = p.x;\n if (p.y < minY) minY = p.y;\n if (p.y > maxY) maxY = p.y;\n }\n const w = maxX - minX;\n const h = maxY - minY;\n const cx = (minX + maxX) / 2;\n const cy = (minY + maxY) / 2;\n const rx = w / 2;\n const ry = h / 2;\n\n let ellipseLike = false;\n if (rx > 1e-6 && ry > 1e-6) {\n let sum = 0;\n let sumSq = 0;\n let n = 0;\n for (const p of pts) {\n const nx = (p.x - cx) / rx;\n const ny = (p.y - cy) / ry;\n const r = Math.sqrt(nx * nx + ny * ny);\n if (!Number.isFinite(r)) continue;\n sum += r;\n sumSq += r * r;\n n++;\n }\n if (n >= 8) {\n const mean = sum / n;\n const varR = Math.max(0, sumSq / n - mean * mean);\n const std = Math.sqrt(varR);\n // mean≈1 且 std 很小 → 近似椭圆/圆\n ellipseLike = (mean > 0.90 && mean < 1.10 && std < 0.03);\n }\n }\n\n if (ellipseLike) {\n strokeLoops.push(pts);\n continue;\n }\n\n // otherwise treat as fill shape\n const shape = new THREE.Shape();\n shape.moveTo(pts[0].x, pts[0].y);\n for (let i = 1; i < pts.length; i++) {\n shape.lineTo(pts[i].x, pts[i].y);\n }\n shape.closePath();\n fillShapes.push(shape);\n }\n }\n }\n\n if (fillShapes.length === 0 && strokeLoops.length === 0 && openPolylines.length === 0) return;\n\n const material = this.getCachedMaterial('silkscreen', () =>\n new THREE.MeshPhysicalMaterial({\n color: COLORS.SILKSCREEN,\n side: THREE.DoubleSide\n })\n );\n\n // 1) Fill shapes (with hole post-processing to keep text counters hollow)\n if (fillShapes.length > 0) {\n const shapesWithHoles = this.processSilkscreenHoles(fillShapes);\n if (shapesWithHoles.length > 0) {\n this.renderShapesInChunks(shapesWithHoles, material, z, scale, 2000, isTop ? 'GTO' : 'GBO');\n }\n }\n\n // 2) Stroke ribbons (open polylines + ellipse-like closed loops)\n // 让描边字/描边圆看起来“更实心”(与 2D Gerber 观感更接近)\n const desiredWidthMm = 0.20;\n const widthInLayerUnits = desiredWidthMm / (scale || 1.0);\n\n const strokeShapes = [];\n const allStrokePolylines = openPolylines.concat(strokeLoops);\n for (const pts of allStrokePolylines) {\n if (pts.length < 2) continue;\n\n const first = pts[0];\n const last = pts[pts.length - 1];\n const isClosed = first.distanceTo(last) < 0.001;\n const n = (isClosed && pts.length > 2 && first.distanceTo(last) < 1e-9) ? (pts.length - 1) : pts.length;\n const segCount = isClosed ? n : (n - 1);\n\n for (let i = 0; i < segCount; i++) {\n const p1 = pts[i];\n const p2 = (isClosed && i === n - 1) ? pts[0] : pts[i + 1];\n const dx = p2.x - p1.x;\n const dy = p2.y - p1.y;\n const len = Math.hypot(dx, dy);\n if (len < 1e-8) continue;\n\n const nx = (-dy / len) * (widthInLayerUnits / 2);\n const ny = (dx / len) * (widthInLayerUnits / 2);\n\n const s = new THREE.Shape();\n s.moveTo(p1.x + nx, p1.y + ny);\n s.lineTo(p2.x + nx, p2.y + ny);\n s.lineTo(p2.x - nx, p2.y - ny);\n s.lineTo(p1.x - nx, p1.y - ny);\n s.closePath();\n strokeShapes.push(s);\n }\n }\n\n if (strokeShapes.length > 0) {\n const zOffset = isTop ? 0.001 : -0.001;\n this.renderShapesInChunks(strokeShapes, material, z + zOffset, scale, 2000, isTop ? 'GTO' : 'GBO');\n }\n }\n\n renderDrillLayer(layers, scale = 1.0) {\n const shapes = this.collectStandardShapes(layers);\n // debugLog(`[Drill Layer] 收集到 ${shapes.length} 个钻孔形状`);\n \n if (shapes.length === 0) {\n // debugWarn('[Drill Layer] 没有收集到钻孔形状,检查数据格式');\n // Debug: Check layer data structure\n // layers.forEach((layer, idx) => {\n // debugLog(`[Drill Layer] Layer ${idx}:`, {\n // hasLineStrips: !!layer.lineStrips,\n // lineStripsCount: layer.lineStrips?.length || 0,\n // hasChildren: !!layer.children,\n // childrenCount: layer.children?.length || 0,\n // verticesCount: layer.vertices?.length || 0\n // });\n // });\n return;\n }\n\n // Render drills as black cylinders passing through the board\n const material = this.getCachedMaterial('drill', () =>\n new THREE.MeshBasicMaterial({ \n color: COLORS.DRILL,\n depthWrite: true,\n depthTest: true\n })\n );\n\n const extrusionSettings = {\n depth: BOARD_THICKNESS + 0.35, // Slightly longer than thickness for visibility, must exceed paste layer\n bevelEnabled: false\n };\n\n const geo = new THREE.ExtrudeGeometry(shapes, extrusionSettings);\n geo.translate(0, 0, -BOARD_THICKNESS / 2 - 0.175); // Center it Z-wise, slightly below board, must exceed paste layer\n\n const mesh = new THREE.Mesh(geo, material);\n mesh.scale.set(scale, scale, 1);\n mesh.renderOrder = 10; // Ensure drills render on top to avoid Z-fighting with paste layer\n this.baseGroup.add(mesh);\n // debugLog(`[Drill Layer] 成功渲染 ${shapes.length} 个钻孔`);\n debugLog(`[Drill Layer] 提取到 ${shapes.length} 个钻孔形状,scale=${scale}`);\n }\n\n /**\n * 专门渲染 .pho 文件的函数\n * 根据文件名前缀和数字识别图层类型,并调用对应的渲染函数\n */\n async renderPhoFiles(gerberFiles, halfThick, layerSpacing) {\n // 筛选出所有 .pho 文件\n const phoFiles = gerberFiles.filter(file => {\n const fileNameOnly = file.name.split(/[/\\\\]/).pop() || '';\n const fileExtension = '.' + fileNameOnly.split('.').pop().toUpperCase();\n return fileExtension === '.PHO';\n });\n\n if (phoFiles.length === 0) return;\n\n // 预处理 .pho 前缀分组:用于判定\"最小编号为上层,其余为下层\"\n const buildPhoGroups = (files) => {\n const groups = new Map(); // prefix -> {min:number}\n const add = (prefix, num) => {\n if (!groups.has(prefix)) {\n groups.set(prefix, { min: num });\n } else {\n groups.get(prefix).min = Math.min(groups.get(prefix).min, num);\n }\n };\n files.forEach(f => {\n const nameOnly = f.name.split(/[/\\\\]/).pop() || '';\n const upper = nameOnly.toUpperCase();\n let prefix = null;\n let num = 0;\n if (upper.startsWith('SST')) {\n prefix = 'sst';\n const m = upper.match(/^SST(\\d+)/);\n num = m ? parseInt(m[1], 10) : 0;\n } else if (upper.startsWith('SMD')) {\n prefix = 'smd';\n const m = upper.match(/^SMD(\\d+)/);\n num = m ? parseInt(m[1], 10) : 0;\n } else if (upper.startsWith('SM')) {\n prefix = 'sm';\n const m = upper.match(/^SM(\\d+)/);\n num = m ? parseInt(m[1], 10) : 0;\n } else if (upper.startsWith('ART')) {\n prefix = 'art';\n const m = upper.match(/^ART(\\d+)/);\n num = m ? parseInt(m[1], 10) : 0;\n } else if (upper.startsWith('SSB')) {\n prefix = 'ssb';\n num = 0;\n } else if (upper.startsWith('DRL')) {\n prefix = 'drl';\n num = 0;\n } else if (upper.startsWith('DD')) {\n prefix = 'dd';\n num = 0;\n }\n if (prefix) add(prefix, num);\n });\n return groups;\n };\n\n const phoGroups = buildPhoGroups(phoFiles);\n\n // 获取图层类型的辅助函数\n const getPhoLayerType = (fileName) => {\n const fileNameOnly = fileName.split(/[/\\\\]/).pop() || '';\n const fileNameUpper = fileNameOnly.toUpperCase();\n \n if (fileNameUpper.startsWith('SST')) return 'GTO';\n \n const pickByGroup = (prefix, topType, botType, defaultType = null) => {\n const m = fileNameUpper.match(new RegExp(`^${prefix}(\\\\d+)`));\n const num = m ? parseInt(m[1], 10) : 0;\n const g = phoGroups.get(prefix.toLowerCase());\n if (g) {\n return num === g.min ? topType : botType;\n }\n return defaultType || topType;\n };\n \n if (fileNameUpper.startsWith('SMD')) {\n return pickByGroup('SMD', 'GTP', 'GBP', 'GTP');\n }\n if (fileNameUpper.startsWith('SM')) {\n return pickByGroup('SM', 'GTS', 'GBS', 'GTS');\n }\n if (fileNameUpper.startsWith('ART')) {\n return pickByGroup('ART', 'GTL', 'GBL', 'GTL');\n }\n if (fileNameUpper.startsWith('SSB')) return 'GBO';\n if (fileNameUpper.startsWith('DRL')) return 'DRL';\n \n return null;\n };\n\n // 按图层类型分组渲染\n for (const file of phoFiles) {\n try {\n const layerType = getPhoLayerType(file.name);\n if (!layerType) continue;\n\n // 使用 GerberParser 解析 pho 文件(它内部使用 web-gerber)\n const res = await GerberParser.parseFile(file, '#ffffff');\n if (!res || !res.data) continue;\n\n // 检查单位并缩放\n let scale = 1.0;\n if (res.units === 'in' || res.units === 'inch') {\n scale = 25.4;\n }\n\n // 根据图层类型调用对应的渲染函数\n switch (layerType) {\n case 'GTL':\n this.renderCopperLayer([res.data], halfThick + layerSpacing, true, scale);\n break;\n case 'GBL':\n this.renderCopperLayer([res.data], -halfThick - layerSpacing, false, scale);\n break;\n case 'GTS':\n this.renderMaskLayer([res.data], halfThick + layerSpacing * 2, true, scale);\n break;\n case 'GBS':\n this.renderMaskLayer([res.data], -halfThick - layerSpacing * 2, false, scale);\n break;\n case 'GTP':\n this.renderPasteLayer([res.data], halfThick + layerSpacing * 2.5, true, scale);\n break;\n case 'GBP':\n this.renderPasteLayer([res.data], -halfThick - layerSpacing * 2.5, false, scale);\n break;\n case 'GTO':\n this.renderSilkscreenLayer([res], halfThick + layerSpacing * 3, true, scale);\n break;\n case 'GBO':\n this.renderSilkscreenLayer([res], -halfThick - layerSpacing * 3, false, scale);\n break;\n case 'DRL':\n this.renderDrillLayer([res.data], scale);\n break;\n }\n } catch (e) {\n console.error(`Error processing PHO file ${file.name}:`, e);\n }\n }\n }\n\n // ==================== HELPERS ====================\n\n collectStandardShapes(layers) {\n const shapes = [];\n for (const layer of layers) {\n // 🎯 兼容两种格式:layer 可能是 res(带 .data) 或 res.data\n const webglData = layer.data || layer;\n \n // 1. LineStrips (Polygons/Paths from SVG)\n if (webglData.lineStrips && webglData.vertices) {\n for (const strip of webglData.lineStrips) {\n if (strip.count < 2) continue;\n \n // 收集所有点\n const points = [];\n for (let j = 0; j < strip.count; j++) {\n const ptr = (strip.start + j) * 3;\n points.push({\n x: webglData.vertices[ptr],\n y: -webglData.vertices[ptr + 1] // Y轴翻转\n });\n }\n \n if (points.length < 2) continue;\n \n // 检查路径是否闭合\n const first = points[0];\n const last = points[points.length - 1];\n const closeDist = Math.sqrt(\n Math.pow(first.x - last.x, 2) + \n Math.pow(first.y - last.y, 2)\n );\n const isClosed = closeDist < 0.001;\n \n // 只处理闭合路径或点数足够多的路径(扩展后的走线)\n if (isClosed || points.length >= 4) {\n const shape = new THREE.Shape();\n shape.moveTo(points[0].x, points[0].y);\n \n for (let j = 1; j < points.length; j++) {\n shape.lineTo(points[j].x, points[j].y);\n }\n \n // 确保形状闭合\n if (!isClosed) {\n shape.lineTo(points[0].x, points[0].y);\n }\n \n // 检查面积是否有效\n const area = Math.abs(THREE.ShapeUtils.area(shape.getPoints()));\n if (area > 0.0001) {\n shapes.push(shape);\n }\n }\n }\n }\n\n // 2. Segments (Standard Gerber primitives)\n if (layer.children) {\n const segments = [];\n for (const child of layer.children) {\n if (child.type === 'imagePath' && child.segments) {\n segments.push(...child.segments);\n }\n }\n if (segments.length > 0) {\n const stitched = this.buildShapesFromSegments(segments);\n shapes.push(...stitched);\n }\n }\n }\n return shapes;\n }\n\n buildShapesFromSegments(segments) {\n if (segments.length === 0) return [];\n \n // Optimization: Pre-compute all points to avoid repeated calculations\n const pool = segments.map(s => ({\n start: new THREE.Vector2(s.start[0], -s.start[1]), // Flip Y for WebGL\n end: new THREE.Vector2(s.end[0], -s.end[1]), // Flip Y\n original: s,\n used: false\n }));\n\n const shapes = [];\n const EPSILON = 0.01;\n const EPSILON_SQ = EPSILON * EPSILON; // Use squared distance for faster comparison\n\n while (true) {\n const startSeg = pool.find(s => !s.used);\n if (!startSeg) break;\n\n startSeg.used = true;\n const currentPath = new THREE.Shape();\n \n currentPath.moveTo(startSeg.start.x, startSeg.start.y);\n this.addSegmentToPath(currentPath, startSeg);\n\n let currentPoint = startSeg.end;\n let loopClosed = false;\n let segmentCount = 0;\n const MAX_SEGMENTS = 10000; // Safety limit to prevent infinite loops\n\n while (!loopClosed && segmentCount < MAX_SEGMENTS) {\n segmentCount++;\n \n // Optimization: Use squared distance comparison (faster)\n let nextSeg = null;\n let minDistSq = EPSILON_SQ;\n \n for (let i = 0; i < pool.length; i++) {\n if (pool[i].used) continue;\n const distSq = currentPoint.distanceToSquared(pool[i].start);\n if (distSq < minDistSq) {\n minDistSq = distSq;\n nextSeg = pool[i];\n }\n }\n \n if (!nextSeg) {\n // Check if we can close the loop\n if (currentPoint.distanceToSquared(startSeg.start) < EPSILON_SQ) {\n loopClosed = true;\n } else {\n break; // Open path, stop\n }\n } else {\n nextSeg.used = true;\n this.addSegmentToPath(currentPath, nextSeg);\n currentPoint = nextSeg.end;\n \n if (currentPoint.distanceToSquared(startSeg.start) < EPSILON_SQ) {\n loopClosed = true;\n }\n }\n }\n \n if (loopClosed) {\n shapes.push(currentPath);\n }\n }\n\n return shapes;\n }\n\n addSegmentToPath(path, seg) {\n const s = seg.original;\n if (s.type === 'line') {\n path.lineTo(seg.end.x, seg.end.y);\n } else if (s.type === 'arc') {\n const cx = s.center[0];\n const cy = -s.center[1]; // Flip Y\n const r = s.radius;\n path.lineTo(seg.end.x, seg.end.y); \n }\n }\n\n // --- Silkscreen helper: attach inner contours as holes to keep text counters hollow ---\n processSilkscreenHoles(shapes) {\n const items = shapes\n .map(s => {\n const points = s.getPoints();\n if (!points || points.length < 3) return null;\n\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;\n for (const p of points) {\n if (p.x < minX) minX = p.x;\n if (p.y < minY) minY = p.y;\n if (p.x > maxX) maxX = p.x;\n if (p.y > maxY) maxY = p.y;\n }\n\n const area = Math.abs(THREE.ShapeUtils.area(points));\n if (!isFinite(area) || area <= 1e-6) return null;\n \n // Convert area from square inches to square millimeters\n // 1 inch = 25.4 mm, so 1 inch² = 645.16 mm²\n const areaInMm2 = area * 645.16;\n\n return { shape: s, points, minX, minY, maxX, maxY, area: areaInMm2, isHole: false };\n })\n .filter(Boolean);\n\n if (items.length === 0) return [];\n\n // Largest first (outer contours first)\n items.sort((a, b) => b.area - a.area);\n\n const roots = [];\n\n for (let i = 0; i < items.length; i++) {\n const child = items[i];\n let parent = null;\n\n // Find the smallest containing parent among larger shapes (already processed earlier in list)\n for (let j = i - 1; j >= 0; j--) {\n const potential = items[j];\n\n // bbox containment quick check\n if (child.minX >= potential.minX && child.maxX <= potential.maxX &&\n child.minY >= potential.minY && child.maxY <= potential.maxY) {\n // point-in-polygon check using child's first point\n if (this.isPointInPolygon(child.points[0], potential.points)) {\n parent = potential;\n break;\n }\n }\n }\n\n if (parent) {\n const ratio = child.area / parent.area;\n \n // 🎯 如果子形状几乎和父形状一样大(ratio > 0.90),这个包含关系很可能是误判\n // 不应该建立这个父子关系,让子形状继续寻找其他可能的父形状\n if (ratio > 0.90) {\n // 不使用当前的parent,继续检查是否有其他更大的父形状\n // 如果找不到其他父形状,子形状会被作为根形状处理\n parent = null;\n }\n }\n \n if (parent) {\n const ratio = child.area / parent.area;\n \n // 🎯 自适应面积比限制:根据子形状的绝对面积调整阈值\n let adaptiveMaxRatio;\n if (child.area > 50) {\n // 大形状(>50mm²):允许高达45%的孔洞(大铜皮挖空)\n // 这些通常是clear极性的挖空区域\n adaptiveMaxRatio = 0.45;\n } else if (child.area > 10) {\n // 中等形状(10-50mm²):最大20%\n adaptiveMaxRatio = 0.20;\n } else if (child.area > 1) {\n // 小形状(1-10mm²):允许高达65%(字符孔洞)\n adaptiveMaxRatio = 0.65;\n } else {\n // 极小形状(<1mm²):允许高达90%(字符孔洞如 \"0\" 的内圆)\n // 提高到90%以匹配全局的\"几乎同大小\"规则\n adaptiveMaxRatio = 0.90;\n }\n \n // Filter out extremely tiny artifacts (noise)\n if (ratio < 0.0005) {\n roots.push(child.shape);\n continue;\n }\n \n // Filter out overly large shapes to prevent large graphics from being treated as holes\n if (ratio > adaptiveMaxRatio) {\n console.log(`[3D孔洞拒绝] ✗ 形状面积=${child.area.toFixed(2)}mm², ratio=${ratio.toFixed(4)} > maxRatio=${adaptiveMaxRatio.toFixed(2)}, 父面积=${parent.area.toFixed(2)}mm²`);\n roots.push(child.shape);\n continue;\n }\n\n if (parent.isHole) {\n // island inside a hole -> treat as new solid root (Three.js doesn't support nested islands in one shape well)\n roots.push(child.shape);\n } else {\n parent.shape.holes.push(child.shape);\n child.isHole = true;\n }\n } else {\n roots.push(child.shape);\n }\n }\n\n return roots;\n }\n\n isPointInPolygon(point, vs) {\n // Ray-casting algorithm for point-in-polygon\n const x = point.x, y = point.y;\n let inside = false;\n for (let i = 0, j = vs.length - 1; i < vs.length; j = i++) {\n const xi = vs[i].x, yi = vs[i].y;\n const xj = vs[j].x, yj = vs[j].y;\n\n const intersect = ((yi > y) !== (yj > y)) &&\n (x < (xj - xi) * (y - yi) / ((yj - yi) || 1e-12) + xi);\n if (intersect) inside = !inside;\n }\n return inside;\n }\n\n renderShapesInChunks(shapes, material, zPosition, scale = 1.0, chunkSize = 2000, layerType = null) {\n if (shapes.length === 0) return [];\n \n const meshes = [];\n \n // Optimization: Adaptive chunk size based on total count\n // Smaller chunks for very large batches to reduce memory pressure\n let optimizedChunkSize = chunkSize;\n if (shapes.length > 20000) {\n optimizedChunkSize = 200; // Further reduced for very large batches\n } else if (shapes.length > 10000) {\n optimizedChunkSize = 400;\n } else if (shapes.length > 5000) {\n optimizedChunkSize = 800;\n }\n \n const useAsync = shapes.length > 3000; // Lower threshold for async rendering\n \n if (useAsync) {\n // Async rendering for large batches to avoid blocking\n this.renderShapesAsync(shapes, material, zPosition, scale, optimizedChunkSize, layerType);\n return []; // Async rendering doesn't return meshes immediately\n } else {\n // Synchronous rendering for smaller batches\n for (let i = 0; i < shapes.length; i += optimizedChunkSize) {\n const chunk = shapes.slice(i, i + optimizedChunkSize);\n // OPTIMIZATION: Reduce curveSegments from default 12 to 3 for better performance\n // This drastically reduces triangle count for text and pads\n const geometry = new THREE.ShapeGeometry(chunk, 3); \n const mesh = new THREE.Mesh(geometry, material);\n mesh.position.z = zPosition;\n mesh.scale.set(scale, scale, 1);\n // Mark layer type for camera fitting\n if (layerType) {\n mesh.userData = { layerType: layerType };\n }\n this.baseGroup.add(mesh);\n meshes.push(mesh);\n }\n }\n \n return meshes;\n }\n\n renderShapesAsync(shapes, material, zPosition, scale, chunkSize, layerType = null) {\n let index = 0;\n const totalChunks = Math.ceil(shapes.length / chunkSize);\n let renderedChunks = 0;\n \n const renderNextChunk = () => {\n if (index >= shapes.length) {\n // debugLog(`[Performance] Rendered ${renderedChunks} chunks asynchronously`);\n return;\n }\n \n // Render multiple chunks per iteration for better performance\n const chunksPerFrame = 5; // Increased from 3 to 5\n for (let i = 0; i < chunksPerFrame && index < shapes.length; i++) {\n const chunk = shapes.slice(index, index + chunkSize);\n // OPTIMIZATION: Reduce curveSegments to 3 for better performance\n const geometry = new THREE.ShapeGeometry(chunk, 3);\n const mesh = new THREE.Mesh(geometry, material);\n mesh.position.z = zPosition;\n mesh.scale.set(scale, scale, 1);\n // Mark layer type for camera fitting\n if (layerType) {\n mesh.userData = { layerType: layerType };\n }\n this.baseGroup.add(mesh);\n \n index += chunkSize;\n renderedChunks++;\n }\n \n // Use requestAnimationFrame to avoid blocking the main thread\n if (index < shapes.length) {\n requestAnimationFrame(renderNextChunk);\n }\n };\n \n renderNextChunk();\n }\n\n getCachedMaterial(key, creator) {\n if (!this.materialCache.has(key)) {\n this.materialCache.set(key, creator());\n }\n return this.materialCache.get(key);\n }\n\n fitCameraToObject(object) {\n const box = new THREE.Box3().setFromObject(object);\n if (box.isEmpty()) return;\n this.fitCameraToBbox(box);\n }\n\n fitCameraToBbox(box) {\n if (box.isEmpty()) return;\n const center = box.getCenter(new THREE.Vector3());\n const size = box.getSize(new THREE.Vector3());\n const maxDim = Math.max(size.x, size.y);\n const fov = this.camera.fov * (Math.PI / 180);\n let distance = (maxDim / 2) / Math.tan(fov / 2);\n // Reduce distance multiplier to make objects appear larger (1.4 -> 1.1)\n distance *= 1.1;\n this.camera.position.set(center.x, center.y, center.z + distance);\n this.camera.near = distance / 100;\n this.camera.far = distance * 100;\n this.camera.updateProjectionMatrix();\n this.controls.target.copy(center);\n this.controls.update();\n }\n\n /**\n * 检测并修正钻孔层的坐标缩放问题\n * \n * 常见问题:\n * - 10倍问题:mil被当作inch解析\n * - 25.4倍问题:inch被当作mm解析\n * \n * @param {Object} layerData - 钻孔层数据(包含vertices和lineStrips)\n * @param {number} scale - 单位转换因子(inch -> mm 时为25.4)\n * @param {THREE.Box3} referenceBbox - 参考层边界\n * @returns {{ scale: number, bbox: THREE.Box3|null, success: boolean }}\n */\n fixDrillLayerAlignment(layerData, scale, referenceBbox) {\n if (!layerData?.vertices || !referenceBbox) {\n return { scale, bbox: null, success: false };\n }\n\n // 1. 计算原始钻孔bbox(转换单位)\n let drillBbox = this.calculateLayerBbox([layerData]);\n if (!drillBbox || drillBbox.isEmpty()) {\n return { scale, bbox: null, success: false };\n }\n \n drillBbox.min.multiplyScalar(scale);\n drillBbox.max.multiplyScalar(scale);\n\n // 2. 检查坐标是否已在合理范围内(±10%容差)\n const refSize = referenceBbox.getSize(new THREE.Vector3());\n const tolerance = 0.1;\n const inRangeX = drillBbox.min.x >= referenceBbox.min.x - refSize.x * tolerance && \n drillBbox.max.x <= referenceBbox.max.x + refSize.x * tolerance;\n const inRangeY = drillBbox.min.y >= referenceBbox.min.y - refSize.y * tolerance && \n drillBbox.max.y <= referenceBbox.max.y + refSize.y * tolerance;\n\n if (inRangeX && inRangeY) {\n debugLog('[Drill] 坐标已在范围内,无需修正');\n return { scale, bbox: drillBbox, success: true };\n }\n\n // 3. 检测缩放错误类型\n const drillSize = drillBbox.getSize(new THREE.Vector3());\n const avgSizeRatio = (drillSize.x / refSize.x + drillSize.y / refSize.y) / 2;\n \n let scaleFix = 1.0;\n if (avgSizeRatio > 5 && avgSizeRatio < 15) {\n scaleFix = 10.0; // mil被当作inch\n } else if (avgSizeRatio > 20 && avgSizeRatio < 30) {\n scaleFix = 25.4; // inch被当作mm\n } else if (avgSizeRatio > 1.5) {\n scaleFix = avgSizeRatio; // 其他缩放问题\n }\n\n if (scaleFix === 1.0) {\n debugLog('[Drill] 未检测到常见缩放问题');\n return { scale, bbox: drillBbox, success: true };\n }\n\n debugLog(`[Drill] 检测到${scaleFix.toFixed(1)}倍缩放问题,开始修正...`);\n\n // 4. 应用缩放修正(只缩放孔位,保持孔径)\n const { vertices, lineStrips } = layerData;\n if (lineStrips?.length > 0) {\n this.applyDrillScaleFix(vertices, lineStrips, scale, scaleFix);\n } else {\n // 回退:没有lineStrips,直接缩放所有顶点(孔径也会被缩放)\n debugWarn('[Drill] 缺少lineStrips,孔径会被缩放');\n for (let i = 0; i < vertices.length; i += 3) {\n vertices[i] = vertices[i] * scale / scaleFix;\n vertices[i + 1] = vertices[i + 1] * scale / scaleFix;\n }\n }\n\n // 5. 重新计算修正后的bbox\n drillBbox = this.calculateLayerBbox([layerData]);\n if (!drillBbox || drillBbox.isEmpty()) {\n return { scale: 1.0, bbox: null, success: false };\n }\n\n debugLog(`[Drill] 修正后bbox: (${drillBbox.min.x.toFixed(2)}, ${drillBbox.min.y.toFixed(2)}) - (${drillBbox.max.x.toFixed(2)}, ${drillBbox.max.y.toFixed(2)})`);\n return { scale: 1.0, bbox: drillBbox, success: true };\n }\n\n /**\n * 应用缩放修正,只移动孔位中心,保持孔径不变\n * \n * 原理:每个lineStrip代表一个钻孔圆,通过计算圆心位置并只平移顶点,\n * 可以实现\"缩放位置但保持孔径\"的效果。\n * \n * @param {Float32Array} vertices - 顶点数组\n * @param {Array} lineStrips - 线段描述数组(每个代表一个圆)\n * @param {number} scale - 单位转换因子(inch -> mm)\n * @param {number} scaleFix - 缩放修正因子(如10.0表示除以10)\n */\n applyDrillScaleFix(vertices, lineStrips, scale, scaleFix) {\n let processedCount = 0;\n \n for (const strip of lineStrips) {\n if (strip.count < 3) continue;\n \n // 1. 计算圆心(转mm并翻转Y,与calculateLayerBbox一致)\n let sumX = 0, sumY = 0;\n for (let i = 0; i < strip.count; i++) {\n const idx = (strip.start + i) * 3;\n sumX += vertices[idx];\n sumY += vertices[idx + 1];\n }\n const centerX = sumX / strip.count * scale;\n const centerY = -sumY / strip.count * scale; // Y翻转\n \n // 2. 计算位置偏移(只移动位置,不改变大小)\n const deltaX = centerX / scaleFix - centerX;\n const deltaY = centerY / scaleFix - centerY;\n \n // 3. 平移所有顶点(vertices是未翻转的Y,所以deltaY反向)\n for (let i = 0; i < strip.count; i++) {\n const idx = (strip.start + i) * 3;\n vertices[idx] = vertices[idx] * scale + deltaX;\n vertices[idx + 1] = vertices[idx + 1] * scale - deltaY;\n }\n processedCount++;\n }\n \n debugLog(`[Drill] 已修正 ${processedCount} 个钻孔,孔径保持不变`);\n }\n\n /**\n * 验证钻孔层边界是否在合理范围内\n * \n * @param {THREE.Box3} drillBbox - 钻孔层边界\n * @param {THREE.Box3} referenceBbox - 参考层边界\n * @param {THREE.Box3} expandedReferenceBbox - 扩展后的参考层边界(含容差)\n * @param {string} fileName - 文件名(用于日志)\n * @returns {boolean} 是否通过验证\n */\n validateDrillBbox(drillBbox, referenceBbox, expandedReferenceBbox, fileName) {\n // 检查 1:与板子范围(放大 20mm)无交集\n if (!expandedReferenceBbox.intersectsBox(drillBbox)) {\n debugWarn(`[Drill] ${fileName} 与板子范围无交集(容错20mm),跳过渲染`);\n return false;\n }\n\n if (!referenceBbox) return true;\n\n const refSize = referenceBbox.getSize(new THREE.Vector3());\n const drillSize = drillBbox.getSize(new THREE.Vector3());\n\n // 检查 2:尺寸偏差\n const maxRatio = 1.3; // 允许一定余量(如工艺边/靠边孔)\n const minRatio = 0.2; // 极端偏小通常是单位/格式问题\n \n if (drillSize.x > refSize.x * maxRatio || drillSize.y > refSize.y * maxRatio) {\n debugWarn(`[Drill] ${fileName} 钻孔范围过大(>${maxRatio}x),跳过渲染`);\n return false;\n }\n if (drillSize.x < refSize.x * minRatio && drillSize.y < refSize.y * minRatio) {\n debugWarn(`[Drill] ${fileName} 钻孔范围过小(<${minRatio}x),跳过渲染`);\n return false;\n }\n\n // 检查 3:中心偏移过大\n const centerRef = referenceBbox.getCenter(new THREE.Vector3());\n const centerDrill = drillBbox.getCenter(new THREE.Vector3());\n const maxDim = Math.max(refSize.x, refSize.y);\n const centerThreshold = Math.max(maxDim * 0.15, 25); // 15% 或至少 25mm\n const centerDist = centerRef.distanceTo(centerDrill);\n \n // ✅ 关键修复:对“小范围钻孔文件”(只在板子某一角/某一排连接器区域打孔)不做中心偏移淘汰,\n // 否则像 SlotHoles.TXT 这种局部孔会被误杀(你日志里正是 34.6mm 被跳过)。\n const sizeRatioX = drillSize.x / Math.max(1e-9, refSize.x);\n const sizeRatioY = drillSize.y / Math.max(1e-9, refSize.y);\n const localized = (Math.max(sizeRatioX, sizeRatioY) < 0.60);\n\n if (!localized && centerDist > centerThreshold) {\n debugWarn(`[Drill] ${fileName} 中心偏移过大(${centerDist.toFixed(1)}mm),跳过渲染`);\n return false;\n }\n\n return true;\n }\n\n /**\n * 将线段拼接成THREE.Shape对象(用于多轮廓文件合并)\n * @param {Array<{start:{x,y}, end:{x,y}}>} segments 线段数组\n * @returns {Array<THREE.Shape>} 形状数组\n */\n stitchSegmentsToShapes3D(segments) {\n if (!segments || segments.length === 0) return [];\n \n // 计算容差\n let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;\n for (const seg of segments) {\n minX = Math.min(minX, seg.start.x, seg.end.x);\n maxX = Math.max(maxX, seg.start.x, seg.end.x);\n minY = Math.min(minY, seg.start.y, seg.end.y);\n maxY = Math.max(maxY, seg.start.y, seg.end.y);\n }\n const boardSize = Math.max(maxX - minX, maxY - minY);\n const TOLERANCE = boardSize > 100 ? 0.2 : boardSize > 50 ? 0.1 : 0.05;\n \n // 构建空间网格\n const cellSize = TOLERANCE;\n const grid = new Map();\n const getCell = (pt) => `${Math.floor(pt.x / cellSize)},${Math.floor(pt.y / cellSize)}`;\n \n const poolItems = segments.map(s => ({ seg: s, used: false }));\n \n const addToGrid = (item) => {\n const k1 = getCell(item.seg.start);\n const k2 = getCell(item.seg.end);\n if (!grid.has(k1)) grid.set(k1, []);\n grid.get(k1).push(item);\n if (k1 !== k2) {\n if (!grid.has(k2)) grid.set(k2, []);\n grid.get(k2).push(item);\n }\n };\n \n poolItems.forEach(addToGrid);\n \n const distanceTo = (p1, p2) => Math.sqrt((p1.x - p2.x) ** 2 + (p1.y - p2.y) ** 2);\n \n const getCandidates = (pt) => {\n const cx = Math.floor(pt.x / cellSize);\n const cy = Math.floor(pt.y / cellSize);\n const results = new Set();\n for (let dx = -1; dx <= 1; dx++) {\n for (let dy = -1; dy <= 1; dy++) {\n const k = `${cx + dx},${cy + dy}`;\n const list = grid.get(k);\n if (list) {\n for (const item of list) results.add(item);\n }\n }\n }\n return results;\n };\n \n const chains = [];\n \n // 拼线\n for (const startItem of poolItems) {\n if (startItem.used) continue;\n \n startItem.used = true;\n const chain = [startItem.seg.start, startItem.seg.end];\n let tail = startItem.seg.end;\n let head = startItem.seg.start;\n \n // 向后搜索\n let finding = true;\n while (finding) {\n finding = false;\n const candidates = getCandidates(tail);\n \n let bestNext = null;\n let minDst = Infinity;\n let isReverse = false;\n \n for (const item of candidates) {\n if (item.used) continue;\n \n const d1 = distanceTo(item.seg.start, tail);\n if (d1 < TOLERANCE && d1 < minDst) {\n minDst = d1;\n bestNext = item;\n isReverse = false;\n }\n const d2 = distanceTo(item.seg.end, tail);\n if (d2 < TOLERANCE && d2 < minDst) {\n minDst = d2;\n bestNext = item;\n isReverse = true;\n }\n }\n \n if (bestNext) {\n bestNext.used = true;\n if (isReverse) {\n chain.push(bestNext.seg.start);\n tail = bestNext.seg.start;\n } else {\n chain.push(bestNext.seg.end);\n tail = bestNext.seg.end;\n }\n finding = true;\n }\n }\n \n // 向前搜索\n finding = true;\n while (finding) {\n finding = false;\n const candidates = getCandidates(head);\n \n let bestPrev = null;\n let minDst = Infinity;\n let isReverse = false;\n \n for (const item of candidates) {\n if (item.used) continue;\n \n const d1 = distanceTo(item.seg.end, head);\n if (d1 < TOLERANCE && d1 < minDst) {\n minDst = d1;\n bestPrev = item;\n isReverse = false;\n }\n const d2 = distanceTo(item.seg.start, head);\n if (d2 < TOLERANCE && d2 < minDst) {\n minDst = d2;\n bestPrev = item;\n isReverse = true;\n }\n }\n \n if (bestPrev) {\n bestPrev.used = true;\n if (isReverse) {\n chain.unshift(bestPrev.seg.end);\n head = bestPrev.seg.end;\n } else {\n chain.unshift(bestPrev.seg.start);\n head = bestPrev.seg.start;\n }\n finding = true;\n }\n }\n \n chains.push(chain);\n }\n \n // 将链转换为THREE.Shape\n const shapes = [];\n const MIN_AREA = 0.01;\n \n for (const chain of chains) {\n if (chain.length < 3) continue;\n \n // 检查是否闭合\n const headPt = chain[0];\n const tailPt = chain[chain.length - 1];\n const isClosed = distanceTo(headPt, tailPt) < TOLERANCE;\n \n if (!isClosed) continue; // 只保留闭合路径\n \n // 计算面积\n let area = 0;\n for (let i = 0; i < chain.length; i++) {\n const p1 = chain[i];\n const p2 = chain[(i + 1) % chain.length];\n area += p1.x * p2.y - p2.x * p1.y;\n }\n area = Math.abs(area) / 2;\n \n if (area < MIN_AREA) continue;\n \n // 创建THREE.Shape\n const shape = new THREE.Shape();\n shape.moveTo(chain[0].x, chain[0].y);\n for (let i = 1; i < chain.length; i++) {\n shape.lineTo(chain[i].x, chain[i].y);\n }\n shape.closePath();\n \n shape.userData = { forcedClose: false, area };\n shapes.push(shape);\n }\n \n return shapes;\n }\n\n calculateLayerBbox(layers) {\n const allPoints = [];\n for (const layer of layers) {\n // Collect points from lineStrips\n if (layer.lineStrips && layer.vertices) {\n for (const strip of layer.lineStrips) {\n for (let j = 0; j < strip.count; j++) {\n const ptr = (strip.start + j) * 3;\n allPoints.push(new THREE.Vector3(\n layer.vertices[ptr],\n -layer.vertices[ptr + 1],\n 0\n ));\n }\n }\n }\n // Collect points from children/segments\n if (layer.children) {\n for (const child of layer.children) {\n if (child.type === 'imagePath' && child.segments) {\n for (const seg of child.segments) {\n allPoints.push(new THREE.Vector3(seg.start[0], -seg.start[1], 0));\n allPoints.push(new THREE.Vector3(seg.end[0], -seg.end[1], 0));\n }\n }\n }\n }\n }\n \n if (allPoints.length === 0) return null;\n return new THREE.Box3().setFromPoints(allPoints);\n }\n}\n\nwindow.onload = () => new Viewer3D();","/**\n * 专门用于提取轮廓层(GKO/GM1等)的 Gerber 解析器\n * 基于 2d-direct/js/gerber-parser-direct.js 修改\n * 重点在于解析 G36/G37 区域并直接生成 THREE.Shape\n * 同时也支持标准线段定义的轮廓(非 G36/G37)并进行拼线\n */\nimport * as THREE from 'three';\n\nexport class GerberOutlineParser {\n constructor() {\n this.shapes = []; // 存储生成的 THREE.Shape 对象\n this.strokeSegments = []; // 兜底渲染用的线段集合(G01/G02/G03 离散后)\n \n this.state = {\n x: 0,\n y: 0,\n i: 0,\n j: 0,\n d: 0,\n lastD: null, // 🚀 Modal D-code\n g: 1, // 1: linear, 2: cw, 3: ccw, 36: region start, 37: region end\n interpolation: 'linear',\n regionMode: false,\n quadrant: 'multi',\n unit: 'mm',\n format: {\n integer: 2,\n decimal: 4,\n zero: 'L'\n }\n };\n\n // 区域路径缓存 (G36/G37)\n this.currentRegionContours = [];\n this._currentRegionContour = null;\n\n // 非区域线段缓存 (G01/G02/G03)\n this.segments = []; \n }\n\n parse(content) {\n this.shapes = [];\n this.segments = []; // 清空之前的段\n this.currentRegionContours = [];\n this.strokeSegments = [];\n \n const lines = content.split(/[\\n\\r]+/);\n const MAX_SEGMENTS_DURING_PARSE = 300000; // 🚀 进一步放宽限制,支持复杂圆形等异形轮廓(209K段的圆形板)\n let abortedDueToSize = false;\n \n for (let line of lines) {\n // 🚀 在解析过程中检查,避免无谓处理\n if (this.segments.length > MAX_SEGMENTS_DURING_PARSE || this.strokeSegments.length > MAX_SEGMENTS_DURING_PARSE) {\n abortedDueToSize = true;\n break;\n }\n \n line = line.trim();\n if (!line) continue;\n \n if (line.startsWith('%') && line.endsWith('%')) {\n this.parseExtendedCommand(line.substring(1, line.length - 1));\n continue;\n }\n \n const commands = line.split('*');\n for (let cmd of commands) {\n cmd = cmd.trim();\n if (!cmd) continue;\n this.parseCommand(cmd);\n }\n }\n \n if (abortedDueToSize) {\n console.warn(`[GerberOutline] 解析中止:线段数量过多 (segments=${this.segments.length}, strokes=${this.strokeSegments.length}),跳过复杂解析`);\n return { shapes: [], strokes: [] };\n }\n\n // 1. 处理 G36/G37 区域\n if (this.currentRegionContours.length > 0) {\n this.processRegions();\n }\n\n // 2. 处理标准线段 (如果有)\n if (this.segments.length > 0) {\n this.stitchSegmentsToShapes();\n }\n\n // 3. 移除外接矩形兜底逻辑,避免将异形板误判为矩形\n // 如果需要兜底可视化,使用 strokes 在 Three.js 中单独渲染线框\n if (this.strokeSegments.length >= 100000) {\n // 完全禁用日志输出以提高性能\n // console.warn(`[GerberOutline] 线段数量过多 (${this.strokeSegments.length}),跳过兜底渲染以避免性能问题`);\n }\n\n // 返回面与线两种结果,面用于厚板,线用于兜底可视化\n return {\n shapes: this.shapes,\n strokes: this.strokeSegments\n };\n }\n\n parseExtendedCommand(cmd) {\n if (cmd.startsWith('FS')) {\n const match = cmd.match(/FS([LT])?[AI]X(\\d)(\\d)Y(\\d)(\\d)/);\n if (match) {\n this.state.format.zero = match[1] || 'L';\n this.state.format.integer = parseInt(match[2]);\n this.state.format.decimal = parseInt(match[3]);\n }\n } else if (cmd.startsWith('MO')) {\n this.state.unit = cmd.includes('IN') ? 'inch' : 'mm';\n }\n }\n\n parseCommand(cmd) {\n if (cmd.startsWith('G')) {\n const gCode = parseInt(cmd.substring(1, 3));\n if (gCode === 1) this.state.interpolation = 'linear';\n if (gCode === 2) this.state.interpolation = 'cw';\n if (gCode === 3) this.state.interpolation = 'ccw';\n if (gCode === 36) {\n this.state.regionMode = true;\n this.currentRegionContours = [];\n this._currentRegionContour = null;\n }\n if (gCode === 37) {\n this.state.regionMode = false;\n this.finishRegion(); \n }\n if (cmd.length > 3) this.parseCoordinate(cmd.substring(3));\n return;\n }\n\n // D01/D02/D03\n if (cmd.startsWith('D') && parseInt(cmd.substring(1)) >= 10) {\n return;\n }\n\n this.parseCoordinate(cmd);\n }\n\n parseCoordinate(cmd) {\n let x = this.state.x;\n let y = this.state.y;\n let iOffset = 0;\n let jOffset = 0;\n let d = null;\n\n const xMatch = cmd.match(/X([-+]?\\d+)/);\n if (xMatch) x = this.parseValue(xMatch[1]);\n\n const yMatch = cmd.match(/Y([-+]?\\d+)/);\n if (yMatch) y = this.parseValue(yMatch[1]);\n \n const iMatch = cmd.match(/I([-+]?\\d+)/);\n if (iMatch) iOffset = this.parseValue(iMatch[1]);\n\n const jMatch = cmd.match(/J([-+]?\\d+)/);\n if (jMatch) jOffset = this.parseValue(jMatch[1]);\n\n const dMatch = cmd.match(/D(\\d+)/);\n if (dMatch) {\n d = parseInt(dMatch[1]);\n // 更新模态 D-code\n if (d === 1 || d === 2) {\n this.state.lastD = d;\n }\n } else {\n // 如果没有 D-code,尝试使用模态 D-code\n if ((xMatch || yMatch || iMatch || jMatch) && this.state.lastD) {\n d = this.state.lastD;\n }\n }\n\n const prevX = this.state.x;\n const prevY = this.state.y;\n this.state.x = x;\n this.state.y = y;\n\n if (d !== null) {\n if (d === 1) { // Draw\n if (this.state.regionMode) {\n if (this.state.interpolation === 'linear') {\n if (!this._currentRegionContour) this._startRegionContour(prevX, prevY);\n this._currentRegionContour.push({ x, y });\n } else {\n if (!this._currentRegionContour) this._startRegionContour(prevX, prevY);\n this.addArcToRegion(prevX, prevY, x, y, iOffset, jOffset, this.state.interpolation === 'cw');\n }\n } else {\n // 非 Region 模式:收集线段用于拼线\n this.addSegment(prevX, prevY, x, y, iOffset, jOffset, this.state.interpolation);\n }\n } else if (d === 2) { // Move\n if (this.state.regionMode) {\n this._startRegionContour(x, y);\n }\n }\n }\n }\n\n parseValue(str) {\n let scale = Math.pow(10, this.state.format.decimal);\n let val = parseFloat(str) / scale;\n // 内部转换单位为mm(与home/simulation3d保持一致)\n if (this.state.unit === 'inch') val *= 25.4;\n return val;\n }\n\n // --- Region Logic ---\n\n _startRegionContour(x, y) {\n const contour = [{ x, y }];\n this.currentRegionContours.push(contour);\n this._currentRegionContour = contour;\n }\n\n addArcToRegion(x1, y1, x2, y2, iOffset, jOffset, isCw) {\n const pts = this.discretizeArc(x1, y1, x2, y2, iOffset, jOffset, isCw);\n for (let i = 1; i < pts.length; i++) {\n if (this._currentRegionContour) {\n this._currentRegionContour.push(pts[i]);\n }\n }\n }\n\n finishRegion() {\n if (this.currentRegionContours.length > 0) {\n // 将当前块的 region 轮廓转为 shapes\n // 这里为了支持多个 Region 块,我们将它们全部转为 Shape 存入\n const newShapes = this.contoursToShapes(this.currentRegionContours);\n this.shapes.push(...newShapes);\n this.currentRegionContours = [];\n }\n this._currentRegionContour = null;\n }\n\n processRegions() {\n if (this.currentRegionContours.length > 0) {\n const newShapes = this.contoursToShapes(this.currentRegionContours);\n this.shapes.push(...newShapes);\n this.currentRegionContours = [];\n }\n }\n\n contoursToShapes(rawContours) {\n // 简单清洗并转换为 Shape,不进行任何包含关系计算/布尔运算\n const shapes = [];\n for (const rawPts of rawContours) {\n // 清洗:去除重复点\n const pts = [];\n let last = null;\n for (const p of rawPts) {\n if (!last || Math.hypot(p.x - last.x, p.y - last.y) > 1e-4) {\n pts.push(p);\n last = p;\n }\n }\n \n // 检查闭合性:如果首尾距离过大,说明可能未闭合。\n // 业务诉求:宁可强行闭合,也不要丢面,因此只在超大间隙时才放弃。\n let forcedClose = false;\n if (pts.length > 2) {\n const first = pts[0];\n const end = pts[pts.length - 1];\n const gap = Math.hypot(first.x - end.x, first.y - end.y);\n\n const WARN_GAP = 10.0; // 提示用\n const MAX_GAP = 1000.0; // 仅超大异常才丢弃\n\n if (gap > WARN_GAP) {\n // 完全禁用日志输出以提高性能\n // if (gap > 100.0) {\n // console.warn(`[GerberOutline] 未闭合路径间隙: ${gap.toFixed(3)}mm,尝试强制闭合`);\n // }\n forcedClose = true;\n }\n if (gap > MAX_GAP) {\n // 完全禁用日志输出以提高性能\n // console.warn(`[GerberOutline] 间隙过大,放弃闭合: ${gap.toFixed(3)}mm`);\n continue;\n }\n\n if (gap > 0.001) {\n pts.push({ x: first.x, y: first.y });\n }\n } else {\n continue;\n }\n\n if (pts.length >= 3) {\n const shape = new THREE.Shape();\n shape.moveTo(pts[0].x, pts[0].y);\n for (let i = 1; i < pts.length; i++) {\n shape.lineTo(pts[i].x, pts[i].y);\n }\n shape.closePath();\n // 标记强制闭合的形状,用于避免绘制对角线边框\n shape.userData = { forcedClose };\n \n // 完全禁用日志输出以提高性能\n // const area = THREE.ShapeUtils.area(shape.getPoints());\n // if (Math.abs(area) < 0.001) {\n // console.warn(`[GerberOutline] 生成的形状面积过小: ${area.toFixed(6)} mm², 点数: ${pts.length}`);\n // }\n shapes.push(shape);\n } else {\n // 完全禁用日志输出以提高性能\n // console.warn(`[GerberOutline] 跳过点数不足的轮廓: ${pts.length} 个点`);\n }\n }\n return shapes;\n }\n\n // --- Non-Region Segment Logic ---\n\n addSegment(x1, y1, x2, y2, iOffset, jOffset, mode) {\n if (mode === 'linear') {\n this.segments.push({ \n start: new THREE.Vector2(x1, y1), \n end: new THREE.Vector2(x2, y2) \n });\n } else {\n // Arc\n const pts = this.discretizeArc(x1, y1, x2, y2, iOffset, jOffset, mode === 'cw');\n for (let i = 0; i < pts.length - 1; i++) {\n this.segments.push({\n start: new THREE.Vector2(pts[i].x, pts[i].y),\n end: new THREE.Vector2(pts[i+1].x, pts[i+1].y)\n });\n }\n }\n }\n\n discretizeArc(x1, y1, x2, y2, iOffset, jOffset, isCw) {\n const cx = x1 + iOffset;\n const cy = y1 + jOffset;\n const radius = Math.sqrt(iOffset * iOffset + jOffset * jOffset);\n\n if (radius < 0.0001) return [{x: x1, y: y1}, {x: x2, y: y2}];\n\n let startAngle = Math.atan2(y1 - cy, x1 - cx);\n let endAngle = Math.atan2(y2 - cy, x2 - cx);\n\n if (isCw) {\n if (endAngle >= startAngle) endAngle -= 2 * Math.PI;\n } else {\n if (endAngle <= startAngle) endAngle += 2 * Math.PI;\n }\n\n const arcLength = Math.abs(endAngle - startAngle) * radius;\n const angleSpan = Math.abs(endAngle - startAngle);\n \n // 优化弧线精度:统一处理,确保所有圆角一致\n // 对于小圆角(半径 < 10mm),使用统一的高精度;对于大圆弧,使用更粗精度\n let segmentSize;\n let minSegments;\n \n // 判断是否为小圆角(半径 < 10mm)\n const isSmallCorner = radius < 10;\n \n if (isSmallCorner) {\n // 小圆角:统一使用高精度,确保所有圆角一致和平滑\n segmentSize = 0.003; // 统一使用0.003mm精度\n // 根据角度跨度计算最少段数:90度圆角至少32段,180度至少64段\n minSegments = Math.max(32, Math.ceil(angleSpan / (Math.PI / 2) * 32));\n } else if (arcLength > 100) {\n segmentSize = 0.02; // 大圆弧:0.02mm精度\n minSegments = 12;\n } else if (arcLength > 10) {\n segmentSize = 0.01; // 中等圆弧:0.01mm精度\n minSegments = 16;\n } else {\n segmentSize = 0.005; // 小圆弧:0.005mm精度\n minSegments = 20;\n }\n \n const segments = Math.max(minSegments, Math.ceil(arcLength / segmentSize)); \n\n const pts = [];\n pts.push({x: x1, y: y1}); \n\n for (let k = 1; k <= segments; k++) {\n const t = k / segments;\n const angle = startAngle + (endAngle - startAngle) * t;\n pts.push({\n x: cx + radius * Math.cos(angle),\n y: cy + radius * Math.sin(angle)\n });\n }\n // 强制最后一点精确等于 x2, y2\n pts[pts.length - 1] = { x: x2, y: y2 };\n return pts;\n }\n\n stitchSegmentsToShapes() {\n // 1. 线段去重 (O(N))\n const uniqueSegments = [];\n const seen = new Set();\n // 0.01um precision for deduplication key (提高精度)\n const keyFn = (p) => `${Math.round(p.x * 100000)},${Math.round(p.y * 100000)}`; \n \n for (const seg of this.segments) {\n // 生成双向 Key 以确保无视方向去重\n const k1 = keyFn(seg.start) + \"|\" + keyFn(seg.end);\n const k2 = keyFn(seg.end) + \"|\" + keyFn(seg.start);\n if (!seen.has(k1) && !seen.has(k2)) {\n seen.add(k1);\n uniqueSegments.push(seg);\n }\n }\n \n // 动态计算容差:根据线段范围自动调整,避免容差过小导致拼接失败\n if (uniqueSegments.length === 0) return;\n \n // 计算所有线段的范围\n let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;\n for (const seg of uniqueSegments) {\n minX = Math.min(minX, seg.start.x, seg.end.x);\n maxX = Math.max(maxX, seg.start.x, seg.end.x);\n minY = Math.min(minY, seg.start.y, seg.end.y);\n maxY = Math.max(maxY, seg.start.y, seg.end.y);\n }\n const boardSize = Math.max(maxX - minX, maxY - minY);\n \n // 根据板子尺寸动态调整容差:大板子用更大的容差\n // 对于大板子(>100mm),使用0.5mm容差;中等板子(>50mm)使用0.25mm;小板子使用0.1mm\n let TOLERANCE;\n if (boardSize > 100) {\n TOLERANCE = 0.5;\n } else if (boardSize > 50) {\n TOLERANCE = 0.25;\n } else {\n TOLERANCE = 0.1;\n }\n const cellSize = TOLERANCE;\n \n // 2. 构建 Spatial Grid (O(N))\n // Map<CellKey, Array<PoolItem>>\n const grid = new Map();\n const getCell = (pt) => `${Math.floor(pt.x / cellSize)},${Math.floor(pt.y / cellSize)}`;\n \n // 保存去重后的线段,供兜底线框渲染\n this.strokeSegments = uniqueSegments.map(s => ({\n start: s.start.clone(),\n end: s.end.clone()\n }));\n\n const poolItems = uniqueSegments.map(s => ({ seg: s, used: false }));\n \n const addToGrid = (item) => {\n const k1 = getCell(item.seg.start);\n const k2 = getCell(item.seg.end);\n \n if (!grid.has(k1)) grid.set(k1, []);\n grid.get(k1).push(item);\n \n // 如果跨越 cell,都加上,反正查询时会去重\n if (k1 !== k2) {\n if (!grid.has(k2)) grid.set(k2, []);\n grid.get(k2).push(item);\n }\n };\n \n poolItems.forEach(addToGrid);\n \n const getCandidates = (pt) => {\n const cx = Math.floor(pt.x / cellSize);\n const cy = Math.floor(pt.y / cellSize);\n const results = new Set(); \n \n for (let dx = -1; dx <= 1; dx++) {\n for (let dy = -1; dy <= 1; dy++) {\n const k = `${cx + dx},${cy + dy}`;\n const list = grid.get(k);\n if (list) {\n for (const item of list) results.add(item);\n }\n }\n }\n return results;\n };\n\n const chains = [];\n\n // 3. 拼线 (O(N))\n for (const startItem of poolItems) {\n if (startItem.used) continue;\n\n startItem.used = true;\n const chain = [startItem.seg.start, startItem.seg.end];\n let tail = startItem.seg.end;\n let head = startItem.seg.start;\n \n // 向后搜索 (Tail)\n let finding = true;\n while (finding) {\n finding = false;\n const candidates = getCandidates(tail);\n \n let bestNext = null;\n let minDst = Infinity; \n let isReverse = false;\n\n for (const item of candidates) {\n if (item.used) continue;\n \n const d1 = item.seg.start.distanceTo(tail);\n if (d1 < TOLERANCE && d1 < minDst) {\n minDst = d1;\n bestNext = item;\n isReverse = false;\n }\n const d2 = item.seg.end.distanceTo(tail);\n if (d2 < TOLERANCE && d2 < minDst) {\n minDst = d2;\n bestNext = item;\n isReverse = true;\n }\n }\n\n if (bestNext) {\n bestNext.used = true;\n if (isReverse) {\n chain.push(bestNext.seg.start); \n tail = bestNext.seg.start;\n } else {\n chain.push(bestNext.seg.end);\n tail = bestNext.seg.end;\n }\n finding = true;\n }\n }\n\n // 向前搜索 (Head)\n finding = true;\n while (finding) {\n finding = false;\n const candidates = getCandidates(head);\n \n let bestPrev = null;\n let minDst = Infinity;\n let isReverse = false;\n\n for (const item of candidates) {\n if (item.used) continue;\n \n const d1 = item.seg.end.distanceTo(head);\n if (d1 < TOLERANCE && d1 < minDst) {\n minDst = d1;\n bestPrev = item;\n isReverse = false; \n }\n \n const d2 = item.seg.start.distanceTo(head);\n if (d2 < TOLERANCE && d2 < minDst) {\n minDst = d2;\n bestPrev = item;\n isReverse = true;\n }\n }\n\n if (bestPrev) {\n bestPrev.used = true;\n if (isReverse) {\n chain.unshift(bestPrev.seg.end);\n head = bestPrev.seg.end;\n } else {\n chain.unshift(bestPrev.seg.start);\n head = bestPrev.seg.start;\n }\n finding = true;\n }\n }\n\n chains.push(chain);\n }\n\n // 将 Chains 转为 Shapes\n const contours = [];\n for (const chain of chains) {\n if (chain.length < 3) {\n // 完全禁用日志输出以提高性能\n // console.warn(`[GerberOutline] 跳过过短的链: ${chain.length} 个点`);\n continue;\n }\n const pts = chain.map(p => ({ x: p.x, y: p.y }));\n contours.push(pts);\n }\n\n // 减少日志输出以提高性能\n const newShapes = this.contoursToShapes(contours);\n this.shapes.push(...newShapes);\n\n // 4. 兜底:在存在分叉/网格的情况下再尝试从线段图提取闭合环\n // 逻辑:基于去重后的线段构建无向图,按边遍历找到回到起点的环,避免被分叉打断。\n if (uniqueSegments.length > 0) {\n const fallbackShapes = this.buildLoopsFromSegments(uniqueSegments, TOLERANCE); // 使用相同的容差\n if (fallbackShapes.length > 0) {\n this.shapes.push(...fallbackShapes);\n }\n }\n }\n\n /**\n * 从无向线段集合中提取简单闭合环,适用于拼板网格等分叉场景。\n * 算法:构建邻接表,遍历未使用的边,沿邻接边走到回到起点即认为闭合。\n */\n buildLoopsFromSegments(segments, tol = 0.2) {\n const keyFn = (p) => `${Math.round(p.x / tol)},${Math.round(p.y / tol)}`;\n const nodes = new Map(); // key -> {pt, neighbors:Set<key>}\n\n const addNode = (p) => {\n const k = keyFn(p);\n if (!nodes.has(k)) {\n nodes.set(k, { pt: p.clone(), neighbors: new Set() });\n }\n return k;\n };\n\n const edges = new Map(); // sortedKey -> {aKey, bKey, used}\n const edgeKey = (aKey, bKey) => (aKey < bKey ? `${aKey}|${bKey}` : `${bKey}|${aKey}`);\n\n for (const seg of segments) {\n const aKey = addNode(seg.start);\n const bKey = addNode(seg.end);\n const ek = edgeKey(aKey, bKey);\n if (edges.has(ek)) continue; // 已存在\n edges.set(ek, { aKey, bKey, used: false });\n nodes.get(aKey).neighbors.add(bKey);\n nodes.get(bKey).neighbors.add(aKey);\n }\n\n const loops = [];\n\n for (const [ek, edge] of edges) {\n if (edge.used) continue;\n\n // 选定一条边开始走\n const pathKeys = [];\n let prevKey = edge.aKey;\n let currKey = edge.bKey;\n edge.used = true;\n pathKeys.push(prevKey, currKey);\n\n let closed = false;\n const MAX_STEPS = segments.length * 4; // 安全上限\n let steps = 0;\n\n while (steps < MAX_STEPS) {\n steps++;\n const currNode = nodes.get(currKey);\n if (!currNode) break;\n\n // 找到一条未使用的邻接边\n let nextKey = null;\n for (const nbKey of currNode.neighbors) {\n if (nbKey === prevKey) continue;\n const nk = edgeKey(currKey, nbKey);\n const e = edges.get(nk);\n if (e && !e.used) {\n nextKey = nbKey;\n e.used = true;\n break;\n }\n }\n\n if (nextKey === null) {\n // 尝试用容差判断回到起点\n const startNode = nodes.get(pathKeys[0]);\n const currNodePt = nodes.get(currKey)?.pt;\n if (startNode && currNodePt) {\n const gap = startNode.pt.distanceTo(currNodePt);\n if (gap <= tol && pathKeys.length > 2) {\n closed = true;\n }\n }\n break;\n }\n\n pathKeys.push(nextKey);\n prevKey = currKey;\n currKey = nextKey;\n\n if (currKey === pathKeys[0] && pathKeys.length > 3) {\n closed = true;\n break;\n }\n }\n\n if (closed) {\n // 去重: 量化点映射到原始 pt,生成 Shape\n const pts = [];\n pathKeys.forEach(k => {\n const n = nodes.get(k);\n if (n) pts.push({ x: n.pt.x, y: n.pt.y });\n });\n // 去掉首尾重复点\n if (pts.length > 1 && Math.hypot(pts[0].x - pts[pts.length - 1].x, pts[0].y - pts[pts.length - 1].y) < 1e-6) {\n pts.pop();\n }\n if (pts.length >= 3) {\n const shape = new THREE.Shape();\n shape.moveTo(pts[0].x, pts[0].y);\n for (let i = 1; i < pts.length; i++) {\n shape.lineTo(pts[i].x, pts[i].y);\n }\n shape.closePath();\n loops.push(shape);\n }\n }\n }\n\n return loops;\n }\n\n // 根据线框生成外接矩形兜底面(修复堆栈溢出:使用循环而不是展开运算符)\n buildBBoxShapeFromStrokes(segments) {\n if (!segments || segments.length === 0) return null;\n \n // 使用循环计算最大最小值,避免堆栈溢出\n let minX = Infinity, maxX = -Infinity;\n let minY = Infinity, maxY = -Infinity;\n \n for (let i = 0; i < segments.length; i++) {\n const seg = segments[i];\n if (seg.start.x < minX) minX = seg.start.x;\n if (seg.start.x > maxX) maxX = seg.start.x;\n if (seg.start.y < minY) minY = seg.start.y;\n if (seg.start.y > maxY) maxY = seg.start.y;\n if (seg.end.x < minX) minX = seg.end.x;\n if (seg.end.x > maxX) maxX = seg.end.x;\n if (seg.end.y < minY) minY = seg.end.y;\n if (seg.end.y > maxY) maxY = seg.end.y;\n }\n \n if (!isFinite(minX) || !isFinite(maxX) || !isFinite(minY) || !isFinite(maxY)) return null;\n const shape = new THREE.Shape();\n shape.moveTo(minX, minY);\n shape.lineTo(maxX, minY);\n shape.lineTo(maxX, maxY);\n shape.lineTo(minX, maxY);\n shape.closePath();\n return shape;\n }\n}"],"mappings":"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","names":["THREE","referenceBbox","refSize","refArea","forcedCount","bbox","size","shape"]}