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

2396 lines
82 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 { Circle, Contour, ConverToPolylineAndSplitArc, Shape, ShapeManager } from 'cadapi'
import type { Polyline } from 'cadapi'
import { Vector3 } from 'three'
import { PolylineHelper } from '../../common/LayoutEngine/PolylineHelper.js'
import type { Curve2d } from '../../common/base/CAD.js'
import { Arc2d, Line2d, Point2d } from '../../common/base/CAD.js'
import { PlaceStyle, SizeExpand, PlaceBlock, PlaceBlockDetail, PlaceBorderContour, PlaceSpace, PlaceMaterial } from '../../confClass.js'
import { equal, getDis, getDis2, getDis_PointLine, getRect } from '../../common/base/MathComm.js'
import { getPlacePosition } from '../../common/base/PlaceStyleHelper'
import { SpacePlus } from './SpacePlus'
/**板件计算工具类 小板轮廓,走刀路径等 */
export class BlockPlus {
/** 小板初始化1各种轮廓|走刀路径|2尺寸扩展后的轮廓与走刀路径
* 配置入参
* isRectBlockChamfer = false, // 矩形板件倒角开料
isUnRegularBlockChamfer = false, // 异形板件倒角开料
preMillingSize = 0, // 预铣尺寸
*/
static initBlock(block: PlaceBlock, placeMaterial: PlaceMaterial, params: any) {
if(block.blockDetail == null) {
console.error('BlockPlus.initBlock: block.blockDetail is undefined', block)
return
}
if (block.blockDetail.borderContour)
return // 已初始化
const {
isRectBlockChamfer = false, // 矩形板件倒角开料
isUnRegularBlockChamfer = false, // 异形板件倒角开料
preMillingSize = 0, // 预铣尺寸
helpCutStyle = 0, // 辅助开料方式(0同刀辅助开料 1小刀辅助开料) useSameKnifeToHelpCutStyle
helpCutGap = 2, // 同刀辅助开料缝隙
} = params
if (!block.blockDetail) { return }
const pm = placeMaterial
const bd = block.blockDetail
if (pm == null) {
return // 异常
}
const cutKnifeR = pm.diameter / 2
const cutGap = pm.cutKnifeGap
// 开料偏移值 ,矩形波倒角
bd.offsetKnifeRadius = pm.diameter / 2
bd.isOffsetRounding = true // 默认要倒角
bd.preMillingSize = pm.preMillingSize
if (bd.points.length == 0) // 矩形板,设置不倒角
{
bd.isOffsetRounding = isRectBlockChamfer
}
else // 异形板
{
// 异形板倒角
bd.isOffsetRounding = isUnRegularBlockChamfer
}
// 初始化 小板基础轮廓
// 1.原始轮廓,成品轮廓
const border_final = this.createFinalBorder(bd, block)
// 2.开料轮廓 <不含预铣>
const border_org = this.createOrgBorder(bd)
bd.borderContour = new PlaceBorderContour(PlaceStyle.FRONT, border_final, border_org)
// 3.开料轮廓_带预铣, 外扩尺寸
bd.borderContour.borderPreMilling = border_org
bd.preMillingExpandSize = new SizeExpand()
if (preMillingSize > 0.0001) {
const rt = this.creatOrgBorderWithPrevCut(block, border_org, preMillingSize)
bd.borderContour.borderPreMilling = rt?.newBorders || []
bd.preMillingExpandSize = rt?.newSizeExpand || new SizeExpand()
// console.log('开料轮廓_带预铣, 外扩尺寸==》after', block, rt.newSizeExpand)
}
// 4. 板内走刀路径,板内空间
const innerGroup = this.analyeInners(bd, cutKnifeR, cutGap)
bd.borderContour.borderModelThrough = innerGroup.borders_inner_org
bd.borderContour.borderModelThroughR = innerGroup.borders_inner_r
bd.borderContour.cutLinesModelThrough = innerGroup.borders_inner_cut
bd.borderContour.borderInnerPlace = innerGroup.borders_inner_place
bd.borderContour.blockInnerSpace = innerGroup.spaces
// 5 造型外扩轮廓, 外扩尺寸
const { pls_model, sizeout: sizeout_model } = this.createPolyline_model(block)
bd.borderContour.polylinesOutModel = pls_model
bd.modelExpandSize = sizeout_model
// 6. 2V刀路 外扩轮廓,外扩尺寸
const { pls_2v, sizeout_2v } = this.createPolyline_2vModel(block)
bd.borderContour.polylines2vModel = pls_2v || []
bd.vKnifeModelExpandSize = sizeout_2v
// 7.同刀辅助 外扩尺寸
let isUseSameKnifeToHelpCut = helpCutStyle || 0
let useSameKnifeToHelpCutGap = helpCutGap || 0
const isSameKnifeToCut = isUseSameKnifeToHelpCut && useSameKnifeToHelpCutGap > 0
if (isSameKnifeToCut == false || bd.isUseSameKnifeToHelpCut == false) {
// 未启动同刀辅助, 或 该小板 不需要同刀辅助
bd.useSameKnifeToHelpCutGap = 0
bd.sameKnifeHelpExpandSize = new SizeExpand()
}
else {
const gap = useSameKnifeToHelpCutGap
bd.useSameKnifeToHelpCutGap = gap
bd.sameKnifeHelpExpandSize = new SizeExpand({ left: gap, right: gap, under: gap, upper: gap })
}
// 2V刀路,预洗,同刀辅助开料,出板造型刀
this.resetBlock(block, pm)
}
/** 重设小板 ,因为板材重新设置 预铣值 或 板外下刀 */
static resetBlock(block: PlaceBlock, placeMaterial: PlaceMaterial) {
if (!block.blockDetail) {
console.error('BlockPlus.resetBlock: block.blockDetail is undefined', block)
return
}
const pm = placeMaterial
const bd = block.blockDetail
const preMillingSize = pm.preMillingSize
// startDebug(block);
if (!bd.borderContour) {
console.error('BlockPlus.resetBlock: bd.borderContour is undefined', block)
return
}
// 开料刀 修改了,内部空间发生变化
if (!equal(bd.offsetKnifeRadius, pm.diameter / 2)) {
bd.offsetKnifeRadius = pm.diameter / 2
bd.borderContour.cutKnifeChanged()
// 4. 板内走刀路径,板内空间
const innerGroup = this.analyeInners(bd, pm.diameter / 2, pm.cutKnifeGap)
bd.borderContour.borderModelThrough = innerGroup.borders_inner_org
bd.borderContour.cutLinesModelThrough = innerGroup.borders_inner_cut
bd.borderContour.borderInnerPlace = innerGroup.borders_inner_place
bd.borderContour.blockInnerSpace = innerGroup.spaces
}
// 因为预铣, 同刀辅助会影响到开料走刀等轮廓,所以要将受影响的轮廓清空,需要的时候再生成
// 预铣
if (!equal(bd.preMillingSize, pm.preMillingSize)) {
bd.preMillingSize = preMillingSize
bd.borderContour.preValueChanged()
}
// 同刀辅助
let newTDFZ = 0
if (pm.isHelpCut && pm.helpCutGap > 0 && block.blockDetail.isUseSameKnifeToHelpCut) {
newTDFZ = pm.helpCutGap
block.blockDetail.sameKnifeHelpExpandSize = new SizeExpand({ left: newTDFZ, right: newTDFZ, upper: newTDFZ, under: newTDFZ })
}
else {
newTDFZ = 0
block.blockDetail.sameKnifeHelpExpandSize = new SizeExpand()
}
if (!equal(newTDFZ, bd.useSameKnifeToHelpCutGap)) {
bd.useSameKnifeToHelpCutGap = newTDFZ
bd.borderContour.sameKnifeGapChanged()
}
const cutRadius = (pm.diameter + pm.cutKnifeGap) / 2
// 预铣
let off1 = block.blockDetail.preMillingExpandSize || new SizeExpand()
// 造型外扩
const off2 = block.blockDetail.modelExpandSize || new SizeExpand()
// 2v 板外下刀
const off3 = block.blockDetail.vKnifeModelExpandSize || new SizeExpand()
// 同刀辅助
let off4 = block.blockDetail?.sameKnifeHelpExpandSize || new SizeExpand()
// 不启用 预铣
// if (preMillingSize < 0.0001)
// off1 = new SizeExpand()
if (newTDFZ < 0.001)
off4 = new SizeExpand()
// 预铣+同刀辅助+ 造型外扩2v刀路 应该取最大值
const off = new SizeExpand()
off.left = Math.max(off1.left + off4.left + cutRadius, off2.left, off3.left)
off.right = Math.max(off1.right + off4.right + cutRadius, off2.right, off3.right)
off.bottom = Math.max(off1.bottom + off4.bottom + cutRadius, off2.bottom, off3.bottom)
off.top = Math.max(off1.top + off4.top + cutRadius, off2.top, off3.top)
off.setSize()
bd.currentSizeExpand = off
}
/** 小板是否有超出造型或二维刀路 */
static hasModelOutBlock(block: PlaceBlock): boolean {
if (block.blockDetail == null)
return false
if (block.blockDetail.borderContour == null)
return false
if (block.blockDetail.borderContour.polylinesOutModel == null || block.blockDetail.borderContour.polylines2vModel == null)
return false
return block.blockDetail.borderContour.polylinesOutModel.length + block.blockDetail.borderContour.polylines2vModel.length > 0
}
/** 获得 成品轮廓 isPlaced=false为不旋转的 */
static getFinalBorder(block: PlaceBlock, isPlaced = true, placeStyle?: PlaceStyle): Curve2d[] {
const bu = this.getPlacedUnit(block, isPlaced, placeStyle)
if (bu == null) {
console.error('BlockPlus.getOrgBorderNew: bu is undefined', block)
return []
}
return bu.borderFinal
}
/** 获得 开料轮廓-不含预铣 isPlaced=false为不旋转的 */
static getOrgBorder(block: PlaceBlock, isPlaced = true, placeStyle?: PlaceStyle): Curve2d[] {
const bu = this.getPlacedUnit(block, isPlaced, placeStyle)
if (bu == null) {
console.error('BlockPlus.getOrgBorder: bu is undefined', block)
return []
}
return bu.borderOrg
}
/** 获得 开料轮廓-不含预铣 isPlaced=false为不旋转的 */
static getOrgBorderNew(block: PlaceBlock, isPlaced = true, placeStyle?: PlaceStyle): Curve2d[] {
const bu = this.getPlacedUnitNew(block, isPlaced, placeStyle)
if (bu == null) {
console.error('BlockPlus.getOrgBorderNew: bu is undefined', block)
return []
}
return bu.borderOrg
}
/** 获得当前板 轮廓多段线 */
static getOrgPolyline(block: PlaceBlock): Polyline | null {
if (block.blockDetail == null) {
console.error('BlockPlus.getOrgPolyline: block.blockDetail is undefined', block)
return null
}
const bd = block.blockDetail.borderContour
if (bd == null) {
console.error('BlockPlus.getOrgPolyline: bd is undefined', block)
return null
}
if (!bd.polylineOrg) {
const border = bd.borderOrg
const pl = PolylineHelper.createByCurve2d(border)
bd.polylineOrg = pl
}
return bd.polylineOrg
}
/** 获得 开料轮廓 _有预铣含预铣 */
static getBorder(block: PlaceBlock, isPlaced = true, placeStyle?: PlaceStyle): Curve2d[] {
if (block.blockDetail == null) {
console.error('BlockPlus.getBorder: block.blockDetail is undefined', block)
return []
}
let preSize = block.blockDetail.preMillingSize
if (preSize < 0.0001)
preSize = 0
// 初始
const baseContour = block.blockDetail.borderContour
if (baseContour == null) {
console.error('BlockPlus.getBorder: baseContour is undefined', block)
return []
}
if (!baseContour.border ||(Array.isArray(baseContour.border) && baseContour.border.length ==0)) // 生成 预铣轮廓
{
const border = preSize == 0 ? baseContour.borderOrg : baseContour.borderPreMilling
baseContour.border = border
}
// 放置后
const pbu = this.getPlacedUnit(block, isPlaced, placeStyle)
if (pbu == null) {
console.error('BlockPlus.getBorder_moving_new: pbu is undefined', block)
return []
}
if (!pbu.border) {
pbu.border = this.transformBorder(baseContour.border, pbu.placeStyle, block.cutWidth, block.cutLength)
}
return pbu.border
}
/** 获得 开料轮廓—有预铣带预铣-有同刀辅助带同刀辅助 */
static getBorder_sameKnife(block: PlaceBlock, isPlaced = true, placeStyle?: PlaceStyle): Curve2d[] {
if (block.blockDetail == null) {
console.error('BlockPlus.getBorder_sameKnife: block.blockDetail is undefined', block)
return []
}
// 如果没有同刀辅助,直接返回开料轮廓
let helpCutGap = block.blockDetail.useSameKnifeToHelpCutGap
if (helpCutGap < 0.001)
helpCutGap = 0
// 初始
const baseContour = block.blockDetail.borderContour
if (baseContour == null) {
console.error('BlockPlus.getBorder_sameKnife: baseContour is undefined', block)
return []
}
if (!baseContour.borderSameKnifeHelpCut) {
const borders = this.getBorder(block, false)
if (helpCutGap == 0) // 无同刀辅助
{
baseContour.borderSameKnifeHelpCut = borders
}
else {
let rounding = block.blockDetail.isOffsetRounding
if (block.isUnRegular)
rounding = true // 异形板 必须倒角
baseContour.borderSameKnifeHelpCut = this.offsetCurves(borders, helpCutGap, rounding) // 必须倒角,否则 尖角超出 开料范围
}
}
// 放置后
const pbu = this.getPlacedUnit(block, isPlaced, placeStyle)
if (pbu == null) {
console.error('BlockPlus.getBorder_moving_new: pbu is undefined', block)
return []
}
if (!pbu.borderSameKnifeHelpCut) {
pbu.borderSameKnifeHelpCut = this.transformBorder(baseContour.borderSameKnifeHelpCut, pbu.placeStyle, block.cutWidth, block.cutLength)
}
return pbu.borderSameKnifeHelpCut
}
/** 获得走刀路径(含预铣) isPlaced = false为不旋转 */
/**
*
* @param block 小板
* @param placeMaterial 开料大板
* @param isPlaced 是否旋转
* @param placeStyle 旋转后的放置方式
* @param config 配置
{
isRectBlockChamfer: false, // 矩形板件倒角开料
isUnRegularBlockChamfer: false, // 异形板件倒角开料
}
* @returns
*/
static getCutLines(block: PlaceBlock, placeMaterial: PlaceMaterial, isPlaced = true, placeStyle: PlaceStyle | undefined, config: any): Curve2d[] {
// 走刀路径由开料轮廓(含预铣) border_plus 偏移一个刀半径而成
const {
isRectBlockChamfer = false, // 矩形板件倒角开料
isUnRegularBlockChamfer = false, // 异形板件倒角开料
} = config
if (!block.blockDetail) {
console.error('BlockPlus.getCutLines: block.blockDetail is undefined', block)
return []
}
if (!block.blockDetail.borderContour) {
console.error('BlockPlus.getCutLines: block.blockDetail.borderContour is undefined', block)
return []
}
// 初始
const baseContour = block.blockDetail.borderContour
if (!baseContour.cutLines) {
const borders = this.getBorder(block, false)
// 偏移值
const offvalue = placeMaterial.diameter / 2 // 开料刀的一半
// 是否倒角
let isOffsetRounding = false // block.SaleBlockDetail.IsOffsetRounding;
if (block.isUnRegular == false) // 矩形板,设置不倒角
{
isOffsetRounding = isRectBlockChamfer
}
else // 异形板
{
// 异形倒角
isOffsetRounding = isUnRegularBlockChamfer
}
baseContour.cutLines = this.offsetCurves(borders, offvalue, isOffsetRounding)
}
// 放置后
const pbu = this.getPlacedUnit(block, isPlaced, placeStyle)
if (pbu == null) {
console.error('BlockPlus.getBorder_moving_new: pbu is undefined', block)
return []
}
if (!pbu.cutLines) {
pbu.cutLines = this.transformBorder(baseContour.cutLines, pbu.placeStyle, block.cutWidth, block.cutLength)
}
return pbu.cutLines
}
/**
* 获得 同刀辅助 的走刀路径
* @param block 小板
* @param isPlaced 是否翻转
* @param placeStyle 翻转后的放置方式
* @param config 配置
* {
isRectBlockChamfer: false, // 矩形板件倒角开料
isUnRegularBlockChamfer: false, // 异形板件倒角
} = config || {}
* @returns
*/
static getCutLines_sameKnife(block: PlaceBlock, placeMaterial: PlaceMaterial, isPlaced = true, placeStyle?: PlaceStyle, config?: any): Curve2d[] {
// 同刀辅助 走刀路径 由 开料轮廓 _含预铣_同刀辅助 偏移一个刀半径 厚度 而成
const {
isRectBlockChamfer = false, // 矩形板件倒角开料
isUnRegularBlockChamfer = false, // 异形板件倒角开料
} = config || {}
if (!block.blockDetail) {
console.error('BlockPlus.getCutLines_sameKnife: block.blockDetail is undefined', block)
return []
}
// 不用同刀辅助
const helpCutGap = block.blockDetail.useSameKnifeToHelpCutGap
if (helpCutGap < 0.001) {
return this.getCutLines(block, placeMaterial, isPlaced, placeStyle, config)
}
const baseContour = block.blockDetail.borderContour
if (baseContour == null) {
console.error('BlockPlus.getCutLines_sameKnife: baseContour is undefined', block)
return []
}
if (!baseContour.cutLinesSameKnifeHelpCut) {
const borders = this.getBorder_sameKnife(block, false)
// 偏移值
const kr = placeMaterial.diameter / 2 // 开料刀的一半
// 同刀辅助 不倒角 ,
// 是否倒角 异形板必须倒角
let isOffsetRounding = false // block.SaleBlockDetail.IsOffsetRounding;
if (block.isUnRegular == false) // 矩形板,设置不倒角
{
isOffsetRounding = isRectBlockChamfer
}
else // 异形板
{
isOffsetRounding = isUnRegularBlockChamfer
}
baseContour.cutLinesSameKnifeHelpCut = this.offsetCurves(borders, kr, isOffsetRounding)
}
// 放置后
const pbu = this.getPlacedUnit(block, isPlaced, placeStyle)
if (pbu == null) {
console.error('BlockPlus.getBorder_moving_new: pbu is undefined', block)
return []
}
if (!pbu.cutLinesSameKnifeHelpCut) {
pbu.cutLinesSameKnifeHelpCut = this.transformBorder(baseContour.cutLinesSameKnifeHelpCut, pbu.placeStyle, block.cutWidth, block.cutLength)
}
return pbu.cutLinesSameKnifeHelpCut
}
/**
* 获得 手动排版路径 包括板外下刀等轮廓
* 由开料轮廓 偏移 预铣 ,同刀辅助, 开料刀半径 缝隙/2 )
* 再与 二维刀路,板外小刀,造型外扩 合并起来的
*/
static getBorder_moving(block: PlaceBlock, placeMaterial: PlaceMaterial, isPlaced = true, placeStyle?: PlaceStyle): Curve2d[] {
if (!block.blockDetail || !block.blockDetail.borderContour) {
console.error('BlockPlus.getBorder_moving: block.blockDetail or block.blockDetail.borderContour is undefined', block)
return []
}
this.theBlock = block
const bd = block.blockDetail
// 初始
const baseContour = bd.borderContour
if (baseContour == null) {
console.error('BlockPlus.getBorder_moving: baseContour is undefined', block)
return []
}
if (!baseContour.borderMoving) {
// 1.开料轮廓<带预铣>
const borders = this.getBorder(block, false)
// 偏移值 = 同刀辅助 + 刀半径 + 缝隙 /2
const cutGap = block.blockDetail.useSameKnifeToHelpCutGap + (placeMaterial.diameter + placeMaterial.cutKnifeGap) / 2
// 是否倒角(如果倒角,手动排版,拖拉时,停靠点不便计算,所以设置成不倒角,然后截断>
const isOffsetRounding = false
// 原轮廓
let border_moving = this.offsetCurves(borders, cutGap, isOffsetRounding)
const pl = this.borderToPolyline(border_moving)
// 造型的外扩,2v刀路的
const pls_m = baseContour.polylinesOutModel.concat(baseContour.polylines2vModel)
// 合并
const rpl = this.unionPolylines(pl, pls_m)
//
border_moving = this.polylineToBorder(rpl)
baseContour.borderMoving = border_moving
}
// 放置后
const pbu = this.getPlacedUnit(block, isPlaced, placeStyle)
if (pbu == null) {
console.error('BlockPlus.getBorder_moving_new: pbu is undefined', block)
return []
}
return pbu.borderMoving
}
static getBorder_moving_new(block: PlaceBlock, pb: PlaceMaterial, isPlaced = true, placeStyle: PlaceStyle): Curve2d[] {
if (block.blockDetail == null) {
console.error('BlockPlus.getBorder_moving_new: block.blockDetail is undefined', block)
return []
}
this.theBlock = block
const bd = block.blockDetail
// 初始
const baseContour = bd.borderContour
if (!baseContour) {
console.error('BlockPlus.getBorder_moving_new: baseContour is undefined', block)
return []
}
if (!baseContour.borderMoving) {
// 1.开料轮廓<带预铣>
const borders = this.getBorder(block, false)
// 偏移值 = 同刀辅助 + 刀半径 + 缝隙 /2
const cutGap = block.blockDetail.useSameKnifeToHelpCutGap + (pb.diameter + pb.cutKnifeGap) / 2
// 是否倒角(如果倒角,手动排版,拖拉时,停靠点不便计算,所以设置成不倒角,然后截断>
const isOffsetRounding = false
// 原轮廓
let border_moving = this.offsetCurves(borders, cutGap, isOffsetRounding)
const pl = this.borderToPolyline(border_moving)
// 造型的外扩,2v刀路的
const pls_m = baseContour.polylinesOutModel.concat(baseContour.polylines2vModel)
// 合并
const rpl = this.unionPolylines(pl, pls_m)
//
border_moving = this.polylineToBorder(rpl)
baseContour.borderMoving = border_moving
}
// 放置后
const pbu = this.getPlacedUnit(block, isPlaced, placeStyle)
if (pbu == null) {
console.error('BlockPlus.getBorder_moving_new: pbu is undefined', block)
return []
}
if (!pbu.borderMoving) {
pbu.borderMoving = this.transformBorder(baseContour.borderMoving, pbu.placeStyle, block.cutWidth, block.cutLength)
}
return pbu.borderMoving
}
static getOutModelPloyline(block: PlaceBlock, isPlaced = true, placeStyle?: PlaceStyle): Polyline[] {
if (!block.blockDetail || !block.blockDetail.borderContour) {
console.error('BlockPlus.getOutModelPloyline: block.blockDetail or block.blockDetail.borderContour is undefined', block)
return []
}
const bd = block.blockDetail
// 初始
const baseContour = bd.borderContour
if (baseContour == null) {
console.error('BlockPlus.getOutModelPloyline: baseContour is undefined', block)
return []
}
const pls_m = baseContour.polylinesOutModel.concat(baseContour.polylines2vModel)
if (placeStyle == PlaceStyle.FRONT)
return pls_m
const pbu = this.getPlacedUnit(block, isPlaced, placeStyle)
if (pbu == null) {
console.error('BlockPlus.getOutModelPloyline: pbu is undefined', block)
return []
}
let newPls: Polyline[] = []
for (let pl of pls_m) {
let newpl = this.transformPolyline(pl, pbu.placeStyle, block.cutWidth, block.cutLength)
newPls.push(newpl)
}
return newPls
}
static theBlock
/** 获取轮廓用于王者优化,预铣 + 同刀辅助 ,造型外扩 + 2维刀路外扩 */
static getBorder_WZYH(block: PlaceBlock, placeMaterial: PlaceMaterial, isPlaced = true, placeStyle?: PlaceStyle): Curve2d[] {
this.theBlock = block
const bd = block.blockDetail
if (!bd || !bd.borderContour) {
console.error('BlockPlus.getBorder_WZYH: block.blockDetail or block.blockDetail.borderContour is undefined', block)
return []
}
const baseContour = bd.borderContour
// 生成 同刀辅助 路径 <原方向》
if (baseContour.borderKingOptimize == null) {
// 开料轮廓 <同刀辅助>
const borders = this.getBorder_sameKnife(block, false)
// 偏移值= 同刀辅助 + 刀半径 + + 缝隙 /2
const cutGap = (placeMaterial.diameter + placeMaterial.diameter) / 2
// 是否倒角 < 如果倒角,手动排版,拖拉时,停靠点 不好计算,所以设置成不倒角,然后截断>,
const isOffsetRounding = bd.isOffsetRounding
// 走刀路径
const borders2 = this.offsetCurves(borders, cutGap, isOffsetRounding)
const pl = this.borderToPolyline(borders2)
// 造型的外扩,2v刀路的
const pls_m = baseContour.polylinesOutModel.concat(baseContour.polylines2vModel)
// 合并
const rpl = this.unionPolylines(pl, pls_m)
baseContour.borderKingOptimize = this.polylineToBorder(rpl)
}
// 放置后
const pbu = this.getPlacedUnit(block, isPlaced, placeStyle)
if (pbu == null) {
return []
}
if (!pbu.borderKingOptimize) {
pbu.borderKingOptimize = this.transformBorder(baseContour.borderKingOptimize, pbu.placeStyle, block.cutWidth, block.cutLength)
}
return pbu.borderKingOptimize
}
/** 获得 内部轮廓 <挖穿造型> */
static getBorders_inner(block: PlaceBlock, isPlaced = true, placeStyle?: PlaceStyle): Curve2d[][] {
const bu = this.getPlacedUnit(block, isPlaced, placeStyle)
if (bu == null) {
console.error('BlockPlus.getBorders_inner: 获取板的内部轮廓失败', block)
return []
}
// 如果没有内部轮廓
if (bu.borderModelThrough == null) {
const borders = this.getBorders_inner(block, false)
const borders_off: Curve2d[][] = []
for (const border of borders) {
const newBorder = this.transformBorder(border, bu.placeStyle, block.cutWidth, block.cutLength)
borders_off.push(newBorder)
}
bu.borderModelThrough = borders_off
}
return bu.borderModelThrough
}
/** 获得 内部轮廓 <挖穿造型> */
static getBorders_innerNew(block: PlaceBlock, isPlaced = true, placeStyle?: PlaceStyle): Curve2d[][] {
const bu = this.getPlacedUnitNew(block, isPlaced, placeStyle)
if (bu == null) {
console.error('BlockPlus.getBorders_innerNew: 获取板的内部轮廓失败', block)
return []
}
if (bu.borderModelThrough == null) {
const borders = this.getBorders_innerNew(block, false)
const borders_off: Curve2d[][] = []
for (const border of borders) {
const newBorder = this.transformBorderNew(border, bu.placeStyle, block.cutWidth, block.cutLength)
borders_off.push(newBorder)
}
bu.borderModelThrough = borders_off
}
return bu.borderModelThrough
}
/** 获得内部轮廓 <挖穿造型> 半径 */
static getBorders_inner_r(block: PlaceBlock) {
if (block.blockDetail == null || block.blockDetail.borderContour == null) {
console.error('BlockPlus.getBorders_inner_r: block.blockDetail or block.blockDetail.borderContour is undefined', block)
return []
}
return block.blockDetail.borderContour.borderModelThroughR
}
/** 获得 内部走刀轮廓 <挖穿造型> */
static getCutLines_inner(block: PlaceBlock, isPlaced = true, placeStyle?: PlaceStyle): Curve2d[][] {
const bu = this.getPlacedUnit(block, isPlaced, placeStyle)
if (bu == null) {
console.error('BlockPlus.getCutLines_inner: 获取板的内部走刀轮廓失败', block)
return []
}
if (bu.cutLinesModelThrough == null) {
const borders = this.getCutLines_inner(block, false)
const borders_off: Curve2d[][] = []
for (const border of borders) {
const newBorder = this.transformBorder(border, bu.placeStyle, block.cutWidth, block.cutLength)
borders_off.push(newBorder)
}
bu.cutLinesModelThrough = borders_off
}
return bu.cutLinesModelThrough
}
/** 获得 内部排版轮廓 <挖穿造型> */
static getInnerPlaceBorders(block: PlaceBlock, isPlaced = true, placeStyle?: PlaceStyle): Curve2d[][] {
const bu = this.getPlacedUnit(block, isPlaced, placeStyle)
if (bu == null) {
console.error('BlockPlus.getInnerPlaceBorders: 获取板的内部排版轮廓失败', block)
return []
}
if (bu.borderInnerPlace == null) {
const borders = this.getInnerPlaceBorders(block, false)
const borders_off: Curve2d[][] = []
for (const border of borders) {
const newBorder = this.transformBorder(border, bu.placeStyle, block.cutWidth, block.cutLength)
borders_off.push(newBorder)
}
bu.borderInnerPlace = borders_off
}
return bu.borderInnerPlace
}
/** 获得 板内空间 《挖穿孔洞 + 缺角》 */
static getSpaces(block: PlaceBlock, pm: PlaceMaterial): PlaceSpace[] {
if (block.blockDetail == null || block.blockDetail.borderContour == null) {
console.error('BlockPlus.getSpaces: block.blockDetail or block.blockDetail.borderContour is undefined', block)
return []
}
const bu = block.blockDetail.borderContour
if (!bu.blockOuterSpace)
bu.blockOuterSpace = this.createOutSpaces(block, pm) // 缺角空间不存在,创建
// 挖穿孔洞 + 缺角
return bu.blockInnerSpace.concat(bu.blockOuterSpace)
}
static getInnerSpaces(block: PlaceBlock): PlaceSpace[] {
const bu = this.getPlacedUnit(block, false)
// 挖穿孔洞
return bu ? bu.blockInnerSpace : []
}
static getModelHole(block: PlaceBlock, isPlaced = true, placeStyle?: PlaceStyle): Curve2d[][] {
const bu = this.getPlacedUnit(block, isPlaced, placeStyle)
if (bu == null) {
console.error('BlockPlus.getModelHole: 获取板的轮廓集失败', block)
return []
}
if (!bu.borderInnerPlace) {
if (block.blockDetail == undefined) {
console.error('BlockPlus.getModelHole: block.blockDetail is undefined', block)
return []
}
if (block.blockDetail.borderContour == undefined) {
console.error('BlockPlus.getModelHole: block.blockDetail.borderContour is undefined', block)
return []
}
const org_list = block.blockDetail.borderContour.borderInnerPlace
if (!org_list || org_list.length == 0)
return []
const liset: Curve2d[][] = []
for (const cur of org_list) {
const newCur = this.transformBorder(cur, bu.placeStyle, block.cutWidth, block.cutLength)
if (newCur)
liset.push(newCur)
}
bu.borderInnerPlace = liset
}
return bu.borderInnerPlace
}
/** 获得 板的轮廓多段线(包括内部挖穿) */
static getOrgPloylines(block: PlaceBlock, isPlaced = true, placeStyle?: PlaceStyle) {
const borderPlus = this.getBorder(block, isPlaced, placeStyle)
const innerBorders = this.getBorders_inner(block, isPlaced, placeStyle)
const pl = this.borderToPolyline(borderPlus)
const pls_inner = new Array<Polyline>()
for (const border of innerBorders) {
const npl = this.borderToPolyline(border)
pls_inner.push(npl)
}
return { pl, pls_inner }
}
/** 获得 板的开料多段线(包括内部挖穿) */
static getCutPloylines(block: PlaceBlock, pm: PlaceMaterial, isPlaced = true, placeStyle?: PlaceStyle) {
const borderPlus = this.getCutLines_sameKnife(block, pm, isPlaced, placeStyle)
const innerBorders = this.getCutLines_inner(block, isPlaced, placeStyle)
const pl = this.borderToPolyline(borderPlus)
const pls_inner = new Array<Polyline>()
for (const border of innerBorders) {
const npl = this.borderToPolyline(border)
pls_inner.push(npl)
}
return { pl, pls_inner }
}
/** 获得小板 板外造型轮廓 */
static getOutModelBorders(block: PlaceBlock, isPlaced = true, placeStyle?: PlaceStyle) {
// b1.SaleBlockDetail.borderUnit.polylines_outModel
// b1.SaleBlockDetail.borderUnit.polylines_2vModel
const bu = this.getPlacedUnit(block, isPlaced, placeStyle)
if (bu == null) {
console.error('BlockPlus.getOutModelBorders: 获取板的轮廓集失败', block)
return []
}
if (block.blockDetail == undefined) {
console.error('BlockPlus.getOutModelBorders: block.blockDetail is undefined', block)
return []
}
if (block.blockDetail.borderContour == undefined) {
console.error('BlockPlus.getOutModelBorders: block.blockDetail.borderContour is undefined', block)
return []
}
if (bu.polylinesOutModel == null) {
const polylines_outModel = block.blockDetail.borderContour.polylinesOutModel
const new_outModels: Polyline[] = []
for (const border of polylines_outModel) {
const newBorder = this.transformPolyline(border, bu.placeStyle, block.cutWidth, block.cutLength)
new_outModels.push(newBorder)
}
bu.polylinesOutModel = new_outModels
}
if (bu.polylines2vModel == null) {
const polylines_2vModel = block.blockDetail.borderContour.polylines2vModel
const new_outModels: Polyline[] = []
for (const border of polylines_2vModel) {
const newBorder = this.transformPolyline(border, bu.placeStyle, block.cutWidth, block.cutLength)
new_outModels.push(newBorder)
}
bu.polylines2vModel = new_outModels
}
return bu.polylinesOutModel.concat(bu.polylines2vModel)
}
/** 获得小板外形轮廓 */
static getOrgContour(block: PlaceBlock): any {
if (!block.blockDetail) {
console.error('BlockPlus.getOrgContour: block.blockDetail is undefined', block)
return null
}
if (!block.blockDetail.orgContourData) {
const pts: any = []
const buls: any = []
if (!block.isUnRegular) {
pts.push({ x: 0, y: 0 })
pts.push({ x: block.width, y: 0 })
pts.push({ x: block.width, y: block.length })
pts.push({ x: 0, y: block.length })
buls.push(0)
buls.push(0)
buls.push(0)
buls.push(0)
}
else // 矩形板
{
for (const p of block.blockDetail.orgPoints) {
pts.push({ x: p.pointX, y: p.pointY })
buls.push(p.curve)
}
}
block.blockDetail.orgContourData = { pts, buls }
}
return block.blockDetail.orgContourData
}
/** 获得板的 轮廓集 isPlaced=false为不旋转的 */
private static getPlacedUnit(block: PlaceBlock, isPlaced = true, style?: PlaceStyle): PlaceBorderContour | null {
if (!block.blockDetail) {
console.error('BlockPlus.getPlacedUnit: block.blockDetail is undefined', block)
return null
}
if (block.blockDetail.borderContour == undefined) {
console.error('BlockPlus.getPlacedUnit: block.blockDetail.borderContour is undefined', block)
return null
}
const baseContour = block.blockDetail.borderContour
if (isPlaced == false)
style = PlaceStyle.FRONT
if (isPlaced == true) {
if (style == undefined || style == null)
style = block.placeStyle
}
if (style == undefined) {
style = PlaceStyle.FRONT
}
if (style == PlaceStyle.FRONT)
return baseContour
let placeContour = baseContour.placeContours.find(t => t.placeStyle == style)
if (placeContour == null) {
const border_final = this.transformBorder(baseContour.borderFinal, style, block.width, block.length)
const border_org = this.transformBorder(baseContour.borderOrg, style, block.cutWidth, block.cutLength)
placeContour = new PlaceBorderContour(style, border_final, border_org)
baseContour.placeContours.push(placeContour)
}
return placeContour
}
/**
* 获得板的 轮廓集 isPlaced=false为不旋转的
* @param block
* @param isPlaced
* @param style
* @returns
*/
private static getPlacedUnitNew(block: PlaceBlock, isPlaced = true, style?: PlaceStyle): PlaceBorderContour | null {
if (!block.blockDetail) {
console.error('BlockPlus.getPlacedUnitNew: block.blockDetail is undefined', block)
return null
}
if (block.blockDetail.borderContour == undefined) {
console.error('BlockPlus.getPlacedUnitNew: block.blockDetail.borderContour is undefined', block)
return null
}
const baseContour = block.blockDetail.borderContour
if (isPlaced == false)
style = PlaceStyle.FRONT
if (isPlaced == true) {
if (style == undefined || style == null)
style = block.placeStyle
}
if (style == undefined) {
style = PlaceStyle.FRONT
}
if (style == PlaceStyle.FRONT)
return baseContour
let placeContour = baseContour.placeContours.find(t => t.placeStyle == style)
if (placeContour == null) {
const border_final = this.transformBorderNew(baseContour.borderFinal, style, block.width, block.length)
const border_org = this.transformBorderNew(baseContour.borderOrg, style, block.cutWidth, block.cutLength)
placeContour = new PlaceBorderContour(style, border_final, border_org)
baseContour.placeContours.push(placeContour)
}
return placeContour
}
/** 创建 小板成品轮廓 */
private static createFinalBorder(bd: PlaceBlockDetail, block: PlaceBlock): Curve2d[] {
const orgPoints = bd.orgPoints
const orgBorderCurveList = new Array<Curve2d>()
if (orgPoints && orgPoints.length > 1) // 异形
{
const count = orgPoints.length
for (let i = 0; i < count; i++) {
const p0 = orgPoints[i]
const p1 = i == count - 1 ? orgPoints[0] : orgPoints[i + 1]
const sideHoleCount = bd.holeListSide.filter(t => t.faceId == i).length
if (p0.curve == 0) // 直线
{
const newLine = Line2d.New(p0.pointX, p0.pointY, p1.pointX, p1.pointY)
newLine.tagData = p0.sealSize
newLine.tagData2 = sideHoleCount
orgBorderCurveList.push(newLine)
p0.radius = 0
}
else // 曲线
{
const crc = Arc2d.New(p0.pointX, p0.pointY, p1.pointX, p1.pointY, p0.curve)
crc.tagData = p0.sealSize
crc.tagData2 = sideHoleCount
p0.radius = crc.m_Radius
orgBorderCurveList.push(crc)
}
}
}
else // 矩形板
{
const w = block.width
const l = block.length
const line0 = Line2d.New(0, 0, w, 0)
line0.tagData = block.sealBottom
line0.tagData2 = block.holeCountBottom()
const line1 = Line2d.New(w, 0, w, l)
line1.tagData = block.sealRight
line1.tagData2 = block.holeCountRight()
const line2 = Line2d.New(w, l, 0, l)
line2.tagData = block.sealTop
line2.tagData2 = block.holeCountTop()
const line3 = Line2d.New(0, l, 0, 0)
line3.tagData = block.sealLeft
line3.tagData2 = block.holeCountLeft()
orgBorderCurveList.push(line0)
orgBorderCurveList.push(line1)
orgBorderCurveList.push(line2)
orgBorderCurveList.push(line3)
}
return orgBorderCurveList
}
/** 创建 开料轮廓 */
private static createOrgBorder(bd: PlaceBlockDetail): Curve2d[] {
const borders = new Array<Curve2d>()
if (bd.points && bd.points.length > 1) // 异形
{
const count = bd.points.length
for (let i = 0; i < count - 1; i++) // 异形点(无封边,起点终点 是重复的)
{
const p0 = bd.points[i]
const p1 = i == count - 1 ? bd.points[0] : bd.points[i + 1]
const sideHoleCount = bd.holeListSide.filter(t => t.faceId == i).length
if (p0.curve == 0) // 直线
{
const newLine = Line2d.New(p0.pointX, p0.pointY, p1.pointX, p1.pointY)
newLine.tagData = p0.sealSize
newLine.tagData2 = sideHoleCount
borders.push(newLine)
p0.radius = 0
}
else // 曲线
{
const crc = Arc2d.New(p0.pointX, p0.pointY, p1.pointX, p1.pointY, p0.curve)
crc.tagData = p0.sealSize
crc.tagData2 = sideHoleCount
p0.radius = crc.m_Radius
if (p0.radius < 2) {
p0.curve = 0
p0.radius = 0
}
borders.push(crc)
}
}
}
else // 矩形板
{
const w = bd.cutWidth
const l = bd.cutLength
const line0 = Line2d.New(0, 0, w, 0)
const line1 = Line2d.New(w, 0, w, l)
const line2 = Line2d.New(w, l, 0, l)
const line3 = Line2d.New(0, l, 0, 0)
borders.push(line0)
borders.push(line1)
borders.push(line2)
borders.push(line3)
}
return borders
}
/** 创建预铣轮廓 */
private static creatOrgBorderWithPrevCut(block: PlaceBlock, border: Curve2d[], preSize: number) {
// 矩形板
const newBorders: Curve2d[] = []
const newSizeExpand = new SizeExpand()
if (!block.isUnRegular) {
let x1 = 0
let y1 = 0
let x2 = block.cutWidth
let y2 = block.cutLength
if (block.isUnRegular == false) // 矩形板
{
if (block.sealLeft > 0.001) {
x1 -= preSize
newSizeExpand.left = preSize
}
if (block.sealRight > 0.001) {
x2 += preSize
newSizeExpand.right = preSize
}
if (block.sealBottom > 0.001) {
y1 -= preSize
newSizeExpand.bottom = preSize
}
if (block.sealTop > 0.001) {
y2 += preSize
newSizeExpand.top = preSize
}
}
newBorders.push(Line2d.New(x1, y1, x2, y1))
newBorders.push(Line2d.New(x2, y1, x2, y2))
newBorders.push(Line2d.New(x2, y2, x1, y2))
newBorders.push(Line2d.New(x1, y2, x1, y1))
newSizeExpand.setSize()
return { newBorders, newSizeExpand }
}
// 二。异形板
// 2.1 先分析 每条原始边 是否预铣
if (!block.blockDetail) {
console.error("创建预铣轮廓时block.blockDetail 为空", block);
return;
}
const bd = block.blockDetail
for (let i = 0; i < bd.orgPoints.length; i++) {
let s = i - 1
let j = i + 1
if (s == -1)
s = bd.orgPoints.length - 1
if (j == bd.orgPoints.length)
j = 0
const p0 = bd.orgPoints[s]
const p1 = bd.orgPoints[i]
const p2 = bd.orgPoints[j]
p1.isPreCutRequired = checkYX(p0, p1, p2, block.width, block.length)
}
// 2.1.5 同一边,如果有缺角,则都不能预铣
for (let i = 0; i < bd.orgPoints.length - 1; i++) {
const j = (i + 1) % bd.orgPoints.length
const pi = bd.orgPoints[i]
const pj = bd.orgPoints[j]
// if(pi.needPreCut==false) continue;
// 垂直或平行
let isVertical = equal(pi.pointX, pj.pointX)
if (isVertical == false) {
if (equal(pi.pointY, pj.pointY)) {
isVertical = false
}
else {
continue // 斜线
}
}
for (let m = j; m < bd.orgPoints.length; m++) {
const n = (m + 1) % bd.orgPoints.length
const pm = bd.orgPoints[m]
const pn = bd.orgPoints[n]
// 垂直 ,同边 有缝隙,多段线 ,不能预铣
if (isVertical && equal(pi.pointX, pm.pointX) && equal(pi.pointX, pn.pointX)) {
pi.isPreCutRequired = false
pm.isPreCutRequired = false
}
// 水平 ,同边 有缝隙,多段线 ,不能预铣
if (isVertical == false && equal(pi.pointY, pm.pointY) && equal(pi.pointY, pn.pointY)) {
pi.isPreCutRequired = false
pm.isPreCutRequired = false
}
}
}
// 2.2 生成预铣轮廓
for (let i = 0; i < border.length; i++) {
const cur = border[i]
let newCur: Curve2d
if (cur instanceof Arc2d) {
newCur = new Arc2d(cur.StartPoint, cur.EndPoint, cur.Bul)
}
else {
newCur = new Line2d(cur.StartPoint, cur.EndPoint)
}
if ((newCur instanceof Line2d) && newCur.m_Length < 0.001)
continue
// 曲线肯定不能偏移,
// 直线的话,需要跟 板原始轮廓边 比对确定是否需要偏移
const curNeedOff = preSize > 0 && needPrev(cur)
if (curNeedOff) {
// 偏移
const line = cur as Line2d
newCur = line.Offset(preSize)
}
// 判断前一条边的终点是否 != 当前边的起点,需要加一条连接线
if (newBorders.length > 0) {
const pLast = newBorders[newBorders.length - 1]
if (equal2Point(pLast.EndPoint, newCur.StartPoint) == false) {
let hasJD = false
if ((pLast instanceof Line2d) && (newCur instanceof Line2d)) {
const p_jds: Point2d[] = []
newCur.IntersectWith(pLast, p_jds)
if (p_jds.length == 1) {
pLast.EndPoint = new Point2d(p_jds[0].m_X, p_jds[0].m_Y)
newCur.StartPoint = new Point2d(p_jds[0].m_X, p_jds[0].m_Y)
hasJD = true
}
}
if (hasJD == false) // 直接连接
{
const linkLine = new Line2d(pLast.EndPoint, newCur.StartPoint)
newBorders.push(linkLine)
}
}
}
// 插入新的边
newBorders.push(newCur)
}
// 2.3 闭合 最后一边 ,是否与 第一条边 连接
const firstB = newBorders[0]
const lastB = newBorders[newBorders.length - 1]
if (equal2Point(lastB.EndPoint, firstB.StartPoint) == false) {
// 如果前后都是直线则求交点, 直接延长直线
let hasJD = false
if ((firstB instanceof Line2d) && (lastB instanceof Line2d)) {
const p_jds: Point2d[] = []
lastB.IntersectWith(firstB, p_jds)
if (p_jds.length == 1) {
lastB.EndPoint = new Point2d(p_jds[0].m_X, p_jds[0].m_Y)
firstB.StartPoint = new Point2d(p_jds[0].m_X, p_jds[0].m_Y)
hasJD = true
}
}
if (hasJD == false) // 直接连接
{
const linkLine = new Line2d(lastB.EndPoint, firstB.StartPoint)
newBorders.push(linkLine)
}
}
// 2.4 生成外扩
let xz = 0; let xy = block.cutWidth; let yx = 0; let ys = block.cutLength
for (const cur of newBorders) {
const p = cur.StartPoint
if (p.m_X < xz)
xz = p.m_X
if (p.m_X > xy)
xy = p.m_X
if (p.m_Y < yx)
yx = p.m_Y
if (p.m_Y > ys)
ys = p.m_Y
}
newSizeExpand.left = -xz
newSizeExpand.right = xy - block.cutWidth
newSizeExpand.bottom = -yx
newSizeExpand.top = ys - block.cutLength
newSizeExpand.setSize()
return { newBorders, newSizeExpand }
// 判断外轮廓点p1是否需要预铣
function checkYX(p0, p1, p2, width, length) {
if (p1.curve != 0)
return false // 本身是圆弧
if (p1.sealSize < 0.001)
return false// 本身不封边
if (p0.curve != 0)
return false // 前一段是圆弧
if (p2.curve != 0)
return false// 后一段是圆弧
// p1.p2 只要有一点在板内,就不行
const isIn1 = (p1.pointX > 0.001 && p1.pointX < width - 0.001 && p1.pointY > 0.001 && p1.pointY < length - 0.001)
if (isIn1)
return false
const isIn2 = (p2.pointX > 0.001 && p2.pointX < width - 0.001 && p2.pointY > 0.001 && p2.pointY < length - 0.001)
if (isIn2)
return false
return true // 需要预洗
}
// 判断边是否预铣
function needPrev(line: Curve2d) {
if (!block.blockDetail) {
console.error("判断边是否预铣时block.blockDetail 为空", block);
return false;
}
if (!(line instanceof Line2d))
return false
if (block.isUnRegular == false) // 矩形
{
if (line.StartPoint.m_Y == 0 && line.EndPoint.m_Y == 0)
return block.sealBottom > 0
if (line.StartPoint.m_X == block.cutWidth && line.EndPoint.m_X == block.cutWidth)
return block.sealRight > 0
if (line.StartPoint.m_Y == block.cutLength && line.EndPoint.m_Y == block.cutLength)
return block.sealTop > 0
if (line.StartPoint.m_X == 0 && line.EndPoint.m_X == 0)
return block.sealLeft > 0
return false
}
const offx = block.blockDetail.offsetX
const offy = block.blockDetail.offsetY
const x1 = line.StartPoint.m_X
const y1 = line.StartPoint.m_Y
const x2 = line.EndPoint.m_X
const y2 = line.EndPoint.m_Y
const tag0 = (x2 - x1) / getDis(x1, y1, x2, y2)
// 找出原始轮廓中 对应的边 , 是否有 预洗信息
for (let i = 0; i < block.orgPoints.length; i++) {
let j = i + 1
if (j == block.orgPoints.length)
j = 0
if (block.orgPoints[i].isPreCutRequired == false)
continue
const tag1 = (block.orgPoints[j].pointX - block.orgPoints[i].pointX) / getDis(block.orgPoints[i].pointX, block.orgPoints[i].pointY, block.orgPoints[j].pointX, block.orgPoints[j].pointY)
if (equal(tag0, tag1, 0.1) == false)
continue // 不平行
const dis = getDis_PointLine(x1, y1, x2, y2, block.orgPoints[i].pointX - offx, block.orgPoints[i].pointY - offy)
if (dis < block.orgPoints[i].sealSize * 2 + 3)
return true
}
return false
}
function equal2Point(p1, p2, dis = 0.001) {
const x1 = p1.m_X
const y1 = p1.m_Y
const x2 = p2.m_X
const y2 = p2.m_Y
const len1 = (x1 - x2) * (x1 - x2)
const len2 = (y1 - y2) * (y1 - y2)
const len = Math.sqrt(len2 + len1)
return len < dis
}
}
/** 创建 挖穿造型,走刀路径,板内空间 */
private static analyeInners(bd: PlaceBlockDetail, cutR, cutGap = 1) {
/** 挖穿轮廓 */
const borders_inner_org: Curve2d[][] = []
/** 挖穿轮廓 刀半径 */
const borders_inner_r: number[] = []
/** 挖穿走刀路径 */
const borders_inner_cut: Curve2d[][] = []
/** 挖穿排版轮廓 <加缝隙> */
const borders_inner_place: Curve2d[][] = []
/** 排版空间 */
const spaces: PlaceSpace[] = []
for (const m of bd.models) {
if (m.depth < bd.thickness - 0.01)
continue // 非挖穿
if (m.isVKnifeModel())
continue // 挖穿的二维刀路造型 不计算.
if (m.isCutting == false)
continue // 不加工
// 挖穿轮廓 <切割后的>,顺时针的
let baseBorder
if (m.hasContour()) // 有轮廓数据
{
let ptsArr = m.originModeling.outline.map(e => e.pts)
const pts = ptsArr.map((t) => { return { x: t.x, y: t.y } })
for (let i = 0; i < pts.length; i++) {
pts[i].bul = m.originModeling.outline[i].buls
}
baseBorder = this.createBorderByPts(pts)
}
else // 没有轮廓数据,用走刀路径 偏移
{
const pts = m.pointList.map((t) => { return { x: t.pointX, y: t.pointY, bul: t.curve } })
baseBorder = this.createBorderByPts(pts)
baseBorder = this.offsetCurves(baseBorder, m.knifeRadius, false)
}
// 铣刀路径
const border_cut = this.offsetCurves(baseBorder, -m.realKnifeRadius, false)
// 排版轮廓
const placeGap = Math.max(m.realKnifeRadius, cutR) * 2 - cutR + cutGap / 2 // 取造型刀,开料刀 最大的
const border_place = this.offsetCurves(baseBorder, -placeGap, false)
borders_inner_org.push(baseBorder)
borders_inner_r.push(m.realKnifeRadius)
borders_inner_cut.push(border_cut)
borders_inner_place.push(border_place)
// 内部空间
let createdSpaces = false
if (m.hasContour()) // 简单形状,直接生成矩形,圆形
{
// 是否矩形,圆形
const rect = isRect(m.originModeling.outline) || isCircle(m.originModeling.outline)
if (rect) {
const gap = placeGap
rect.x += gap
rect.y += gap
rect.w -= gap * 2
rect.l -= gap * 2
if (rect.w > 100 && rect.l > 100) {
const space = new PlaceSpace(rect.x, rect.y, rect.w, rect.l)
space.isBlockInnerSpace = true
spaces.push(space)
}
createdSpaces = true
}
}
if (createdSpaces == false) // 复杂形状
{
const tmpSpaces = SpacePlus.borderToSpace(border_place)
if (tmpSpaces) {
tmpSpaces.forEach(t => t.isBlockInnerSpace = true)
tmpSpaces.forEach(t => spaces.push(t))
}
}
}
return { borders_inner_org, borders_inner_r, borders_inner_cut, borders_inner_place, spaces }
function isRect(outline: any): any {
const pts = outline.map(e => e.pts) //outline.pts
const buls = outline.map(e => e.buls) // outline.buls
if (buls.length != 5)
return null
if (buls.some(t => t != 0))
return null
if (pts.length != 5)
return null
if (pts[4].x != pts[0].x || pts[4].y != pts[0].y)
return null
return getRect(pts[0], pts[1], pts[2], pts[3])
}
function isCircle(outline: any): any {
// const pts = outline.pts
// const buls = outline.buls
const pts = outline.map(e => e.pts) //outline.pts
const buls = outline.map(e => e.buls) // outline.buls
if (buls.length != 3)
return null
if (equal(buls[0], 1) && equal(buls[1], 1) && equal(buls[2], 0)) {
const p0 = Array.isArray(outline) ? outline[0].pts : outline?.pts[0]
const p1 = Array.isArray(outline) ? outline[1].pts : outline?.pts[1]
let x0 = Math.min(p0.x, p1.x)
let x1 = Math.max(p0.x, p1.x)
let y0 = Math.min(p0.y, p1.y)
let y1 = Math.max(p0.y, p1.y)
let r
if (equal(x0, x1)) {
r = (y1 - y0) / 2
x0 -= r
x1 += r
}
else {
r = (x1 - x0) / 2
y0 -= r
y1 += r
}
const t = r / Math.SQRT2
const dis = r - t
return { x: x0 + dis, y: y0 + dis, w: t * 2, l: t * 2 }
}
}
}
/** 创建 缺角空间 */
private static createOutSpaces(block: PlaceBlock, placeMaterial: PlaceMaterial): PlaceSpace[] {
if (block.blockDetail == undefined) {
console.error("创建缺角空间时block.blockDetail 为空", block);
return [];
}
if (block.blockDetail.borderContour == null) {
console.error("创建缺角空间时block.blockDetail.borderContour 为空", block);
return [];
}
if (block.isUnRegular == false && (block.blockDetail.borderContour.polylines2vModel.length + block.blockDetail.borderContour.polylinesOutModel.length == 0))
return [] // 矩形
const pm = placeMaterial
let border = this.getBorder_WZYH(block, placeMaterial, false) // 获得全偏移的轮廓
const pl = this.borderToPolyline(border, true)
/** 空间 */
let spaces: PlaceSpace[] = []
const reg = { z: 0, x: 0, y: 0, s: 0, w: 0, l: 0 } // 外围空间 左右上下 ,宽长
reg.z = pl.BoundingBox.min.x
reg.x = pl.BoundingBox.min.y
reg.y = pl.BoundingBox.max.x
reg.s = pl.BoundingBox.max.y
reg.w = -reg.z + reg.y
reg.l = -reg.x + reg.s
const checkSize = new SizeExpand() // 空间验证
checkSize.left = -block.sizeExpand()?.left - (pm.diameter + pm.cutKnifeGap) / 2
checkSize.right = block.cutWidth + block.sizeExpand()?.right + (pm.diameter + pm.cutKnifeGap) / 2
checkSize.bottom = -block.sizeExpand()?.bottom - (pm.diameter + pm.cutKnifeGap) / 2
checkSize.top = block.cutLength + block.sizeExpand()?.top + (pm.diameter + pm.cutKnifeGap) / 2
const offDis = pm.preMillingSize + 0.01 // 点判断是否在边缘 误差 一个预铣值
border = border.slice(0)
// 确保 第一条 起点在边缘
let count = 0 // 移动不能大于一个循环,避免死循环
while (count < border.length) {
const line0 = border[0]
const isOnBorder = onBorder(line0.StartPoint)
if (isOnBorder)
break
// 如果起点在板内,移动到最后面
border.shift()
border.push(line0)
count++
}
SpacePlus.setSpaceStyle(block)
let lines: Curve2d[] = [] //
for (let i = 0; i < border.length; i++) {
const line = border[i]
const spOnBorder = onBorder(line.StartPoint)
const epOnBorder = onBorder(line.EndPoint)
const isxl = isXL(line)
if (spOnBorder && (!epOnBorder || isxl)) // 起始线
{
lines = []
lines.push(line)
}
if (!spOnBorder && !epOnBorder) // 板内线
{
if (lines && lines.length > 0 && lines[lines.length - 1] != line)
lines.push(line)
}
if (epOnBorder && (!spOnBorder || isxl)) // 结束线,开始分析空间
{
if (lines && lines.length > 0) {
if (lines[lines.length - 1] != line)
lines.push(line)
const newspaces = createSpace(lines)
if (newspaces && newspaces.length > 0)
spaces = spaces.concat(newspaces)
lines = []
}
}
}
const newSpaces: PlaceSpace[] = []
// 空间验证
for (const space of spaces) {
let x1 = space.x
let y1 = space.y
let x2 = space.topX()
let y2 = space.topY()
if (x1 < checkSize.left)
x1 = checkSize.left
if (y1 < checkSize.bottom)
y1 = checkSize.bottom
if (x2 > checkSize.right)
x2 = checkSize.right
if (y2 > checkSize.top)
y2 = checkSize.top
const newspace = PlaceSpace.create(x1, y1, x2, y2)
newSpaces.push(newspace)
}
return newSpaces
/** 缺角的开始? 起点在边缘,终点在板内的 或 斜线 (终点在另外一边) */
function isBegin(curve: Curve2d) { return onBorder(curve.StartPoint) && (!onBorder(curve.EndPoint) || isXL(curve)) }
/** 缺角的结束? 终点在边缘的 起点在板内 或 (起点点在另外一边) */
function isEnd(curve: Curve2d) { return onBorder(curve.EndPoint) && (!onBorder(curve.StartPoint) || isXL(curve)) }
/** 在板内 */
function inBorder(curve: Curve2d) { return !onBorder(curve.StartPoint) && !onBorder(curve.EndPoint) }
/** 点是否在边缘 */
function onBorder(p: Point2d) { return equal(p.m_X, reg.z, offDis) || equal(p.m_X, reg.y, offDis) || equal(p.m_Y, reg.s, offDis) || equal(p.m_Y, reg.x, offDis) }
/** 斜线 */
function isXL(line: Curve2d) { return !equal(line.StartPoint.m_X, line.EndPoint.m_X) && !equal(line.StartPoint.m_Y, line.EndPoint.m_Y) }
/** 线是边缘 */
function isBorderLine(line: Line2d) { return !isXL(line) && onBorder(line.StartPoint) && onBorder(line.EndPoint) }
/** 分析空间 */
function createSpace(curves: Curve2d[]): PlaceSpace[] {
if (curves.length == 0)
return []
// 1.补边,闭合轮廓
const sp = curves[0].StartPoint
const ep = curves[curves.length - 1].EndPoint
const pushPts: Point2d[] = []
pushPts.push(ep)
const sb = getEdge(sp) // 起点的边
const eb = getEdge(ep) // 终点的边
if (sb == -1 || eb == -1)
return []// 不在边上
// 在同一边 的缺角
if (sb == eb) {
if (equal(sp.m_X, ep.m_X, offDis) && sp.m_X != ep.m_X) // 消除误差
{
let x = Math.max(sp.m_X, ep.m_X)
if (sp.m_X > block.width / 2)
x = Math.min(sp.m_X, ep.m_X)
sp.m_X = x
ep.m_X = x
}
if (equal(sp.m_Y, ep.m_Y, offDis) && sp.m_Y != ep.m_Y) // 消除误差
{
let y = Math.max(sp.m_Y, ep.m_Y)
if (sp.m_Y > block.length / 2)
y = Math.min(sp.m_Y, ep.m_Y)
sp.m_Y = y
ep.m_Y = y
}
}
// 右下角
else if (sb == 0 && eb == 1) {
const cp = new Point2d(ep.m_X, sp.m_Y)
pushPts.push(cp)
}
// 右上角
else if (sb == 1 && eb == 2) {
const cp = new Point2d(sp.m_X, ep.m_Y)
pushPts.push(cp)
}
// 左上角
else if (sb == 2 && eb == 3) {
const cp = new Point2d(ep.m_X, sp.m_Y)
pushPts.push(cp)
}
// 左下角
else if (sb == 3 && eb == 0) {
const cp = new Point2d(sp.m_X, ep.m_Y)
pushPts.push(cp)
}
// 起点下边 -> 终点上边 //因为倒角
else if (sb == 0 && eb == 2) {
const cp1 = new Point2d(reg.y, ep.m_Y)
const cp2 = new Point2d(reg.y, sp.m_Y)
pushPts.push(cp1)
pushPts.push(cp2)
}
// 起点右边 -> 终点左边
else if (sb == 1 && eb == 3) {
const cp1 = new Point2d(ep.m_X, reg.s)
const cp2 = new Point2d(sp.m_X, reg.s)
pushPts.push(cp1)
pushPts.push(cp2)
}
// 起点上边 -> 终点下边
else if (sb == 2 && eb == 0) {
const cp1 = new Point2d(reg.z, ep.m_Y)
const cp2 = new Point2d(reg.z, sp.m_Y)
pushPts.push(cp1)
pushPts.push(cp2)
}
// 起点左边 -> 终点右边
else if (sb == 3 && eb == 1) {
const cp1 = new Point2d(ep.m_X, reg.x)
const cp2 = new Point2d(sp.m_X, reg.x)
pushPts.push(cp1)
pushPts.push(cp2)
}
// 起点下边 -> 终点左边
else if (sb == 0 && eb == 3) {
const cp1 = new Point2d(reg.z, reg.s)
const cp2 = new Point2d(reg.y, reg.s)
const cp3 = new Point2d(reg.y, reg.x)
pushPts.push(cp1)
pushPts.push(cp2)
pushPts.push(cp3)
}
// 起点右边 -> 终点下边
else if (sb == 1 && eb == 0) {
const cp1 = new Point2d(reg.z, reg.x)
const cp2 = new Point2d(reg.z, reg.s)
const cp3 = new Point2d(reg.y, reg.s)
pushPts.push(cp1)
pushPts.push(cp2)
pushPts.push(cp3)
}
// 起点上 -> 终点右边
else if (sb == 2 && eb == 1) {
const cp1 = new Point2d(reg.y, reg.x)
const cp2 = new Point2d(reg.z, reg.x)
const cp3 = new Point2d(reg.z, reg.s)
pushPts.push(cp1)
pushPts.push(cp2)
pushPts.push(cp3)
}
// 起点左 -> 终点上边
else if (sb == 3 && eb == 2) {
const cp1 = new Point2d(reg.y, reg.s)
const cp2 = new Point2d(reg.y, reg.x)
const cp3 = new Point2d(reg.z, reg.x)
pushPts.push(cp1)
pushPts.push(cp2)
pushPts.push(cp3)
}
else // 判断不了 缺口 的起点终点 范围
{
return []
}
pushPts.push(sp)
for (let i = 0; i < pushPts.length - 1; i++) // 闭合缺口
{
const newLine = new Line2d(pushPts[i], pushPts[i + 1])
curves.push(newLine)
}
// 3 目前轮廓顺时针,必须转成 逆时针
curves = SpacePlus.reverseCurves(curves)
// 4. 分析空间 analyeSpace
const tmpSpaces = SpacePlus.borderToSpace(curves) || []
return tmpSpaces
}
/** 获得点所在的边 getB */
function getEdge(sp) {
if (equal(sp.m_Y, reg.x, offDis))
return 0
if (equal(sp.m_X, reg.y, offDis))
return 1
if (equal(sp.m_Y, reg.s, offDis))
return 2
if (equal(sp.m_X, reg.z, offDis))
return 3
return -1
}
/** 设置方向 */
function setDirect(line: Line2d) {
let fx = -1 // 向右 0,向上 1向左 2向下 3 ,右上 4,左上5,左下6右下 7
if (line.EndPoint.m_X > line.StartPoint.m_X && equal(line.EndPoint.m_Y, line.StartPoint.m_Y)) {
fx = 0
}
else if (line.EndPoint.m_X < line.StartPoint.m_X && equal(line.EndPoint.m_Y, line.StartPoint.m_Y)) {
fx = 2
}
else if (line.EndPoint.m_Y > line.StartPoint.m_Y && equal(line.EndPoint.m_X, line.StartPoint.m_X)) {
fx = 1
}
else if (line.EndPoint.m_Y < line.StartPoint.m_Y && equal(line.EndPoint.m_X, line.StartPoint.m_X)) {
fx = 3
}
else if (line.EndPoint.m_X > line.StartPoint.m_X && line.EndPoint.m_Y > line.StartPoint.m_Y) {
fx = 4
}
else if (line.EndPoint.m_X < line.StartPoint.m_X && line.EndPoint.m_Y > line.StartPoint.m_Y) {
fx = 5
}
else if (line.EndPoint.m_X < line.StartPoint.m_X && line.EndPoint.m_Y < line.StartPoint.m_Y) {
fx = 6
}
else if (line.EndPoint.m_X > line.StartPoint.m_X && line.EndPoint.m_Y < line.StartPoint.m_Y) {
fx = 7
}
line.fx = fx
return fx > -1
}
}
/** 创建 普通造型外扩的 多段线 */
public static createPolyline_model(block: PlaceBlock) {
if (!block.blockDetail) {
console.warn("PlaceBlock没有blockDetail无法创建造型轮廓")
return { pls_model: [], sizeout: new SizeExpand() }
}
const pl_block = this.getOrgPolyline(block)
const pls_model: Polyline[] = []
for (const model of block.blockDetail.models) {
if (model.originModeling == undefined) {
continue
}
let _pts: any[] = []
let _buls: any[] = []
if (Array.isArray(model.originModeling.outline)) {
_pts = model.originModeling.outline.map(e => e.pts)
_buls = model.originModeling.outline.map(e => e.buls)
} else {
_pts = model.originModeling.outline.pts
_buls = model.originModeling.outline.buls
}
if (model.isCutting == false)
continue
if (model.isVKnifeModel())
continue
if (model.depth > block.thickness - 0.01)
continue
if (model.pointList.length < 2)
continue
if (model.hasContour() == false)
continue
if (model.originModeling == null)
continue
if (model.originModeling.outline == null)
continue
if (!Array.isArray(_pts))
continue
if (_pts.length < 1)
continue
if (model.knifeRadius < 0.001)
continue
const pl_model = PolylineHelper.createByPts(_pts, _buls, true)
const pl_off = pl_model.GetOffsetCurves(model.knifeRadius)[0]
if (pl_off == null)
continue
if (pl_block.IntersectWith(pl_off, 0).length == 0)
continue // 造型轮廓偏移一个刀半径 ,没有与板轮廓相交
// 有可能超出板外
const pts: any[] = []
const p0 = model.pointList[0]
let isClose = false
for (let i = 0; i < model.pointList.length; i++) {
const p = model.pointList[i]
if (i == 0) {
pts.push({ x: p.pointX, y: p.pointY, bul: p.curve })
continue
}
const pp = pts[pts.length - 1]
if (getDis2(pp, p) < 0.1)
pts.pop() // 与前一点,接近去掉前一点,避免重合
pts.push({ x: p.pointX, y: p.pointY, bul: p.curve })
if (i == model.pointList.length - 1)
break // 完成了
isClose = getDis2(p0, p) < 0.1
if (isClose) // 闭环且后面的点都在环内,那后面的点就不需要考虑了
{
const pl = PolylineHelper.create(pts, true)
let isAllIn = true
for (let j = i + 1; j < model.pointList.length; j++) {
const pn = model.pointList[j]
isAllIn = pl.PtInCurve(new Vector3(pn.pointX, pn.pointY, 0))
if (isAllIn == false)
break
}
if (isAllIn)
break
}
}
try {
this.createModelPLS(pl_block, pls_model, pts, model.knifeRadius)
}
catch {
continue
}
}
// 计算外扩偏移
let xz = 0; let xy = block.cutWidth; let yx = 0; let ys = block.cutLength
for (const pl of pls_model) {
if (pl.BoundingBox.min.x < xz)
xz = pl.BoundingBox.min.x
if (pl.BoundingBox.min.y < yx)
yx = pl.BoundingBox.min.y
if (pl.BoundingBox.max.x > xy)
xy = pl.BoundingBox.max.x
if (pl.BoundingBox.max.y > ys)
ys = pl.BoundingBox.max.y
}
const sizeout_model = new SizeExpand()
if (xz < 0)
sizeout_model.left = -xz
if (xy > block.cutWidth)
sizeout_model.right = xy - block.cutWidth
if (yx < 0)
sizeout_model.bottom = -yx
if (ys > block.cutLength)
sizeout_model.top = ys - block.cutLength
sizeout_model.setSize()
return { pls_model, sizeout: sizeout_model }
}
/** 创建 2v板外下刀的 多段线 */
private static createPolyline_2vModel(block: PlaceBlock) {
if (!block.blockDetail) {
console.warn("PlaceBlock没有blockDetail无法创建造型轮廓")
return { pls_model: [], sizeout: new SizeExpand() }
}
const pls_2v: Polyline[] = []
for (const model of block.blockDetail.models) {
if (model.isVKnifeModel() == false)
continue
if (model.isCutting == false)
continue
// if(model.depth > block.thickness - 0.01) continue;
const pl_block = this.getOrgPolyline(block)
for (const vline of model.VLines) { // knifeRadius 刀半径, depth深度, points{x,y,z,bul,r}
const r = vline.knifeRadius
if (r < 0.001)
continue
const pts = vline.points.map((t) => { return { x: t.x, y: t.y, bul: t.bul } })
try {
this.createModelPLS(pl_block, pls_2v, pts, r, true)
}
catch {
continue
}
}
}
// 计算外扩偏移
let xz = 0; let xy = block.cutWidth; let yx = 0; let ys = block.cutLength
for (const pl of pls_2v) {
if (pl.BoundingBox.min.x < xz)
xz = pl.BoundingBox.min.x
if (pl.BoundingBox.min.y < yx)
yx = pl.BoundingBox.min.y
if (pl.BoundingBox.max.x > xy)
xy = pl.BoundingBox.max.x
if (pl.BoundingBox.max.y > ys)
ys = pl.BoundingBox.max.y
}
const sizeout_2v = new SizeExpand()
if (xz < 0)
sizeout_2v.left = -xz
if (xy > block.cutWidth)
sizeout_2v.right = xy - block.cutWidth
if (yx < 0)
sizeout_2v.bottom = -yx
if (ys > block.cutLength)
sizeout_2v.top = ys - block.cutLength
sizeout_2v.setSize()
return { pls_2v, sizeout_2v }
}
/**
* 创建超出板外的造型轮廓
*
*/
private static createModelPLS(pl_block: Polyline, pls_model: Polyline[], points: any[], r: number, is2V = false) {
const lines: any = []
// 23.10.9 发现普通造型还是有自交的线段,强制 分段处理
for (let i = 0; i < points.length - 1; i++) {
const j = i + 1
const p1 = { x: points[i].x, y: points[i].y, bul: points[i].bul }
const p2 = { x: points[j].x, y: points[j].y, bul: 0 }
lines.push([p1, p2])
}
// 对 每段line 进行 偏移多半径,获取闭合多段线
const pls: Polyline[] = []
for (const pts of lines) {
// 1. pts 不闭合偏移0.5
// 原路回来,组合成闭合线
const l = pts.length - 1
pts[l].bul = 0 // 确保最后一点 是直线点
const isclose = equal(pts[0].x, pts[l].x) && equal(pts[0].y, pts[l].y)
if (isclose == false) //
{
const pl_0 = PolylineHelper.create(pts, false)
const pl_1s = pl_0.GetOffsetCurves(0.5)
let pl_1 = pl_1s[0]
if (pl_1 == null)
continue
pl_1 = pl_1.Reverse()
for (const p of pl_1.LineData) {
pts.push({ x: p.pt.x, y: p.pt.y, bul: p.bul })
}
}
// 2 偏移刀r后的 轮廓
let pl_vline = PolylineHelper.create(pts, true)
if (pl_vline.IsClockWise)
pl_vline = pl_vline.Reverse()
const pl_off = pl_vline.GetOffsetCurves(r)[0]
if (pl_off == null)
continue
// if(pl_off.CloseMark == false) ;
pls.push(pl_off)
}
if (pls.length == 0)
return
// 对 多段线进行 合并,获得最后 造型轮廓
let pl: Polyline | undefined = pls.shift()
if (pl == undefined || pl == null) {
console.warn("创建造型轮廓失败pls数组为空")
return
}
if (pls.length > 0) {
pl = this.unionPolylines(pl, pls)
}
// 3 造型轮廓 与 板轮廓干涉
if (pl_block.IntersectWith(pl, 0).length > 0) {
pls_model.push(pl)
}
// 4 2V 轮廓 可能包含了 板轮廓
if (pl.BoundingBox.min.x <= pl_block.BoundingBox.min.x
&& pl.BoundingBox.min.y <= pl_block.BoundingBox.min.y
&& pl.BoundingBox.max.x >= pl_block.BoundingBox.max.x
&& pl.BoundingBox.max.y >= pl_block.BoundingBox.max.y) {
pls_model.push(pl)
}
}
/** 创建 点阵pts ,在 板边缘 干涉到的 区域 */
private static createInterPLS(pl_block: Polyline, pts: any[], r: number, pls_model: Polyline[]) {
const pl_vline = PolylineHelper.create(pts)
let curves
curves = pl_vline.Explode() // 分解成 一段 一段的
const outlines: any = [] // 当前在板外的线段
for (let i = 0; i < curves.length;) // 判断 有没有交集
{
const curve = curves[i]
const pos = getRelation(pl_block, curve, r)
if (pos[0] == -1) {
if (outlines.length > 0)
createPL_outLines(outlines, pls_model, r)
}
else if (pos[0] == 0 || pos[0] == 1) // 板外,或交接
{
outlines.push(curve)
}
else // 多个连接点 。,要拆分 多段,处理
{
const childs = curve.GetSplitCurves(0.2)
curves.splice(i, 1)
for (let j = childs.length - 1; j >= 0; j--) {
const child = childs[j]
curves.splice(i, 0, child)
}
continue
}
i++
}
// 最后一条线段可能是板外,那就要补 板外线段生成
if (outlines.length > 0)
createPL_outLines(outlines, pls_model, r)
/** 判断 line 与 polyline 的关系 -1 板内0 板外 ,> 0 相交点数 */
function getRelation(pl_block, curve, r) {
const xjd = pl_block.IntersectWith(curve, 0)
if (xjd.length > 0)
return [xjd.length, xjd] // 相交点
// line 的 4 个点
const box = curve.BoundingBox
const x0 = box.min.x - r
const y0 = box.min.y - r
const x1 = box.max.x + r
const y1 = box.max.y + r
const p0 = pl_block.PtInCurve(new Vector3(x0, y0))
const p1 = pl_block.PtInCurve(new Vector3(x1, y0))
const p2 = pl_block.PtInCurve(new Vector3(x1, y1))
const p3 = pl_block.PtInCurve(new Vector3(x0, y1))
if (p0 && p1 && p2 && p3)
return [-1, []] // 板内
if (!p0 && !p1 && !p2 && !p3)
return [0, []] // 板外
return [0, []]
}
function createPL(x0, y0, x1, y1) {
const pts: any[] = []
pts.push({ x: x0, y: y0 })
pts.push({ x: x1, y: y0 })
pts.push({ x: x1, y: y1 })
pts.push({ x: x0, y: y1 })
const pl_line = PolylineHelper.create(pts, true)
return pl_line
}
function createPL_outLines(outlines, pls_model, r) {
let xz = 28000; let xy = -100000; let yx = 2900000; let ys = -100000
for (const curve of outlines) {
const box = curve.BoundingBox
const x0 = box.min.x - r - 1
const y0 = box.min.y - r - 1
const x1 = box.max.x + r + 1
const y1 = box.max.y + r + 1
if (x0 < xz)
xz = x0
if (x1 > xy)
xy = x1
if (y0 < yx)
yx = y0
if (y1 > ys)
ys = y1
}
const pl_line = createPL(xz, yx, xy, ys)
pls_model.push(pl_line)
outlines.splice(0) // 清空,可能下面 还有 板外的线段
}
}
/** 创建 轮廓 pts : {x,y,bul}[] */
static createBorderByPts(pts: any[]): Curve2d[] {
const borders: Curve2d[] = []
for (let i = 0; i < pts.length; i++) {
let j = i + 1
if (j == pts.length)
j = 0
const pi = pts[i]
const pj = pts[j]
if (pi.bul == 0) {
const line = new Line2d(new Point2d(pi.x, pi.y), new Point2d(pj.x, pj.y))
borders.push(line)
}
else {
const arc = new Arc2d(new Point2d(pi.x, pi.y), new Point2d(pj.x, pj.y), pi.bul)
borders.push(arc)
}
}
return borders
}
/** 翻转 多线段 */
static transformBorder(borders: Curve2d[], placeStyle: PlaceStyle, width: number, length: number, blockNo?: any): Curve2d[] {
// console.log('翻转 多线段')
const newBorders: Curve2d[] = []
for (let i = 0; i < borders.length; i++) {
const border = borders[i]
const np1 = getPlacePosition(border.StartPoint.m_X, border.StartPoint.m_Y, width, length, placeStyle)
const np2 = getPlacePosition(border.EndPoint.m_X, border.EndPoint.m_Y, width, length, placeStyle)
let p1 = new Point2d(np1.x, np1.y)
let p2 = new Point2d(np2.x, np2.y)
if (placeStyle >= 4)
[p1, p2] = [p2, p1]
let newBorder
if (border instanceof Arc2d) {
newBorder = new Arc2d(p1, p2, border.Bul)
}
else {
newBorder = new Line2d(p1, p2)
}
if (border.tagData != undefined || border.tagData != null) {
newBorder.tagData = border.tagData
newBorder.tagData2 = border.tagData2
}
newBorders.push(newBorder)
}
if (placeStyle >= 4)
newBorders.reverse()
return newBorders
}
/** 翻转 多线段 */
static transformBorderNew(borders: Curve2d[], placeStyle: PlaceStyle, width: number, length: number): Curve2d[] {
const newBorders: Curve2d[] = []
for (let i = 0; i < borders.length; i++) {
const border = borders[i]
const np1 = getPlacePosition(border.StartPoint.m_X, border.StartPoint.m_Y, width, length, placeStyle)
const np2 = getPlacePosition(border.EndPoint.m_X, border.EndPoint.m_Y, width, length, placeStyle)
let p1 = new Point2d(np1.x, np1.y)
let p2 = new Point2d(np2.x, np2.y)
if (placeStyle >= 4)
[p1, p2] = [p2, p1]
let newBorder
if (border instanceof Arc2d) {
newBorder = new Arc2d(p1, p2, border.Bul)
}
else {
newBorder = new Line2d(p1, p2)
}
if (border.tagData != undefined || border.tagData != null) {
newBorder.tagData = border.tagData
newBorder.tagData2 = border.tagData2
}
newBorders.push(newBorder)
}
if (placeStyle >= 4)
newBorders.reverse()
return newBorders
}
/** 翻转 多段线 */
static transformPolyline(pl: Polyline, placeStyle: PlaceStyle, width: number, length: number): Polyline {
const bx = pl.Position.x
const by = pl.Position.y
let pts = pl.LineData.map((t) => { return { x: t.pt.x, y: t.pt.y, bul: t.bul } })
pts.forEach((t) => { t.x += bx; t.y += by })
// 翻面,翻转点阵
if (placeStyle > 3) {
const newPts: any[] = []
for (let j = pts.length - 1; j >= 0; j--) {
let i = j - 1
if (i < 0)
i = pts.length - 1
const x = pts[j].x
const y = pts[j].y
const bul = pts[i].bul
newPts.push({ x, y, bul })
}
pts = newPts
}
// 转换坐标
for (let i = 0; i < pts.length; i++) {
const p = pts[i]
const np = getPlacePosition(p.x, p.y, width, length, placeStyle)
p.x = np.x
p.y = np.y
}
const npl = PolylineHelper.create(pts)
npl.CloseMark = true
return npl
}
/** 偏移 多段线 */
static offsetCurves(borders: Curve2d[], offvalue: number, isOffsetRounding: boolean): Curve2d[] {
if (equal(offvalue, 0))
return borders
const pts: any[] = []
for (const cur of borders) {
const x = cur.StartPoint.m_X
const y = cur.StartPoint.m_Y
const bul = (cur instanceof Arc2d) ? cur.Bul : 0
pts.push({ x, y, bul })
}
if (borders.length != 0) {
pts.push({ x: borders[0].StartPoint.m_X, y: borders[0].StartPoint.m_Y, bul: 0 })
}
const pl = PolylineHelper.create(pts)
// 偏移 倒角:直角不倒角 2023.10.27 QQ陈雄
const pls = isOffsetRounding ? pl.GetFeedingToolPath(offvalue, 0) : pl.GetOffsetCurves(offvalue)
if (pls.length == 0)
return borders
const npls = pls[0] // 偏移多段线
const ita = ConverToPolylineAndSplitArc(npls, false, true) // 拆分多段线
const offsetCurves: Curve2d[] = []
for (let i = 0; i < ita.pts.length; i++) {
let j = i + 1
if (j == ita.pts.length)
j = 0
const p1 = ita.pts[i]
const p2 = ita.pts[j]
const np1 = new Point2d(p1.x, p1.y)
const np2 = new Point2d(p2.x, p2.y)
if (ita.buls[i] == 0) {
const line = new Line2d(np1, np2)
if (line.m_Length < 0.01)
continue
offsetCurves.push(line)
}
else {
const arc = new Arc2d(np1, np2, ita.buls[i])
if (arc.m_Radius < 0.01)
continue
offsetCurves.push(arc)
}
}
return offsetCurves
}
/** 轮廓 转成 多断线 */
static borderToPolyline(border: Curve2d[], CloseMark = true): Polyline {
return PolylineHelper.createByCurve2d(border, CloseMark)
}
/** 多段线 转成 轮廓 */
static polylineToBorder(pl: Polyline): Curve2d[] {
const pts = pl.LineData.map((t) => { return { x: t.pt.x, y: t.pt.y, bul: t.bul } })
return this.createBorderByPts(pts)
}
/** 合并 多段线 */
static unionPolylines(pl: Polyline, childs: Polyline[]): Polyline {
const strPLS = PolylineHelper.getStrPLs([pl].concat(childs))
if (childs.length == 0)
return pl
try {
const contour1 = Contour.CreateContour(pl)
const reg1 = new ShapeManager([new Shape(contour1)])
for (const c of childs) {
const contour2 = Contour.CreateContour(c, false)
if (contour2 == null) {
return pl
} else {
PolylineHelper.getArcRadius
const reg2 = new ShapeManager([new Shape(contour2)])
reg1.UnionBoolOperation(reg2)
}
}
if (reg1.ShapeList.length == 0)
return pl
let newStr = ''
const pls: Array<Polyline | Circle> = []
for (const sh of reg1.ShapeList) {
pls.push(sh.Outline.Curve)
}
newStr = PolylineHelper.getStrPLs(pls)
const cur = reg1.ShapeList[0].Outline.Curve
let newpl: Polyline
if (cur instanceof Circle) {
newpl = PolylineHelper.cicleToPolyline(cur)
}
else {
newpl = cur
}
newStr = PolylineHelper.getStrPLs([newpl])
return PolylineHelper.resetPosition(newpl)
}
catch (err) {
console.log(err);
throw new Error('有非常规造型或2v刀路在合并空间时发生错误请导出优化结果cfdat文件并与软件服务商联系!')
}
}
/** 小板 标签位置 */
static resetLabelPos(b: PlaceBlock) {
if (!b.blockDetail) {
console.warn("PlaceBlock没有blockDetail无法计算标签位置")
return
}
if (b.blockDetail.labelPosX != -1)
return // 已计算
const pls = this.getOrgPloylines(b, false)
const pl = pls.pl
const mpls = pls.pls_inner
const x = b.cutWidth / 2
const y = b.cutLength / 2
b.blockDetail.labelPosX = x
b.blockDetail.labelPosY = y
// 矩形 且没有挖穿造型
if (b.isUnRegular == false && mpls.length == 0)
return
const vp = getValidPos()
if (vp) {
b.blockDetail.labelPosX = vp.x
b.blockDetail.labelPosY = vp.y
}
// 从中心点出发,左右上下偏移,求点。
function getValidPos() {
const off = 40
const offw = x / off
const offl = y / off
let nx = 0; let ny = 0
for (let i = 0; i < offw; i++) {
for (let j = 0; j < offl; j++) {
nx = x + i * off
ny = y + j * off
if (isInPolyline(pl, mpls, nx, ny))
return { x: nx, y: ny }
nx = x + i * off
ny = y - j * off
if (isInPolyline(pl, mpls, nx, ny))
return { x: nx, y: ny }
nx = x - i * off
ny = y + j * off
if (isInPolyline(pl, mpls, nx, ny))
return { x: nx, y: ny }
nx = x - i * off
ny = y - j * off
if (isInPolyline(pl, mpls, nx, ny))
return { x: nx, y: ny }
}
}
return null
}
/** 判断点 在范围内 */
function isInPolyline(pl: Polyline, mpls: Polyline[], x: number, y: number): boolean {
for (const mp of mpls) {
if (PolylineHelper.isPointInPolyline(mp, x, y))
return false // 在造型洞里头,
}
return PolylineHelper.isPointInPolyline(pl, x, y)
}
}
}