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
|
|||
|
}
|