Files
cut-abstractions/tests/dev1/dataHandle/confClass.ts

4815 lines
153 KiB
TypeScript
Raw Normal View History

2025-07-22 18:22:31 +08:00
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> | 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<Knife>
/**
*
* 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 = <TextureType>data.texture
} else if (key == 'placeHole') {
this.placeHole = <HoleArrange>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 = <HoleType>data.holeType
this.face = <FaceType>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 = <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 = <FaceType>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 ? <FaceType>data.Face : <FaceType>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
*
*
*
*
* 1face
* 2
* 1X轴 || 使 isPointInBlock
* 2Y轴 || 使 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 = <SideFaceType>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<PlaceStyle, PlacementConfig>;
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;//是否被切掉的板
}