feat:提交
This commit is contained in:
400
tests/dev1/dataHandle/optimizeLayout/optimizeLayout.ts
Normal file
400
tests/dev1/dataHandle/optimizeLayout/optimizeLayout.ts
Normal file
@@ -0,0 +1,400 @@
|
||||
import { ProcessorBase, ProcessorContext, ResCodeType, resultInfo } from "../base";
|
||||
import { init2VModel, resetModelContour, resetModelKnife } from "../common/LayoutEngine/BlockDataPlus";
|
||||
import { getDoFace } from "../common/LayoutEngine/BlockDoFace";
|
||||
import { BlockPlus } from "../common/LayoutEngine/BlockPlus";
|
||||
import { PlaceBlock, PlaceBlockDetail, PlaceMaterial } from "../confClass";
|
||||
import { ConfigBase } from "../models/config";
|
||||
import { Big_bang, ComposingType, LineType, WorkerItemType, xbang } from "./RectOptimizeWorker/bang";
|
||||
/** 优化排版 */
|
||||
export class OptimizeLayoutProcessor extends ProcessorBase<any, Function, any> {
|
||||
public get name(): string {
|
||||
return "OptimizeLayoutProcessor_优化排版";
|
||||
}
|
||||
|
||||
public get version(): string {
|
||||
return "1.0.0";
|
||||
}
|
||||
|
||||
private _output?: Function;
|
||||
private _source: any;
|
||||
private _params: ConfigBase = new ConfigBase();
|
||||
/** 多线程数据集 */
|
||||
private workerList: WorkerItemType[] = []
|
||||
constructor() {
|
||||
super();
|
||||
this._params.name = "优化排版配置";
|
||||
this._params.version = "1.0.0";
|
||||
/** 初始化配置 这里 如果不初始化 load 的时候 不会加载上 */
|
||||
/**板最小宽度 */
|
||||
this._params.minBlockWidth = 5;
|
||||
/** 板最小厚度 */
|
||||
this._params.minBlockThickness = 2;
|
||||
/** 排版方式(0按机台尺寸排版 1按板材规格排版) */
|
||||
this._params.placeStyle = 1;
|
||||
/** 机台长度 */
|
||||
this._params.boardLength = 2440;
|
||||
/** 机台宽度 */
|
||||
this._params.boardWidth = 1220;
|
||||
/** 刀路间距 --板件开料轮廓的间距 */
|
||||
this._params.blockKnifeLineSpacing = 0
|
||||
/** 排版跟随大板定位,小板需要反面优化 */
|
||||
this._params.isTurnFaceToPlace = false
|
||||
/** 双面加工板件优先集中排版AllowDoubleHoleFirstSort */
|
||||
this._params.isDoubleFaceBlockFirst = true;
|
||||
/** 是否是矩形优化? */
|
||||
this._params.isRectPlace = true
|
||||
/** 余料板允许排入双面加工的小板yuLiaoBoardDo2FaceBlock */
|
||||
this._params.isDoubleFaceBlockInRemain = true;
|
||||
}
|
||||
public async exec(context: ProcessorContext<any, Function, any>): Promise<void> {
|
||||
// 输入数据
|
||||
this._source = context.input
|
||||
// 输出函数
|
||||
this._output = context.output;
|
||||
// 加载配置
|
||||
// this._params = context.params;
|
||||
this._params?.load(context.params);
|
||||
|
||||
// this._output?.('初始化完成,开始进行优化!')
|
||||
this.optimizeLayout()
|
||||
|
||||
}
|
||||
/** 开始优化主程序 */
|
||||
private async optimizeLayout() {
|
||||
|
||||
|
||||
let { materialList, blockList, blockDetailList, toolsHelper } = this._source
|
||||
|
||||
if (!Array.isArray(toolsHelper.knifeList) || toolsHelper.knifeList.length == 0) {
|
||||
console.error('optimizeLayout: 刀库位置异常,请先确认刀库配置!')
|
||||
return
|
||||
}
|
||||
|
||||
let checkRes = this.checkPlaceBefore(materialList, blockList)
|
||||
|
||||
if (checkRes.length > 0) {
|
||||
let res: resultInfo = {
|
||||
code: ResCodeType.ERROR,
|
||||
message: '优化前检测未通过',
|
||||
data: checkRes
|
||||
};
|
||||
this.callBack(res);
|
||||
} else {
|
||||
let _blockList: PlaceBlock[] = [];
|
||||
let _blockDetailList: PlaceBlockDetail[] = [];
|
||||
for (const b of blockList) {
|
||||
let block = new PlaceBlock(b);
|
||||
_blockList.push(block);
|
||||
}
|
||||
|
||||
for (const bd of blockDetailList) {
|
||||
|
||||
let blockDetail = new PlaceBlockDetail(bd);
|
||||
await resetModelContour(blockDetail);
|
||||
await init2VModel(blockDetail, toolsHelper, false);
|
||||
|
||||
_blockDetailList.push(blockDetail);
|
||||
|
||||
let i = blockList.findIndex(e => e.blockId == blockDetail.blockId);
|
||||
_blockList[i].blockDetail = blockDetail;
|
||||
|
||||
}
|
||||
|
||||
for (const block of _blockList) {
|
||||
let pm = materialList.find(e => e.goodsId == block.goodsId);
|
||||
|
||||
let knife = toolsHelper.getKnifeByParams({ length: pm?.thickness });
|
||||
|
||||
pm.diameter = knife?.diameter;
|
||||
pm.cutKnifeGap = this._params.blockKnifeLineSpacing || 0.01;
|
||||
|
||||
await BlockPlus.initBlock(block, pm, this._params)
|
||||
await BlockPlus.getBorder(block, false, block.placeStyle)
|
||||
// await blockBoardClass.getBorder(block);
|
||||
await resetModelKnife(block, toolsHelper)
|
||||
}
|
||||
this._source.blockList = _blockList
|
||||
materialList.forEach(m => {
|
||||
let pm = new PlaceMaterial(m);
|
||||
this.startPlaceThreed(pm)
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
/**开始优化线程 输入的数据没有初始化 */
|
||||
startPlaceThreed(material: PlaceMaterial) {
|
||||
const { materialList, blockList, blockDetailList, toolsHelper } = this._source
|
||||
const { processMode = 0, cutBoardBorder = 3, blockKnifeLineSpacing = 0 } = this._params
|
||||
let bList: any = []
|
||||
|
||||
|
||||
let pm: PlaceMaterial = new PlaceMaterial(material)
|
||||
|
||||
blockList.map(e => {
|
||||
if (e.goodsId == pm.goodsId) {
|
||||
bList[e.blockNo] = e
|
||||
let detail = blockDetailList.find(x => x.blockId == e.blockId)
|
||||
if (!Reflect.has(bList[e.blockNo], 'blockDetail')) {
|
||||
bList[e.blockNo].blockDetail = new PlaceBlockDetail(detail)
|
||||
}
|
||||
bList[e.blockNo].isTurnFaceToPlace = getDoFace(bList[e.blockNo], processMode)
|
||||
|
||||
pm.blockList.push(e)
|
||||
}
|
||||
})
|
||||
pm.cutBorder = cutBoardBorder
|
||||
pm.cutKnifeGap = blockKnifeLineSpacing
|
||||
let knife = toolsHelper.getKnifeByParams({ length: pm.thickness })
|
||||
if (!knife) {
|
||||
console.log('没有开料刀')
|
||||
return '没有开料刀'
|
||||
}
|
||||
pm.diameter = knife?.diameter
|
||||
pm.cutKnifeName = knife.knifeName
|
||||
/** 小板 */
|
||||
let bans: xbang[] = []
|
||||
|
||||
// 实际开料大板的列表
|
||||
let big_Bang: Big_bang[] = []
|
||||
let big_BangSL: number[] = []
|
||||
|
||||
|
||||
let border = cutBoardBorder
|
||||
let borderOff = (pm.diameter + pm.cutKnifeGap) / 2
|
||||
|
||||
// 余料板 以及实际开料大板
|
||||
for (const cuttingBoard of material.remainBoardList) {
|
||||
big_Bang.push({ w: cuttingBoard.width - border * 2 + borderOff * 2, l: cuttingBoard.length - border * 2 + borderOff * 2, x: border - borderOff, y: border - borderOff })
|
||||
big_BangSL.push(cuttingBoard.count || 999)
|
||||
}
|
||||
// big_Bang = []
|
||||
// big_BangSL = []
|
||||
// 母板 兜底的
|
||||
big_Bang.push({ w: pm.width - border * 2 + borderOff * 2, l: pm.length - border * 2 + borderOff * 2, x: border - borderOff, y: border - borderOff })
|
||||
// 生成小板
|
||||
for (let key in bList) {
|
||||
let b = bList[key]
|
||||
|
||||
let bid = b.blockNo
|
||||
|
||||
let width = b.placeFullWidth()
|
||||
let length = b.placeFullLength()
|
||||
let line = this.toLine(b.texture)
|
||||
|
||||
bans.push({
|
||||
l: length,
|
||||
w: width,
|
||||
line,
|
||||
face: this.toface(b),
|
||||
id: bid,
|
||||
bno: b.blockNo,
|
||||
holeFaceCount: 3,
|
||||
isRect: !b.isUnRegular,
|
||||
hasHole: false,
|
||||
isdtwosided: true,
|
||||
})
|
||||
}
|
||||
|
||||
let bestCount = 0
|
||||
if (bans.length == 0) // 没有板了
|
||||
{
|
||||
let best = []
|
||||
let yl: Big_bang[] = []
|
||||
let fit = 0
|
||||
let resObj = {
|
||||
data: { bList, best, yl, fit, bans, width: pm.width, length: pm.length, bestCount: bestCount++, pm },
|
||||
info: {
|
||||
times: -1,
|
||||
type: 'noBan'
|
||||
}
|
||||
}
|
||||
this.callBack(resObj)
|
||||
return
|
||||
|
||||
}
|
||||
let xyhcs = 50
|
||||
if (bans.length > 1000) { xyhcs = 40 }
|
||||
else if (bans.length > 1500) { xyhcs = 30 }
|
||||
else if (bans.length > 2000) { xyhcs = 25 }
|
||||
else if (bans.length > 4000) { xyhcs = 20 }
|
||||
else if (bans.length > 6000) { xyhcs = 15 }
|
||||
else if (bans.length > 10000) { xyhcs = 10 }
|
||||
else if (bans.length > 15000) { xyhcs = 5 }
|
||||
else if (bans.length > 20000) { xyhcs = 1 }
|
||||
let isDoubleFaceBlockFirst = this._params.isDoubleFaceBlockFirst // 双面加工排前面
|
||||
let gap = this._params.blockKnifeLineSpacing
|
||||
// this.bestfit = 0
|
||||
|
||||
for (let j = 0; j < 1; j++) {
|
||||
|
||||
let w = new Worker(new URL('./RectOptimizeWorker/RectOptimizeWorkerWorker.ts', import.meta.url), { type: 'module' })
|
||||
// this.optimizeEngines.push(w)
|
||||
const data = {
|
||||
type: 'start',
|
||||
data: [bans, big_Bang, big_BangSL, xyhcs, isDoubleFaceBlockFirst, gap, this._params.isRectPlace, this._params.isDoubleFaceBlockInRemain],
|
||||
}
|
||||
let item: WorkerItemType = {
|
||||
w: w,
|
||||
goodsId: pm.goodsId,
|
||||
pm,
|
||||
status: 'start'
|
||||
}
|
||||
if (this.workerList.findIndex(e => e.goodsId == item.goodsId) == -1) {
|
||||
this.workerList.push(item)
|
||||
}
|
||||
|
||||
|
||||
let workItem = this.workerList.find(e => e.goodsId == pm.goodsId)
|
||||
if (workItem && workItem != undefined) {
|
||||
workItem.w?.postMessage(data)
|
||||
workItem.w.onmessage = async (d) => {
|
||||
let [best, yl, fit, info] = d.data as [any[], Big_bang[], number, any]
|
||||
|
||||
switch (info.type) {
|
||||
case 'loop':
|
||||
let resObj = {
|
||||
data: { bList, best, yl, fit, bans, width: pm.width, length: pm.length, bestCount: bestCount++, pm },
|
||||
info
|
||||
}
|
||||
this.callBack(resObj)
|
||||
break;
|
||||
case 'stop':
|
||||
console.log('stop =》dataHandleBase', info, this.workerList)
|
||||
this.terminateWorker({ goodsId: pm.goodsId })
|
||||
break;
|
||||
case 'isStop':
|
||||
// console.error('isStop', info)
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
console.log('新算法线程启动', pm.goodsId, this.workerList)
|
||||
}
|
||||
}
|
||||
|
||||
private callBack(data: any) {
|
||||
this._output?.(data);
|
||||
}
|
||||
/** 关闭线程 */
|
||||
async terminateWorker(params) {
|
||||
const { key, goodsId } = params
|
||||
let data = {
|
||||
type: 'stop',
|
||||
msg: 'byKey'
|
||||
}
|
||||
if (key) {
|
||||
const worker = this.workerList[key]
|
||||
|
||||
await worker.w?.postMessage(data)
|
||||
worker.w?.terminate()
|
||||
this.workerList[key].status = 'stop'
|
||||
}
|
||||
|
||||
if (goodsId) {
|
||||
let i = this.workerList.findIndex(e => e.goodsId == goodsId)
|
||||
if (i != -1) {
|
||||
data.msg = 'byGoodsId'
|
||||
const worker = this.workerList[i]
|
||||
|
||||
await worker.w?.postMessage(data)
|
||||
worker.w?.terminate()
|
||||
this.workerList[i].status = 'stop'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async terminateWorkerAll() {
|
||||
let data = {
|
||||
type: 'stop',
|
||||
msg: 'allStop'
|
||||
}
|
||||
|
||||
for (const i in this.workerList) {
|
||||
let worker = this.workerList[i]
|
||||
await worker.w?.postMessage(data)
|
||||
worker.w?.terminate()
|
||||
this.workerList[i].status = 'stop'
|
||||
}
|
||||
}
|
||||
|
||||
/** 优化前检测 */
|
||||
checkPlaceBefore(materialList, blockList) {
|
||||
const arr = this.checkMetrial(materialList)
|
||||
const arr1 = this.checkBlocks(materialList, blockList)
|
||||
let errMsg = ''
|
||||
if (arr.length > 0 || arr1.length > 0) {
|
||||
|
||||
errMsg = errMsg + (arr.length > 0 ? '该订单内大板有异常' : '')
|
||||
errMsg = errMsg + (arr1.length > 0 ? '该订单内小板有异常' : '')
|
||||
|
||||
}
|
||||
|
||||
return errMsg
|
||||
}
|
||||
/** 检查是否 板材尺寸大于机台尺寸 */
|
||||
checkMetrial(materialList): any[] {
|
||||
|
||||
let errPMs: any = []
|
||||
|
||||
if (this._params.placeStyle !== 1) {
|
||||
for (let pm of materialList) {
|
||||
if (pm.orgWidth > this._params.boardWidth || pm.orgLength > this._params.boardLength) {
|
||||
|
||||
errPMs.push(pm)
|
||||
}
|
||||
}
|
||||
}
|
||||
return errPMs
|
||||
}
|
||||
/**
|
||||
* 正纹 = 0, 可翻转 = 1, 反纹 = 2;
|
||||
* 正文 Positive = 0, 反纹 Reverse = 1, 可翻转 CanReversal = 2,
|
||||
*/
|
||||
toLine(texture): LineType {
|
||||
if (texture == 0)
|
||||
return LineType.Positive
|
||||
if (texture == 1)
|
||||
return LineType.CanReversal
|
||||
return LineType.Reverse
|
||||
}
|
||||
/** 小板加工面:Positive=0正面 Reverse=1反面 Arbitrary=2任意 */
|
||||
toface(block: PlaceBlock): ComposingType {
|
||||
|
||||
let turnF = block.isTurnFaceToPlace
|
||||
if (this._params.isTurnFaceToPlace)
|
||||
turnF = !turnF
|
||||
if (!turnF)
|
||||
return ComposingType.Positive
|
||||
return ComposingType.Reverse
|
||||
}
|
||||
/** 检查异常板 */
|
||||
checkBlocks(materialList, blockList): any[] {
|
||||
|
||||
let allBlocks: any[] = []
|
||||
//**20250327 li: 现有的需求情况下 这里去验证异常板 不合理 大板有 没有尺寸的情况 二优化尺寸 根据 优化的弹窗去选择尺寸 做优化 */
|
||||
/** 有个能参与优化小板的最小尺寸限制 在这里做 */
|
||||
for (let pm of materialList) {
|
||||
let bList = blockList.filter(e => e.goodsId == pm.goodsId)
|
||||
for (const pb of bList) {
|
||||
if (pb.width < this._params.minBlockWidth) {
|
||||
allBlocks.push(pb)
|
||||
}
|
||||
if (pb.thickness < this._params.minBlockThickness) {
|
||||
allBlocks.push(pb)
|
||||
}
|
||||
}
|
||||
}
|
||||
return allBlocks
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
Reference in New Issue
Block a user