提交:1、导XML格式的CNC 2、NCwriter功能填充
This commit is contained in:
		
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					mes-processors-libs-*.tgz
 | 
				
			||||||
 | 
					node_modules
 | 
				
			||||||
 | 
					dist/*
 | 
				
			||||||
							
								
								
									
										111
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,111 @@
 | 
				
			|||||||
 | 
					# @mes-processors/libs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					这是一个用于处理MES(制造执行系统)相关工作流的处理器类库。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 安装
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					在内网环境下执行以下脚本进行安装
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```sh
 | 
				
			||||||
 | 
					pnpm add http://gitea.cf/MES-FE/mes-packages/releases/download/0.1/mes-processors-libs-0.1.0.tgz
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> [!CAUTION]
 | 
				
			||||||
 | 
					> 在安装库之前,请确认以下信息:  
 | 
				
			||||||
 | 
					>
 | 
				
			||||||
 | 
					> - 该库发布于内网gitea仓库的release中,所以你需要提前在gitea中进行登录,并确保你有该仓库的访问权限。  
 | 
				
			||||||
 | 
					> - 库的版本需要手动进行控制,注意上述链接中的版本信息,在安装前需要主动修改版本号,请前往<http://gitea.cf/MES-FE/mes-packages/releases>来确认最新版本。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 使用
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					该库提供了MES/iMES公用的处理器,并已配置为导出项,请参考以下Typescript代码进行使用:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```ts
 | 
				
			||||||
 | 
					// 引入矩形优化处理器
 | 
				
			||||||
 | 
					import { RectLayoutProcConfig } from 'cut-abstractions';
 | 
				
			||||||
 | 
					import { RectLayoutProc } from '@mes-processors/libs';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 实例化处理器
 | 
				
			||||||
 | 
					const proc = new RectLayoutProc();
 | 
				
			||||||
 | 
					// 构建上下文f proc.exec>[0] = {
 | 
				
			||||||
 | 
					    input: testObj,
 | 
				
			||||||
 | 
					    params: new RectLayoutProcConfig()
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					// 异步执行
 | 
				
			||||||
 | 
					const ctx: Parameters<typeo
 | 
				
			||||||
 | 
					await proc.exec(ctx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 从上下文对象中获取输出内容
 | 
				
			||||||
 | 
					console.log("RESULT: ", ctx.output);
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Q&A
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 运行某些处理器时出现404(Not Found)错误
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**错误描述**  
 | 
				
			||||||
 | 
					当执行处理器时,出现类似下面的错误:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```log
 | 
				
			||||||
 | 
					GET http://localhost:5173/node_modules/.vite/deps/assets/RectOptimizeMachine.worker-BO2fmpVH.js 404 (Not Found)
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**根本原因**  
 | 
				
			||||||
 | 
					该库中某些处理器使用了Web Worker来实现多线程异步处理(例如矩形优化处理器)。  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Web Worker为单独打包的资产文件,但某些打包工具可能会对`node_modules`中的依赖进行预构建来提高性能,如果Worker文件被视为了预构建的一部分,就可能导致处理器无法正确地处理Worker文件的相对引用路径,导致在运行时尝试从`node_modules/.vite/deps/assets/`这样的内部路径加载,而这个路径在实际部署或服务时是不存在的。  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**解决方法**  
 | 
				
			||||||
 | 
					在打包工具中对该库进行配置,禁用对该库的优化和预构建,以`vite`为例:
 | 
				
			||||||
 | 
					```ts
 | 
				
			||||||
 | 
					// vite.config.ts
 | 
				
			||||||
 | 
					...
 | 
				
			||||||
 | 
					optimizeDeps: {
 | 
				
			||||||
 | 
					    exclude: ["@mes-processors/libs"] // 从optimizeDeps中排除该库
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					...
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 开发
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 发布并打包项目
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```sh
 | 
				
			||||||
 | 
					pnpm build
 | 
				
			||||||
 | 
					pnpm pack
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> [!NOTE]
 | 
				
			||||||
 | 
					> 发布前记得更改版本号
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 约定
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**目录**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					src
 | 
				
			||||||
 | 
					├── modules         项目模块分组
 | 
				
			||||||
 | 
					├── processors      处理器
 | 
				
			||||||
 | 
					└── utils           公用的工具类
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**导出和打包**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- 编写的处理器请在`src/index.ts`中进行导出
 | 
				
			||||||
 | 
					- 编写的工具类请在`src/utils/index.ts`中进行导出
 | 
				
			||||||
 | 
					- 在打包时项目仅会对`src/index.ts`进行打包,工具类相关模块不会进行打包
 | 
				
			||||||
 | 
					- 关于打包相关明细请自行查看相关文件
 | 
				
			||||||
 | 
					  - [package.json](package.json) 
 | 
				
			||||||
 | 
					  - [vite.config.ts](vite.config.ts)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> [!WARNING]
 | 
				
			||||||
 | 
					> 在该工作区中编写模块时,禁止使用绝对路径进行导入,禁止在`tsconfig.json`或`vite.config.ts`中添加"@"别名,所有导入语句请使用相对路径进行引入,否则会因monorepo内部导入混乱导致模块解析失败。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 测试
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					项目使用[Vitest](http://vitest.dev/)作为单元测试框架,若要对TS文件编写单元测试,请在文件的同目录下创建`<文件名>.test.ts`文件,并遵循Vitest规范编写单元测试。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					要执行单元测试,请运行下面的命令:
 | 
				
			||||||
 | 
					```sh
 | 
				
			||||||
 | 
					pnpm test
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
							
								
								
									
										39
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "name": "@mes-process-code-converter/libs",
 | 
				
			||||||
 | 
					  "version": "0.1.4",
 | 
				
			||||||
 | 
					  "description": "",
 | 
				
			||||||
 | 
					  "type": "module",
 | 
				
			||||||
 | 
					  "scripts": {
 | 
				
			||||||
 | 
					    "build": "vite build",
 | 
				
			||||||
 | 
					    "test": "vitest",
 | 
				
			||||||
 | 
					    "check": "tsc --noEmit --skipLibCheck -p tsconfig.app.json"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "files": [
 | 
				
			||||||
 | 
					    "dist",
 | 
				
			||||||
 | 
					    "package.json",
 | 
				
			||||||
 | 
					    "src",
 | 
				
			||||||
 | 
					    "tsconfig.json",
 | 
				
			||||||
 | 
					    "tsconfig.app.json",
 | 
				
			||||||
 | 
					    "tsconfig.node.json"
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					  "exports": {
 | 
				
			||||||
 | 
					    ".": "./src/index.ts",
 | 
				
			||||||
 | 
					    "./utils": "./src/utils/index.ts"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "dependencies": {
 | 
				
			||||||
 | 
					    "cut-abstractions": "http://gitea.cf/MES-FE/cut-abstractions/releases/download/0.3/cut-abstractions-0.3.3.tgz",
 | 
				
			||||||
 | 
					    "mes-processors":"http://gitea.cf/MES-FE/mes-packages/releases/download/0.2/mes-processors-libs-0.2.1.tgz"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "devDependencies": {
 | 
				
			||||||
 | 
					    "@types/node": "^24.0.10",
 | 
				
			||||||
 | 
					    "typescript": "~5.8.3",
 | 
				
			||||||
 | 
					    "vite": "^7.0.0",
 | 
				
			||||||
 | 
					    "vite-plugin-dts": "^4.5.4",
 | 
				
			||||||
 | 
					    "vite-plugin-node-polyfills": "^0.24.0",
 | 
				
			||||||
 | 
					    "vite-plugin-resolve": "^2.5.2",
 | 
				
			||||||
 | 
					    "vitest": "^3.2.4"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "keywords": [],
 | 
				
			||||||
 | 
					  "author": "",
 | 
				
			||||||
 | 
					  "license": "ISC"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										2471
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										2471
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										68
									
								
								src/cncTest.test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								src/cncTest.test.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,68 @@
 | 
				
			|||||||
 | 
					import { test } from "vitest";
 | 
				
			||||||
 | 
					import { CncConverter, CncTemplateParams, TemplateEndTargetType } from "./processors/CncConverter/CncConverter";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test('cncTest', async () => {
 | 
				
			||||||
 | 
					    const testData: CncTemplateParams = {
 | 
				
			||||||
 | 
					        templateName: 'MicroDrawBan_XML',
 | 
				
			||||||
 | 
					        propertyList: [{
 | 
				
			||||||
 | 
					            propertyName: 'Version',
 | 
				
			||||||
 | 
					            propertyValue: '3.0',
 | 
				
			||||||
 | 
					        }, {
 | 
				
			||||||
 | 
					            propertyName: 'Time',
 | 
				
			||||||
 | 
					            propertyValue: '20250903',
 | 
				
			||||||
 | 
					        }, {
 | 
				
			||||||
 | 
					            propertyName: 'Source',
 | 
				
			||||||
 | 
					            propertyValue: '福州晨丰科技有限公司',
 | 
				
			||||||
 | 
					        }, {
 | 
				
			||||||
 | 
					            propertyName: 'SourceType',
 | 
				
			||||||
 | 
					            propertyValue: 'CNC-Drilling',
 | 
				
			||||||
 | 
					        }],
 | 
				
			||||||
 | 
					        children: [{
 | 
				
			||||||
 | 
					            templateName: 'Plane',
 | 
				
			||||||
 | 
					            propertyList: [{
 | 
				
			||||||
 | 
					                propertyName: 'Name',
 | 
				
			||||||
 | 
					                propertyValue: '板名称',
 | 
				
			||||||
 | 
					            }, {
 | 
				
			||||||
 | 
					                propertyName: 'Code',
 | 
				
			||||||
 | 
					                propertyValue: '板编号',
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                propertyName: 'Order',
 | 
				
			||||||
 | 
					                propertyValue: '生产单号',
 | 
				
			||||||
 | 
					            }],
 | 
				
			||||||
 | 
					            children: [{
 | 
				
			||||||
 | 
					                templateName: 'Outline',
 | 
				
			||||||
 | 
					                propertyList: [],
 | 
				
			||||||
 | 
					                children: [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        templateName: 'Point',
 | 
				
			||||||
 | 
					                        propertyList: [{
 | 
				
			||||||
 | 
					                            propertyName:'Value',
 | 
				
			||||||
 | 
					                            propertyValue: 213,
 | 
				
			||||||
 | 
					                        }],
 | 
				
			||||||
 | 
					                        children: [],
 | 
				
			||||||
 | 
					                        templateEndType: TemplateEndTargetType.SingleEnd
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                templateEndType: TemplateEndTargetType.DoubleEnd
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                templateName:'HoleV',
 | 
				
			||||||
 | 
					                propertyList:[
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        propertyName:'Name',
 | 
				
			||||||
 | 
					                        propertyValue:"HoleV"
 | 
				
			||||||
 | 
					                    }, 
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                children:[],
 | 
				
			||||||
 | 
					                templateEndType: TemplateEndTargetType.SingleEnd
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					            templateEndType: TemplateEndTargetType.DoubleEnd
 | 
				
			||||||
 | 
					        }],
 | 
				
			||||||
 | 
					        templateEndType: TemplateEndTargetType.DoubleEnd
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    let cncWriter = new CncConverter()
 | 
				
			||||||
 | 
					   await cncWriter.doXML([testData])
 | 
				
			||||||
 | 
					    debugger
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
							
								
								
									
										5
									
								
								src/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/index.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// processors
 | 
				
			||||||
 | 
					export * from "./processors/processCodeConverter/processCodeConverter";
 | 
				
			||||||
 | 
					export * from "./processors/NcConverter/NcConverter"
 | 
				
			||||||
							
								
								
									
										2
									
								
								src/modules/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								src/modules/README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					### react-layout
 | 
				
			||||||
 | 
					矩形优化算法(陈总新优化)
 | 
				
			||||||
							
								
								
									
										1523
									
								
								src/modules/rect-layout/KLSCclass.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1523
									
								
								src/modules/rect-layout/KLSCclass.ts
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1993
									
								
								src/modules/rect-layout/RectOptimizeMachine.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1993
									
								
								src/modules/rect-layout/RectOptimizeMachine.ts
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										17
									
								
								src/modules/rect-layout/RectOptimizeMachine.worker.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/modules/rect-layout/RectOptimizeMachine.worker.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					import {type Big_bang,type xbang } from "./bang";
 | 
				
			||||||
 | 
					import { RectOptimizeMachine } from "./RectOptimizeMachine";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ctx: Worker = self as any;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ctx.addEventListener("message", async (event) =>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // 小板 / 大板 / 大板数量 / 优化迭代次数 / 双面加工优先排版? / 刀路间隙 / 电子锯算法 / ???
 | 
				
			||||||
 | 
					    let [xbangs, B_bang, B_bangsl, yhcs, isdtwosided, gap, dzjsf, yuliaodo2face] = (event.data) as [xbang[], Big_bang[], number[], number, boolean, number, boolean, boolean];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let m = new RectOptimizeMachine(async (best, scrap, fit) =>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        ctx.postMessage([best, scrap, fit]);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    m.Start(xbangs, B_bang, B_bangsl, yhcs, isdtwosided, gap, dzjsf, yuliaodo2face);
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
							
								
								
									
										42
									
								
								src/modules/rect-layout/bang.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/modules/rect-layout/bang.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,42 @@
 | 
				
			|||||||
 | 
					import type { ComposingType, HoleType, WaveType } from "cut-abstractions";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 单块1220*2440的板结果 Container
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export type Con = YH_bang[];
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 个体:优化结果 包含多个大板 Individual
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export type Inv = Con[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface YH_bang {
 | 
				
			||||||
 | 
					    bangid: number;
 | 
				
			||||||
 | 
					    line: WaveType;
 | 
				
			||||||
 | 
					    x: number;
 | 
				
			||||||
 | 
					    y: number;
 | 
				
			||||||
 | 
					    pbg: number;
 | 
				
			||||||
 | 
					    pbk: number;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 待优化小板 */
 | 
				
			||||||
 | 
					export interface xbang {
 | 
				
			||||||
 | 
					    l: number;
 | 
				
			||||||
 | 
					    w: number;
 | 
				
			||||||
 | 
					    line: WaveType;
 | 
				
			||||||
 | 
					    face: ComposingType;
 | 
				
			||||||
 | 
					    id: number;
 | 
				
			||||||
 | 
					    bno: string;
 | 
				
			||||||
 | 
					    holeFaceCount: HoleType;
 | 
				
			||||||
 | 
					    isRect?: boolean;
 | 
				
			||||||
 | 
					    hasHole?: boolean;
 | 
				
			||||||
 | 
					    isdtwosided?: boolean;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 待优化大板 */
 | 
				
			||||||
 | 
					export interface Big_bang
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    l: number;
 | 
				
			||||||
 | 
					    w: number;
 | 
				
			||||||
 | 
					    x: number;
 | 
				
			||||||
 | 
					    y: number;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										29
									
								
								src/modules/rect-layout/utils.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/modules/rect-layout/utils.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					export async function Sleep(time: number)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return new Promise(res =>
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        setTimeout(res, time);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function arrayLast<T>(arr: { [key: number]: T, length: number; }): T
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return arr[arr.length - 1];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function arrayMax<T>(arr: T[], f: (item: T) => number = a => (a as unknown as number)): [T, number]
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    let max = -Infinity;
 | 
				
			||||||
 | 
					    let maxIndex = -1;
 | 
				
			||||||
 | 
					    for (let i = 0; i < arr.length; i++)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        let item = arr[i];
 | 
				
			||||||
 | 
					        let v = f(item);
 | 
				
			||||||
 | 
					        if (v > max)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            maxIndex = i;
 | 
				
			||||||
 | 
					            max = v;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return [arr[maxIndex], maxIndex];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										149
									
								
								src/processors/CncConverter/CncConverter.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								src/processors/CncConverter/CncConverter.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,149 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					export class CncConverter implements ICncWriter {
 | 
				
			||||||
 | 
					    private lines: string[] = []
 | 
				
			||||||
 | 
					    private nodes: any[] = [];
 | 
				
			||||||
 | 
					    private actionRecord: CncAction[] = []
 | 
				
			||||||
 | 
					    get cncActions(): CncAction[] {
 | 
				
			||||||
 | 
					        return this.actionRecord
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    config: CncConverterConfig = {
 | 
				
			||||||
 | 
					        isNcFileComment: true,
 | 
				
			||||||
 | 
					        /** 换行符  个别文件需要用 ;\n 结束*/
 | 
				
			||||||
 | 
					        lineBreak: '\n',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        leaderChar: '//',
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    async doXML(data: CncTemplateParams[]) {
 | 
				
			||||||
 | 
					        // let line = []
 | 
				
			||||||
 | 
					        for (const template of data) {
 | 
				
			||||||
 | 
					            await this.doCncTemplate(template)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async doCncTemplate(templateItem: CncTemplateParams, level: number = 0) {
 | 
				
			||||||
 | 
					        /** 行缩进 内容 */
 | 
				
			||||||
 | 
					        let tabContent = `    `
 | 
				
			||||||
 | 
					        /** 实际行缩进输出内容 */
 | 
				
			||||||
 | 
					        let tabVal = '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (let i = 0; i < level; i++) {
 | 
				
			||||||
 | 
					            // 按照节点层级  生成缩进内容
 | 
				
			||||||
 | 
					            tabVal = tabVal + tabContent;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let node: any[] = []
 | 
				
			||||||
 | 
					        node.push(tabVal)
 | 
				
			||||||
 | 
					        let startCode = `<${templateItem.templateName}`
 | 
				
			||||||
 | 
					        node.push(startCode)
 | 
				
			||||||
 | 
					        for (const propertyInfo of templateItem.propertyList) {
 | 
				
			||||||
 | 
					            let propertyItem = `${propertyInfo.propertyName}="${propertyInfo.propertyValue}"`
 | 
				
			||||||
 | 
					            node.push(propertyItem)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let endStr = ' >'
 | 
				
			||||||
 | 
					        if (templateItem.templateEndType == TemplateEndTargetType.SingleEnd) {
 | 
				
			||||||
 | 
					            endStr = ' />'
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        node.push(endStr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.lines.push(node.join(' '))
 | 
				
			||||||
 | 
					        if (Array.isArray(templateItem.children) && templateItem.children.length > 0) {
 | 
				
			||||||
 | 
					            // 子节点 内容
 | 
				
			||||||
 | 
					            for (const kid of templateItem.children) {
 | 
				
			||||||
 | 
					                await this.doCncTemplate(kid, level + 1)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /** 结尾 */
 | 
				
			||||||
 | 
					        let endCode = templateItem.templateEndType == TemplateEndTargetType.DoubleEnd ? `</ ${templateItem.templateName}>` : ''
 | 
				
			||||||
 | 
					        if(endCode){
 | 
				
			||||||
 | 
					            this.lines.push((tabVal + endCode))
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    recordAction(type: CncActionType): string {
 | 
				
			||||||
 | 
					        const id = this.createActionId();
 | 
				
			||||||
 | 
					        const act: CncAction = {
 | 
				
			||||||
 | 
					            id: id,
 | 
				
			||||||
 | 
					            type,
 | 
				
			||||||
 | 
					            lineIndex: this.lines.length
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        this.comment(`CMP ${act.id} ${act.type}`);
 | 
				
			||||||
 | 
					        this.actionRecord.push(act);
 | 
				
			||||||
 | 
					        return id;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    private _actionIdx = 0;
 | 
				
			||||||
 | 
					    private createActionId() {
 | 
				
			||||||
 | 
					        return `A${this._actionIdx++}`;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    comment(content: string): string {
 | 
				
			||||||
 | 
					        let markContent = content + this.config.lineBreak
 | 
				
			||||||
 | 
					        let isShowMark = this.config.isNcFileComment || false
 | 
				
			||||||
 | 
					        if (isShowMark) {
 | 
				
			||||||
 | 
					            let leaderChar = this.config.leaderChar || ''
 | 
				
			||||||
 | 
					            markContent = `${leaderChar} ${markContent}`
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            markContent = ''
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return markContent + this.config.lineBreak
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface ICncWriter {
 | 
				
			||||||
 | 
					    get cncActions(): CncAction[]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface CncAction {
 | 
				
			||||||
 | 
					    readonly id: string;
 | 
				
			||||||
 | 
					    readonly type: CncActionType;
 | 
				
			||||||
 | 
					    readonly lineIndex: number;
 | 
				
			||||||
 | 
					    // parent: CncAction;
 | 
				
			||||||
 | 
					    // children: CncAction[]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type CncActionType = string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type CncTemplateParams = {
 | 
				
			||||||
 | 
					    /** 标签名 */
 | 
				
			||||||
 | 
					    templateName: string
 | 
				
			||||||
 | 
					    /** 属性列表 */
 | 
				
			||||||
 | 
					    propertyList: CncTemplatePropertyType[]
 | 
				
			||||||
 | 
					    /** 子标签 */
 | 
				
			||||||
 | 
					    children?: CncTemplateParams[]
 | 
				
			||||||
 | 
					    /** 标签结束方式 */
 | 
				
			||||||
 | 
					    templateEndType?: TemplateEndTargetType
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface CncTemplatePropertyType {
 | 
				
			||||||
 | 
					    /** 属性名 */
 | 
				
			||||||
 | 
					    propertyName: string
 | 
				
			||||||
 | 
					    /** 属性值 */
 | 
				
			||||||
 | 
					    propertyValue?: string | number
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					/** 
 | 
				
			||||||
 | 
					 * 节点结束类型 
 | 
				
			||||||
 | 
					 * 标记文本语言的结尾形式
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * <div></div>
 | 
				
			||||||
 | 
					 * <div />
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export enum TemplateEndTargetType {
 | 
				
			||||||
 | 
					    /** 这种  <div></div>*/
 | 
				
			||||||
 | 
					    DoubleEnd = 0,
 | 
				
			||||||
 | 
					    /** 这种 <div />*/
 | 
				
			||||||
 | 
					    SingleEnd = 1
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type CncConverterConfig = {
 | 
				
			||||||
 | 
					    /** 换行符  个别文件需要用 ;\n 结束*/
 | 
				
			||||||
 | 
					    lineBreak?: string
 | 
				
			||||||
 | 
					    /** 是否添加注释信息 */
 | 
				
			||||||
 | 
					    isNcFileComment?: boolean
 | 
				
			||||||
 | 
					    /** 注释标识符 */
 | 
				
			||||||
 | 
					    leaderChar?: string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										5
									
								
								src/processors/NcConverter/NcConverter.test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/processors/NcConverter/NcConverter.test.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					import { test } from "vitest";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test('NcConverterTest',()=>{
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
							
								
								
									
										794
									
								
								src/processors/NcConverter/NcConverter.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										794
									
								
								src/processors/NcConverter/NcConverter.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,794 @@
 | 
				
			|||||||
 | 
					import { CCode, CCodeParams, FaceType, GCode, GCodeParams, INcWriter, IPoint, Knife, NcAction, NcActionType, } from "cut-abstractions";
 | 
				
			||||||
 | 
					// // import { CArc2GCode, NcArcType, NcReductionType } from "mes-processors"
 | 
				
			||||||
 | 
					// import { Vector2 } from "node_modules/mes-processors/src/math/vector2";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 用以对接 NC类型的加工文件--即 解析器  */
 | 
				
			||||||
 | 
					export class NcConverter implements INcWriter {
 | 
				
			||||||
 | 
					    /** NC加工动作记录 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private lines: string[] = [];
 | 
				
			||||||
 | 
					    /** 刀库 */
 | 
				
			||||||
 | 
					    knifeList: Array<Knife> = []
 | 
				
			||||||
 | 
					    /** 当前刀具 */
 | 
				
			||||||
 | 
					    private currentKnife?: Knife = undefined;
 | 
				
			||||||
 | 
					    private actionRecord: NcAction[] = [];
 | 
				
			||||||
 | 
					    arcType: NcArcType = 'R';
 | 
				
			||||||
 | 
					    /** 最后一行代码参数 */
 | 
				
			||||||
 | 
					    // private lastParams?: any
 | 
				
			||||||
 | 
					    private lastParams: GCodeParams = new GCodeParams();
 | 
				
			||||||
 | 
					    private lastCode: string = '';
 | 
				
			||||||
 | 
					    /** 可以做代码转换 如G2转G3,G3转G2等 */
 | 
				
			||||||
 | 
					    codeMap: Record<string, string> = {};
 | 
				
			||||||
 | 
					    get ncActions(): NcAction[] {
 | 
				
			||||||
 | 
					        return this.actionRecord;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    reductionType: NcReductionType = NcReductionType.None;
 | 
				
			||||||
 | 
					    /** 配置  这里给默认值*/
 | 
				
			||||||
 | 
					    config: NcConverterConfig = {
 | 
				
			||||||
 | 
					        isEnableConverterAxis: false,
 | 
				
			||||||
 | 
					        thickness: 18,
 | 
				
			||||||
 | 
					        doSimpleFirstCode: false,
 | 
				
			||||||
 | 
					        isNcFileComment: true,
 | 
				
			||||||
 | 
					        isNcLinePrefixEnabled: false,
 | 
				
			||||||
 | 
					        ncLinePrefix: '',
 | 
				
			||||||
 | 
					        isUseSimpleCode: false,
 | 
				
			||||||
 | 
					        isSimpleFirstCode: false,
 | 
				
			||||||
 | 
					        arcType: 'R',
 | 
				
			||||||
 | 
					        reverseArcCode: false,
 | 
				
			||||||
 | 
					        NcCodeFreeMove: 'G00',
 | 
				
			||||||
 | 
					        NcCodeLineInterpolation: 'G01',
 | 
				
			||||||
 | 
					        NcCodeClockwiseArcInterpolation: 'G02',
 | 
				
			||||||
 | 
					        NcCodeAnticlockwiseArcInterpolation: 'G03',
 | 
				
			||||||
 | 
					        NcCodeAxisX: 'X',
 | 
				
			||||||
 | 
					        NcCodeAxisY: 'Y',
 | 
				
			||||||
 | 
					        NcCodeAxisZ: 'Z',
 | 
				
			||||||
 | 
					        NcCodeSpeed: 'F',
 | 
				
			||||||
 | 
					        NcCodeIncrementAxisX: 'I',
 | 
				
			||||||
 | 
					        NcCodeIncrementAxisY: 'J',
 | 
				
			||||||
 | 
					        NcCodeIncrementAxisZ: 'K',
 | 
				
			||||||
 | 
					        leaderChar: '//',
 | 
				
			||||||
 | 
					        boardLength: 2440,
 | 
				
			||||||
 | 
					        boardWidth: 1220,
 | 
				
			||||||
 | 
					        boardHeight: 50,
 | 
				
			||||||
 | 
					        originPointPosition: BoardPosition.LEFT_TOP,
 | 
				
			||||||
 | 
					        originZ0Position: OriginZPosition.WorkTop,
 | 
				
			||||||
 | 
					        heightAxis: AxisType.Z_POS,
 | 
				
			||||||
 | 
					        decimalPointPrecision: 3,
 | 
				
			||||||
 | 
					        fixFloatNumberEndZero: true,
 | 
				
			||||||
 | 
					        intNumberAddDecimalPoint: true,
 | 
				
			||||||
 | 
					        lineBreak: '\n'
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /** G代码转换关系 */
 | 
				
			||||||
 | 
					    codeTransform = {
 | 
				
			||||||
 | 
					        [GCode.G0]: this.config.NcCodeFreeMove,
 | 
				
			||||||
 | 
					        [GCode.G1]: this.config.NcCodeLineInterpolation,
 | 
				
			||||||
 | 
					        [GCode.G2]: this.config.NcCodeClockwiseArcInterpolation,
 | 
				
			||||||
 | 
					        [GCode.G3]: this.config.NcCodeAnticlockwiseArcInterpolation
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    initConfig(conf: NcConverterConfig) {
 | 
				
			||||||
 | 
					        this.config = { ...this.config, ...conf }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /** 更新下代码转换关系 */
 | 
				
			||||||
 | 
					        this.codeTransform = {
 | 
				
			||||||
 | 
					            [GCode.G0]: this.config.NcCodeFreeMove,
 | 
				
			||||||
 | 
					            [GCode.G1]: this.config.NcCodeLineInterpolation,
 | 
				
			||||||
 | 
					            [GCode.G2]: this.config.NcCodeClockwiseArcInterpolation,
 | 
				
			||||||
 | 
					            [GCode.G3]: this.config.NcCodeAnticlockwiseArcInterpolation
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected code(code: keyof typeof GCode, params: Partial<GCodeParams>) {
 | 
				
			||||||
 | 
					        const line: any[] = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * G0 - G3 代码 显示的时候可以配置  
 | 
				
			||||||
 | 
					         * 例
 | 
				
			||||||
 | 
					         * G00 - G03
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (this.reductionType & NcReductionType.Code) {
 | 
				
			||||||
 | 
					            if (this.lastCode != code) {
 | 
				
			||||||
 | 
					                line.push(this.codeTransform[code]);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            line.push(this.codeTransform[code]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.lastCode = code;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let x = params.x ??= this.lastParams.x;
 | 
				
			||||||
 | 
					        let y = params.y ??= this.lastParams.y;
 | 
				
			||||||
 | 
					        let z = params.z ??= this.lastParams.z;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let x_val = this.handleValue_DecimalPointPrecision(x)
 | 
				
			||||||
 | 
					        let y_val = this.handleValue_DecimalPointPrecision(y)
 | 
				
			||||||
 | 
					        let z_val = this.handleValue_DecimalPointPrecision(z)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let x_code = this.config.NcCodeAxisX || 'X'
 | 
				
			||||||
 | 
					        let y_code = this.config.NcCodeAxisY || 'Y'
 | 
				
			||||||
 | 
					        let z_code = this.config.NcCodeAxisZ || 'Z'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (this.reductionType & NcReductionType.Position) {
 | 
				
			||||||
 | 
					            if (x != this.lastParams.x) {
 | 
				
			||||||
 | 
					                line.push(x_code + x_val);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (y != this.lastParams.y) {
 | 
				
			||||||
 | 
					                line.push(y_code + y_val);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (z != this.lastParams.z) {
 | 
				
			||||||
 | 
					                line.push(z_code + z_val);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            line.push(x_code + x_val);
 | 
				
			||||||
 | 
					            line.push(y_code + y_val);
 | 
				
			||||||
 | 
					            line.push(z_code + z_val);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (code == 'G2' || code == 'G3') {
 | 
				
			||||||
 | 
					            if (this.config.arcType == 'R') {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let r = params.r ??= this.lastParams.r;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let r_val = this.handleValue_DecimalPointPrecision(r)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                line.push('R' + r_val);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (this.config.arcType == 'IJK') {
 | 
				
			||||||
 | 
					                let i = params.i ??= this.lastParams.i;
 | 
				
			||||||
 | 
					                let j = params.j ??= this.lastParams.j;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let i_val = this.handleValue_DecimalPointPrecision(i)
 | 
				
			||||||
 | 
					                let j_val = this.handleValue_DecimalPointPrecision(j)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                line.push('I' + i_val);
 | 
				
			||||||
 | 
					                line.push('J' + j_val);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const speed = params.f ??= this.lastParams.f
 | 
				
			||||||
 | 
					        if (speed != 0) {
 | 
				
			||||||
 | 
					            if (this.reductionType & NcReductionType.Speed) {
 | 
				
			||||||
 | 
					                if (speed != this.lastParams.f) {
 | 
				
			||||||
 | 
					                    line.push('F' + speed);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                line.push('F' + speed);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Object.assign(this.lastParams, params); // 更新上一次参数
 | 
				
			||||||
 | 
					        if (this.codeMap[line[0]]) { // 命令转换
 | 
				
			||||||
 | 
					            line[0] = this.codeMap[line[0]];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        this.lines.push(line.join(' '));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    gCode<TCode extends (keyof typeof GCode | keyof typeof CCode)>(code: TCode, params: Partial<TCode extends keyof typeof GCode ? GCodeParams : CCodeParams>): void {
 | 
				
			||||||
 | 
					        switch (code) {
 | 
				
			||||||
 | 
					            case 'G0':
 | 
				
			||||||
 | 
					            case 'G1':
 | 
				
			||||||
 | 
					            case 'G2':
 | 
				
			||||||
 | 
					            case 'G3': {
 | 
				
			||||||
 | 
					                this.code(code, params);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            // 自定义代码
 | 
				
			||||||
 | 
					            case 'CArc': {
 | 
				
			||||||
 | 
					                // 凸度转GCode
 | 
				
			||||||
 | 
					                const cParam = params as Partial<CCodeParams>;
 | 
				
			||||||
 | 
					                if (!cParam.x || !cParam.y || !cParam.b) throw new Error("CArc命令缺少必要参数(X, Y, B)");
 | 
				
			||||||
 | 
					                const targetPoint = { x: cParam.x, y: cParam.y };
 | 
				
			||||||
 | 
					                if (this.config.arcType === 'R') {
 | 
				
			||||||
 | 
					                    const result = CArc2GCode(this.lastParams, targetPoint, cParam.b, 'R');
 | 
				
			||||||
 | 
					                    this.code(result.gCode, { ...targetPoint, r: result.r });
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    const result = CArc2GCode(this.lastParams, targetPoint, cParam.b, 'IJK');
 | 
				
			||||||
 | 
					                    this.code(result.gCode, { ...targetPoint, i: result.i, j: result.j });
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** 处理值  最终显示的值 小数点后X位功能  */
 | 
				
			||||||
 | 
					    handleValue_DecimalPointPrecision(val: number) {
 | 
				
			||||||
 | 
					        const { fixFloatNumberEndZero, intNumberAddDecimalPoint, decimalPointPrecision } = this.config
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * 2种方式  末尾补零 或者 直接保留小数点后N位
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        let isToFix = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let resVal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (fixFloatNumberEndZero == true) {
 | 
				
			||||||
 | 
					            // 末尾补零
 | 
				
			||||||
 | 
					            isToFix = true
 | 
				
			||||||
 | 
					        } else if (intNumberAddDecimalPoint == true) {
 | 
				
			||||||
 | 
					            // 整数值末尾加小数点
 | 
				
			||||||
 | 
					            if (Number.isInteger(val)) {
 | 
				
			||||||
 | 
					                isToFix = true
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (isToFix) {
 | 
				
			||||||
 | 
					            resVal = val.toFixed(decimalPointPrecision)
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            resVal = val.toString()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return resVal
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** 更换刀具 */
 | 
				
			||||||
 | 
					    changeKnife() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** 校验值是否有效 不为'' 或 undefined */
 | 
				
			||||||
 | 
					    checkVal(val: any): boolean {
 | 
				
			||||||
 | 
					        let r = true
 | 
				
			||||||
 | 
					        if ((val == undefined || val == '')) {
 | 
				
			||||||
 | 
					            r = false
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return r
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    toString() {
 | 
				
			||||||
 | 
					        return this.lines.join(this.config.lineBreak);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    comment(content: string): string {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let markContent = content + this.config.lineBreak
 | 
				
			||||||
 | 
					        let isShowMark = this.config.isNcFileComment || false
 | 
				
			||||||
 | 
					        if (isShowMark) {
 | 
				
			||||||
 | 
					            let leaderChar = this.config.leaderChar || ''
 | 
				
			||||||
 | 
					            markContent = `${leaderChar} ${markContent}`
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            markContent = ''
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return markContent + this.config.lineBreak
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    recordAction(type: NcActionType): string {
 | 
				
			||||||
 | 
					        const id = this.createActionId();
 | 
				
			||||||
 | 
					        const act: NcAction = {
 | 
				
			||||||
 | 
					            id: id,
 | 
				
			||||||
 | 
					            type,
 | 
				
			||||||
 | 
					            lineIndex: this.lines.length
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        this.comment(`CMP ${act.id} ${act.type}`);
 | 
				
			||||||
 | 
					        this.actionRecord.push(act);
 | 
				
			||||||
 | 
					        return id;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    private _actionIdx = 0;
 | 
				
			||||||
 | 
					    private createActionId() {
 | 
				
			||||||
 | 
					        return `A${this._actionIdx++}`;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    append(str: string) {
 | 
				
			||||||
 | 
					        // this.lines.push(str);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    appendLine(str: string) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					       * 
 | 
				
			||||||
 | 
					       * @param point 加工项的点
 | 
				
			||||||
 | 
					       * @param processItemInfo 加工项的信息 水平基准、垂直基准、轴方向(x、y、z),板件方向(x、y、z)
 | 
				
			||||||
 | 
					       * // 这里加工项的点数据  都是经过数据处理的  假定这里拿到的数据都是基于左上角 台面
 | 
				
			||||||
 | 
					       * 
 | 
				
			||||||
 | 
					       * @returns 实际加工项的点
 | 
				
			||||||
 | 
					       */
 | 
				
			||||||
 | 
					    getXYZ(point: CodeParams, processItemInfo: ProcessInfo): CodeParams {
 | 
				
			||||||
 | 
					        let newPoint: any = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (this.config.isEnableConverterAxis) {
 | 
				
			||||||
 | 
					            // 进行坐标轴转换
 | 
				
			||||||
 | 
					            for (const key in point) {
 | 
				
			||||||
 | 
					                if (point[key] != undefined) {
 | 
				
			||||||
 | 
					                    Reflect.set(newPoint, key, parseFloat(point[key]))
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // /** 有2个部分  
 | 
				
			||||||
 | 
					            //  * 一个是基于机台和板件的转换  依据板件定位
 | 
				
			||||||
 | 
					            //  * 另外一个是基于板件和加工项的转换 依据板件长高方向*/
 | 
				
			||||||
 | 
					            // switch (this.config.originZ0Position) {
 | 
				
			||||||
 | 
					            //     case 0:
 | 
				
			||||||
 | 
					            //         // 台面 不操作
 | 
				
			||||||
 | 
					            //         break;
 | 
				
			||||||
 | 
					            //     case 1:
 | 
				
			||||||
 | 
					            //         // 板面 Z坐标需要转换
 | 
				
			||||||
 | 
					            //         newPoint.z = newPoint.z - this.config.thickness
 | 
				
			||||||
 | 
					            //         break;
 | 
				
			||||||
 | 
					            //     default:
 | 
				
			||||||
 | 
					            //         break;
 | 
				
			||||||
 | 
					            // }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // /** step  先转换板件的位置 */
 | 
				
			||||||
 | 
					            // // 大板定位 不同 根据不同的定位点修改
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // // processItemInfo
 | 
				
			||||||
 | 
					            // switch (this.config.originPointPosition) {
 | 
				
			||||||
 | 
					            //     case BoardPosition.LEFT_TOP:
 | 
				
			||||||
 | 
					            //         // 不操作
 | 
				
			||||||
 | 
					            //         newPoint = this.changeXYZAxiosSide(newPoint)
 | 
				
			||||||
 | 
					            //         break;
 | 
				
			||||||
 | 
					            //     case BoardPosition.LEFT_BOTTOM:
 | 
				
			||||||
 | 
					            //         // 左下角 x坐标要转换
 | 
				
			||||||
 | 
					            //         newPoint.x = newPoint.x + this.config.boardWidth - processItemInfo.block.cutWidth //400
 | 
				
			||||||
 | 
					            //         newPoint = this.changeXYZAxiosSide(newPoint)
 | 
				
			||||||
 | 
					            //         break;
 | 
				
			||||||
 | 
					            //     case BoardPosition.RIGHT_TOP:
 | 
				
			||||||
 | 
					            //         // 右上角 y坐标要转换
 | 
				
			||||||
 | 
					            //         newPoint.y = newPoint.y + this.config.boardLength - processItemInfo.block.cutLength // 600
 | 
				
			||||||
 | 
					            //         newPoint = this.changeXYZAxiosSide(newPoint)
 | 
				
			||||||
 | 
					            //         break;
 | 
				
			||||||
 | 
					            //     case BoardPosition.RIGHT_BOTTOM:
 | 
				
			||||||
 | 
					            //         // 右下角 xy 坐标要转换
 | 
				
			||||||
 | 
					            //         newPoint.x = newPoint.x + this.config.boardWidth - processItemInfo.block.cutWidth
 | 
				
			||||||
 | 
					            //         newPoint.y = newPoint.y + this.config.boardLength - processItemInfo.block.cutLength
 | 
				
			||||||
 | 
					            //         newPoint = this.changeXYZAxiosSide(newPoint)
 | 
				
			||||||
 | 
					            //         break;
 | 
				
			||||||
 | 
					            //     default:
 | 
				
			||||||
 | 
					            //         break;
 | 
				
			||||||
 | 
					            // }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // 这里做 数值的小数点处理 
 | 
				
			||||||
 | 
					            for (const key in newPoint) {
 | 
				
			||||||
 | 
					                if (['x', 'y', 'z', 'r', 'i', 'j', 'k'].includes(key)) {
 | 
				
			||||||
 | 
					                    let isTofix = false
 | 
				
			||||||
 | 
					                    if (this.config.fixFloatNumberEndZero == true) {
 | 
				
			||||||
 | 
					                        // 末尾补零
 | 
				
			||||||
 | 
					                        isTofix = true
 | 
				
			||||||
 | 
					                    } else if (this.config.intNumberAddDecimalPoint == true) {
 | 
				
			||||||
 | 
					                        // 整数值末尾加小数点
 | 
				
			||||||
 | 
					                        if (Number.isInteger(newPoint[key])) {
 | 
				
			||||||
 | 
					                            isTofix = true
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    if (isTofix) {
 | 
				
			||||||
 | 
					                        newPoint[key] = parseFloat(newPoint[key]).toFixed(this.config.decimalPointPrecision)
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return newPoint
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            return point
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /** 根据 轴向变更坐标 */
 | 
				
			||||||
 | 
					    changeXYZAxiosSide(point: CodeParams) {
 | 
				
			||||||
 | 
					        let newPoint: any = {}
 | 
				
			||||||
 | 
					        for (const key in point) {
 | 
				
			||||||
 | 
					            if (point[key] != undefined) {
 | 
				
			||||||
 | 
					                Reflect.set(newPoint, key, parseFloat(point[key]))
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let width = this.config.boardWidth
 | 
				
			||||||
 | 
					        let length = this.config.boardLength
 | 
				
			||||||
 | 
					        let height = this.config.boardHeight
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (this.config.widthSideAxis == AxisType.X_POS && this.config.lengthSideAxis == AxisType.Y_POS) {
 | 
				
			||||||
 | 
					            // 默认 为 X = x 正 Y = y 正  不操作
 | 
				
			||||||
 | 
					        } else if (this.config.widthSideAxis == AxisType.Y_POS && this.config.lengthSideAxis == AxisType.X_POS) {
 | 
				
			||||||
 | 
					            // x = y正   y = x正   X Y坐标 倒转
 | 
				
			||||||
 | 
					            newPoint = { ...newPoint, x: newPoint.y, y: newPoint.x }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        else if (this.config.widthSideAxis == AxisType.X_NEG && this.config.lengthSideAxis == AxisType.Y_POS) {
 | 
				
			||||||
 | 
					            // x = x负  y = y正     
 | 
				
			||||||
 | 
					            newPoint = { ...newPoint, x: newPoint.x - width, y: newPoint.y }
 | 
				
			||||||
 | 
					        } else if (this.config.widthSideAxis == AxisType.Y_POS && this.config.lengthSideAxis == AxisType.X_NEG) {
 | 
				
			||||||
 | 
					            // x = y正  y = x负   
 | 
				
			||||||
 | 
					            newPoint = { ...newPoint, x: newPoint.y - width, y: newPoint.x }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        else if (this.config.widthSideAxis == AxisType.X_NEG && this.config.lengthSideAxis == AxisType.Y_NEG) {
 | 
				
			||||||
 | 
					            // x = x负  y = y负  
 | 
				
			||||||
 | 
					            newPoint = { ...newPoint, x: newPoint.x - width, y: newPoint.y - length }
 | 
				
			||||||
 | 
					        } else if (this.config.widthSideAxis == AxisType.Y_NEG && this.config.lengthSideAxis == AxisType.X_NEG) {
 | 
				
			||||||
 | 
					            // x = y负  y = x负   
 | 
				
			||||||
 | 
					            newPoint = { ...newPoint, x: newPoint.y - width, y: newPoint.x - length }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        else if (this.config.widthSideAxis == AxisType.X_POS && this.config.lengthSideAxis == AxisType.Y_NEG) {
 | 
				
			||||||
 | 
					            // x = x正  y = y负  
 | 
				
			||||||
 | 
					            newPoint = { ...newPoint, x: newPoint.x, y: newPoint.y - length }
 | 
				
			||||||
 | 
					        } else if (this.config.widthSideAxis == AxisType.Y_NEG && this.config.lengthSideAxis == AxisType.X_POS) {
 | 
				
			||||||
 | 
					            // x = y负  y = x正  
 | 
				
			||||||
 | 
					            newPoint = { ...newPoint, x: newPoint.y, y: newPoint.x - length }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (this.config.heightAxis == AxisType.Z_NEG) {
 | 
				
			||||||
 | 
					            // Z轴负
 | 
				
			||||||
 | 
					            newPoint = { ...newPoint, z: newPoint.z - height }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return newPoint
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type NcConverterConfig = {
 | 
				
			||||||
 | 
					    /** 是否启用解析器的坐标系转换 */
 | 
				
			||||||
 | 
					    isEnableConverterAxis?: boolean,
 | 
				
			||||||
 | 
					    /** 板厚 */
 | 
				
			||||||
 | 
					    thickness: number,
 | 
				
			||||||
 | 
					    /**是否执行换刀后的第一行精简指令 */
 | 
				
			||||||
 | 
					    doSimpleFirstCode?: boolean
 | 
				
			||||||
 | 
					    /** 是否添加注释信息 */
 | 
				
			||||||
 | 
					    isNcFileComment?: boolean
 | 
				
			||||||
 | 
					    /** 是否空行插入前缀 */
 | 
				
			||||||
 | 
					    isNcLinePrefixEnabled?: boolean
 | 
				
			||||||
 | 
					    /** 空行插入前缀  前缀内容*/
 | 
				
			||||||
 | 
					    ncLinePrefix?: string
 | 
				
			||||||
 | 
					    /** 使用精简指令 */
 | 
				
			||||||
 | 
					    isUseSimpleCode?: boolean
 | 
				
			||||||
 | 
					    /** 精简换刀后第一行指令 */
 | 
				
			||||||
 | 
					    isSimpleFirstCode?: boolean
 | 
				
			||||||
 | 
					    /** 圆弧指令模式类型 */
 | 
				
			||||||
 | 
					    arcType?: NcArcType
 | 
				
			||||||
 | 
					    /** 反转圆弧指令 */
 | 
				
			||||||
 | 
					    reverseArcCode?: boolean
 | 
				
			||||||
 | 
					    /** 空程移动指令 */
 | 
				
			||||||
 | 
					    NcCodeFreeMove?: string
 | 
				
			||||||
 | 
					    /** 直线插补标识 */
 | 
				
			||||||
 | 
					    NcCodeLineInterpolation?: string
 | 
				
			||||||
 | 
					    /** 顺时针圆弧插补标识 */
 | 
				
			||||||
 | 
					    NcCodeClockwiseArcInterpolation?: string
 | 
				
			||||||
 | 
					    /** 逆时针圆弧插补标识 */
 | 
				
			||||||
 | 
					    NcCodeAnticlockwiseArcInterpolation?: string
 | 
				
			||||||
 | 
					    /** 水平坐标横轴标识 */
 | 
				
			||||||
 | 
					    NcCodeAxisX?: string
 | 
				
			||||||
 | 
					    /** 水平坐标纵轴标识 */
 | 
				
			||||||
 | 
					    NcCodeAxisY?: string
 | 
				
			||||||
 | 
					    /** 垂直坐标轴标识 */
 | 
				
			||||||
 | 
					    NcCodeAxisZ?: string
 | 
				
			||||||
 | 
					    /** 速度标识 */
 | 
				
			||||||
 | 
					    NcCodeSpeed?: string
 | 
				
			||||||
 | 
					    /** 水平坐标横轴增量标识 */
 | 
				
			||||||
 | 
					    NcCodeIncrementAxisX?: string
 | 
				
			||||||
 | 
					    /** 水平坐标纵轴增量标识 */
 | 
				
			||||||
 | 
					    NcCodeIncrementAxisY?: string
 | 
				
			||||||
 | 
					    /** 垂直坐标轴增量标识 */
 | 
				
			||||||
 | 
					    NcCodeIncrementAxisZ?: string
 | 
				
			||||||
 | 
					    /** 注释标识符 */
 | 
				
			||||||
 | 
					    leaderChar?: string
 | 
				
			||||||
 | 
					    /** 工作区域长 x */
 | 
				
			||||||
 | 
					    boardLength: number
 | 
				
			||||||
 | 
					    /** 工作区域宽 y */
 | 
				
			||||||
 | 
					    boardWidth: number
 | 
				
			||||||
 | 
					    /** 工作区域高 z */
 | 
				
			||||||
 | 
					    boardHeight: number
 | 
				
			||||||
 | 
					    /** 水平基准点 */
 | 
				
			||||||
 | 
					    originPointPosition?: BoardPosition
 | 
				
			||||||
 | 
					    /** 垂直基准点 */
 | 
				
			||||||
 | 
					    originZ0Position?: OriginZPosition
 | 
				
			||||||
 | 
					    /** 水平纵轴坐标轴向 */
 | 
				
			||||||
 | 
					    widthSideAxis?: AxisType
 | 
				
			||||||
 | 
					    /** 水平横轴坐标轴向 */
 | 
				
			||||||
 | 
					    lengthSideAxis?: AxisType
 | 
				
			||||||
 | 
					    /** 垂直轴坐标轴向 */
 | 
				
			||||||
 | 
					    heightAxis?: AxisType
 | 
				
			||||||
 | 
					    /** 保留小数点位数 */
 | 
				
			||||||
 | 
					    decimalPointPrecision?: number
 | 
				
			||||||
 | 
					    /** 末尾补零 */
 | 
				
			||||||
 | 
					    fixFloatNumberEndZero?: boolean
 | 
				
			||||||
 | 
					    /** 整数值末尾加小数点 */
 | 
				
			||||||
 | 
					    intNumberAddDecimalPoint?: boolean
 | 
				
			||||||
 | 
					    /** 换行符  个别文件需要用 ;\n 结束*/
 | 
				
			||||||
 | 
					    lineBreak?: string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 枚举 大板边角位置 */
 | 
				
			||||||
 | 
					export enum BoardPosition {
 | 
				
			||||||
 | 
					    /** 左上角 */
 | 
				
			||||||
 | 
					    LEFT_TOP = 3,
 | 
				
			||||||
 | 
					    /** 左下角 */
 | 
				
			||||||
 | 
					    LEFT_BOTTOM = 0,
 | 
				
			||||||
 | 
					    /** 右下角 */
 | 
				
			||||||
 | 
					    RIGHT_BOTTOM = 1,
 | 
				
			||||||
 | 
					    /** 右上角 */
 | 
				
			||||||
 | 
					    RIGHT_TOP = 2,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					/** 枚举 坐标轴类型 */
 | 
				
			||||||
 | 
					export enum OriginZPosition {
 | 
				
			||||||
 | 
					    /** 台面向上Z轴正 */
 | 
				
			||||||
 | 
					    WorkTop = 0,
 | 
				
			||||||
 | 
					    /** 板面向上Z轴正 */
 | 
				
			||||||
 | 
					    BoardFace = 1,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 枚举 坐标轴类型 */
 | 
				
			||||||
 | 
					export enum AxisType {
 | 
				
			||||||
 | 
					    /** X轴正 */
 | 
				
			||||||
 | 
					    X_POS = 0,
 | 
				
			||||||
 | 
					    /** X轴负 */
 | 
				
			||||||
 | 
					    X_NEG = 1,
 | 
				
			||||||
 | 
					    /** Y轴正 */
 | 
				
			||||||
 | 
					    Y_POS = 2,
 | 
				
			||||||
 | 
					    /** Y轴负 */
 | 
				
			||||||
 | 
					    Y_NEG = 3,
 | 
				
			||||||
 | 
					    /** 向上Z轴正 */
 | 
				
			||||||
 | 
					    Z_POS = 4,
 | 
				
			||||||
 | 
					    /** 向下Z轴负 */
 | 
				
			||||||
 | 
					    Z_NEG = 5,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					// 加工项 点数据 
 | 
				
			||||||
 | 
					export class CodeParams {
 | 
				
			||||||
 | 
					    /** x坐标 */
 | 
				
			||||||
 | 
					    x?: Number | String
 | 
				
			||||||
 | 
					    /** y坐标 */
 | 
				
			||||||
 | 
					    y?: Number | String
 | 
				
			||||||
 | 
					    /** z坐标 */
 | 
				
			||||||
 | 
					    z?: Number | String
 | 
				
			||||||
 | 
					    /** 调用的代码编号 */
 | 
				
			||||||
 | 
					    dir?: Number | String
 | 
				
			||||||
 | 
					    /** 圆弧半径 */
 | 
				
			||||||
 | 
					    r?: Number | String
 | 
				
			||||||
 | 
					    /** 速度  */
 | 
				
			||||||
 | 
					    f?: Number | String
 | 
				
			||||||
 | 
					    /** IJK 模式的i */
 | 
				
			||||||
 | 
					    i?: Number | String
 | 
				
			||||||
 | 
					    /** IJK 模式的j */
 | 
				
			||||||
 | 
					    j?: Number | String
 | 
				
			||||||
 | 
					    /** IJK 模式的k */
 | 
				
			||||||
 | 
					    k?: Number | String
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** 代码标识 */
 | 
				
			||||||
 | 
					    codeKey?: String
 | 
				
			||||||
 | 
					    /** x坐标 */
 | 
				
			||||||
 | 
					    xKey?: String
 | 
				
			||||||
 | 
					    /** y坐标 */
 | 
				
			||||||
 | 
					    yKey?: String
 | 
				
			||||||
 | 
					    /** z坐标 */
 | 
				
			||||||
 | 
					    zKey?: String
 | 
				
			||||||
 | 
					    /** 圆弧半径 */
 | 
				
			||||||
 | 
					    rKey?: String
 | 
				
			||||||
 | 
					    /** 速度  */
 | 
				
			||||||
 | 
					    fKey?: String
 | 
				
			||||||
 | 
					    /** IJK 模式的i */
 | 
				
			||||||
 | 
					    iKey?: String
 | 
				
			||||||
 | 
					    /** IJK 模式的j */
 | 
				
			||||||
 | 
					    jKey?: String
 | 
				
			||||||
 | 
					    /** IJK 模式的k */
 | 
				
			||||||
 | 
					    kKey?: String
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 加工项对应的信息 */
 | 
				
			||||||
 | 
					export class ProcessInfo {
 | 
				
			||||||
 | 
					    /**当前加工项的下标*/
 | 
				
			||||||
 | 
					    i?: Number
 | 
				
			||||||
 | 
					    /** 加工项 对应刀具的数据 */
 | 
				
			||||||
 | 
					    knife?: Knife
 | 
				
			||||||
 | 
					    /** 加工项的类型 */
 | 
				
			||||||
 | 
					    type?: processItemType
 | 
				
			||||||
 | 
					    /** 加工项所在的 文件名 */
 | 
				
			||||||
 | 
					    belong?: string
 | 
				
			||||||
 | 
					    /** 该加工项基于哪个加工面  传入数据 主要用于 加工项坐标转换   感觉可能没用 */
 | 
				
			||||||
 | 
					    belongFace?: FaceType
 | 
				
			||||||
 | 
					    /** 板件信息 */
 | 
				
			||||||
 | 
					    block?: any
 | 
				
			||||||
 | 
					    // /** 垂直基准点 */
 | 
				
			||||||
 | 
					    // originZ0Position?: OriginZPosition
 | 
				
			||||||
 | 
					    // /** 水平基准点 */
 | 
				
			||||||
 | 
					    // originPointPosition?: BoardPosition
 | 
				
			||||||
 | 
					    // /** 大板定位 */
 | 
				
			||||||
 | 
					    // boardLocation?: BoardPosition
 | 
				
			||||||
 | 
					    // /** 加工项的宽方向 x */
 | 
				
			||||||
 | 
					    // widthSideAxis?: AxisType
 | 
				
			||||||
 | 
					    // /** 加工项的长方向 y */
 | 
				
			||||||
 | 
					    // lengthSideAxis ?: AxisType
 | 
				
			||||||
 | 
					    // /** 加工项的高方向 */
 | 
				
			||||||
 | 
					    // heightSideAxis ?: AxisType
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 加工项的类别
 | 
				
			||||||
 | 
					 * 用于区分加工项的类别,不同的类别  在文件生成的时候  可能需要对应某些独立的节点
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export enum processItemType {
 | 
				
			||||||
 | 
					    /**排钻 */
 | 
				
			||||||
 | 
					    Hole = 'hole',
 | 
				
			||||||
 | 
					    /** 铣孔 */
 | 
				
			||||||
 | 
					    MillingHole = 'millingHole',
 | 
				
			||||||
 | 
					    /** 造型 非槽加工 铣型 */
 | 
				
			||||||
 | 
					    Model = 'model',
 | 
				
			||||||
 | 
					    /** 造型 槽-- 拉槽 */
 | 
				
			||||||
 | 
					    Grooves = 'grooves',
 | 
				
			||||||
 | 
					    /** 造型 铣槽  */
 | 
				
			||||||
 | 
					    MillingGrooves = 'millingGrooves',
 | 
				
			||||||
 | 
					    /** 侧面造型 */
 | 
				
			||||||
 | 
					    SideModel = 'SideModel',
 | 
				
			||||||
 | 
					    /** 侧面槽 - 拉槽 */
 | 
				
			||||||
 | 
					    SideGrooves = 'sideGrooves',
 | 
				
			||||||
 | 
					    /** 侧面槽 - 拉槽 */
 | 
				
			||||||
 | 
					    SideMillingGrooves = 'SideMillingGrooves',
 | 
				
			||||||
 | 
					    /** 侧面孔 排钻 */
 | 
				
			||||||
 | 
					    SideHole = 'sideHole',
 | 
				
			||||||
 | 
					    /** 侧面孔 铣孔 */
 | 
				
			||||||
 | 
					    MillingSideHole = 'MillingSideHole',
 | 
				
			||||||
 | 
					    /** 开料 */
 | 
				
			||||||
 | 
					    CutBlock = 'cutBlock',
 | 
				
			||||||
 | 
					    /** 修边 */
 | 
				
			||||||
 | 
					    MillingBlockBoard = 'MillingBlockBoard'
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type NcArcType = 'R' | 'IJK';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 将基于凸度的圆弧转换为基于圆弧半径/圆心坐标表示的圆弧,暂不支持三维圆弧(Z轴或K分量)
 | 
				
			||||||
 | 
					 * @param source 圆弧起始点
 | 
				
			||||||
 | 
					 * @param target 圆弧终点
 | 
				
			||||||
 | 
					 * @param bulge 凸度值
 | 
				
			||||||
 | 
					 * @param mode 圆弧模式
 | 
				
			||||||
 | 
					 * @returns 圆弧参数(IJ或R)
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export function CArc2GCode(source: IPoint, target: IPoint, bulge: number, mode: 'R'): { gCode: 'G2' | 'G3'; r: number; };
 | 
				
			||||||
 | 
					export function CArc2GCode(source: IPoint, target: IPoint, bulge: number, mode: 'IJK'): { gCode: 'G2' | 'G3'; i: number; j: number; };
 | 
				
			||||||
 | 
					export function CArc2GCode(source: IPoint, target: IPoint, bulge: number, mode: NcArcType): { gCode: 'G2' | 'G3'; r?: number; i?: number; j?: number; } {
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * ♿♿♿ 修改必看!!!
 | 
				
			||||||
 | 
					     * 凸度为圆弧圆心角的1/4正切值
 | 
				
			||||||
 | 
					     * Bulge = tan(θ / 4) θ为圆心角
 | 
				
			||||||
 | 
					     * 凸度为正数,则从起点顺时针绘制圆弧到终点
 | 
				
			||||||
 | 
					     * 凸度为负数,则逆时针绘制
 | 
				
			||||||
 | 
					     * 当凸度为0时,绘制直线
 | 
				
			||||||
 | 
					     * 当凸度为1时,圆心角为180度 tan(180 / 4) = 1
 | 
				
			||||||
 | 
					     * 凸度转换公式见 https://www.lee-mac.com/bulgeconversion.html
 | 
				
			||||||
 | 
					     * 
 | 
				
			||||||
 | 
					     * NC圆弧规则
 | 
				
			||||||
 | 
					     * 圆弧半径(R)模式:
 | 
				
			||||||
 | 
					     * 从起点到终点绘制半径为|R|的圆弧,R越大圆弧越平滑,越小圆弧越弯曲
 | 
				
			||||||
 | 
					     * 当R为正数时,表示绘制圆的短弧
 | 
				
			||||||
 | 
					     * 当R为负数时,表示绘制圆的长弧
 | 
				
			||||||
 | 
					     * ⚠️注意 起点到终点的距离不可大于 2 * |R|,否则应当抛出错误
 | 
				
			||||||
 | 
					     * 
 | 
				
			||||||
 | 
					     * 圆心坐标(IJ)模式:
 | 
				
			||||||
 | 
					     * 从起点到终点绘制圆弧,圆心坐标为(I, J),I为圆心在X轴上的坐标(带符号),J为圆心在Y轴上的坐标(带符号)
 | 
				
			||||||
 | 
					     * ⚠️注意 圆心到圆弧起点和圆心到圆弧终点的距离必须相等(都等于圆弧的半径),否则应当抛出错误
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (bulge === 0) {
 | 
				
			||||||
 | 
					        throw new Error("圆弧模式下,凸度值不能为0");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const p1 = Vector2.FromPoint(source);
 | 
				
			||||||
 | 
					    const p2 = Vector2.FromPoint(target);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const gCode = bulge > 0 ? 'G2' : 'G3';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const delta = p2.Subtract(p1);
 | 
				
			||||||
 | 
					    const dist = delta.Magnitude;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (dist < 1e-6) {
 | 
				
			||||||
 | 
					        throw new Error("起点与终点距离过近");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 通过凸度值计算圆弧半径
 | 
				
			||||||
 | 
					    // 圆弧半径 r = (弦长 / 2) * (1 + bulge²) / (2 * |bulge|)
 | 
				
			||||||
 | 
					    // 详见: https://www.lee-mac.com/bulgeconversion.html#bulgeradius
 | 
				
			||||||
 | 
					    const chordLength = delta.Magnitude;
 | 
				
			||||||
 | 
					    const radius = (chordLength / 2) * (1 + bulge * bulge) / (2 * Math.abs(bulge));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // R模式
 | 
				
			||||||
 | 
					    if (mode === 'R') {
 | 
				
			||||||
 | 
					        return { gCode: gCode, r: radius };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // IJK模式
 | 
				
			||||||
 | 
					    // 圆心位于弦的垂直平分线
 | 
				
			||||||
 | 
					    // 计算弦的中点
 | 
				
			||||||
 | 
					    const midPoint = p1.Add(delta.Multiply(0.5));
 | 
				
			||||||
 | 
					    // 计算弦心距d
 | 
				
			||||||
 | 
					    // 公式:d = √(r² - a²),r为半径,a为弦长的一半(勾股定理)
 | 
				
			||||||
 | 
					    const d = Math.sqrt(radius * radius - (dist / 2) * (dist / 2));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 垂直平分线单位向量
 | 
				
			||||||
 | 
					    const perpVec = new Vector2(-delta.y, delta.x).Normalize();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 从弦的中点向垂直平分线向量移动弦心距d来计算出圆心的坐标
 | 
				
			||||||
 | 
					    const center = midPoint.Add(perpVec.Multiply(d * -Math.sign(bulge)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const i = center.x - p1.x;
 | 
				
			||||||
 | 
					    const j = center.y - p1.y;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return { gCode, i, j };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export enum NcReductionType {
 | 
				
			||||||
 | 
					    None = 0,
 | 
				
			||||||
 | 
					    Position = 1 << 0,
 | 
				
			||||||
 | 
					    Speed = 1 << 1,
 | 
				
			||||||
 | 
					    Code = 1 << 2,
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 换刀重置
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    SwitchKnifeReset = 1 << 3
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export class Vector2 implements IPoint {
 | 
				
			||||||
 | 
					    static Zero = new Vector2(0, 0);
 | 
				
			||||||
 | 
					    static One = new Vector2(1, 1);
 | 
				
			||||||
 | 
					    static Up = new Vector2(0, 1);
 | 
				
			||||||
 | 
					    static Down = new Vector2(0, -1);
 | 
				
			||||||
 | 
					    static Left = new Vector2(-1, 0);
 | 
				
			||||||
 | 
					    static Right = new Vector2(1, 0);
 | 
				
			||||||
 | 
					    static FromPoint(pt: IPoint) {
 | 
				
			||||||
 | 
					        if (pt instanceof Vector2) return pt as Vector2;
 | 
				
			||||||
 | 
					        return new Vector2(pt.x, pt.y);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    x: number;
 | 
				
			||||||
 | 
					    y: number;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** 获取向量的模长 */
 | 
				
			||||||
 | 
					    get Magnitude() {
 | 
				
			||||||
 | 
					        return Math.sqrt(Math.pow(this.x, 2) + Math.pow(this.y, 2));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** 获取向量的平方模长,这个属性比 `Magnitude` 属性更快 */
 | 
				
			||||||
 | 
					    get SquaredMagnitude() {
 | 
				
			||||||
 | 
					        return Math.pow(this.x, 2) + Math.pow(this.y, 2);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor(x: number, y: number) {
 | 
				
			||||||
 | 
					        this.x = x;
 | 
				
			||||||
 | 
					        this.y = y;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** 克隆向量 */
 | 
				
			||||||
 | 
					    Clone(): Vector2 {
 | 
				
			||||||
 | 
					        return new Vector2(this.x, this.y);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** 计算两个向量之间的距离 */
 | 
				
			||||||
 | 
					    Distance(other: Vector2): number {
 | 
				
			||||||
 | 
					        return Math.sqrt(Math.pow(this.x - other.x, 2) + Math.pow(this.y - other.y, 2));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** 计算两个向量之间的平方距离,这个属性比 `Distance` 属性更快 */
 | 
				
			||||||
 | 
					    SquaredDistance(other: Vector2): number {
 | 
				
			||||||
 | 
					        return Math.pow(this.x - other.x, 2) + Math.pow(this.y - other.y, 2);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** 向量和 */
 | 
				
			||||||
 | 
					    Add(other: Vector2): Vector2 {
 | 
				
			||||||
 | 
					        return new Vector2(this.x + other.x, this.y + other.y);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** 向量差 */
 | 
				
			||||||
 | 
					    Subtract(other: Vector2): Vector2 {
 | 
				
			||||||
 | 
					        return new Vector2(this.x - other.x, this.y - other.y);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** 向量点乘 */
 | 
				
			||||||
 | 
					    Dot(other: Vector2): number {
 | 
				
			||||||
 | 
					        return this.x * other.x + this.y * other.y;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** 向量叉乘 */
 | 
				
			||||||
 | 
					    Cross(other: Vector2): number {
 | 
				
			||||||
 | 
					        return this.x * other.y - this.y * other.x;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** 向量与标量相乘 */
 | 
				
			||||||
 | 
					    Multiply(scalar: number): Vector2 {
 | 
				
			||||||
 | 
					        return new Vector2(this.x * scalar, this.y * scalar);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** 向量归一化 */
 | 
				
			||||||
 | 
					    Normalize(): Vector2 {
 | 
				
			||||||
 | 
					        const magnitude = this.Magnitude;
 | 
				
			||||||
 | 
					        if (magnitude === 0) {
 | 
				
			||||||
 | 
					            return Vector2.Zero;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return new Vector2(this.x / magnitude, this.y / magnitude);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										4528
									
								
								src/processors/processCodeConverter/processCodeConverter.test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4528
									
								
								src/processors/processCodeConverter/processCodeConverter.test.ts
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										114
									
								
								src/processors/processCodeConverter/processCodeConverter.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								src/processors/processCodeConverter/processCodeConverter.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,114 @@
 | 
				
			|||||||
 | 
					import { ConfigBase, ProcessorBase, ProcessorContext, IProcessingItem } from "cut-abstractions";
 | 
				
			||||||
 | 
					import { NcConverter } from "../NcConverter/NcConverter";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 *  加工代码转换器  
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export class ProcessCodeConverterProc extends ProcessorBase<ProcessCodeConverterProcInput, ProcessCodeConverterProcOutput, ProcessCodeConverterProcConfig> {
 | 
				
			||||||
 | 
					    get name(): string {
 | 
				
			||||||
 | 
					        return 'ProcessCodeConverter';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    get version(): string {
 | 
				
			||||||
 | 
					        return '1.0.0';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    /** 正在使用的解析器 */
 | 
				
			||||||
 | 
					    private _usedConverter?: NcConverter;
 | 
				
			||||||
 | 
					    exec(context: ProcessorContext<ProcessCodeConverterProcInput, ProcessCodeConverterProcOutput, ProcessCodeConverterProcConfig>): Promise<void> | void {
 | 
				
			||||||
 | 
					        return new Promise(async (resolve, reject) => {
 | 
				
			||||||
 | 
					            try {
 | 
				
			||||||
 | 
					                resolve()
 | 
				
			||||||
 | 
					            } catch (error) {
 | 
				
			||||||
 | 
					                reject(error);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** 
 | 
				
			||||||
 | 
					     * 精简指令 NC代码精简指令处理  
 | 
				
			||||||
 | 
					     * 兼容注释的行处理  精简指令只处理G代码所在的行
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    handleNcSimpleCode(code: string) {
 | 
				
			||||||
 | 
					        let arr = code.split('\n')
 | 
				
			||||||
 | 
					        let objArr = arr.map((e, i) => {
 | 
				
			||||||
 | 
					            let type = (!e.includes('//') && !e.includes('/**') || e.includes('"//')) ? 'code' : 'remark'
 | 
				
			||||||
 | 
					            let temp = {
 | 
				
			||||||
 | 
					                code: e,
 | 
				
			||||||
 | 
					                index: i,
 | 
				
			||||||
 | 
					                regList: e.match(/[XYZF]([-+]?\d*\.?\d+)/g) || [],
 | 
				
			||||||
 | 
					                type
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return temp
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        let checkLines = objArr.filter(e => e.type == 'code')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 校验对象  存键值
 | 
				
			||||||
 | 
					        let targetObject: any = {}
 | 
				
			||||||
 | 
					        for (const key in checkLines) {
 | 
				
			||||||
 | 
					            let line = checkLines[key]
 | 
				
			||||||
 | 
					            if (line.regList.length > 0) {
 | 
				
			||||||
 | 
					                for (const regVal of line.regList) {
 | 
				
			||||||
 | 
					                    let reg = regVal.match(/([XYZF])([-+]?\d*\.?\d+)/)
 | 
				
			||||||
 | 
					                    if (!reg) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    else {
 | 
				
			||||||
 | 
					                        let FullVal = reg[0]
 | 
				
			||||||
 | 
					                        let valKey = reg[1]
 | 
				
			||||||
 | 
					                        let val = reg[2]
 | 
				
			||||||
 | 
					                        if (Reflect.has(targetObject, valKey)) {
 | 
				
			||||||
 | 
					                            if (targetObject[valKey] == val) {
 | 
				
			||||||
 | 
					                                // 相同  需要精简操作
 | 
				
			||||||
 | 
					                                objArr[line.index].code = objArr[line.index].code.replace(FullVal, ``)
 | 
				
			||||||
 | 
					                            } else {
 | 
				
			||||||
 | 
					                                // 不同 更新校验的值
 | 
				
			||||||
 | 
					                                targetObject[valKey] = val
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        } else {
 | 
				
			||||||
 | 
					                            // 键值 没有  赋给 校验对象
 | 
				
			||||||
 | 
					                            Reflect.set(targetObject, valKey, val)
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        let newCode = objArr.map(e => e.code).join('\n')
 | 
				
			||||||
 | 
					        // 这里 数据中莫名其妙多了个空格 处理下
 | 
				
			||||||
 | 
					        let list = newCode.split(' ').filter(e => e != '')
 | 
				
			||||||
 | 
					        newCode = list.join(' ')
 | 
				
			||||||
 | 
					        return newCode
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type ProcessCodeConverterProcInput = {
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type ProcessCodeConverterProcOutput = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export declare class ProcessCodeConverterProcConfig extends ConfigBase {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					/** 加工流程类型 加工项与加工项直接的流程类型 */
 | 
				
			||||||
 | 
					export enum ProcessStepType {
 | 
				
			||||||
 | 
					    /** 开料加工 */
 | 
				
			||||||
 | 
					    blockProcess = "processBlock",
 | 
				
			||||||
 | 
					    /** 修边加工 */
 | 
				
			||||||
 | 
					    blockBoardProcess = "processBlockBoard",
 | 
				
			||||||
 | 
					    /** 孔加工 */
 | 
				
			||||||
 | 
					    holeProcess = "holeProcess",
 | 
				
			||||||
 | 
					    /** 造型加工 */
 | 
				
			||||||
 | 
					    modelProcess = "modelProcess",
 | 
				
			||||||
 | 
					    /** 槽加工 */
 | 
				
			||||||
 | 
					    grooveProcess = "grooveProcess"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 单一加工项内的业务流程类型 */
 | 
				
			||||||
 | 
					export enum ProcessItemStepType {
 | 
				
			||||||
 | 
					    /** 快速定位  --空程移动 */
 | 
				
			||||||
 | 
					    knifeRapidMove = 'knifeRapidMove'
 | 
				
			||||||
 | 
					    /**  */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										25
									
								
								src/utils/corsWorker.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/utils/corsWorker.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					export class CorsWorker {
 | 
				
			||||||
 | 
					    private readonly url: string | URL;
 | 
				
			||||||
 | 
					    private readonly options?: WorkerOptions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Have this only to trick Webpack into properly transpiling
 | 
				
			||||||
 | 
					    // the url address from the component which uses it
 | 
				
			||||||
 | 
					    constructor(url: string | URL, options?: WorkerOptions) {
 | 
				
			||||||
 | 
					        this.url = url;
 | 
				
			||||||
 | 
					        this.options = options;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async createWorker(): Promise<Worker> {
 | 
				
			||||||
 | 
					        if (import.meta.env.DEV) { // 修复调试模式
 | 
				
			||||||
 | 
					            return new Worker(this.url, this.options);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        const f = await fetch(this.url);
 | 
				
			||||||
 | 
					        const t = await f.text();
 | 
				
			||||||
 | 
					        const b = new Blob([t], {
 | 
				
			||||||
 | 
					            type: 'application/javascript',
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        const url = URL.createObjectURL(b);
 | 
				
			||||||
 | 
					        const worker = new Worker(url, this.options);
 | 
				
			||||||
 | 
					        return worker;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										116
									
								
								src/utils/helper.array.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								src/utils/helper.array.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,116 @@
 | 
				
			|||||||
 | 
					import { AssignByPath, Resolve, type Paths, type PathValue } from "./helper.lang";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 将对象数组按指定字段分组,并返回分组结果的数组。
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @template T - 输入数组中对象的类型。
 | 
				
			||||||
 | 
					 * @param data - 要分组的对象数组。
 | 
				
			||||||
 | 
					 * @param fields - 用于分组对象的键(字段)数组。
 | 
				
			||||||
 | 
					 * @param sort - 一个布尔值,指示是否按键对分组结果进行排序。默认为 `true`。
 | 
				
			||||||
 | 
					 * @param separator - 用于连接字段值以形成分组键的字符串。默认为 `'-'`。
 | 
				
			||||||
 | 
					 * @returns 分组结果的数组
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @example
 | 
				
			||||||
 | 
					 * ```typescript
 | 
				
			||||||
 | 
					 * const data = [
 | 
				
			||||||
 | 
					 *   { category: 'A', type: 'X', value: 10 },
 | 
				
			||||||
 | 
					 *   { category: 'A', type: 'Y', value: 20 },
 | 
				
			||||||
 | 
					 *   { category: 'B', type: 'X', value: 30 },
 | 
				
			||||||
 | 
					 * ];
 | 
				
			||||||
 | 
					 * const grouped = GroupBy(data, ['category', 'type']);
 | 
				
			||||||
 | 
					 * console.log(grouped);
 | 
				
			||||||
 | 
					 * // 输出:
 | 
				
			||||||
 | 
					 * // [
 | 
				
			||||||
 | 
					 * //   {
 | 
				
			||||||
 | 
					 * //     key: 'A-X',
 | 
				
			||||||
 | 
					 * //     keyList: ['A', 'X'],
 | 
				
			||||||
 | 
					 * //     value: [{ category: 'A', type: 'X', value: 10 }],
 | 
				
			||||||
 | 
					 * //     keyObj: { category: 'A', type: 'X' }
 | 
				
			||||||
 | 
					 * //   },
 | 
				
			||||||
 | 
					 * //   {
 | 
				
			||||||
 | 
					 * //     key: 'A-Y',
 | 
				
			||||||
 | 
					 * //     keyList: ['A', 'Y'],
 | 
				
			||||||
 | 
					 * //     value: [{ category: 'A', type: 'Y', value: 20 }],
 | 
				
			||||||
 | 
					 * //     keyObj: { category: 'A', type: 'Y' }
 | 
				
			||||||
 | 
					 * //   },
 | 
				
			||||||
 | 
					 * //   {
 | 
				
			||||||
 | 
					 * //     key: 'B-X',
 | 
				
			||||||
 | 
					 * //     keyList: ['B', 'X'],
 | 
				
			||||||
 | 
					 * //     value: [{ category: 'B', type: 'X', value: 30 }],
 | 
				
			||||||
 | 
					 * //     keyObj: { category: 'B', type: 'X' }
 | 
				
			||||||
 | 
					 * //   }
 | 
				
			||||||
 | 
					 * // ]
 | 
				
			||||||
 | 
					 * ```
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export function GroupBy<T extends object, TKeys extends (Paths<T>)[]>(
 | 
				
			||||||
 | 
					    data: T[],
 | 
				
			||||||
 | 
					    fields: TKeys,
 | 
				
			||||||
 | 
					    sort = true,
 | 
				
			||||||
 | 
					    separator = '-',
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    // eslint-disable-next-line @typescript-eslint/no-explicit-any
 | 
				
			||||||
 | 
					    const groupList = {} as any;
 | 
				
			||||||
 | 
					    const groupArray = [] as IGrouping<T, { [Key in TKeys[number]]: PathValue<T, Key> }>[];
 | 
				
			||||||
 | 
					    if (fields.length === 0) return [];
 | 
				
			||||||
 | 
					    for (const item of data) {
 | 
				
			||||||
 | 
					        const keyList = fields.map((field) => Resolve(item, field));
 | 
				
			||||||
 | 
					        const key = keyList.join(separator);
 | 
				
			||||||
 | 
					        groupList[key] = groupList[key] || [];
 | 
				
			||||||
 | 
					        groupList[key].push(item);
 | 
				
			||||||
 | 
					        groupList[key].keyList = keyList;
 | 
				
			||||||
 | 
					        const keyObj = {} as T;
 | 
				
			||||||
 | 
					        fields.forEach((t) => {
 | 
				
			||||||
 | 
					            AssignByPath(keyObj, t, Resolve(item, t) as PathValue<T, typeof t>);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        groupList[key].keyObj = keyObj;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    for (const key in groupList) {
 | 
				
			||||||
 | 
					        groupArray.push({
 | 
				
			||||||
 | 
					            key,
 | 
				
			||||||
 | 
					            keyList: groupList[key].keyList,
 | 
				
			||||||
 | 
					            value: groupList[key],
 | 
				
			||||||
 | 
					            keyObj: groupList[key].keyObj,
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (sort)
 | 
				
			||||||
 | 
					        return groupArray.sort(function (a, b) {
 | 
				
			||||||
 | 
					            return a.key.localeCompare(b.key, 'zh-CN', { numeric: true });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    else return groupArray;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 将对象数组按指定字段分组,并返回分组结果的数组。
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export interface IGrouping<T, TKeyRecord> {
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 分组的键,若有多个键,则用连接符连接
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    key: string;
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 分组的键列表
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    keyList: unknown[];
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 分组的对象数组
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    value: T[];
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 分组键对象,其属性名为分组键名,属性值为分组键
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    keyObj: TKeyRecord;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					declare global {
 | 
				
			||||||
 | 
					    interface Array<T> {
 | 
				
			||||||
 | 
					        GroupBy: <TKeys extends (Paths<T>)[]>(
 | 
				
			||||||
 | 
					            fields: TKeys,
 | 
				
			||||||
 | 
					            sort?: boolean,
 | 
				
			||||||
 | 
					            separator?: string,
 | 
				
			||||||
 | 
					        ) => Array<IGrouping<T, { [Key in TKeys[number]]: PathValue<T, Key> }>>;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Array.prototype.GroupBy = function (fields, sort, separator) {
 | 
				
			||||||
 | 
					    return GroupBy(this, fields, sort, separator);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										21
									
								
								src/utils/helper.async.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/utils/helper.async.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 异步等待
 | 
				
			||||||
 | 
					 * @param ms 等待毫秒数
 | 
				
			||||||
 | 
					 * @param value 等待完成后返回的值
 | 
				
			||||||
 | 
					 * @returns 
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export function AsyncDelay<T>(ms: number, value?: T) {
 | 
				
			||||||
 | 
					    return new Promise<T>((resolve) => setTimeout(resolve, ms, value));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export async function AsyncWaitUntil(predicate: () => boolean, waitTime = 100) {
 | 
				
			||||||
 | 
					    while (!predicate()) {
 | 
				
			||||||
 | 
					        await AsyncDelay(waitTime);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export async function AsyncWaitForChange(obj: () => any, waitTime = 100) {
 | 
				
			||||||
 | 
					    while (obj() === undefined) {
 | 
				
			||||||
 | 
					        await AsyncDelay(waitTime);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										128
									
								
								src/utils/helper.lang.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								src/utils/helper.lang.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,128 @@
 | 
				
			|||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 检查枚举值中是否包含某个标志位
 | 
				
			||||||
 | 
					 * @param $enum 枚举值
 | 
				
			||||||
 | 
					 * @param flag 标志位
 | 
				
			||||||
 | 
					 * @returns 是否包含标志位
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export function HasFlag($enum: number, ...flags: number[]) {
 | 
				
			||||||
 | 
					    return flags.every(flag => ($enum & flag) === flag);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 深拷贝
 | 
				
			||||||
 | 
					 * @param obj 对象
 | 
				
			||||||
 | 
					 * @returns 深拷贝后的对象
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export function Clone<T>(obj: T): T {
 | 
				
			||||||
 | 
					    return JSON.parse(JSON.stringify(obj));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function ToPercent(num: number, precision = 2) {
 | 
				
			||||||
 | 
					    return (num * 100).toFixed(precision) + '%';
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** 访问对象的成员 */
 | 
				
			||||||
 | 
					// eslint-disable-next-line @typescript-eslint/no-explicit-any
 | 
				
			||||||
 | 
					export function Resolve<T extends object, TPath extends Paths<T>>(obj: T, path: TPath): PathValue<T, TPath> | T {
 | 
				
			||||||
 | 
					    return path.split('.').reduce(function (item, key) {
 | 
				
			||||||
 | 
					        return item ? (item as any)[key] : null;
 | 
				
			||||||
 | 
					    }, obj);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @description 根据字符串路径向对象深层嵌套的属性赋值。
 | 
				
			||||||
 | 
					 * 如果路径中的对象不存在,则会自动创建。
 | 
				
			||||||
 | 
					 * @param obj 要修改的对象。注意:这个函数会直接修改传入的对象(in-place mutation)。
 | 
				
			||||||
 | 
					 * @param path 属性路径字符串,例如 "a.b.c"。
 | 
				
			||||||
 | 
					 * @param value 要赋给目标属性的值。
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @example
 | 
				
			||||||
 | 
					 * const obj = { a: { b: { c: 1 } } };
 | 
				
			||||||
 | 
					 * AssignByPath(obj, "a.b.c", 2);
 | 
				
			||||||
 | 
					 * console.log(obj); // { a: { b: { c: 2 } } }
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					// eslint-disable-next-line @typescript-eslint/no-explicit-any
 | 
				
			||||||
 | 
					export function AssignByPath<T extends object, TPath extends Paths<T>>(obj: T, path: TPath, value: PathValue<T, TPath>) {
 | 
				
			||||||
 | 
					    const keys = path.split(".");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // eslint-disable-next-line @typescript-eslint/no-explicit-any
 | 
				
			||||||
 | 
					    let current: any = obj;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (let i = 0; i < keys.length; i++) {
 | 
				
			||||||
 | 
					        // eslint-disable-next-line @typescript-eslint/no-explicit-any
 | 
				
			||||||
 | 
					        let key = keys[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 如果当前层级的对象不存在,或者不是一个对象,就需要创建它
 | 
				
			||||||
 | 
					        // 这是一个关键步骤,确保路径是可写的
 | 
				
			||||||
 | 
					        if (current[key] === undefined || typeof current[key] !== 'object' || current[key] === null) {
 | 
				
			||||||
 | 
					            // 检查下一个键是否是数字,来决定创建对象还是数组。
 | 
				
			||||||
 | 
					            // 这是一个启发式方法,对于像 'a.0.b' 这样的路径,它会创建 { a: [ { b: ... } ] }
 | 
				
			||||||
 | 
					            // 注意:这个逻辑对于严格的类型安全来说是一个简化。
 | 
				
			||||||
 | 
					            // 我们的 Paths<T> 类型目前不支持数字索引,所以这个逻辑是为了运行时健壮性。
 | 
				
			||||||
 | 
					            const nextKey = keys[i + 1];
 | 
				
			||||||
 | 
					            current[key] = /^\d+$/.test(nextKey) ? [] : {};
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 移动到下一层
 | 
				
			||||||
 | 
					        current = current[key];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // 获取最后一个键,并进行赋值
 | 
				
			||||||
 | 
					    const lastKey = keys[keys.length - 1];
 | 
				
			||||||
 | 
					    current[lastKey] = value;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 检查对象是否是构造函数的直接实例(不检查继承关系)
 | 
				
			||||||
 | 
					 * @param obj 对象
 | 
				
			||||||
 | 
					 * @param constructor 构造函数
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export function IsDirectInstanceOf(obj: object, constructor: Function) {
 | 
				
			||||||
 | 
					    // 确保 obj 是一个对象,并且 Constructor 是一个函数/类
 | 
				
			||||||
 | 
					    if (obj === null || typeof obj !== 'object' && typeof obj !== 'function') {
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (typeof constructor !== 'function') {
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 比较对象的直接原型与构造函数的 prototype 属性
 | 
				
			||||||
 | 
					    return Object.getPrototypeOf(obj) === constructor.prototype;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @description 递归生成对象所有可能的属性访问路径。
 | 
				
			||||||
 | 
					 * 类型T必须是object,不支持数组对象
 | 
				
			||||||
 | 
					 * 例如:{ a: { b: string } } -> "a" | "a.b"
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export type Paths<T> = T extends object
 | 
				
			||||||
 | 
					    ? {
 | 
				
			||||||
 | 
					        [K in keyof T]:
 | 
				
			||||||
 | 
					        // K 本身是一个有效的路径
 | 
				
			||||||
 | 
					        | `${K & string}`
 | 
				
			||||||
 | 
					        // 如果 T[K] 也是一个对象,则递归地为其生成路径,并加上前缀 "K."
 | 
				
			||||||
 | 
					        // 使用NonNullable来解决T[K]可能为null | undefined的情况
 | 
				
			||||||
 | 
					        | (NonNullable<T[K]> extends object ?
 | 
				
			||||||
 | 
					            // 对于数组类型的子对象,不进行解析,防止TS类型死循环
 | 
				
			||||||
 | 
					            NonNullable<T[K]> extends any[] ? never
 | 
				
			||||||
 | 
					            : `${K & string}.${NonNullable<Paths<T[K]>>}` : never);
 | 
				
			||||||
 | 
					    }[keyof T] // 取出所有可能路径的联合类型
 | 
				
			||||||
 | 
					    : never;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					* @description 根据给定的路径字符串 P,在对象 T 中查找并返回对应值的类型。
 | 
				
			||||||
 | 
					* 例如:PathValue<{ a: { b: string } }, "a.b"> -> string
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					export type PathValue<T, P extends string> =
 | 
				
			||||||
 | 
					    // 使用条件类型和 infer 来分割路径字符串 P
 | 
				
			||||||
 | 
					    P extends `${infer Key}.${infer Rest}`
 | 
				
			||||||
 | 
					    ? // 如果 Key 是 T 的一个键
 | 
				
			||||||
 | 
					    Key extends keyof T
 | 
				
			||||||
 | 
					    ? // 则在 T[Key] 类型中递归查找剩余路径 Rest 的值类型
 | 
				
			||||||
 | 
					    NonNullable<PathValue<T[Key], Rest>>
 | 
				
			||||||
 | 
					    : never
 | 
				
			||||||
 | 
					    : // 如果路径 P 不包含 ".", 说明是最后一层
 | 
				
			||||||
 | 
					    P extends keyof T
 | 
				
			||||||
 | 
					    ? // 直接返回 T[P] 的类型
 | 
				
			||||||
 | 
					    T[P]
 | 
				
			||||||
 | 
					    : never;
 | 
				
			||||||
							
								
								
									
										33
									
								
								src/utils/helper.string.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/utils/helper.string.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
				
			|||||||
 | 
					export function IsNullOrEmpty(str?: string | null) {
 | 
				
			||||||
 | 
					    return str === null || str === undefined || str === "";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function IsNullOrWhitespace(str?: string | null) {
 | 
				
			||||||
 | 
					    return str === null || str === undefined || str.trim() === "";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					declare global {
 | 
				
			||||||
 | 
					    interface String {
 | 
				
			||||||
 | 
					        /** 将字符串转换为 camelCase 格式 */
 | 
				
			||||||
 | 
					        ToCamelCase(): string
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					String.prototype.ToCamelCase = function (this: string) {
 | 
				
			||||||
 | 
					    return ToCamelCase(this);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 将字符串转换为 camelCase 格式
 | 
				
			||||||
 | 
					 * @param str 输入字符串
 | 
				
			||||||
 | 
					 * @returns camelCase 格式的字符串
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export function ToCamelCase(str: string): string {
 | 
				
			||||||
 | 
					    return str
 | 
				
			||||||
 | 
					        .replace(/([-_][a-z])/g, group =>
 | 
				
			||||||
 | 
					            group.toUpperCase()
 | 
				
			||||||
 | 
					                .replace('-', '')
 | 
				
			||||||
 | 
					                .replace('_', '')
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        .replace(/^[A-Z]/, firstChar => firstChar.toLowerCase());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										35
									
								
								src/utils/helper.version.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								src/utils/helper.version.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,35 @@
 | 
				
			|||||||
 | 
					export class Version {
 | 
				
			||||||
 | 
					    major: number;
 | 
				
			||||||
 | 
					    minor: number;
 | 
				
			||||||
 | 
					    build: number;
 | 
				
			||||||
 | 
					    revision: number;
 | 
				
			||||||
 | 
					    toString(): string {
 | 
				
			||||||
 | 
					        return `${this.major}.${this.minor}.${this.build}.${this.revision}`
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    constructor(major: number, minor: number, build: number = 0, revision: number = 0) {
 | 
				
			||||||
 | 
					        this.major = major;
 | 
				
			||||||
 | 
					        this.minor = minor;
 | 
				
			||||||
 | 
					        this.build = build;
 | 
				
			||||||
 | 
					        this.revision = revision;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    compareTo(obj: Version): number {
 | 
				
			||||||
 | 
					        if (this.major > obj.major) return 1;
 | 
				
			||||||
 | 
					        if (this.major < obj.major) return -1;
 | 
				
			||||||
 | 
					        if (this.minor > obj.minor) return 1;
 | 
				
			||||||
 | 
					        if (this.minor < obj.minor) return -1;
 | 
				
			||||||
 | 
					        if (this.build > obj.build) return 1;
 | 
				
			||||||
 | 
					        if (this.build < obj.build) return -1;
 | 
				
			||||||
 | 
					        if (this.revision > obj.revision) return 1;
 | 
				
			||||||
 | 
					        if (this.revision < obj.revision) return -1;
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function parseVersion(verStr: string): Version {
 | 
				
			||||||
 | 
					    const arr = verStr.split(".").map(c => parseInt(c));
 | 
				
			||||||
 | 
					    if (arr.length < 2 || arr.length > 4)
 | 
				
			||||||
 | 
					        throw new Error("无效的版本号");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return new Version(arr[0], arr[1], arr[2] || 0, arr[3] || 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										14
									
								
								src/utils/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/utils/index.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @package @mes-processors/libs/utils
 | 
				
			||||||
 | 
					 * @author CZY
 | 
				
			||||||
 | 
					 * @description 帮助类库,这个导出仅供内部使用,不在打包中暴露,在这个文件中使用导出时,不要在路径中使用'@',否则模块无法加载
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export * from "./corsWorker";
 | 
				
			||||||
 | 
					export * from "./helper.array";
 | 
				
			||||||
 | 
					export * from "./helper.async";
 | 
				
			||||||
 | 
					export * from "./helper.lang";
 | 
				
			||||||
 | 
					export * from "./helper.string";
 | 
				
			||||||
 | 
					export * from "./helper.version";
 | 
				
			||||||
 | 
					export * from "./utilTypes";
 | 
				
			||||||
							
								
								
									
										27
									
								
								src/utils/utilTypes.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/utils/utilTypes.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 读取泛型T中的KEY作为类型,支持嵌套属性
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export type NestedKey<T extends object> = {
 | 
				
			||||||
 | 
					    [K in keyof T & string]: T[K] extends object ? `${K}` | `${K}.${NestedKey<T[K]>}` : `${K}`;
 | 
				
			||||||
 | 
					}[keyof T & string];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 读取泛型T中的VALUE作为类型,支持嵌套属性,你可能需要把类型T设为标量(`as const`)
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export type NestedValue<T extends object> = {
 | 
				
			||||||
 | 
					    [K in keyof T & string]: T[K] extends object ? T[K] | NestedValue<T[K]> : T[K];
 | 
				
			||||||
 | 
					}[keyof T & string];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 将泛型T中的属性P设置为必选
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export type WithRequired<T, K extends keyof T> = T & { [P in K]-?: T[P] }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 递归地将泛型T的所有属性变为只读
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export type DeepReadonly<T> = T extends object
 | 
				
			||||||
 | 
					  ? {
 | 
				
			||||||
 | 
					      readonly [P in keyof T]: DeepReadonly<T[P]>;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  : T;
 | 
				
			||||||
							
								
								
									
										1
									
								
								src/vite-env.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/vite-env.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					/// <reference types="vite/client" />
 | 
				
			||||||
							
								
								
									
										39
									
								
								tsconfig.app.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								tsconfig.app.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  // TODO: Warn: 在进行TS类型检查的时候会检查到workflow工作区中的文件,原因未知
 | 
				
			||||||
 | 
					  "compilerOptions": {
 | 
				
			||||||
 | 
					    "lib": [
 | 
				
			||||||
 | 
					      "ES2020",
 | 
				
			||||||
 | 
					      "ES2021",
 | 
				
			||||||
 | 
					      "ESNext",
 | 
				
			||||||
 | 
					      "DOM",
 | 
				
			||||||
 | 
					      "DOM.Iterable"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    "noEmit": true,
 | 
				
			||||||
 | 
					    "target": "esnext",
 | 
				
			||||||
 | 
					    "module": "ESNext",
 | 
				
			||||||
 | 
					    "moduleResolution": "Bundler",
 | 
				
			||||||
 | 
					    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
 | 
				
			||||||
 | 
					    "baseUrl": ".",
 | 
				
			||||||
 | 
					    "paths": {
 | 
				
			||||||
 | 
					      // 为了保证导入不与被引入项目冲突,不应该配置'@/*'别名
 | 
				
			||||||
 | 
					      "@libs/*": [
 | 
				
			||||||
 | 
					        "./src/*"
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    /* Linting */
 | 
				
			||||||
 | 
					    "strict": true,
 | 
				
			||||||
 | 
					    "erasableSyntaxOnly": false,
 | 
				
			||||||
 | 
					    "noFallthroughCasesInSwitch": true,
 | 
				
			||||||
 | 
					    "noUncheckedSideEffectImports": true,
 | 
				
			||||||
 | 
					    "composite": true
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "include": [
 | 
				
			||||||
 | 
					    "src/**/*.ts",
 | 
				
			||||||
 | 
					    "src/**/*.tsx",
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					  "exclude": [
 | 
				
			||||||
 | 
					    "src/**/__tests__/*",
 | 
				
			||||||
 | 
					    "dist",
 | 
				
			||||||
 | 
					    "node_modules/**"
 | 
				
			||||||
 | 
					  ]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										7
									
								
								tsconfig.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								tsconfig.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "files": [],
 | 
				
			||||||
 | 
					  "references": [
 | 
				
			||||||
 | 
					    { "path": "./tsconfig.app.json" },
 | 
				
			||||||
 | 
					    { "path": "./tsconfig.node.json" }
 | 
				
			||||||
 | 
					  ]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										25
									
								
								tsconfig.node.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								tsconfig.node.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "compilerOptions": {
 | 
				
			||||||
 | 
					    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
 | 
				
			||||||
 | 
					    "target": "ES2023",
 | 
				
			||||||
 | 
					    "lib": ["ES2023"],
 | 
				
			||||||
 | 
					    "module": "ESNext",
 | 
				
			||||||
 | 
					    "skipLibCheck": true,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Bundler mode */
 | 
				
			||||||
 | 
					    "moduleResolution": "bundler",
 | 
				
			||||||
 | 
					    "allowImportingTsExtensions": true,
 | 
				
			||||||
 | 
					    "verbatimModuleSyntax": true,
 | 
				
			||||||
 | 
					    "moduleDetection": "force",
 | 
				
			||||||
 | 
					    "noEmit": true,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Linting */
 | 
				
			||||||
 | 
					    "strict": true,
 | 
				
			||||||
 | 
					    "noUnusedLocals": true,
 | 
				
			||||||
 | 
					    "noUnusedParameters": true,
 | 
				
			||||||
 | 
					    "erasableSyntaxOnly": true,
 | 
				
			||||||
 | 
					    "noFallthroughCasesInSwitch": true,
 | 
				
			||||||
 | 
					    "noUncheckedSideEffectImports": true,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "include": ["vite.config.ts"]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										34
									
								
								vite.config.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								vite.config.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
				
			|||||||
 | 
					/// <reference types="vitest/config" />
 | 
				
			||||||
 | 
					import { defineConfig } from 'vite'
 | 
				
			||||||
 | 
					import { nodePolyfills } from 'vite-plugin-node-polyfills';
 | 
				
			||||||
 | 
					import { resolve } from 'node:path';
 | 
				
			||||||
 | 
					import dts from 'vite-plugin-dts';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let basePath = process.env.basePath ?? '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// https://vite.dev/config/
 | 
				
			||||||
 | 
					export default defineConfig({
 | 
				
			||||||
 | 
					  base: basePath,
 | 
				
			||||||
 | 
					  plugins: [
 | 
				
			||||||
 | 
					    nodePolyfills(),
 | 
				
			||||||
 | 
					    dts({rollupTypes: true, tsconfigPath: './tsconfig.app.json',insertTypesEntry: true}),
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					  build: {
 | 
				
			||||||
 | 
					    modulePreload: {
 | 
				
			||||||
 | 
					      resolveDependencies() {
 | 
				
			||||||
 | 
					        return [];
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    lib: {
 | 
				
			||||||
 | 
					      entry: resolve(__dirname, 'src/index.ts'),
 | 
				
			||||||
 | 
					      name: 'MesProcessors',
 | 
				
			||||||
 | 
					      fileName(format) {
 | 
				
			||||||
 | 
					          return `mes-processors.${format}.js`
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      formats: ['es', 'umd', 'iife']
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  esbuild: {
 | 
				
			||||||
 | 
					    drop: process.env.NODE_ENV === 'production' ? ['console', 'debugger'] : [],
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
		Reference in New Issue
	
	Block a user