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

2396 lines
82 KiB
TypeScript
Raw Normal View History

2025-07-22 18:22:31 +08:00
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)
}
}
}