Files
cut-abstractions/tests/dev1/dataHandle/common/LayoutEngine/BlockHelper.ts

1299 lines
45 KiB
TypeScript
Raw Normal View History

2025-07-22 18:22:31 +08:00
import { ArrayExt } from '../../common/base/ArrayExt.js'
import type { Arc2d, Curve2d } from '../../common/base/CAD.js'
import { CADExt, Line2d } from '../../common/base/CAD.js'
import {
BlockRegion,
FaceType, HoleType, HoleArrange, PlaceStyle, TextureType, BlockBorderPoint, BlockHole,
BlockModel, BlockModelPoint, PlacePositionClass,
PlaceBlock,
PlaceMaterial,
PlaceBoard
} from '../../confClass.js'
import { equal } from '../../common/base/MathComm.js'
import { PolylineHelper } from '../../common/LayoutEngine/PolylineHelper.js'
import { Point } from '../../common/Vector2.js'
import { BlockPlus } from './BlockPlus.js'
import { BlockSizePlus } from './BlockSizePlus.js'
import { NcAdvanceHelper } from '@/imes/biz/NcAdvance.js' // './NcAdvance.js'
import { getPlaceBoard, resetPlaceBoard, resetPlaceMaterial } from './PlaceBase'
import { resetModelKnife } from './BlockDataPlus.js'
/** 小板业务类 */
export class BlockHelper {
// static testBlockNo = ''; //测试板号
/** 初始化小板明细 */
static setBlockDetail(block: PlaceBlock) {
if (block.blockDetail)
return // 已存在
}
// 初始化block ,边框,内部边框,偏移后等----------------------------------------
/** 初始化 block (初始化明细,重设排版) */
private static equal(a, b, off = 0.001): boolean {
return Math.abs(a - b) < off
}
// 排版相关:小板翻转,移动---------------------------------------------------
/** 翻转小板,翻转动作opType: 0翻面 1右转 2后转 3左转 */
static turnBlock(block: PlaceBlock, placeMaterial: 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
// 修改小板的放置方式
console.log('修改小板的放置方式', block.blockNo, block, newStyle)
// BlockHelper.resetPlaceStyle(block, newStyle)
PlacePositionClass.resetPlaceStyle(block, newStyle);
this.resetDoFace_HoleModel(block, false)
this.restOther(block)
// 重置放置,检查冲突
BlockHelper.replaceBlock(placeMaterial, 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
}
/** 板放置后重置placeWidth, placeLength, 封边, 正反面, 面孔, 造型等 */
static resetPlaceStyle(block: PlaceBlock, newStyle: PlaceStyle) {
block.placeStyle = newStyle
// tryFix
let _width = block.cutWidth
let _lenth = block.cutLength
if (block.width > block.length) {
block.cutWidth = Math.max(_width, _lenth)
block.cutLength = Math.min(_width, _lenth)
} else {
block.cutWidth = Math.min(_width, _lenth)
block.cutLength = Math.max(_width, _lenth)
}
switch (newStyle) {
case PlaceStyle.FRONT: // 正面
block.placeWidth = block.cutWidth
block.placeLength = block.cutLength
block.placeSealLeft = block.sealLeft
block.placeSealRight = block.sealRight
block.placeSealTop = block.sealTop
block.placeSealBottom = block.sealBottom
block.holeCountSideLeft = block.holeCountLeft()
block.holeCountSideRight = block.holeCountRight()
block.holeCountSideTop = block.holeCountTop()
block.holeCountSideBottom = block.holeCountBottom()
block.placeDirection = '→'
block.placeDirection_Length = block.length > block.width - 0.001 ? '→' : '↓'
break
case PlaceStyle.FRONT_TURN_RIGHT: // 正面右转
block.placeWidth = block.cutLength
block.placeLength = block.cutWidth
block.placeSealLeft = block.sealBottom
block.placeSealRight = block.sealTop
block.placeSealTop = block.sealLeft
block.placeSealBottom = block.sealRight
block.holeCountSideLeft = block.holeCountBottom()
block.holeCountSideRight = block.holeCountTop()
block.holeCountSideTop = block.holeCountLeft()
block.holeCountSideBottom = block.holeCountRight()
block.placeDirection = '↓'
block.placeDirection_Length = block.length > block.width - 0.001 ? '↓' : '←'
break
case PlaceStyle.FRONT_TURN_BACK: // 正面后转
block.placeWidth = block.cutWidth
block.placeLength = block.cutLength
block.placeSealLeft = block.sealRight
block.placeSealRight = block.sealLeft
block.placeSealTop = block.sealBottom
block.placeSealBottom = block.sealTop
block.holeCountSideLeft = block.holeCountRight()
block.holeCountSideRight = block.holeCountLeft()
block.holeCountSideTop = block.holeCountBottom()
block.holeCountSideBottom = block.holeCountTop()
block.placeDirection = '←'
block.placeDirection_Length = block.length > block.width - 0.001 ? '←' : '↑'
break
case PlaceStyle.FRONT_TURN_LEFT: // 正面左转
block.placeWidth = block.cutLength
block.placeLength = block.cutWidth
block.placeSealLeft = block.sealTop
block.placeSealRight = block.sealBottom
block.placeSealTop = block.sealRight
block.placeSealBottom = block.sealLeft
block.holeCountSideLeft = block.holeCountTop()
block.holeCountSideRight = block.holeCountBottom()
block.holeCountSideTop = block.holeCountRight()
block.holeCountSideBottom = block.holeCountLeft()
block.placeDirection = '↑'
block.placeDirection_Length = block.length > block.width - 0.001 ? '↑' : '→'
break
case PlaceStyle.BACK: // 反面
block.placeWidth = block.cutWidth
block.placeLength = block.cutLength
block.placeSealLeft = block.sealRight
block.placeSealRight = block.sealLeft
block.placeSealTop = block.sealTop
block.placeSealBottom = block.sealBottom
block.holeCountSideLeft = block.holeCountRight()
block.holeCountSideRight = block.holeCountLeft()
block.holeCountSideTop = block.holeCountTop()
block.holeCountSideBottom = block.holeCountBottom()
block.placeDirection = '→'
block.placeDirection_Length = block.length > block.width - 0.001 ? '→' : '↑'
break
case PlaceStyle.BACK_TURN_RIGHT: // 反面右转
block.placeWidth = block.cutLength
block.placeLength = block.cutWidth
block.placeSealLeft = block.sealBottom
block.placeSealRight = block.sealTop
block.placeSealTop = block.sealRight
block.placeSealBottom = block.sealLeft
block.holeCountSideLeft = block.holeCountBottom()
block.holeCountSideRight = block.holeCountTop()
block.holeCountSideTop = block.holeCountRight()
block.holeCountSideBottom = block.holeCountLeft()
block.placeDirection = '↓'
block.placeDirection_Length = block.length > block.width - 0.001 ? '↓' : '→'
break
case PlaceStyle.BACK_TURN_BACK: // 反面后转
block.placeWidth = block.cutWidth
block.placeLength = block.cutLength
block.placeSealLeft = block.sealLeft
block.placeSealRight = block.sealRight
block.placeSealTop = block.sealTop
block.placeSealBottom = block.sealBottom
block.holeCountSideLeft = block.holeCountLeft()
block.holeCountSideRight = block.holeCountRight()
block.holeCountSideTop = block.holeCountTop()
block.holeCountSideBottom = block.holeCountBottom()
block.placeDirection = '←'
block.placeDirection_Length = block.length > block.width - 0.001 ? '←' : '↓'
break
case PlaceStyle.BACK_TURN_LEFT: // 反面左转
block.placeWidth = block.cutLength
block.placeLength = block.cutWidth
block.placeSealLeft = block.sealTop
block.placeSealRight = block.sealBottom
block.placeSealTop = block.sealLeft
block.placeSealBottom = block.sealRight
block.holeCountSideLeft = block.holeCountTop()
block.holeCountSideRight = block.holeCountBottom()
block.holeCountSideTop = block.holeCountLeft()
block.holeCountSideBottom = block.holeCountRight()
block.placeDirection = '↑'
block.placeDirection_Length = block.length > block.width - 0.001 ? '↑' : '←'
break
default:
break
}
this.resetDoFace_HoleModel(block)
this.restOther(block)
}
/** 获得小板放置方向标识 */
static getPlaceDirection(block: PlaceBlock): string {
return block.placeDirection
}
/** 选择最近的板,弹出定位方向盘,选择定位位置 */
static replaceBlockWidthDirect(pm: PlaceMaterial, block: PlaceBlock, newBoardId: number, dragingBlockPoint: BlockBorderPoint, referBlockPoint: BlockBorderPoint, direction: number) {
let gap = pm.diameter + pm.cutKnifeGap
// '↖', '↑', '↗', '←', 'X', '→', '↙', '↓', '↘'
// 参照点 现在位置
let rPointX = referBlockPoint.placeX
let rPointY = referBlockPoint.placeY
if (direction == 0) // '↖'
{
rPointX -= gap
rPointY -= gap
}
if (direction == 1) // '↑'
{
rPointX -= gap
}
if (direction == 2) // '↗'
{
rPointX -= gap
rPointY += gap
}
if (direction == 3) // '←'
{
rPointY -= gap
}
if (direction == 4) // '←'
{
}
if (direction == 5) // '→'
{
rPointY += gap
}
if (direction == 6) // '↙'
{
rPointX += gap
rPointY -= gap
}
if (direction == 7) // '↓'
{
rPointX += gap
}
if (direction == 8) // '↘'
{
rPointX += gap
rPointY += gap
}
// 减去拖拉点自身与基点的距离
rPointX = rPointX - dragingBlockPoint.x
rPointY = rPointY - dragingBlockPoint.y
BlockHelper.replaceBlock(pm, block, newBoardId, new Point(rPointX, rPointY))
}
/** 移动小板 自由移动 */
static replaceBlock(pm: PlaceMaterial, block: PlaceBlock, newBoardId: number, p: Point) {
let oldBoardId = block.boardId
let isChangeBoard = block.boardId != newBoardId
if (oldBoardId > pm.boardList.length) {
oldBoardId = 1
}
if (newBoardId > pm.boardList.length) {
newBoardId = 1
}
let pb_org = getPlaceBoard(pm, oldBoardId)
let pb_new = getPlaceBoard(pm, newBoardId)
pb_org.isCreateRemainSpace = true
pb_new.isCreateRemainSpace = true
let orgPlaceX = block.placeX
let orgPlaceY = block.placeY
let list = pb_new.blockList
let maxPlaceId = ArrayExt.max(list, t => t.placeId, t => true, 0) + 1
let newPlaceId = maxPlaceId++
// 设置block
block.boardId = newBoardId
block.placeId = newPlaceId
block.placeX = p.x
block.placeY = p.y
block.isAutoPlaced = false
if (isChangeBoard) {
ArrayExt.remove(pb_org.blockList, block)
pb_new.blockList.push(block)
}
if (isChangeBoard) {
pb_org.blockList = pb_org.blockList.filter(b => b.blockId != block.blockId)
for (let board of pm.boardList) {
if (board.boardId == oldBoardId) {
board = pb_org
continue
}
}
// pm.boardList[oldBoardId] = pb_org
checkOverlapInBoard(pm, pb_org)
resetPlaceBoard(pm, pb_org)
}
checkOverlapInBoard(pm, pb_new)
resetPlaceBoard(pm, pb_new)
resetPlaceMaterial(pm)
}
/** 开始拖动时,获得板上的停靠点 */
static getDragingPointInBlock(block: PlaceBlock, mousePos: Point): BlockBorderPoint {
let dis = Number.MAX_VALUE
let point: Point
let index = -1
// 基于小板排版基点的 鼠标坐标
let rx = mousePos.x - block.placeX
let ry = mousePos.y - block.placeY
// 算出 最近的拖拉点
let curves = BlockPlus.getBorder_moving(block)
for (let i = 0; i < curves.length; i++) {
let line = curves[i]
let d = Math.pow(line.StartPoint.m_X + block.placeX - mousePos.x, 2) + Math.pow(line.StartPoint.m_Y + block.placeY - mousePos.y, 2);
if (d < dis) {
point = new Point(line.StartPoint.m_X, line.StartPoint.m_Y)
dis = d
index = i
}
}
// 存在板外 的造型或2v刀路
if (BlockPlus.hasModelOutBlock(block)) {
let pl = BlockPlus.borderToPolyline(curves, true)
let x1 = pl.BoundingBox.min.x
let y1 = pl.BoundingBox.min.y
let x2 = pl.BoundingBox.max.x
let y2 = pl.BoundingBox.max.y
if (point.x < 0)
point.x = x1
if (point.x > block.placeWidth)
point.x = x2
if (point.y < 0)
point.y = y1
if (point.y > block.placeLength)
point.y = y2
// //拖拉死角,用偏移后的
// if(point.X < 0 && point.Y < 0) //左下角
// {
// if(Math.abs(point.X -x1 ) < 40 ) point.X = x1;
// if(Math.abs(point.Y -y1 ) < 40 ) point.Y = y1;
// }
// else if(point.X>block.PlaceWidth && point.Y < 0) //右下角
// {
// if(Math.abs(point.X -x2 ) < 40 ) point.X = x2;
// if(Math.abs(point.Y -y1 ) < 40 ) point.Y = y1;
// }
// else if(point.X>block.PlaceWidth && point.Y > block.PlaceLength )
// {
// if(Math.abs(point.X -x2 ) < 40 ) point.X = x2;
// if(Math.abs(point.Y -y2 ) < 40 ) point.Y = y2;
// }
// else if(point.X<0 && point.Y > block.PlaceLength)
// {
// if(Math.abs(point.X -x1 ) < 40 ) point.X = x1;
// if(Math.abs(point.Y -y2 ) < 40 ) point.Y = y2;
// }
}
// 找出 距 小板
dis = Number.MAX_VALUE
let point_base: Point
let curves_cut = BlockPlus.getBorder_sameKnife(block)
for (let i = 0; i < curves_cut.length; i++) {
let line = curves_cut[i]
let d = Math.pow(line.StartPoint.m_X + block.placeX - mousePos.x, 2) + Math.pow(line.StartPoint.m_Y + block.placeY - mousePos.y, 2);
if (d < dis) {
point_base = new Point(line.StartPoint.m_X, line.StartPoint.m_Y)
dis = d
index = i
}
}
let apexId = BlockHelper.getApexAngleNumFromBlock(block, point)
return new BlockBorderPoint(block, point.x, point.y, index, apexId, point_base.x, point_base.y)
}
/** 拖动时,寻找停靠点最近的板和参照点 */
static getClosestBlock(pm: PlaceMaterial, pb: PlaceBoard, block: PlaceBlock, p: Point): BlockBorderPoint {
let bestDis = Number.MAX_VALUE
let closestBlock: PlaceBlock // 最接近的小板
let curveIndex = 0
let x = 0; let y = 0 // 最接近小板的接触点 坐标(现对于小板的位置)
// 1先判断是否把停靠点拉到大板的四个点
let border = pm.cutBorder - pm.diameter / 2 - pm.cutKnifeGap / 2 // 因为移动小板的轮廓 是包括缝隙的一半 ,所以这边要抵消掉。
if (p.x < border + 50 && p.y < border + 50) return new BlockBorderPoint(null, border, border, -1, -1);
if (p.x > pb.width - 50 && p.y < border + 50) return new BlockBorderPoint(null, pb.width - border, border, -1, -1);
if (p.x > pb.width - 50 && p.y > pb.length - 50) return new BlockBorderPoint(null, pb.width - border, pb.length - border, -1, -1);
if (p.x < border + 50 && p.y > pb.length - 50) return new BlockBorderPoint(null, border, pb.length - border, -1, -1);
let innerBlocks = BlockHelper.getInnerBlock(block, pb.blockList) // 内部的小板
// 2找最靠近的板顶点(包括内部被造型挖掉的顶点)
for (let b of pb.blockList) {
if (b == block)
continue
// 这个板在block 内部,不参与对比
if (innerBlocks.includes(b))
continue
let border = BlockPlus.getBorder_moving(b)
let borders_inner = BlockPlus.getInnerPlaceBorders(b)
// 在外框+内部内框内找到点
let borders = []
borders.push(border)
for (const b of borders_inner) { borders.push(b) }
for (const curves of borders) {
for (let i = 0; i < curves.length; i++) {
let line = curves[i]
let dis = Math.pow(b.placeX + line.StartPoint.m_X - p.x, 2) + Math.pow(b.placeY + line.StartPoint.m_Y - p.y, 2);
if (dis < 5000 && dis < bestDis) {
bestDis = dis
x = line.StartPoint.m_X
y = line.StartPoint.m_Y
curveIndex = i
closestBlock = b
}
}
}
}
if (closestBlock != null) {
const point = new Point(x, y)
let apexId = BlockHelper.getApexAngleNumFromBlock(closestBlock, point)
// 考虑 closestBlock 有微小突出造型,加以偏移
const curves = BlockPlus.getBorder_moving(closestBlock)
// 存在板外 的造型或2v刀路
if (BlockPlus.hasModelOutBlock(closestBlock)) {
let pl = BlockPlus.borderToPolyline(curves, true)
let x1 = pl.BoundingBox.min.x
let y1 = pl.BoundingBox.min.y
let x2 = pl.BoundingBox.max.x
let y2 = pl.BoundingBox.max.y
if (point.x < 0)
point.x = x1
if (point.x > closestBlock.placeWidth)
point.x = x2
if (point.y < 0)
point.y = y1
if (point.y > closestBlock.placeLength)
point.y = y2
}
return new BlockBorderPoint(closestBlock, point.x, point.y, curveIndex, apexId)
}
// 3找不到最靠近的板 看看是否靠近大板四边
if (p.x < border + 50)
return new BlockBorderPoint(null, border, p.y, -1, -1)
if (p.x > pb.width - 50)
return new BlockBorderPoint(null, pb.width - border, p.y, -1, -1)
if (p.y < border + 50)
return new BlockBorderPoint(null, p.x, border, -1, -1)
if (p.y > pb.length - 50)
return new BlockBorderPoint(null, p.x, pb.length - border, -1, -1)
// 没找到附近可参考的板
return null
}
/** 选择最近的板,来定位被移动小板的位置 */
static replaceBlockRefClosest(pm: PlaceMaterial, block: PlaceBlock, newBoardId: number, dragingBlockPoint: BlockBorderPoint, referBlockPoint: BlockBorderPoint, dragedDistance: Point) {
let gap = pm.diameter + pm.cutKnifeGap
// 拖拉点现在位置
let dragedPointX = dragingBlockPoint.placeX + dragedDistance.x
let dragedPointY = dragingBlockPoint.placeY + dragedDistance.y
// 板的当前外扩
let blockoff = BlockSizePlus.getOffDis(block)
let newP: Point
let nx = 0
let ny = 0
// 参照点 为大板的四个顶点
if (referBlockPoint.block == null) {
nx = referBlockPoint.x
ny = referBlockPoint.y
// block 定位坐标 < 拖拉点 偏移>
nx = nx - dragingBlockPoint.x
ny = ny - dragingBlockPoint.y
}
else {
// 实际停靠点 坐标
nx = referBlockPoint.block.placeX + referBlockPoint.x
ny = referBlockPoint.block.placeY + referBlockPoint.y
// block 定位坐标 < 拖拉点 偏移>
nx = nx - dragingBlockPoint.x
ny = ny - dragingBlockPoint.y
}
// 默认按P定位
BlockHelper.replaceBlock(pm, block, newBoardId, new Point(nx, ny))
}
/** 获得放置在block内部的板列表 */
static getInnerBlock(block: PlaceBlock, list: PlaceBlock[]): PlaceBlock[] {
let innerList: PlaceBlock[] = []
// 如果没有内部空间直接范围
let borders = BlockPlus.getBorders_inner(block)
if (!(borders && borders.length > 0))
return innerList
for (let b of list) {
if (b == block)
continue
let p1 = new Point(b.placeX, b.placeY)
let p2 = new Point(b.placeX + b.placeWidth, b.placeY + b.placeLength)
if (BlockHelper.isPointInInnerSpace(p1, block) && BlockHelper.isPointInInnerSpace(p2, block)) {
innerList.push(b)
continue
}
}
return innerList
}
static findIdx(arr, target) {
return arr.findIndex(c => c.blockId == target.blockId)
}
/** 删除小板 */
static removeBlock(order: PlaceOrder, pm: PlaceMaterial, pb: PlaceBoard, block: PlaceBlock) {
console.log('移除前', order.blockList, pm.blockList, pb.blockList, 'block', block);
if (block.isAdditionalBlock == false && block.isRemainBlock == false && [0, 1, 2].includes(block.type))
throw new Error('该板不能删除')
console.log('移除前', order.blockList, pm.blockList, pb.blockList, 'block', block);
// ArrayExt.remove(order.blockList, block);
// ArrayExt.remove(pm.blockList, block);
// ArrayExt.remove(pb.blockList, block);
order.blockList.splice(this.findIdx(order.blockList, block), 1);
pm.blockList.splice(this.findIdx(pm.blockList, block), 1);
pb.blockList.splice(this.findIdx(pb.blockList, block), 1);
console.log('移除后', order.blockList, pm.blockList, pb.blockList, 'block', block);
//检查干涉
checkOverlapInBoard(pm, pb);
//重设汇总
resetPlaceBoard(pm, pb);
resetPlaceMaterial(pm);
}
/** 订单中添加余料板 */
static createRemainBlock(order: PlaceOrder, pm: PlaceMaterial, pb: PlaceBoard, binfo: BlockPlaceInfo) {
let block = new PlaceBlock()
let [info] = binfo.abInfo
block.isRemainBlock = true
block.blockName = '余料板'
block.width = info.width
block.length = info.length
block.area = info.width * info.length * 0.000001
block.sealLeft = 0
block.sealRight = 0
block.sealTop = 0
block.sealBottom = 0
block.cutWidth = info.width
block.cutLength = info.length
block.cutArea = block.area
block.texture = info.texture
block.placeHole = 2
block.thickness = pm.thickness
block.goodsId = pm.goodsId
block.blockNo = binfo.bo
block.blockId = Number.parseInt(binfo.bo)
block.orderId = 0
if (binfo.points && binfo.points.length > 0) {
let bdetail = new PlaceBlockDetail()
bdetail.points = binfo.points
bdetail.orgPoints = JSON.parse(JSON.stringify(binfo.points))
bdetail.isUnRegular = true
bdetail.cutWidth = block.width
bdetail.cutLength = block.length
order.blockDetailList.push(bdetail)
block.blockDetail = bdetail
}
let saleorder = order.orderList.find(t => t.orderId == 0)
if (saleorder == null) {
saleorder = new Order()
order.orderList.push(saleorder)
}
block.placeOrder = order
block.order = saleorder
block.placeMaterial = pm
order.blockList.push(block)
pm.blockList.push(block)
if (pb)
pb.blockList.push(block)
return block
}
/** 获得排序ID的位置 */
static getCutOrderPoint(block: PlaceBlock): Point {
// return this.GetPlaceXYInBoard(block, block.SaleBlockDetail.notePosX, block.SaleBlockDetail.notePosY);
return new Point(block.placeX + block.labelPosX, block.placeY + block.labelPosY)
}
static getBackPlaceStyle(placeStype: PlaceStyle): PlaceStyle {
console.log('getBackPlaceStyle')
// 正面=0,正面右转=1,正面后转=2,正面左转=3,反面=4,反面右转=5,反面后转=6,反面左转=7
if (placeStype == PlaceStyle.FRONT)
return PlaceStyle.BACK
if (placeStype == PlaceStyle.FRONT_TURN_RIGHT)
return PlaceStyle.BACK_TURN_LEFT
if (placeStype == PlaceStyle.FRONT_TURN_BACK)
return PlaceStyle.BACK_TURN_BACK
if (placeStype == PlaceStyle.FRONT_TURN_LEFT)
return PlaceStyle.BACK_TURN_RIGHT
if (placeStype == PlaceStyle.BACK)
return PlaceStyle.FRONT
if (placeStype == PlaceStyle.BACK_TURN_LEFT)
return PlaceStyle.FRONT_TURN_RIGHT
if (placeStype == PlaceStyle.BACK_TURN_BACK)
return PlaceStyle.FRONT_TURN_BACK
if (placeStype == PlaceStyle.BACK_TURN_RIGHT)
return PlaceStyle.FRONT_TURN_LEFT
return placeStype
}
// 开料面排钻, 造型, 是否双面开料----------------------------------------------
/** 重设开料正方面孔造型列表 */
/**
*
* @param block
* @param config
* config.processMode (0() 1CNC组合 2)
* config.isCutProcess ()
*/
static resetDoFace_HoleModel(block: PlaceBlock, config) {
// //开料机加工模式: 0全加工 1不加工特殊板除外 2加工多的一面特殊版都加工 3加工少的一面特殊版都加工 4编程模式 5高级模式
// let processMode = PlaceStore.sysConfig.processMode;
const {
processMode = 0,
isCutProcess = true,
isCutAndCNCProcess = false,
isCustomized = false
} = config
if (!block.blockDetail) {
console.log('resetDoFace_HoleModel:block.blockDetail is undefind, please chck')
return
}
let isTurnOver = block.isTurnOver()
// 模式0: 开料机全部处理
if (isCutProcess) {
if (!block.blockDetail) {
console.error('')
}
// 正面 排钻
let faceHoles = isTurnOver ? block.blockDetail.holeListFaceB : block.blockDetail.holeListFaceA
block.holeListFaceA = faceHoles.concat(block.blockDetail.holeListThrough)
// 反面 排钻
block.holeListFaceB = isTurnOver ? block.blockDetail.holeListFaceA : block.blockDetail.holeListFaceB
// 正面 造型
let faceModels = isTurnOver ? block.blockDetail.modelListFaceB : block.blockDetail.modelListFaceA
block.modelListFaceA = faceModels.concat(block.blockDetail.modelListThrough)
// 反面造型
block.modelListFaceB = isTurnOver ? block.blockDetail.modelListFaceA : block.blockDetail.modelListFaceB
}
else if (isCutAndCNCProcess) {
NcAdvanceHelper.changeDoFace(block);
let orgMA = block.blockDetail.modelListFaceA.filter(t => t.isCutting);
let orgMB = block.blockDetail.modelListFaceB.filter(t => t.isCutting);
let orgMT = block.blockDetail.modelListThrough.filter(t => t.isCutting);
let orgHA = block.blockDetail.holeListFaceA.filter(t => t.isCutting);
let orgHB = block.blockDetail.holeListFaceB.filter(t => t.isCutting);
let orgHT = block.blockDetail.holeListThrough.filter(t => t.isCutting);
if (isTurnOver) {
block.modelListFaceA = orgMB.concat(orgMT);
block.modelListFaceB = orgMA;
block.holeListFaceA = orgHB.concat(orgHT);
block.holeListFaceB = orgHA;
}
else {
block.modelListFaceA = orgMA.concat(orgMT);
block.modelListFaceB = orgMB;
block.holeListFaceA = orgHA.concat(orgHT);;
block.holeListFaceB = orgHB;
}
}
else if (isCustomized) {
//正面 排钻
let faceHoles = isTurnOver ? block.blockDetail.holeListFaceB : block.blockDetail.holeListFaceA;
block.holeListFaceA = faceHoles.concat(block.blockDetail.holeListThrough);
block.holeListFaceA = block.holeListFaceA.filter(t => t.isCutting);
//反面 排钻
block.holeListFaceB = isTurnOver ? block.blockDetail.holeListFaceA : block.blockDetail.holeListFaceB;
block.holeListFaceB = block.holeListFaceB.filter(t => t.isCutting);
//正面 造型
let faceModels = isTurnOver ? block.blockDetail.modelListFaceB : block.blockDetail.modelListFaceA;
block.modelListFaceA = faceModels.concat(block.blockDetail.modelListThrough);
block.modelListFaceA = block.modelListFaceA.filter(t => t.isCutting);
//反面造型
block.modelListFaceB = isTurnOver ? block.blockDetail.modelListFaceA : block.blockDetail.modelListFaceB;
block.modelListFaceB = block.modelListFaceB.filter(t => t.isCutting);
}
//重设 isDO
block.blockDetail.holes.forEach(t => t.isCutting = false);
block.blockDetail.models.forEach(t => t.isCutting = false);
block.holeListFaceA.forEach(t => t.isCutting = true);
block.holeListFaceB.forEach(t => t.isCutting = true);
block.modelListFaceA.forEach(t => t.isCutting = true);
block.modelListFaceB.forEach(t => t.isCutting = true);
//修改了默认加工,需要再对造型换刀处理
resetModelKnife(block, config);
//B面是否需要加工
block.isCutOtherFace = block.blockDetail.holeListFaceB.length + block.blockDetail.modelListFaceB.length > 0;
//需翻面处理(包括开料机,cnc)
block.isCutTurnOver = block.isCutOtherFace;
//反面需处理(包括开料机,cnc) by origin
// if (!block.IsTurnOver)
// {
// block.NeedTurnFaceToDo = block.BackHoleCount + block.BackModelCount + block.HoleCount_Side > 0;
// }
//获取贴标位置
let p = this.getPlaceXYInBlock(block, block.blockDetail.labelPosX, block.blockDetail.labelPosY, false, false);
block.labelPosX = p.x;
block.labelPosY = p.y;
//设置 cnc 处理面
this.resetCncIsDoFace(block);
}
/** 重设其他 */
static restOther(block) {
//B面是否需要加工
block.isCutOtherFace = block.blockDetail.holeListFaceB.length + block.blockDetail.modelListFaceB.length > 0;
//需翻面处理(包括开料机,cnc)
block.isCutTurnOver = block.isCutOtherFace;
//获取贴标位置
let p = this.getPlaceXYInBlock(block, block.blockDetail.labelPosX, block.blockDetail.labelPosY, false, false);
block.labelPosX = p.x;
block.labelPosY = p.y;
//设置 cnc 处理面
this.resetCncIsDoFace(block);
}
/** 开料面排钻列表 */
static getHoles_DoFace(block: PlaceBlock, isBackFace: boolean): BlockHole[] {
if (!block.blockDetail) {
console.log('getHoles_DoFace:blockDetail is undefind!')
return []
}
let holesArr = isBackFace ? block.blockDetail?.holes.filter(e => e.face == 1) : block.blockDetail?.holes.filter(e => e.face == 0)
// 给孔 加上所属的板编号
holesArr.map(e => e.blockNo = block.blockNo)
return holesArr
}
/** 获取开料大板内所有的排钻 未排序*/
2025-07-23 10:12:11 +08:00
static async GetHoles_BoardAllBlocksByDoFace(pb: PlaceBoard,isBackFace: boolean) {
2025-07-22 18:22:31 +08:00
let allHoles: any[] = []
2025-07-23 10:12:11 +08:00
// const backPlaceStyleArr = [PlaceStyle.BACK, PlaceStyle.BACK_TURN_BACK, PlaceStyle.BACK_TURN_LEFT, PlaceStyle.BACK_TURN_RIGHT]
2025-07-22 18:22:31 +08:00
for (const block of pb.blockList) {
2025-07-23 10:12:11 +08:00
let holes = await this.getHoles_DoFace(block, isBackFace)
2025-07-22 18:22:31 +08:00
allHoles = allHoles.concat(holes)
}
return allHoles
}
/** 开料面造型列表 */
static GetModels_DoFace(block: PlaceBlock, isBackFace: boolean): BlockModel[] {
if (!block.blockDetail) {
console.log('getHoles_DoFace:blockDetail is undefind!')
return []
}
let modelsArr = isBackFace ? block.blockDetail?.models.filter(e => e.face == 1) : block.blockDetail?.models.filter(e => e.face == 0)
// 给造型 加上所属的板编号
modelsArr.map(e => e.blockNo = block.blockNo)
return modelsArr
}
2025-07-23 10:12:11 +08:00
static async GetModels_BoardAllBlocksByDoFace(pb: PlaceBoard,isBackFace: boolean) {
2025-07-22 18:22:31 +08:00
let allModels: any[] = []
const backPlaceStyleArr = [PlaceStyle.BACK, PlaceStyle.BACK_TURN_BACK, PlaceStyle.BACK_TURN_LEFT, PlaceStyle.BACK_TURN_RIGHT]
for (const block of pb.blockList) {
2025-07-23 10:12:11 +08:00
let models = await this.GetModels_DoFace(block, isBackFace)
2025-07-22 18:22:31 +08:00
allModels = allModels.concat(models)
}
return allModels
}
// 判断造型是否打穿且矩形
static checkModelIsThroughRectange(block: PlaceBlock, m: BlockModel): boolean {
if (m.depth < block.thickness - 0.01)
return false
if (m.pointList.length != 5)
return false
let p0 = m.pointList[0]
let p1 = m.pointList[1]
let p2 = m.pointList[2]
let p3 = m.pointList[3]
let p4 = m.pointList[4]
// 有曲线,不算
if (p0.curve != 0 || p1.curve != 0 || p2.curve != 0 || p3.curve != 0 || p4.curve != 0)
return false
// 不是闭合的,不算矩形
if (!equal(p0.pointX, p4.pointX) || !equal(p0.pointY, p4.pointY))
return false
// 有边都斜线 ,就不算矩形
if (!equal(p0.pointX, p1.pointX) && !equal(p0.pointY, p1.pointY))
return false
if (!equal(p1.pointX, p2.pointX) && !equal(p1.pointY, p2.pointY))
return false
if (!equal(p2.pointX, p3.pointX) && !equal(p2.pointY, p3.pointY))
return false
if (!equal(p3.pointX, p4.pointX) && !equal(p3.pointY, p4.pointY))
return false
// 对角线 不想等,不算
let d1 = (p0.pointX - p2.pointX) * (p0.pointX - p2.pointX) + (p0.pointY - p2.pointY) * (p0.pointY - p2.pointY)
let d2 = (p1.pointX - p3.pointX) * (p1.pointX - p3.pointX) + (p1.pointY - p3.pointY) * (p1.pointY - p3.pointY)
if (Math.abs(d1 - d2) > 0.5)
return false
return true
}
// 判断孔是打穿的面孔
static isHoleThrough(block: PlaceBlock, hole: BlockHole): boolean {
if (hole.face == FaceType.SIDE)
return false
if (hole.holeType == HoleType.THROUGH_HOLE)
return true
if (hole.depth >= block.thickness)
return true
return false
}
// 翻面标签开料面 是否需处理<标签显示>--------------------------------------------
/** 计算 cnc 正面,翻面是否应该处理 */
static resetCncIsDoFace(block: PlaceBlock) {
// remove by yonnie
// //开料机加工模式: 0全加工 1不加工特殊板除外 2加工多的一面特殊版都加工 3加工少的一面特殊版都加工 4编程模式 5高级模式
// let roleNum = PlaceStore.sysConfig.IsPriorFacing_RoleNum;
// 模式1: 开料机默认全部排钻造型 (正反面全部)
if (PlaceStore.sysConfig.isCutProcess) {
block.isCncLabelA = false
block.isCncLabelB = false
block.isCncLabelTurnOver = block.holeCountFaceB + block.modelCountFaceB > 0
return
}
// 其他模式
block.isCncLabelA = false
block.isCncLabelB = false
// 侧孔
block.isCncLabelTurnOver = block.holeCountSide + (block.isTurnOver ? block.holeCountFront + block.modelCountFront : block.holeCountBack + block.modelCountBack) > 0
return
}
// 开料时下刀点,下刀路径相关--------------------------------------------------
/** 获得下刀点在边框线上的坐标 */
static getCutPoint(block: PlaceBlock): Point {
let curves = BlockPlus.getBorder(block)
let pnum = block.cutPointId
while (pnum < 0) {
pnum += curves.length
}
while (pnum >= curves.length) {
pnum -= curves.length
}
return new Point(curves[pnum].StartPoint.m_X, curves[pnum].StartPoint.m_Y)
}
/** 获得下刀点在大板上的显示红点坐标 */
static getCutPointXYInBoard(block: PlaceBlock): Point {
let p = this.getCutPoint(block)
let x = p.x
let y = p.y
let offset = 4 // 靠近板心 距离
x = (x < block.placeWidth * 0.5) ? x + offset : x - offset
y = (y < block.placeLength * 0.5) ? y + offset : y - offset
return new Point(block.placeX + x, block.placeY + y)
}
/** 获得下刀线,下刀点前一段线 */
static getCutLine_Prev(block: PlaceBlock, borders: Curve2d[], offValue: number, prevLength = 10): Curve2d {
let p = this.getCutPoint(block)
let minDis = Number.MAX_VALUE
let index = 0
for (let i = 0; i < borders.length; i++) {
let x0 = borders[i].StartPoint.m_X - p.x
let y0 = borders[i].StartPoint.m_Y - p.y
let dis = x0 * x0 + y0 * y0
if (dis < minDis) {
minDis = dis
index = i
}
}
let prevID = index - 1
if (prevID < 0)
prevID = prevID + borders.length
let prevCurve = borders[prevID]
if (prevCurve instanceof Line2d) {
if (prevCurve.m_Length < prevLength) {
let newID = index - 2
if (newID < 0)
newID = newID + borders.length
let newC = borders[newID]
if (newC instanceof Line2d) {
if (newC.m_Length > prevLength)
return newC
}
}
return prevCurve
}
let arc = prevCurve as Arc2d
if (Math.abs(arc.m_Radius - offValue) < 0.2) {
// 这是倒角,返回 再前一段作为下刀线
let prevID = index - 2
if (prevID < 0)
prevID = prevID + borders.length
return borders[prevID]
}
else {
// 不是倒角,鬼知道之前是什么东西,就返回这条了.
return arc
}
}
// 获得下一条线段
static getCutLine_Next(borders: Curve2d[], line: Curve2d): Curve2d {
let index = borders.indexOf(line)
index++
if (index == borders.length) {
index = 0
}
return borders[index]
}
// 坐标相关 ,判断点在板内, 转换坐标等--------------------------------------------
/** 获得点在小板的顶角序号 左下角0,右下角1,右上角2,左上角3 不是顶角-1 */
static getApexAngleNumFromBlock(block: PlaceBlock, p: Point) {
let areaID = -1
if (equal(p.x, 0) && equal(p.y, 0))
return 0
if (equal(p.x, block.placeWidth) && equal(p.y, 0))
return 1
if (equal(p.x, block.placeWidth) && equal(p.y, block.placeLength))
return 2
if (equal(p.x, 0) && equal(p.y, block.placeLength))
return 3
return -1
}
// 判断点是否在板内,isOffset 是否外扩 刀直径
static isPointInBlock(p: Point, block: PlaceBlock, isOffset: boolean = false): boolean {
let offValue = isOffset ? block.blockDetail.offsetKnifeRadius : 0
// 如果 点 直接在异形的所在的矩形外,表示不在异形内,直接返回false
if (p.x < block.placeX - offValue)
return false
if (p.x > block.placeX + block.placeWidth + offValue)
return false
if (p.y < block.placeY - offValue)
return false
if (p.y > block.placeY + block.placeLength + offValue)
return false
let x = p.x - block.placeX
let y = p.y - block.placeY
let bpl = isOffset ? BlockPlus.getOrgPloylines(block) : BlockPlus.getCutPloylines(block)
if (!bpl)
return false
let isIn = PolylineHelper.isPointInPolyline(bpl.pl, x, y)
if (isIn == false)
return false
for (let mpl of bpl.pls_inner) {
let isInModel = PolylineHelper.isPointInPolyline(mpl, x, y)
if (isInModel)
return false // 如果在造型洞里头
}
return true
}
// 判断点是否在板内空间里头(造型挖空的)
static isPointInInnerSpace(p: Point, block: PlaceBlock) {
// 判断是否在内部空间里头,则返回false;
let borders_inner = BlockPlus.getCutLines_inner(block)
if (borders_inner && borders_inner.length > 0) {
for (const border of borders_inner) {
// 内部空间 有四个边
let xs = border.map((t) => { return t.StartPoint.m_X })
let ys = border.map((t) => { return t.StartPoint.m_X })
let x0 = Math.min.apply(null, xs)
let x1 = Math.max.apply(null, xs)
let y0 = Math.min.apply(null, ys)
let y1 = Math.max.apply(null, ys)
if (p.x >= block.placeX + x0 && p.x <= block.placeX + x1 && p.y >= block.placeY + y0 && p.y <= block.placeY + y1)
return true
}
}
return false
}
/** 获得原坐标在放置后的新坐标 */
static getPlaceXYInBlock(block: PlaceBlock, x: number, y: number, isSealed: boolean, isFaceB = false, preCutValueOff = null): Point {
let bwidth = block.cutWidth
let blength = block.cutLength
let x0 = x
let y0 = y
if (isSealed) // 已封边
{
bwidth = block.width
blength = block.length
x0 += block.offsetX
y0 += block.offsetY
}
if (!isSealed && preCutValueOff) // 没封边,且有封边
{
bwidth += preCutValueOff.w
blength += preCutValueOff.l
x0 += preCutValueOff.x
y0 += preCutValueOff.y
}
let _point: any = BlockHelper.getPlacedPostionInBlock(block.placeStyle, bwidth, blength, x0, y0, isFaceB)
return _point
}
/** 获得原板内坐标在大板中的坐标 */
static getPlaceXYInBoard(block: PlaceBlock, x: number, y: number, isSealed = false): Point {
// 正面
let pos0 = BlockHelper.getPlaceXYInBlock(block, x, y, isSealed, false)
pos0.x += block.placeX
pos0.y += block.placeY
return pos0
}
/** 获得翻转后的新坐标 */
static getPlacedPostionInBlock(placeStyle: PlaceStyle, bwidth: number, blength: number, x0: number, y0: number, isFaceB: boolean): Point {
let posX = x0
let posY = y0
let placeWidth = bwidth
switch (placeStyle) {
case PlaceStyle.FRONT:
break
case PlaceStyle.FRONT_TURN_RIGHT:
posX = y0
posY = bwidth - x0
placeWidth = blength
break
case PlaceStyle.FRONT_TURN_BACK:
posX = bwidth - x0
posY = blength - y0
break
case PlaceStyle.FRONT_TURN_LEFT:
posX = blength - y0
posY = x0
placeWidth = blength
break
case PlaceStyle.BACK:
posX = bwidth - x0
posY = y0
break
case PlaceStyle.BACK_TURN_RIGHT:
posX = y0
posY = x0
placeWidth = blength
break
case PlaceStyle.BACK_TURN_BACK:
posX = x0
posY = blength - y0
break
case PlaceStyle.BACK_TURN_LEFT:
posX = blength - y0
posY = bwidth - x0
placeWidth = blength
break
default:
break
}
if (isFaceB) {
posX = placeWidth - posX
}
return new Point(posX, posY)
}
/** 获得翻转前 小板内原坐标 posX,posY 放置后的坐标 */
static getOrginalPositionInBlock(block: PlaceBlock, placeStyle: PlaceStyle, posX: number, posY: number): Point {
let x0 = posX
let y0 = posY
let bwidth = block.cutWidth
let blength = block.cutLength
switch (placeStyle) {
case PlaceStyle.FRONT:
break
case PlaceStyle.FRONT_TURN_RIGHT:
y0 = posX
x0 = bwidth - posY
break
case PlaceStyle.FRONT_TURN_BACK:
x0 = bwidth - posX
y0 = blength - posY
break
case PlaceStyle.FRONT_TURN_LEFT:
y0 = blength - posX
x0 = posY
break
case PlaceStyle.BACK:
x0 = bwidth - posX
y0 = posY
break
case PlaceStyle.BACK_TURN_RIGHT:
y0 = posX
x0 = posY
break
case PlaceStyle.BACK_TURN_BACK:
x0 = posX
y0 = blength - posY
break
case PlaceStyle.BACK_TURN_LEFT:
y0 = blength - posX
x0 = bwidth - posY
break
default:
break
}
return new Point(x0, y0)
}
/** 获得离点距离最近的边框序号 faceId */
static getClosestSideFaceID(bDetail: PlaceBlockDetail, x3: number, y3: number): number {
let index = 0
let minDis = 99999
for (let i = 0; i < bDetail.points.length; i++) {
let j = i + 1
if (i == bDetail.points.length - 1)
j = 0
let x1 = bDetail.points[i].pointX
let y1 = bDetail.points[i].pointY
let x2 = bDetail.points[j].pointX
let y2 = bDetail.points[j].pointY
let dis = CADExt.getDisOff(x1, y1, x2, y2, x3, y3)
if (dis < minDis) {
minDis = dis
index = i
}
}
return index
}
/** 获得造型 反向点阵 */
static getModelPoints(model: BlockModel, isTurn: boolean): BlockModelPoint[] {
let orgPoints = model.pointList
if (isTurn == false)
return orgPoints
return BlockHelper.getTurnedModelPoints(orgPoints)
}
static getTurnedModelPoints(orgPoints: BlockModelPoint[]) // 造型翻转
{
let newPoints = []
for (let i = orgPoints.length - 1; i >= 0; i--) {
let prev = i > 0 ? i - 1 : orgPoints.length - 1
let newPoint = orgPoints[i].copy()
newPoint.curve = -orgPoints[prev].curve
newPoint.radius = orgPoints[prev].radius
newPoints.push(newPoint)
}
return newPoints
}
static getTurnPoints(orgPoints): any[] {
let newPoints = []
for (let i = orgPoints.length - 1; i >= 0; i--) {
let p = orgPoints[i]
let p_prev = i > 0 ? orgPoints[i - 1] : orgPoints[orgPoints.length - 1]
let newP = { x: p.x, y: p.y, z: p.z, bul: p_prev.bul, r: p_prev.r }
newPoints.push(newP)
}
return newPoints
}
static getRadius(x1: number, y1: number, x2: number, y2: number, bul: number): number {
let d = Math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2) / 2
return 0.5 * d * (1 + bul ** 2) / bul
}
}