import { Circle, Contour, ConverToPolylineAndSplitArc, Shape, ShapeManager } from 'cadapi' import type { Polyline } from 'cadapi' import { Vector3 } from 'three' import { PolylineHelper } from '../../common/LayoutEngine/PolylineHelper.js' import type { Curve2d } from '../../common/base/CAD.js' import { Arc2d, Line2d, Point2d } from '../../common/base/CAD.js' import { PlaceStyle, SizeExpand, PlaceBlock, PlaceBlockDetail, PlaceBorderContour, PlaceSpace, PlaceMaterial } from '../../confClass.js' import { equal, getDis, getDis2, getDis_PointLine, getRect } from '../../common/base/MathComm.js' import { getPlacePosition } from '../../common/base/PlaceStyleHelper' import { SpacePlus } from './SpacePlus' /**板件计算工具类 小板轮廓,走刀路径等 */ export class BlockPlus { /** 小板初始化:1各种轮廓|走刀路径|,2尺寸扩展后的轮廓与走刀路径 * 配置入参 * isRectBlockChamfer = false, // 矩形板件倒角开料 isUnRegularBlockChamfer = false, // 异形板件倒角开料 preMillingSize = 0, // 预铣尺寸 */ static initBlock(block: PlaceBlock, placeMaterial: PlaceMaterial, params: any) { if(block.blockDetail == null) { console.error('BlockPlus.initBlock: block.blockDetail is undefined', block) return } if (block.blockDetail.borderContour) return // 已初始化 const { isRectBlockChamfer = false, // 矩形板件倒角开料 isUnRegularBlockChamfer = false, // 异形板件倒角开料 preMillingSize = 0, // 预铣尺寸 helpCutStyle = 0, // 辅助开料方式(0同刀辅助开料 1小刀辅助开料) useSameKnifeToHelpCutStyle helpCutGap = 2, // 同刀辅助开料缝隙 } = params if (!block.blockDetail) { return } const pm = placeMaterial const bd = block.blockDetail if (pm == null) { return // 异常 } const cutKnifeR = pm.diameter / 2 const cutGap = pm.cutKnifeGap // 开料偏移值 ,矩形波倒角 bd.offsetKnifeRadius = pm.diameter / 2 bd.isOffsetRounding = true // 默认要倒角 bd.preMillingSize = pm.preMillingSize if (bd.points.length == 0) // 矩形板,设置不倒角 { bd.isOffsetRounding = isRectBlockChamfer } else // 异形板 { // 异形板倒角 bd.isOffsetRounding = isUnRegularBlockChamfer } // 初始化 小板基础轮廓 // 1.原始轮廓,成品轮廓 const border_final = this.createFinalBorder(bd, block) // 2.开料轮廓 <不含预铣> const border_org = this.createOrgBorder(bd) bd.borderContour = new PlaceBorderContour(PlaceStyle.FRONT, border_final, border_org) // 3.开料轮廓_带预铣, 外扩尺寸 bd.borderContour.borderPreMilling = border_org bd.preMillingExpandSize = new SizeExpand() if (preMillingSize > 0.0001) { const rt = this.creatOrgBorderWithPrevCut(block, border_org, preMillingSize) bd.borderContour.borderPreMilling = rt?.newBorders || [] bd.preMillingExpandSize = rt?.newSizeExpand || new SizeExpand() // console.log('开料轮廓_带预铣, 外扩尺寸==》after', block, rt.newSizeExpand) } // 4. 板内走刀路径,板内空间 const innerGroup = this.analyeInners(bd, cutKnifeR, cutGap) bd.borderContour.borderModelThrough = innerGroup.borders_inner_org bd.borderContour.borderModelThroughR = innerGroup.borders_inner_r bd.borderContour.cutLinesModelThrough = innerGroup.borders_inner_cut bd.borderContour.borderInnerPlace = innerGroup.borders_inner_place bd.borderContour.blockInnerSpace = innerGroup.spaces // 5 造型外扩轮廓, 外扩尺寸 const { pls_model, sizeout: sizeout_model } = this.createPolyline_model(block) bd.borderContour.polylinesOutModel = pls_model bd.modelExpandSize = sizeout_model // 6. 2V刀路 外扩轮廓,外扩尺寸 const { pls_2v, sizeout_2v } = this.createPolyline_2vModel(block) bd.borderContour.polylines2vModel = pls_2v || [] bd.vKnifeModelExpandSize = sizeout_2v // 7.同刀辅助 外扩尺寸 let isUseSameKnifeToHelpCut = helpCutStyle || 0 let useSameKnifeToHelpCutGap = helpCutGap || 0 const isSameKnifeToCut = isUseSameKnifeToHelpCut && useSameKnifeToHelpCutGap > 0 if (isSameKnifeToCut == false || bd.isUseSameKnifeToHelpCut == false) { // 未启动同刀辅助, 或 该小板 不需要同刀辅助 bd.useSameKnifeToHelpCutGap = 0 bd.sameKnifeHelpExpandSize = new SizeExpand() } else { const gap = useSameKnifeToHelpCutGap bd.useSameKnifeToHelpCutGap = gap bd.sameKnifeHelpExpandSize = new SizeExpand({ left: gap, right: gap, under: gap, upper: gap }) } // 2V刀路,预洗,同刀辅助开料,出板造型刀 this.resetBlock(block, pm) } /** 重设小板 ,因为板材重新设置 预铣值 或 板外下刀 */ static resetBlock(block: PlaceBlock, placeMaterial: PlaceMaterial) { if (!block.blockDetail) { console.error('BlockPlus.resetBlock: block.blockDetail is undefined', block) return } const pm = placeMaterial const bd = block.blockDetail const preMillingSize = pm.preMillingSize // startDebug(block); if (!bd.borderContour) { console.error('BlockPlus.resetBlock: bd.borderContour is undefined', block) return } // 开料刀 修改了,内部空间发生变化 if (!equal(bd.offsetKnifeRadius, pm.diameter / 2)) { bd.offsetKnifeRadius = pm.diameter / 2 bd.borderContour.cutKnifeChanged() // 4. 板内走刀路径,板内空间 const innerGroup = this.analyeInners(bd, pm.diameter / 2, pm.cutKnifeGap) bd.borderContour.borderModelThrough = innerGroup.borders_inner_org bd.borderContour.cutLinesModelThrough = innerGroup.borders_inner_cut bd.borderContour.borderInnerPlace = innerGroup.borders_inner_place bd.borderContour.blockInnerSpace = innerGroup.spaces } // 因为预铣, 同刀辅助会影响到开料走刀等轮廓,所以要将受影响的轮廓清空,需要的时候再生成 // 预铣 if (!equal(bd.preMillingSize, pm.preMillingSize)) { bd.preMillingSize = preMillingSize bd.borderContour.preValueChanged() } // 同刀辅助 let newTDFZ = 0 if (pm.isHelpCut && pm.helpCutGap > 0 && block.blockDetail.isUseSameKnifeToHelpCut) { newTDFZ = pm.helpCutGap block.blockDetail.sameKnifeHelpExpandSize = new SizeExpand({ left: newTDFZ, right: newTDFZ, upper: newTDFZ, under: newTDFZ }) } else { newTDFZ = 0 block.blockDetail.sameKnifeHelpExpandSize = new SizeExpand() } if (!equal(newTDFZ, bd.useSameKnifeToHelpCutGap)) { bd.useSameKnifeToHelpCutGap = newTDFZ bd.borderContour.sameKnifeGapChanged() } const cutRadius = (pm.diameter + pm.cutKnifeGap) / 2 // 预铣 let off1 = block.blockDetail.preMillingExpandSize || new SizeExpand() // 造型外扩 const off2 = block.blockDetail.modelExpandSize || new SizeExpand() // 2v 板外下刀 const off3 = block.blockDetail.vKnifeModelExpandSize || new SizeExpand() // 同刀辅助 let off4 = block.blockDetail?.sameKnifeHelpExpandSize || new SizeExpand() // 不启用 预铣 // if (preMillingSize < 0.0001) // off1 = new SizeExpand() if (newTDFZ < 0.001) off4 = new SizeExpand() // 预铣+同刀辅助+, 造型外扩,2v刀路 应该取最大值 const off = new SizeExpand() off.left = Math.max(off1.left + off4.left + cutRadius, off2.left, off3.left) off.right = Math.max(off1.right + off4.right + cutRadius, off2.right, off3.right) off.bottom = Math.max(off1.bottom + off4.bottom + cutRadius, off2.bottom, off3.bottom) off.top = Math.max(off1.top + off4.top + cutRadius, off2.top, off3.top) off.setSize() bd.currentSizeExpand = off } /** 小板是否有超出造型或二维刀路 */ static hasModelOutBlock(block: PlaceBlock): boolean { if (block.blockDetail == null) return false if (block.blockDetail.borderContour == null) return false if (block.blockDetail.borderContour.polylinesOutModel == null || block.blockDetail.borderContour.polylines2vModel == null) return false return block.blockDetail.borderContour.polylinesOutModel.length + block.blockDetail.borderContour.polylines2vModel.length > 0 } /** 获得 成品轮廓 isPlaced=false为不旋转的 */ static getFinalBorder(block: PlaceBlock, isPlaced = true, placeStyle?: PlaceStyle): Curve2d[] { const bu = this.getPlacedUnit(block, isPlaced, placeStyle) if (bu == null) { console.error('BlockPlus.getOrgBorderNew: bu is undefined', block) return [] } return bu.borderFinal } /** 获得 开料轮廓-不含预铣 isPlaced=false为不旋转的 */ static getOrgBorder(block: PlaceBlock, isPlaced = true, placeStyle?: PlaceStyle): Curve2d[] { const bu = this.getPlacedUnit(block, isPlaced, placeStyle) if (bu == null) { console.error('BlockPlus.getOrgBorder: bu is undefined', block) return [] } return bu.borderOrg } /** 获得 开料轮廓-不含预铣 isPlaced=false为不旋转的 */ static getOrgBorderNew(block: PlaceBlock, isPlaced = true, placeStyle?: PlaceStyle): Curve2d[] { const bu = this.getPlacedUnitNew(block, isPlaced, placeStyle) if (bu == null) { console.error('BlockPlus.getOrgBorderNew: bu is undefined', block) return [] } return bu.borderOrg } /** 获得当前板 轮廓多段线 */ static getOrgPolyline(block: PlaceBlock): Polyline | null { if (block.blockDetail == null) { console.error('BlockPlus.getOrgPolyline: block.blockDetail is undefined', block) return null } const bd = block.blockDetail.borderContour if (bd == null) { console.error('BlockPlus.getOrgPolyline: bd is undefined', block) return null } if (!bd.polylineOrg) { const border = bd.borderOrg const pl = PolylineHelper.createByCurve2d(border) bd.polylineOrg = pl } return bd.polylineOrg } /** 获得 开料轮廓 _有预铣含预铣 */ static getBorder(block: PlaceBlock, isPlaced = true, placeStyle?: PlaceStyle): Curve2d[] { if (block.blockDetail == null) { console.error('BlockPlus.getBorder: block.blockDetail is undefined', block) return [] } let preSize = block.blockDetail.preMillingSize if (preSize < 0.0001) preSize = 0 // 初始 const baseContour = block.blockDetail.borderContour if (baseContour == null) { console.error('BlockPlus.getBorder: baseContour is undefined', block) return [] } if (!baseContour.border ||(Array.isArray(baseContour.border) && baseContour.border.length ==0)) // 生成 预铣轮廓 { const border = preSize == 0 ? baseContour.borderOrg : baseContour.borderPreMilling baseContour.border = border } // 放置后 const pbu = this.getPlacedUnit(block, isPlaced, placeStyle) if (pbu == null) { console.error('BlockPlus.getBorder_moving_new: pbu is undefined', block) return [] } if (!pbu.border) { pbu.border = this.transformBorder(baseContour.border, pbu.placeStyle, block.cutWidth, block.cutLength) } return pbu.border } /** 获得 开料轮廓—有预铣带预铣-有同刀辅助带同刀辅助 */ static getBorder_sameKnife(block: PlaceBlock, isPlaced = true, placeStyle?: PlaceStyle): Curve2d[] { if (block.blockDetail == null) { console.error('BlockPlus.getBorder_sameKnife: block.blockDetail is undefined', block) return [] } // 如果没有同刀辅助,直接返回开料轮廓 let helpCutGap = block.blockDetail.useSameKnifeToHelpCutGap if (helpCutGap < 0.001) helpCutGap = 0 // 初始 const baseContour = block.blockDetail.borderContour if (baseContour == null) { console.error('BlockPlus.getBorder_sameKnife: baseContour is undefined', block) return [] } if (!baseContour.borderSameKnifeHelpCut) { const borders = this.getBorder(block, false) if (helpCutGap == 0) // 无同刀辅助 { baseContour.borderSameKnifeHelpCut = borders } else { let rounding = block.blockDetail.isOffsetRounding if (block.isUnRegular) rounding = true // 异形板 必须倒角 baseContour.borderSameKnifeHelpCut = this.offsetCurves(borders, helpCutGap, rounding) // 必须倒角,否则 尖角超出 开料范围 } } // 放置后 const pbu = this.getPlacedUnit(block, isPlaced, placeStyle) if (pbu == null) { console.error('BlockPlus.getBorder_moving_new: pbu is undefined', block) return [] } if (!pbu.borderSameKnifeHelpCut) { pbu.borderSameKnifeHelpCut = this.transformBorder(baseContour.borderSameKnifeHelpCut, pbu.placeStyle, block.cutWidth, block.cutLength) } return pbu.borderSameKnifeHelpCut } /** 获得走刀路径(含预铣) isPlaced = false为不旋转 */ /** * * @param block 小板 * @param placeMaterial 开料大板 * @param isPlaced 是否旋转 * @param placeStyle 旋转后的放置方式 * @param config 配置 { isRectBlockChamfer: false, // 矩形板件倒角开料 isUnRegularBlockChamfer: false, // 异形板件倒角开料 } * @returns */ static getCutLines(block: PlaceBlock, placeMaterial: PlaceMaterial, isPlaced = true, placeStyle: PlaceStyle | undefined, config: any): Curve2d[] { // 走刀路径由开料轮廓(含预铣) border_plus 偏移一个刀半径而成 const { isRectBlockChamfer = false, // 矩形板件倒角开料 isUnRegularBlockChamfer = false, // 异形板件倒角开料 } = config if (!block.blockDetail) { console.error('BlockPlus.getCutLines: block.blockDetail is undefined', block) return [] } if (!block.blockDetail.borderContour) { console.error('BlockPlus.getCutLines: block.blockDetail.borderContour is undefined', block) return [] } // 初始 const baseContour = block.blockDetail.borderContour if (!baseContour.cutLines) { const borders = this.getBorder(block, false) // 偏移值 const offvalue = placeMaterial.diameter / 2 // 开料刀的一半 // 是否倒角 let isOffsetRounding = false // block.SaleBlockDetail.IsOffsetRounding; if (block.isUnRegular == false) // 矩形板,设置不倒角 { isOffsetRounding = isRectBlockChamfer } else // 异形板 { // 异形倒角 isOffsetRounding = isUnRegularBlockChamfer } baseContour.cutLines = this.offsetCurves(borders, offvalue, isOffsetRounding) } // 放置后 const pbu = this.getPlacedUnit(block, isPlaced, placeStyle) if (pbu == null) { console.error('BlockPlus.getBorder_moving_new: pbu is undefined', block) return [] } if (!pbu.cutLines) { pbu.cutLines = this.transformBorder(baseContour.cutLines, pbu.placeStyle, block.cutWidth, block.cutLength) } return pbu.cutLines } /** * 获得 同刀辅助 的走刀路径 * @param block 小板 * @param isPlaced 是否翻转 * @param placeStyle 翻转后的放置方式 * @param config 配置 * { isRectBlockChamfer: false, // 矩形板件倒角开料 isUnRegularBlockChamfer: false, // 异形板件倒角 } = config || {} * @returns */ static getCutLines_sameKnife(block: PlaceBlock, placeMaterial: PlaceMaterial, isPlaced = true, placeStyle?: PlaceStyle, config?: any): Curve2d[] { // 同刀辅助 走刀路径 由 开料轮廓 _含预铣_同刀辅助 偏移一个刀半径 厚度 而成 const { isRectBlockChamfer = false, // 矩形板件倒角开料 isUnRegularBlockChamfer = false, // 异形板件倒角开料 } = config || {} if (!block.blockDetail) { console.error('BlockPlus.getCutLines_sameKnife: block.blockDetail is undefined', block) return [] } // 不用同刀辅助 const helpCutGap = block.blockDetail.useSameKnifeToHelpCutGap if (helpCutGap < 0.001) { return this.getCutLines(block, placeMaterial, isPlaced, placeStyle, config) } const baseContour = block.blockDetail.borderContour if (baseContour == null) { console.error('BlockPlus.getCutLines_sameKnife: baseContour is undefined', block) return [] } if (!baseContour.cutLinesSameKnifeHelpCut) { const borders = this.getBorder_sameKnife(block, false) // 偏移值 const kr = placeMaterial.diameter / 2 // 开料刀的一半 // 同刀辅助 不倒角 , // 是否倒角 异形板必须倒角 let isOffsetRounding = false // block.SaleBlockDetail.IsOffsetRounding; if (block.isUnRegular == false) // 矩形板,设置不倒角 { isOffsetRounding = isRectBlockChamfer } else // 异形板 { isOffsetRounding = isUnRegularBlockChamfer } baseContour.cutLinesSameKnifeHelpCut = this.offsetCurves(borders, kr, isOffsetRounding) } // 放置后 const pbu = this.getPlacedUnit(block, isPlaced, placeStyle) if (pbu == null) { console.error('BlockPlus.getBorder_moving_new: pbu is undefined', block) return [] } if (!pbu.cutLinesSameKnifeHelpCut) { pbu.cutLinesSameKnifeHelpCut = this.transformBorder(baseContour.cutLinesSameKnifeHelpCut, pbu.placeStyle, block.cutWidth, block.cutLength) } return pbu.cutLinesSameKnifeHelpCut } /** * 获得 手动排版路径 包括板外下刀等轮廓 * 由开料轮廓 偏移 ( 预铣 ,同刀辅助, 开料刀半径 , 缝隙/2 ) * 再与 二维刀路,板外小刀,造型外扩 合并起来的 */ static getBorder_moving(block: PlaceBlock, placeMaterial: PlaceMaterial, isPlaced = true, placeStyle?: PlaceStyle): Curve2d[] { if (!block.blockDetail || !block.blockDetail.borderContour) { console.error('BlockPlus.getBorder_moving: block.blockDetail or block.blockDetail.borderContour is undefined', block) return [] } this.theBlock = block const bd = block.blockDetail // 初始 const baseContour = bd.borderContour if (baseContour == null) { console.error('BlockPlus.getBorder_moving: baseContour is undefined', block) return [] } if (!baseContour.borderMoving) { // 1.开料轮廓<带预铣> const borders = this.getBorder(block, false) // 偏移值 = 同刀辅助 + 刀半径 + 缝隙 /2 const cutGap = block.blockDetail.useSameKnifeToHelpCutGap + (placeMaterial.diameter + placeMaterial.cutKnifeGap) / 2 // 是否倒角(如果倒角,手动排版,拖拉时,停靠点不便计算,所以设置成不倒角,然后截断> const isOffsetRounding = false // 原轮廓 let border_moving = this.offsetCurves(borders, cutGap, isOffsetRounding) const pl = this.borderToPolyline(border_moving) // 造型的外扩,2v刀路的 const pls_m = baseContour.polylinesOutModel.concat(baseContour.polylines2vModel) // 合并 const rpl = this.unionPolylines(pl, pls_m) // border_moving = this.polylineToBorder(rpl) baseContour.borderMoving = border_moving } // 放置后 const pbu = this.getPlacedUnit(block, isPlaced, placeStyle) if (pbu == null) { console.error('BlockPlus.getBorder_moving_new: pbu is undefined', block) return [] } return pbu.borderMoving } static getBorder_moving_new(block: PlaceBlock, pb: PlaceMaterial, isPlaced = true, placeStyle: PlaceStyle): Curve2d[] { if (block.blockDetail == null) { console.error('BlockPlus.getBorder_moving_new: block.blockDetail is undefined', block) return [] } this.theBlock = block const bd = block.blockDetail // 初始 const baseContour = bd.borderContour if (!baseContour) { console.error('BlockPlus.getBorder_moving_new: baseContour is undefined', block) return [] } if (!baseContour.borderMoving) { // 1.开料轮廓<带预铣> const borders = this.getBorder(block, false) // 偏移值 = 同刀辅助 + 刀半径 + 缝隙 /2 const cutGap = block.blockDetail.useSameKnifeToHelpCutGap + (pb.diameter + pb.cutKnifeGap) / 2 // 是否倒角(如果倒角,手动排版,拖拉时,停靠点不便计算,所以设置成不倒角,然后截断> const isOffsetRounding = false // 原轮廓 let border_moving = this.offsetCurves(borders, cutGap, isOffsetRounding) const pl = this.borderToPolyline(border_moving) // 造型的外扩,2v刀路的 const pls_m = baseContour.polylinesOutModel.concat(baseContour.polylines2vModel) // 合并 const rpl = this.unionPolylines(pl, pls_m) // border_moving = this.polylineToBorder(rpl) baseContour.borderMoving = border_moving } // 放置后 const pbu = this.getPlacedUnit(block, isPlaced, placeStyle) if (pbu == null) { console.error('BlockPlus.getBorder_moving_new: pbu is undefined', block) return [] } if (!pbu.borderMoving) { pbu.borderMoving = this.transformBorder(baseContour.borderMoving, pbu.placeStyle, block.cutWidth, block.cutLength) } return pbu.borderMoving } static getOutModelPloyline(block: PlaceBlock, isPlaced = true, placeStyle?: PlaceStyle): Polyline[] { if (!block.blockDetail || !block.blockDetail.borderContour) { console.error('BlockPlus.getOutModelPloyline: block.blockDetail or block.blockDetail.borderContour is undefined', block) return [] } const bd = block.blockDetail // 初始 const baseContour = bd.borderContour if (baseContour == null) { console.error('BlockPlus.getOutModelPloyline: baseContour is undefined', block) return [] } const pls_m = baseContour.polylinesOutModel.concat(baseContour.polylines2vModel) if (placeStyle == PlaceStyle.FRONT) return pls_m const pbu = this.getPlacedUnit(block, isPlaced, placeStyle) if (pbu == null) { console.error('BlockPlus.getOutModelPloyline: pbu is undefined', block) return [] } let newPls: Polyline[] = [] for (let pl of pls_m) { let newpl = this.transformPolyline(pl, pbu.placeStyle, block.cutWidth, block.cutLength) newPls.push(newpl) } return newPls } static theBlock /** 获取轮廓用于王者优化,预铣 + 同刀辅助 ,造型外扩 + 2维刀路外扩 */ static getBorder_WZYH(block: PlaceBlock, placeMaterial: PlaceMaterial, isPlaced = true, placeStyle?: PlaceStyle): Curve2d[] { this.theBlock = block const bd = block.blockDetail if (!bd || !bd.borderContour) { console.error('BlockPlus.getBorder_WZYH: block.blockDetail or block.blockDetail.borderContour is undefined', block) return [] } const baseContour = bd.borderContour // 生成 同刀辅助 路径 <原方向》 if (baseContour.borderKingOptimize == null) { // 开料轮廓 <同刀辅助> const borders = this.getBorder_sameKnife(block, false) // 偏移值= 同刀辅助 + 刀半径 + + 缝隙 /2 const cutGap = (placeMaterial.diameter + placeMaterial.diameter) / 2 // 是否倒角 < 如果倒角,手动排版,拖拉时,停靠点 不好计算,所以设置成不倒角,然后截断>, const isOffsetRounding = bd.isOffsetRounding // 走刀路径 const borders2 = this.offsetCurves(borders, cutGap, isOffsetRounding) const pl = this.borderToPolyline(borders2) // 造型的外扩,2v刀路的 const pls_m = baseContour.polylinesOutModel.concat(baseContour.polylines2vModel) // 合并 const rpl = this.unionPolylines(pl, pls_m) baseContour.borderKingOptimize = this.polylineToBorder(rpl) } // 放置后 const pbu = this.getPlacedUnit(block, isPlaced, placeStyle) if (pbu == null) { return [] } if (!pbu.borderKingOptimize) { pbu.borderKingOptimize = this.transformBorder(baseContour.borderKingOptimize, pbu.placeStyle, block.cutWidth, block.cutLength) } return pbu.borderKingOptimize } /** 获得 内部轮廓 <挖穿造型> */ static getBorders_inner(block: PlaceBlock, isPlaced = true, placeStyle?: PlaceStyle): Curve2d[][] { const bu = this.getPlacedUnit(block, isPlaced, placeStyle) if (bu == null) { console.error('BlockPlus.getBorders_inner: 获取板的内部轮廓失败', block) return [] } // 如果没有内部轮廓 if (bu.borderModelThrough == null) { const borders = this.getBorders_inner(block, false) const borders_off: Curve2d[][] = [] for (const border of borders) { const newBorder = this.transformBorder(border, bu.placeStyle, block.cutWidth, block.cutLength) borders_off.push(newBorder) } bu.borderModelThrough = borders_off } return bu.borderModelThrough } /** 获得 内部轮廓 <挖穿造型> */ static getBorders_innerNew(block: PlaceBlock, isPlaced = true, placeStyle?: PlaceStyle): Curve2d[][] { const bu = this.getPlacedUnitNew(block, isPlaced, placeStyle) if (bu == null) { console.error('BlockPlus.getBorders_innerNew: 获取板的内部轮廓失败', block) return [] } if (bu.borderModelThrough == null) { const borders = this.getBorders_innerNew(block, false) const borders_off: Curve2d[][] = [] for (const border of borders) { const newBorder = this.transformBorderNew(border, bu.placeStyle, block.cutWidth, block.cutLength) borders_off.push(newBorder) } bu.borderModelThrough = borders_off } return bu.borderModelThrough } /** 获得内部轮廓 <挖穿造型> 半径 */ static getBorders_inner_r(block: PlaceBlock) { if (block.blockDetail == null || block.blockDetail.borderContour == null) { console.error('BlockPlus.getBorders_inner_r: block.blockDetail or block.blockDetail.borderContour is undefined', block) return [] } return block.blockDetail.borderContour.borderModelThroughR } /** 获得 内部走刀轮廓 <挖穿造型> */ static getCutLines_inner(block: PlaceBlock, isPlaced = true, placeStyle?: PlaceStyle): Curve2d[][] { const bu = this.getPlacedUnit(block, isPlaced, placeStyle) if (bu == null) { console.error('BlockPlus.getCutLines_inner: 获取板的内部走刀轮廓失败', block) return [] } if (bu.cutLinesModelThrough == null) { const borders = this.getCutLines_inner(block, false) const borders_off: Curve2d[][] = [] for (const border of borders) { const newBorder = this.transformBorder(border, bu.placeStyle, block.cutWidth, block.cutLength) borders_off.push(newBorder) } bu.cutLinesModelThrough = borders_off } return bu.cutLinesModelThrough } /** 获得 内部排版轮廓 <挖穿造型> */ static getInnerPlaceBorders(block: PlaceBlock, isPlaced = true, placeStyle?: PlaceStyle): Curve2d[][] { const bu = this.getPlacedUnit(block, isPlaced, placeStyle) if (bu == null) { console.error('BlockPlus.getInnerPlaceBorders: 获取板的内部排版轮廓失败', block) return [] } if (bu.borderInnerPlace == null) { const borders = this.getInnerPlaceBorders(block, false) const borders_off: Curve2d[][] = [] for (const border of borders) { const newBorder = this.transformBorder(border, bu.placeStyle, block.cutWidth, block.cutLength) borders_off.push(newBorder) } bu.borderInnerPlace = borders_off } return bu.borderInnerPlace } /** 获得 板内空间 《挖穿孔洞 + 缺角》 */ static getSpaces(block: PlaceBlock, pm: PlaceMaterial): PlaceSpace[] { if (block.blockDetail == null || block.blockDetail.borderContour == null) { console.error('BlockPlus.getSpaces: block.blockDetail or block.blockDetail.borderContour is undefined', block) return [] } const bu = block.blockDetail.borderContour if (!bu.blockOuterSpace) bu.blockOuterSpace = this.createOutSpaces(block, pm) // 缺角空间不存在,创建 // 挖穿孔洞 + 缺角 return bu.blockInnerSpace.concat(bu.blockOuterSpace) } static getInnerSpaces(block: PlaceBlock): PlaceSpace[] { const bu = this.getPlacedUnit(block, false) // 挖穿孔洞 return bu ? bu.blockInnerSpace : [] } static getModelHole(block: PlaceBlock, isPlaced = true, placeStyle?: PlaceStyle): Curve2d[][] { const bu = this.getPlacedUnit(block, isPlaced, placeStyle) if (bu == null) { console.error('BlockPlus.getModelHole: 获取板的轮廓集失败', block) return [] } if (!bu.borderInnerPlace) { if (block.blockDetail == undefined) { console.error('BlockPlus.getModelHole: block.blockDetail is undefined', block) return [] } if (block.blockDetail.borderContour == undefined) { console.error('BlockPlus.getModelHole: block.blockDetail.borderContour is undefined', block) return [] } const org_list = block.blockDetail.borderContour.borderInnerPlace if (!org_list || org_list.length == 0) return [] const liset: Curve2d[][] = [] for (const cur of org_list) { const newCur = this.transformBorder(cur, bu.placeStyle, block.cutWidth, block.cutLength) if (newCur) liset.push(newCur) } bu.borderInnerPlace = liset } return bu.borderInnerPlace } /** 获得 板的轮廓多段线(包括内部挖穿) */ static getOrgPloylines(block: PlaceBlock, isPlaced = true, placeStyle?: PlaceStyle) { const borderPlus = this.getBorder(block, isPlaced, placeStyle) const innerBorders = this.getBorders_inner(block, isPlaced, placeStyle) const pl = this.borderToPolyline(borderPlus) const pls_inner = new Array() for (const border of innerBorders) { const npl = this.borderToPolyline(border) pls_inner.push(npl) } return { pl, pls_inner } } /** 获得 板的开料多段线(包括内部挖穿) */ static getCutPloylines(block: PlaceBlock, pm: PlaceMaterial, isPlaced = true, placeStyle?: PlaceStyle) { const borderPlus = this.getCutLines_sameKnife(block, pm, isPlaced, placeStyle) const innerBorders = this.getCutLines_inner(block, isPlaced, placeStyle) const pl = this.borderToPolyline(borderPlus) const pls_inner = new Array() for (const border of innerBorders) { const npl = this.borderToPolyline(border) pls_inner.push(npl) } return { pl, pls_inner } } /** 获得小板 板外造型轮廓 */ static getOutModelBorders(block: PlaceBlock, isPlaced = true, placeStyle?: PlaceStyle) { // b1.SaleBlockDetail.borderUnit.polylines_outModel // b1.SaleBlockDetail.borderUnit.polylines_2vModel const bu = this.getPlacedUnit(block, isPlaced, placeStyle) if (bu == null) { console.error('BlockPlus.getOutModelBorders: 获取板的轮廓集失败', block) return [] } if (block.blockDetail == undefined) { console.error('BlockPlus.getOutModelBorders: block.blockDetail is undefined', block) return [] } if (block.blockDetail.borderContour == undefined) { console.error('BlockPlus.getOutModelBorders: block.blockDetail.borderContour is undefined', block) return [] } if (bu.polylinesOutModel == null) { const polylines_outModel = block.blockDetail.borderContour.polylinesOutModel const new_outModels: Polyline[] = [] for (const border of polylines_outModel) { const newBorder = this.transformPolyline(border, bu.placeStyle, block.cutWidth, block.cutLength) new_outModels.push(newBorder) } bu.polylinesOutModel = new_outModels } if (bu.polylines2vModel == null) { const polylines_2vModel = block.blockDetail.borderContour.polylines2vModel const new_outModels: Polyline[] = [] for (const border of polylines_2vModel) { const newBorder = this.transformPolyline(border, bu.placeStyle, block.cutWidth, block.cutLength) new_outModels.push(newBorder) } bu.polylines2vModel = new_outModels } return bu.polylinesOutModel.concat(bu.polylines2vModel) } /** 获得小板外形轮廓 */ static getOrgContour(block: PlaceBlock): any { if (!block.blockDetail) { console.error('BlockPlus.getOrgContour: block.blockDetail is undefined', block) return null } if (!block.blockDetail.orgContourData) { const pts: any = [] const buls: any = [] if (!block.isUnRegular) { pts.push({ x: 0, y: 0 }) pts.push({ x: block.width, y: 0 }) pts.push({ x: block.width, y: block.length }) pts.push({ x: 0, y: block.length }) buls.push(0) buls.push(0) buls.push(0) buls.push(0) } else // 矩形板 { for (const p of block.blockDetail.orgPoints) { pts.push({ x: p.pointX, y: p.pointY }) buls.push(p.curve) } } block.blockDetail.orgContourData = { pts, buls } } return block.blockDetail.orgContourData } /** 获得板的 轮廓集 isPlaced=false为不旋转的 */ private static getPlacedUnit(block: PlaceBlock, isPlaced = true, style?: PlaceStyle): PlaceBorderContour | null { if (!block.blockDetail) { console.error('BlockPlus.getPlacedUnit: block.blockDetail is undefined', block) return null } if (block.blockDetail.borderContour == undefined) { console.error('BlockPlus.getPlacedUnit: block.blockDetail.borderContour is undefined', block) return null } const baseContour = block.blockDetail.borderContour if (isPlaced == false) style = PlaceStyle.FRONT if (isPlaced == true) { if (style == undefined || style == null) style = block.placeStyle } if (style == undefined) { style = PlaceStyle.FRONT } if (style == PlaceStyle.FRONT) return baseContour let placeContour = baseContour.placeContours.find(t => t.placeStyle == style) if (placeContour == null) { const border_final = this.transformBorder(baseContour.borderFinal, style, block.width, block.length) const border_org = this.transformBorder(baseContour.borderOrg, style, block.cutWidth, block.cutLength) placeContour = new PlaceBorderContour(style, border_final, border_org) baseContour.placeContours.push(placeContour) } return placeContour } /** * 获得板的 轮廓集 isPlaced=false为不旋转的 * @param block * @param isPlaced * @param style * @returns */ private static getPlacedUnitNew(block: PlaceBlock, isPlaced = true, style?: PlaceStyle): PlaceBorderContour | null { if (!block.blockDetail) { console.error('BlockPlus.getPlacedUnitNew: block.blockDetail is undefined', block) return null } if (block.blockDetail.borderContour == undefined) { console.error('BlockPlus.getPlacedUnitNew: block.blockDetail.borderContour is undefined', block) return null } const baseContour = block.blockDetail.borderContour if (isPlaced == false) style = PlaceStyle.FRONT if (isPlaced == true) { if (style == undefined || style == null) style = block.placeStyle } if (style == undefined) { style = PlaceStyle.FRONT } if (style == PlaceStyle.FRONT) return baseContour let placeContour = baseContour.placeContours.find(t => t.placeStyle == style) if (placeContour == null) { const border_final = this.transformBorderNew(baseContour.borderFinal, style, block.width, block.length) const border_org = this.transformBorderNew(baseContour.borderOrg, style, block.cutWidth, block.cutLength) placeContour = new PlaceBorderContour(style, border_final, border_org) baseContour.placeContours.push(placeContour) } return placeContour } /** 创建 小板成品轮廓 */ private static createFinalBorder(bd: PlaceBlockDetail, block: PlaceBlock): Curve2d[] { const orgPoints = bd.orgPoints const orgBorderCurveList = new Array() if (orgPoints && orgPoints.length > 1) // 异形 { const count = orgPoints.length for (let i = 0; i < count; i++) { const p0 = orgPoints[i] const p1 = i == count - 1 ? orgPoints[0] : orgPoints[i + 1] const sideHoleCount = bd.holeListSide.filter(t => t.faceId == i).length if (p0.curve == 0) // 直线 { const newLine = Line2d.New(p0.pointX, p0.pointY, p1.pointX, p1.pointY) newLine.tagData = p0.sealSize newLine.tagData2 = sideHoleCount orgBorderCurveList.push(newLine) p0.radius = 0 } else // 曲线 { const crc = Arc2d.New(p0.pointX, p0.pointY, p1.pointX, p1.pointY, p0.curve) crc.tagData = p0.sealSize crc.tagData2 = sideHoleCount p0.radius = crc.m_Radius orgBorderCurveList.push(crc) } } } else // 矩形板 { const w = block.width const l = block.length const line0 = Line2d.New(0, 0, w, 0) line0.tagData = block.sealBottom line0.tagData2 = block.holeCountBottom() const line1 = Line2d.New(w, 0, w, l) line1.tagData = block.sealRight line1.tagData2 = block.holeCountRight() const line2 = Line2d.New(w, l, 0, l) line2.tagData = block.sealTop line2.tagData2 = block.holeCountTop() const line3 = Line2d.New(0, l, 0, 0) line3.tagData = block.sealLeft line3.tagData2 = block.holeCountLeft() orgBorderCurveList.push(line0) orgBorderCurveList.push(line1) orgBorderCurveList.push(line2) orgBorderCurveList.push(line3) } return orgBorderCurveList } /** 创建 开料轮廓 */ private static createOrgBorder(bd: PlaceBlockDetail): Curve2d[] { const borders = new Array() if (bd.points && bd.points.length > 1) // 异形 { const count = bd.points.length for (let i = 0; i < count - 1; i++) // 异形点(无封边,起点终点 是重复的) { const p0 = bd.points[i] const p1 = i == count - 1 ? bd.points[0] : bd.points[i + 1] const sideHoleCount = bd.holeListSide.filter(t => t.faceId == i).length if (p0.curve == 0) // 直线 { const newLine = Line2d.New(p0.pointX, p0.pointY, p1.pointX, p1.pointY) newLine.tagData = p0.sealSize newLine.tagData2 = sideHoleCount borders.push(newLine) p0.radius = 0 } else // 曲线 { const crc = Arc2d.New(p0.pointX, p0.pointY, p1.pointX, p1.pointY, p0.curve) crc.tagData = p0.sealSize crc.tagData2 = sideHoleCount p0.radius = crc.m_Radius if (p0.radius < 2) { p0.curve = 0 p0.radius = 0 } borders.push(crc) } } } else // 矩形板 { const w = bd.cutWidth const l = bd.cutLength const line0 = Line2d.New(0, 0, w, 0) const line1 = Line2d.New(w, 0, w, l) const line2 = Line2d.New(w, l, 0, l) const line3 = Line2d.New(0, l, 0, 0) borders.push(line0) borders.push(line1) borders.push(line2) borders.push(line3) } return borders } /** 创建预铣轮廓 */ private static creatOrgBorderWithPrevCut(block: PlaceBlock, border: Curve2d[], preSize: number) { // 矩形板 const newBorders: Curve2d[] = [] const newSizeExpand = new SizeExpand() if (!block.isUnRegular) { let x1 = 0 let y1 = 0 let x2 = block.cutWidth let y2 = block.cutLength if (block.isUnRegular == false) // 矩形板 { if (block.sealLeft > 0.001) { x1 -= preSize newSizeExpand.left = preSize } if (block.sealRight > 0.001) { x2 += preSize newSizeExpand.right = preSize } if (block.sealBottom > 0.001) { y1 -= preSize newSizeExpand.bottom = preSize } if (block.sealTop > 0.001) { y2 += preSize newSizeExpand.top = preSize } } newBorders.push(Line2d.New(x1, y1, x2, y1)) newBorders.push(Line2d.New(x2, y1, x2, y2)) newBorders.push(Line2d.New(x2, y2, x1, y2)) newBorders.push(Line2d.New(x1, y2, x1, y1)) newSizeExpand.setSize() return { newBorders, newSizeExpand } } // 二。异形板 // 2.1 先分析 每条原始边 是否预铣 if (!block.blockDetail) { console.error("创建预铣轮廓时,block.blockDetail 为空", block); return; } const bd = block.blockDetail for (let i = 0; i < bd.orgPoints.length; i++) { let s = i - 1 let j = i + 1 if (s == -1) s = bd.orgPoints.length - 1 if (j == bd.orgPoints.length) j = 0 const p0 = bd.orgPoints[s] const p1 = bd.orgPoints[i] const p2 = bd.orgPoints[j] p1.isPreCutRequired = checkYX(p0, p1, p2, block.width, block.length) } // 2.1.5 同一边,如果有缺角,则都不能预铣 for (let i = 0; i < bd.orgPoints.length - 1; i++) { const j = (i + 1) % bd.orgPoints.length const pi = bd.orgPoints[i] const pj = bd.orgPoints[j] // if(pi.needPreCut==false) continue; // 垂直或平行 let isVertical = equal(pi.pointX, pj.pointX) if (isVertical == false) { if (equal(pi.pointY, pj.pointY)) { isVertical = false } else { continue // 斜线 } } for (let m = j; m < bd.orgPoints.length; m++) { const n = (m + 1) % bd.orgPoints.length const pm = bd.orgPoints[m] const pn = bd.orgPoints[n] // 垂直 ,同边 有缝隙,多段线 ,不能预铣 if (isVertical && equal(pi.pointX, pm.pointX) && equal(pi.pointX, pn.pointX)) { pi.isPreCutRequired = false pm.isPreCutRequired = false } // 水平 ,同边 有缝隙,多段线 ,不能预铣 if (isVertical == false && equal(pi.pointY, pm.pointY) && equal(pi.pointY, pn.pointY)) { pi.isPreCutRequired = false pm.isPreCutRequired = false } } } // 2.2 生成预铣轮廓 for (let i = 0; i < border.length; i++) { const cur = border[i] let newCur: Curve2d if (cur instanceof Arc2d) { newCur = new Arc2d(cur.StartPoint, cur.EndPoint, cur.Bul) } else { newCur = new Line2d(cur.StartPoint, cur.EndPoint) } if ((newCur instanceof Line2d) && newCur.m_Length < 0.001) continue // 曲线肯定不能偏移, // 直线的话,需要跟 板原始轮廓边 比对确定是否需要偏移 const curNeedOff = preSize > 0 && needPrev(cur) if (curNeedOff) { // 偏移 const line = cur as Line2d newCur = line.Offset(preSize) } // 判断前一条边的终点是否 != 当前边的起点,需要加一条连接线 if (newBorders.length > 0) { const pLast = newBorders[newBorders.length - 1] if (equal2Point(pLast.EndPoint, newCur.StartPoint) == false) { let hasJD = false if ((pLast instanceof Line2d) && (newCur instanceof Line2d)) { const p_jds: Point2d[] = [] newCur.IntersectWith(pLast, p_jds) if (p_jds.length == 1) { pLast.EndPoint = new Point2d(p_jds[0].m_X, p_jds[0].m_Y) newCur.StartPoint = new Point2d(p_jds[0].m_X, p_jds[0].m_Y) hasJD = true } } if (hasJD == false) // 直接连接 { const linkLine = new Line2d(pLast.EndPoint, newCur.StartPoint) newBorders.push(linkLine) } } } // 插入新的边 newBorders.push(newCur) } // 2.3 闭合 最后一边 ,是否与 第一条边 连接 const firstB = newBorders[0] const lastB = newBorders[newBorders.length - 1] if (equal2Point(lastB.EndPoint, firstB.StartPoint) == false) { // 如果前后都是直线则求交点, 直接延长直线 let hasJD = false if ((firstB instanceof Line2d) && (lastB instanceof Line2d)) { const p_jds: Point2d[] = [] lastB.IntersectWith(firstB, p_jds) if (p_jds.length == 1) { lastB.EndPoint = new Point2d(p_jds[0].m_X, p_jds[0].m_Y) firstB.StartPoint = new Point2d(p_jds[0].m_X, p_jds[0].m_Y) hasJD = true } } if (hasJD == false) // 直接连接 { const linkLine = new Line2d(lastB.EndPoint, firstB.StartPoint) newBorders.push(linkLine) } } // 2.4 生成外扩 let xz = 0; let xy = block.cutWidth; let yx = 0; let ys = block.cutLength for (const cur of newBorders) { const p = cur.StartPoint if (p.m_X < xz) xz = p.m_X if (p.m_X > xy) xy = p.m_X if (p.m_Y < yx) yx = p.m_Y if (p.m_Y > ys) ys = p.m_Y } newSizeExpand.left = -xz newSizeExpand.right = xy - block.cutWidth newSizeExpand.bottom = -yx newSizeExpand.top = ys - block.cutLength newSizeExpand.setSize() return { newBorders, newSizeExpand } // 判断外轮廓点p1是否需要预铣 function checkYX(p0, p1, p2, width, length) { if (p1.curve != 0) return false // 本身是圆弧 if (p1.sealSize < 0.001) return false// 本身不封边 if (p0.curve != 0) return false // 前一段是圆弧 if (p2.curve != 0) return false// 后一段是圆弧 // p1.p2 只要有一点在板内,就不行 const isIn1 = (p1.pointX > 0.001 && p1.pointX < width - 0.001 && p1.pointY > 0.001 && p1.pointY < length - 0.001) if (isIn1) return false const isIn2 = (p2.pointX > 0.001 && p2.pointX < width - 0.001 && p2.pointY > 0.001 && p2.pointY < length - 0.001) if (isIn2) return false return true // 需要预洗 } // 判断边是否预铣 function needPrev(line: Curve2d) { if (!block.blockDetail) { console.error("判断边是否预铣时,block.blockDetail 为空", block); return false; } if (!(line instanceof Line2d)) return false if (block.isUnRegular == false) // 矩形 { if (line.StartPoint.m_Y == 0 && line.EndPoint.m_Y == 0) return block.sealBottom > 0 if (line.StartPoint.m_X == block.cutWidth && line.EndPoint.m_X == block.cutWidth) return block.sealRight > 0 if (line.StartPoint.m_Y == block.cutLength && line.EndPoint.m_Y == block.cutLength) return block.sealTop > 0 if (line.StartPoint.m_X == 0 && line.EndPoint.m_X == 0) return block.sealLeft > 0 return false } const offx = block.blockDetail.offsetX const offy = block.blockDetail.offsetY const x1 = line.StartPoint.m_X const y1 = line.StartPoint.m_Y const x2 = line.EndPoint.m_X const y2 = line.EndPoint.m_Y const tag0 = (x2 - x1) / getDis(x1, y1, x2, y2) // 找出原始轮廓中 对应的边 , 是否有 预洗信息 for (let i = 0; i < block.orgPoints.length; i++) { let j = i + 1 if (j == block.orgPoints.length) j = 0 if (block.orgPoints[i].isPreCutRequired == false) continue const tag1 = (block.orgPoints[j].pointX - block.orgPoints[i].pointX) / getDis(block.orgPoints[i].pointX, block.orgPoints[i].pointY, block.orgPoints[j].pointX, block.orgPoints[j].pointY) if (equal(tag0, tag1, 0.1) == false) continue // 不平行 const dis = getDis_PointLine(x1, y1, x2, y2, block.orgPoints[i].pointX - offx, block.orgPoints[i].pointY - offy) if (dis < block.orgPoints[i].sealSize * 2 + 3) return true } return false } function equal2Point(p1, p2, dis = 0.001) { const x1 = p1.m_X const y1 = p1.m_Y const x2 = p2.m_X const y2 = p2.m_Y const len1 = (x1 - x2) * (x1 - x2) const len2 = (y1 - y2) * (y1 - y2) const len = Math.sqrt(len2 + len1) return len < dis } } /** 创建 挖穿造型,走刀路径,板内空间 */ private static analyeInners(bd: PlaceBlockDetail, cutR, cutGap = 1) { /** 挖穿轮廓 */ const borders_inner_org: Curve2d[][] = [] /** 挖穿轮廓 刀半径 */ const borders_inner_r: number[] = [] /** 挖穿走刀路径 */ const borders_inner_cut: Curve2d[][] = [] /** 挖穿排版轮廓 <加缝隙> */ const borders_inner_place: Curve2d[][] = [] /** 排版空间 */ const spaces: PlaceSpace[] = [] for (const m of bd.models) { if (m.depth < bd.thickness - 0.01) continue // 非挖穿 if (m.isVKnifeModel()) continue // 挖穿的二维刀路造型 不计算. if (m.isCutting == false) continue // 不加工 // 挖穿轮廓 <切割后的>,顺时针的 let baseBorder if (m.hasContour()) // 有轮廓数据 { let ptsArr = m.originModeling.outline.map(e => e.pts) const pts = ptsArr.map((t) => { return { x: t.x, y: t.y } }) for (let i = 0; i < pts.length; i++) { pts[i].bul = m.originModeling.outline[i].buls } baseBorder = this.createBorderByPts(pts) } else // 没有轮廓数据,用走刀路径 偏移 { const pts = m.pointList.map((t) => { return { x: t.pointX, y: t.pointY, bul: t.curve } }) baseBorder = this.createBorderByPts(pts) baseBorder = this.offsetCurves(baseBorder, m.knifeRadius, false) } // 铣刀路径 const border_cut = this.offsetCurves(baseBorder, -m.realKnifeRadius, false) // 排版轮廓 const placeGap = Math.max(m.realKnifeRadius, cutR) * 2 - cutR + cutGap / 2 // 取造型刀,开料刀 最大的 const border_place = this.offsetCurves(baseBorder, -placeGap, false) borders_inner_org.push(baseBorder) borders_inner_r.push(m.realKnifeRadius) borders_inner_cut.push(border_cut) borders_inner_place.push(border_place) // 内部空间 let createdSpaces = false if (m.hasContour()) // 简单形状,直接生成矩形,圆形 { // 是否矩形,圆形 const rect = isRect(m.originModeling.outline) || isCircle(m.originModeling.outline) if (rect) { const gap = placeGap rect.x += gap rect.y += gap rect.w -= gap * 2 rect.l -= gap * 2 if (rect.w > 100 && rect.l > 100) { const space = new PlaceSpace(rect.x, rect.y, rect.w, rect.l) space.isBlockInnerSpace = true spaces.push(space) } createdSpaces = true } } if (createdSpaces == false) // 复杂形状 { const tmpSpaces = SpacePlus.borderToSpace(border_place) if (tmpSpaces) { tmpSpaces.forEach(t => t.isBlockInnerSpace = true) tmpSpaces.forEach(t => spaces.push(t)) } } } return { borders_inner_org, borders_inner_r, borders_inner_cut, borders_inner_place, spaces } function isRect(outline: any): any { const pts = outline.map(e => e.pts) //outline.pts const buls = outline.map(e => e.buls) // outline.buls if (buls.length != 5) return null if (buls.some(t => t != 0)) return null if (pts.length != 5) return null if (pts[4].x != pts[0].x || pts[4].y != pts[0].y) return null return getRect(pts[0], pts[1], pts[2], pts[3]) } function isCircle(outline: any): any { // const pts = outline.pts // const buls = outline.buls const pts = outline.map(e => e.pts) //outline.pts const buls = outline.map(e => e.buls) // outline.buls if (buls.length != 3) return null if (equal(buls[0], 1) && equal(buls[1], 1) && equal(buls[2], 0)) { const p0 = Array.isArray(outline) ? outline[0].pts : outline?.pts[0] const p1 = Array.isArray(outline) ? outline[1].pts : outline?.pts[1] let x0 = Math.min(p0.x, p1.x) let x1 = Math.max(p0.x, p1.x) let y0 = Math.min(p0.y, p1.y) let y1 = Math.max(p0.y, p1.y) let r if (equal(x0, x1)) { r = (y1 - y0) / 2 x0 -= r x1 += r } else { r = (x1 - x0) / 2 y0 -= r y1 += r } const t = r / Math.SQRT2 const dis = r - t return { x: x0 + dis, y: y0 + dis, w: t * 2, l: t * 2 } } } } /** 创建 缺角空间 */ private static createOutSpaces(block: PlaceBlock, placeMaterial: PlaceMaterial): PlaceSpace[] { if (block.blockDetail == undefined) { console.error("创建缺角空间时,block.blockDetail 为空", block); return []; } if (block.blockDetail.borderContour == null) { console.error("创建缺角空间时,block.blockDetail.borderContour 为空", block); return []; } if (block.isUnRegular == false && (block.blockDetail.borderContour.polylines2vModel.length + block.blockDetail.borderContour.polylinesOutModel.length == 0)) return [] // 矩形 const pm = placeMaterial let border = this.getBorder_WZYH(block, placeMaterial, false) // 获得全偏移的轮廓 const pl = this.borderToPolyline(border, true) /** 空间 */ let spaces: PlaceSpace[] = [] const reg = { z: 0, x: 0, y: 0, s: 0, w: 0, l: 0 } // 外围空间 左右上下 ,宽长 reg.z = pl.BoundingBox.min.x reg.x = pl.BoundingBox.min.y reg.y = pl.BoundingBox.max.x reg.s = pl.BoundingBox.max.y reg.w = -reg.z + reg.y reg.l = -reg.x + reg.s const checkSize = new SizeExpand() // 空间验证 checkSize.left = -block.sizeExpand()?.left - (pm.diameter + pm.cutKnifeGap) / 2 checkSize.right = block.cutWidth + block.sizeExpand()?.right + (pm.diameter + pm.cutKnifeGap) / 2 checkSize.bottom = -block.sizeExpand()?.bottom - (pm.diameter + pm.cutKnifeGap) / 2 checkSize.top = block.cutLength + block.sizeExpand()?.top + (pm.diameter + pm.cutKnifeGap) / 2 const offDis = pm.preMillingSize + 0.01 // 点判断是否在边缘 误差 一个预铣值 border = border.slice(0) // 确保 第一条 起点在边缘 let count = 0 // 移动不能大于一个循环,避免死循环 while (count < border.length) { const line0 = border[0] const isOnBorder = onBorder(line0.StartPoint) if (isOnBorder) break // 如果起点在板内,移动到最后面 border.shift() border.push(line0) count++ } SpacePlus.setSpaceStyle(block) let lines: Curve2d[] = [] // for (let i = 0; i < border.length; i++) { const line = border[i] const spOnBorder = onBorder(line.StartPoint) const epOnBorder = onBorder(line.EndPoint) const isxl = isXL(line) if (spOnBorder && (!epOnBorder || isxl)) // 起始线 { lines = [] lines.push(line) } if (!spOnBorder && !epOnBorder) // 板内线 { if (lines && lines.length > 0 && lines[lines.length - 1] != line) lines.push(line) } if (epOnBorder && (!spOnBorder || isxl)) // 结束线,开始分析空间 { if (lines && lines.length > 0) { if (lines[lines.length - 1] != line) lines.push(line) const newspaces = createSpace(lines) if (newspaces && newspaces.length > 0) spaces = spaces.concat(newspaces) lines = [] } } } const newSpaces: PlaceSpace[] = [] // 空间验证 for (const space of spaces) { let x1 = space.x let y1 = space.y let x2 = space.topX() let y2 = space.topY() if (x1 < checkSize.left) x1 = checkSize.left if (y1 < checkSize.bottom) y1 = checkSize.bottom if (x2 > checkSize.right) x2 = checkSize.right if (y2 > checkSize.top) y2 = checkSize.top const newspace = PlaceSpace.create(x1, y1, x2, y2) newSpaces.push(newspace) } return newSpaces /** 缺角的开始? 起点在边缘,终点在板内的 或 斜线 (终点在另外一边) */ function isBegin(curve: Curve2d) { return onBorder(curve.StartPoint) && (!onBorder(curve.EndPoint) || isXL(curve)) } /** 缺角的结束? 终点在边缘的 起点在板内 或 (起点点在另外一边) */ function isEnd(curve: Curve2d) { return onBorder(curve.EndPoint) && (!onBorder(curve.StartPoint) || isXL(curve)) } /** 在板内 */ function inBorder(curve: Curve2d) { return !onBorder(curve.StartPoint) && !onBorder(curve.EndPoint) } /** 点是否在边缘 */ function onBorder(p: Point2d) { return equal(p.m_X, reg.z, offDis) || equal(p.m_X, reg.y, offDis) || equal(p.m_Y, reg.s, offDis) || equal(p.m_Y, reg.x, offDis) } /** 斜线 */ function isXL(line: Curve2d) { return !equal(line.StartPoint.m_X, line.EndPoint.m_X) && !equal(line.StartPoint.m_Y, line.EndPoint.m_Y) } /** 线是边缘 */ function isBorderLine(line: Line2d) { return !isXL(line) && onBorder(line.StartPoint) && onBorder(line.EndPoint) } /** 分析空间 */ function createSpace(curves: Curve2d[]): PlaceSpace[] { if (curves.length == 0) return [] // 1.补边,闭合轮廓 const sp = curves[0].StartPoint const ep = curves[curves.length - 1].EndPoint const pushPts: Point2d[] = [] pushPts.push(ep) const sb = getEdge(sp) // 起点的边 const eb = getEdge(ep) // 终点的边 if (sb == -1 || eb == -1) return []// 不在边上 // 在同一边 的缺角 if (sb == eb) { if (equal(sp.m_X, ep.m_X, offDis) && sp.m_X != ep.m_X) // 消除误差 { let x = Math.max(sp.m_X, ep.m_X) if (sp.m_X > block.width / 2) x = Math.min(sp.m_X, ep.m_X) sp.m_X = x ep.m_X = x } if (equal(sp.m_Y, ep.m_Y, offDis) && sp.m_Y != ep.m_Y) // 消除误差 { let y = Math.max(sp.m_Y, ep.m_Y) if (sp.m_Y > block.length / 2) y = Math.min(sp.m_Y, ep.m_Y) sp.m_Y = y ep.m_Y = y } } // 右下角 else if (sb == 0 && eb == 1) { const cp = new Point2d(ep.m_X, sp.m_Y) pushPts.push(cp) } // 右上角 else if (sb == 1 && eb == 2) { const cp = new Point2d(sp.m_X, ep.m_Y) pushPts.push(cp) } // 左上角 else if (sb == 2 && eb == 3) { const cp = new Point2d(ep.m_X, sp.m_Y) pushPts.push(cp) } // 左下角 else if (sb == 3 && eb == 0) { const cp = new Point2d(sp.m_X, ep.m_Y) pushPts.push(cp) } // 起点下边 -> 终点上边 //因为倒角 else if (sb == 0 && eb == 2) { const cp1 = new Point2d(reg.y, ep.m_Y) const cp2 = new Point2d(reg.y, sp.m_Y) pushPts.push(cp1) pushPts.push(cp2) } // 起点右边 -> 终点左边 else if (sb == 1 && eb == 3) { const cp1 = new Point2d(ep.m_X, reg.s) const cp2 = new Point2d(sp.m_X, reg.s) pushPts.push(cp1) pushPts.push(cp2) } // 起点上边 -> 终点下边 else if (sb == 2 && eb == 0) { const cp1 = new Point2d(reg.z, ep.m_Y) const cp2 = new Point2d(reg.z, sp.m_Y) pushPts.push(cp1) pushPts.push(cp2) } // 起点左边 -> 终点右边 else if (sb == 3 && eb == 1) { const cp1 = new Point2d(ep.m_X, reg.x) const cp2 = new Point2d(sp.m_X, reg.x) pushPts.push(cp1) pushPts.push(cp2) } // 起点下边 -> 终点左边 else if (sb == 0 && eb == 3) { const cp1 = new Point2d(reg.z, reg.s) const cp2 = new Point2d(reg.y, reg.s) const cp3 = new Point2d(reg.y, reg.x) pushPts.push(cp1) pushPts.push(cp2) pushPts.push(cp3) } // 起点右边 -> 终点下边 else if (sb == 1 && eb == 0) { const cp1 = new Point2d(reg.z, reg.x) const cp2 = new Point2d(reg.z, reg.s) const cp3 = new Point2d(reg.y, reg.s) pushPts.push(cp1) pushPts.push(cp2) pushPts.push(cp3) } // 起点上 -> 终点右边 else if (sb == 2 && eb == 1) { const cp1 = new Point2d(reg.y, reg.x) const cp2 = new Point2d(reg.z, reg.x) const cp3 = new Point2d(reg.z, reg.s) pushPts.push(cp1) pushPts.push(cp2) pushPts.push(cp3) } // 起点左 -> 终点上边 else if (sb == 3 && eb == 2) { const cp1 = new Point2d(reg.y, reg.s) const cp2 = new Point2d(reg.y, reg.x) const cp3 = new Point2d(reg.z, reg.x) pushPts.push(cp1) pushPts.push(cp2) pushPts.push(cp3) } else // 判断不了 缺口 的起点终点 范围 { return [] } pushPts.push(sp) for (let i = 0; i < pushPts.length - 1; i++) // 闭合缺口 { const newLine = new Line2d(pushPts[i], pushPts[i + 1]) curves.push(newLine) } // 3 目前轮廓顺时针,必须转成 逆时针 curves = SpacePlus.reverseCurves(curves) // 4. 分析空间 analyeSpace const tmpSpaces = SpacePlus.borderToSpace(curves) || [] return tmpSpaces } /** 获得点所在的边 getB */ function getEdge(sp) { if (equal(sp.m_Y, reg.x, offDis)) return 0 if (equal(sp.m_X, reg.y, offDis)) return 1 if (equal(sp.m_Y, reg.s, offDis)) return 2 if (equal(sp.m_X, reg.z, offDis)) return 3 return -1 } /** 设置方向 */ function setDirect(line: Line2d) { let fx = -1 // 向右 0,向上 1,向左 2,向下 3 ,右上 4,左上5,左下6,右下 7 if (line.EndPoint.m_X > line.StartPoint.m_X && equal(line.EndPoint.m_Y, line.StartPoint.m_Y)) { fx = 0 } else if (line.EndPoint.m_X < line.StartPoint.m_X && equal(line.EndPoint.m_Y, line.StartPoint.m_Y)) { fx = 2 } else if (line.EndPoint.m_Y > line.StartPoint.m_Y && equal(line.EndPoint.m_X, line.StartPoint.m_X)) { fx = 1 } else if (line.EndPoint.m_Y < line.StartPoint.m_Y && equal(line.EndPoint.m_X, line.StartPoint.m_X)) { fx = 3 } else if (line.EndPoint.m_X > line.StartPoint.m_X && line.EndPoint.m_Y > line.StartPoint.m_Y) { fx = 4 } else if (line.EndPoint.m_X < line.StartPoint.m_X && line.EndPoint.m_Y > line.StartPoint.m_Y) { fx = 5 } else if (line.EndPoint.m_X < line.StartPoint.m_X && line.EndPoint.m_Y < line.StartPoint.m_Y) { fx = 6 } else if (line.EndPoint.m_X > line.StartPoint.m_X && line.EndPoint.m_Y < line.StartPoint.m_Y) { fx = 7 } line.fx = fx return fx > -1 } } /** 创建 普通造型外扩的 多段线 */ public static createPolyline_model(block: PlaceBlock) { if (!block.blockDetail) { console.warn("PlaceBlock没有blockDetail,无法创建造型轮廓") return { pls_model: [], sizeout: new SizeExpand() } } const pl_block = this.getOrgPolyline(block) const pls_model: Polyline[] = [] for (const model of block.blockDetail.models) { if (model.originModeling == undefined) { continue } let _pts: any[] = [] let _buls: any[] = [] if (Array.isArray(model.originModeling.outline)) { _pts = model.originModeling.outline.map(e => e.pts) _buls = model.originModeling.outline.map(e => e.buls) } else { _pts = model.originModeling.outline.pts _buls = model.originModeling.outline.buls } if (model.isCutting == false) continue if (model.isVKnifeModel()) continue if (model.depth > block.thickness - 0.01) continue if (model.pointList.length < 2) continue if (model.hasContour() == false) continue if (model.originModeling == null) continue if (model.originModeling.outline == null) continue if (!Array.isArray(_pts)) continue if (_pts.length < 1) continue if (model.knifeRadius < 0.001) continue const pl_model = PolylineHelper.createByPts(_pts, _buls, true) const pl_off = pl_model.GetOffsetCurves(model.knifeRadius)[0] if (pl_off == null) continue if (pl_block.IntersectWith(pl_off, 0).length == 0) continue // 造型轮廓偏移一个刀半径 ,没有与板轮廓相交 // 有可能超出板外 const pts: any[] = [] const p0 = model.pointList[0] let isClose = false for (let i = 0; i < model.pointList.length; i++) { const p = model.pointList[i] if (i == 0) { pts.push({ x: p.pointX, y: p.pointY, bul: p.curve }) continue } const pp = pts[pts.length - 1] if (getDis2(pp, p) < 0.1) pts.pop() // 与前一点,接近去掉前一点,避免重合 pts.push({ x: p.pointX, y: p.pointY, bul: p.curve }) if (i == model.pointList.length - 1) break // 完成了 isClose = getDis2(p0, p) < 0.1 if (isClose) // 闭环且后面的点都在环内,那后面的点就不需要考虑了 { const pl = PolylineHelper.create(pts, true) let isAllIn = true for (let j = i + 1; j < model.pointList.length; j++) { const pn = model.pointList[j] isAllIn = pl.PtInCurve(new Vector3(pn.pointX, pn.pointY, 0)) if (isAllIn == false) break } if (isAllIn) break } } try { this.createModelPLS(pl_block, pls_model, pts, model.knifeRadius) } catch { continue } } // 计算外扩偏移 let xz = 0; let xy = block.cutWidth; let yx = 0; let ys = block.cutLength for (const pl of pls_model) { if (pl.BoundingBox.min.x < xz) xz = pl.BoundingBox.min.x if (pl.BoundingBox.min.y < yx) yx = pl.BoundingBox.min.y if (pl.BoundingBox.max.x > xy) xy = pl.BoundingBox.max.x if (pl.BoundingBox.max.y > ys) ys = pl.BoundingBox.max.y } const sizeout_model = new SizeExpand() if (xz < 0) sizeout_model.left = -xz if (xy > block.cutWidth) sizeout_model.right = xy - block.cutWidth if (yx < 0) sizeout_model.bottom = -yx if (ys > block.cutLength) sizeout_model.top = ys - block.cutLength sizeout_model.setSize() return { pls_model, sizeout: sizeout_model } } /** 创建 2v板外下刀的 多段线 */ private static createPolyline_2vModel(block: PlaceBlock) { if (!block.blockDetail) { console.warn("PlaceBlock没有blockDetail,无法创建造型轮廓") return { pls_model: [], sizeout: new SizeExpand() } } const pls_2v: Polyline[] = [] for (const model of block.blockDetail.models) { if (model.isVKnifeModel() == false) continue if (model.isCutting == false) continue // if(model.depth > block.thickness - 0.01) continue; const pl_block = this.getOrgPolyline(block) for (const vline of model.VLines) { // knifeRadius 刀半径, depth深度, points{x,y,z,bul,r} const r = vline.knifeRadius if (r < 0.001) continue const pts = vline.points.map((t) => { return { x: t.x, y: t.y, bul: t.bul } }) try { this.createModelPLS(pl_block, pls_2v, pts, r, true) } catch { continue } } } // 计算外扩偏移 let xz = 0; let xy = block.cutWidth; let yx = 0; let ys = block.cutLength for (const pl of pls_2v) { if (pl.BoundingBox.min.x < xz) xz = pl.BoundingBox.min.x if (pl.BoundingBox.min.y < yx) yx = pl.BoundingBox.min.y if (pl.BoundingBox.max.x > xy) xy = pl.BoundingBox.max.x if (pl.BoundingBox.max.y > ys) ys = pl.BoundingBox.max.y } const sizeout_2v = new SizeExpand() if (xz < 0) sizeout_2v.left = -xz if (xy > block.cutWidth) sizeout_2v.right = xy - block.cutWidth if (yx < 0) sizeout_2v.bottom = -yx if (ys > block.cutLength) sizeout_2v.top = ys - block.cutLength sizeout_2v.setSize() return { pls_2v, sizeout_2v } } /** * 创建超出板外的造型轮廓 * */ private static createModelPLS(pl_block: Polyline, pls_model: Polyline[], points: any[], r: number, is2V = false) { const lines: any = [] // 23.10.9 发现普通造型还是有自交的线段,强制 分段处理 for (let i = 0; i < points.length - 1; i++) { const j = i + 1 const p1 = { x: points[i].x, y: points[i].y, bul: points[i].bul } const p2 = { x: points[j].x, y: points[j].y, bul: 0 } lines.push([p1, p2]) } // 对 每段line 进行 偏移多半径,获取闭合多段线 const pls: Polyline[] = [] for (const pts of lines) { // 1. pts 不闭合,偏移0.5 // 原路回来,组合成闭合线 const l = pts.length - 1 pts[l].bul = 0 // 确保最后一点 是直线点 const isclose = equal(pts[0].x, pts[l].x) && equal(pts[0].y, pts[l].y) if (isclose == false) // { const pl_0 = PolylineHelper.create(pts, false) const pl_1s = pl_0.GetOffsetCurves(0.5) let pl_1 = pl_1s[0] if (pl_1 == null) continue pl_1 = pl_1.Reverse() for (const p of pl_1.LineData) { pts.push({ x: p.pt.x, y: p.pt.y, bul: p.bul }) } } // 2 偏移刀r后的 轮廓 let pl_vline = PolylineHelper.create(pts, true) if (pl_vline.IsClockWise) pl_vline = pl_vline.Reverse() const pl_off = pl_vline.GetOffsetCurves(r)[0] if (pl_off == null) continue // if(pl_off.CloseMark == false) ; pls.push(pl_off) } if (pls.length == 0) return // 对 多段线进行 合并,获得最后 造型轮廓 let pl: Polyline | undefined = pls.shift() if (pl == undefined || pl == null) { console.warn("创建造型轮廓失败,pls数组为空") return } if (pls.length > 0) { pl = this.unionPolylines(pl, pls) } // 3 造型轮廓 与 板轮廓干涉 if (pl_block.IntersectWith(pl, 0).length > 0) { pls_model.push(pl) } // 4 2V 轮廓 可能包含了 板轮廓 if (pl.BoundingBox.min.x <= pl_block.BoundingBox.min.x && pl.BoundingBox.min.y <= pl_block.BoundingBox.min.y && pl.BoundingBox.max.x >= pl_block.BoundingBox.max.x && pl.BoundingBox.max.y >= pl_block.BoundingBox.max.y) { pls_model.push(pl) } } /** 创建 点阵pts ,在 板边缘 干涉到的 区域 */ private static createInterPLS(pl_block: Polyline, pts: any[], r: number, pls_model: Polyline[]) { const pl_vline = PolylineHelper.create(pts) let curves curves = pl_vline.Explode() // 分解成 一段 一段的 const outlines: any = [] // 当前在板外的线段 for (let i = 0; i < curves.length;) // 判断 有没有交集 { const curve = curves[i] const pos = getRelation(pl_block, curve, r) if (pos[0] == -1) { if (outlines.length > 0) createPL_outLines(outlines, pls_model, r) } else if (pos[0] == 0 || pos[0] == 1) // 板外,或交接 { outlines.push(curve) } else // 多个连接点 。,要拆分 多段,处理 { const childs = curve.GetSplitCurves(0.2) curves.splice(i, 1) for (let j = childs.length - 1; j >= 0; j--) { const child = childs[j] curves.splice(i, 0, child) } continue } i++ } // 最后一条线段可能是板外,那就要补 板外线段生成 if (outlines.length > 0) createPL_outLines(outlines, pls_model, r) /** 判断 line 与 polyline 的关系 -1 板内,0 板外 ,> 0 相交点数 */ function getRelation(pl_block, curve, r) { const xjd = pl_block.IntersectWith(curve, 0) if (xjd.length > 0) return [xjd.length, xjd] // 相交点 // line 的 4 个点 const box = curve.BoundingBox const x0 = box.min.x - r const y0 = box.min.y - r const x1 = box.max.x + r const y1 = box.max.y + r const p0 = pl_block.PtInCurve(new Vector3(x0, y0)) const p1 = pl_block.PtInCurve(new Vector3(x1, y0)) const p2 = pl_block.PtInCurve(new Vector3(x1, y1)) const p3 = pl_block.PtInCurve(new Vector3(x0, y1)) if (p0 && p1 && p2 && p3) return [-1, []] // 板内 if (!p0 && !p1 && !p2 && !p3) return [0, []] // 板外 return [0, []] } function createPL(x0, y0, x1, y1) { const pts: any[] = [] pts.push({ x: x0, y: y0 }) pts.push({ x: x1, y: y0 }) pts.push({ x: x1, y: y1 }) pts.push({ x: x0, y: y1 }) const pl_line = PolylineHelper.create(pts, true) return pl_line } function createPL_outLines(outlines, pls_model, r) { let xz = 28000; let xy = -100000; let yx = 2900000; let ys = -100000 for (const curve of outlines) { const box = curve.BoundingBox const x0 = box.min.x - r - 1 const y0 = box.min.y - r - 1 const x1 = box.max.x + r + 1 const y1 = box.max.y + r + 1 if (x0 < xz) xz = x0 if (x1 > xy) xy = x1 if (y0 < yx) yx = y0 if (y1 > ys) ys = y1 } const pl_line = createPL(xz, yx, xy, ys) pls_model.push(pl_line) outlines.splice(0) // 清空,可能下面 还有 板外的线段 } } /** 创建 轮廓 pts : {x,y,bul}[] */ static createBorderByPts(pts: any[]): Curve2d[] { const borders: Curve2d[] = [] for (let i = 0; i < pts.length; i++) { let j = i + 1 if (j == pts.length) j = 0 const pi = pts[i] const pj = pts[j] if (pi.bul == 0) { const line = new Line2d(new Point2d(pi.x, pi.y), new Point2d(pj.x, pj.y)) borders.push(line) } else { const arc = new Arc2d(new Point2d(pi.x, pi.y), new Point2d(pj.x, pj.y), pi.bul) borders.push(arc) } } return borders } /** 翻转 多线段 */ static transformBorder(borders: Curve2d[], placeStyle: PlaceStyle, width: number, length: number, blockNo?: any): Curve2d[] { // console.log('翻转 多线段') const newBorders: Curve2d[] = [] for (let i = 0; i < borders.length; i++) { const border = borders[i] const np1 = getPlacePosition(border.StartPoint.m_X, border.StartPoint.m_Y, width, length, placeStyle) const np2 = getPlacePosition(border.EndPoint.m_X, border.EndPoint.m_Y, width, length, placeStyle) let p1 = new Point2d(np1.x, np1.y) let p2 = new Point2d(np2.x, np2.y) if (placeStyle >= 4) [p1, p2] = [p2, p1] let newBorder if (border instanceof Arc2d) { newBorder = new Arc2d(p1, p2, border.Bul) } else { newBorder = new Line2d(p1, p2) } if (border.tagData != undefined || border.tagData != null) { newBorder.tagData = border.tagData newBorder.tagData2 = border.tagData2 } newBorders.push(newBorder) } if (placeStyle >= 4) newBorders.reverse() return newBorders } /** 翻转 多线段 */ static transformBorderNew(borders: Curve2d[], placeStyle: PlaceStyle, width: number, length: number): Curve2d[] { const newBorders: Curve2d[] = [] for (let i = 0; i < borders.length; i++) { const border = borders[i] const np1 = getPlacePosition(border.StartPoint.m_X, border.StartPoint.m_Y, width, length, placeStyle) const np2 = getPlacePosition(border.EndPoint.m_X, border.EndPoint.m_Y, width, length, placeStyle) let p1 = new Point2d(np1.x, np1.y) let p2 = new Point2d(np2.x, np2.y) if (placeStyle >= 4) [p1, p2] = [p2, p1] let newBorder if (border instanceof Arc2d) { newBorder = new Arc2d(p1, p2, border.Bul) } else { newBorder = new Line2d(p1, p2) } if (border.tagData != undefined || border.tagData != null) { newBorder.tagData = border.tagData newBorder.tagData2 = border.tagData2 } newBorders.push(newBorder) } if (placeStyle >= 4) newBorders.reverse() return newBorders } /** 翻转 多段线 */ static transformPolyline(pl: Polyline, placeStyle: PlaceStyle, width: number, length: number): Polyline { const bx = pl.Position.x const by = pl.Position.y let pts = pl.LineData.map((t) => { return { x: t.pt.x, y: t.pt.y, bul: t.bul } }) pts.forEach((t) => { t.x += bx; t.y += by }) // 翻面,翻转点阵 if (placeStyle > 3) { const newPts: any[] = [] for (let j = pts.length - 1; j >= 0; j--) { let i = j - 1 if (i < 0) i = pts.length - 1 const x = pts[j].x const y = pts[j].y const bul = pts[i].bul newPts.push({ x, y, bul }) } pts = newPts } // 转换坐标 for (let i = 0; i < pts.length; i++) { const p = pts[i] const np = getPlacePosition(p.x, p.y, width, length, placeStyle) p.x = np.x p.y = np.y } const npl = PolylineHelper.create(pts) npl.CloseMark = true return npl } /** 偏移 多段线 */ static offsetCurves(borders: Curve2d[], offvalue: number, isOffsetRounding: boolean): Curve2d[] { if (equal(offvalue, 0)) return borders const pts: any[] = [] for (const cur of borders) { const x = cur.StartPoint.m_X const y = cur.StartPoint.m_Y const bul = (cur instanceof Arc2d) ? cur.Bul : 0 pts.push({ x, y, bul }) } if (borders.length != 0) { pts.push({ x: borders[0].StartPoint.m_X, y: borders[0].StartPoint.m_Y, bul: 0 }) } const pl = PolylineHelper.create(pts) // 偏移 倒角:直角不倒角 2023.10.27 QQ陈雄 const pls = isOffsetRounding ? pl.GetFeedingToolPath(offvalue, 0) : pl.GetOffsetCurves(offvalue) if (pls.length == 0) return borders const npls = pls[0] // 偏移多段线 const ita = ConverToPolylineAndSplitArc(npls, false, true) // 拆分多段线 const offsetCurves: Curve2d[] = [] for (let i = 0; i < ita.pts.length; i++) { let j = i + 1 if (j == ita.pts.length) j = 0 const p1 = ita.pts[i] const p2 = ita.pts[j] const np1 = new Point2d(p1.x, p1.y) const np2 = new Point2d(p2.x, p2.y) if (ita.buls[i] == 0) { const line = new Line2d(np1, np2) if (line.m_Length < 0.01) continue offsetCurves.push(line) } else { const arc = new Arc2d(np1, np2, ita.buls[i]) if (arc.m_Radius < 0.01) continue offsetCurves.push(arc) } } return offsetCurves } /** 轮廓 转成 多断线 */ static borderToPolyline(border: Curve2d[], CloseMark = true): Polyline { return PolylineHelper.createByCurve2d(border, CloseMark) } /** 多段线 转成 轮廓 */ static polylineToBorder(pl: Polyline): Curve2d[] { const pts = pl.LineData.map((t) => { return { x: t.pt.x, y: t.pt.y, bul: t.bul } }) return this.createBorderByPts(pts) } /** 合并 多段线 */ static unionPolylines(pl: Polyline, childs: Polyline[]): Polyline { const strPLS = PolylineHelper.getStrPLs([pl].concat(childs)) if (childs.length == 0) return pl try { const contour1 = Contour.CreateContour(pl) const reg1 = new ShapeManager([new Shape(contour1)]) for (const c of childs) { const contour2 = Contour.CreateContour(c, false) if (contour2 == null) { return pl } else { PolylineHelper.getArcRadius const reg2 = new ShapeManager([new Shape(contour2)]) reg1.UnionBoolOperation(reg2) } } if (reg1.ShapeList.length == 0) return pl let newStr = '' const pls: Array = [] for (const sh of reg1.ShapeList) { pls.push(sh.Outline.Curve) } newStr = PolylineHelper.getStrPLs(pls) const cur = reg1.ShapeList[0].Outline.Curve let newpl: Polyline if (cur instanceof Circle) { newpl = PolylineHelper.cicleToPolyline(cur) } else { newpl = cur } newStr = PolylineHelper.getStrPLs([newpl]) return PolylineHelper.resetPosition(newpl) } catch (err) { console.log(err); throw new Error('有非常规造型或2v刀路在合并空间时发生错误,请导出优化结果cfdat文件,并与软件服务商联系!') } } /** 小板 标签位置 */ static resetLabelPos(b: PlaceBlock) { if (!b.blockDetail) { console.warn("PlaceBlock没有blockDetail,无法计算标签位置") return } if (b.blockDetail.labelPosX != -1) return // 已计算 const pls = this.getOrgPloylines(b, false) const pl = pls.pl const mpls = pls.pls_inner const x = b.cutWidth / 2 const y = b.cutLength / 2 b.blockDetail.labelPosX = x b.blockDetail.labelPosY = y // 矩形 且没有挖穿造型 if (b.isUnRegular == false && mpls.length == 0) return const vp = getValidPos() if (vp) { b.blockDetail.labelPosX = vp.x b.blockDetail.labelPosY = vp.y } // 从中心点出发,左右上下偏移,求点。 function getValidPos() { const off = 40 const offw = x / off const offl = y / off let nx = 0; let ny = 0 for (let i = 0; i < offw; i++) { for (let j = 0; j < offl; j++) { nx = x + i * off ny = y + j * off if (isInPolyline(pl, mpls, nx, ny)) return { x: nx, y: ny } nx = x + i * off ny = y - j * off if (isInPolyline(pl, mpls, nx, ny)) return { x: nx, y: ny } nx = x - i * off ny = y + j * off if (isInPolyline(pl, mpls, nx, ny)) return { x: nx, y: ny } nx = x - i * off ny = y - j * off if (isInPolyline(pl, mpls, nx, ny)) return { x: nx, y: ny } } } return null } /** 判断点 在范围内 */ function isInPolyline(pl: Polyline, mpls: Polyline[], x: number, y: number): boolean { for (const mp of mpls) { if (PolylineHelper.isPointInPolyline(mp, x, y)) return false // 在造型洞里头, } return PolylineHelper.isPointInPolyline(pl, x, y) } } }