3 Commits
main ... dev_li

Author SHA1 Message Date
b7399fd6e7 feat: 提交 2025-07-22 18:38:25 +08:00
xief
87e2804d1f 切换vitest-browser 2025-07-15 10:56:24 +08:00
cf9913469f feat:提交 2025-07-14 16:04:08 +08:00
41 changed files with 38973 additions and 2951 deletions

View File

@@ -1,3 +1,2 @@
{
"recommendations": ["Orta.vscode-jest"]
}

67
.vscode/launch.json vendored
View File

@@ -1,36 +1,33 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Jest All",
"program": "${workspaceFolder}/node_modules/.bin/jest",
"args": ["--runInBand"],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"disableOptimisticBPs": true,
"windows": {
"program": "${workspaceFolder}/node_modules/jest/bin/jest"
}
},
{
"type": "node",
"request": "launch",
"name": "Jest Current File",
"program": "${workspaceFolder}/node_modules/.bin/jest",
"args": [
"--runTestsByPath",
"${relativeFile}",
"--config",
"jest.config.js"
],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"disableOptimisticBPs": true,
"windows": {
"program": "${workspaceFolder}/node_modules/jest/bin/jest"
}
}
]
}
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Run Vitest Browser",
"program": "${workspaceRoot}/node_modules/vitest/vitest.mjs",
"console": "integratedTerminal",
"args": [
"--inspect-brk",
"--browser",
"--no-file-parallelism"
]
},
{
"type": "chrome",
"request": "attach",
"name": "Attach to Vitest Browser",
"port": 9229
}
],
"compounds": [
{
"name": "Debug Vitest Browser",
"configurations": [
"Attach to Vitest Browser",
"Run Vitest Browser"
],
"stopAll": true
}
]
}

View File

@@ -1,3 +1,2 @@
{
"jest.useJest30": true
}

View File

@@ -1,8 +0,0 @@
module.exports = {
transform: {
'^.+\\.(t|j)sx?$': '@swc/jest',
},
preset: 'ts-jest',
testEnvironment: 'node',
extensionsToTreatAsEsm: ['.ts', '.tsx']
};

View File

@@ -1,5 +1,6 @@
{
"name": "cut-abstractions",
"type": "module",
"version": "0.1.5",
"description": "",
"files": [
@@ -15,28 +16,24 @@
"build": "tsc",
"release": "pnpm pack --pack-destination ./dist-packs",
"clean": "rimraf ./dist",
"test": "jest"
"test": "vitest"
},
"keywords": [],
"author": "",
"license": "ISC",
"packageManager": "pnpm@9.1.1+sha1.09ada6cd05003e0ced25fb716f9fda4063ec2e3b",
"devDependencies": {
"@jest/globals": "^30.0.2",
"@swc/core": "^1.12.4",
"@swc/jest": "^0.2.38",
"@types/jest": "^30.0.0",
"@testing-library/dom": "^10.4.0",
"@vitest/browser": "^3.2.4",
"cadapi": "http://gitea.cf/MES-FE/webcad-api/archive/0.0.60.tar.gz",
"jest": "^30.0.2",
"jest-worker": "^30.0.2",
"js-angusj-clipper": "^1.0.4",
"playwright": "^1.54.1",
"rimraf": "^6.0.1",
"ts-jest": "^29.4.0",
"typescript": "^5.8.3"
"typescript": "^5.8.3",
"vitest": "^3.2.4"
},
"dependencies": {
"jest-worker": "^30.0.2",
"three": "^0.178.0",
"webworker": "^0.8.4"
"@types/node": "^22.16.3",
"three": "^0.178.0"
}
}

3899
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

45
samples/WorkerHelper.ts Normal file
View File

@@ -0,0 +1,45 @@
import path from 'path';
import { Worker as NodeWorker } from 'worker_threads';
export class UniversalWorker {
private worker: NodeWorker | Worker;
constructor(workerPath: string | URL) {
if (typeof window !== 'undefined' && 'Worker' in window) {
// 浏览器环境
this.worker = new Worker(workerPath);
} else {
// Node.js 环境
// const resolvedPath = require.resolve(workerPath);
this.worker = new NodeWorker(workerPath, { eval: false });
}
}
postMessage(message: any): void {
this.worker.postMessage(message);
}
onMessage(callback: (data: any) => void): void {
if ('onmessage' in this.worker) {
this.worker.onmessage = (event) => callback(event.data);
} else {
this.worker.on('message', callback);
}
}
onError(callback: (err: Error) => void): void {
if ('onerror' in this.worker) {
this.worker.onerror = (event) => callback(new Error(event.message));
} else {
this.worker.on('error', callback);
}
}
terminate(): void {
this.worker.terminate();
}
getWorker(){
return this.worker
}
}

View File

@@ -1,6 +1,6 @@
import { FaceType, PlaceBlock, PlaceBlockDetail, PlaceBorderContour, PlaceMaterial, PlaceStyle, SizeExpand } from "../confClass"
import { BlockDetailHelperBase } from "../handleAbility/blockDetailHelperBase"
import { PolylineHelper } from "../handleAbility/common/LayoutEngine/PolylineHelper"
// import { PolylineHelper } from "../handleAbility/common/LayoutEngine/PolylineHelper"
import { KnifeHelper } from "../handleAbility/knifeHelper"

View File

@@ -237,27 +237,7 @@ export enum KnifeType {
BLADE = 5
}
/** 刀功能:
** 1-CUT开料/切割 2-PULLING_GROOVE拉槽 3-MILLING_MODEL铣型 4-MILLING_HOLE铣孔
** 5-DRILL_HOLE钻孔 6-RAMINO拉米诺 7-EASY_FASTEN乐扣 8-T_TYPE T型 */
export enum AbilityType {
/** 1开料/切割 */
CUT = 1,
/** 2拉槽 */
PULLING_GROOVE = 2,
/** 3铣型 */
MILLING_MODEL = 3,
/** 4铣孔 */
MILLING_HOLE = 4,
/** 5钻孔 */
DRILL_HOLE = 5,
/** 6拉米诺 */
RAMINO = 6,
/** 7乐扣 */
EASY_FASTEN = 7,
/** 8T型 */
T_TYPE = 8
}
/** 枚举 坐标轴类型 */
export enum AxisType {
@@ -511,13 +491,15 @@ export class PlaceBlock {
}
/** 左侧孔数 HoleCount_Left */
holeCountLeft() { return this.blockDetail && this.blockDetail.holeCountLeft }
holeCountLeft() { return this?.blockDetail?.holeCountLeft || 0 }
/** 右侧孔数 HoleCount_Right */
holeCountRight() { return this.blockDetail && this.blockDetail.holeCountRight }
holeCountRight() {
return this?.blockDetail?.holeCountRight || 0
}
/** 侧孔数 HoleCount_Upper */
holeCountTop() { return this.blockDetail && this.blockDetail.holeCountTop }
holeCountTop() { return this?.blockDetail?.holeCountTop || 0 }
/** 侧孔数 HoleCount_Under */
holeCountBottom() { return this.blockDetail && this.blockDetail.holeCountBottom }
holeCountBottom() { return this?.blockDetail?.holeCountBottom || 0 }
/** 正面造型数 */
modelCountFront(): number {
return this.blockDetail && this.blockDetail.modelCountFront || 0
@@ -1478,6 +1460,7 @@ export class BlockModel {
}
} catch (error) {
console.log('handle hasContour error',error)
val = false
}
return val // this.originModeling?.outline.map(e=>e?.pts).length >0 //this.originModeling?.outline?.pts?.length > 0

View File

@@ -1,6 +1,14 @@
import { ProcessorModule, StepControllerProcessor } from "../../src/device";
import { RectOptimizeMachineModule } from "../moduleManager/module1";
import { ProcessorModule, StepControllerProcessor, Processor } from "../../src/device";
import { RectOptimizeMachineModule } from "../moduleManager/module_RectOptimizeMachine";
import { ToolsModule } from "../moduleManager/module_tools";
import { CheckMaterial } from "../moduleManager/module_checkMaterial";
import { CheckBlocks } from "../moduleManager/module_checkBlocks";
import { ResetModelContour } from "../moduleManager/module_resetModelContour";
import { AutoCalcCutOrder } from "../moduleManager/module_autoCalcCutOrder";
import { HandleMaterialPlaceResult } from "../moduleManager/module_handleMaterialPlaceResult";
import { handlePlaceResultToPlaceMaterial } from "../moduleManager/module_handlePlaceResultToPlaceMaterial";
// import { Init2VModel } from "../moduleManager/module_init2VModel";
/**
* demo 开料机处理器
*
@@ -10,66 +18,94 @@ export class demoHandleGroupCutting {
processorName = "cutting"
processor: StepControllerProcessor<any, any>
constructor() {
const callbackStyleModule: ProcessorModule<any, any> = {
// 主线程
const demoCallbackModule: ProcessorModule<any, any> = {
moduleName: "callbackStyle",
process(input, next, context) {
console.log("做优化");
const _input = input
const _next = next
const _next = next
const _context = context
// 可以在这里调用异步操作
Reflect.set(context, 'CallBack', callBack1)
// 决定是否调用 next
this.onMessage('测试传消息给处理器');
function callBack1(v) {
console.log('接收到其它模块回传的数据', v);
console.log('接收到其它模块回传的数据');
}
// 调用 next 继续流程
return next(input);
}
};
const demoModule: ProcessorModule<string, string> = {
moduleName: "demoModule",
process(input, next, context) {
// 写入上下文
context.processedAt = new Date().toLocaleString();
context.originalLength = input.length;
// 设置下一步需要的上下文
context.previousStep = "demoModule";
if (context.CallBack) {
context.CallBack("demoModule end and callback")
}
return next(input);
}
};
this.processor = new StepControllerProcessor<any, any>();
this.processor.setOnMessageFunc(this.getMessageByModules)
this.processor.use([
{
moduleName: "traditional",
handle(input, next) {
// 第一个流程
console.log(`第一个模块功能:有${input?.blockList.length}片小板,可以做些计算`)
return next ? next(input) : input;
}
},
callbackStyleModule,
demoModule,
RectOptimizeMachineModule,
{
moduleName: "final",
process(input, next) {
// 不调用 next终止流程
console.log('结束了')
return next(input);
}
}
// demoCallbackModule,
ToolsModule, // 刀库
// CheckMaterial,
// CheckBlocks,
// ResetModelContour,
// Init2VModel,
RectOptimizeMachineModule, // 优化
// {
// moduleName: "final",
// process(input, next,context) {
// // 不调用 next终止流程
// console.log('结束了')
// return next(input);
// }
// }
])
}
}
// 获取到模块的消息
async getMessageByModules(data) {
console.log('getMessageByModules', data);
this.processor = new StepControllerProcessor<any, any>();
switch (data.moduleName) {
// 处理优化模块的消息
case 'RectOptimizeMachine':
// 处理优化数据
this.processor.use([HandleMaterialPlaceResult,
handlePlaceResultToPlaceMaterial,
AutoCalcCutOrder])
this.processor.setOnMessageFunc(this.getMessageByModules)
let bList = []
data.pm.blockList.forEach(b => {
bList[b.blockNo] = b
});
let params = {
bList: bList,
best:data.result[0],
yl:data.result[1],
pm:data.pm,
width:data.pm.width,
length:data.pm.length
}
let context = {
MaterialPlaceSource:params
}
let res = await this.processor.process(data.input,context)
console.log(res);
// this.processor.use(handlePlaceResultToPlaceMaterial)
// let params1 = res
// let res1 = await this.processor.process(res)
break;
default:
break;
}
}
}

View File

@@ -1,5 +1,5 @@
import { ConfigBase } from "../src/base";
import { ConfigBase } from "../src";
import { ParserBase } from "../src/parsers";
import { _knifeType, CodeParams } from "./confClass";
import { knifeData, knifeData1, knifeData2 } from "./demoKnives";

View File

@@ -1,66 +1,41 @@
import type { Big_bang, xbang } from './bang'
import { RectOptimizeMachine } from './RectOptimizeMachine'
import {Worker} from "worker_threads"
// import {Worker} from "worker_threads"
import { Worker as NodeWorker } from 'worker_threads';
const ctx: NodeWorker | Worker = self as any
if (typeof window !== 'undefined' && 'Worker' in window) {
ctx.addEventListener('message', async (event) => {
let m = new RectOptimizeMachine()
m.CallBack = async (best, fit, arg, info) => {
const ctx: Worker = self as any
ctx.addListener('message', async (event) => {
let m = new RectOptimizeMachine()
m.CallBack = async (best, fit, arg, info) => {
ctx.postMessage([best, fit, arg, info])
}
if (event.data.type == 'start') {
/**
* blockList 小板列表
* boardList 大板(N个元素前N-1个元素表示余料板且余料板须为矩形第N个元素表示大板)
* boardCount 余料板数量(bigBang中前N-1个元素对应的数量如果bigBang中只有一个元素即只有大板没有余料板则为空数组)
* optimizeTimes 新优化次数
* isDoubleFaceBlockFirst 双面加工的小板是否优先排入
* gap 排版缝隙 = 开料刀直径 + 缝隙
* gzpb 规则排版
* isDoubleFaceBlockInRemain 余料板是否排入双面加工的小板
*/
let [blockList, boardList, boardCount, optimizeTimes, isDoubleFaceBlockFirst, gap, gzpb, isDoubleFaceBlockInRemain] = (event.data.data) as [xbang[], Big_bang[], number[], number, boolean, number, boolean, boolean]
m.Start(blockList, boardList, boardCount, optimizeTimes, isDoubleFaceBlockFirst, gap, gzpb, isDoubleFaceBlockInRemain)
} else {
const info = {
type: 'isStop',
ctx.postMessage([best, fit, arg, info])
}
await m.Stop(info)
ctx.postMessage([[], null, null, info])
ctx?.terminate()
}
})
// ctx.addEventListener('message', async (event) => {
// let m = new RectOptimizeMachine()
// m.CallBack = async (best, fit, arg, info) => {
if (event.data.type == 'start') {
/**
* blockList 小板列表
* boardList 大板(N个元素前N-1个元素表示余料板且余料板须为矩形第N个元素表示大板)
* boardCount 余料板数量(bigBang中前N-1个元素对应的数量如果bigBang中只有一个元素即只有大板没有余料板则为空数组)
* optimizeTimes 新优化次数
* isDoubleFaceBlockFirst 双面加工的小板是否优先排入
* gap 排版缝隙 = 开料刀直径 + 缝隙
* gzpb 规则排版
* isDoubleFaceBlockInRemain 余料板是否排入双面加工的小板
*/
let [blockList, boardList, boardCount, optimizeTimes, isDoubleFaceBlockFirst, gap, gzpb, isDoubleFaceBlockInRemain] = (event.data.data) as [xbang[], Big_bang[], number[], number, boolean, number, boolean, boolean]
// ctx.postMessage([best, fit, arg, info])
// }
// if (event.data.type == 'start') {
// /**
// * blockList 小板列表
// * boardList 大板(N个元素前N-1个元素表示余料板且余料板须为矩形第N个元素表示大板)
// * boardCount 余料板数量(bigBang中前N-1个元素对应的数量如果bigBang中只有一个元素即只有大板没有余料板则为空数组)
// * optimizeTimes 新优化次数
// * isDoubleFaceBlockFirst 双面加工的小板是否优先排入
// * gap 排版缝隙 = 开料刀直径 + 缝隙
// * gzpb 规则排版
// * isDoubleFaceBlockInRemain 余料板是否排入双面加工的小板
// */
// let [blockList, boardList, boardCount, optimizeTimes, isDoubleFaceBlockFirst, gap, gzpb, isDoubleFaceBlockInRemain] = (event.data.data) as [xbang[], Big_bang[], number[], number, boolean, number, boolean, boolean]
m.Start(blockList, boardList, boardCount, optimizeTimes, isDoubleFaceBlockFirst, gap, gzpb, isDoubleFaceBlockInRemain)
} else {
const info = {
type: 'isStop',
}
await m.Stop(info)
ctx.postMessage([[], null, null, info])
ctx?.terminate()
}
})
} else {
}
// m.Start(blockList, boardList, boardCount, optimizeTimes, isDoubleFaceBlockFirst, gap, gzpb, isDoubleFaceBlockInRemain)
// } else {
// const info = {
// type: 'isStop',
// }
// await m.Stop(info)
// ctx.postMessage([[], null, null, info])
// ctx?.terminate()
// }
// })
export default {} as typeof Worker & (new () => Worker)

View File

@@ -86,7 +86,7 @@ export interface xbang
}
/** 大板 */
export interface Big_bang //待优化的板
export class Big_bang //待优化的板
{
l: number; //长
w: number; //宽

View File

@@ -0,0 +1,365 @@
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.arrayRemoveDuplicateBySort = exports.GroupItem = exports.ArrayExt = exports.List = void 0;
var List = /** @class */ (function (_super) {
__extends(List, _super);
function List() {
return _super !== null && _super.apply(this, arguments) || this;
}
/** 返回符合条件的第一个元素 */
List.prototype.first = function (fn) {
if (this.length == 0)
return null;
for (var _i = 0, _a = this; _i < _a.length; _i++) {
var item = _a[_i];
if (fn(item))
return item;
}
return null;
};
/** 返回符合条件的最后一元素 */
List.prototype.last = function (fn) {
if (this.length == 0)
return null;
for (var i = this.length - 1; i >= 0; i--) {
if (fn(this[i]))
return this[i];
}
return null;
};
/** 最大值 */
List.prototype.max = function (fn) {
var maxV;
for (var _i = 0, _a = this; _i < _a.length; _i++) {
var i = _a[_i];
var v = fn(i);
if (maxV == null) {
maxV = fn(i);
}
else {
if (v > maxV) {
maxV = v;
}
}
}
return maxV;
};
/** 最小值 */
List.prototype.min = function (fn) {
var minV;
for (var _i = 0, _a = this; _i < _a.length; _i++) {
var i = _a[_i];
var v = fn(i);
if (minV == null) {
minV = fn(i);
}
else {
if (v < minV) {
minV = v;
}
}
}
return minV;
};
/** 累加 */
List.prototype.sum = function (fn) {
var v = 0;
for (var _i = 0, _a = this; _i < _a.length; _i++) {
var t = _a[_i];
v = v + fn(t);
}
return v;
};
/** 平均值 */
List.prototype.avg = function (fn) {
if (this.length == 0)
return 0;
var sum = this.sum(fn);
return sum / this.length;
};
/** 满足条件的元素数量 */
List.prototype.count = function (fn) {
if (this.length == 0)
return 0;
var c = 0;
for (var _i = 0, _a = this; _i < _a.length; _i++) {
var item = _a[_i];
if (fn(item))
c = c + 1;
}
return c;
};
List.prototype.FindMax = function (fn) {
return this.reduce(function (a, b) { return fn(a) > fn(b) ? a : b; });
};
return List;
}(Array));
exports.List = List;
var ArrayExt = /** @class */ (function () {
function ArrayExt() {
}
/** 返回满足条件的元素数量 */
ArrayExt.count = function (list, fn) {
if (list.length == 0)
return 0;
var c = 0;
for (var _i = 0, list_1 = list; _i < list_1.length; _i++) {
var item = list_1[_i];
if (fn(item))
c = c + 1;
}
return c;
};
/** 移除 */
ArrayExt.remove = function (list, obj) {
var index = list.findIndex(function (t) { return t == obj; });
if (index == -1)
return;
list.splice(index, 1);
};
/** 返回符合条件的第一个元素 */
ArrayExt.first = function (list, fn, orderFn1, orderFn2) {
if (orderFn1 === void 0) { orderFn1 = null; }
if (orderFn2 === void 0) { orderFn2 = null; }
if (list.length == 0)
return null;
if (orderFn1 == null) {
for (var _i = 0, list_2 = list; _i < list_2.length; _i++) {
var item = list_2[_i];
if (fn(item))
return item;
}
return null;
}
var minValue1;
var minValue2;
var minItem;
for (var _a = 0, list_3 = list; _a < list_3.length; _a++) {
var item = list_3[_a];
if (fn(item) == false)
continue;
var v1 = orderFn1(item);
var v2 = orderFn2 != null ? orderFn2(item) : 0;
if (minValue1 == null || v1 < minValue1 || (v1 == minValue1 && v2 < minValue2)) {
minValue1 = v1;
minValue2 = v2;
minItem = item;
}
}
return minItem;
};
/** 返回符合条件的最后一元素 */
ArrayExt.last = function (list, fn, orderFn1, orderFn2) {
if (orderFn1 === void 0) { orderFn1 = null; }
if (orderFn2 === void 0) { orderFn2 = null; }
if (list.length == 0)
return null;
if (orderFn1 == null) {
for (var i = list.length - 1; i >= 0; i--) {
if (fn(list[i]))
return list[i];
}
return null;
}
//
var maxValue1;
var maxValue2;
var maxItem;
for (var _i = 0, list_4 = list; _i < list_4.length; _i++) {
var item = list_4[_i];
if (fn(item) == false)
continue;
var v1 = orderFn1(item);
var v2 = orderFn2 ? orderFn2(item) : 0;
if (maxValue1 == null || v1 > maxValue1 || (v1 == maxValue1 && v2 > maxValue2)) {
maxValue1 = v1;
maxValue2 = v2;
maxItem = item;
}
}
return maxItem;
};
/** 取最大值 */
ArrayExt.max = function (list, fn, whereF, defaultV) {
if (whereF === void 0) { whereF = null; }
if (defaultV === void 0) { defaultV = null; }
var maxV;
for (var _i = 0, list_5 = list; _i < list_5.length; _i++) {
var i = list_5[_i];
if (whereF && whereF(i) == false)
continue;
var v = fn(i);
if (maxV == undefined) {
maxV = fn(i);
}
else {
if (v > maxV) {
maxV = v;
}
}
}
if (maxV != undefined)
return maxV;
return defaultV;
};
/** 最小值 */
ArrayExt.min = function (list, fn, whereF, defaultV) {
if (whereF === void 0) { whereF = null; }
if (defaultV === void 0) { defaultV = null; }
var minV;
for (var _i = 0, list_6 = list; _i < list_6.length; _i++) {
var i = list_6[_i];
if (whereF && whereF(i) == false)
continue;
var v = fn(i);
if (minV == undefined) {
minV = v;
}
else {
if (v < minV) {
minV = v;
}
}
}
if (minV != undefined)
return minV;
return defaultV;
};
/** 累加 */
ArrayExt.sum = function (list, fn, wn) {
var v = 0;
for (var _i = 0, list_7 = list; _i < list_7.length; _i++) {
var t = list_7[_i];
if (wn && wn(t) == false)
continue;
v = v + fn(t);
}
return v;
};
/** 平均值 */
ArrayExt.avg = function (list, fn) {
if (this.length == 0)
return 0;
var sum = ArrayExt.sum(list, fn);
return sum / this.length;
};
/** 排序 */
ArrayExt.sortBy = function (list, fn, fn2) {
if (fn2 === void 0) { fn2 = null; }
if (fn2 == null)
return list.sort(function (a, b) { return fn(a) - fn(b); });
else
return list.sort(function (a, b) { return fn(a) == fn(b) ? (fn2(a) - fn2(b)) : fn(a) - fn(b); });
};
/** 降序 排序 */
ArrayExt.sortByDescending = function (list, fn) {
list.sort(function (a, b) { return fn(b) - fn(a); });
};
/** 排序成新的数组 */
ArrayExt.orderBy = function (list, fn, fn2) {
if (fn2 === void 0) { fn2 = null; }
var newList = list.concat([]);
if (fn2 == null)
return newList.sort(function (a, b) { return fn(a) - fn(b); });
else
return newList.sort(function (a, b) { return fn(a) == fn(b) ? (fn2(a) - fn2(b)) : fn(a) - fn(b); });
};
/** 降序成新的数组 */
ArrayExt.orderByDescending = function (list, fn, fn2) {
if (fn2 === void 0) { fn2 = null; }
var newList = list.concat([]);
if (fn2 == null)
return list.sort(function (a, b) { return fn(b) - fn(a); });
else
return list.sort(function (a, b) { return fn(a) == fn(b) ? (fn2(b) - fn2(a)) : fn(b) - fn(a); });
};
/** 分组 */
ArrayExt.groupBy = function (list, fn) {
var groups = new Array();
var _loop_1 = function (item) {
var key = fn(item);
var group = groups.find(function (t) { return t.key == key; });
if (group == null) {
group = new GroupItem(key);
groups.push(group);
}
group.push(item);
};
for (var _i = 0, list_8 = list; _i < list_8.length; _i++) {
var item = list_8[_i];
_loop_1(item);
}
return groups;
};
/**
* 选择
* let newObjectList = ArrayExt.Select(list,t=>({pA:t.name, pB:t.age + "_"+ t.month}) ) ;
*/
ArrayExt.Select = function (list, fn) {
var newList = new Array();
for (var _i = 0, list_9 = list; _i < list_9.length; _i++) {
var t = list_9[_i];
newList.push(fn(t));
}
return newList;
};
/** 过来,并按顺序排序 */
ArrayExt.where = function (list, whereFn, orderfn1, orderfn2) {
if (orderfn1 === void 0) { orderfn1 = null; }
if (orderfn2 === void 0) { orderfn2 = null; }
var newList = list.filter(whereFn);
if (orderfn1 == null && orderfn2 == null)
return newList;
return ArrayExt.sortBy(newList, orderfn1, orderfn2);
};
return ArrayExt;
}());
exports.ArrayExt = ArrayExt;
var GroupItem = /** @class */ (function () {
function GroupItem(k) {
this.key = k;
this.list = [];
}
Object.defineProperty(GroupItem.prototype, "count", {
get: function () { return this.list.length; },
enumerable: false,
configurable: true
});
GroupItem.prototype.push = function (d) {
this.list.push(d);
};
return GroupItem;
}());
exports.GroupItem = GroupItem;
/**
* 对排序好的数组进行去重操作
* @param {(e1, e2) => boolean} [checkFuction] 校验对象相等函数
* @returns {Array<T>} 返回自身
*/
function arrayRemoveDuplicateBySort(arr, checkFuction) {
if (checkFuction === void 0) { checkFuction = checkEqual; }
if (arr.length < 2)
return arr;
var j = 1;
for (var i = 1, l = arr.length; i < l; i++)
if (!checkFuction(arr[j - 1], arr[i]))
arr[j++] = arr[i];
arr.length = j;
return arr;
}
exports.arrayRemoveDuplicateBySort = arrayRemoveDuplicateBySort;

View File

@@ -0,0 +1,141 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Box2 = void 0;
var Vector2_js_1 = require("./Vector2.js");
var Box2 = /** @class */ (function () {
function Box2(min, max) {
if (min === void 0) { min = new Vector2_js_1.Vector2(+Number.POSITIVE_INFINITY, +Number.POSITIVE_INFINITY); }
if (max === void 0) { max = new Vector2_js_1.Vector2(Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY); }
this.min = min;
this.max = max;
}
Object.defineProperty(Box2.prototype, "area", {
/** 获取面积 */
get: function () {
return (this.max.x - this.min.x) * (this.max.y - this.min.y);
},
enumerable: false,
configurable: true
});
/** */
Box2.prototype.set = function (min, max) {
this.min.copy(min);
this.max.copy(max);
return this;
};
Box2.prototype.setFromPoints = function (points) {
this.makeEmpty();
for (var _i = 0, points_1 = points; _i < points_1.length; _i++) {
var p = points_1[_i];
this.expandByPoint(p);
}
return this;
};
Box2.prototype.setFromCenterAndSize = function (center, size) {
var v1 = Box2._setFromCenterAndSize_v1;
var halfSize = v1.copy(size).multiplyScalar(0.5);
this.min.copy(center).sub(halfSize);
this.max.copy(center).add(halfSize);
return this;
};
Box2.prototype.clone = function () {
return new this.constructor().copy(this);
};
Box2.prototype.copy = function (box) {
this.min.copy(box.min);
this.max.copy(box.max);
return this;
};
Box2.prototype.makeEmpty = function () {
this.min.x = this.min.y = +Number.POSITIVE_INFINITY;
this.max.x = this.max.y = Number.NEGATIVE_INFINITY;
return this;
};
Box2.prototype.isEmpty = function () {
// this is a more robust check for empty than (volume <= 0) because volume can get positive with two negative axes
return (this.max.x < this.min.x) || (this.max.y < this.min.y);
};
Box2.prototype.getCenter = function (result) {
if (result === void 0) { result = new Vector2_js_1.Vector2(); }
return this.isEmpty() ? result.set(0, 0) : result.addVectors(this.min, this.max).multiplyScalar(0.5);
};
Box2.prototype.getSize = function (result) {
if (result === void 0) { result = new Vector2_js_1.Vector2(); }
return this.isEmpty() ? result.set(0, 0) : result.subVectors(this.max, this.min);
};
Box2.prototype.expandByPoint = function (point) {
this.min.min(point);
this.max.max(point);
return this;
};
Box2.prototype.expandByVector = function (vector) {
this.min.sub(vector);
this.max.add(vector);
return this;
};
Box2.prototype.expandByScalar = function (scalar) {
this.min.addScalar(-scalar);
this.max.addScalar(scalar);
return this;
};
Box2.prototype.containsPoint = function (point) {
if (point.x < this.min.x || point.x > this.max.x
|| point.y < this.min.y || point.y > this.max.y) {
return false;
}
return true;
};
Box2.prototype.containsBox = function (box) {
if ((this.min.x <= box.min.x) && (box.max.x <= this.max.x)
&& (this.min.y <= box.min.y) && (box.max.y <= this.max.y)) {
return true;
}
return false;
};
Box2.prototype.getParameter = function (point, result) {
if (result === void 0) { result = new Vector2_js_1.Vector2(); }
// This can potentially have a divide by zero if the box
// has a size dimension of 0.
return result.set((point.x - this.min.x) / (this.max.x - this.min.x), (point.y - this.min.y) / (this.max.y - this.min.y));
};
Box2.prototype.intersectsBox = function (box) {
// using 6 splitting planes to rule out intersections.
if (box.max.x < this.min.x || box.min.x > this.max.x
|| box.max.y < this.min.y || box.min.y > this.max.y) {
return false;
}
return true;
};
Box2.prototype.clampPoint = function (point, result) {
if (result === void 0) { result = new Vector2_js_1.Vector2(); }
return result.copy(point).clamp(this.min, this.max);
};
Box2.prototype.distanceToPoint = function (point) {
var v1 = Box2._distanceToPoint_v1;
var clampedPoint = v1.copy(point).clamp(this.min, this.max);
return clampedPoint.sub(point).length();
};
Box2.prototype.intersect = function (box) {
this.min.max(box.min);
this.max.min(box.max);
return this;
};
Box2.prototype.union = function (box) {
this.min.min(box.min);
this.max.max(box.max);
return this;
};
Box2.prototype.translate = function (offset) {
this.min.add(offset);
this.max.add(offset);
return this;
};
Box2.prototype.equals = function (box) {
return box.min.equals(this.min) && box.max.equals(this.max);
};
Box2._setFromCenterAndSize_v1 = new Vector2_js_1.Vector2();
Box2._distanceToPoint_v1 = new Vector2_js_1.Vector2();
return Box2;
}());
exports.Box2 = Box2;
;

View File

@@ -7,7 +7,6 @@ import type { Curve2d } from '../base/CAD'
import { Arc2d, Point2d, copyTextToClipboard } from '../base/CAD'
import { CurveWrap } from './Curves2Parts'
// import type { Curve2d } from '../../common/base/CAD'
export class PolylineHelper {
/** 创建闭合多段线 */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,75 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (g && (g = 0, op[0] && (_ = 0)), _) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
Object.defineProperty(exports, "__esModule", { value: true });
var RectOptimizeMachine_1 = require("./RectOptimizeMachine");
var ctx = this;
if (typeof window !== 'undefined' && 'Worker' in window) {
ctx.addEventListener('message', function (event) { return __awaiter(void 0, void 0, void 0, function () {
var m, _a, blockList, boardList, boardCount, optimizeTimes, isDoubleFaceBlockFirst, gap, gzpb, isDoubleFaceBlockInRemain, info;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
m = new RectOptimizeMachine_1.RectOptimizeMachine();
m.CallBack = function (best, fit, arg, info) { return __awaiter(void 0, void 0, void 0, function () {
return __generator(this, function (_a) {
ctx.postMessage([best, fit, arg, info]);
return [2 /*return*/];
});
}); };
if (!(event.data.type == 'start')) return [3 /*break*/, 1];
_a = (event.data.data), blockList = _a[0], boardList = _a[1], boardCount = _a[2], optimizeTimes = _a[3], isDoubleFaceBlockFirst = _a[4], gap = _a[5], gzpb = _a[6], isDoubleFaceBlockInRemain = _a[7];
m.Start(blockList, boardList, boardCount, optimizeTimes, isDoubleFaceBlockFirst, gap, gzpb, isDoubleFaceBlockInRemain);
return [3 /*break*/, 3];
case 1:
info = {
type: 'isStop',
};
return [4 /*yield*/, m.Stop(info)];
case 2:
_b.sent();
ctx.postMessage([[], null, null, info]);
ctx === null || ctx === void 0 ? void 0 : ctx.terminate();
_b.label = 3;
case 3: return [2 /*return*/];
}
});
}); });
}
else {
}
exports.default = {};

View File

@@ -0,0 +1,42 @@
import type { Big_bang, xbang } from './bang'
import { RectOptimizeMachine } from './RectOptimizeMachine'
// import {Worker} from "worker_threads"
import { Worker as NodeWorker } from 'worker_threads';
const ctx: NodeWorker | Worker = self as any
debugger
if (typeof window !== 'undefined' && 'Worker' in window) {
ctx.addEventListener('message', async (event) => {
let m = new RectOptimizeMachine()
m.CallBack = async (best, fit, arg, info) => {
ctx.postMessage([best, fit, arg, info])
}
if (event.data.type == 'start') {
/**
* blockList 小板列表
* boardList 大板(N个元素前N-1个元素表示余料板且余料板须为矩形第N个元素表示大板)
* boardCount 余料板数量(bigBang中前N-1个元素对应的数量如果bigBang中只有一个元素即只有大板没有余料板则为空数组)
* optimizeTimes 新优化次数
* isDoubleFaceBlockFirst 双面加工的小板是否优先排入
* gap 排版缝隙 = 开料刀直径 + 缝隙
* gzpb 规则排版
* isDoubleFaceBlockInRemain 余料板是否排入双面加工的小板
*/
let [blockList, boardList, boardCount, optimizeTimes, isDoubleFaceBlockFirst, gap, gzpb, isDoubleFaceBlockInRemain] = (event.data.data) as [xbang[], Big_bang[], number[], number, boolean, number, boolean, boolean]
m.Start(blockList, boardList, boardCount, optimizeTimes, isDoubleFaceBlockFirst, gap, gzpb, isDoubleFaceBlockInRemain)
} else {
const info = {
type: 'isStop',
}
await m.Stop(info)
ctx.postMessage([[], null, null, info])
ctx?.terminate()
}
})
} else {
}
export default {} as typeof Worker & (new () => Worker)

View File

@@ -0,0 +1,60 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.WorkerItemType = exports.BlockRegion = exports.Big_bang = exports.HoleType = exports.ComposingType = exports.LineType = void 0;
/**纹路类型 Positive=0正纹 Reverse=1反纹 CanReversal=2可翻转 */
var LineType;
(function (LineType) {
/**正纹 */
LineType[LineType["Positive"] = 0] = "Positive";
/**反纹 */
LineType[LineType["Reverse"] = 1] = "Reverse";
/**可翻转 */
LineType[LineType["CanReversal"] = 2] = "CanReversal";
})(LineType || (exports.LineType = LineType = {}));
/**版面类型: Positive=0正面 Reverse=1反面 Arbitrary=2任意面 */
var ComposingType;
(function (ComposingType) {
/**正面 */
ComposingType[ComposingType["Positive"] = 0] = "Positive";
/**反面 */
ComposingType[ComposingType["Reverse"] = 1] = "Reverse";
/**任意面 */
ComposingType[ComposingType["Arbitrary"] = 2] = "Arbitrary";
})(ComposingType || (exports.ComposingType = ComposingType = {}));
/**孔类型 None=0无 Positive=1正面 Reverse=2反面 Two=3正反 */
var HoleType;
(function (HoleType) {
/**无 */
HoleType[HoleType["None"] = 0] = "None";
/**正面 */
HoleType[HoleType["Positive"] = 1] = "Positive";
/**反面 */
HoleType[HoleType["Reverse"] = 2] = "Reverse";
/**正反 */
HoleType[HoleType["Two"] = 3] = "Two";
})(HoleType || (exports.HoleType = HoleType = {}));
/** 大板 */
var Big_bang //待优化的板
= /** @class */ (function () {
function Big_bang() {
}
return Big_bang;
}());
exports.Big_bang = Big_bang;
var BlockRegion;
(function (BlockRegion) {
/** 左下 = 0 */
BlockRegion[BlockRegion["LEFT_BOTTOM"] = 0] = "LEFT_BOTTOM";
/** 右下 = 1 */
BlockRegion[BlockRegion["RIGHT_BOTTOM"] = 1] = "RIGHT_BOTTOM";
/** 右上 = 2 */
BlockRegion[BlockRegion["RIGHT_TOP"] = 2] = "RIGHT_TOP";
/** 左上 = 3 */
BlockRegion[BlockRegion["LEFT_TOP"] = 3] = "LEFT_TOP";
})(BlockRegion || (exports.BlockRegion = BlockRegion = {}));
var WorkerItemType = /** @class */ (function () {
function WorkerItemType() {
}
return WorkerItemType;
}());
exports.WorkerItemType = WorkerItemType;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,245 @@
import { Processor, ProcessorModule } from "../../src/device";
import { confItem, PlaceBlock, PlaceBlockDetail, PlaceMaterial } from "../confClass";
import { Big_bang, ComposingType, LineType, WorkerItemType, xbang } from "../handleAbility/RectOptimizeWorker/bang";
import resData from './res1.json'
import { UniversalWorker } from "../WorkerHelper";
import { RectOptimizeMachine } from "./RectOptimizeWorker/RectOptimizeMachine";
/** 模块 新优化
*
* input 入参
*
* ProcessorModule<any, any>这里的any 可以自定义 根据组件需求
*/
export const RectOptimizeMachineModule: ProcessorModule<any, any> = {
moduleName: "RectOptimizeMachine",
moduleVersion: '20250714',
config: {
placeStyle: 1,
/** 总修边宽度 */
cutBoardBorder: 3,
cutKnifeGap: 1,
isDoubleFaceBlockFirst: true,
blockKnifeLineSpacing: 0,
isRectPlace: false,
isDoubleFaceBlockInRemain: true,
},
workerList: [],
setConfig(config) {
this.config = { ...this.config, ...config };
},
before(input) {
// console.log(`优化前要做的事情`, input);
},
// 会在处理器自动执行
/**
*
* @param input 输入数据
* @param next 下一个流程的函数
* @param context 上下文
* @returns
*/
process(input, next, context) {
let { blockList, materialList } = input
let bList: any = []
let pm = materialList[0]
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
if (Array.isArray(pm.blockList)) {
pm.blockList.push(e)
} else {
pm.blockList = [e]
}
}
})
pm.cutBorder = this.config.cutBoardBorder
pm.cutKnifeGap = this.config.cutKnifeGap
/** 小板 */
let bans: xbang[] = []
// 实际开料大板的列表
let big_Bang: Big_bang[] = []
let big_BangSL: number[] = []
let border = this.config.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 = toLine(b.texture)
bans.push({
l: length,
w: width,
line,
face: toface(b),
id: bid,
bno: b.blockNo,
holeFaceCount: 3,
isRect: !b.isUnRegular,
hasHole: false,
isdtwosided: true,
})
}
let bestCount = 0
if (bans.length == 0) // 没有板了
{
if (context.CallBack) {
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'
}
}
context.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.config.isDoubleFaceBlockFirst // 双面加工排前面
let gap = this.config.blockKnifeLineSpacing
/** 这里要做个多线程 测试环境下 这部分有问题 暂时略过 */
const m = new RectOptimizeMachine()
const self = this
m.CallBack = async (best, fit, arg, info) => {
console.log('优化结果', pm, [best, fit, arg, info]);
let res={
moduleName:self.moduleName,
pm,
result: [best, fit, arg, info],
input,
context
}
self.onMessage(res)
}
const data = {
type: 'start',
data: [bans, big_Bang, big_BangSL, xyhcs, isDoubleFaceBlockFirst, gap, this.config.isRectPlace, this.config.isDoubleFaceBlockInRemain],
}
m.Start(bans, big_Bang, big_BangSL, xyhcs, isDoubleFaceBlockFirst, gap, this.config.isRectPlace, this.config.isDoubleFaceBlockInRemain)
return next ? next(input) : input;
},
after(result, input, context) {
console.log(`优化后要做的事情`,);
},
onError(error) {
console.log('出错了哦', error);
}
};
function toLine(texture): LineType {
if (texture == 0)
return LineType.Positive
if (texture == 1)
return LineType.CanReversal
return LineType.Reverse
}
/** 小板加工面Positive=0正面 Reverse=1反面 Arbitrary=2任意 */
function toface(block: PlaceBlock): ComposingType {
let turnF = block.isTurnFaceToPlace
// if (this.isTurnFaceToPlace)
if (true)
turnF = !turnF
if (!turnF)
return ComposingType.Positive
return ComposingType.Reverse
}
/** 配置列表 */
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
},
]

View File

@@ -0,0 +1,130 @@
import { Processor, ProcessorModule } from "../../src/device";
import { ErrorInfo } from "../../src/device";
import { KLSC, YH_bang } from "./RectOptimizeWorker/bang";
/** 模块 开料顺序
*
* input 入参
*/
/** 开料顺序 */
export const AutoCalcCutOrder: ProcessorModule<any, any> = {
moduleName: "AutoCalcCutOrder",
moduleVersion: '20250714',
config: {
boardWidth: 0,
boardLength: 0,
placeStyle: 1,
},
setConfig(config) {
this.config = { ...this.config, ...config };
},
// 会在处理器自动执行
/**
*
* @param input 输入数据
* @param next 下一个流程的函数
* @param context 上下文
* @returns
*/
process(input, next, context) {
const { materialList } = input
for (const pm of materialList) {
for (const pb of pm.boardList) {
let selectBs = pb.blockList;
let beginId = 0;
const has0 = pb.blockList.filter(t => t.cutOrder == 0);
const has1 = pb.blockList.filter(t => t.cutOrder > 0);
const has2 = pb.blockList.filter(t => t.cutOrder < 0);
//有手动指定开料顺序的
if (has0.length > 0 && (has1.length + has2.length) > 0) {
selectBs = has0;
if (has1.length > 0) //开头的
{
const bs = has1.sort((a, b) => a.cutOrder - b.cutOrder);
for (const b of bs) {
beginId++;
b.cutOrder = beginId;
}
}
if (has2.length > 0) //结尾的
{
const bs = has2.sort((a, b) => a.cutOrder - b.cutOrder);
let endId = has0.length + has1.length;
for (const b of bs) {
endId++;
b.cutOrder = endId;
}
}
}
let bangs: YH_bang[] = [];
let blocks = new Array();
for (let i = 0; i < selectBs.length; i++) {
let block = selectBs[i];
let bangid = i + 1;
let x = block.placeX;
let y = block.placeY;
let pbg = block.placeLength;
let pbk = block.placeWidth;
blocks[bangid] = block;
bangs.push({
bangid,
line: 0,
pbg,
pbk,
x,
y,
ishb: false,
hb: [],
isbig: false,
isqg: false,
isgr: false,
gr: [],
grid: -1
});
}
let dt = pm.diameter + pm.cutKnifeGap;
let k = pb.width;
let g = pb.length;
let xdsc: KLSC = new KLSC(bangs, k, g, dt, 0, 0, 1);
// try {
// xdsc
// } catch (error) {
// console.log(error);
// }
let rt = xdsc.SCid;
// let rt = JSXDSC(bangs, dt, k, g);
if (rt.length < selectBs.length) return;
for (let i = 0; i < rt.length; i++) {
let bid = rt[i];
beginId++;
blocks[bid].cutOrder = beginId;
}
}
}
return next ? next(input) : input;
},
onError(error) {
console.error('出错了哦', error);
}
};

View File

@@ -0,0 +1,76 @@
import { Processor, ProcessorModule } from "../../src/device";
import { ErrorInfo } from "../../src/device";
/** 模块 检查异常板
*
* input 入参
*/
export const CheckBlocks: ProcessorModule<any, any> = {
moduleName: "CheckMaterial",
moduleVersion: '20250714',
config: {
minBlockWidth: 0,
minBlockThickness: 0,
},
setConfig(config) {
this.config = { ...this.config, ...config };
},
// 会在处理器自动执行
/**
*
* @param input 输入数据
* @param next 下一个流程的函数
* @param context 上下文
* @returns
*/
process(input, next, context) {
const { materialList, blockList } = input
const self = this;
let checkArr = checkBlocks(materialList, blockList)
if (checkArr.length > 0) {
const _errinfo: ErrorInfo = {
moduleName: this.moduleName,
moduleVersion: this.moduleVersion,
info: {
data: checkArr,
msg: '该订单内小板有异常'
}
}
this.onError(_errinfo)
}
function checkBlocks(materialList, blockList): any[] {
let allBlocks: any[] = []
for (let pm of materialList) {
let bList = blockList.filter(e => e.goodsId == pm.goodsId)
for (const pb of bList) {
if (pb.width < self.minBlockWidth) {
allBlocks.push(pb)
}
if (pb.thickness < self.minBlockThickness) {
allBlocks.push(pb)
}
}
}
return allBlocks
}
return next ? next(input) : input;
},
onError(error) {
console.error('出错了哦', error);
}
};

View File

@@ -0,0 +1,77 @@
import { Processor, ProcessorModule } from "../../src/device";
import { ErrorInfo } from "../../src/device";
/** 模块 检查是否 板材尺寸大于机台尺寸
*
* input 入参
*/
/** 检查是否 板材尺寸大于机台尺寸 */
export const CheckMaterial: ProcessorModule<any, any> = {
moduleName: "CheckMaterial",
moduleVersion: '20250714',
config: {
boardWidth: 0,
boardLength: 0,
placeStyle:1,
},
setConfig(config) {
this.config = { ...this.config, ...config };
},
// 会在处理器自动执行
/**
*
* @param input 输入数据
* @param next 下一个流程的函数
* @param context 上下文
* @returns
*/
process(input, next, context) {
const { materialList } = input
const self = this;
let checkArr = checkMetrial(materialList)
if (checkArr.length > 0) {
const _errinfo: ErrorInfo = {
moduleName: this.moduleName,
moduleVersion: this.moduleVersion,
info: {
data: checkArr,
msg: '该订单内大板有异常'
}
}
this.onError(_errinfo)
}
function checkMetrial(materialList): any[] {
let errPMs: any = []
if (self.placeStyle !== 1) {
for (let pm of materialList) {
if (pm.orgWidth > self.boardWidth || pm.orgLength > self.boardLength) {
// console.log('板材尺寸大于机台尺寸', PlaceStore.sysConfig)
errPMs.push(pm)
}
}
}
return errPMs
}
return next ? next(input) : input;
},
onError(error) {
console.error('出错了哦', error);
}
};

View File

@@ -0,0 +1,58 @@
import { Processor, ProcessorModule } from "../../src/device";
import { ErrorInfo } from "../../src/device";
/** 模块 开料顺序
*
* input 入参
*/
/** 开料顺序 */
export const AutoCalcCutOrder: ProcessorModule<any, any> = {
moduleName: "CheckMaterial",
moduleVersion: '20250714',
config: {
boardWidth: 0,
boardLength: 0,
placeStyle:1,
},
setConfig(config) {
this.config = { ...this.config, ...config };
},
// 会在处理器自动执行
/**
*
* @param input 输入数据
* @param next 下一个流程的函数
* @param context 上下文
* @returns
*/
process(input, next, context) {
const { materialList } = input
// if (pb.isLocked) return;
// let blocks = pb.blockList;
// if (blocks.length == 0) return;
// if (blocks.length == 1) {
// blocks[0].cutOrder = 1;
// }
// else {
// this.autoSortBlockNew(pm, pb);
// }
return next ? next(input) : input;
},
onError(error) {
console.error('出错了哦', error);
}
};

View File

@@ -0,0 +1,152 @@
import { Processor, ProcessorModule } from "../../src/device";
import { ErrorInfo } from "../../src/device";
import { BlockPlaceResult, BoardPlaceResult, BoardPosition, MaterialPlaceResult, PlaceStyle } from "../confClass";
/** 模块 处理优化源数据 数据处理 将优化数据转 为 MaterialPlaceResult
*
* input 入参
*/
export const HandleMaterialPlaceResult: ProcessorModule<any, any> = {
moduleName: "HandleMaterialPlaceResult",
moduleVersion: '20250714',
config: {
cutBoardBorder:3,
// 是否跟随大板定位
placeOriginByBoardLocation: true,
boardLocation: 0
},
setConfig(config) {
this.config = { ...this.config, ...config };
},
// 会在处理器自动执行
/**
*
* @param input 输入数据
* @param next 下一个流程的函数
* @param context 上下文
* @returns
*/
process(input, next, context) {
let {
bList, best, yl, pm, width, length
} = context.MaterialPlaceSource
let blocks = bList
let retData = new MaterialPlaceResult()
let boardCount = 0
let remainCount = 0
let border = this.config.cutBoardBorder
let borderOff = (pm.diameter + pm.cutKnifeGap) / 2
// 所有大板上的小板面积
let size_all = 0
for (let i = 0; i < best.length; i++) {
let bd = best[i]
let isRemainBoard = false
boardCount = retData.boards.length + 1
if (i < yl.length) // 余料板
{
width = yl[i].w + border * 2 - borderOff * 2
length = yl[i].l + border * 2 - borderOff * 2
isRemainBoard = true
remainCount++
}
let boardResult = new BoardPlaceResult()
boardResult.boardId = boardCount
boardResult.width = width
boardResult.length = length
boardResult.isRemainBoard = isRemainBoard
let pid = 0
for (let b of bd) {
pid++
let block = blocks[b.bangid]
let placeStyle = PlaceStyle.FRONT
if (!block) {
return
}
let faceF = block.isTurnFaceToPlace || false
let isTurnFaceToPlace = this.config.placeOriginByBoardLocation && (
this.config.boardLocation == BoardPosition.RIGHT_BOTTOM || this.boardLocation == BoardPosition.LEFT_TOP)
if (isTurnFaceToPlace)
faceF = !faceF
if (faceF) // 翻面开料
{
if (block.texture == 0) {
placeStyle = PlaceStyle.BACK
}
else if (block.texture == 2) {
placeStyle = PlaceStyle.BACK_TURN_LEFT
}
else {
placeStyle = (b.pbg == block.placeFullLength ? PlaceStyle.BACK : PlaceStyle.BACK_TURN_LEFT)
}
}
else {
if (block.texture == 0) {
placeStyle = PlaceStyle.FRONT
}
else if (block.texture == 2) {
placeStyle = PlaceStyle.FRONT_TURN_RIGHT
}
else {
placeStyle = (b.pbg == block.placeFullLength ? PlaceStyle.FRONT : PlaceStyle.FRONT_TURN_RIGHT)
}
}
let br: any = null
br = new BlockPlaceResult(block.blockNo, boardCount, pid, b.x, b.y, b.pbk, b.pbg, placeStyle, block.area)
boardResult.blocks.push(br)
boardResult.area += block.area
}
retData.boards.push(boardResult)
size_all += boardResult.area
let val = (size_all - boardResult.area) / (retData.boards.length - 1)
retData.avgUsageRateAll = size_all / retData.boards.length
retData.avgUsageRateExcludeLastBoard = Number.isNaN(val) ? boardResult.area : val
retData.usageRateLastBoard = boardResult.area
retData.boardCount = retData.boards.length
}
retData.boardCount = retData.boards.length // 大板数
let remainBoardCount = retData.boards.filter(t => t.remainNo != '').length // 异形大板数
let remianCount = 0
if (Array.isArray(pm.remainBoardList)) {
pm.remainBoardList.forEach(e => {
if (e?.placeBoardJSON) {
let str = e?.placeBoardJSON
e.placeBoardList = JSON.parse(str)
remianCount += e.placeBoardList.length
}
})
}
retData.remainBoardCount = pm?.remainBoardList ? remianCount : yl.length + remainBoardCount
console.log({ placeResult: retData, pm } )
let res = { module:this.moduleName, placeResult: retData, pm }
Reflect.set(context,'MaterialPlaceResult',res)
return next ? next(input) : input;
},
onError(error) {
console.error('出错了哦', error);
}
};

View File

@@ -0,0 +1,639 @@
import { Processor, ProcessorModule } from "../../src/device";
import { ErrorInfo } from "../../src/device";
import { BoardPosition, PlaceBlock, PlaceBoard, PlaceMaterial, PlaceStyle } from "../confClass";
import { ArrayExt } from "../handleAbility/common/ArrayExt";
/** 模块 检查是否 板材尺寸大于机台尺寸
*
* input 入参
*/
class Point {
/** 坐标x */
x: number
/** 坐标y */
y: number
constructor(x: number, y: number) {
this.x = x
this.y = y
}
}
/** 检查是否 板材尺寸大于机台尺寸 */
export const handlePlaceResultToPlaceMaterial: ProcessorModule<any, any> = {
moduleName: "handlePlaceResultToPlaceMaterial",
moduleVersion: '20250714',
config: {
boardWidth: 0,
boardLength: 0,
placeStyle: 1,
},
setConfig(config) {
this.config = { ...this.config, ...config };
},
// 会在处理器自动执行
/**
*
* @param input 输入数据
* @param next 下一个流程的函数
* @param context 上下文
* @returns
*/
process(input, next, context) {
// const { placeResult,pm } = input
let pm: PlaceMaterial = context.MaterialPlaceResult.pm
pm.tempBestPlaceResult = context.MaterialPlaceResult.placeResult
// 没发现优化结果
if (!pm.tempBestPlaceResult) {
let errInfo: ErrorInfo = {
moduleName: this.moduleName,
info: '没有优化数据'
}
return errInfo
}
let placeResult = pm.tempBestPlaceResult
let orgBoardList = pm.boardList
let dic: any = [] // 存放当前 优化的小板
pm.boardList = []
let boardId = 1
// 第一次 false
if (pm.tempPlaceResultOnyUnlockedBoard) {
for (let pb of orgBoardList) {
if (pb.isLocked == false && pb.cutedType == 0) // 未锁定
{
pb.blockList.forEach(i => dic[i.blockNo] = i)
}
else // 锁定
{
if (pb.isAdnormal) {
let sb = pm.remainBoardList.find(t => t.id == Number(pb.boardNo))
if (sb)
sb.isUsed = true
}
pb.boardId = boardId
pm.boardList.push(pb)
boardId++
}
}
}
else {
pm.blockList.forEach(i => dic[i.blockNo] = i)
}
// 0904 修复 需求改造后 导致 这里的dic 最终为空
if (Object.keys(dic).length == 0) {
pm.blockList.forEach(i => dic[i.blockNo] = i)
}
let locator = this.boardLocation
// 大板优化结果
for (let bpr of placeResult.boards) {
boardId++
// bpr.isRemainBoard false
let bW = bpr.isRemainBoard ? bpr.width : pm.width
let bL = bpr.isRemainBoard ? bpr.length : pm.length
let pb = new PlaceBoard(boardId, bW, bL, bpr.remainId, bpr.remainNo)
pb.isCreateRemainSpace = true
for (let bInfo of bpr.blocks) {
let block: PlaceBlock = dic[bInfo.blockId]
if (block) {
block.isPlaced = true
block.boardId = boardId
block.placeId = bInfo.placeId
block.placeX = bInfo.placeX
block.placeY = bInfo.placeY
// console.log('重置 开料面 开料信息 after', block.boardId, block.blockNo, block, block.placeStyle, bInfo.placeStyle)
/**
* 雕刻机(钻孔、拉槽、开料)优化排版,开料排版面(开料正面)选择顺序:排版面>>造型>>排钻>>设计正面
1. 排版面
小板设计排版面为正面或反面,设置对应面为开料排版面,
小板设计排版面为随意面,则继续;
2. 造型
小板只有单面造型,设置对应面为开料排版面,
小板双面无造型或双面有造型,则继续;
3. 排钻
小板有大孔(偏心轮锁孔),设置对应面为开料排版面,
小板无大孔(偏心轮锁孔),则设置孔多的面为开料排版面,
小板无孔,则继续;
4. 设计正面
默认设置设计正面为开料排版面。
*/
block.placeStyle = bInfo.placeStyle
let posOff = this.getOffDis(block)
block.placeOffX = posOff.x
block.placeOffY = posOff.y
block.placeX = bInfo.placeX + posOff.x
block.placeY = bInfo.placeY + posOff.y
if (bInfo.placeStyle == PlaceStyle.FRONT || bInfo.placeStyle == PlaceStyle.FRONT_TURN_BACK
|| bInfo.placeStyle == PlaceStyle.BACK || bInfo.placeStyle == PlaceStyle.BACK_TURN_BACK) {
block.placeWidth = block.cutWidth
block.placeLength = block.cutLength
}
else {
block.placeWidth = block.cutLength
block.placeLength = block.cutWidth
}
block.isAutoPlaced = true
block.isOverlap = false
block.cutOrder = 0
pb.blockList.push(block)
pb.blockCount++
pb.blockArea += block.area
delete dic[bInfo.blockId] // 移除block;
} else {
}
}
if (bpr.isScrap) {
// 设置前余料板的使用状态,将不需要的释放.
console.log('设置前余料板的使用状态,将不需要的释放.')
let sb = pm.remainBoardList.find(t => t.id == bpr.remainId)
if (sb) {
sb.isUsed = true
if (sb.placeStyle % 2 != 0) {
pb.width = sb.length
pb.length = sb.width
}
let pl = sb.placePolyline
pb.points = sb?.placePolyline?.LineData.map((t) => { return { x: t.pt.x, y: t.pt.y, bul: t.bul } }) || []
// pb.StoreNo = sb.StoreHouse;
}
}
pb.usageRate = Math.round(10000 * pb.blockArea / pb.area) / 100
pm.boardList.push(pb)
console.log('大板靠板翻转', pb.boardId, locator)
// 大板靠板翻转
this.turnPlacePosition(pb, locator)
for (let block of pb.blockList) {
// 重置 开料面 开料信息
// console.log('重置 开料面 开料信息', block.boardId, block.blockNo, block, block.placeStyle)
if (block.placeStyle == null || block.placeStyle == undefined) {
console.log('handleTempPlaceResultToPlaceMaterial error block.placeStyle is null or undefined')
} else {
this.resetPlaceStyle(block, block.placeStyle)
}
}
}
//【功能】 大板长边两侧 width 范围内 避免出现造型 DisPoseModelInBoardBorderWidth > 0 生效
// this.DisPoseModelInBoardBorder(
// pm,
// this.boardBorderModelRange,
// this.boardBorderModelModeToFace,
// this.boardBorderModelByMachine,
// this.modelNearBoardBorder,
// )
// for (let pb of pm.boardList) {
// // 重设大板汇总 重设 大板开料 顺序,下刀点
// this.resetPlaceBoard(pm, pb)
// // 检查干涉
// if (pb.isLocked == false && pb.cutedType == 0)
// this.checkOverlapInBoard(pm, pb)
// }
let rBoardCount = placeResult.boardCount
let rUseSize_avg = placeResult.avgUsageRateAll
let rUseSize_noLast = placeResult.avgUsageRateExcludeLastBoard
let rUseSize_last = placeResult.usageRateLastBoard
pm.avgUsageRateAll = rUseSize_avg
pm.avgUsageRateExcludeLastBoard = rUseSize_noLast
pm.usageRateLastBoard = rUseSize_last
pm.boardCount = pm.boardList.length
pm.remainBoardCount = placeResult.remainBoardCount
pm.minBoardId = 1
pm.maxBoardId = pm.boardCount
//【功能】 获取封边长度
// pm.edgeSealLengthList = this.getMaterialSealEdge(pm.blockList)
pm.boardCountFlipFace = ArrayExt.count(pm.boardList, t => t.isTwoFaceProcessing)
pm.isOptimized = true
pm.tempBestPlaceResult = null
pm.tempPlaceResultError = ''
let mesg = ''
let c = 0
for (let v in dic) {
mesg += `${v} `
c++
}
mesg = `${c}片小板未能排入大板,有可能是尖角导致优化失败.${mesg}`
if (c > 0) {
console.log(pm)
// createMessage.error(mesg)
throw new Error(mesg)
}
// return pm
let res = { module:this.moduleName, pm }
Reflect.set(context,this.moduleName,res)
return next ? next(input) : input;
},
onError(error) {
console.error('出错了哦', error);
},
/** 获得板件偏移值 */
getOffDis(block: PlaceBlock, placeStyle?: PlaceStyle): any {
// console.log('获得板件偏移值')
if (placeStyle == null || placeStyle == undefined) {
placeStyle = block.placeStyle
}
let expandSize: any = block.sizeExpand
let posOff = { x: 0, y: 0, left: 0, right: 0, top: 0, bottom: 0 }
if (expandSize) {
switch (placeStyle) {
case PlaceStyle.FRONT: // 正面
posOff.x = expandSize.left
posOff.y = expandSize.bottom
posOff.left = expandSize.left
posOff.right = expandSize.right
posOff.bottom = expandSize.bottom
posOff.top = expandSize.top
break
case PlaceStyle.FRONT_TURN_RIGHT: // 正面右转
posOff.x = expandSize.bottom
posOff.y = expandSize.right
posOff.left = expandSize.bottom
posOff.right = expandSize.top
posOff.bottom = expandSize.right
posOff.top = expandSize.left
break
case PlaceStyle.FRONT_TURN_BACK: // 正面后转
posOff.x = expandSize.right
posOff.y = expandSize.top
posOff.left = expandSize.right
posOff.right = expandSize.left
posOff.bottom = expandSize.top
posOff.top = expandSize.bottom
break
case PlaceStyle.FRONT_TURN_LEFT: // 正面左转
posOff.x = expandSize.top
posOff.y = expandSize.left
posOff.left = expandSize.top
posOff.right = expandSize.bottom
posOff.bottom = expandSize.left
posOff.top = expandSize.right
break
case PlaceStyle.BACK: // 反面
posOff.x = expandSize.right
posOff.y = expandSize.bottom
posOff.left = expandSize.right
posOff.right = expandSize.left
posOff.bottom = expandSize.bottom
posOff.top = expandSize.top
break
case PlaceStyle.BACK_TURN_RIGHT: // 反面右转
posOff.x = expandSize.bottom
posOff.y = expandSize.left
posOff.left = expandSize.bottom
posOff.right = expandSize.top
posOff.bottom = expandSize.left
posOff.top = expandSize.right
break
case PlaceStyle.BACK_TURN_BACK: // 反面后转
posOff.x = expandSize.left
posOff.y = expandSize.top
posOff.left = expandSize.left
posOff.right = expandSize.right
posOff.bottom = expandSize.top
posOff.top = expandSize.bottom
break
case PlaceStyle.BACK_TURN_LEFT: // 反面左转
posOff.x = expandSize.top
posOff.y = expandSize.right
posOff.left = expandSize.bottom
posOff.right = expandSize.bottom
posOff.bottom = expandSize.right
posOff.top = expandSize.left
break
default:
break
}
}
return posOff
},
/**翻转 */
turnPlacePosition(pb: PlaceBoard, newlocator: BoardPosition) {
if (this.placeOriginByBoardLocation == false)
return
if (pb.isAdnormal())
return // 余料板是余料板,不参与翻转
let width = pb.width
let length = pb.length
// RIGHT_BOTTOM, 靠板
if (newlocator == BoardPosition.RIGHT_BOTTOM) {
for (let block of pb.blockList) {
let x = width - block.placeX - block.placeWidth
let y = block.placeY
let placeStyle = this.getPlaceStyle_zy(block)
block.placeX = x
block.placeY = y
block.placeStyle = placeStyle
}
}
// RIGHT_TOP, 靠板
if (newlocator == BoardPosition.RIGHT_TOP) {
console.log('BoardPosition=BoardPosition.RIGHT_TOP')
for (let block of pb.blockList) {
let x = width - block.placeX - block.placeWidth
let y = length - block.placeLength - block.placeY
let placeStyle = this.getPlaceStyle_dj(block)
block.placeX = x
block.placeY = y
block.placeStyle = placeStyle
}
}
// 左上角, 靠板
if (newlocator == BoardPosition.LEFT_TOP) {
console.log('BoardPosition=BoardPosition.左上角')
for (let block of pb.blockList) {
let x = block.placeX
let y = length - block.placeLength - block.placeY
let placeStyle = this.getPlaceStyle_sx(block)
block.placeX = x
block.placeY = y
block.placeStyle = placeStyle
}
}
},
/** 板放置后重置placeWidth, placeLength, 封边, 正反面, 面孔, 造型等 */
resetPlaceStyle(_block: PlaceBlock, newStyle: PlaceStyle) {
let block = new PlaceBlock(_block)
block = { ..._block }
// console.debug('resetPlaceStyle test!!!',newStyle)
block.placeStyle = newStyle
// tryFix
let _width = block.cutWidth
let _lenth = block.cutLength
if (block.width > block.length) {
block.cutWidth = Math.max(_width, _lenth)
block.cutLength = Math.min(_width, _lenth)
} else {
block.cutWidth = Math.min(_width, _lenth)
block.cutLength = Math.max(_width, _lenth)
}
switch (newStyle) {
case PlaceStyle.FRONT: // 正面
block.placeWidth = block.cutWidth
block.placeLength = block.cutLength
block.placeSealLeft = block.sealLeft
block.placeSealRight = block.sealRight
block.placeSealTop = block.sealTop
block.placeSealBottom = block.sealBottom
block.holeCountSideLeft = block?.blockDetail?.holeCountLeft || 0
block.holeCountSideRight = block?.blockDetail?.holeCountRight || 0
block.holeCountSideTop = block?.blockDetail?.holeCountTop || 0
block.holeCountSideBottom = block?.blockDetail?.holeCountBottom || 0
block.placeDirection = '→'
block.placeDirection_Length = block.length > block.width - 0.001 ? '→' : '↓'
break
case PlaceStyle.FRONT_TURN_RIGHT: // 正面右转
block.placeWidth = block.cutLength
block.placeLength = block.cutWidth
block.placeSealLeft = block.sealBottom
block.placeSealRight = block.sealTop
block.placeSealTop = block.sealLeft
block.placeSealBottom = block.sealRight
block.holeCountSideLeft = block?.blockDetail?.holeCountBottom || 0
block.holeCountSideRight = block?.blockDetail?.holeCountTop || 0
block.holeCountSideTop = block?.blockDetail?.holeCountLeft || 0
block.holeCountSideBottom = block?.blockDetail?.holeCountRight || 0
block.placeDirection = '↓'
block.placeDirection_Length = block.length > block.width - 0.001 ? '↓' : '←'
break
case PlaceStyle.FRONT_TURN_BACK: // 正面后转
block.placeWidth = block.cutWidth
block.placeLength = block.cutLength
block.placeSealLeft = block.sealRight
block.placeSealRight = block.sealLeft
block.placeSealTop = block.sealBottom
block.placeSealBottom = block.sealTop
block.holeCountSideLeft = block?.blockDetail?.holeCountRight || 0
block.holeCountSideRight = block?.blockDetail?.holeCountLeft || 0
block.holeCountSideTop = block?.blockDetail?.holeCountBottom || 0
block.holeCountSideBottom = block?.blockDetail?.holeCountTop || 0
block.placeDirection = '←'
block.placeDirection_Length = block.length > block.width - 0.001 ? '←' : '↑'
break
case PlaceStyle.FRONT_TURN_LEFT: // 正面左转
block.placeWidth = block.cutLength
block.placeLength = block.cutWidth
block.placeSealLeft = block.sealTop
block.placeSealRight = block.sealBottom
block.placeSealTop = block.sealRight
block.placeSealBottom = block.sealLeft
block.holeCountSideLeft = block?.blockDetail?.holeCountTop || 0
block.holeCountSideRight = block?.blockDetail?.holeCountBottom || 0
block.holeCountSideTop = block?.blockDetail?.holeCountRight || 0
block.holeCountSideBottom = block?.blockDetail?.holeCountLeft || 0
block.placeDirection = '↑'
block.placeDirection_Length = block.length > block.width - 0.001 ? '↑' : '→'
break
case PlaceStyle.BACK: // 反面
block.placeWidth = block.cutWidth
block.placeLength = block.cutLength
block.placeSealLeft = block.sealRight
block.placeSealRight = block.sealLeft
block.placeSealTop = block.sealTop
block.placeSealBottom = block.sealBottom
block.holeCountSideLeft = block?.blockDetail?.holeCountRight || 0
block.holeCountSideRight = block?.blockDetail?.holeCountLeft || 0
block.holeCountSideTop = block?.blockDetail?.holeCountTop || 0
block.holeCountSideBottom = block?.blockDetail?.holeCountBottom || 0
block.placeDirection = '→'
block.placeDirection_Length = block.length > block.width - 0.001 ? '→' : '↑'
break
case PlaceStyle.BACK_TURN_RIGHT: // 反面右转
block.placeWidth = block.cutLength
block.placeLength = block.cutWidth
block.placeSealLeft = block.sealBottom
block.placeSealRight = block.sealTop
block.placeSealTop = block.sealRight
block.placeSealBottom = block.sealLeft
block.holeCountSideLeft = block?.blockDetail?.holeCountBottom || 0
block.holeCountSideRight = block?.blockDetail?.holeCountTop || 0
block.holeCountSideTop = block?.blockDetail?.holeCountRight || 0
block.holeCountSideBottom = block?.blockDetail?.holeCountLeft || 0
block.placeDirection = '↓'
block.placeDirection_Length = block.length > block.width - 0.001 ? '↓' : '→'
break
case PlaceStyle.BACK_TURN_BACK: // 反面后转
block.placeWidth = block.cutWidth
block.placeLength = block.cutLength
block.placeSealLeft = block.sealLeft
block.placeSealRight = block.sealRight
block.placeSealTop = block.sealTop
block.placeSealBottom = block.sealBottom
block.holeCountSideLeft = block?.blockDetail?.holeCountLeft || 0
block.holeCountSideRight = block?.blockDetail?.holeCountRight || 0
block.holeCountSideTop = block?.blockDetail?.holeCountTop || 0
block.holeCountSideBottom = block?.blockDetail?.holeCountBottom || 0
block.placeDirection = '←'
block.placeDirection_Length = block.length > block.width - 0.001 ? '←' : '↓'
break
case PlaceStyle.BACK_TURN_LEFT: // 反面左转
block.placeWidth = block.cutLength
block.placeLength = block.cutWidth
block.placeSealLeft = block.sealTop
block.placeSealRight = block.sealBottom
block.placeSealTop = block.sealLeft
block.placeSealBottom = block.sealRight
block.holeCountSideLeft = block?.blockDetail?.holeCountTop || 0
block.holeCountSideRight = block?.blockDetail?.holeCountBottom || 0
block.holeCountSideTop = block?.blockDetail?.holeCountLeft || 0
block.holeCountSideBottom = block?.blockDetail?.holeCountRight || 0
block.placeDirection = '↑'
block.placeDirection_Length = block.length > block.width - 0.001 ? '↑' : '←'
break
default:
break
}
this.resetDoFace_HoleModel(block)
},
resetDoFace_HoleModel(block: PlaceBlock) {
let isTurnOver = block.isTurnOver
if (block.blockDetail == null) {
console.error('resetDoFace_HoleModel error,with out blockDetail');
return
}
let orgMA = block.blockDetail.modelListFaceA
let orgMB = block.blockDetail.modelListFaceB
let orgMT = block.blockDetail.modelListThrough
let orgHA = block.blockDetail.holeListFaceA
let orgHB = block.blockDetail.holeListFaceB
let orgHT = block.blockDetail.holeListThrough
if (isTurnOver) {
block.modelListFaceA = orgMB.concat(orgMT);
block.modelListFaceB = orgMA;
block.holeListFaceA = orgHB.concat(orgHT);
block.holeListFaceB = orgHA;
}
else {
block.modelListFaceA = orgMA.concat(orgMT);
block.modelListFaceB = orgMB;
block.holeListFaceA = orgHA.concat(orgHT);;
block.holeListFaceB = orgHB;
}
//获取贴标位置
let p = this.getPlaceXYInBlock(block, block.blockDetail.labelPosX, block.blockDetail.labelPosY, false, false);
block.labelPosX = p.x;
block.labelPosY = p.y;
},
getPlaceXYInBlock(block: PlaceBlock, x: number, y: number, isSealed: boolean, isFaceB = false, preCutValueOff = null): Point {
let bwidth = block.cutWidth
let blength = block.cutLength
let x0: any = x
let y0: any = y
if (isSealed) // 已封边
{
bwidth = block.width
blength = block.length
x0 += block.offsetX
y0 += block.offsetY
}
if (!isSealed && preCutValueOff) // 没封边,且有封边
{
bwidth += preCutValueOff.w
blength += preCutValueOff.l
x0 += preCutValueOff.x
y0 += preCutValueOff.y
}
let _point: any = this.getPlacedPostionInBlock(block.placeStyle, bwidth, blength, x0, y0, isFaceB)
return _point
},
/** 获得翻转后的新坐标 */
getPlacedPostionInBlock(placeStyle: PlaceStyle, bwidth: number, blength: number, x0: number, y0: number, isFaceB: boolean): Point {
let posX = x0
let posY = y0
let placeWidth = bwidth
switch (placeStyle) {
case PlaceStyle.FRONT:
break
case PlaceStyle.FRONT_TURN_RIGHT:
posX = y0
posY = bwidth - x0
placeWidth = blength
break
case PlaceStyle.FRONT_TURN_BACK:
posX = bwidth - x0
posY = blength - y0
break
case PlaceStyle.FRONT_TURN_LEFT:
posX = blength - y0
posY = x0
placeWidth = blength
break
case PlaceStyle.BACK:
posX = bwidth - x0
posY = y0
break
case PlaceStyle.BACK_TURN_RIGHT:
posX = y0
posY = x0
placeWidth = blength
break
case PlaceStyle.BACK_TURN_BACK:
posX = x0
posY = blength - y0
break
case PlaceStyle.BACK_TURN_LEFT:
posX = blength - y0
posY = bwidth - x0
placeWidth = blength
break
default:
break
}
if (isFaceB) {
posX = placeWidth - posX
}
return new Point(posX, posY)
}
}

View File

@@ -0,0 +1,83 @@
import { Processor, ProcessorModule } from "../../src/device";
import { ErrorInfo } from "../../src/device";
import { FaceType, PlaceBlockDetail } from "../confClass";
// import { PolylineHelper } from "../handleAbility/common/LayoutEngine/PolylineHelper";
// import {PolylineHelper} from "../handleAbility/common/LayoutEngine/PolylineHelper.js"
/** 模块 造型轮廓(含封边),扣除封边, 变成开料坐标
* 有异常 要调整
* input 入参
*/
export const Init2VModel: ProcessorModule<any, any> = {
moduleName: "Init2VModel",
moduleVersion: '20250714',
config: {
},
setConfig(config) {
this.config = { ...this.config, ...config };
},
// 会在处理器自动执行
/**
*
* @param input 输入数据
* @param next 下一个流程的函数
* @param context 上下文
* @returns
*/
process(input, next, context) {
const { blockDetailList } = input
for (const bd of blockDetailList) {
init2VModel(bd);
}
function init2VModel(blockDetail: PlaceBlockDetail, isCNC = false) {
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 : this.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
}
}
return next ? next(input) : input;
},
onError(error) {
console.error('出错了哦', error);
}
};

View File

@@ -0,0 +1,66 @@
import { Processor, ProcessorModule } from "../../src/device";
import { ErrorInfo } from "../../src/device";
import { PlaceBlockDetail } from "../confClass";
/** 模块 造型轮廓(含封边),扣除封边, 变成开料坐标
* !!!!!!!!! 有异常 要调整
* input 入参
*/
export const ResetModelContour: ProcessorModule<any, any> = {
moduleName: "ResetModelContour",
moduleVersion: '20250714',
config: {
},
setConfig(config) {
this.config = { ...this.config, ...config };
},
// 会在处理器自动执行
/**
*
* @param input 输入数据
* @param next 下一个流程的函数
* @param context 上下文
* @returns
*/
process(input, next, context) {
const { blockDetailList } = input
for (const bd of blockDetailList) {
let blockDetail = new PlaceBlockDetail(bd);
resetModelContour(blockDetail);
}
/** 造型轮廓(含封边),扣除封边, 变成开料坐标 */
function resetModelContour(bd: PlaceBlockDetail) {
let ox = bd.offsetX
let oy = bd.offsetY
for (let m of bd.models) {
if (m.hasContour()) {
let ptsArr = m.originModeling.outline.map(e => e.pts)
for (let pt of ptsArr) {
// 23.8.5 发现矩形的挖穿轮廓坐标是不含封边的
pt.x -= ox
pt.y -= oy
}
}
}
}
return next ? next(input) : input;
},
onError(error) {
console.error('出错了哦', error);
}
};

View File

@@ -0,0 +1,93 @@
import { Processor, ProcessorModule } from "../../src/device";
import { confItem, Knife, PlaceBlock, PlaceBlockDetail, PlaceMaterial, _knifeType } from "../confClass";
import { Big_bang, ComposingType, LineType, WorkerItemType, xbang } from "../handleAbility/RectOptimizeWorker/bang";
/** 模块 刀库
*
* input 入参
*/
/** 优化前的 刀库 */
export const ToolsModule: ProcessorModule<any, any> = {
moduleName: "RectOptimizeMachine",
moduleVersion: '20250714',
config: {
knifeList: [],
},
setConfig(config) {
this.config = { ...this.config, ...config };
},
// 会在处理器自动执行
/**
*
* @param input 输入数据
* @param next 下一个流程的函数
* @param context 上下文
* @returns
*/
process(input, next, context) {
// 将刀库添加到上下文
Reflect.set(context, 'knifeList', this.config.knifeList)
// 将刀具查询方法加到上下文
Reflect.set(context, 'getKnifeByParams', getKnifeByParams)
/** 通用 找刀具 根据查询条件 */
function getKnifeByParams(params: _knifeType, knifeList: Knife[]) {
let knife: Knife | null = null
if (params) {
let tempKnifeList: Knife[] = [...knifeList] // []
let keys = Object.keys(params)
if (keys.length > 0) {
keys.forEach(key => {
if (Array.isArray(params[key]) && key == 'ability') {
// 进来的应该是ability 是数组 判断刀的能力
for (const arrItem of params[key]) {
let _knifeList = knifeList.filter(e => e.ability.includes(arrItem))
_knifeList.forEach(k => {
if (!this.KnifeIsInKnifeList(k, tempKnifeList)) {
tempKnifeList.push(k)
}
})
}
} else if (['string', 'number'].includes(typeof (params[key]))) {
if (params && params[key] && typeof (params[key]) == 'number') {
if (key == 'length') {
tempKnifeList = tempKnifeList.filter(e => e[key] >= params[key])
} else {
tempKnifeList = tempKnifeList.filter(e => e[key] == params[key])
}
}
}
});
if (tempKnifeList.length > 0) {
knife = tempKnifeList[0]
}
} else {
console.log('传入的查询条件 没有参数')
}
}
return knife
}
return next ? next(input) : input;
},
onError(error) {
console.log('出错了哦', error);
}
};

View File

@@ -42,14 +42,6 @@
"y": 1091.42,
"pbg": 106.01,
"pbk": 171.01
},
{
"bangid": "25044454404",
"line": 0,
"x": 1032.03,
"y": 1197.43,
"pbg": 105.01,
"pbk": 171.01
}
]
],

View File

@@ -1,8 +1,9 @@
import { error } from "console";
// 回调函数类型定义
type ProcessCallback<T, R> = (
input: T,
next: (input: T) => R | Promise<R>,
next?: (input: T) => R | Promise<R>,
context?: any
) => R | Promise<R>;
@@ -11,36 +12,92 @@ type ProcessCallback<T, R> = (
type ModuleConfig = Record<string, any>;
// 回调函数类型
type ModuleCallback<T, R> = (result: R, input?: T) => void | Promise<void>;
type ModuleCallback<T, R> = (result: R, input?: T,context?:any) => void | Promise<void>;
export interface ErrorInfo {
moduleName?: string
moduleVersion?: string
info?: any
}
export class ProcessorManager<T, R> implements ProcessorCollection<T, R> {
private processors = new Map<string, Processor<T, R>>();
private currentProcessor?: Processor<T, R>;
constructor() {
}
/** 注册模块流程 */
registerProcessor(name: string, processor: Processor<T, R>): this {
this.processors.set(name, processor);
return this;
}
/** 使用处理器 */
useProcessor(name: string): Processor<T, R> {
const processor = this.processors.get(name);
if (!processor) {
throw new Error(`Processor ${name} not found`);
}
this.currentProcessor = processor;
return processor;
}
/** 获取处理器 */
getProcessor(name: string): Processor<T, R> | undefined {
return this.processors.get(name);
}
/** 获取正在使用的处理器 */
getCurrentProcessor(): Processor<T, R> | undefined {
return this.currentProcessor;
}
}
// 扩展后的功能模块接口
export interface ProcessorModule<T, R> {
export interface ProcessorModuleBase<T, R> {
// 主处理函数(可回调)
process?: ProcessCallback<T, R>;
// 直接是处理函数(无回调)
handle?: (input: T, next?: (input: T) => R | Promise<R>, context?: Record<string, any>) => R | Promise<R>;
// // 直接是处理函数(无回调)
// handle?: (input: T, next?: (input: T) => R | Promise<R>, context?: Record<string, any>) => R | Promise<R>;
// 模块名称(用于标识和排序)
moduleName?: string;
/** 模块版本号 */
moduleVersion?: string
// 模块配置
config?: ModuleConfig;
getConfigList?: () => ModuleConfig
// // 多线程列表
// workerList?: any[]
// 获取配置列表
getConfigList?: () => any[]
// 设置配置的方法
setConfig?: (config: ModuleConfig) => void;
// 前置回调(在模块处理前执行)
before?: ModuleCallback<T, R>;
// // 前置回调(在模块处理前执行)
// before?: ModuleCallback<T, R>;
// 后置回调(在模块处理后执行)
after?: ModuleCallback<T, R>;
// // 后置回调(在模块处理后执行)
// after?: ModuleCallback<T, R>;
// 错误处理回调
onError?: (error: unknown, input?: T) => void | Promise<void>;
// 消息传递 模块将数据传给处理器
onMessage?: Function//(data:unknown) => void | Promise<void>;
[key: string]:any
}
/** 支持自定义函数 */
export interface ProcessorModuleExtensions {
/** 允许在模块内添加自定义函数 和属性 */
[key: string]: ((...args: any[]) => any) | undefined;
}
export interface strictModuleExtensions {
}
export type ProcessorModule<T, R> = ProcessorModuleBase<T, R> // & ProcessorModuleExtensions;
export interface Processor<T, R> {
// 注册模块
use(module: ProcessorModule<T, R> | ProcessorModule<T, R>[]): this;
@@ -55,7 +112,18 @@ export interface Processor<T, R> {
getModules(): ProcessorModule<T, R>[];
// 新增方法:更新模块配置
updateModuleConfig(moduleName: string, config: ModuleConfig): this;
updateModuleConfig(config: ModuleConfig): this;
/**
获取模块的配置项
*/
getModuleConfig(): ModuleConfig
/**
* 获取模块配置列表
*/
getModuleConfigList(): any[]
//
//
}
// 处理器集合接口
@@ -78,13 +146,14 @@ export interface ProcessorCollection<T, R> {
export class StepControllerProcessor<T, R> implements Processor<T, R> {
private modules: ProcessorModule<T, R>[] = [];
private modulesMap = new Map<string, ProcessorModule<T, R>>();
private onMessageFunction: Function = () => { }
use(module: ProcessorModule<T, R> | ProcessorModule<T, R>[]): this {
const modules = Array.isArray(module) ? module : [module];
modules.forEach(m => {
if (m.moduleName) {
this.modulesMap.set(m.moduleName, m);
m.onMessage = this.onMessageFunction
}
this.modules.push(m);
});
@@ -104,16 +173,94 @@ export class StepControllerProcessor<T, R> implements Processor<T, R> {
this.modules = [...orderedModules, ...remainingModules];
return this;
}
/** 更新处理器 内的模块的配置 */
updateModuleConfig(config: ModuleConfig): this {
// const module = this.modulesMap.get(moduleName)
let log = []
for (const m of this.modules) {
if (m.config != undefined) {
let conArr = Object.keys(m.config)
let m_config = {}
for (const keyStr of conArr) {
if (Reflect.has(config, keyStr)) {
// m.config[keyStr] = config[keyStr]
Reflect.set(m_config, keyStr, config[keyStr])
} else {
let noConfigInfo = {
moduleName: m.moduleName,
configKey: keyStr,
info: '没有配置参数!'
}
log.push(noConfigInfo)
}
}
if (m?.setConfig) {
m?.setConfig(m_config)
} else {
let noConfigInfo = {
moduleName: m.moduleName,
configKey: '',
info: '模块设置了【config】,却没有设置【setConfig】'
}
log.push(noConfigInfo)
}
updateModuleConfig(moduleName: string, config: ModuleConfig): this {
const module = this.modulesMap.get(moduleName);
if (module && module.setConfig) {
module.setConfig(config);
} else if (module) {
module.config = { ...module.config, ...config };
}
}
if (log.length > 0) {
let str = log.map(e => {
let s = '模块:' + e.moduleName
if (e.configKey) {
s = s + '-' + e.configKey
}
s = s + ',' + e.info + ';'
return s
})
console.warn('加载配置异常:', str)
}
return this;
}
getModuleConfig(): ModuleConfig {
let config:ModuleConfig = {}
for (const m of this.modules) {
config = {...config,...m.config}
}
return config
}
getModuleConfigList(){
//#region 方式1
let configList:any[] = []
let config:ModuleConfig = {}
for (const m of this.modules) {
config = {...config,...m.config}
// let keys = Object.keys(m.config)
}
let keys = Object.keys(config)
for (const key of keys) {
let temp= {
key: key,
value: config[key]
}
configList.push(temp)
}
//#endregion
//#region 方式二
let configList1:any[] = []
for (const m of this.modules) {
if(Reflect.has(m,'getConfigList')){
let m_configList = m.getConfigList() || []
configList1 = [...configList1,...m_configList]
}
}
//#endregion
return configList
}
private async executeModule(
module: ProcessorModule<T, R>,
@@ -145,7 +292,7 @@ export class StepControllerProcessor<T, R> implements Processor<T, R> {
// 执行后置回调
if (module.after) {
await module.after(result, input);
await module.after(result, input,context);
}
return result;
@@ -159,18 +306,26 @@ export class StepControllerProcessor<T, R> implements Processor<T, R> {
throw error;
}
}
async process(input: T): Promise<R> {
private async executeModuleByModuleName(moduleName:string,input){
let module =this.modulesMap.get(moduleName)
return module.process(input)
}
async process(input: T,_context?:Record<string, any>): Promise<R> {
if (this.modules.length === 0) {
throw new Error("No modules registered");
}
let currentIndex = 0;
const modules = this.modules;
const context: Record<string, any> = {};
const context: Record<string, any> = {..._context};
const executeNext = async (currentInput: T): Promise<R> => {
const currentModule = modules[currentIndex++];
if (!currentModule) {
console.log('执行结束,上下文',context);
return currentInput as unknown as R;
}
@@ -185,64 +340,14 @@ export class StepControllerProcessor<T, R> implements Processor<T, R> {
return executeNext(input);
}
// async process(input: T): Promise<R> {
// if (this.modules.length === 0) {
// throw new Error("No modules registered");
// }
// let currentIndex = 0;
// const modules = this.modules;
// const context: Record<string, any> = {}; // 共享上下文
// const executeNext = async (currentInput: T): Promise<R> => {
// const currentModule = modules[currentIndex++];
// if (!currentModule) {
// return currentInput as unknown as R;
// }
// try {
// // 执行前置回调
// if (currentModule.before) {
// await currentModule.before(currentInput, currentInput);
// }
// // 执行主处理函数
// const next = async (nextInput: T): Promise<R> => {
// return executeNext(nextInput);
// };
// let result: R;
// const processResult = currentModule.process(currentInput, next, context);
// if (processResult instanceof Promise) {
// result = await processResult;
// } else {
// result = processResult;
// }
// // 执行后置回调
// if (currentModule.after) {
// await currentModule.after(result, currentInput);
// }
// return result;
// } catch (error) {
// // 执行错误处理
// if (currentModule.onError) {
// await currentModule.onError(error, currentInput);
// } else {
// throw error; // 如果没有错误处理,则向上抛出
// }
// // 根据错误处理结果决定是否继续
// return currentInput as unknown as R;
// }
// };
// return executeNext(input);
// }
getModules(): ProcessorModule<T, R>[] {
return [...this.modules];
}
setOnMessageFunc(func: Function) {
this.onMessageFunction = func
}
}

221
src/paser.test.ts Normal file
View File

@@ -0,0 +1,221 @@
import { describe, it, expect, test } from 'vitest';
import { DemoParser } from '../samples/demoParser';
// import { ProcessorModule, StepControllerProcessor } from '../src/device';
import { ProcessorManager, StepControllerProcessor } from '../src/device';
import { demoHandleGroupCutting } from '../samples/demoDatahandle/demoDataHandle1';
import testJson from "./test.json"
import { RectOptimizeMachineModule } from '../samples/moduleManager/module_RectOptimizeMachine';
// import { Worker, parentPort } from 'worker_threads';
// import { UniversalWorker } from '../samples/WorkerHelper';
// 在测试文件中直接使用 console.log 或 debugger 语句
test('demoParser', () => {
// expect(1 + 1).toBe(2);
const text = `FSTART
TD 5
G0 X100 Y100 Z10 F8000
g0 x100 y100 z18 f8000
g2 x120 y120 z18 R20 f8000
g3 x100 y100 z18 i20 j0 f8000
TN T2
FEND
`
const demoParser = new DemoParser();
const result = demoParser.execTest(text);
console.log(result);
});
test('dataHandle', async () => {
const sysConfig = {
placeStyle: 1,
boardWidth: 2440,
boardLength: 1220,
cutBoardBorder:3,
cutKnifeGap:1,
isDoubleFaceBlockFirst:true,
// 测试刀库数据
knifeList: [knifeData, knifeData1, knifeData2]
}
const json = testJson
// 创建处理器集合
const processorManager = new ProcessorManager<any, any>();
// 这里省略了 选择处理器的环节 --这里选了demo开料机
const cuttingHandle = new demoHandleGroupCutting()
// 注册处理器
processorManager.registerProcessor(cuttingHandle.processorName, cuttingHandle.processor)
// 使用XX处理器 会返回激活【正在使用】的 处理器
let processor = processorManager.useProcessor(cuttingHandle.processorName)
// 或者 这样 获取 正在使用的处理器 注若未执行useProcessor 将会返回 undefind
// processor = processorManager.getCurrentProcessor()
/** 处理器配置加载 */
processor.updateModuleConfig(sysConfig)
// 方式1
const res = await processor.process(json)
console.log('处理器所有流程都结束了', res);
})
test('Module Test',async()=>{
//测试 模块
// 配置项
const sysConfig = {
placeStyle: 1,
boardWidth: 2440,
boardLength: 1220,
// 测试刀库数据
knifeList: [knifeData, knifeData1, knifeData2]
}
// 测试数据
const json = testJson
// 处理器集合 的管理器
const processorManager = new ProcessorManager<any, any>();
// 处理器的管理器
const stepManager = new StepControllerProcessor<any, any>();
// 处理器 要调用的模块 可设置多个
stepManager.use([RectOptimizeMachineModule])
stepManager.setOnMessageFunc(callBack)
function callBack(data){
console.log('数据回调,这里测试优化',)
}
//
let processName = 'testRectOptimize'
processorManager.registerProcessor(processName,stepManager)
processorManager.useProcessor(processName,)
})
/** demo 刀具数据 */
export const knifeData = {
"isEnabled": true,
"axleId": 2,
"knifeId": 2,
"processFace": "",
"knifeName": "T1",
"knifeType": 3,
"ability": [
5
],
"diameter": 5,
"length": 20,
"sawThiness": 7,
"sawDirection": 2,
"processDirection": 4,
"speed": 0,
"stepDepth": 0,
"offsetX": 0,
"offsetY": 0,
"offsetZ": 0,
"baseX": 0,
"baseY": 0,
"isModularDrill": false,
"isPreStartEnabled": false,
"preStartAheadActionCount": 5,
"isPreStartToolChangeDelay": false,
"preStartToolChangeDelayCode": "",
"isAxisStartCodePostpost": false,
"isAxisStopCodePrepose": false,
"drillGroupCode": "",
"axisStartCode": "M03 S18000\n",
"knifeStartCode": `M06 T1\nG43 H1\n`,
"drillGroupStartCode": "T1",
"drillGroupEndCode": "",
"knifeStopCode": "",
"axisStopCode": "M05\n",
"preStartActionDeferCode": "",
"useHolesGroupKnife": false,
"preStartActionStepsLimit": "",
"knifeNo": "",
"editable": true,
"isDefaultCutKnife": false,
"isPreStartChangeKnifeDefer": false
}
export const knifeData1 = {
"isEnabled": true,
"axleId": 2,
"knifeId": 2,
"processFace": "",
"knifeName": "T2",
"knifeType": 3,
"ability": [
5
],
"diameter": 6,
"length": 20,
"sawThiness": 7,
"sawDirection": 2,
"processDirection": 4,
"speed": 0,
"stepDepth": 0,
"offsetX": 0,
"offsetY": 0,
"offsetZ": 0,
"baseX": 0,
"baseY": 0,
"isModularDrill": false,
"isPreStartEnabled": false,
"preStartAheadActionCount": 5,
"isPreStartToolChangeDelay": false,
"preStartToolChangeDelayCode": "",
"isAxisStartCodePostpost": false,
"isAxisStopCodePrepose": false,
"drillGroupCode": "",
"axisStartCode": "M03 S18000\n",
"knifeStartCode": `M06 T2\nG43 H2\n`,
"drillGroupStartCode": "T2",
"drillGroupEndCode": "",
"knifeStopCode": "",
"axisStopCode": "M05\n",
"preStartActionDeferCode": "",
"useHolesGroupKnife": false,
"preStartActionStepsLimit": "",
"knifeNo": "",
"editable": true,
"isDefaultCutKnife": false,
"isPreStartChangeKnifeDefer": false
}
export const knifeData2 = {
"isEnabled": true,
"axleId": 2,
"knifeId": 2,
"processFace": "",
"knifeName": "T3",
"knifeType": 3,
"ability": [
5
],
"diameter": 6,
"length": 20,
"sawThiness": 7,
"sawDirection": 2,
"processDirection": 4,
"speed": 0,
"stepDepth": 0,
"offsetX": 0,
"offsetY": 0,
"offsetZ": 0,
"baseX": 0,
"baseY": 0,
"isModularDrill": false,
"isPreStartEnabled": false,
"preStartAheadActionCount": 5,
"isPreStartToolChangeDelay": false,
"preStartToolChangeDelayCode": "",
"isAxisStartCodePostpost": false,
"isAxisStopCodePrepose": false,
"drillGroupCode": "",
"axisStartCode": "M03 S18000\n",
"knifeStartCode": `M06 T2\nG43 H2\n`,
"drillGroupStartCode": "T3",
"drillGroupEndCode": "",
"knifeStopCode": "",
"axisStopCode": "M05\n",
"preStartActionDeferCode": "",
"useHolesGroupKnife": false,
"preStartActionStepsLimit": "",
"knifeNo": "",
"editable": true,
"isDefaultCutKnife": false,
"isPreStartChangeKnifeDefer": false
}

29451
src/test.json Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +1,13 @@
import { test } from '@jest/globals'
import { test, it, expect } from 'vitest';
import { DemoParser } from '../samples/demoParser';
import { ProcessorModule, StepControllerProcessor } from '../src/device';
import { ProcessorManager } from '../samples/demoDataHandleServer';
import { demoHandleGroupCutting } from '../samples/demoDatahandle/demoDataHandle1';
import testJson from "./test.json"
// import { ProcessorModule, StepControllerProcessor } from '../src/device';
// import { ProcessorManager } from '../src/device';
// import { demoHandleGroupCutting } from '../samples/demoDatahandle/demoDataHandle1';
// import testJson from "./test.json"
// import { Worker, parentPort } from 'worker_threads';
// import { UniversalWorker } from '../samples/WorkerHelper';
test('demoParser', () => {
const text = `FSTART
const text = `FSTART
TD 5
G0 X100 Y100 Z10 F8000
g0 x100 y100 z18 f8000
@@ -14,26 +16,170 @@ g3 x100 y100 z18 i20 j0 f8000
TN T2
FEND
`
const demoParser = new DemoParser();
const result = demoParser.execTest(text);
console.log(result);
const demoParser = new DemoParser();
const result = demoParser.execTest(text);
console.log(result);
})
test('data', async () => {
const json = testJson
// 创建处理器集合
const processorManager = new ProcessorManager<any, any>();
// 这里省略了 选择处理器的环节 --这里选了demo开料机
const cuttingHandle = new demoHandleGroupCutting()
// 注册处理器
processorManager.registerProcessor(cuttingHandle.processorName, cuttingHandle.processor)
// 使用XX处理器 会返回激活【正在使用】的 处理器
const processor = processorManager.useProcessor(cuttingHandle.processorName)
const res = await processor.process(json)
console.log('处理器所有流程都结束了', res);
})
// describe('data', async () => {
// const sysConfig = {
// placeStyle: 1,
// boardWidth: 2440,
// boardLength: 1220,
// // 测试刀库数据
// knifeList: [knifeData, knifeData1, knifeData2]
// }
// const json = testJson
// // 创建处理器集合
// const processorManager = new ProcessorManager<any, any>();
// // 这里省略了 选择处理器的环节 --这里选了demo开料机
// const cuttingHandle = new demoHandleGroupCutting()
// // 注册处理器
// processorManager.registerProcessor(cuttingHandle.processorName, cuttingHandle.processor)
// // 使用XX处理器 会返回激活【正在使用】的 处理器
// let processor = processorManager.useProcessor(cuttingHandle.processorName)
// // 或者 这样 获取 正在使用的处理器 注若未执行useProcessor 将会返回 undefind
// // processor = processorManager.getCurrentProcessor()
// /** 处理器配置加载 */
// processor.updateModuleConfig(sysConfig)
// const res = await processor.process(json)
// // console.log('处理器所有流程都结束了', res);
// })
//
// /** demo 刀具数据 */
// export const knifeData = {
// "isEnabled": true,
// "axleId": 2,
// "knifeId": 2,
// "processFace": "",
// "knifeName": "T1",
// "knifeType": 3,
// "ability": [
// 5
// ],
// "diameter": 5,
// "length": 20,
// "sawThiness": 7,
// "sawDirection": 2,
// "processDirection": 4,
// "speed": 0,
// "stepDepth": 0,
// "offsetX": 0,
// "offsetY": 0,
// "offsetZ": 0,
// "baseX": 0,
// "baseY": 0,
// "isModularDrill": false,
// "isPreStartEnabled": false,
// "preStartAheadActionCount": 5,
// "isPreStartToolChangeDelay": false,
// "preStartToolChangeDelayCode": "",
// "isAxisStartCodePostpost": false,
// "isAxisStopCodePrepose": false,
// "drillGroupCode": "",
// "axisStartCode": "M03 S18000\n",
// "knifeStartCode": `M06 T1\nG43 H1\n`,
// "drillGroupStartCode": "T1",
// "drillGroupEndCode": "",
// "knifeStopCode": "",
// "axisStopCode": "M05\n",
// "preStartActionDeferCode": "",
// "useHolesGroupKnife": false,
// "preStartActionStepsLimit": "",
// "knifeNo": "",
// "editable": true,
// "isDefaultCutKnife": false,
// "isPreStartChangeKnifeDefer": false
// }
// export const knifeData1 = {
// "isEnabled": true,
// "axleId": 2,
// "knifeId": 2,
// "processFace": "",
// "knifeName": "T2",
// "knifeType": 3,
// "ability": [
// 5
// ],
// "diameter": 6,
// "length": 20,
// "sawThiness": 7,
// "sawDirection": 2,
// "processDirection": 4,
// "speed": 0,
// "stepDepth": 0,
// "offsetX": 0,
// "offsetY": 0,
// "offsetZ": 0,
// "baseX": 0,
// "baseY": 0,
// "isModularDrill": false,
// "isPreStartEnabled": false,
// "preStartAheadActionCount": 5,
// "isPreStartToolChangeDelay": false,
// "preStartToolChangeDelayCode": "",
// "isAxisStartCodePostpost": false,
// "isAxisStopCodePrepose": false,
// "drillGroupCode": "",
// "axisStartCode": "M03 S18000\n",
// "knifeStartCode": `M06 T2\nG43 H2\n`,
// "drillGroupStartCode": "T2",
// "drillGroupEndCode": "",
// "knifeStopCode": "",
// "axisStopCode": "M05\n",
// "preStartActionDeferCode": "",
// "useHolesGroupKnife": false,
// "preStartActionStepsLimit": "",
// "knifeNo": "",
// "editable": true,
// "isDefaultCutKnife": false,
// "isPreStartChangeKnifeDefer": false
// }
// export const knifeData2 = {
// "isEnabled": true,
// "axleId": 2,
// "knifeId": 2,
// "processFace": "",
// "knifeName": "T3",
// "knifeType": 3,
// "ability": [
// 5
// ],
// "diameter": 6,
// "length": 20,
// "sawThiness": 7,
// "sawDirection": 2,
// "processDirection": 4,
// "speed": 0,
// "stepDepth": 0,
// "offsetX": 0,
// "offsetY": 0,
// "offsetZ": 0,
// "baseX": 0,
// "baseY": 0,
// "isModularDrill": false,
// "isPreStartEnabled": false,
// "preStartAheadActionCount": 5,
// "isPreStartToolChangeDelay": false,
// "preStartToolChangeDelayCode": "",
// "isAxisStartCodePostpost": false,
// "isAxisStopCodePrepose": false,
// "drillGroupCode": "",
//
// "axisStartCode": "M03 S18000\n",
// "knifeStartCode": `M06 T2\nG43 H2\n`,
// "drillGroupStartCode": "T3",
// "drillGroupEndCode": "",
// "knifeStopCode": "",
// "axisStopCode": "M05\n",
//
// "preStartActionDeferCode": "",
// "useHolesGroupKnife": false,
// "preStartActionStepsLimit": "",
// "knifeNo": "",
// "editable": true,
// "isDefaultCutKnife": false,
// "isPreStartChangeKnifeDefer": false
// }

View File

@@ -1,28 +1,29 @@
{
"include": ["src/**/*"],
"exclude": ["node_modules","samples","tests"],
// "compilerOptions": {
// "target": "ES6",
"module": "ESNext", // 必须用 ESNext
// "esModuleInterop": true,
// "moduleResolution": "node",
// "skipLibCheck": true,
// "sourceMap": true,
// "outDir": "./dist",
// "rootDir": ".", // 改为 "." 包含所有文件
// "strict": true,
// "baseUrl": ".", // 确保路径解析正确
// "paths": {
// // 可选:自定义路径映射(如 "@/*": ["src/*"]
// }
// },
// "include": ["src/**/*", "tests/**/*"], // 包含测试文件
"compilerOptions": {
/* Visit https://aka.ms/tsconfig to read more about this file */
/* Language and Environment */
// "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
"target": "ES6",
/* Modules */
"module": "commonjs", /* Specify what module code is generated. */
// "rootDir": "./", /* Specify the root folder within your source files. */
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
/* Emit */
"declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
"outDir": "./dist", /* Specify an output folder for all emitted files. */
"rootDir": "./src",
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
/* Type Checking */
"strict": true, /* Enable all strict type-checking options. */
"skipLibCheck": true, /* Skip type checking all .d.ts files. */
"sourceMap": true
}
}
"types": ["@vitest/browser/providers/playwright"],
"resolveJsonModule": true, // 允许导入 .json 文件
"esModuleInterop": true, // 确保 CommonJS/ESM 兼容
"module": "ESNext", // 推荐使用 ESM
"moduleResolution": "Node" // 确保 Node.js 模块解析
},
"exclude": [
"node_modules",
"dist"
]
}

View File

@@ -0,0 +1,11 @@
import { expect, test } from 'vitest'
import { getByText } from '@testing-library/dom'
import HelloWorld from './HelloWorld.js'
test('renders name', () => {
const parent = HelloWorld({ name: 'Vitest' })
document.body.appendChild(parent)
const element = getByText(parent, 'Hello Vitest!')
expect(element).toBeInTheDocument()
})

View File

@@ -0,0 +1,9 @@
export default function HelloWorld({ name }: { name: string }): HTMLDivElement {
const parent = document.createElement('div')
const h1 = document.createElement('h1')
h1.textContent = 'Hello ' + name + '!'
parent.appendChild(h1)
return parent
}

14
vitest.config.ts Normal file
View File

@@ -0,0 +1,14 @@
import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
browser: {
enabled: true,
provider: 'playwright',
// https://vitest.dev/guide/browser/playwright
instances: [
{ browser: 'chromium' },
],
},
},
})