import { BlockHelper } from './BlockHelper.js' import { BlockSizePlus } from './BlockSizePlus.js' import { resetPlaceBoard } from './PlaceBase.js' import { NcCustomized } from '@/imes/biz/NcCustomized.js' import { FaceType, HoleType, HoleArrange, PlaceBlock, PlaceMaterial, PlaceBoard } from '../../confClass.js' /** 计算大板中所有的小板的正反面孔造型数量,让正面加工时间接近 比例 30% */ export async function TurnOverWithDoneRate(pm: PlaceMaterial, cncData: boolean, doneRate: number, sp_h: number, sp_m: number) { let i = 0 console.time(`${pm.fullName} full use time`) for (let pb of pm.boardList) { // if (pb.IsOddmengt) continue; i++ // console.log(`${pm.FullName} bid=${i} 开始计算`); await TurnOverWithDoneRate_pb(pm, pb, cncData, doneRate, sp_h, sp_m, i) } console.timeEnd(`${pm.fullName} full use time`) } /** 计算大板中所有的小板的正反面孔造型数量,让正面加工时间接近 比例 30% */ export async function TurnOverWithDoneRate_pb(pm: PlaceMaterial, pb: PlaceBoard, useCncData: boolean, doneRate: number, sp_h: number, sp2: number, i) { // 孔 0.5秒/个 // 造型, 16秒/米 , 0.016秒/mm let sp_m = sp2 * 0.001 let rate = doneRate * 0.01 // 一. 先求出大板所有小板,当前正反面加工时间,是否可翻转 let tm: any = [] // let t1_z = 0 // 不可翻 正面加工时间 合计 let t1_f = 0 // 不可翻 反面加工时间 合计 let t2_z = 0 // 可翻 正面加工时间 合计 let t2_f = 0 // 可翻 反面加工时间 合计 let t_full = 0 // 所有加工时间 合计 let t_throngh = 0// 挖穿的造型的时间, for (let block of pb.blockList) { let tc = 0 // 挖穿; let tz = 0 // 当前加工面 时间 let tf = 0 // 反面 时间 let holes = block.holeListFaceA let models = block.modelListFaceA if (useCncData) // 使用cnc 数据 { holes = block.isTurnOver ? block.holeListOrgFaceB.filter(t => t.isCutting == false) : block.holeListOrgFaceA.filter(t => t.isCutting == false) models = block.isTurnOver ? block.modelListOrgFaceB.filter(t => t.isCutting == false) : block.modelListOrgFaceA.filter(t => t.isCutting == false) } tz += holes.length * sp_h // 正面孔时间 for (let model of models) { let len = 0 for (let i = 0; i < model.pointList.length - 1; i++) { let p0 = model.pointList[i] let p1 = model.pointList[i + 1] if (p0 == null || p1 == null) continue len += Math.sqrt((p0.pointX - p1.pointX) ** 2 + (p0.pointY - p1.pointY) ** 2) } if (model.depth >= block.thickness - 0.001) { tc += len * sp_m } else { tz += len * sp_m } } let holes2 = block.holeListFaceB let models2 = block.modelListFaceB if (useCncData) // 使用cnc 数据 { holes2 = block.isTurnOver ? block.holeListOrgFaceA.filter(t => t.isCutting == false) : block.holeListOrgFaceB.filter(t => t.isCutting == false) models2 = block.isTurnOver ? block.modelListOrgFaceB.filter(t => t.isCutting == false) : block.modelListOrgFaceB.filter(t => t.isCutting == false) } tf += holes2.length * sp_h for (let model of models2) { let len = 0 for (let i = 0; i < model.pointList.length - 1; i++) { let p0 = model.pointList[i] let p1 = model.pointList[i + 1] if (p0 == null || p1 == null) continue len += Math.sqrt((p0.pointX - p1.pointX) ** 2 + (p0.pointY - p1.pointY) ** 2) } tf += len * sp_m } if (tz + tc == 0 && tf == 0) continue // 没有加工 let canTurn = true if (block.isUnRegular) canTurn = false // 异形不能翻 if (canTurn && block.placeHole != 2) canTurn = false // 非可翻转的 if (canTurn && hasChildBlock(block, pb.blockList)) canTurn = false// 里面有小板,不能翻 t_throngh += tc t_full += (tc + tz + tf) if (canTurn == false) // 不能翻 { t1_z += tz t1_f += tf } else // 可以翻 , { if (Math.abs(tz - tf) > sp_h) // 翻面效果很差, 时间小于一个孔 ,翻不翻无所谓, { tm.push({ bno: block.blockNo, z: tz, f: tf, dis: tz - tf, child: [] }) } t2_z += tz t2_f += tf } } // 二. 计算 不可翻的小板 正面加工 与理论值 相差多少 let t2_L = t_full * rate - t1_z - t_throngh // 剩下加工正面的时间 理论值 ( 理论值- 当前正面加工时间,就是剩下可翻的板 正面加工时间 ) let tz: any = t1_z + t_throngh + t2_z // 当前正面时间 let t2_dis = t2_z - t2_L // 理论值与 当前剩下正面加工时间的差值 ,应该要节省的时间总 // 正面加工时间 比例 接近预定于的比例 。 则不再计算 if (Math.abs(100 * t2_dis / t_full) < 3) return { tz, fz: t_full - tz, full: t_full } // 三.接下来的问题就是在 tm 中 找出 翻面加工省时 合计 最接近 t2_dis 的集合出来. let best_list: any = [] // 最优解 需要翻面的 let best_v = t2_dis // 差值最大 默认当前 // 四.将tm 转换成 最多16个可翻面 的数组 tm.sort((a, b) => a.dis - b.dis) // 按小到大排序 // 精简 tm //将tm中 翻面效果 相反的 且大的 剔除掉 if (tm.length > 16) { if (t2_dis > 0) { for (let i = tm.length - 1; i >= 0; i--) { if (tm[i].dis < -t2_dis) { tm.splice(i, 1) } } } else { for (let i = tm.length - 1; i >= 0; i--) { if (tm[i].dis > -t2_dis) { tm.splice(i, 1) } } } } if (tm.length == 0) return { tz, fz: t_full - tz, full: t_full } let blocks: any = [] for (let b of pb.blockList) { blocks[b.blockNo] = b } // 可翻转小板集合,精简 tm = smallerBlocks(tm) let rt = await getBestTurnBlocks(pm, i, tm, best_v, t_full) best_list = rt.result best_v = rt.v // 四. 将最优解中的小板 翻面 for (let m of best_list) { tz -= m.dis let bs: any = [] let block: any = blocks[m.bno] bs.push(block) for (let no of m.child) { bs.push(blocks[no]) } for (let block of bs) { let orgStyle = block.placeStyle let newStyle = BlockHelper.getTurnedPlaceStyle(orgStyle, 0) let orgPlaceX = block.placeX - block.placeOffX let orgPlaceY = block.placeY - block.placeOffY let offset = BlockSizePlus.getOffDis(block, newStyle) let newPlaceX = orgPlaceX + offset.x let newPlaceY = orgPlaceY + offset.y block.placeX = newPlaceX block.placeY = newPlaceY block.placeOffX = offset.x block.placeOffY = offset.y // 修改小板的放置方式 BlockHelper.resetPlaceStyle(block, newStyle) } } // 重设pb if (best_list.length > 0) resetPlaceBoard(pm, pb) return { tz, fz: t_full - tz, full: t_full } } /** 获取加工面:processMode: 0开料机加工 1开料机CNC组合加工 2定制加工 */ export function getDoFace(block: PlaceBlock, processMode: number = 0): boolean { // 模式0: 开料机处理排钻, 造型, 采用大孔面作为正面的模式. 正面多加工, cnc多加工 if (processMode == 0) { // 先考虑 设计开料面 if (block.placeHole == HoleArrange.FRONT) return true if (block.placeHole == HoleArrange.BACK) return false // 造型单面 作为开料面 if (block.modelCountFront() > 0 && block.modelCountBack() == 0) return true if (block.modelCountFront() == 0 && block.modelCountBack() > 0) return false // 优先考虑 大孔面 多孔面 return getHoleFaceMore(block) } // 造型单面 作为开料面 if (block.modelCountFront() > 0 && block.modelCountBack() == 0) return true if (block.modelCountFront() == 0 && block.modelCountBack() > 0) return false return true } /** 大孔/孔多作为正面 */ function getHoleFaceMore(block: PlaceBlock): boolean { if (!block.blockDetail) { console.log('getHoleFaceMore: blockDetail is undefind', block) return true } // 优先考虑 大孔面 let bigHole = block.blockDetail.holes.find(t => t.holeType == HoleType.BIG_HOLE) if (bigHole) return bigHole.face == FaceType.FRONT // 多孔面 if (block.blockDetail.holeListFaceA.length > block.blockDetail.holeListFaceB.length) return true if (block.blockDetail.holeListFaceA.length < block.blockDetail.holeListFaceB.length) return false return true } // 大孔/孔多 作为正面 function getHoleFace_more(block: PlaceBlock): boolean { // 优先考虑 大孔面 let bigHole = block.holes().find(t => t.holeType == HoleType.BIG_HOLE) if (bigHole) return bigHole.face == FaceType.FRONT // 多孔面 if (block.holeCountFront > block.holeCountBack) return true if (block.holeCountFront < block.holeCountBack) return false return true } // 非大孔/孔少 作为正面 function getHoleFace_less(block: PlaceBlock): boolean { // 优先考虑 大孔面 let bigHole = block.holes().find(t => t.holeType == HoleType.BIG_HOLE) if (bigHole) return bigHole.face != FaceType.FRONT // 少孔面 if (block.holeCountFront > block.holeCountBack) return false if (block.holeCountFront < block.holeCountBack) return true return true } // 可翻转小板集合,精简 function smallerBlocks(tm: any[]): any[] { if (tm.length <= 30) return tm let time = 1 if (tm.length > 40) time = 2 if (tm.length > 60) time = 3 if (tm.length > 80) time = 4 if (tm.length > 100) time = 5 if (tm.length > 120) time = 10 let newtm: any = [] let newLength = Math.ceil(tm.length / time) for (let t = 0; t < newLength; t++) { let block0 = tm[t * time] block0.child = [] // bno: block.BlockNo, z: t1, f: t2, dis: t1 - t2 for (let i = 1; i < time; i++) { let j = t * time + i if (j >= tm.length) break let blockNext = tm[j] block0.child.push(blockNext.bno) block0.z += blockNext.z block0.f += blockNext.f block0.dis += blockNext.dis } newtm.push(block0) } return newtm } async function getBestTurnBlocks(pm, pid, tm: any[], best_v, t_full) { let result = [] let result_v = best_v let disRate = 111111 return new Promise((resolve, reject) => { let num1 = 1 let num2 = 2 ** tm.length - 1 let isOK = false // const worker = new Worker(new URL('./FaceDoTimeWorker', import.meta.url)) // worker.onmessage = (res) => // { // let tmp = res.data.tmp // let v = res.data.v // let rate = res.data.rate // result = tmp // result_v = v // disRate = rate // if (res.data.ok == 1) // { // worker.terminate() // 关闭 // resolve({ result, v: result_v }) // isOK = true // } // } // worker.postMessage({ num1, num2, blocks: tm, disTime: best_v, fullTime: t_full }) // Sleep(3000).then(() => // { // if (isOK) // return // resolve({ result, v: result_v }) // // console.log(`${pm.FullName} bid=${pid} ${tm.length} 超时3秒`); // }) }) } /** 判断block 里头有没有小板 */ function hasChildBlock(block: PlaceBlock, blocks: PlaceBlock[]): boolean { for (let b of blocks) { if (b.blockNo == block.blockNo) continue if (b.placeX > block.placeX && b.placeX + b.placeWidth < block.placeX + block.placeWidth && b.placeY > block.placeY && b.placeY + b.placeLength < block.placeY + block.placeLength) return true } return false }