import { ConfigBase, ProcessorBase, ProcessorContext } from "cut-abstractions"; /** * 获取造型在开料大板的坐标 * * 输入的造型数据为 要处理的造型数据 */ export class ModelProcessPointsProc extends ProcessorBase { get name(): string { return 'ModelProcessPoints'; } get version(): string { return '1.0.0'; } exec(context: ProcessorContext): Promise | void { return new Promise(async (resolve, reject) => { try { if (context.input) { if (context.input.block) { // if (Array.isArray(context.input.block.models) && context.input.block.models.length > 0) { /** 板件的坐标X */ let placeX = context.input.block.x /** 板件的坐标Y */ let placeY = context.input.block.y let output: ModelProcessPointsOutput = { block: { id: context.input.block.id, positionType: context.input.block.positionType || 0, models: [], width: context.input.block.width, length: context.input.block.length, offsetInfo: context.input.block.offsetInfo } } /** * 提要: * 1、这里的造型数据 都是 基于板件(小板)的正面的点阵数据 * 2、坐标转换 依据2个要素进行转换 【板件(小板)的优化坐标】 和 【板件(小板)的放置方式】 * * 先处理放置方式 在处理 优化坐标 会简单很多 */ let resBlock = this.handleByPositionType(context.input.block, context.input.targetPosition) let res1 = this.handleByPlaceXY(resBlock.models, placeX, placeY) resBlock.models = res1 output.block = { ...output.block, ...resBlock, } context.output = output resolve() } else { reject('ModelProcessPoints error: input.block is undefined;') } } else { reject('ModelProcessPoints error: input is undefined;') } resolve() } catch (error) { reject(error); } }); } /** * 根据小板的放置方式进行偏移 * * 提要:models内的造型数据 都是以小板正面 为基准 * 即 PositionType.FRONT * 需要 以下几种情况 * 加工项所在的面 -- 2种 正 反 -- 但实际 在改处理器应该是不考虑的 * 小板放置方式 -- 8 种 详见 PositionType 处理器入参 默认为 PositionType.FRONT * * 细节: * 加工项 为正面 且放置方式为正面的 无需操作 直接输出,其它情况 都需要做处理 * * 如果有 翻面的情况 弧度值需要取反 * * 思考: 坐标转换的实质 其实 也就是以下几种行为 * 面与面的行为: 翻面(a 面到 b 面 ) * 单面内的行为: 左转 右转 翻转 * * 这里其实 可以有个流程 * 先判定 是不是要 翻面 * 然后再去 做 单面内的行为 相关的坐标转换 将问题集中在一个面的操作上 * * PositionType XXX 转到 PositionType XX 无非就是 【左转 或 右转 或 翻转】 或者 先 翻面 然后 【左转 或 右转 或 翻转】 * 那么 就 * 有翻面 先 翻面 然后 再 【左| 右 | 翻】 转 * * 注: 这里的操作 都依据绘图可视的X Y 轴进行处理 * block.width 对应 Y轴的值 * block.length 对应 x轴的值 */ handleByPositionType(block: ModelProcessPointsInputBlock, targetPosition: PositionType) { /** 造型输出的数据 */ let models: ModelProcessItem[] = [] let _width = block.width let _length = block.length let temp = JSON.parse(JSON.stringify(block)) let resBlock: ModelProcessPointsInputBlock = { ...temp } /** 默认 正面 */ if (resBlock.positionType == undefined) { resBlock.positionType = PositionType.FRONT } //#region 板件 进行分析 翻面 以及 行为 let face = this.getFace(resBlock.positionType) let targetFace = this.getFace(targetPosition) if (face == -1) { // 异常情况 console.log(`block-${resBlock.id}:block.positionType is invalid`) } if (targetFace == -1) { // 异常情况 console.log(`targetFace:targetFace is invalid`) } // 判定是否要翻面 const isTurn = !(face == targetFace) /** 翻面后的 放置方式 */ let tempPosition = resBlock.positionType if (isTurn) { tempPosition = this.getPositionAfterTurnFace(resBlock.positionType) } // 获取行为 左|右|翻转|不操作 const action = this.getDir(tempPosition, targetPosition) //#endregion // 处理造型的部分 for (const i in resBlock.models) { let model = { ...resBlock.models[i] } /** 如果要 翻面 那就先把面 翻过来 */ if (isTurn) { // 翻面 x 不变 Y 变 model = this.change_turnFace(model, _width) // 然后 弧度值要取反 model = this.reverseBuls(model) } /** * 根据 行为标识 转换坐标 * 注: 左转 或者时右转 需要 转换 板件(小板)的 长宽值 * */ switch (action) { case 'doNothing': // 啥事也不做 break; case 'turnAround': // 翻转 x 变 y 也变 model = this.change_turnAround(model, _length, _width) break; case 'turnLeft': model = this.change_turnLeft(model, _length, _width) break; case 'turnRight': model = this.change_turnRight(model, _length, _width) break; default: break; } models.push(model) } /** 左转 或者 右转 长宽值 要互换 */ if (action == 'turnLeft' || action == 'turnRight') { resBlock = { ...resBlock, width: _length, length: _width, } } /** 更加行为 以及是否 翻转 转换 板件的偏移值 */ if (isTurn) { // 翻面 左右封边互换 上下不变 resBlock.offsetInfo = { ...resBlock.offsetInfo, top: resBlock.offsetInfo.bottom, bottom: resBlock.offsetInfo.top } } switch (action) { case 'turnAround': // 翻转 resBlock.offsetInfo = { top: resBlock.offsetInfo.bottom, bottom: resBlock.offsetInfo.top, left: resBlock.offsetInfo.right, right: resBlock.offsetInfo.left } break; case 'turnLeft': resBlock.offsetInfo = { top: resBlock.offsetInfo.right, right: resBlock.offsetInfo.bottom, bottom: resBlock.offsetInfo.left, left: resBlock.offsetInfo.top } break case 'turnRight': resBlock.offsetInfo = { top: resBlock.offsetInfo.left, left: resBlock.offsetInfo.bottom, bottom: resBlock.offsetInfo.right, right: resBlock.offsetInfo.top } break default: break; } return resBlock } /** 获取翻面 后的 放置方式 */ getPositionAfterTurnFace(v: PositionType) { let res = transitions_PositionTurnFace[v] return res } /** 获取行为 左|右|翻转|不需要操作 */ getDir(v1: PositionType, v2: PositionType) { let flag: RotationAction = 'doNothing' try { flag = transitions_PositionToAction[v1][v2] } catch (error) { console.log('逻辑异常!请保证 v1 v2 的放置方式处在同一个面上,或者输入的值在转换关系中没有匹配的值') flag = 'doNothing' } return flag } /** 右转 * @param model 造型数据 * @param valueX 排版长 */ change_turnRight(model: ModelProcessItem, valueX: number) { let newModel = { ...model } for (const i in newModel.pts) { newModel.pts[i] = { x: valueX - newModel.pts[i].y, y: newModel.pts[i].x } } return newModel } /** 左转 * @param model 造型数据 * @param valueX 排版长 */ change_turnLeft(model: ModelProcessItem, valueX: number) { let newModel = { ...model } for (const i in newModel.pts) { newModel.pts[i] = { x: newModel.pts[i].y, y: valueX - newModel.pts[i].x } } return newModel } /** 翻转 改变 xy 坐标 * @param model 造型数据 * @param valueX 排版长 * @param valueY 排版宽 */ change_turnAround(model: ModelProcessItem, valueX: number, valueY: number) { let newModel = { ...model } for (const i in newModel.pts) { newModel.pts[i] = { x: valueX - newModel.pts[i].x, y: valueY - newModel.pts[i].y } } return newModel } /**翻面 改变 y坐标 */ change_turnFace(model: ModelProcessItem, valueY: number) { let newModel = { ...model } for (const i in newModel.pts) { newModel.pts[i].y = valueY - newModel.pts[i].y } return newModel } /** 给 弧度值 取反 */ reverseBuls(model: ModelProcessItem) { let newModel = { ...model } for (const i in newModel.buls) { newModel.buls[i] = -newModel.buls[i] } return newModel } /**正面的放置方式 集合*/ frontArr = [ PositionType.FRONT, PositionType.FRONT_TURN_BACK, PositionType.FRONT_TURN_LEFT, PositionType.FRONT_TURN_RIGHT ] /** 反面的放置方式 集合*/ backArr = [ PositionType.BACK, PositionType.BACK_TURN_BACK, PositionType.BACK_TURN_LEFT, PositionType.BACK_TURN_RIGHT ] /** 根据放置方式 获取面 */ getFace(positionValue: PositionType) { let res = -1 if (this.frontArr.includes(positionValue)) { res = FaceType.FRONT } if (this.backArr.includes(positionValue)) { res = FaceType.BACK } return res } /** 根据 优化后的坐标XY便宜 */ handleByPlaceXY(models: ModelProcessItem[], placeX: number, placeY: number) { let newModels: ModelProcessItem[] = [] for (const model of models) { let newModel: ModelProcessItem = { ...model } let newPts = [] for (const k in newModel.pts) { let p = { x: model.pts[k].x + placeX, y: model.pts[k].y + placeY } newPts.push(p) } newModel.pts = newPts newModels.push(newModel) } return newModels } } /** 处理器输入-- 获取造型在大板的刀路 */ export type ModelProcessPointsInput = { /** 小板数据 */ block: ModelProcessPointsInputBlock, /** 小板的最终的放置位置 */ targetPosition: PositionType } /** 处理器输入--小板 -- 获取造型在大板的刀路 */ export type ModelProcessPointsInputBlock = { /** 板件唯一标识 */ id: string | number, /** 板件基于大板的 坐标X */ x: number, /** 板件基于大板的 坐标y */ y: number, /** 板件(小板)长 */ length: number, /** 板件(小板)宽 */ width: number, /** 造型数据 依据放置方式positionType 下的造型数据 默认为 依据放置方式positionType.FRONT 的造型数据 */ models: ModelProcessItem[], /** 板件的原放置方式 默认为正面(0) 不传则为正面 原 placestyle*/ positionType?: PositionType, /** 偏移值 */ offsetInfo: OffsetInfo } /** 板件 上下左右 偏移值信息 */ export type OffsetInfo = { top: number, bottom: number, left: number, right: number, } /** 处理器输出--小板 -- 获取造型在大板的刀路 */ export type ModelProcessPointsOutputBlock = { /** 板件唯一标识 */ id: string | number /** 放置方式 */ positionType: PositionType /** 造型数据 */ models: ModelProcessItem[] /** 板件(小板)长 */ length: number, /** 板件(小板)宽 */ width: number, /** 偏移值 */ offsetInfo: OffsetInfo } /** 处理器输出-- 获取造型在大板的刀路 */ export type ModelProcessPointsOutput = { block: ModelProcessPointsOutputBlock } /** 处理器配置-- 获取造型在大板的刀路 暂无 */ export declare class ModelProcessPointsProcConfig extends ConfigBase { } /** 造型类 */ export interface ModelProcessItem { /** 加工项唯一标识 */ id?: string | number /** * 加工点数组 */ pts: IPoint[]; /** * 凸度数组 */ buls: number[]; /** 加工面 */ face: FaceType } /** 加工面 */ export enum FaceType { /** 正面 */ FRONT = 0, /** 反面 */ BACK = 1, } /** 点坐标类 */ export interface IPoint { x: number, y: number; } /** 小板的放置方式 */ export enum PositionType { /** 正面 */ FRONT = 0, /** 正面右转 */ FRONT_TURN_RIGHT = 1, /** 正面后转 */ FRONT_TURN_BACK = 2, /** 正面左转 */ FRONT_TURN_LEFT = 3, /** 反面 */ BACK = 4, /** 反面右转 */ BACK_TURN_RIGHT = 5, /** 反面后转 */ BACK_TURN_BACK = 6, /** 反面左转 */ BACK_TURN_LEFT = 7, } /** 行为类型 */ export type RotationAction = 'doNothing' | 'turnLeft' | 'turnRight' | 'turnAround' /** * 原放置方式 依据 目标放置方式 转 行为的 转换关系 * * 注:原放置方式 为 翻面 转换后 的数值 * 若要支持 翻转转换前 需对内容进一步填充 */ export const transitions_PositionToAction: any = { [PositionType.FRONT]: { [PositionType.FRONT_TURN_BACK]: 'turnAround', [PositionType.FRONT_TURN_LEFT]: 'turnLeft', [PositionType.FRONT_TURN_RIGHT]: 'turnRight', [PositionType.FRONT]: 'doNothing' }, [PositionType.FRONT_TURN_LEFT]: { [PositionType.FRONT]: 'turnRight', [PositionType.FRONT_TURN_RIGHT]: 'turnAround', [PositionType.FRONT_TURN_BACK]: 'turnLeft', [PositionType.FRONT_TURN_LEFT]: 'doNothing' }, [PositionType.FRONT_TURN_RIGHT]: { [PositionType.FRONT]: 'turnLeft', [PositionType.FRONT_TURN_LEFT]: 'turnAround', [PositionType.FRONT_TURN_BACK]: 'turnRight', [PositionType.FRONT_TURN_RIGHT]: 'doNothing' }, [PositionType.FRONT_TURN_BACK]: { [PositionType.FRONT]: 'turnAround', [PositionType.FRONT_TURN_LEFT]: 'turnRight', [PositionType.FRONT_TURN_RIGHT]: 'turnLeft', [PositionType.FRONT_TURN_BACK]: 'doNothing' }, [PositionType.BACK]: { [PositionType.BACK_TURN_BACK]: 'turnAround', [PositionType.BACK_TURN_LEFT]: 'turnLeft', [PositionType.BACK_TURN_RIGHT]: 'turnRight', [PositionType.BACK]: 'doNothing' }, [PositionType.BACK_TURN_LEFT]: { [PositionType.BACK]: 'turnRight', [PositionType.BACK_TURN_RIGHT]: 'turnAround', [PositionType.BACK_TURN_BACK]: 'turnLeft', [PositionType.BACK_TURN_LEFT]: 'doNothing' }, [PositionType.BACK_TURN_RIGHT]: { [PositionType.BACK]: 'turnLeft', [PositionType.BACK_TURN_LEFT]: 'turnAround', [PositionType.BACK_TURN_BACK]: 'turnRight', [PositionType.BACK_TURN_RIGHT]: 'doNothing' }, [PositionType.BACK_TURN_BACK]: { [PositionType.BACK]: 'turnAround', [PositionType.BACK_TURN_LEFT]: 'turnRight', [PositionType.BACK_TURN_RIGHT]: 'turnLeft', [PositionType.BACK_TURN_BACK]: 'doNothing' } } /** 放置方式 翻转后的转换关系 */ export const transitions_PositionTurnFace: any = { [PositionType.FRONT]: PositionType.BACK, [PositionType.FRONT_TURN_RIGHT]: PositionType.BACK_TURN_LEFT, [PositionType.FRONT_TURN_BACK]: PositionType.BACK_TURN_BACK, [PositionType.FRONT_TURN_LEFT]: PositionType.BACK_TURN_RIGHT, [PositionType.BACK]: PositionType.FRONT, [PositionType.BACK_TURN_BACK]: PositionType.FRONT_TURN_BACK, [PositionType.BACK_TURN_LEFT]: PositionType.FRONT_TURN_RIGHT, [PositionType.BACK_TURN_RIGHT]: PositionType.FRONT_TURN_LEFT }