import { StringFormat } from "./StringFormat" import type * as CAD from './common/base/CAD' import { Polyline } from "cadapi" import { ArrayExt } from "./ArrayExt" import { BlockHelper } from "./common/LayoutEngine/BlockHelper" import { BlockSizePlus } from "./common/LayoutEngine/BlockSizePlus" import { Point } from "./common/Vector2" /**配置项属性 */ export class confItem { /** 属性key */ key: string = '' /** 说明 */ label: string = '' /** 属性value 值 */ value: Array | any } /** 内部指令 接收 */ export class CodeAction { code?: String order?: String codeParams?: any } /**内部响应类 */ export class GCodeResType { code: number = -1 data: any = null msg: string = '' logError(msg) { console.error(msg) } } /** 排孔类型 */ export enum HoleArrange { /** 正面 */ FRONT = 0, /** 反面 */ BACK = 1, /** 随意面 */ RANDOM_FACE = 2, } // 加工项 点数据 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 type _knifeType = Partial /** * 板面类型 * 0正面 1反面 2侧面 21左侧面 22右侧面 23上侧面 24下侧面 29 弧形侧面 30异形侧面 */ export enum FaceType { /** 正面 */ FRONT = 0, /** 反面 */ BACK = 1, /** 侧面 */ SIDE = 2, /** 左侧面 */ LEFT_SIDE = 21, /** 右侧面 */ RIGHT_SIDE = 22, /** 上侧面 */ TOP_SIDE = 23, /** 下侧面 */ BOTTOM_SIDE = 24, /** 弧形侧面 */ CURVED_SIDE = 29, /** 异形侧面 */ SPECIAL_SHAPED_SIDE = 30, /** 未设置 */ UNSET = -1 } /** 开料刀 */ export class Knife { /** 是否启用 */ isEnabled = true; /** 轴号 */ axleId = 0; /** 开料刀ID号 */ knifeId = 1; /** 加工面(0正面 1反面 2左侧面 3右侧面 4上侧面 5下侧面 6任意) */ processFace = 0; /** 刀名称 */ knifeName = ''; /** 刀具类型(1铣刀 2成型刀 3钻头 4锯 5刀片) */ knifeType = KnifeType.MILLING_CUTTER; /** 功能属性(数组): 1开料/切割 2拉槽 3铣型 4铣孔 5钻孔 6拉米诺 7乐扣 8T型 */ ability: any = []; // /** 默认开料刀 */ // isDefaultCutKnife = false; // /** 是否可用于开料切割 */ // isCuttingKnife = false; // /** 是否允许铣孔(knifeType为铣刀生效) */ // isMillingAllowed = false; /** 刀直径mm */ diameter = 6; /** 刀长(最大深度) */ length = 20; /** 锯齿厚度,单次加工切缝宽度 */ sawThiness = 0; /**锯向: 0横向(或长边) 1纵向(短边) 2自由角度*/ sawDirection = 0; /**切向加工方向: 0横向左往右 2横向右往左 3纵向上往下 4纵向下往上 5随意 */ processDirection = 0; /**进给速度, 0取系统默认 */ speed = 0; /** 进给深度 */ stepDepth = 0; // /** 组号 */ // groupNo = 0; // /** 主刀 */ // isMainKnife = false; // /** 是否高级加工 */ // isAdvancedProcessEnabled = false; // /** 是否集合加工 */ // isBatchProcessEnabled = false; // /** 副刀偏置长边偏移(Y轴) */ // auxKnifeOffsetY = 0; // /** 副刀偏置短边偏移(X轴) */ // auxKnifeOffsetX = 0; /** 偏置短边偏移(X轴)-相对于工件原点位置XY坐标的短边方向偏移量 */ offsetX = 0; /** 偏置长边偏移(Y轴) -相对于工件原点位置XY坐标的长边方向偏移量*/ offsetY = 0; /** 偏置垂直偏移(Z轴) -相对于工件原点位置XY坐标的垂直方向偏移量*/ offsetZ = 0; /** 基准坐标-短边(X轴) -钻头在钻包中短边方向(纵向)的相对位置 */ baseX = 0; /** 基准坐标-长边(Y轴) -钻头在钻包中长边方向(横向)的相对位置 */ baseY = 0; /**组合钻 */ isModularDrill = false; /** 是否预启动 */ isPreStartEnabled = false; /** 预启动提前动作数 */ preStartAheadActionCount = 5; /** 预启动延迟换刀 */ isPreStartToolChangeDelay = false; /** 预启动延迟换刀指令 */ preStartToolChangeDelayCode = ''; /** 轴启动指令后置 */ isAxisStartCodePostpost = false; /** 轴停止指令前置 */ isAxisStopCodePrepose = false; /** 钻组独立指令(启用后,刀起始指令、刀结束指令使用钻组起始指令、钻组结束指令替换) */ drillGroupCode = ''; /** 轴启动代码*/ axisStartCode = ""; /** 刀启动代码 */ knifeStartCode = ''; /** 钻组起始指令 */ drillGroupStartCode = ''; /** 钻组结束指令 */ drillGroupEndCode = ''; /** 刀停止代码 */ knifeStopCode = ''; /** 轴停止指令 */ axisStopCode = ''; // /** 高级加工指令 */ // advancedCode = ''; /** 开料刀 */ isCuttingKnife() { return this.isEnabled && this.ability.includes(AbilityType.CUT); } /** 造型刀 */ isModelingKnife() { return this.isEnabled && this.ability.includes(AbilityType.MILLING_MODEL); } /** 钻刀 */ isDrillingKnife() { return this.isEnabled && this.ability.includes(AbilityType.DRILL_HOLE); } /** 铣孔 */ isCutting4HoleKnife() { return this.isEnabled && this.ability.includes(AbilityType.MILLING_HOLE); } /** 设置刀具(轴号, 刀名, 刀直径, 是否主刀, 是否铣孔, 是否开料刀) */ // set(axleId: number, name: string, diameter: number, isMainKnife: boolean, isMillingAllowed: boolean, isCuttingKnife: boolean) /** 设置刀具(轴号, 刀名, 刀类型, 刀直径, 刀长, 是否默认刀) */ } /** 刀类型: MILLING_CUTTER铣刀 FORMING_CUTTER成型刀 DRILL钻头 SAW锯 BLADE刀片 */ export enum KnifeType { /** 铣刀 */ MILLING_CUTTER = 1, /** 成型刀 */ FORMING_CUTTER = 2, /** 钻头 */ DRILL = 3, /** 锯 */ SAW = 4, /** 刀片 */ BLADE = 5 } /** 刀功能: ** 1-CUT开料/切割 2-PULLING_GROOVE拉槽 3-MILLING_MODEL铣型 4-MILLING_HOLE铣孔 ** 5-DRILL_HOLE钻孔 6-RAMINO拉米诺 7-EASY_FASTEN乐扣 8-T_TYPE T型 */ export enum AbilityType { /** 1开料/切割 */ CUT = 1, /** 2拉槽 */ PULLING_GROOVE = 2, /** 3铣型 */ MILLING_MODEL = 3, /** 4铣孔 */ MILLING_HOLE = 4, /** 5钻孔 */ DRILL_HOLE = 5, /** 6拉米诺 */ RAMINO = 6, /** 7乐扣 */ EASY_FASTEN = 7, /** 8T型 */ T_TYPE = 8 } /** 枚举 坐标轴类型 */ export enum AxisType { /** 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 enum OriginZPosition { /** 台面向上Z轴正 */ WorkTop = 0, /** 板面向上Z轴正 */ BoardFace = 1, } // nc文件编码 export const ncEncodeMap = { 'UTF-8': 'UTF-8', 'GB2312': 'GB2312', 'UTF-8-BOM': 'UTF-8-BOM', 'GBK': 'GBK', 'Big-5': 'Big-5', 'GB18030': 'GB18030', 'Unicode': 'Unicode' } // 小板文件名选项 export const smallPlateOptionsMap = { 板宽: '{0}', 板长: '{1}', 颜色: '{2}', 材质: '{3}', 大板号: '{4}', 工位号: '{5}', 板厚: '{6}', 开料顺序: '{7}', 批次识别: '{8}', 小板编号: '{9}', 全局大板号: '{10}', 品牌: '{11}', } // zip压缩包文件名选项 export const zipFileOptionsMap = { '板宽': '{0}', '板长': '{1}', '颜色': '{2}', '材质': '{3}', '大板号': '{4}', '工位号': '{5}', '板厚': '{6}', '开料顺序': '{7}', '批次识别': '{8}', '小板编号': '{9}', '全局大板号': '{10}', '品牌': '11', } /** 枚举 大板边角位置 */ export enum BoardPosition { /** 左上角 */ // LEFT_TOP = 0, // /** 左下角 */ // LEFT_BOTTOM = 1, // /** 右下角 */ // RIGHT_BOTTOM = 2, // /** 右上角 */ // RIGHT_TOP = 3, /** 左上角 */ LEFT_TOP = 3, /** 左下角 */ LEFT_BOTTOM = 0, /** 右下角 */ RIGHT_BOTTOM = 1, /** 右上角 */ RIGHT_TOP = 2, /** * 左下角 = 0, 右下角 = 1, 右上角 = 2, 左上角 = 3 */ } /** 排版样式 */ export enum PlaceStyle { /** 正面 */ 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 enum EdgeType { /** 下=0 */ BOTTOM = 0, /** 右=1 */ RIGHT = 1, /** 上=2 */ TOP = 2, /** 左=3 */ LEFT = 3, } /** 开料小板 */ export class PlaceBlock { /** 小板明细(异形,孔,造型) */ blockDetail?: PlaceBlockDetail | null = null // 订单信息---------------------------------------------------------- /** 订单号 */ orderId: number = 0 /** 板材ID */ goodsId = '' // 小板属性----------------------------------------------------------- // 房间名, 柜体名, 小板ID, 小板编号,小板名称, 板材名称, 备注 // 房间ID roomId = '' /** 房间名 */ roomName = '' /** 柜体号 */ bodyId = '' /** 柜体名 */ bodyName = '' /** 小板ID */ blockId = 0 /** 原小板ID */ oldBlockId: number = 0 /** 板编号 */ blockNo: number = 0 /** 自定义板编号 */ customPlateNo: any = '' /** 明细ID */ itemId: number = 0 /** 标签板号 */ labelNo = '' /** 板名称 */ blockName = '' /** 板件备注 */ plateRemark = '' /** 备注1 */ remark1 = '' /** 备注2 */ remark2 = '' /** 备注3 */ remark3 = '' /** 备注4 */ remark4 = '' /** 备注5 */ remark5 = '' /** 铰链备注 */ extraRemark: object = {} // 尺寸,封边,开料尺寸----------------------------------------------------- /** 板宽 */ width = 0 /** 板长 */ length = 0 /** 板厚 */ thickness = 0 /** 面积 Size */ area = 0 /** 左封边 BorderLeft */ sealLeft = 0 /** 右封边 BorderRight */ sealRight = 0 /** 上封边 BorderUpper */ sealTop = 0 /** 下封边 BorderUnder */ sealBottom = 0 /** 无封边板宽 开料板宽 CuttingWidth */ cutWidth = 0 /** 无封边板长 开料板长 CuttingLength */ cutLength = 0 /** 无封边面积 开料面积 CuttingSize */ cutArea = 0 // 高级------------------------------------------------------------- /** 自增小板 */ isAdditionalBlock = false /** 余料板 IsScrapBlock */ isRemainBlock = false /** 开料纹路 */ texture = TextureType.ROTATABLE_TEXTURE // 可翻转 /** 排版面 PaiKong */ placeHole = HoleArrange.RANDOM_FACE // 随意面 /** 异型偏移x BorderLengthHeavy */ abnormalOffsetX = 0 /** 异型偏移y BorderLengthLight */ abnormalOffsetY = 0 /** 正面有大孔 */ bigHoleInFaceA(): boolean { let res = false if (this.blockDetail && this.blockDetail.bigHoleInFaceA) { res = true } return res } /** 是否异形 */ isUnRegular = false // isUnRegular(): boolean { // return this.blockDetail && this.blockDetail.isUnRegular || false // } /** 正面孔数 */ holeCountFront(): number { return this.blockDetail && this.blockDetail.holeCountFront || 0 } /** 反面孔数 */ holeCountBack(): number { return this.blockDetail && this.blockDetail.holeCountBack || 0 } /** 通孔数 */ holeCountThrough(): number { return this.blockDetail && this.blockDetail.holeCountThrough || 0 } /** 侧孔数 HoleCount_Side */ holeCountSide(): number { return this.blockDetail && this.blockDetail.holeCountSide || 0 } /** 左侧孔数 HoleCount_Left */ holeCountLeft() { return this?.blockDetail?.holeCountLeft || 0 } /** 右侧孔数 HoleCount_Right */ holeCountRight() { return this?.blockDetail?.holeCountRight || 0 } /** 侧孔数 HoleCount_Upper */ holeCountTop() { return this?.blockDetail?.holeCountTop || 0 } /** 侧孔数 HoleCount_Under */ holeCountBottom() { return this?.blockDetail?.holeCountBottom || 0 } /** 正面造型数 */ modelCountFront(): number { return this.blockDetail && this.blockDetail.modelCountFront || 0 } /** 反面造型数 */ modelCountBack(): number { return this.blockDetail && this.blockDetail.modelCountBack || 0 } /** 打穿造型数 */ modelCountThrough(): number { return (this.blockDetail && this.blockDetail.modelCountThrough) || 0 } /** 有挖穿造型 */ hasModelThrough(): boolean { return (this.blockDetail && this.blockDetail.hasModelThrogh) || false } /** 需双面处理 */ isDoubleFaceProcess(): boolean { if (this.placeHole == HoleArrange.RANDOM_FACE) // 随意面 { return (this.blockDetail && this.blockDetail.isTwoFaceProcess) || false } else if (this.placeHole == HoleArrange.FRONT) // 正面 { return this.holeCountBack() + this.modelCountBack() > 0 } else { return this.holeCountFront() + this.modelCountFront() > 0 } } // (根据排版规格计算) /** 优化排版时,需反面(不是真正的反面开料) */ isTurnFaceToPlace = false /** 优化排版时,可双面排版 */ isTwoFaceToPlace = false /** 是否弧形地脚,不处理异形 IsHXDJX */ isCurvedGroundLine = false /** 封边偏移值x */ offsetX(): number { return (this.blockDetail && this.blockDetail.offsetX) || 0 } /** 封边偏移值y */ offsetY(): number { return (this.blockDetail && this.blockDetail.offsetY) || 0 } // 异形、孔、造型明细列表 points(): BlockPoint[] { return (this.blockDetail && this.blockDetail.points) || [] } orgPoints(): BlockPoint[] { return (this.blockDetail && this.blockDetail.orgPoints) || [] } holes(): BlockHole[] { return (this.blockDetail && this.blockDetail.holes) || [] } models(): BlockModel[] { return (this.blockDetail && this.blockDetail.models) || [] } holeListOrgFaceA(): BlockHole[] { return (this.blockDetail && this.blockDetail.holeListFaceA) || [] } holeListOrgFaceB(): BlockHole[] { return (this.blockDetail && this.blockDetail.holeListFaceB) || [] } holeListOrgThrough(): BlockHole[] { return (this.blockDetail && this.blockDetail.holeListThrough) || [] } holeListOrgFaceSide(): SideHole[] { return (this.blockDetail && this.blockDetail.holeListSide) || [] } modelListOrgFaceA(): BlockModel[] { return (this.blockDetail && this.blockDetail.modelListFaceA) || [] } modelListOrgFaceB(): BlockModel[] { return (this.blockDetail && this.blockDetail.modelListFaceB) || [] } modelListOrgTrough(): BlockModel[] { return (this.blockDetail && this.blockDetail?.modelListThrough) || [] } // 排版情况 /** 已排版 */ isPlaced = false /** 全局大板Id */ fullBoardId = 0 /** 大板ID */ boardId = 0 /** 排单ID */ placeId = 0 /** 坐标X */ placeX = 0 /** 坐标Y */ placeY = 0 /** 排版方式 */ placeStyle: PlaceStyle = PlaceStyle.FRONT // 正面 /** 下刀点区域 */ cutRegion = BlockRegion.LEFT_BOTTOM // 左下 /** 开料顺序 */ cutOrder = 0 /** 下刀点位 */ cutPointId = 0 /** 开料宽 */ placeWidth = 0 /** 开料长 */ placeLength = 0 /** 开料左封边 */ placeSealLeft = 0 /** 开料右封边 */ placeSealRight = 0 /** 开料上封边 */ placeSealTop = 0 /** 开料下封边 */ placeSealBottom = 0 /** 原造型下刀超出板外情况 OrgSizeOutOff */ orgSizeExpand: SizeExpand = new SizeExpand() /** 造型下刀超出板外情况 尺寸扩展 SizeOutOff */ sizeExpand() { return this.blockDetail && this.blockDetail.currentSizeExpand ? this.blockDetail.currentSizeExpand : new SizeExpand() }; /** 排版宽 加上预铣等外括 ,开料刀半径 ,缝隙 */ placeFullWidth() { return this.cutWidth + (this.blockDetail ? this.blockDetail?.currentSizeExpand?.width || 0 : 0) } /** 排版长 加上预铣等外括 ,开料刀半径 ,缝隙 */ placeFullLength() { return this.cutLength + (this.blockDetail ? this.blockDetail?.currentSizeExpand?.length || 0 : 0) } /** 坐标偏移情况 */ placeOffX = 0 placeOffY = 0 /** 原始排版坐标 */ placeOrgX() { return this.placeX - this.placeOffX } placeOrgY() { return this.placeY - this.placeOffY } /** 反面开料 */ isTurnOver(): boolean { return this.placeStyle > 3 } /** 后转180 */ isTurnBack(): boolean { return ( this.placeStyle == PlaceStyle.BACK_TURN_BACK || this.placeStyle == PlaceStyle.FRONT_TURN_BACK ) } /** 反纹开料 */ isTurnDown(): boolean { return this.placeStyle % 2 == 1 } /** 自动排版 */ isAutoPlaced = true /** 超出板外 */ isOutBoard = false /** 已重叠 */ isOverlap = false /** 高方向 */ placeDirection = '→' /** 长边方向 */ placeDirection_Length = '→' // 开料情况 // isUseSameKnifeToHelpCut() { return this.blockDetail ? this.blockDetail.isHelpCut : false; }; /** 是否排钻 IsDoHoling */ isDrilling = true /** 是否造型 IsDoModeling */ isModeling = true /** 超限板标识 : -1=不是; 0=不判断 1=是 */ overBlockFlag = 0 /** 开料时需翻面 IsDoOtherFace */ isCutOtherFace = false /** 开料反面要处理 NeedTurnFaceToDo */ isCutTurnOver = false /** 开料面孔数 HoleCount_DoFaceA */ holeCountFaceA(): number { return this.holeListFaceA.length } /** 开料反面孔数 HoleCount_DoFaceB */ holeCountFaceB(): number { return this.holeListFaceB.length } /** 开料左侧孔数 HoleCount_DoLeft */ holeCountSideLeft = 0 /** 开料右侧孔数 HoleCount_DoRight */ holeCountSideRight = 0 /** 开料上侧孔数 HoleCount_DoUpper */ holeCountSideTop = 0 /** 开料下侧孔数 HoleCount_DoUnder */ holeCountSideBottom = 0 /** 开料面造型数 ModelCount_DoFaceA */ modelCountFaceA(): number { return this.modelListFaceA.length } /** 开料反面造型数 ModelCount_DoFaceB */ modelCountFaceB(): number { return this.modelListFaceB.length } // 不显示 /** 开料面孔 Holes_DoFaceA */ holeListFaceA: BlockHole[] = [] // 不显示 /** 开料反面孔 Holes_DoFaceB */ holeListFaceB: BlockHole[] = [] // 不显示 /** 开料面造型 Models_DoFaceA */ modelListFaceA: BlockModel[] = [] // 不显示 /** 开料反面造型 Models_DoFaceB */ modelListFaceB: BlockModel[] = [] /** 贴标位置x NotePosX */ labelPosX = 0 /** 贴标位置y NotePosY */ labelPosY = 0 // CNC高级对接-------------------------------------------------------- /** CNC正面条码 CNC_NoteA */ isCncLabelA = false /** CNC反面条码 CNC_NoteB */ isCncLabelB = false /** CNC翻面条码 CNC_NoteT */ isCncLabelTurnOver = false /** 类型 */ type = '' /** 加工组 */ processGroupName = '' /** 开门类型 */ openDoorType = OpenDoorType.NONE // 无 /** 自增小板的id接口获取 */ _blockId = '' constructor(data: any = null) { if (data != null) { for (const key in data) { if (Reflect.has(this, key)) { if (['goodsId'].includes(key)) { this[key] = data[key].toString() } else if (['width', 'length', 'thickness', 'sealLeft', 'sealRight', 'sealTop', 'sealBottom'].includes(key)) { this[key] = StringFormat.toFixed(data[key], 3) } else if (key == 'texture') { this.texture = data.texture } else if (key == 'placeHole') { this.placeHole = data.placeHole } else if (key == 'remarkJson') { let remarkList = JSON.parse(data.remarkJson == null || data.remarkJson == '' ? '[]' : data.remarkJson) this.remark1 = remarkList[0] == null ? '' : remarkList[0] this.remark2 = remarkList[1] == null ? '' : remarkList[1] this.remark3 = remarkList[2] == null ? '' : remarkList[2] this.remark4 = remarkList[3] == null ? '' : remarkList[3] this.remark5 = remarkList[4] == null ? '' : remarkList[4] } else { try { if (Object.getOwnPropertyDescriptor(this, key)?.writable == true) { this[key] = data[key] } } catch (error) { console.log(error) } } } else { // console.log('PlaceBlock Init', key) } } this.cutWidth = this.width - this.sealLeft - this.sealRight this.cutLength = this.length - this.sealTop - this.sealBottom this.cutArea = this.cutWidth * this.cutLength * 0.000001 this._blockId = data.blockId } } getRemark(rname, st = '', ed = '') { if (!this.extraRemark) return '' if (!this.extraRemark[rname]) return '' let text: string = this.extraRemark[rname] if (st != '') { let index = text.indexOf(st) if (index > -1) { // text = text.substr(index + st.length, 99999); text = text.substring(index + st.length, 99999) } } if (ed != '') { let index = text.indexOf(ed) if (index > -1) { text = text.substring(0, index) } } return text } } /** 小板明细(异形,造型,孔) */ export class PlaceBlockDetail { // 数据库定义列 /** 用户ID */ organId: number = 0 /** 数据类型 */ dataType: number = 0 /** 订单号 */ orderId: number = 0 /** 小板ID */ blockId: number = 0 /** 原柜体编号rawBoxNo */ rawBoxNo: number = 0 /** 异形定义明细 */ pointDetail: any = [] /** 造型定义明细 */ modelDetail: any = [] /** 排钻定义明细 */ holeDetail: any = [] /** 封边偏移值x */ offsetX = 0 /** 封边偏移值y */ offsetY = 0 /** 开料宽度 KaiLiaoWidth */ cutWidth = 0 /** 开料长度 KaiLiaoLength */ cutLength = 0 /** 异形点阵 */ points: BlockPoint[] = [] /** 异形点阵含封边 */ orgPoints: BlockPoint[] = [] /** 原轮廓数据 */ orgContourData: any = null /** 排钻 */ holes: BlockHole[] = [] /** 正面孔列表(不包含通孔和孔深大于板厚) Holes_FaceA */ holeListFaceA: BlockHole[] = [] /** 反面孔列表(不包含通孔和孔深大于板厚) Holes_FaceB */ holeListFaceB: BlockHole[] = [] /** 穿孔列表(通孔和孔深大于板厚) Holes_Through */ holeListThrough: BlockHole[] = [] /** 侧孔列表 Holes_FaceSide */ holeListSide: SideHole[] = [] /** 造型点阵 */ models: BlockModel[] = [] /** 正面造型列表(不包含打穿) Models_FaceA */ modelListFaceA: BlockModel[] = [] /** 反面造型列表(不包含打穿) Models_FaceB */ modelListFaceB: BlockModel[] = [] /** 打穿造型列表 Models_Through */ modelListThrough: BlockModel[] = [] /** 侧面造型 BlockModel SideModels 20241111 改为 BlockModel */ modelListSide: SideModel[] = [] // /** 切割板宽 */ // cuttingWidth = 0; // /** 切割板厚 */ // cuttingLength = 0; /** 板厚 */ thickness = 18 /** 是否异形 */ isUnRegular = false /** 正面有打孔 */ bigHoleInFaceA = false /** 正面孔数 */ holeCountFront = 0 /** 反面孔数 */ holeCountBack = 0 /** 穿孔数 */ holeCountThrough = 0 /** 侧孔数 */ holeCountSide = 0 /** 左侧孔数 */ holeCountLeft = 0 /** 右侧孔数 */ holeCountRight = 0 /** 上侧孔数 */ holeCountTop = 0 /** 下侧孔数 */ holeCountBottom = 0 /** 斜孔数量 */ holeCountBevelled = 0 /** 正面造型数 */ modelCountFront = 0 /** 反面造型数 */ modelCountBack = 0 /** 打穿造型数 */ modelCountThrough = 0 /** 侧面造型数量 */ modelCountSide(): number { return this.modelListSide.length } /** 下侧造型数量 */ modelCountBottom(): number { return this.modelListSide.filter(sideModel => sideModel.face == 0).length } /** 右侧造型数量 */ modelCountRight(): number { return this.modelListSide.filter(sideModel => sideModel.face == 1).length } /** 下侧造型数量 */ modelCountTop(): number { return this.modelListSide.filter(sideModel => sideModel.face == 2).length } /** 下侧造型数量 */ modelCountLeft(): number { return this.modelListSide.filter(sideModel => sideModel.face == 3).length } /** 是否有挖穿的造型 */ hasModelThrogh = false /** 双面处理 Do2Face */ isTwoFaceProcess = false // isTwoFaceProcess(): boolean // { // return this.blockDetail && this.blockDetail.isTwoFaceProcess // } // 为了缺角空间 放在右边 /** 当需要正面正纹的,最佳放置方式: 正面或正面后转 Ps00 */ placeStyleFront = PlaceStyle.FRONT // 正面 /** 正面反纹放置方式 Ps01 */ placeStyleFrontReverse = PlaceStyle.FRONT_TURN_RIGHT // 正面右转 /** 反面正纹放置方式 Ps10 */ placeStyleBack = PlaceStyle.BACK // 反面 /** 反面反纹放置方式 Ps11 */ placeStyleBackReverse = PlaceStyle.BACK_TURN_LEFT // 反面左转 /** 开料序号贴标位置x */ labelPosX = -1 /** 开料序号贴标位置y */ labelPosY = -1 /** 是否初始化 */ isInited = false /** 是否已检查 */ isChecked = false /** 全部二维刀路径集合 { model, modelID, lineID, isFaceB, name, value, knife, knifeRadius, depth, points, offset} */ // vKnifeModels: any[]; /** 是否偏移倒角 IsOffsetRounding */ isOffsetRounding = false /** 偏移值刀半径 CutR */ offsetKnifeRadius = 0 /** 当前的预铣值 preCutValue */ preMillingSize = 0 /** 该板需要辅助开料 isNeedHelpCut */ isUseSameKnifeToHelpCut = false /** 同刀辅助值 */ useSameKnifeToHelpCutGap = 2 /** 预铣外扩尺寸 preCutSizeOutOff */ preMillingExpandSize?: SizeExpand | null = null /** 板外造型外扩尺寸 modelKnifeOutOff */ modelExpandSize?: SizeExpand | null = null /** 2V刀路V外扩尺寸 */ vKnifeModelExpandSize?: SizeExpand | null = null /** 同刀辅助外扩尺寸 sameKnfieHelpOutOff */ sameKnifeHelpExpandSize?: SizeExpand | null = null /** 当前外扩 currentOutOff */ currentSizeExpand?: SizeExpand | null = null /** 边框轮廓,走刀路径等(包含偏移后的轮廓结合) borderUnit */ borderContour?: PlaceBorderContour | null = null // 板件扩展尺寸 数据集 plateExtraRemark: any /** 优化前的配置及其轮廓等用于恢复 */ savedSetting /** 备注 数据集 */ remarkParams: any constructor(data: any = null, sourceType: number = 2) { if (data != null) { this.remarkParams = data.remarkParams this.orderId = data.orderId this.dataType = data.dataType this.orderId = data.orderId this.blockId = data.blockId this.rawBoxNo = data.rawBoxNo // 封边偏移值 this.offsetX = data.offSet && data.offSet.x ? StringFormat.toFixed(data.offSet.x, 3) : 0 this.offsetY = data.offSet && data.offSet.y ? StringFormat.toFixed(data.offSet.y, 3) : 0 // 开料长宽(不含封边) this.cutWidth = data.cutSize ? StringFormat.toFixed(data.cutSize.width, 3) : 0 this.cutLength = data.cutSize ? StringFormat.toFixed(data.cutSize.height, 3) : 0 // 初始化 异形点阵 data.pointDetail.forEach((p) => { this.points.push(new BlockPoint(p)) }) // 初始化 异形点阵 含封边 if (!data.orgPointDetail) { data.orgPointDetail = [] } data.orgPointDetail.forEach((p) => { this.orgPoints.push(new BlockPoint(p)) }) if (!data.holes) { data.holes = data.holeDetail || [] } // 初始化 排钻列表 data.holes.forEach((h) => { this.holes.push(new BlockHole(h)) }) // 初始化 侧孔列表 if (!data.holeListSide) { data.holeListSide = data.sideHoleDetail || [] } data.holeListSide.forEach((sh) => { this.holeListSide.push(new SideHole(sh)) }) // 初始化 造型列表 data.modelDetail.forEach((t) => { this.models.push(new BlockModel(t)) }) // 初始化 侧面造型列表 if (!data.modelListSide) { data.modelListSide = [] } this.plateExtraRemark = data.plateExtraRemark data.modelListSide.forEach((t) => { this.modelListSide.push(new SideModel(t)) }) // 侧面 this.holeListFaceA = this.holes.filter(t => t.face == FaceType.FRONT) // 正面 this.holeListFaceB = this.holes.filter(t => t.face == FaceType.BACK) // 反面 this.holeListThrough = [] this.modelListFaceA = this.models.filter(t => t.face == FaceType.FRONT && (t.depth < this.thickness || t.isVKnifeModel())) this.modelListFaceB = this.models.filter(t => t.face == FaceType.BACK && (t.depth < this.thickness || t.isVKnifeModel())) this.modelListThrough = this.models.filter(t => t.depth > this.thickness - 0.01 && t.isVKnifeModel() == false) this.holeCountFront = this.holeListFaceA.length this.holeCountBack = this.holeListFaceB.length this.holeCountThrough = this.holeListThrough.length this.holeCountSide = this.holeListSide.length this.modelCountFront = this.modelListFaceA.length this.modelCountBack = this.modelListFaceB.length this.modelCountThrough = this.modelListThrough.length this.hasModelThrogh = this.modelListThrough.length > 0 this.bigHoleInFaceA = this.holeListFaceA.some(t => t.holeType == HoleType.BIG_HOLE) // 大孔 } this.isUnRegular = this.points.length > 0 } /** 保存 开料配置 */ saveSetting() { this.savedSetting = {} this.savedSetting.offsetKnifeRadius = this.offsetKnifeRadius this.savedSetting.preMillingSize = this.preMillingSize this.savedSetting.isUseSameKnifeToHelpCut = this.isUseSameKnifeToHelpCut this.savedSetting.useSameKnifeToHelpCutGap = this.useSameKnifeToHelpCutGap // SizeExpand this.savedSetting.preMillingExpandSize = this.preMillingExpandSize this.savedSetting.modelExpandSize = this.modelExpandSize this.savedSetting.vKnifeModelExpandSize = this.vKnifeModelExpandSize this.savedSetting.sameKnifeHelpExpandSize = this.sameKnifeHelpExpandSize this.savedSetting.currentExpandSize = this.currentSizeExpand // 轮廓,铣刀路径 if (this.borderContour != null) { this.savedSetting.borderContour = this.borderContour.clone() } } loadSetting() { if (!this.savedSetting) return this.offsetKnifeRadius = this.savedSetting.offsetKnifeRadius this.preMillingSize = this.savedSetting.preMillingSize this.isUseSameKnifeToHelpCut = this.savedSetting.isUseSameKnifeToHelpCut this.useSameKnifeToHelpCutGap = this.savedSetting.useSameKnifeToHelpCutGap // SizeOutOff this.preMillingExpandSize = this.savedSetting.preMillingExpandSize this.modelExpandSize = this.savedSetting.modelExpandSize this.vKnifeModelExpandSize = this.savedSetting.vKnifeModelExpandSize this.sameKnifeHelpExpandSize = this.savedSetting.sameKnifeHelpExpandSize this.currentSizeExpand = this.savedSetting.currentSizeExpand // 轮廓,铣刀路径 this.borderContour = this.savedSetting.borderContour } } /** 开门类型(0无 1左 2右 3上 4下) */ export enum OpenDoorType { /** 无 */ NONE = 0, /** 左 */ LEFT = 1, /** 右 */ RIGHT = 2, /** 上 */ TOP = 3, /** 下 */ BOTTOM = 4, } /** 纹理类型 */ export enum TextureType { /** 正纹 */ NORMAL_TEXTURE = 0, /** 可翻转 */ ROTATABLE_TEXTURE = 1, /** 反纹 */ REVERSE_TEXTURE = 2, } /** 排钻 */ export class BlockHole { /** 孔类别 */ holeType: HoleType = 0 /** 面 */ face: FaceType = 0 /** 侧孔所在面 */ sideFace: FaceType = FaceType.FRONT // 正面 /** 坐标x */ pointX: number = 0 /** 坐标y */ pointY: number = 0 /** 坐标z */ pointZ: number = 0 /** 半径 */ radius: number = 5 /** 深度 */ depth: number = 12 /** 终点坐标 */ endPoint: string = '' /** 角度 */ angle: number = 0 /** CNC不能加工 cncUndo */ isCncCanNotProcess: boolean = false /** 不能加工类型 unDoType */ cncCanNotProcessType = '' /** 是否在开料机上处理 IsDo */ isCutting: boolean = true knife?: Knife | null = null blockNo?: string | number constructor(data: any = null) { if (data != null) { this.holeType = data.holeType this.face = data.face this.pointX = StringFormat.toFixed(data.pointX, 3) this.pointY = StringFormat.toFixed(data.pointY, 3) this.pointZ = StringFormat.toFixed(data.pointZ, 3) this.radius = StringFormat.toFixed(data.radius, 3) this.depth = StringFormat.toFixed(data.depth, 3) this.angle = data.angle ? data.angle : 0 this.endPoint = data.endPoint } } ToSideHole(block: PlaceBlock): SideHole { let newH = new SideHole() newH.holeType = this.holeType newH.faceId = 0 newH.sideFace = SideFaceType.BOTTOM // 下侧面 newH.pointX = this.pointX newH.pointY = this.pointY newH.pointZ = this.pointZ newH.radius = 4 let diameter = this.radius * 2 if (Math.abs(diameter - 8.3) < 0.1 || Math.abs(diameter - 6.3) < 0.1 || Math.abs(diameter - 11.5) < 0.1 || Math.abs(diameter - 12) < 0.1) { newH.radius = this.radius } newH.depth = this.depth let cells = this.endPoint.split(',') if (cells.length >= 3) { // 起点坐标 let bx = Number.parseFloat(cells[0]) let by = Number.parseFloat(cells[1]) // x 相等 , 侧孔方向 上下 if (Math.abs(bx - this.pointX) < 0.1) { let toUpper = this.isToTop(block, by) if (toUpper) // y+ 向上 { newH.pointX2 = bx newH.pointY2 = this.pointY + this.depth newH.direct = 0 newH.faceId = 0 newH.sideFace = SideFaceType.BOTTOM_SIDE // 下侧面 } // y- 向下 else { newH.pointX2 = bx newH.pointY2 = this.pointY - this.depth newH.direct = 2 newH.faceId = 2 newH.sideFace = SideFaceType.TOP_SIDE // 上侧面 } } else if (Math.abs(by - this.pointY) < 0.1) { let toRight = this.isToRight(block, bx) // y相等, 侧孔方向左右 if (toRight) { // x+ 向右 newH.pointX2 = this.pointX + this.depth newH.pointY2 = by newH.direct = 3 newH.faceId = 3 newH.sideFace = SideFaceType.LEFT_SIDE // 左侧面 } // x- 向左 else { newH.pointX2 = this.pointX - this.depth newH.pointY2 = by newH.direct = 1 newH.faceId = 1 newH.sideFace = SideFaceType.RIGHT_SIDE // 右侧面 } } // x ,y 都不相等 else { newH.pointX2 = bx newH.pointY2 = by newH.direct = -1 newH.faceId = 4 newH.sideFace = SideFaceType.SPECIAL_SHAPED_SIDE // 异形侧面 } } return newH } /** 向右(bx: 起点坐标X) */ private isToRight(block: PlaceBlock, bx: number): boolean { // 在左侧外 if (bx < 0) return true // 在板内 靠左侧 if (bx > 22 && bx < 40) return true // 在右侧外 if (bx > block.width) return false // 在右侧外 if (bx > block.width - 40 && bx < block.width - 22) return false for (let i = 0; i < block.points.length; i++) { let j = i + 1 if (j == block.points.length) j = 0 let p1 = block.points[i] let p2 = block.points[j] if (Math.abs(p1.pointX - this.pointX) < 3 && Math.abs(p2.pointX - this.pointX) < 3 && (p1.pointY > this.pointY != p2.pointY > this.pointY)) { return p1.pointY > p2.pointY } } return false } /** 向上(起点坐标Y) */ private isToTop(block: PlaceBlock, by: number): boolean { // 在下侧外 if (by < 0) return true // 靠近下侧 if (by > 22 && by < 40) return true if (by > block.length) return false if (by > block.length - 40 && by < block.length - 20) return false for (let i = 0; i < block.points.length; i++) { let j = i + 1 if (j == block.points.length) j = 0 let p1 = block.points[i] let p2 = block.points[j] if (Math.abs(p1.pointY - this.pointY) < 3 && Math.abs(p2.pointY - this.pointY) < 3 && (p1.pointX > this.pointX != p2.pointX > this.pointX)) { return p1.pointX < p2.pointX } } return false } } /** 异形点 */ export class BlockPoint { /** 坐标x */ pointX: number = 0 /** 坐标y */ pointY: number = 0 /** 凹凸度 */ curve: number = 0 /** 半径 */ radius: number = 0 /** 封边 */ sealSize: number = 0 /** 是否这条边需预洗 */ isPreCutRequired = false constructor(data: any = null) { if (data != null) { let x = data.PointX != undefined ? data.PointX : data.pointX let y = data.PointY != undefined ? data.PointY : data.pointY let curve = data.Curve != undefined ? data.Curve : data.curve let radius = 1 / curve this.pointX = StringFormat.toFixed(x) this.pointY = StringFormat.toFixed(y) this.curve = curve this.radius = StringFormat.toFixed(Math.abs(radius)) if (Math.abs(this.curve) < 1e-5) { this.curve = 0 this.radius = 0 } this.sealSize = data.SealSize != undefined ? data.SealSize : data.sealSize || 0 } } copy(): BlockPoint { let nw = new BlockPoint() nw.pointX = this.pointX nw.pointY = this.pointY nw.curve = this.curve nw.radius = this.radius nw.sealSize = this.sealSize return nw } } /** 侧孔 */ export class SideHole { /** 孔类别 */ holeType: HoleType = 0 /** 面 */ faceId: number = 0 /** 侧孔所在面 */ sideFace: SideFaceType = SideFaceType.BOTTOM // 正面 /** 方向 0向上 1向左 2向下 3向右 -1斜 */ direct: number = 0 /** 坐标x */ pointX: number = 0 /** 坐标y */ pointY: number = 0 /** 坐标z */ pointZ: number = 0 /** 半径 */ radius: number = 5 /** 深度 */ depth: number = 12 /** 坐标x */ pointX2: number = 0 /** 坐标y */ pointY2: number = 0 // cncUndo: boolean = true; //cnc不能做. /** CNC不能处理 */ isCncCanNotProcess: boolean = true /** 是否可处理 IsDo */ isProcess: boolean = true knife?: Knife | null = null constructor(data: any = null) { if (data != null) { this.holeType = data.holeType this.faceId = data.face this.sideFace = data.sideFace this.direct = data.sideFace this.pointX = StringFormat.toFixed(data.pointX, 3) this.pointY = StringFormat.toFixed(data.pointY, 3) this.pointZ = StringFormat.toFixed(data.pointZ, 3) this.radius = StringFormat.toFixed(data.radius, 3) this.depth = StringFormat.toFixed(data.depth, 3) this.pointX2 = StringFormat.toFixed(data.pointX2, 3) this.pointY2 = StringFormat.toFixed(data.pointY2, 3) } } } /** 孔类型 */ export enum HoleType { /** 大孔 */ BIG_HOLE = 0, /** 小孔 */ TINY_HOLE = 10, /** 木削 */ WOOD_DUST = 20, /** 木削大孔 */ WOOD_DUST_BIG_HOLE = 21, /** 层板钉 */ LAMINATED_NAIL = 30, /** 通孔 */ THROUGH_HOLE = 40, /** 造型孔 */ MODELING_HOLE = -10, /** 连接杆 */ CONNECTING_ROD = 50, } /** 板件造型 */ export class BlockModel { /** 订单号 */ orderId: string = '' /** 小板号 */ blockId: number = 0 /** 造型Id */ modelId: number = 0 /**线ID */ lineId: number = 0; /** 纹路Id */ textureId: number = 0 /** 板面 */ face: FaceType = FaceType.UNSET /** 刀号 */ knifeName: string = '' /** 刀半径 */ knifeRadius: number = 0 /** 深度 */ depth: number = 0 /** 是否可以挖空后排版 */ canSpace = false /** 是否是矩形 */ isRect = false /** 是否倾斜 至少有一条边是斜的 */ isTilt = false type = '' knife: Knife | null | undefined = null blockNo?: string| number /** 有轮廓 */ hasContour() { let val = false try { if (this.originModeling != null && this.originModeling.outline != 0 && this.originModeling?.outline.map(e => e?.pts).length > 0) { val = true } } catch (error) { console.log('handle hasContour error', error) val = false } return val // this.originModeling?.outline.map(e=>e?.pts).length >0 //this.originModeling?.outline?.pts?.length > 0 } modelWidth: any = 0 modelLength: any = 0 modelStartPoint: any = null modelEndPoint: any = null /** * 造型轮廓(孔转的造型,没有造型轮廓) * OriginModeling.outline.pts.x | y ; outline.buls */ originModeling: any = null /** 点列表 */ pointList: BlockModelPoint[] = [] /** 实际替代刀直径 */ realKnifeRadius = 0 /** 实际替代刀点阵 */ realPointList: BlockModelPoint[] = [] /** 实际刀编号 */ realKnifeId = -1 /** cnc不能加工 cncUndo */ isCncCanNotProcess: boolean = true /** 超限类型(cnc为何不能加工) unDoType */ cncCanNotProcessType = '' /** 是否在开料机加工 IsDo */ isCutting: boolean = true /** 二维造型的偏移数组 */ offsetList: ModelOffsetData[] = [] /** 转换过的二维刀路路径{isFaceB, name刀名称, offset偏移, knife刀, knifeId刀Id, knifeRadius刀半径, depth深度, points{x,y,z,bul,r}, orgOffset(源偏移)} */ VLines: any[] = [] offsetInfo = '' /** 是否二维造型 */ isVKnifeModel(): boolean { return this.offsetList.length > 0 } /** 是否三维造型 */ is3VModel(): boolean { return this.offsetList.length == 0 && this.pointList.some(t => Math.abs(t.depth - this.depth) > 0.01) } constructor(data: any = null) { if (data != null) { this.modelId = data.modelId this.lineId = data.lineId this.textureId = data.textureId this.face = data.face this.knifeName = data.knifeName ? data.knifeName.trim() : '' this.knifeRadius = StringFormat.toFixed(data.knifeRadius, 3) this.depth = StringFormat.toFixed(data.depth, 3) if (data.modelPoint) data.modelPoint.forEach(pt => { this.pointList.push(new BlockModelPoint(pt)) }) if (data.modelOffSet) data.modelOffSet.forEach(os => this.offsetList.push(new ModelOffsetData(os))) if (this.offsetList.length > 0) { let names: any = [] for (let os of this.offsetList) { if (os.name == this.knifeName) continue if (names.includes(os.name)) continue names.push(name) } if (names.length == 0) this.offsetInfo = `${this.offsetList.length - 1}` else this.offsetInfo = `${this.offsetList.length - 1}(${names.join(' ')})` } if (data.originModeling) { this.originModeling = JSON.parse(JSON.stringify(data.originModeling)) // 计算造型 // this.countModelWidthAndLength(this) } } } } /** 造型点 */ export class BlockModelPoint { /** 坐标X */ pointX: number = 2 /** 坐标Y */ pointY: number = 2 /** 半径 */ radius: number = 0 /** 深度 */ depth: number = 6 /** 凹凸度 */ curve: number = 0 constructor(data: any = null) { if (data != null) { this.pointX = StringFormat.toFixed(data.PointX || data.pointX) this.pointY = StringFormat.toFixed(data.PointY || data.pointY) this.radius = StringFormat.toFixed(Math.abs(data.Radius || data.radius)) this.depth = StringFormat.toFixed(data.Depth || data.depth) this.curve = data.Curve || data.curve } } copy(): BlockModelPoint { let obj = new BlockModelPoint() obj.pointX = this.pointX obj.pointY = this.pointY obj.radius = this.radius obj.depth = this.depth obj.curve = this.curve return obj } } /** 二维造型的偏移数据 */ export class ModelOffsetData { /** 刀名称 */ name: string = '' /** 偏移 */ offset: number = 0 /** 刀半径 */ radius: number = 0 /** 深度 */ depth: number = 0 /** 角度 */ angle: number = 0 /** 板面类型 */ face: FaceType = FaceType.UNSET fullName() { return `偏移${this.offset} 深${this.depth} 刀${this.name}` } constructor(data: any = null) { if (data != null) { let off = 0 if (data.offset != undefined) { off = data.offset } else if (data.value != undefined) { off = data.value } else if (data.value != undefined) { off = data.value } this.name = data.Name != undefined ? data.Name : data.name this.offset = StringFormat.toFixed(data.offset || data.value || data.value) this.radius = StringFormat.toFixed(data.Radius || data.radius) this.depth = StringFormat.toFixed(data.Deep || data.depth) this.face = data.Face != undefined ? data.Face : data.face this.angle = StringFormat.toFixed(data.Angle || data.angle) } } } /** * 侧面造型 所在的面 0 下 1 右 2上 3 左 其它待测试 */ export enum SideFaceType { /** 下 */ BOTTOM = 0, /** 右 */ RIGHT = 1, /** 上 */ TOP = 2, /** 左 */ LEFT = 3, /** 左侧面 */ LEFT_SIDE = 21, /** 右侧面 */ RIGHT_SIDE = 22, /** 上侧面 */ TOP_SIDE = 23, /** 下侧面 */ BOTTOM_SIDE = 24, /** 弧形侧面 */ CURVED_SIDE = 29, /** 异形侧面 */ SPECIAL_SHAPED_SIDE = 30, } /** 侧边造型 * * 侧面造型的点阵判断逻辑 * * 提要: * 1、 face 为 该造型在该板件的第几条边上 * 2、 originModeling 内的造型轮廓点阵的 X Y轴 为 : * 以该造型为正面 且小板板面朝上 造型为正面的左下角为原点 板厚 为 Y 横象为X * 注:最终使用的时候 要得到该造型 对应机台的 轮廓数据和刀路数据 * * 平行判断 参考 checkIsTilt 修改一个新的方法 * 是否在板内 可使用 isPointInBlock * * 要求:要得到 * * 转换逻辑 * 1、通过face 获取 该造型所在的边 * 2、将这条边 与 板件的坐标轴做比较 判断平行 * 情况1:与板件的X轴 平行 则造型 可能为 上 || 下 ,使用 isPointInBlock 判断 具体是上 还是下 * 情况2:与板件的Y轴 平行 则造型 可能为 左 || 右 , 使用 isPointInBlock 判断 具体是左 还是右 * 情况3:都不平行 则 朝向的值为斜边 * 最终得到造型的朝向 * 3、依据边的坐标和造型的朝向 可以 根据造型的轮廓数据转为 对应机台的轮廓数据 和刀路数据 */ export class SideModel { /** 订单号 */ orderId: string = '' /** 小板号 */ blockId: number = 0 /** 造型Id */ modelId: number = 0 /**线ID */ lineId: number = 0; /** 纹路Id */ textureId: number = 0 /** 板面 造型所在的边 第几条边 */ face: SideFaceType = 0 /** 刀号 */ knifeName: string = '' /** 刀半径 */ knifeRadius: number = 0 /** 深度 */ depth: number = 0 /** 是否可以挖空后排版 */ canSpace = false /** 是否是矩形 */ isRect = false /** 是否倾斜 至少有一条边是斜的 */ isTilt = false /** 暂时没用 */ type = '' /** 造型方向 -2 未知(是异常情况 要排查) -1 斜的 0 下 1右 2上 3左 10 左下斜 11 右下斜 12 右上斜 13 左上斜 */ direction = 0 knife?: Knife | null = null /** 有轮廓 */ hasContour() { return this.originModeling != null && this.originModeling.outline != 0 && this.originModeling?.outline?.pts?.length > 0 } /** 侧面造型 宽 */ modelWidth: any = 0 /** 侧面造型 长 */ modelLength: any = 0 /** 侧面造型 起点 */ modelStartPoint: any = null /** 侧面造型 终点 */ modelEndPoint: any = null /** * 造型轮廓(孔转的造型,没有造型轮廓) * OriginModeling.outline.pts.x | y ; outline.buls */ originModeling: any = null /** 点列表 */ pointList: BlockSideModelPoint[] = [] /** 实际替代刀直径 */ realKnifeRadius = 0 /** 实际替代刀点阵 */ realPointList: BlockSideModelPoint[] = [] /** 实际刀编号 */ realKnifeId = -1 /** cnc不能加工 cncUndo */ isCncCanNotProcess: boolean = true /** 超限类型(cnc为何不能加工) unDoType */ cncCanNotProcessType = '' /** 是否在开料机加工 IsDo */ isCutting: boolean = true /** 二维造型的偏移数组 */ offsetList: ModelOffsetData[] = [] /** 转换过的二维刀路路径{isFaceB, name刀名称, offset偏移, knife刀, knifeId刀Id, knifeRadius刀半径, depth深度, points{x,y,z,bul,r}, orgOffset(源偏移)} */ VLines = [] offsetInfo = '' /** 是否二维造型 */ isVKnifeModel(): boolean { return this.offsetList.length > 0 } /** 是否三维造型 */ is3VModel(): boolean { return this.offsetList.length == 0 && this.pointList.some(t => Math.abs(t.depth - this.depth) > 0.01) } constructor(data: any = null) { if (data != null) { this.modelId = data.modelId this.lineId = data.lineId this.textureId = data.textureId this.face = data.face this.knifeName = data.knifeName ? data.knifeName.trim() : '' this.knifeRadius = StringFormat.toFixed(data.knifeRadius, 3) this.depth = StringFormat.toFixed(data.depth, 3) // if (data.originModeling) // { // this.originModeling = JSON.parse(JSON.stringify(data.originModeling)) // MachineHelper.countModelWidthAndLength(this) // } } } } /** 小板区域 */ export enum BlockRegion { /** 左下 = 0 */ LEFT_BOTTOM = 0, /** 右下 = 1 */ RIGHT_BOTTOM = 1, /** 右上 = 2 */ RIGHT_TOP = 2, /** 左上 = 3 */ LEFT_TOP = 3, } /** 造型偏移 */ export class SizeExpand { /** 左 */ left: number = 0 /** 右 */ right: number = 0 /** 上 */ top: number = 0 /** 下 */ bottom: number = 0 /** 板外扩宽 */ width: number = 0 /** 板外扩长 */ length: number = 0 /** 排版外扩宽 */ outWidth: boolean = false /** 排版外扩长 */ outLength: boolean = false /** 是否完成 */ hasDone: boolean = false constructor(data: any = null) { if (data != null) { this.left = data.left || 0 this.right = data.right || 0 this.bottom = data.bottom || 0 this.top = data.top || 0 this.width = (this.left + this.right) || 0 this.length = (this.top + this.bottom) || 0 } } /** 设置长宽 */ setSize() { this.width = this.left + this.right this.length = this.top + this.bottom } toString() { return `左:${this.left.toFixed(2)} 右:${this.right.toFixed(2)} 上:${this.top.toFixed(2)} 下:${this.bottom.toFixed(2)}` } } /** * 板件侧面早些点阵 */ export class BlockSideModelPoint { /** 坐标X */ pointX: number = 2 /** 坐标Y */ pointY: number = 2 /** 坐标Z */ pointZ: number = 2 /** 半径 */ radius: number = 0 /** 深度 */ depth: number = 6 /** 凹凸度 */ curve: number = 0 constructor(data: any = null) { if (data != null) { this.pointX = StringFormat.toFixed(data.pointX || data.x) this.pointY = StringFormat.toFixed(data.pointY || data.y) this.pointZ = StringFormat.toFixed(data.pointZ || data.z) this.radius = StringFormat.toFixed(Math.abs(data.radius || 0)) this.depth = StringFormat.toFixed(data.depth) this.curve = data.curve || data.buls || 0 if (this.radius == 0 && this.curve != 0) { this.radius = 1 / this.curve } } } copy(): BlockSideModelPoint { let obj = new BlockSideModelPoint() obj.pointX = this.pointX obj.pointY = this.pointY obj.radius = this.radius obj.depth = this.depth obj.curve = this.curve return obj } } /** 放置板的边框集合,内部轮廓,偏移后轮廓 */ export class PlaceBorderContour { /** 放置方式 */ placeStyle: PlaceStyle = PlaceStyle.FRONT // 正面 /** 1成品轮廓 必须提前生成 */ borderFinal: CAD.Curve2d[] /** 2原始轮廓 <不含预铣> 必须提前生成 */ borderOrg: CAD.Curve2d[] /** 2.原始轮廓含预铣 border_preCut */ borderPreMilling: CAD.Curve2d[] = [] /** 2原始多段线 《不含预铣》 必须提前生成,用于 计算造型,2v板外干涉轮廓 */ polylineOrg?: Polyline | null = null /** 3.1开料轮廓 <含预铣> */ border: CAD.Curve2d[] = [] /** 3.2真.开料轮廓.同刀辅助._有预铣带预铣) border_tdfz */ borderSameKnifeHelpCut: CAD.Curve2d[] = [] /** 走刀路径(预铣) */ cutLines: CAD.Curve2d[] = [] /** 走刀路径2(预铣 同刀辅助) cutLines_tdfz */ cutLinesSameKnifeHelpCut: CAD.Curve2d[] = [] /** 排版轮廓+预铣+同刀辅助+刀半径+缝隙/2 再与造型外扩并集 border_moving */ borderMoving: CAD.Curve2d[] = [] /** 优化轮廓,用于王者优化 border_wxyh */ borderKingOptimize: CAD.Curve2d[] = [] /** 板内轮廓挖穿造型(borders_inner) */ borderModelThrough: CAD.Curve2d[][] = [] /** 板内轮廓挖穿r(borders_inner_r) */ borderModelThroughR: number[] = [] /** 板内挖穿造型走刀路径,内部走刀轮廓(cutLines_inner) */ cutLinesModelThrough: CAD.Curve2d[][] = [] /** 板内排版轮廓,用于手动排版定位(borders_inner_place) */ borderInnerPlace: CAD.Curve2d[][] = [] /** 板内空间:挖穿造型(spaces_inner) */ blockInnerSpace: PlaceSpace[] = [] /** 板外空间:缺角(spaces_outer) */ blockOuterSpace: PlaceSpace[] = [] /** 空间,包括造型矩形与缺角空间 */ spaces: PlaceSpace[] = [] /** 2v刀路,板外轮廓 */ polylines2vModel: Polyline[] = [] /** 造型,板外轮廓 */ polylinesOutModel: Polyline[] = [] /** 翻转后的这些轮廓集合 */ placeContours: PlaceBorderContour[] constructor(placeStyle: PlaceStyle, borderFinal: CAD.Curve2d[], borderOrg: CAD.Curve2d[]) { this.placeStyle = placeStyle this.borderFinal = borderFinal this.borderOrg = borderOrg this.placeContours = [] } /** 开料刀 半径变化了 */ cutKnifeChanged() { this.cutLines = [] this.cutLinesSameKnifeHelpCut = [] this.borderMoving = [] // this.borderKingOptimize = null; this.borderModelThrough = [] this.borderInnerPlace = [] this.blockInnerSpace = [] this.blockOuterSpace = [] if (this.placeContours) this.placeContours.forEach(t => t.cutKnifeChanged()) } /** 预铣值变化, 将有关轮廓全部清理 */ preValueChanged() { // console.log('预铣值变化, 将有关轮廓全部清理') this.border = [] this.borderSameKnifeHelpCut = [] this.cutLines = [] this.cutLinesSameKnifeHelpCut = [] this.borderMoving = [] // this.borderKingOptimize = null; this.blockOuterSpace = [] if (this.placeContours) this.placeContours.forEach(t => t.preValueChanged()) } /** 同刀辅助 变化了 */ sameKnifeGapChanged() { this.borderSameKnifeHelpCut = [] this.cutLinesSameKnifeHelpCut = [] this.borderMoving = [] // this.borderKingOptimize = null; this.blockOuterSpace = [] if (this.placeContours) this.placeContours.forEach(t => t.sameKnifeGapChanged()) } /** 克隆 */ clone(): PlaceBorderContour { let newObj = new PlaceBorderContour(this.placeStyle, this.borderFinal, this.borderOrg) newObj.borderPreMilling = this.borderPreMilling newObj.polylineOrg = this.polylineOrg newObj.border = this.border newObj.borderSameKnifeHelpCut = this.borderSameKnifeHelpCut newObj.cutLines = this.cutLines newObj.cutLinesSameKnifeHelpCut = this.cutLinesSameKnifeHelpCut newObj.borderMoving = this.borderMoving // newObj.borderKingOptimize = this.borderKingOptimize; newObj.borderModelThrough = this.borderModelThrough newObj.borderModelThroughR = this.borderModelThroughR newObj.cutLinesModelThrough = this.cutLinesModelThrough newObj.borderInnerPlace = this.borderInnerPlace newObj.blockInnerSpace = this.blockInnerSpace newObj.blockOuterSpace = this.blockOuterSpace newObj.spaces = this.spaces newObj.polylines2vModel = this.polylines2vModel newObj.polylinesOutModel = this.polylinesOutModel newObj.placeContours = [] for (let pc of this.placeContours) { if (pc) { let npc = pc.clone() newObj.placeContours.push(npc) } } console.log('克隆', newObj) return newObj } } /** 优化空间 */ export class PlaceSpace { /** 大板ID */ boardId: number /** 空间ID */ spaceId: number /** 坐标x */ x: number /** 坐标y */ y: number /** 宽 */ width: number /** 长 */ length: number /** 是否是小板内部造型空间 IsInner */ isBlockInnerSpace = false /** 顶点Y */ topY(): number { return this.y + this.length } /** 右边X */ topX(): number { return this.x + this.width }; constructor(x: number, y: number, width: number, length: number) { this.boardId = 0 this.spaceId = 0 this.x = x this.y = y this.width = width this.length = length } /** 克隆 */ clone(): PlaceSpace { let obj = new PlaceSpace(this.x, this.y, this.width, this.length) return obj } static create(x1, y1, x2, y2): PlaceSpace { return new PlaceSpace(x1, y1, x2 - x1, y2 - y1) } } /** 开料板材 */ export class PlaceMaterial { /** 订单号(*) */ orderId = '' /** 板材ID(*) */ goodsId = '' /** 板材名称(*) */ goodsName = '' /** 规格(*) */ spec = '' /** 材质(*) */ material = '' /** 颜色(*) */ color = '' /** 品牌(*) */ brand = '' /** 有纹路 */ hasTexture = false /** 最后保存时间 */ updateTime = '' /** 纹路标识 */ get textureFlag(): string { return this.hasTexture ? '有' : '无' } /** 板材全名 */ get fullName(): string { return `${this.hasTexture ? '' : '【无纹】'}${this.thickness} ${this.goodsName} ${this.material} ${this.color}` } /** 板材原宽 */ orgWidth = 1220 /** 板材原长 */ orgLength = 2440 /** 板宽,用于生产 */ width = 1220 /** 板长 */ length = 2440 /** 板厚 */ thickness = 18 /** 全部尺寸 */ get fullSize(): string { return `${this.length}*${this.width}*${this.thickness}` } /** 修边值(*) Border */ cutBorder = 3 /** 开料刀直径(*) CutDia */ diameter = 6 /** 开料刀路间隙(*) CutGap */ cutKnifeGap = 1 /** 预铣值 PreCutValue */ preMillingSize = 0 /** 是否辅助开料 HelpCut */ isHelpCut = false /** 辅助开料标识 */ get strHelpCut() { return this.isHelpCut ? '✔' : '✘' } /** 同刀辅助开料偏移 SameKnifeHelpCutGap */ helpCutGap = 0 /** 开料刀ID */ cutKnifeId = -1 /** 开料刀名称 */ cutKnifeName = '' /** 辅助刀ID */ helpKnifeId = -1 /** 辅助刀名称 */ helpKnifeName = '' get strHelpKnifeName() { return this.isHelpCut ? this.helpKnifeName : '' } /** 是否已优化(*) isSorted */ isOptimized = false get optimizedFlag() { return this.isOptimized ? '是' : '-' } /** 大板数(*) */ boardCount = 0 /** 余料板数 */ remainBoardCount = 0 /** 最小板号(*) */ minBoardId = 0 /** 最大板号(*) */ maxBoardId = 0 /** 当前板号 */ currentBoardId = 0 /** 总平均利用率(*) AvgLyr_All */ avgUsageRateAll = 0 /** 前N块板(不包含最后一块板)的平均利用率(*) AvgLyr_NoLastOne */ avgUsageRateExcludeLastBoard = 0 /** 最后一块板的利用率(*) Lyr_LastOne */ usageRateLastBoard = 0 /** 分配到该板材的 小板数量 */ allBlockCount = 0 /**分配到该板材的优化后小板数量 -- 选择优化的板件数目 */ selectedBlockCount = 0 /** 分配到该板材的优化后 未被优化的 小板数量 */ noPlaceBlockCount = 0 /** 优化时大板数(*) */ optimizingBoardCount = 0 /** 优化时余料板数 */ optimizingRemainBoardCount = 0 /** 优化时不含余料的大板数 */ get OptimizingNoRemainBoardCount() { return this.optimizingBoardCount - this.optimizingRemainBoardCount } /** 优化时总平均利用率(*) */ optimizingAvgUsageRateAll = 0 /** 优化时前N块板(不包含最后一块板)的平均利用率(*) */ optimizingAvgUsageRateExcludeLastBoard = 0 /** 优化时最后一块板的利用率(*) */ optimizingUsageRateLastBoard = 0 /** 优化时间 */ placeTime /** 使用大板情况(*) */ usedBoardInfo = '' /** 小板排版情况(*) */ blockPlaceInfo = '' /** 余料板情况 */ remainBoardInfo = '' /** 翻面开料的大板数 BoardCount_do2Face */ boardCountFlipFace = 0 /** 小板数 */ blockCount = 0 /** 小板总面积 */ blockArea = 0 /** 封边长度 [{t:1,l:233}, {t:2,l:100}] */ edgeSealLengthList: any = [] edgeSealLengthStr() { let s = '' for (let rt of this.edgeSealLengthList) { s += `[${rt.t}]${rt.l}米;` } return s } /** 余料前利用(异形优化) */ // ScrapBoardList: ScrapBoard[] = []; remainBoardList: RemainBoard[] = [] /** 后余料板 */ remainList: any[] = [] /** 大板(优化)列表 */ boardList: PlaceBoard[] = [] /** 小板(优化)列表 */ blockList: PlaceBlock[] = [] /** 是否有锁定的大板 */ hasBoardLocked() { return this.boardList.some(t => t.isLocked) } /** 最优优化结果(临时) */ tempBestPlaceResult?: MaterialPlaceResult | null = null tempBestPlaceResultLast?: MaterialPlaceResult | null = null tempBestPlaceResultLastTime = 0 /** 需要最后一片重新计算 */ rePlaceLastBoardRequired = false tempPlaceUnregular: boolean = false /** 最优优化结果(临时)标识 */ tempPlaceResultFlag() { return (this.tempBestPlaceResult) ? '有' : '-' } /** 最优优化结果是否只使用没锁定的 */ tempPlaceResultOnyUnlockedBoard = false /** 最后优化错误信息 */ tempPlaceResultError: string = '' /** 移动小板临时仓 */ moveBlockList: PlaceBlock[] = [] /** 新优化前原配置,用于取消优化后还原到原先的配置 */ savedSetting constructor(data: any = null) { if (data != null) { this.boardList = data?.boardList || [] this.boardCount = data?.boardCount || 0 this.orderId = data.orderId this.goodsId = data.goodsId this.goodsName = data.goodsName this.spec = data.spec this.material = data.material this.color = data.color this.brand = data.brand this.hasTexture = true if (!(data.hasTexture == null || data.hasTexture == undefined)) this.hasTexture = data.hasTexture this.orgWidth = StringFormat.toFixed(Number(data.orgWidth || data.width)) this.orgLength = StringFormat.toFixed(Number(data.orgLength || data.length)) this.width = StringFormat.toFixed(Number(data.width)) this.length = StringFormat.toFixed(Number(data.length)) this.thickness = StringFormat.toFixed(Number(data.thickness)) this.cutBorder = StringFormat.toFixed(Number(data.cutBorder)) this.diameter = StringFormat.toFixed(Number(data.diameter)) this.cutKnifeGap = StringFormat.toFixed(Number(data.cutKnifeGap)) this.preMillingSize = data.preMillingSize || 0 this.isHelpCut = data.isHelpCut || false this.helpCutGap = data.helpCutGap || 0 this.cutKnifeId = data.cutKnifeId || -1 this.helpKnifeId = data.helpKnifeId || -1 this.isOptimized = Boolean(data.isOptimized) this.boardCount = StringFormat.toFixed(Number(data.boardCount)) this.remainBoardCount = StringFormat.toFixed(data.remainBoardCount ? Number(data.remainBoardCount) : 0) this.minBoardId = Number(data.minBoardId) this.maxBoardId = Number(data.maxBoardId) this.avgUsageRateAll = StringFormat.toFixed(Number(data.avgUsageRateAll)) this.avgUsageRateExcludeLastBoard = StringFormat.toFixed(Number(data.avgUsageRateExcludeLastBoard)) this.usageRateLastBoard = StringFormat.toFixed(Number(data.usageRateLastBoard)) this.usedBoardInfo = data.usedBoardInfo this.blockPlaceInfo = data.blockPlaceInfo this.remainBoardInfo = data.remainBoardInfo ? data.remainBoardInfo : '' // this.remainBoardList = data.remainBoardList ? data.remainBoardList : [] if (Array.isArray(data.remainBoardList)) { this.remainBoardList = data.remainBoardList } else { this.remainBoardList = data.remainBoardInfo ? JSON.parse(this.remainBoardInfo) : '' } this.updateTime = data['this.updateTime'] || '' } } /** 保存 原尺寸,开料刀,预铣,辅助开料 */ saveSetting() { let setting: any = {} // 尺寸, setting.orgWidth = this.orgWidth setting.orgLength = this.orgLength setting.width = this.width setting.length = this.length setting.thickness = this.thickness setting.preMillingSize = this.preMillingSize setting.isHelpCut = this.isHelpCut setting.helpCutGap = this.helpCutGap setting.diameter = this.diameter setting.cutKnifeId = this.cutKnifeId setting.cutKnifeName = this.cutKnifeName setting.helpKnifeId = this.helpKnifeId setting.helpKnifeName = this.helpKnifeName this.savedSetting = setting // 小板备份资料 let createTime = Date.now() for (let block of this.blockList) { if (block.blockDetail) { let savedObj = block.blockDetail.savedSetting if (savedObj && savedObj.createTime == createTime) break // 已备份 block.blockDetail.saveSetting() block.blockDetail.savedSetting.createTime = createTime } } } loadSetting() { if (this.savedSetting == null) return // 尺寸, this.orgWidth = this.savedSetting.orgWidth this.orgLength = this.savedSetting.orgLength this.width = this.savedSetting.width this.length = this.savedSetting.length this.thickness = this.savedSetting.thickness this.preMillingSize = this.savedSetting.preMillingSize this.isHelpCut = this.savedSetting.isHelpCut this.helpCutGap = this.savedSetting.helpCutGap this.diameter = this.savedSetting.diameter this.cutKnifeId = this.savedSetting.cutKnifeId this.cutKnifeName = this.savedSetting.cutKnifeName this.helpKnifeId = this.savedSetting.helpKnifeId this.helpKnifeName = this.savedSetting.helpKnifeName for (let block of this.blockList) { if (block.blockDetail) { block.blockDetail.loadSetting() block.blockDetail.savedSetting = null } } } } /** 排单大板 */ export class PlaceBoard { /** 数据源ID */ sourceId = 0 /** 大板编码(余料板号) */ boardNo = '' /** 大板ID */ boardId = 0 /** 大板ID(按全排单) */ fullBoardId = 0 /** 大板宽 */ width = 0 /** 大板长/高 */ length = 0 /** 面积 */ area = 0 /** 小板数 */ blockCount = 0 /** 利用面积 BlockSize */ blockArea = 0 /** 利用率 */ usageRate = 0 /** 余料板异形 IsOddmengt */ isAdnormal() { return this.points && this.points.length > 0 } /** 余料板异形点{x,y,bul} */ points: any[] = [] /** 是否加工2面, 需反面 IsDo2Face */ isTwoFaceProcessing() { let res = this.blockList.some(e => e.isDoubleFaceProcess()) return res } /** 是否锁定 */ isLocked = false /** 是否开料 */ isCuted = false /** 开料状态 * * 0 未开料 1 开料中 2 已开料 */ cutedType = 0 /** 小板列表 */ blockList: PlaceBlock[] = [] /** 余料板列表 ScrapBlockList */ remainBlockList: RemainBlock[] = [] /** 需要生成余料空间 needToScrapSpace */ isCreateRemainSpace = false /** 异形大板的轮廓线 */ polyline?: Polyline /** 无法加工的左边出现造型 */ hasModelOnLeft = false /** 无法加工的右边出现造型 */ hasModelOnRight = false /** 构造函数 */ constructor(boardId: number, width: number, length: number, sourceId = 0, boardNo = '') { this.sourceId = sourceId this.boardId = boardId this.width = width this.length = length this.boardNo = boardNo this.area = width * length * 0.000001 this.blockList = [] } reset() { this.blockCount = this.blockList.length this.blockArea = ArrayExt.sum(this.blockList, t => t.area) this.usageRate = (100 * this.blockArea) / this.area // this.isTwoFaceProcessing = this.blockList.some(t => t.isCutOtherFace) } addBlock(block: PlaceBlock) { if (this.blockList.includes(block)) return this.blockList.push(block) this.reset() } removeBlock(block: PlaceBlock) { let index = this.blockList.findIndex(t => t == block) if (index == -1) return this.blockList.splice(index, 1) this.reset() } getSize(): string { return `${this.width}*${this.length}` } } /** 实际开料的板材 || 余料板材 */ export class RemainBoard { /** 余料板ID */ id: number | string = '' /** 源排单ID */ orgPlanId: number | string = '' /** 排单ID */ planId: number | string = '' /** 状态(未使用 = 0, 已使用 = 1) */ status: number = 0 /** 商品ID */ goodsId: number | string = '' /** 商品名 */ goodsName: string = '' /** 材质 */ material: string = '' // /** 材料名 */ // materialName: string = ''; /** 颜色 */ color: string = '' /** 宽 */ width: number = 0 /** 长 */ length: number = 0 /** 品牌 */ brand: string = '' // /** 保存仓库 */ // storeHouse: string = ''; /** 纹路 */ texture?: string /** 排单号 */ planCode: string = '' /** 数量 */ count: number = 0 /** 排版宽 */ placeWidth() { return this.placeStyle % 2 == 0 ? this.width : this.length } /** 排版长 */ placeLength() { return this.placeStyle % 2 == 0 ? this.length : this.width } /** 厚度 */ thickness: number | undefined /** 轮廓 */ outLineJson: string = '{}' /** 备注 */ remark: string = '' /** */ basePolyline: Polyline | undefined /** 排版样式 */ placeStyle: PlaceStyle = PlaceStyle.FRONT /** 排版多段线 */ placePolyline: Polyline | undefined /** 是否已使用 */ isUsed: boolean = false /** 是否已入库 */ isStored = false /** 是否开料 */ isCuted = false /**是否开料 */ cutedType = 0 /** 实际优化板材的优化数据 */ // placeBoardList: BoardPlaceResult[] = [] /** 实际开料大板的数量 */ usedCount = 0 /** 总利用率 */ avgUsageRateAll = 0 /** 前N块板利用率 */ avgUsageRateExcludeLastBoard = 0 /** 最后一块板利用率 */ usageRateLastBoard = 0 copy(): RemainBoard { let obj = new RemainBoard() obj.id = this.id obj.planId = this.planId obj.status = this.status obj.goodsId = this.goodsId obj.goodsName = this.goodsName obj.material = this.material obj.color = this.color obj.width = this.width obj.length = this.length obj.thickness = this.thickness obj.outLineJson = this.outLineJson obj.remark = this.remark obj.placeStyle = this.placeStyle obj.isUsed = this.isUsed obj.texture = this.texture return obj } } /** 余料小板 */ export class RemainBlock { /** 余料板ID */ remainId: number = 0 /** 排版坐标x */ placeX: number /** 排版坐标y */ placeY: number /** 开料宽 */ placeWidth: number /** 开料长 */ placeLength: number /** 是否不规则 */ isUnRegular = false /** 是否重叠 */ isOverlap = false /** 是否已录入余料库 */ isStored = false private pointlist: any = [] points() { if (this.pointlist.length == 0) { this.pointlist.push({ x: 0, y: 0 }) this.pointlist.push({ x: this.placeWidth, y: 0 }) this.pointlist.push({ x: this.placeWidth, y: this.placeLength }) this.pointlist.push({ x: 0, y: this.placeLength }) } return this.pointlist } private pl: Polyline | null = null get polyline() { return this.pl } set polyline(v) { this.pl = v; this.polylineOffset = null } /** 多段线偏移 */ polylineOffset?: Polyline | null constructor(x, y, width, length) { this.placeX = x this.placeY = y this.placeWidth = width this.placeLength = length } /** 修改大小 */ reSize(width, length) { if (this.isUnRegular) return this.placeWidth = width this.placeLength = length this.pointlist = [] this.pl = null this.polylineOffset = null } setPoints(pts) { this.pointlist = pts if (this.pointlist.length == 0 || this.pointlist.length == 4) this.isUnRegular = false else this.isUnRegular = true this.polyline = null this.polylineOffset = null } load(data) { this.remainId = data.remainId this.placeX = data.placeX this.placeY = data.placeY this.placeWidth = data.placeWidth this.placeLength = data.placeLength this.isUnRegular = data.isUnRegular this.pointlist = data.pointlist this.isStored = data.isStored || false } } /** 板材优化结果 */ export class MaterialPlaceResult { /** 线程ID */ threadId = 0 /** 使用时间 */ usedTime = 0 /** 优化次数 */ placeCount = 0 /** 大板数 */ boardCount = 0 /** 总平均利用率 */ avgUsageRateAll = 0 /** 前N块板(不包含最后一块板)的平均利用率 */ avgUsageRateExcludeLastBoard = 0 /** 最后一块板的利用率 */ usageRateLastBoard = 0 /** 余料板数 */ remainBoardCount = 0 /** 大板列表 */ boards: BoardPlaceResult[] = [] /** 小板优化数据 */ results: BlockPlaceResult[] = [] /** 优化是否全部完成 */ placeStoped = false /** 余料板利用情况 */ remailBoardList: any[] = [] constructor() { } /** 比other 更好 */ isBetterThan(other: MaterialPlaceResult): boolean { if (this.boardCount < other.boardCount) return true if (this.usageRateLastBoard < other.usageRateLastBoard) return true return false } } export class BoardPlaceResult { /** 大板ID */ boardId = 0 /** 宽 */ width = 0 /** 长 */ length = 0 /** 是否余料板 */ isRemainBoard = false /** 余料板编码 */ remainNo = '' /** 余料板ID */ remainId = 0 /** 是否废弃物 */ isScrap = false /** 点列表 */ points: any[] = [] /** 小板排版结果 */ blocks: BlockPlaceResult[] = [] /** 小板排版 */ objects: any[] = [] /** 面积 */ area = 0 /** 是否双面加工 */ isTwoFaceProcess = false cutedType = 0 isLock = false /**当前大板的利用率 */ // avgUsageRate = 0 constructor() { } /** 是否有异形板重叠 */ hasOverLapBlock() { for (let i = 0; i < this.blocks.length; i++) { let b1 = this.blocks[i] for (let j = i + 1; j < this.blocks.length; j++) { let b2 = this.blocks[j] if (this.isOverLap(b1, b2)) return true } } return false } /** 两块板是否是否重叠 */ isOverLap(b1: BlockPlaceResult, b2: BlockPlaceResult): boolean { let l1 = { x: b1.placeX, y: b1.placeY + b1.length } let r1 = { x: b1.placeX + b1.width, y: b1.placeY } let l2 = { x: b2.placeX, y: b2.placeY + b2.length } let r2 = { x: b2.placeX + b2.width, y: b2.placeY } if (l1.x > r2.x || l2.x > r1.x) return false if (l1.y < r2.y || l2.y < r1.y) return false return true } } /** 小板优化结果 */ export class BlockPlaceResult { /** 小板号 */ blockId = 0 /** 小板编号 */ blockNo = '' /** 大板ID */ boardId: number /** 排版情况: 排版ID */ placeId: number /** 排版情况: 大板坐标X */ placeX: number // 坐标 /** 排版情况: 大板坐标Y */ placeY: number /** 宽 */ width: number /** 长 */ length: number /** 排版情况正纹 */ placeStyle: PlaceStyle /** 面积 */ area: number constructor(blockId: number, boardId: number, placeId: number, x: number, y: number, width: number, length: number, pstyle: PlaceStyle, area: number) { this.blockId = blockId this.boardId = boardId this.placeId = placeId this.placeX = x this.placeY = y this.placeStyle = pstyle this.width = width this.length = length this.area = area } } export enum PlaceType { /** 凸包模式 (凸包面积) */ Hull = 0, /** 盒子模式 (长乘以宽) */ Box = 1, /** 重力模式(重力) */ Gravity = 2, } export class BlockBorderPoint { /** 板 */ block: PlaceBlock /** 原坐标x */ x: number /** 原坐标y */ y: number /** 大板坐标X */ placeX: number /** 大板坐标Y */ placeY: number /** 拖拉点距切割后板的坐标偏移x */ bx = 0 /** 拖拉点距切割后板的坐标偏移x */ by = 0 /** 在placed线框中的序号 */ curveIndex: number /** 在板的位置: 10:基点(左下点);1:右下角;2:右上角;3:左上角; -1:表示异形非顶点 areaID */ posId: number constructor(block: PlaceBlock, x: number, y: number, index: number, posId: number, bx = 0, by = 0) { this.block = block this.x = x this.y = y this.placeX = (block ? block.placeX : 0) + x this.placeY = (block ? block.placeY : 0) + y this.curveIndex = index this.posId = posId this.bx = bx this.by = by } } /** * 放置位置类 */ export class PlacePositionClass { // 4. 放置配置映射表 private placementConfigs: Record; constructor() { this.placementConfigs = { // 正面放置配置 [PlaceStyle.FRONT]: { widthSource: 'cutWidth', lengthSource: 'cutLength', sealMap: { left: 'sealLeft', right: 'sealRight', top: 'sealTop', bottom: 'sealBottom' }, holeCountMap: { left: 'holeCountLeft', right: 'holeCountRight', top: 'holeCountTop', bottom: 'holeCountBottom' }, direction: Direction.RIGHT, lengthDirection: (block) => block.length > block.width - 0.001 ? Direction.RIGHT : Direction.DOWN }, // 正面右转配置 [PlaceStyle.FRONT_TURN_RIGHT]: { widthSource: 'cutLength', lengthSource: 'cutWidth', sealMap: { left: 'sealBottom', right: 'sealTop', top: 'sealLeft', bottom: 'sealRight' }, holeCountMap: { left: 'holeCountBottom', right: 'holeCountTop', top: 'holeCountLeft', bottom: 'holeCountRight' }, direction: Direction.DOWN, lengthDirection: (block) => block.length > block.width - 0.001 ? Direction.DOWN : Direction.LEFT }, // 正面后转配置 [PlaceStyle.FRONT_TURN_BACK]: { widthSource: 'cutWidth', lengthSource: 'cutLength', sealMap: { left: 'sealRight', right: 'sealLeft', top: 'sealBottom', bottom: 'sealTop' }, holeCountMap: { left: 'holeCountRight', right: 'holeCountLeft', top: 'holeCountBottom', bottom: 'holeCountTop' }, direction: Direction.LEFT, lengthDirection: (block) => block.length > block.width - 0.001 ? Direction.LEFT : Direction.UP }, // 正面左转配置 [PlaceStyle.FRONT_TURN_LEFT]: { widthSource: 'cutLength', lengthSource: 'cutWidth', sealMap: { left: 'sealTop', right: 'sealBottom', top: 'sealRight', bottom: 'sealLeft' }, holeCountMap: { left: 'holeCountTop', right: 'holeCountBottom', top: 'holeCountRight', bottom: 'holeCountLeft' }, direction: Direction.UP, lengthDirection: (block) => block.length > block.width - 0.001 ? Direction.UP : Direction.RIGHT }, // 反面配置 [PlaceStyle.BACK]: { widthSource: 'cutWidth', lengthSource: 'cutLength', sealMap: { left: 'sealRight', right: 'sealLeft', top: 'sealTop', bottom: 'sealBottom' }, holeCountMap: { left: 'holeCountRight', right: 'holeCountLeft', top: 'holeCountTop', bottom: 'holeCountBottom' }, direction: Direction.RIGHT, lengthDirection: (block) => block.length > block.width - 0.001 ? Direction.RIGHT : Direction.UP }, // 反面右转配置 [PlaceStyle.BACK_TURN_RIGHT]: { widthSource: 'cutLength', lengthSource: 'cutWidth', sealMap: { left: 'sealBottom', right: 'sealTop', top: 'sealRight', bottom: 'sealLeft' }, holeCountMap: { left: 'holeCountBottom', right: 'holeCountTop', top: 'holeCountRight', bottom: 'holeCountLeft' }, direction: Direction.DOWN, lengthDirection: (block) => block.length > block.width - 0.001 ? Direction.DOWN : Direction.RIGHT }, // 反面后转配置 [PlaceStyle.BACK_TURN_BACK]: { widthSource: 'cutWidth', lengthSource: 'cutLength', sealMap: { left: 'sealLeft', right: 'sealRight', top: 'sealTop', bottom: 'sealBottom' }, holeCountMap: { left: 'holeCountLeft', right: 'holeCountRight', top: 'holeCountTop', bottom: 'holeCountBottom' }, direction: Direction.LEFT, lengthDirection: (block) => block.length > block.width - 0.001 ? Direction.LEFT : Direction.DOWN }, // 反面左转配置 [PlaceStyle.BACK_TURN_LEFT]: { widthSource: 'cutLength', lengthSource: 'cutWidth', sealMap: { left: 'sealTop', right: 'sealBottom', top: 'sealLeft', bottom: 'sealRight' }, holeCountMap: { left: 'holeCountTop', right: 'holeCountBottom', top: 'holeCountLeft', bottom: 'holeCountRight' }, direction: Direction.UP, lengthDirection: (block) => block.length > block.width - 0.001 ? Direction.UP : Direction.LEFT } }; } /** * 设置块的放置属性 * @param block 块对象 * @param newStyle 新的放置样式 */ static setBlockPlacementProperties(block: Block, newStyle: PlaceStyle): Block { // 创建一个临时实例来访问 placementConfigs const instance = new PlacePositionClass(); const config = instance.placementConfigs[newStyle]; if (!config) return block; // 设置尺寸 block.placeWidth = block[config.widthSource] as number; block.placeLength = block[config.lengthSource] as number; // 设置封边 block.placeSealLeft = block[config.sealMap.left]; block.placeSealRight = block[config.sealMap.right]; block.placeSealTop = block[config.sealMap.top]; block.placeSealBottom = block[config.sealMap.bottom]; // 设置孔位计数 block.holeCountSideLeft = block[config.holeCountMap.left] as number; block.holeCountSideRight = block[config.holeCountMap.right] as number; block.holeCountSideTop = block[config.holeCountMap.top] as number; block.holeCountSideBottom = block[config.holeCountMap.bottom] as number; // 设置方向,严格参照 BlockHelper.resetPlaceStyle switch (newStyle) { case PlaceStyle.FRONT: block.placeDirection = '→'; block.placeDirection_Length = block.length > block.width - 0.001 ? '→' : '↓'; break; case PlaceStyle.FRONT_TURN_RIGHT: block.placeDirection = '↓'; block.placeDirection_Length = block.length > block.width - 0.001 ? '↓' : '←'; break; case PlaceStyle.FRONT_TURN_BACK: block.placeDirection = '←'; block.placeDirection_Length = block.length > block.width - 0.001 ? '←' : '↑'; break; case PlaceStyle.FRONT_TURN_LEFT: block.placeDirection = '↑'; block.placeDirection_Length = block.length > block.width - 0.001 ? '↑' : '→'; break; case PlaceStyle.BACK: block.placeDirection = '→'; block.placeDirection_Length = block.length > block.width - 0.001 ? '→' : '↑'; break; case PlaceStyle.BACK_TURN_RIGHT: block.placeDirection = '↓'; block.placeDirection_Length = block.length > block.width - 0.001 ? '↓' : '→'; break; case PlaceStyle.BACK_TURN_BACK: block.placeDirection = '←'; block.placeDirection_Length = block.length > block.width - 0.001 ? '←' : '↓'; break; case PlaceStyle.BACK_TURN_LEFT: block.placeDirection = '↑'; block.placeDirection_Length = block.length > block.width - 0.001 ? '↑' : '←'; break; default: block.placeDirection = ''; block.placeDirection_Length = ''; break; } return block; } static getOriginalSides(placeStyle: PlaceStyle): number[] { // let orgSides = [0, 1, 2, 3]; let orgSides = [EdgeType.BOTTOM, EdgeType.RIGHT, EdgeType.TOP, EdgeType.LEFT] switch (placeStyle) { case PlaceStyle.FRONT: // 正面 break case PlaceStyle.FRONT_TURN_RIGHT: // 正面右转 orgSides[EdgeType.BOTTOM] = EdgeType.RIGHT orgSides[EdgeType.RIGHT] = EdgeType.TOP orgSides[EdgeType.TOP] = EdgeType.LEFT orgSides[EdgeType.LEFT] = EdgeType.BOTTOM break case PlaceStyle.FRONT_TURN_BACK: // 正面后转 orgSides[EdgeType.BOTTOM] = EdgeType.TOP orgSides[EdgeType.RIGHT] = EdgeType.LEFT orgSides[EdgeType.TOP] = EdgeType.BOTTOM orgSides[EdgeType.LEFT] = EdgeType.RIGHT break case PlaceStyle.FRONT_TURN_LEFT: // 正面左转 orgSides[EdgeType.BOTTOM] = EdgeType.LEFT orgSides[EdgeType.RIGHT] = EdgeType.BOTTOM orgSides[EdgeType.TOP] = EdgeType.RIGHT orgSides[EdgeType.LEFT] = EdgeType.TOP break case PlaceStyle.BACK: // 反面 orgSides[EdgeType.BOTTOM] = EdgeType.BOTTOM orgSides[EdgeType.RIGHT] = EdgeType.LEFT orgSides[EdgeType.TOP] = EdgeType.TOP orgSides[EdgeType.LEFT] = EdgeType.RIGHT break case PlaceStyle.BACK_TURN_RIGHT: // 反面右转 orgSides[EdgeType.BOTTOM] = EdgeType.LEFT orgSides[EdgeType.RIGHT] = EdgeType.TOP orgSides[EdgeType.TOP] = EdgeType.RIGHT orgSides[EdgeType.LEFT] = EdgeType.BOTTOM break case PlaceStyle.BACK_TURN_BACK: // 反面后转 orgSides[EdgeType.BOTTOM] = EdgeType.TOP orgSides[EdgeType.RIGHT] = EdgeType.RIGHT orgSides[EdgeType.TOP] = EdgeType.BOTTOM orgSides[EdgeType.LEFT] = EdgeType.LEFT break case PlaceStyle.BACK_TURN_LEFT: // 反面左转 orgSides[EdgeType.BOTTOM] = EdgeType.RIGHT orgSides[EdgeType.RIGHT] = EdgeType.BOTTOM orgSides[EdgeType.TOP] = EdgeType.LEFT orgSides[EdgeType.LEFT] = EdgeType.TOP break default: break } return orgSides } /** 翻转小板,翻转动作opType: 0翻面 1右转 2后转 3左转 */ static turnBlock(block: PlaceBlock, pm: PlaceMaterial, opType: number) { let orgStyle = block.placeStyle let newStyle = BlockHelper.getTurnedPlaceStyle(orgStyle, opType) let orgPlaceX = block.placeX - block.placeOffX let orgPlaceY = block.placeY - block.placeOffY let offset = BlockSizePlus.getOffDis(block, newStyle) let newPlaceX = orgPlaceX + offset.x let newPlaceY = orgPlaceY + offset.y block.placeOffX = offset.x block.placeOffY = offset.y // 修改小板的放置方式 BlockHelper.resetPlaceStyle(block, newStyle) // 重置放置,检查冲突 BlockHelper.replaceBlock(pm, block, block.boardId, new Point(newPlaceX, newPlaceY)) } /** 获得翻转后的新放置方式, 翻转动作opType: 0翻面 1右转 2后转 3左转 */ static getTurnedPlaceStyle(orgStyle: PlaceStyle, opType: number): PlaceStyle { let newStyle: number = orgStyle if (opType == 0) // 翻面 { switch (orgStyle) { case PlaceStyle.FRONT: // 正面 newStyle = PlaceStyle.BACK // 反面 break case PlaceStyle.FRONT_TURN_RIGHT: // 正面右转 newStyle = PlaceStyle.BACK_TURN_LEFT // 反面左转 break case PlaceStyle.FRONT_TURN_BACK: // 正面后转 newStyle = PlaceStyle.BACK_TURN_BACK // 反面后转 break case PlaceStyle.FRONT_TURN_LEFT: // 正面左转 newStyle = PlaceStyle.BACK_TURN_RIGHT // 反面右转 break case PlaceStyle.BACK: // 反面 newStyle = PlaceStyle.FRONT // 正面 break case PlaceStyle.BACK_TURN_RIGHT: // 反面右转 newStyle = PlaceStyle.FRONT_TURN_LEFT // 正面左转 break case PlaceStyle.BACK_TURN_BACK: // 反面后转 newStyle = PlaceStyle.FRONT_TURN_BACK // 正面后转 break case PlaceStyle.BACK_TURN_LEFT: // 反面左转 newStyle = PlaceStyle.FRONT_TURN_RIGHT // 正面右转 break default: break } } else if (opType == 1) // 右转 { newStyle = orgStyle + 1 if (newStyle == 4) newStyle = 0 if (newStyle == 8) newStyle = 4 } else if (opType == 2) // 后转 { newStyle = orgStyle + 2 if (orgStyle < 4 && newStyle >= 4) newStyle = newStyle - 4 if (orgStyle >= 4 && newStyle >= 8) newStyle = newStyle - 4 } else if (opType == 3) // 左转 { newStyle = orgStyle - 1 if (newStyle == 3) newStyle = 7 if (newStyle == -1) newStyle = 3 } return newStyle } static resetPlaceStyle(block: PlaceBlock, newStyle: PlaceStyle) { block.placeStyle = newStyle let _width = block.cutWidth let _lenth = block.cutLength if (block.width > block.length) { block.cutWidth = Math.max(_width, _lenth) block.cutLength = Math.min(_width, _lenth) } else { block.cutWidth = Math.min(_width, _lenth) block.cutLength = Math.max(_width, _lenth) } let _block: Block = { placeWidth: block.placeWidth, placeLength: block.placeLength, cutWidth: block.cutWidth, cutLength: block.cutLength, width: block.width, length: block.length, sealLeft: block.sealLeft, sealRight: block.sealRight, sealTop: block.sealTop, sealBottom: block.sealBottom, placeSealLeft: block.placeSealLeft, placeSealRight: block.placeSealRight, placeSealTop: block.placeSealTop, placeSealBottom: block.placeSealBottom, holeCountLeft: block.holeCountLeft(), holeCountRight: block.holeCountRight(), holeCountTop: block.holeCountTop(), holeCountBottom: block.holeCountBottom(), holeCountSideLeft: block.holeCountSideLeft, holeCountSideRight: block.holeCountSideRight, holeCountSideTop: block.holeCountSideTop, holeCountSideBottom: block.holeCountSideBottom, placeDirection: block.placeDirection, placeDirection_Length: block.placeDirection_Length } this.setBlockPlacementProperties(_block, newStyle) } } // 1. 定义Block接口 interface Block { // 尺寸相关 placeWidth: number; placeLength: number; cutWidth: number; cutLength: number; width: number; length: number; // 封边相关 sealLeft: any; sealRight: any; sealTop: any; sealBottom: any; placeSealLeft: any; placeSealRight: any; placeSealTop: any; placeSealBottom: any; // 孔位计数相关 holeCountLeft: number; holeCountRight: number; holeCountTop: number; holeCountBottom: number; holeCountSideLeft: number; holeCountSideRight: number; holeCountSideTop: number; holeCountSideBottom: number; // 方向相关 placeDirection: string; placeDirection_Length: string; } // 2. 定义方向枚举(增强类型安全) enum Direction { RIGHT = '→', LEFT = '←', UP = '↑', DOWN = '↓' } // 3. 定义放置配置接口 interface PlacementConfig { widthSource: keyof Block; // 取宽度的来源 lengthSource: keyof Block; // 取长度的来源 sealMap: { // 封边映射 left: keyof Block; right: keyof Block; top: keyof Block; bottom: keyof Block; }; holeCountMap: { // 孔位计数映射 left: keyof Block; right: keyof Block; top: keyof Block; bottom: keyof Block; }; direction: Direction; // 基础方向 lengthDirection: (block: Block) => Direction; // 长度方向计算函数 } //import { DrawRect } from "../DrawRect"; //开料生产 export class KLSC { xbang: YH_bang[]; //小板集合 Bakbang: YH_bang[]; //备份小板集合 HB_bang: number[] = []; //合并的板 HB: number[][] = []; //合并板的数组 B_k: number; //大板宽 B_g: number; //大板高 dt: number; //刀头大小(含修边) wzx: number; //临时用于打印 wzy: number; //临时用于打印 jl_mz: number; //用于测试距离或者面积优选 SCid: number[] = []; //用于存化顺序的板的bangid //f = () => 5; constructor(xbang: YH_bang[], Bang_k: number, Bang_g: number, dt: number, wzx: number, wzy: number, JL_MZ: number) //false JL ture MZ { this.xbang = JSON.parse(JSON.stringify(xbang)); //this.xbang = [...xbang]; this.Bakbang = JSON.parse(JSON.stringify(xbang)); this.B_g = Bang_g; this.B_k = Bang_k; this.dt = dt; this.wzx = wzx; this.wzy = wzy; this.jl_mz = JL_MZ; this.XDscjs(); }; //查找距离中心最近,且跟最大的板相差不大于容差面积 rcmz 的板 返加YH_bang[].bangid MaxMZ = (rcmz: number): number => { let tmepckb: number; let tmepckb1: number; let tempxbang: YH_bang[] = []; this.xbang.sort((b, a) => a.pbg * a.pbk - b.pbg * b.pbk); let maxmz = this.xbang[0].pbg * this.xbang[0].pbk / 1000000; let maxbangid = this.xbang[0].bangid; for (let i = 0; i < this.xbang.length; i++) { if (this.xbang[i].pbg > this.xbang[i].pbk) { tmepckb = this.xbang[i].pbg / this.xbang[i].pbk; } else { tmepckb = this.xbang[i].pbk / this.xbang[i].pbg; } if (this.xbang[0].pbg > this.xbang[0].pbk) { tmepckb1 = this.xbang[0].pbg / this.xbang[0].pbk; } else { tmepckb1 = this.xbang[0].pbk / this.xbang[0].pbg; } if (equaln(this.xbang[i].pbg * this.xbang[i].pbk / 1000000, maxmz, rcmz) && equaln(tmepckb, tmepckb1, 2)) { tempxbang.push(this.xbang[i]); } } if (tempxbang.length > 0) { return this.minJL(tempxbang); } else { return maxbangid; } }; //查找指定Bangid的板 返回在数组中的位置ID f = () => 5; getID = (bangid: number): number => this.xbang.findIndex((n) => n.bangid == bangid); //查找备份板Bangid的板 返回在数组中的位置ID f = () => 5; getID_Bkb = (bangid: number): number => this.Bakbang.findIndex((n) => n.bangid == bangid); //查找距离最近的板 返加YH_bang[].bangid minJL = (xbang: YH_bang[]): number => { xbang.sort((b, a) => Math.hypot(this.B_k / 2 - b.x - b.pbk / 2, this.B_g / 2 - b.y - b.pbg / 2) - Math.hypot(this.B_k / 2 - a.x - a.pbk / 2, this.B_g / 2 - a.y - a.pbg / 2)); return xbang[0].bangid; }; //查找左边且Y位置一样的板,, 返加YH_bang[].bangid F_Left = (bangid: number): number => { let a = this.xbang.find((n) => equaln(n.x + n.pbk + this.dt, this.xbang[this.getID(bangid)].x, 0.001) && equaln(n.y, this.xbang[this.getID(bangid)].y, 0.001) && n.ishb == false); if (a == undefined) { return; } return a.bangid; }; //查找左边关连的板,并写入 F_GL_LR = () => { let temp: number; let bangIndex: number; let maxkd: number = 0; let maxid: number; //bangid if (this.xbang.length > 1) { for (let i = 0; i < this.xbang.length; i++) { bangIndex = i; while (1) //左边 { if (this.xbang[bangIndex].pbg > this.xbang[bangIndex].pbk && this.xbang[bangIndex].pbk < 200 && this.xbang[bangIndex].ishb == false) { temp = this.xbang.findIndex(n => n.x + n.pbk < this.xbang[bangIndex].x && n.y <= this.xbang[bangIndex].y && this.XJcd(n.bangid, this.xbang[bangIndex].bangid)[1] > this.xbang[bangIndex].pbk); if (temp != -1) { if (this.xbang[temp].pbk > maxkd) { maxkd = this.xbang[temp].pbk; maxid = this.xbang[temp].bangid; } if (this.xbang[temp].pbk > 200) { this.xbang[temp].isgr = true; this.xbang[temp].gr.push(this.xbang[bangIndex].bangid); this.xbang[bangIndex].grid = this.xbang[temp].bangid; break; } else { bangIndex = temp; } } else { break; } } else { break; } } bangIndex = i; while (1) //右边 { if (this.xbang[bangIndex].pbg > this.xbang[bangIndex].pbk && this.xbang[bangIndex].pbk < 200 && this.xbang[bangIndex].ishb == false) { temp = this.xbang.findIndex(n => n.x > this.xbang[bangIndex].x + this.xbang[bangIndex].pbk && this.LR_is(this.xbang[bangIndex].bangid, n.bangid) == false && n.pbg > 300 && this.XJcd(n.bangid, this.xbang[bangIndex].bangid)[1] > this.xbang[bangIndex].pbk); if (temp != -1) { if (this.xbang[temp].pbk > maxkd) { maxkd = this.xbang[temp].pbk; maxid = this.xbang[temp].bangid; } if (this.xbang[temp].pbk > 200) { this.xbang[temp].isgr = true; this.xbang[temp].gr.push(this.xbang[bangIndex].bangid); this.xbang[bangIndex].grid = this.xbang[temp].bangid; break; } else { bangIndex = temp; } } else { break; } } else { break; } } } }; }; //查找上下边关连的板,并写入 F_GL_TD = () => { let temp: number; let bangIndex: number; let maxkd: number = 0; let maxid: number; //bangid if (this.xbang.length > 1) { for (let i = 0; i < this.xbang.length; i++) { bangIndex = i; while (1) //上面 { if (this.xbang[bangIndex].pbg < this.xbang[bangIndex].pbk && this.xbang[bangIndex].pbg < 200 && this.xbang[bangIndex].ishb == false) { temp = this.xbang.findIndex(n => n.y > this.xbang[bangIndex].y + this.xbang[bangIndex].pbg && n.x + 0.01 <= this.xbang[bangIndex].x && this.XJcd(n.bangid, this.xbang[bangIndex].bangid)[0] > this.xbang[bangIndex].pbg); if (temp != -1) { if (this.xbang[temp].pbg > maxkd) { maxkd = this.xbang[temp].pbg; maxid = this.xbang[temp].bangid; } if (this.xbang[temp].pbg > 200) { this.xbang[temp].isgr = true; this.xbang[temp].gr.push(this.xbang[bangIndex].bangid); this.xbang[bangIndex].grid = this.xbang[temp].bangid; break; } else { bangIndex = temp; } } else { break; } } else { break; } } bangIndex = i; while (1) //下面 { if (this.xbang[bangIndex].pbg < this.xbang[bangIndex].pbk && this.xbang[bangIndex].pbg < 200 && this.xbang[bangIndex].ishb == false) { temp = this.xbang.findIndex(n => n.y + n.pbg < this.xbang[bangIndex].y + this.xbang[bangIndex].pbg && n.x - 0.01 <= this.xbang[bangIndex].x && this.XJcd(n.bangid, this.xbang[bangIndex].bangid)[0] > this.xbang[bangIndex].pbg); if (temp != -1) { if (this.xbang[temp].pbg > maxkd) { maxkd = this.xbang[temp].pbg; maxid = this.xbang[temp].bangid; } if (this.xbang[temp].pbg > 200) { this.xbang[temp].isgr = true; this.xbang[temp].gr.push(this.xbang[bangIndex].bangid); this.xbang[bangIndex].grid = this.xbang[temp].bangid; break; } else { bangIndex = temp; } } else { break; } } else { break; } } } }; }; //查找有异形交集关连的板,并写入 F_GL_JJB = () => { let temp: number; if (this.xbang.length > 1) { for (let i = 0; i < this.xbang.length; i++) { temp = this.xbang.findIndex(n => this.XJcd(n.bangid, this.xbang[i].bangid)[0] > 50 && this.XJcd(n.bangid, this.xbang[i].bangid)[1] > 50 && n.bangid != this.xbang[i].bangid); if (temp != -1) { if (this.xbang[i].pbg * this.xbang[i].pbk > this.xbang[temp].pbg * this.xbang[temp].pbk) { this.xbang[i].isgr = true; this.xbang[i].gr.push(this.xbang[temp].bangid); this.xbang[temp].grid = this.xbang[i].bangid; } else if (equaln(this.xbang[i].pbg * this.xbang[i].pbk, this.xbang[temp].pbg * this.xbang[temp].pbk, 0.01)) { if (this.xbang[temp].x > this.xbang[i].x) { this.xbang[i].isgr = true; this.xbang[i].gr.push(this.xbang[temp].bangid); this.xbang[temp].grid = this.xbang[i].bangid; } else { this.xbang[temp].isgr = true; this.xbang[temp].gr.push(this.xbang[i].bangid); this.xbang[i].grid = this.xbang[temp].bangid; } } else { this.xbang[temp].isgr = true; this.xbang[temp].gr.push(this.xbang[i].bangid); this.xbang[i].grid = this.xbang[temp].bangid; } } } }; for (let k = 0; k < this.xbang.length; k++) { let newgr = [... new Set(this.xbang[k].gr)]; this.xbang[k].gr = newgr; } }; //判断有关联的板跟大板之间是否有交集,如果有取消这块板的关联 Is_big_gr = () => { for (let k = 0; k < this.xbang.length; k++) { let newgr = [... new Set(this.xbang[k].gr)]; this.xbang[k].gr = newgr; } let tempx: number; let tempy: number; let bangIndex1 = this.xbang[this.getID(this.HB[0][0])]; let bangIndex2: number; for (let i = 0; i < this.xbang.length; i++) { if (this.xbang[i].isgr == true) { tempx = 0; tempy = 0; for (let j = 0; j < this.xbang[i].gr.length; j++) { bangIndex2 = this.getID(this.xbang[i].gr[j]); if (this.xbang[i].bangid == 10)////////////////////用于调试 { console.log(this.xbang[i].bangid); } if (this.xbang[bangIndex2].pbg > this.xbang[bangIndex2].pbk) { tempy = this.Jcxj(bangIndex1.y, bangIndex1.pbg, this.xbang[bangIndex2].y, this.xbang[bangIndex2].pbg); } else { tempx = this.Jcxj(bangIndex1.x, bangIndex1.pbk, this.xbang[bangIndex2].x, this.xbang[bangIndex2].pbk); } } if (tempx > 50 || tempy > 50) { this.xbang[i].isgr = false; } } } }; //检测两块板之间的右上角是否有板 false 没有 true 有 LR_is = (bangid1: number, bangid2: number): boolean => { let tb: YH_bang[] = []; tb.push(this.xbang[this.getID(bangid1)]); tb.push(this.xbang[this.getID(bangid2)]); if (tb[0].pbg + tb[0].y > tb[1].pbg + tb[1].y)//右上空间 左边高 { return this.JCQY_is_bang(tb[1].x, tb[1].y + tb[1].pbg + this.dt, tb[1].pbk, tb[0].pbg - tb[1].pbg - this.dt); } else { return false; } }; //检测两块板之间的右上角是否有板 false 没有 true 有 TD_is = (bangid1: number, bangid2: number): boolean => { let tb: YH_bang[] = []; tb.push(this.xbang[this.getID(bangid1)]); tb.push(this.xbang[this.getID(bangid2)]); if (tb[0].pbk + tb[0].x > tb[1].pbk + tb[1].x)//右下空间 左边高 { return this.JCQY_is_bang(tb[1].x, tb[1].y + tb[1].pbg + this.dt, tb[1].pbk, tb[0].pbg - tb[1].pbg - this.dt); } else { return false; } }; //查找左边且Y位置一样的板,, 返加YH_bang[].bangid F_Left_Big = (bangid: number, gbcd: number): number => { let tempjh: YH_bang[] = []; for (let i = 0; i < this.xbang.length; i++) { if (this.xbang[i].x + this.xbang[i].pbk < this.xbang[this.getID(bangid)].x && this.XJcd(this.xbang[i].bangid, this.xbang[this.getID(bangid)].bangid)[1] > gbcd) { tempjh.push(this.xbang[i]); } } if (tempjh.length > 0) { tempjh.sort((a, b) => a.x - b.x); return tempjh[0].bangid; } else { return -1; } }; //找到左右靠边最长的高度 返回 [0]长度 [1] y位置 [2] 0左边 1 右边 L_R_kbcd = (bangid: number): [number, number, number] => { let l_b: YH_bang[] = []; let cd_l = 0; let cd_r: number = 0; let wzl: number; let wzr: number; let tb = [...this.xbang]; let tempx: number = this.xbang[this.getID(bangid)].x; let tempy: number = this.xbang[this.getID(bangid)].y; let tempk: number = this.xbang[this.getID(bangid)].pbk; let tempid: number; let isend: boolean = true; for (let i = 0; i < 2; i++) { l_b = []; tb = [...this.xbang]; isend = true; while (isend == true) { if (i == 0) { tempid = tb.findIndex((n) => equaln(n.x + n.pbk + this.dt, tempx, 0.001) && (n.y <= tempy)); } else { tempid = tb.findIndex((n) => equaln(n.x, tempx + tempk + this.dt, 0.001) && (n.y <= tempy)); } if (tempid != -1) { l_b.push(tb[tempid]); tb.splice(tempid, 1); } else { isend = false; } } if (l_b.length > 0) { l_b.sort((a, b) => b.pbg - a.pbg); if (i == 0) { cd_l = l_b[0].pbg; wzl = l_b[0].y; } else { cd_r = l_b[0].pbg; wzr = l_b[0].y; } } } if (cd_l > cd_r || cd_l == cd_r && cd_l > 0) { return [cd_l, wzl, 0]; } else if (cd_l < cd_r) { return [cd_r, wzr, 1]; } else { return [0, 0, 0]; } }; //查找右边且Y位置一样的板,, 返加YH_bang[].bangid F_Right = (bangid: number): number => { let a = this.xbang.find((n) => equaln(n.x, this.xbang[this.getID(bangid)].x + this.xbang[this.getID(bangid)].pbk + this.dt, 0.001) && equaln(n.y, this.xbang[this.getID(bangid)].y, 0.001) && n.ishb == false); if (a == undefined) { return; } return a.bangid; }; //查找右边且Y位置一样的板,, 返加YH_bang[].bangid F_Right_Big = (bangid: number, gbcd: number): number => { let tempjh: YH_bang[] = []; for (let i = 0; i < this.xbang.length; i++) { if (this.xbang[i].x > this.xbang[this.getID(bangid)].x + this.xbang[this.getID(bangid)].pbk && this.XJcd(this.xbang[i].bangid, this.xbang[this.getID(bangid)].bangid)[1] > gbcd) { tempjh.push(this.xbang[i]); } } if (tempjh.length > 0) { tempjh.sort((a, b) => a.x - b.x); return tempjh[0].bangid; } else { return -1; } }; //查找下边且X位置一样的板,, 返加YH_bang[].bangid F_Down = (bangid: number): number => { let a = this.xbang.find((n) => equaln(n.y + n.pbg + this.dt, this.xbang[this.getID(bangid)].y, 0.001) // && n.x > 10 && equaln(n.x, this.xbang[this.getID(bangid)].x, 0.001) && n.ishb == false); if (a == undefined) { return; } return a.bangid; }; //查找上边且X位置一样的板,, 返加YH_bang[].bangid F_TOP = (bangid: number): number => { let a = this.xbang.find((n) => equaln(n.y, this.xbang[this.getID(bangid)].y + this.xbang[this.getID(bangid)].pbg + this.dt, 0.001) //&& n.x > 10 && equaln(n.x, this.xbang[this.getID(bangid)].x, 0.001) && n.ishb == false); if (a == undefined) { return; } return a.bangid; }; //查找上边且X位置一样的板,, 返加YH_bang[].bangid hbcd为大于共边的长度 F_Top_Big = (bangid: number, gbcd: number): number => { let tempjh: YH_bang[] = []; for (let i = 0; i < this.xbang.length; i++) { if (this.xbang[i].y > this.xbang[this.getID(bangid)].y + this.xbang[this.getID(bangid)].pbg && this.xbang[i].x + this.xbang[i].pbk <= this.xbang[this.getID(bangid)].x + this.xbang[this.getID(bangid)].pbk + 0.1 && this.XJcd(this.xbang[i].bangid, this.xbang[this.getID(bangid)].bangid)[0] > gbcd) { tempjh.push(this.xbang[i]); } } if (tempjh.length > 0) { tempjh.sort((a, b) => a.x - b.x); return tempjh[0].bangid; } else { return -1; } }; //查找下边且X位置一样的板,, 返加YH_bang[].bangid F_Down_Big = (bangid: number, gbcd: number): number => { let tempjh: YH_bang[] = []; for (let i = 0; i < this.xbang.length; i++) { for (let i = 0; i < this.xbang.length; i++) { if (this.xbang[i].y + this.xbang[i].pbg < this.xbang[this.getID(bangid)].y && this.xbang[i].x >= this.xbang[this.getID(bangid)].x && this.xbang[i].pbg > 300 && this.XJcd(this.xbang[i].bangid, this.xbang[this.getID(bangid)].bangid)[0] > gbcd) { tempjh.push(this.xbang[i]); } } } if (tempjh.length > 0) { tempjh.sort((a, b) => a.x - b.x); return tempjh[0].bangid; } else { return -1; } }; //合并同高相邻的板 isbig: true 为第一回合并的大板 wz为方位 L 左 R右 T上 D下 返回是否有合并过 false 为没有合并过 true 有合并过 HB_LR = (bangid: number, isbig: boolean): boolean => { let isend: boolean = true; let tempbangid: number; let ishb: boolean = false; while (isend == true) { tempbangid = this.F_Left(bangid); if (tempbangid != undefined) { let temp = this.JC_is_bang(bangid, tempbangid); //[f/t,1:x,2:y,3:k,4:g] if (temp[0] == false) { this.addbang(bangid, tempbangid, temp[1], temp[2], temp[3], temp[4], isbig); ishb = true; } else { isend = false; } } else { isend = false; } } isend = true; while (isend == true) { tempbangid = this.F_Right(bangid); if (tempbangid != undefined) { let temp = this.JC_is_bang(bangid, tempbangid); //[f/t,1:x,2:y,3:k,4:g] if (temp[0] == false) { this.addbang(bangid, tempbangid, temp[1], temp[2], temp[3], temp[4], isbig); ishb = true; } else { isend = false; } } else { isend = false; } } return ishb; }; //合并同宽相邻的板 isbig: true 为第一回合并的大板 wz为方位 L 左 R右 T上 D下 返回是否有合并过 false 为没有合并过 true 有合并过 HB_TD = (bangid: number, isbig: boolean): boolean => { let isend: boolean = true; let tempbangid: number; let ishb: boolean = false; while (isend == true) { tempbangid = this.F_Down(bangid); if (tempbangid != undefined) { let temp = this.JC_is_bang(bangid, tempbangid); //[f/t,1:x,2:y,3:k,4:g] if (temp[0] == false) { this.addbang(bangid, tempbangid, temp[1], temp[2], temp[3], temp[4], isbig); ishb = true; } else { isend = false; } } else { isend = false; } } isend = true; while (isend == true) { tempbangid = this.F_TOP(bangid); if (tempbangid != undefined) { let temp = this.JC_is_bang(bangid, tempbangid); //[f/t,1:x,2:y,3:k,4:g] if (temp[0] == false) { this.addbang(bangid, tempbangid, temp[1], temp[2], temp[3], temp[4], isbig); ishb = true; } else { isend = false; } } else { isend = false; } } return ishb; }; addbang = (id1: number, id2: number, x: number, y: number, k: number, g: number, isbig: boolean) => //把合并的板写入,并改板的大小 { let tempid1 = this.getID(id1); let tempid2 = this.getID(id2); if (this.xbang[tempid1].ishb == false) { this.HB_bang.push(id1); } this.HB_bang.push(id2); this.xbang[tempid1].x = x; this.xbang[tempid1].y = y; this.xbang[tempid1].pbk = k; this.xbang[tempid1].pbg = g; this.xbang[tempid1].ishb = true; this.xbang[tempid2].ishb = true; if (isbig == true) { this.xbang[tempid1].isbig = true; this.xbang[tempid2].isbig = true; } }; //计算相邻两块板中有空位的地方是否有其它小板 返回 false 为没有其它板,true 有其它板 x,y,k,g JC_is_bang = (bangid1: number, bangid2: number): [boolean, number, number, number, number] => { let tb: YH_bang[] = []; tb.push(this.xbang[this.getID(bangid1)]); tb.push(this.xbang[this.getID(bangid2)]); if (equaln(tb[0].y, tb[1].y, 0.01)) //左右相邻 { tb.sort((a, b) => a.x - b.x); if (tb[0].pbg < tb[1].pbg)//左上空间 右边高 { return [this.JCQY_is_bang(tb[0].x, tb[0].y + tb[0].pbg + this.dt, tb[0].pbk, tb[1].pbg - tb[0].pbg - this.dt), tb[0].x, tb[0].y, tb[0].pbk + tb[1].pbk + this.dt, tb[1].pbg]; } else if (tb[0].pbg > tb[1].pbg)//右上空间 左边高 { return [this.JCQY_is_bang(tb[1].x, tb[1].y + tb[1].pbg + this.dt, tb[1].pbk, tb[0].pbg - tb[1].pbg - this.dt), tb[0].x, tb[0].y, tb[0].pbk + tb[1].pbk + this.dt, tb[0].pbg]; } else //一样高 { return [false, tb[0].x, tb[0].y, tb[0].pbk + tb[1].pbk + this.dt, tb[0].pbg]; } } else //上下空间 { tb.sort((b, a) => a.y - b.y); if (tb[0].pbk < tb[1].pbk)//右上空间 上边短 { return [this.JCQY_is_bang(tb[0].x + tb[0].pbk + this.dt, tb[0].y, tb[1].pbk - tb[0].pbk - this.dt, tb[0].pbg), tb[1].x, tb[1].y, tb[1].pbk, tb[0].pbg + tb[1].pbg + this.dt]; } else if (tb[0].pbk > tb[1].pbk)//右下空间 下边短 { return [this.JCQY_is_bang(tb[1].x + tb[1].pbk + this.dt, tb[1].y, tb[0].pbk - tb[1].pbk - this.dt, tb[1].pbg), tb[1].x, tb[1].y, tb[0].pbk, tb[0].pbg + tb[1].pbg + this.dt]; } else //一样高 { return [false, tb[1].x, tb[1].y, tb[0].pbk, tb[0].pbg + tb[1].pbg + this.dt]; } } }; //检测两块板之间相交的长度且两块板之间没有其它板 ,返回长度,第一个为X相交长度 第二个为Y相交长度 XJcd = (bangid1: number, bangid2: number): [number, number] => { let tempbang: YH_bang[] = []; tempbang.push(this.xbang[this.getID(bangid1)]); tempbang.push(this.xbang[this.getID(bangid2)]); let tempx = this.Jcxj(tempbang[0].x, tempbang[0].pbk, tempbang[1].x, tempbang[1].pbk); let tempy = this.Jcxj(tempbang[0].y, tempbang[0].pbg, tempbang[1].y, tempbang[1].pbg); if (tempx > 0 && tempy > 0) { return [tempx, tempy]; } else if (tempx > 0) { tempbang.sort((a, b) => a.x - b.x); if (tempbang[0].y > tempbang[1].y) { if (this.JCQY_is_bang(tempbang[1].x, tempbang[1].y + tempbang[1].pbg, tempx, tempbang[0].y - tempbang[1].y - tempbang[1].pbg) == false) { return [tempx, 0]; } else { return [0, 0]; } } else { if (this.JCQY_is_bang(tempbang[1].x, tempbang[0].y + tempbang[0].pbg, tempx, tempbang[1].y - tempbang[0].y - tempbang[0].pbg) == false) { return [tempx, 0]; } else { return [0, 0]; } } } else if (tempy > 0) { tempbang.sort((a, b) => a.x - b.x); if (tempbang[0].y > tempbang[1].y) { if (this.JCQY_is_bang(tempbang[0].x + tempbang[0].pbk, tempbang[0].y, tempbang[1].x - tempbang[0].x - tempbang[0].pbk, tempy) == false) { return [0, tempy]; } else { return [0, 0]; } } else { if (this.JCQY_is_bang(tempbang[0].x + tempbang[0].pbk, tempbang[1].y, tempbang[1].x - tempbang[0].x - tempbang[0].pbk, tempy) == false) { return [0, tempy]; } else { return [0, 0]; } } } else { return [0, 0]; } }; //检测指定区域内否有其它小板 返回 false 为没有其它板,true 有其它板 JCQY_is_bang = (x: number, y: number, k: number, g: number): boolean => { let result = this.xbang.findIndex((n) => (k + n.pbk - Math.abs(x - n.x) - Math.abs(x - n.x + k - n.pbk)) / 2 > 0.01 && (g + n.pbg - Math.abs(y - n.y) - Math.abs(y - n.y + g - n.pbg)) / 2 > 0.01); if (result == -1) { return false; } else { return true; } }; //计算两边相交长度/ Jcxj = (wz1: number, l1: number, wz2: number, l2: number): number => { return (l1 + l2 - Math.abs(wz1 - wz2) - Math.abs(wz1 - wz2 + l1 - l2)) / 2; }; Find_BS = (): number[] => { let temp = this.Find_BS_gr(); if (temp[0] > 2) { return this.Find_BS_wgr()[1]; } else { if (temp[1][0] == 0) { return this.Find_BS_wgr()[1]; } else { return temp[1]; } } }; //找到共边最少的板的集合 订算有关系的板 Find_BS_gr = (): [number, number[]] => { let bs: number = 6; let id: number[] = []; let tempsl: number[]; if (this.xbang.length == 1) { return [0, [0]]; } else { for (let i = 0; i < this.xbang.length; i++) { if (this.xbang[i].isgr == false && this.xbang[i].ishb == false && this.xbang[i].isqg == false) { tempsl = this.JSgbsl(this.xbang[i].bangid); if (bs == tempsl[0]) { id.push(this.xbang[i].bangid); } else if (bs > tempsl[0]) { bs = tempsl[0]; id = []; id.push(this.xbang[i].bangid); } } } if (id.length > 0) { return [bs, id]; } else { //console.log("没找到最少边"); return [0, [0]]; } } }; //找到共边最少的板的集合 订算没有算关系的板 Find_BS_wgr = (): [number, number[]] => { let bs: number = 6; let id: number[] = []; let tempsl: number[]; if (this.xbang.length == 1) { return [0, [0]]; } else { for (let i = 0; i < this.xbang.length; i++) { if (this.xbang[i].ishb == false && this.xbang[i].isqg == false) { tempsl = this.JSgbsl(this.xbang[i].bangid); if (bs == tempsl[0]) { id.push(this.xbang[i].bangid); } else if (bs > tempsl[0]) { bs = tempsl[0]; id = []; id.push(this.xbang[i].bangid); } } } if (id.length > 0) { return [bs, id]; } else { return [0, [0]]; } } }; //计算这块板的与其它板的相交的边数,及每条边数跟权重 0数量 1左 2右 3上 4下 5权重 JSgbsl = (bangid: number): [number, number, number, number, number, number] => { let left = 0, right = 0, top = 0, down = 0, qz = 0; let bangIndex = this.getID(bangid); for (let j = 0; j < this.xbang.length; j++) { if (bangIndex != j && this.xbang[j].isqg == false) { let jjy = this.Jcxj(this.xbang[bangIndex].y, this.xbang[bangIndex].pbg, this.xbang[j].y, this.xbang[j].pbg); let jjx = this.Jcxj(this.xbang[bangIndex].x, this.xbang[bangIndex].pbk, this.xbang[j].x, this.xbang[j].pbk); if (this.xbang[bangIndex].pbg > this.xbang[bangIndex].pbk) { if (jjy < this.xbang[bangIndex].pbk && jjy < 50) { jjy = 0; } } if (this.xbang[bangIndex].pbk > this.xbang[bangIndex].pbg) { if (jjx < this.xbang[bangIndex].pbg && jjx < 50) { jjx = 0; } } if (jjy > 0 && this.xbang[bangIndex].x > this.xbang[j].x + this.xbang[j].pbk) { left = 1; } if (jjy > 0 && this.xbang[j].x > this.xbang[bangIndex].x + this.xbang[bangIndex].pbk) { right = 1; } if (jjx > 0 && this.xbang[bangIndex].y > this.xbang[j].y + this.xbang[j].pbg) { down = 1; } if (jjx > 0 && this.xbang[j].y > this.xbang[bangIndex].y + this.xbang[bangIndex].pbg) { top = 1; } if ((left == 1 && right == 1) || (down == 1 && top == 1)) { qz = 1; } } } return [left + right + top + down + qz, left, right, top, down, qz]; }; Jcsb = (bangid1: number, bangid2: number): boolean => // 把bang1 要去掉, bang2 是否少边 返加True 有少边 False 没有少边 { let xj = this.XJcd(bangid1, bangid2); let jjx = xj[0]; let jjy = xj[1]; if (jjx > 0 && this.xbang[this.getID(bangid1)].pbg < this.xbang[this.getID(bangid2)].pbg) { return true; } else if (jjx > 0 && jjx > 0 && this.xbang[this.getID(bangid1)].pbk * this.xbang[this.getID(bangid1)].pbg < this.xbang[this.getID(bangid2)].pbk * this.xbang[this.getID(bangid2)].pbg) { return false; } else if (jjy > 0 && this.xbang[this.getID(bangid1)].pbg < this.xbang[this.getID(bangid2)].pbg) { return false; } else if (jjy > 0 && this.xbang[this.getID(bangid1)].pbg > this.xbang[this.getID(bangid2)].pbg) { return true; } // else if (jjy > 0 && this.xbang[this.getID(bangid2)].pbk > this.xbang[this.getID(bangid2)].pbg // && this.xbang[this.getID(bangid2)].pbk * this.xbang[this.getID(bangid2)].pbg < this.xbang[this.getID(bangid1)].pbk * this.xbang[this.getID(bangid1)].pbg) // { // return true; // } else { return false; } // if (bangid1 == 2 && bangid2 == 10) // { // console.log(bangid1); // } // let bs1 = this.JSgbsl(bangid1)[0]; // let bs2 = this.JSgbsl(bangid2)[0]; // let sb2 = this.is_sb(bangid1, bangid2)[0]; // let sb1 = this.is_sb(bangid2, bangid1)[0]; // if (sb2 < bs1 && sb1 < bs2) // { // return true; // } // else // { // return false; // } }; //检测所有会让其它板少条且最小的的板 JS_sb_minmz = (): number => { let Bangidzh = this.Find_BS(); if (Bangidzh[0] != 0) { let tempbang: YH_bang[] = []; for (let m = 0; m < Bangidzh.length; m++) { tempbang.push(this.xbang[this.getID(Bangidzh[m])]); } if (tempbang.length > 0) { tempbang.sort((a, b) => a.pbg * a.pbk - b.pbg * b.pbk); return tempbang[0].bangid; } else if (tempbang.length == 1) { return tempbang[0].bangid; } else { return -1; } } else { return -1; } }; //合并所有的板 HB_b = () => { let jshb_lr: boolean = true; let jshb_td: boolean = true; let jshb: boolean; for (let i = 0; i < this.xbang.length; i++) { if (this.xbang[i].ishb == false) { jshb = true; } else { jshb = false; } while (jshb == true) { if (this.xbang[i].pbg > this.xbang[i].pbk && this.xbang[i].pbk > 100) //左右 { jshb_lr = this.HB_LR(this.xbang[i].bangid, false); } else { jshb_lr = false; } if ((this.xbang[i].pbg < this.xbang[i].pbk && this.xbang[i].pbg > 100)) //上下合并 { jshb_td = this.HB_TD(this.xbang[i].bangid, false); } else { jshb_td = false; } if (jshb_lr == true || jshb_td == true) { jshb = true; } else if (jshb_lr == false || jshb_td == false) { if ((this.xbang[i].pbg > 100 && this.xbang[i].pbk > 100)) //上下合并 { jshb_lr = this.HB_LR(this.xbang[i].bangid, false); jshb_td = this.HB_TD(this.xbang[i].bangid, false); if (jshb_lr == true || jshb_td == true) { jshb = true; } else { jshb = false; } } else { jshb = false; } } else { jshb = true; } } if (this.HB_bang.length > 0) { this.HB.push(this.HB_bang); this.HB_bang = []; } } }; //合并指定的板 第一步 HB_Max_bang = (Bangid: number) => { if (Bangid > 0) { let jshb_lr: boolean = true; let jshb_td: boolean = true; let jshb: boolean; let bangid = this.getID(Bangid); if (this.xbang[bangid].ishb == false) { jshb = true; } else { jshb = false; } while (jshb == true) { if (this.xbang[bangid].pbg > this.xbang[bangid].pbk && this.xbang[bangid].pbk > 100) //左右 { jshb_lr = this.HB_LR(this.xbang[bangid].bangid, false); } else { jshb_lr = false; } if ((this.xbang[bangid].pbg < this.xbang[bangid].pbk && this.xbang[bangid].pbg > 100)) //上下合并 { jshb_td = this.HB_TD(this.xbang[bangid].bangid, false); } else { jshb_td = false; } if (jshb_lr == true || jshb_td == true) { jshb = true; } else if (jshb_lr == false || jshb_td == false) { if ((this.xbang[bangid].pbg > 100 && this.xbang[bangid].pbk > 100)) //上下合并 { jshb_lr = this.HB_LR(this.xbang[bangid].bangid, false); jshb_td = this.HB_TD(this.xbang[bangid].bangid, false); if (jshb_lr == true || jshb_td == true) { jshb = true; } else { jshb = false; } } else { jshb = false; } } else { jshb = true; } } if (this.HB_bang.length > 0) { this.HB.push(this.HB_bang); this.HB_bang = []; } else { this.HB.push([Bangid]); this.xbang[bangid].ishb = true; } } }; //合并上面的大板 cd为共边长度 HB_top = (bangid: number, cd: number) => { let hbbang: number[] = []; let fid: number = bangid; while (fid > -1) { fid = this.F_Top_Big(fid, cd); if (fid > -1) { this.xbang[this.getID(fid)].ishb = true; hbbang.push(fid); //this.printstr(fid, 1, "大合", -30, 80, 50); } } if (hbbang.length > 0) { this.HB.push(hbbang); } }; //合并下面的大板 cd为共边长度 HB_down = (bangid: number, cd: number) => { let hbbang: number[] = []; let fid: number = bangid; while (fid > -1) { fid = this.F_Down_Big(fid, cd); if (fid > -1) { this.xbang[this.getID(fid)].ishb = true; hbbang.push(fid); // this.printstr(fid, 1, "大合", 10, 80, 50); } } if (hbbang.length > 0) { this.HB.push(hbbang); } }; //寻找最后一块要切割的板 F_last_mz = (jlID: number): number => { let bangid: number; let temp: number[]; let index: number = 1; let lastId: number; if (jlID == 0) { lastId = this.F_minMZ(); } else { lastId = jlID; } while (true) { if (lastId == -1) { break; } bangid = this.JS_sb_Bxl(lastId); //检测所有会让其它板少条且有两块或者多块边相邻的板 if (bangid > -1) { this.add_last(bangid, index); index++; lastId = bangid; } else { bangid = this.JS_sb_minmz(); //检测所有会让其它板少条且最小的的板 if (bangid > -1) { this.add_last(bangid, index); index++; lastId = bangid; } else { if (lastId == -1) { break; } bangid = this.F_minJL(lastId); if (bangid > -1) { this.add_last(bangid, index); index++; lastId = bangid; } else { bangid = this.F_minMZ(); //找到面积最小的板 this.add_last(bangid, index); index++; lastId = bangid; } } } // bangid = this.F_minJL(bangid); //if (bangid > -1) { this.add_last(bangid, index); index++; } temp = this.Find_BS(); if (temp[0] == 0) { break; } } return index; }; //寻找最后一块要切割的板 F_last_jl = (jlID: number): number => { let bangid: number; let temp: number[]; let index: number = 1; let lastId: number; if (jlID == 0) { lastId = this.F_minMZ(); } else { lastId = jlID; } let tempend: boolean = false; while (true) { if (lastId == -1) { break; } bangid = this.JS_sb_Bxl(lastId); //检测所有会让其它板少条且有两块或者多块边相邻的板 if (bangid > -1) { this.add_last(bangid, index); index++; lastId = bangid; } else { if (lastId == -1) { break; } bangid = this.F_minJL(lastId); if (bangid > -1) { this.add_last(bangid, index); index++; lastId = bangid; } else { //bangid = this.F_minMZ(); //找到面积最小的板 // if (lastId == -1) { break; } // bangid = this.F_minJL(lastId); bangid = this.JS_sb_minmz(); //检测所有会让其它板少条且最小的的板 if (bangid > -1) { this.add_last(bangid, index); index++; lastId = bangid; } else { bangid = this.F_minMZ(); //找到面积最小的板 this.add_last(bangid, index); index++; lastId = bangid; } } } // bangid = this.F_minJL(bangid); //if (bangid > -1) { this.add_last(bangid, index); index++; } temp = this.Find_BS(); if (temp[0] == 0) { break; } } return index; }; //打印并添加最后一块 add_last = (bangid: number, index: number) => { let tempx: number; //if (index > 9) { tempx = 27; } else { tempx = 10; } 这两行用于测试打印 //this.printstr(bangid, 1, index.toString(), this.xbang[this.getID(bangid)].pbk / 2 - tempx, this.xbang[this.getID(bangid)].pbg / 2 - 20, 50); this.SCid.push(bangid); this.xbang[this.getID(bangid)].isqg = true; let tempid = this.xbang[this.getID(bangid)].grid; if (this.xbang[this.getID(bangid)].grid > -1) { let tempin = this.xbang[this.getID(tempid)].gr.findIndex((n) => n == bangid); if (tempin > -1) { this.xbang[this.getID(tempid)].gr.splice(tempin, 1); if (this.xbang[this.getID(tempid)].gr.length == 0) { this.xbang[this.getID(tempid)].isgr = false; } } } }; //找到面积最小的板 F_minMZ = (): number => { let jhb = this.Find_BS(); if (jhb[0] != 0) { let tempBang: YH_bang[] = []; if (jhb.length == 1) { return jhb[0]; } else { for (let i = 0; i < jhb.length; i++) { tempBang.push(this.xbang[this.getID(jhb[i])]); } tempBang = tempBang.sort((a, b) => { if (a.pbg * a.pbk == b.pbg * b.pbk) { return Math.hypot(this.B_k - a.x - a.pbk / 2, this.B_g - a.y - a.pbg / 2) - Math.hypot(this.B_k - b.x - b.pbk / 2, this.B_g - b.y - b.pbg / 2); } else { return a.pbg * a.pbk - b.pbg * b.pbk ? -1 : 1; } }); return tempBang[0].bangid; } } else { return -1; } }; //按位置最近排序 F_minJL = (bangid: number): number => { let jhb = this.Find_BS(); if (jhb.length[0] != 0) { let tempBang: YH_bang[] = []; if (jhb.length > 0) { for (let i = 0; i < jhb.length; i++) { tempBang.push(this.xbang[this.getID(jhb[i])]); } let wzx = this.xbang[this.getID(bangid)].x + this.xbang[this.getID(bangid)].pbk / 2; let wzy = this.xbang[this.getID(bangid)].y + this.xbang[this.getID(bangid)].pbg / 2; tempBang.sort((a, b) => a.pbk * a.pbg - b.pbk * b.pbg); if (tempBang[tempBang.length - 1].pbg * tempBang[tempBang.length - 1].pbk / 1000000 - tempBang[0].pbg * tempBang[0].pbk / 1000000 > 0.2) { return tempBang[0].bangid; } else { tempBang.sort((a, b) => Math.hypot(wzx - a.x - a.pbk / 2, wzy - a.y - a.pbg / 2) - Math.hypot(wzx - b.x - b.pbk / 2, wzy - b.y - b.pbg / 2)); return tempBang[0].bangid; } } else if (jhb.length == 1) { return jhb[0]; } else { return -1; } } else { return -1; } }; //检测所有会让其它板少条且有两块或者多块边相邻的板 JS_sb_Bxl = (bangid: number): number => { let Bangidzh = this.Find_BS(); if (Bangidzh[0] != 0) { let tempbang: YH_bang[] = []; let tempxj: YH_bang[] = []; let temp: YH_bang; for (let m = 0; m < Bangidzh.length; m++) { for (let n = 0; n < Bangidzh.length; n++) { if (m != n) { if (this.Jcsb(Bangidzh[m], Bangidzh[n]) == true) { tempbang.push(this.xbang[this.getID(Bangidzh[m])]); } } } } if (tempbang.length == 1) { return tempbang[0].bangid; } else if (tempbang.length == 0) { return -1; } else //(tempbang.length > 1); { let wzx = this.xbang[this.getID(bangid)].x + this.xbang[this.getID(bangid)].pbk / 2; let wzy = this.xbang[this.getID(bangid)].y + this.xbang[this.getID(bangid)].pbg / 2; tempbang.sort((a, b) => Math.hypot(wzx - a.x - a.pbk / 2, wzy - a.y - a.pbg / 2) - Math.hypot(wzx - b.x - b.pbk / 2, wzy - b.y - b.pbg / 2)); return tempbang[0].bangid; } } else { return -1; } }; //用于计算下刀顺序 XDscjs = () => { let bangid = this.MaxMZ(0.05); this.HB_Max_bang(bangid); this.HB_top(bangid, 200); this.HB_down(bangid, 200); this.F_GL_LR(); this.F_GL_TD(); this.Is_big_gr(); this.F_GL_JJB(); let index: number; if (this.jl_mz == 1) { index = this.F_last_jl(0); } else { index = this.F_last_mz(0); } this.printHBCS(index); }; printHBCS = (index: number) => { for (let m = this.HB.length - 1; m >= 0; m--) { for (let n = this.HB[m].length - 1; n >= 0; n--) { //this.printstr(this.HB[m][n], 1, index.toString(), this.Bakbang[this.getID_Bkb(this.HB[m][n])].pbk / 2, this.Bakbang[this.getID_Bkb(this.HB[m][n])].pbg / 2, 50); this.SCid.push(this.HB[m][n]); index++; }; } }; }; function equaln(v1: number, v2: number, fuzz = 1e-5) { return Math.abs(v1 - v2) <= fuzz; } export interface YH_bang { bangid: number; line: number ; x: number; y: number; pbg: number; pbk: number; ishb?: boolean;//是否参与合并的板 hb?: number[]; //合在并的板 isgr?: boolean; //是否关连 gr?: number[];//关联的板的集合 grid: number; //跟别的板关联的ID isbig?: boolean;//是否为合并的大板 isqg?: boolean;//是否被切掉的板 }