366 lines
11 KiB
TypeScript
366 lines
11 KiB
TypeScript
|
||
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<any>((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
|
||
}
|