feat:处理器初步实现---有接上了新优化,回显需要再看下

This commit is contained in:
2025-07-09 16:36:26 +08:00
parent 92b49c7035
commit 595675a08a
42 changed files with 70546 additions and 1993 deletions

View File

@@ -0,0 +1,152 @@
import { FaceType, PlaceBlock, PlaceBlockDetail, PlaceBorderContour, PlaceMaterial, PlaceStyle, SizeExpand } from "../confClass"
import { BlockDetailHelperBase } from "../handleAbility/blockDetailHelperBase"
import { PolylineHelper } from "../handleAbility/common/LayoutEngine/PolylineHelper"
import { KnifeHelper } from "../handleAbility/knifeHelper"
/** 小板明细 相关的计算 孔 造型 以及轮廓 */
export class BlockDetailHelper extends BlockDetailHelperBase {
/** 预铣(板件外扩)值 */
preMillingSize = 0;
constructor(config?: any) {
super()
if(config){
this.updateConfig(config)
}
}
updateConfig(config) {
if (config) {
let keys = Object.keys(config)
for (const key of keys) {
if (Reflect.has(this, key)) {
this[key] = config[key]
}
}
}
}
/** 小板初始化1各种轮廓|走刀路径|2尺寸扩展后的轮廓与走刀路径 */
initBlock(block: PlaceBlock, pm: PlaceMaterial) {
if (block.blockDetail == null) {
// 异常情况
console.error(`【initBlock()】${block.blockNo}没用板件明细,请检查`);
return
}
if (block.blockDetail.borderContour) return // 已初始化
// const pm = block.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 = false// sysConfig.RegularBlockFilletCurve;
}
else // 异形板
{
// 异形板倒角
bd.isOffsetRounding = true // sysConfig.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()
// console.log('开料轮廓_带预铣, 外扩尺寸', block, bd.preMillingExpandSize, sysConfig.preMillingSize)
if (this.preMillingSize > 0.0001) {
const rt = this.creatOrgBorderWithPrevCut(block, border_org, this.sysConfig.preMillingSize)
bd.borderContour.borderPreMilling = rt.newBorders
bd.preMillingExpandSize = rt.newSizeExpand
// 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 = this.sysConfig.helpCutStyle || 0
let useSameKnifeToHelpCutGap = this.sysConfig.helpCutGap || 0
const isSameKnifeToCut = isUseSameKnifeToHelpCut && useSameKnifeToHelpCutGap > 0
if (isSameKnifeToCut == false || bd.isUseSameKnifeToHelpCut == false) {
// 未启动同刀辅助, 或 该小板 不需要同刀辅助
bd.useSameKnifeToHelpCutGap = 0
bd.sameKnfieHelpExpandSize = new SizeExpand()
}
else {
const gap = useSameKnifeToHelpCutGap
bd.useSameKnifeToHelpCutGap = gap
bd.sameKnfieHelpExpandSize = new SizeExpand({ left: gap, right: gap, under: gap, upper: gap })
}
// 2V刀路,预洗,同刀辅助开料,出板造型刀
this.resetBlock(block, pm)
}
/** 二维刀路初始化 */
init2VModel(blockDetail: PlaceBlockDetail, isCNC = false, _knifeHelper: KnifeHelper) {
for (let model of blockDetail.models) {
if (!model.isVKnifeModel)
continue
let vModels: any = []
model.VLines = vModels
let isFaceB = model.face == FaceType.BACK
if (model.pointList.length < 1)
continue
let ps = model.pointList.map((t) => { return { x: t.pointX, y: t.pointY, bul: t.curve } })
let pl = PolylineHelper.create(ps)
if (model.VLines?.length > 0)
return // 已经分析了
model.VLines = []
for (let os of model.offsetList) {
let knife1 = isCNC ? null : _knifeHelper.getModelKnifeByName(os.name) // getModelKnifeByName(os.name)
let knifeR = os.radius
let knifeId = knife1 ? knife1.knifeId : -1
try {
let vps_1 = PolylineHelper.getVModelPoints_offset(pl, os.offset, os.depth, os.angle)
let vLine = { isFaceB, name: os.name, value: os.offset, knife: knife1, knifeId, knifeRadius: knifeR, depth: os.depth, points: vps_1, offset: os }
vModels.push(vLine) // 偏移路径
model.VLines.push(vLine)
}
catch (err) {
console.log('v型刀走刀路径算法出错。' + err)
}
}
model.VLines = vModels
}
}
}

View File

@@ -0,0 +1,283 @@
import { ConfigBase } from "../../src/models/config";
import { confItem, HoleArrange, Knife, PlaceBlock, PlaceBlockDetail, PlaceMaterial } from "../confClass";
import { Big_bang, ComposingType, LineType, WorkerItemType, xbang } from "../handleAbility/RectOptimizeWorker/bang";
/** 配置列表 */
export const confList: confItem[] = [
{
key: 'isCutProcess',
label: '开料机(雕刻机)加工',
value: true
},
{
key: 'isCutAndCNCProcess',
label: '开料机CNC组合',
value: false
},
{
key: 'isCustomized',
label: '定制加工',
value: false
},
{
key: 'cutBoardBorder',
label: '总修边宽度',
value: 3
},
{
key: 'blockKnifeLineSpacing',
label: '刀路间距',
value: 0
},
{
key: 'isDoubleFaceBlockFirst',
label: '双面开料优先排版',
value: true
},
{
key: 'isRectPlace',
label: '新优化规则排版',
value: false
},
{
// yuLiaoBoardDo2FaceBlock
key: 'isDoubleFaceBlockInRemain',
label: '余料板允许排入双面加工的小板',
value: true
},
]
/**
* 新优化
* 调用流程
* 1、准备工作 加载配置 + 加载刀库 + 设置 回调函数
* 2、调用 startPlaceThreed
* 入参data (数据源 必须包含 小板数据列表和小板明细数据列表)
* pm 优化的材质
* pm.diameter = knife?.diameter
pm.cutKnifeName = knife.knifeName
*/
export class BusinessRectOptimizeMachine extends ConfigBase {
/** 多线程数据集 */
workerList: WorkerItemType[] = []
/** 优化回调 */
placeCallBack: Function = () => { }
constructor() {
super()
}
/** 设置优化回调 */
setPlaceTaskCallBackFun(func: Function) {
this.placeCallBack = func
}
/**开始优化线程 输入的数据没有初始化
* @param data 数据源 包含小板列表和小板明细列表 data内需要包含blockList小板列表 和 blockDetailList小板明细列表
* @param pm 优化的材质 包含该材质的可用开料大板信息 需包含开料刀的信息 pm.diameter pm.cutKnifeName
*/
startPlaceThreed(data, pm: PlaceMaterial) {
let { blockList, blockDetailList } = data
let bList: any = []
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 = !this.getDoFace(bList[e.blockNo], this.processMode())
// 是否翻面后续处理
bList[e.blockNo].isTurnFaceToPlace = true
pm.blockList.push(e)
}
})
pm.cutBorder = this.cutBoardBorder
pm.cutKnifeGap = this.blockKnifeLineSpacing
/** 小板 */
let bans: xbang[] = []
// 实际开料大板的列表
let big_Bang: Big_bang[] = []
let big_BangSL: number[] = []
let border = this.cutBoardBorder
let borderOff = (pm.diameter + pm.cutKnifeGap) / 2
// 余料板 以及实际开料大板
for (const cuttingBoard of pm.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.placeCallBack(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.isDoubleFaceBlockFirst // 双面加工排前面
let gap = this.blockKnifeLineSpacing
// this.bestfit = 0
for (let j = 0; j < 1; j++) {
let w = new Worker(new URL('../handleAbility/RectOptimizeWorker/RectOptimizeWorker.worker', import.meta.url), { type: 'module' })
const data = {
type: 'start',
data: [bans, big_Bang, big_BangSL, xyhcs, isDoubleFaceBlockFirst, gap, this.isRectPlace, this.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.placeCallBack(resObj)
break;
case 'stop':
console.error('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)
}
}
/** 停止优化 */
async stopPlaceTask() {
for (const key in this.workerList) {
await this.terminateWorker({ key })
}
}
/**
* 获取加工面
* @param block
* @param processMode
* @returns
*/
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 this.getHoleFaceMore(block)
} else {
return false
}
}
processMode() {
let processMode = 0;
if (this.isCutProcess) processMode = 0;
if (this.isCutAndCNCProcess) processMode = 1;
if (this.isCustomized) processMode = 2;
return processMode;
}
/**
* 正纹 = 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.isTurnFaceToPlace)
turnF = !turnF
if (!turnF)
return ComposingType.Positive
return ComposingType.Reverse
}
}