Files
cut-abstractions/tests/dev1/dataHandle/common/LayoutEngine/BlockHelper.ts
2025-07-22 18:22:31 +08:00

1301 lines
45 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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开料机(雕刻机)加工 1开料机CNC组合 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
}
/** 获取开料大板内所有的排钻 未排序*/
static async GetHoles_BoardAllBlocksByDoFace(pb: PlaceBoard) {
let allHoles: any[] = []
const backPlaceStyleArr = [PlaceStyle.BACK, PlaceStyle.BACK_TURN_BACK, PlaceStyle.BACK_TURN_LEFT, PlaceStyle.BACK_TURN_RIGHT]
for (const block of pb.blockList) {
let holes = await this.getHoles_DoFace(block, backPlaceStyleArr.includes(block.placeStyle))
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
}
static async GetModels_BoardAllBlocksByDoFace(pb: PlaceBoard) {
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) {
let models = await this.GetModels_DoFace(block, backPlaceStyleArr.includes(block.placeStyle))
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
}
}