1714 lines
54 KiB
TypeScript
1714 lines
54 KiB
TypeScript
import { Production } from 'cadapi'
|
||
import { PolylineHelper } from '../../common/LayoutEngine/PolylineHelper.js'
|
||
import { ArrayExt } from '../../common/base/ArrayExt.js'
|
||
import { CADExt } from '../../common/base/CAD.js'
|
||
import { equal } from '../../common/base/MathComm.js'
|
||
|
||
import { getDis_PointLine, getDis2 } from '@/imes/common/base/MathComm.js'
|
||
|
||
// import { SideModel } from '../model/SideModel.js'
|
||
import { BlockHelper } from './BlockHelper.js'
|
||
import { SideModel, PlaceBlock, PlaceBlockDetail, FaceType, HoleType, BlockHole, BlockModelPoint, BlockSideModelPoint, SideFaceType, HoleArrange } from '../../confClass.js'
|
||
import { getDoFace } from './BlockDoFace.js'
|
||
import { ToolsHelper } from '../../tools/tool.js'
|
||
/**
|
||
* 小板原始数据的修改|计算
|
||
* 造型点阵,屏蔽一些不合理数据等
|
||
* 造型换刀铣
|
||
* 计算侧孔方向
|
||
* 计算异形板的封边
|
||
*/
|
||
|
||
/** 强制造型内往外铣 */
|
||
export function reverseModelPoints(bd: PlaceBlockDetail) {
|
||
// 默认:正面造型,外->内铣;反面造型,内->外铣;因此修改正面造型的点阵顺序
|
||
for (let model of bd.models) {
|
||
if (model.offsetList.length > 0)
|
||
continue // 2维刀路 不处理
|
||
if (model.depth > bd.thickness - 0.001)
|
||
continue // 挖穿的造型不算
|
||
if (model.pointList.length < 3)
|
||
continue
|
||
if (model.face != FaceType.FRONT)
|
||
continue // 正面
|
||
|
||
// 找出最外圈
|
||
let p0 = model.pointList[0]
|
||
let index = -1
|
||
for (let i = 1; i < model.pointList.length; i++) {
|
||
if (model.pointList[i].pointX == p0.pointX && model.pointList[i].pointY == p0.pointY) {
|
||
index = i
|
||
break
|
||
}
|
||
}
|
||
if (index == model.pointList.length - 1)
|
||
continue
|
||
if (index == -1)
|
||
continue // 找不到
|
||
// 最外圈
|
||
let ps_0 = model.pointList.splice(0, index + 1)
|
||
|
||
// 剩下倒序
|
||
model.pointList.reverse()
|
||
// 换 bul
|
||
for (let i = 0; i < model.pointList.length; i++) {
|
||
let j = i + 1
|
||
if (j < model.pointList.length) {
|
||
model.pointList[i].curve = -model.pointList[j].curve
|
||
model.pointList[i].radius = model.pointList[j].radius
|
||
}
|
||
else {
|
||
model.pointList[i].curve = 0
|
||
model.pointList[i].radius = 0
|
||
}
|
||
}
|
||
model.pointList = model.pointList.concat(ps_0)
|
||
// 最开始添加一点,避免cnc 当做槽处理
|
||
let pf = model.pointList[0].copy()
|
||
model.pointList.splice(0, 0, pf)
|
||
}
|
||
}
|
||
|
||
// /** 排钻转造型 */
|
||
// export function Hole2Model(bds: PlaceBlockDetail[], sysConfig: SysConfig)
|
||
// {
|
||
// let knifes = sysConfig.HoleToModelKnifes;
|
||
// knifes = knifes.filter(t => t.isUse && t.knifeId > 0);
|
||
|
||
// for (let knife of knifes)
|
||
// {
|
||
// let k = sysConfig.getKnifeById(knife.knifeId);
|
||
// if (k == null) continue;
|
||
// knife.knifeR = -1;
|
||
// if (k.AllowCut || k.AllowModel)
|
||
// {
|
||
// knife.knifeR = k.diameter / 2;
|
||
// }
|
||
// }
|
||
// knifes = knifes.filter(t => t.knifeR > 0);
|
||
|
||
// for (let bd of bds)
|
||
// {
|
||
// for (let i = bd.holes.length - 1; i >= 0; i--)
|
||
// {
|
||
// let hole = bd.holes[i];
|
||
// let k = knifes.find(t => t.minR <= hole.radius + 0.00001 && t.maxR > hole.radius + 0.0000001);
|
||
// if (k == null) continue;
|
||
// let model = toModel(bd.thickness, hole, k.knifeR);
|
||
// if (model == null) continue;
|
||
// bd.models.push(model);
|
||
// bd.holes.splice(i, 1);
|
||
// }
|
||
// }
|
||
|
||
// function toModel(t: number, hole: BlockHole, r: number)
|
||
// {
|
||
// let depth = hole.depth;
|
||
// let hR = hole.radius;
|
||
// if (hR < r + 0.001) return null;
|
||
|
||
// let model = new BlockModel();
|
||
// model.face = hole.face;
|
||
// model.knifeRadius = r;
|
||
// model.knifeName = '';
|
||
// model.realKnifeRadius = r;
|
||
// model.depth = hole.depth;
|
||
// model.canSpace = false;
|
||
// model.pointList = [];
|
||
// model.realPointList = model.pointList;
|
||
// let cx = hole.pointX;
|
||
// let cy = hole.pointY;
|
||
|
||
// let r0 = hR - r;
|
||
// if (r0 < 0) r0 = 0;
|
||
// //最外层先走一圈,顺时针
|
||
|
||
// //左,上,右,下
|
||
// model.pointList.push( new BlockModelPoint({ pointX: cx - r0, pointY: cy, radius: r0, curve: -0.41421356237309503, depth: depth }) );
|
||
// model.pointList.push( new BlockModelPoint({ pointX: cx, pointY: cy + r0, radius: r0, curve: -0.41421356237309503, depth: depth }) );
|
||
// model.pointList.push( new BlockModelPoint({ pointX: cx + r0, pointY: cy, radius: r0, curve: -0.41421356237309503, depth: depth }) );
|
||
// model.pointList.push( new BlockModelPoint({ pointX: cx, pointY: cy - r0, radius: r0, curve: -0.41421356237309503, depth: depth }) );
|
||
// model.pointList.push( new BlockModelPoint({ pointX: cx - r0, pointY: cy, radius: 0, curve: 0, depth: depth }) );
|
||
|
||
// //挖穿
|
||
// if (depth >= t - 0.001) return model;
|
||
|
||
// //非挖穿的
|
||
// r0 = r0 - r;
|
||
// while (r0 > 0)
|
||
// {
|
||
// //左 ,下,右,上 逆时针
|
||
// model.pointList.push( new BlockModelPoint({ pointX: cx - r0, pointY: cy, radius: r0, curve: 0.41421356237309503, depth: depth }) );
|
||
// model.pointList.push( new BlockModelPoint({ pointX: cx, pointY: cy - r0, radius: r0, curve: 0.41421356237309503, depth: depth }) );
|
||
// model.pointList.push( new BlockModelPoint({ pointX: cx + r0, pointY: cy, radius: r0, curve: 0.41421356237309503, depth: depth }) );
|
||
// model.pointList.push( new BlockModelPoint({ pointX: cx, pointY: cy + r0, radius: r0, curve: 0.41421356237309503, depth: depth }) );
|
||
// model.pointList.push( new BlockModelPoint({ pointX: cx - r0, pointY: cy, radius: 0, curve: 0, depth: depth }) );
|
||
// r0 = r0 - r;
|
||
// }
|
||
// //圆心
|
||
// model.pointList.push( new BlockModelPoint({ pointX: cx, pointY: cy, radius: 0, curve: 0, depth: depth }) );
|
||
// return model;
|
||
// }
|
||
|
||
// }
|
||
|
||
/** 移除无效的面孔:孔不在板内/孔径太小/孔深不够/圆心在外面的孔 */
|
||
|
||
export function removeInvalidHoles(block: PlaceBlockDetail, minHoleRadius: number, minHoleDepth: number) {
|
||
let count = block.holes.length
|
||
|
||
for (let i = count - 1; i >= 0; i--) {
|
||
let hole = block.holes[i]
|
||
// 是否无效, 板外,孔径太小,孔深度太浅
|
||
let invalid = isInvalidHole(block, hole, 1)
|
||
|
||
if (invalid) {
|
||
block.holes.splice(i, 1)
|
||
continue
|
||
}
|
||
|
||
if (hole.face != FaceType.SIDE && hole.depth > block.thickness) {
|
||
hole.depth = block.thickness
|
||
}
|
||
}
|
||
|
||
|
||
function isInvalidHole(blockDetail: PlaceBlockDetail, hole: BlockHole, offset: number): boolean {
|
||
if (hole.radius < minHoleRadius)
|
||
return true // 孔径太小
|
||
if (hole.depth < minHoleDepth)
|
||
return true // 孔深度太浅
|
||
// 圆心不在板内
|
||
if (hole.pointX < -offset)
|
||
return true
|
||
// if (hole.PointX > block.KaiLiaoWidth) return true;
|
||
if (hole.pointY < -offset)
|
||
return true
|
||
// if (hole.PointY > block.KaiLiaoLength + offset) return true;
|
||
return false
|
||
}
|
||
}
|
||
|
||
/** 移除二合一的面孔 */
|
||
|
||
export function remove2in1Hole(block: PlaceBlockDetail, gap: number) {
|
||
/** 二合一侧孔离边距离 */
|
||
|
||
let removeSideHoles = new Array<BlockHole>()
|
||
let count = block.holes.length
|
||
|
||
for (let i = count - 1; i >= 0; i--) {
|
||
let hole = block.holes[i]
|
||
|
||
if (hole.face != FaceType.SIDE) {
|
||
let sideHolesL = block.holes.filter(t => t.face == FaceType.SIDE && t.pointY == hole.pointY && t.pointX < hole.pointX && t.pointX >= hole.pointX - hole.radius - gap)
|
||
let sideHolesR = block.holes.filter(t => t.face == FaceType.SIDE && t.pointY == hole.pointY && t.pointX > hole.pointX && t.pointX <= hole.pointX + hole.radius + gap)
|
||
let sideHolesS = block.holes.filter(t => t.face == FaceType.SIDE && t.pointX == hole.pointX && t.pointY > hole.pointY && t.pointY < hole.pointY + hole.radius + gap)
|
||
let sideHolesX = block.holes.filter(t => t.face == FaceType.SIDE && t.pointX == hole.pointX && t.pointY < hole.pointY && t.pointY > hole.pointY - hole.radius - gap)
|
||
removeSideHoles = removeSideHoles.concat(sideHolesL, sideHolesR, sideHolesS, sideHolesX)
|
||
}
|
||
}
|
||
|
||
|
||
for (let removeHole of removeSideHoles) {
|
||
let index = block.holes.indexOf(removeHole)
|
||
|
||
if (index >= 0) {
|
||
block.holes.splice(index, 1)
|
||
}
|
||
}
|
||
}
|
||
|
||
/** 穿孔或打穿造型通孔一刀加工 */
|
||
/**
|
||
*
|
||
* @param bd
|
||
* @param config
|
||
config
|
||
* throughHoleOneTime 通孔穿孔一刀加工
|
||
* * throughHoleProcessMode 穿孔对面加工方式:
|
||
** 0随意面,根据排版尽量正面加工(少翻板);
|
||
** 1孔面,按碰撞面排孔所在面加工;
|
||
** 2孔对面,按碰撞面排孔所在面的对面打孔
|
||
*/
|
||
export function resetThroughHoleModes(bd: PlaceBlockDetail, config: any) {
|
||
if (!bd.points)
|
||
bd.points = []
|
||
if (!bd.holes)
|
||
bd.holes = []
|
||
if (!bd.models)
|
||
bd.models = []
|
||
|
||
const {
|
||
throughHoleOneTime = false,
|
||
throughHoleProcessMode = 0,
|
||
} = config
|
||
if (throughHoleOneTime) // 通孔穿孔一刀加工
|
||
{
|
||
// 判断正反面匹配的
|
||
bd.holeListThrough = bd.holes.filter(t => t.depth >= bd.thickness - 0.001) // 穿孔
|
||
bd.holeListFaceA = bd.holes.filter(t => t.face == FaceType.FRONT && t.depth < bd.thickness - 0.001)
|
||
bd.holeListFaceB = bd.holes.filter(t => t.face == FaceType.BACK && t.depth < bd.thickness - 0.001)
|
||
|
||
// 通孔判断
|
||
|
||
for (let i = bd.holeListFaceA.length - 1; i >= 0; i--) {
|
||
let hole1 = bd.holeListFaceA[i]
|
||
let isThrough = false
|
||
|
||
for (let j = bd.holeListFaceB.length - 1; j >= 0; j--) {
|
||
let hole2 = bd.holeListFaceB[j]
|
||
|
||
if (isThroughHole(hole1, hole2)) {
|
||
bd.holeListFaceB.splice(j, 1)
|
||
isThrough = true
|
||
}
|
||
}
|
||
|
||
if (isThrough) {
|
||
bd.holeListFaceA.splice(i, 1)
|
||
hole1.depth = bd.thickness
|
||
bd.holeListThrough.push(hole1)
|
||
}
|
||
}
|
||
}
|
||
|
||
else {
|
||
if (throughHoleProcessMode == 2) // 通孔对面加工
|
||
{
|
||
|
||
for (let hole of bd.holes) {
|
||
if (hole.holeType == HoleType.THROUGH_HOLE || hole.depth >= bd.thickness - 0.01) {
|
||
let oldFace = hole.face
|
||
|
||
if (oldFace == FaceType.FRONT) {
|
||
hole.face = FaceType.BACK
|
||
}
|
||
|
||
else if (oldFace == FaceType.BACK) {
|
||
hole.face = FaceType.FRONT
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
bd.holeListFaceA = bd.holes.filter(t => t.face == FaceType.FRONT)
|
||
bd.holeListFaceB = bd.holes.filter(t => t.face == FaceType.BACK)
|
||
bd.holeListThrough = []
|
||
}
|
||
|
||
bd.modelListFaceA = bd.models.filter(t => t.face == FaceType.FRONT && (t.depth < bd.thickness - 0.01 || t.isVKnifeModel()))
|
||
bd.modelListFaceB = bd.models.filter(t => t.face == FaceType.BACK && (t.depth < bd.thickness - 0.01 || t.isVKnifeModel()))
|
||
bd.modelListThrough = bd.models.filter(t => t.depth >= bd.thickness - 0.01 && t.isVKnifeModel() == false)
|
||
|
||
bd.holeCountFront = bd.holeListFaceA.length
|
||
bd.holeCountBack = bd.holeListFaceB.length
|
||
bd.holeCountThrough = bd.holeListThrough.length
|
||
bd.holeCountSide = bd.holeListSide.length
|
||
|
||
bd.modelCountFront = bd.modelListFaceA.length
|
||
bd.modelCountBack = bd.modelListFaceB.length
|
||
bd.modelCountThrough = bd.modelListThrough.length
|
||
bd.hasModelThrogh = bd.modelListThrough.length > 0
|
||
|
||
bd.bigHoleInFaceA = bd.holeListFaceA.some(t => t.holeType == HoleType.BIG_HOLE)
|
||
bd.isTwoFaceProcess = bd.holeCountFront + bd.modelCountFront > 0 && bd.holeCountBack + bd.modelCountBack > 0
|
||
|
||
/** 判断两孔是否是通孔 */
|
||
|
||
function isThroughHole(hole1, hole2) {
|
||
// 孔半径一样,位置一样,深度和大于板厚
|
||
return equal(hole1.radius, hole2.radius)
|
||
|
||
&& equal(hole1.pointX, hole2.pointX)
|
||
&& equal(hole1.pointY, hole2.pointY)
|
||
&& hole1.depth + hole2.depth >= bd.thickness - 0.01
|
||
}
|
||
}
|
||
|
||
/** 设置侧孔的方向 */
|
||
|
||
export function setSideHoleFace(block: PlaceBlockDetail) {
|
||
|
||
// 矩形板的侧孔face原始数据无法保证正确,所有都当做起点,终点来计算侧孔的面与方向
|
||
|
||
for (const hole of block.holeListSide) {
|
||
if (Math.abs(hole.pointX - hole.pointX2) < 1 && hole.pointY2 > hole.pointY) {
|
||
hole.direct = 0 // 下侧边,向上
|
||
hole.sideFace = SideFaceType.BOTTOM_SIDE
|
||
}
|
||
else if (Math.abs(hole.pointX - hole.pointX2) < 1 && hole.pointY2 < hole.pointY) {
|
||
hole.direct = 2 // 上侧边 向下
|
||
hole.sideFace = SideFaceType.TOP_SIDE
|
||
}
|
||
|
||
else if (Math.abs(hole.pointY - hole.pointY2) < 1 && hole.pointX2 > hole.pointX) {
|
||
hole.direct = 3 // 在左侧板 向右
|
||
hole.sideFace = SideFaceType.LEFT_SIDE
|
||
}
|
||
|
||
else if (Math.abs(hole.pointY - hole.pointY2) < 1 && hole.pointX2 < hole.pointX) {
|
||
hole.direct = 1 // 右侧边, 向左
|
||
hole.sideFace = SideFaceType.RIGHT_SIDE
|
||
}
|
||
else // 斜边
|
||
{
|
||
hole.direct = -1
|
||
hole.sideFace = SideFaceType.SPECIAL_SHAPED_SIDE
|
||
}
|
||
}
|
||
block.holeCountLeft = ArrayExt.count(block.holeListSide, t => t.faceId == 3)
|
||
block.holeCountRight = ArrayExt.count(block.holeListSide, t => t.faceId == 1)
|
||
block.holeCountTop = ArrayExt.count(block.holeListSide, t => t.faceId == 2)
|
||
block.holeCountBottom = ArrayExt.count(block.holeListSide, t => t.faceId == 0)
|
||
block.holeCountBevelled = ArrayExt.count(block.holeListSide, t => ![0, 1, 2, 3].includes(t.faceId))
|
||
}
|
||
/** 初始化 侧面造型
|
||
*
|
||
* * 侧面造型的点阵判断逻辑
|
||
*
|
||
* 提要:
|
||
* 1、 face 为 该造型在该板件的第几条边上
|
||
* 2、 originModeling 内的造型轮廓点阵的 X Y轴 为 :
|
||
* 以该造型为正面 且小板板面朝上 造型为正面的左下角为原点 板厚 为 Y 横象为X
|
||
* 注:最终使用的时候 要得到该造型 对应机台的 轮廓数据和刀路数据
|
||
*
|
||
* 平行判断 参考 checkIsTilt 修改一个新的方法
|
||
* 是否在板内 可使用 isPointInBlock
|
||
*
|
||
* 要求:要得到
|
||
*
|
||
* 转换逻辑
|
||
* 1、通过face 获取 该造型所在的边
|
||
* 2、将这条边 与 板件的坐标轴做比较 判断平行
|
||
* 情况1:与板件的X轴 平行 则造型 可能为 上 || 下 ,使用 isPointInBlock 判断 具体是上 还是下
|
||
* 情况2:与板件的Y轴 平行 则造型 可能为 左 || 右 , 使用 isPointInBlock 判断 具体是左 还是右
|
||
* 情况3:都不平行 则 朝向的值为斜边
|
||
* 最终得到造型的朝向
|
||
* 3、依据边的坐标和造型的朝向 可以 根据造型的轮廓数据转为 对应机台的轮廓数据 和刀路数据
|
||
*
|
||
*
|
||
* 注:这里解析出的是设计端的数据
|
||
*/
|
||
export async function initSideModel(block: PlaceBlock) {
|
||
if (!block.blockDetail) {
|
||
console.error('initSideModel: blockDetail is undefind')
|
||
return
|
||
}
|
||
let detail = block.blockDetail
|
||
if (detail.modelListSide.length > 0) {
|
||
|
||
// 判断时侧面造型 还是 侧面槽 以及计算槽的相关信息
|
||
for (const sideModel of detail.modelListSide) {
|
||
let min = 0; // 宽
|
||
let max = 0; // 长
|
||
// let temp: any = []
|
||
let isRect = true // 是否矩形
|
||
let lines: Array<any> = []
|
||
for (let index = 0; index < sideModel.originModeling.outline.length; index++) {
|
||
const baseStartPoint = sideModel.originModeling.outline[index];
|
||
|
||
const baseEndPoint = sideModel.originModeling.outline[index + 1];
|
||
|
||
if (!baseEndPoint) {
|
||
break
|
||
}
|
||
const startPoint = sideModel.originModeling.outline[index].pts;
|
||
const endPoint = sideModel.originModeling.outline[index + 1].pts;
|
||
|
||
if (baseStartPoint.buls != 0 || baseEndPoint.buls != 0) {
|
||
isRect = false
|
||
break
|
||
}
|
||
|
||
let centerPoint = {
|
||
x: (startPoint.x + endPoint.x) / 2,
|
||
y: (startPoint.y + endPoint.y) / 2,
|
||
curve: baseStartPoint.buls,
|
||
depth: sideModel.depth,
|
||
radius: 0
|
||
}
|
||
|
||
|
||
let lineLength = getDis2(startPoint, endPoint) // parseFloat(parseFloat(getDis2(startPoint, endPoint)).toFixed(3))
|
||
if (min == 0) {
|
||
min = lineLength
|
||
}
|
||
if (max == 0) {
|
||
max = lineLength
|
||
}
|
||
min = Math.min(min, lineLength)
|
||
max = Math.max(max, lineLength)
|
||
|
||
|
||
let temp = { startPoint, endPoint, centerPoint, lineLength }
|
||
lines.push(temp);
|
||
if (index + 1 == sideModel.originModeling.outline.length) {
|
||
break
|
||
}
|
||
}
|
||
|
||
let startAndEndLines = lines.filter(e => isInRange(min, e.lineLength - 0.001, e.lineLength + 0.001));
|
||
|
||
// 槽的起点 和终点
|
||
if (startAndEndLines.length == 2) {
|
||
sideModel.modelStartPoint = startAndEndLines[0].centerPoint
|
||
sideModel.modelEndPoint = startAndEndLines[1].centerPoint
|
||
}
|
||
|
||
isRect = (lines.length == 4 || lines.length == 1) && sideModel.offsetList.length == 0
|
||
// console.log('情况123', lines, model,isRect)
|
||
sideModel.modelLength = max
|
||
sideModel.modelWidth = min
|
||
sideModel.isRect = isRect
|
||
if (isRect) {
|
||
sideModel.isTilt = checkIsTilt(lines)
|
||
}
|
||
|
||
let directionRes = getModelDirection(block, sideModel)
|
||
|
||
sideModel.direction = directionRes.direction;
|
||
// console.log('direction', directionRes.direction, sideModel.isRect, sideModel.isTilt);
|
||
|
||
if (!detail.borderContour) {
|
||
console.error('initSideModel: borderContour is undefind')
|
||
return
|
||
}
|
||
const borders = detail?.borderContour?.borderFinal
|
||
const border = borders[sideModel.face]
|
||
|
||
// 依据 造型的朝向 和 造型的轮廓数据 和 所在边的坐标 生成 轮廓数据 还有刀路数据
|
||
if (isRect && sideModel.isTilt == false) {
|
||
detail.borderContour.borderFinal
|
||
sideModel.modelStartPoint = transformSideModelPoint(sideModel.modelStartPoint, directionRes, border, sideModel, 'modelStartPoint')
|
||
sideModel.modelEndPoint = transformSideModelPoint(sideModel.modelEndPoint, directionRes, border, sideModel, 'modelStartPoint')
|
||
}
|
||
|
||
let newPointList: any = []
|
||
if (Array.isArray(sideModel.originModeling.outline)) {
|
||
for (const linePoint of sideModel.originModeling.outline) {
|
||
let tempPoint = {
|
||
curve: linePoint.buls,
|
||
depth: sideModel.depth,
|
||
radius: 1 / linePoint.buls,
|
||
x: linePoint.pts.x,
|
||
y: linePoint.pts.y,
|
||
z: linePoint.pts.z,
|
||
}
|
||
let temp = transformSideModelPoint(tempPoint, directionRes, border, sideModel, 'linePoint')
|
||
|
||
let sideModelPoint = new BlockSideModelPoint(temp)
|
||
|
||
newPointList.push(sideModelPoint)
|
||
}
|
||
} else {
|
||
for (const i in sideModel.originModeling.outline.pts) {
|
||
let pts = sideModel.originModeling.outline.pts[i]
|
||
let bul = sideModel.originModeling.outline.buls[i]
|
||
let tempPoint = {
|
||
curve: bul,
|
||
depth: sideModel.depth,
|
||
radius: 1 / bul,
|
||
x: pts.x,
|
||
y: pts.y,
|
||
z: pts.z,
|
||
}
|
||
|
||
let temp = transformSideModelPoint(tempPoint, directionRes, border, sideModel, 'linePoint')
|
||
|
||
let sideModelPoint = new BlockSideModelPoint(temp)
|
||
|
||
newPointList.push(sideModelPoint)
|
||
}
|
||
}
|
||
|
||
sideModel.pointList = newPointList
|
||
}
|
||
}
|
||
}
|
||
|
||
/**侧面造型数据转换 从设计端 转为生产数据
|
||
* config:
|
||
* placeStyle 小板放置方式
|
||
*/
|
||
export function transFormSideModelDataToProductData(block: PlaceBlock, config) {
|
||
if(!block.blockDetail){
|
||
console.error('transFormSideModelDataToProductData: blockDetail is undefind')
|
||
return
|
||
}
|
||
const {
|
||
placeStyle= 1
|
||
} = config
|
||
if (block.blockDetail.modelListSide.length > 0) {
|
||
for (const sideModel of block.blockDetail.modelListSide) {
|
||
if (sideModel.isRect == true && sideModel.isTilt == false) {
|
||
// 矩形槽 要转换下起始点
|
||
let p_start = BlockHelper.getPlacedPostionInBlock(placeStyle, block.placeWidth, block.placeLength, sideModel.modelStartPoint.x, sideModel.modelStartPoint.y, false)
|
||
let p_end = BlockHelper.getPlacedPostionInBlock(placeStyle, block.placeWidth, block.placeLength, sideModel.modelEndPoint.x, sideModel.modelEndPoint.y, false)
|
||
|
||
sideModel.modelStartPoint.x = p_start.x
|
||
sideModel.modelStartPoint.y = p_start.y
|
||
|
||
sideModel.modelEndPoint.x = p_end.x
|
||
sideModel.modelEndPoint.y = p_end.y
|
||
}
|
||
|
||
// 转换造型 轮廓点阵
|
||
for (const point of sideModel.pointList) {
|
||
let p = BlockHelper.getPlacedPostionInBlock(placeStyle, block.placeWidth, block.placeLength, point.pointX, point.pointY, false)
|
||
point.pointX = p.x
|
||
point.pointY = p.y
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
/**
|
||
* 值 是否在范围内
|
||
* @param value 目标值
|
||
* @param min 最小值 比较值
|
||
* @param max 最大值 比较值
|
||
* @returns
|
||
*/
|
||
function isInRange(value, min, max) {
|
||
return value >= min && value <= max;
|
||
}
|
||
/**
|
||
*
|
||
* @param lines
|
||
* 注:假定2条在坐标轴上的线 与矩形造型的4条线判断是否是平行
|
||
*
|
||
* 线的起始点 与 坐标轴 X Y 比较 判断是否倾斜 (倾斜的矩形 或者 平行四边形)
|
||
*/
|
||
// 判断是否是倾斜的
|
||
function checkIsTilt(lines) {
|
||
// 假定的坐标轴 定义坐标点
|
||
let p1 = { x: 0, y: 0 }
|
||
let p2 = { x: 0, y: 100 }
|
||
let p3 = { x: 100, y: 0 }
|
||
// 假定2条在坐标轴上的线
|
||
// let tempAxiosXLine = [p1,p3]
|
||
// let tempAxiosYLine = [p1,p2]
|
||
|
||
|
||
|
||
lines.forEach(line => {
|
||
// flag 是否平行的标识 true 平行 false 不平行
|
||
let flagX = false
|
||
let flagY = false
|
||
|
||
let startX = line.startPoint.pointX || line.startPoint.x
|
||
let startY = line.startPoint.pointY || line.startPoint.y
|
||
let endX = line.endPoint.pointX || line.endPoint.x
|
||
let endY = line.endPoint.pointY || line.endPoint.y
|
||
|
||
// 距离X轴的距离是否相等
|
||
// 线段的起点 距离X轴的距离
|
||
let len1 = getDis_PointLine(p1.x, p1.y, p3.x, p3.y, startX, startY)
|
||
// 线段的终点 距离X轴的距离
|
||
let len2 = getDis_PointLine(p1.x, p1.y, p3.x, p3.y, endX, endY)
|
||
|
||
// 实际数据是有误差的 误差 的容差为 0.001
|
||
if (isInRange(len1, len2 - 0.001, len2 + 0.001) || isInRange(len2, len1 - 0.001, len1 + 0.001)) {
|
||
flagX = true
|
||
}
|
||
|
||
// 距离Y轴的距离是否相等
|
||
|
||
|
||
// 线段起点距离Y轴的距离
|
||
let len3 = getDis_PointLine(p1.x, p1.y, p2.x, p2.y, startX, startY)
|
||
// 线段终点距离Y轴的距离
|
||
let len4 = getDis_PointLine(p1.x, p1.y, p2.x, p2.y, endX, endY)
|
||
|
||
if (isInRange(len3, len4 - 0.001, len4 + 0.001) || isInRange(len4, len3 - 0.001, len3 + 0.001)) {
|
||
flagX = true
|
||
}
|
||
|
||
// 只要和 X || Y 轴 平行 就不是倾斜的
|
||
|
||
if (flagX || flagY) {
|
||
line.isTilt = false
|
||
} else {
|
||
line.isTilt = true
|
||
}
|
||
});
|
||
// 查找有没有 倾斜的边
|
||
const res = lines.filter(e => e.isTilt == true).length > 0 //.findIndex(e => e.isTilt == true) == -1
|
||
|
||
|
||
return res
|
||
|
||
}
|
||
/** 转换 侧面造型的坐标点 */
|
||
export function transformSideModelPoint(point, directionRes, border, sideModel: SideModel, flag?: string) {
|
||
const { direction, preFlag, nextFlag } = directionRes
|
||
|
||
let newPoint: any = { x: 0, y: 0, z: 0, buls: 0, depth: 0 }
|
||
if (point == null) {
|
||
newPoint = null // { x: -1, y: -1, z: -1, buls: 0, depth: 0 }
|
||
} else {
|
||
/**
|
||
*
|
||
* 侧面造型的点坐标使用 等比三角形 解决坐标问题
|
||
*
|
||
*/
|
||
|
||
// 斜边比例
|
||
let rate = point.x / border.m_Length
|
||
|
||
|
||
|
||
switch (direction) {
|
||
case 0:
|
||
/**坐标转换逻辑 下造型
|
||
*
|
||
* point 里面的
|
||
* x 对应 实际的 X
|
||
* y 对应 实际的 Z
|
||
* 实际的y 为 border 对应的 y
|
||
*/
|
||
|
||
// console.log('下造型',sideModel.modelId)
|
||
newPoint.x = point.x
|
||
newPoint.y = border.StartPoint.m_Y
|
||
newPoint.z = point.y
|
||
newPoint.buls = point.curve
|
||
newPoint.depth = sideModel.depth
|
||
break
|
||
case 1:
|
||
// console.log('右造型',sideModel.modelId)
|
||
newPoint.x = border.StartPoint.m_X
|
||
newPoint.y = point.x
|
||
newPoint.z = point.y
|
||
newPoint.buls = point.curve
|
||
newPoint.depth = sideModel.depth
|
||
break
|
||
case 2:
|
||
// console.log('上造型',sideModel.modelId)
|
||
newPoint.x = border.StartPoint.m_X - point.x
|
||
newPoint.y = border.StartPoint.m_Y
|
||
newPoint.z = point.y
|
||
newPoint.buls = point.curve
|
||
newPoint.depth = sideModel.depth
|
||
break
|
||
case 3:
|
||
// console.log('左造型',sideModel.modelId)
|
||
newPoint.x = border.StartPoint.m_X
|
||
newPoint.y = border.StartPoint.m_Y - point.x
|
||
newPoint.z = point.y
|
||
newPoint.buls = point.curve
|
||
newPoint.depth = sideModel.depth
|
||
break
|
||
case 10:
|
||
// console.log('左下造型',sideModel.modelId)
|
||
|
||
// 底边
|
||
var x = Math.abs(border.StartPoint.m_X) - Math.abs(border.EndPoint.m_X)
|
||
// 竖边
|
||
var y = Math.abs(border.StartPoint.m_Y) - Math.abs(border.EndPoint.m_Y)
|
||
|
||
|
||
// 实际点坐标的 偏移值
|
||
var p_x = Math.abs(x * rate)
|
||
var p_y = Math.abs(y * rate)
|
||
|
||
var fakeStartPoint: any = null
|
||
// 二次计算的原点坐标
|
||
|
||
/**
|
||
* 根据 造型的坐标系的定位点 进行偏移 (边框的起点 或者终点)
|
||
* 根据preFlag (小板的轮廓的上一条边的朝向 判断 定位点事 起点还是终点)
|
||
*/
|
||
if (preFlag == 'toDown') {
|
||
fakeStartPoint =
|
||
{
|
||
x: border.StartPoint.m_X,
|
||
y: border.StartPoint.m_Y
|
||
}
|
||
} else if (preFlag == 'toLeft') {
|
||
fakeStartPoint =
|
||
{
|
||
x: border.EndPoint.m_X,
|
||
y: border.EndPoint.m_Y
|
||
}
|
||
} else {
|
||
console.log('理论上有异常 排查')
|
||
}
|
||
newPoint.x = fakeStartPoint.x + p_x
|
||
newPoint.y = fakeStartPoint.y - p_y
|
||
newPoint.z = point.y
|
||
newPoint.buls = point.curve
|
||
newPoint.depth = sideModel.depth
|
||
break
|
||
case 11:
|
||
// console.log('右下造型',sideModel.modelId)
|
||
|
||
|
||
// 底边
|
||
var x = Math.abs(border.StartPoint.m_X) - Math.abs(border.EndPoint.m_X)
|
||
// 竖边
|
||
var y = Math.abs(border.StartPoint.m_Y) - Math.abs(border.EndPoint.m_Y)
|
||
|
||
|
||
// 实际点坐标的 偏移值
|
||
var p_x = Math.abs(x * rate)
|
||
var p_y = Math.abs(y * rate)
|
||
|
||
var fakeStartPoint: any = null
|
||
// 二次计算的原点坐标
|
||
|
||
/**
|
||
* 根据 造型的坐标系的定位点 进行偏移 (边框的起点 或者终点)
|
||
* 根据preFlag (小板的轮廓的上一条边的朝向 判断 定位点事 起点还是终点)
|
||
*/
|
||
if (preFlag == 'toRight') {
|
||
fakeStartPoint =
|
||
{
|
||
x: border.StartPoint.m_X,
|
||
y: border.StartPoint.m_Y
|
||
}
|
||
} else if (preFlag == 'toDown') {
|
||
fakeStartPoint =
|
||
{
|
||
x: border.EndPoint.m_X,
|
||
y: border.EndPoint.m_Y
|
||
}
|
||
} else {
|
||
console.log('理论上有异常 排查')
|
||
}
|
||
|
||
|
||
newPoint.x = fakeStartPoint.x + p_x
|
||
newPoint.y = fakeStartPoint.y + p_y
|
||
newPoint.z = point.y
|
||
newPoint.buls = point.curve
|
||
newPoint.depth = sideModel.depth
|
||
break
|
||
case 12:
|
||
// console.log('右上造型',sideModel.modelId)
|
||
// 底边
|
||
var x = Math.abs(border.StartPoint.m_X) - Math.abs(border.EndPoint.m_X)
|
||
// 竖边
|
||
var y = Math.abs(border.StartPoint.m_Y) - Math.abs(border.EndPoint.m_Y)
|
||
|
||
|
||
// 实际点坐标的 偏移值
|
||
var p_x = Math.abs(x * rate)
|
||
var p_y = Math.abs(y * rate)
|
||
|
||
var fakeStartPoint: any = null
|
||
// 二次计算的原点坐标
|
||
|
||
/**
|
||
* 根据 造型的坐标系的定位点 进行偏移 (边框的起点 或者终点)
|
||
* 根据preFlag (小板的轮廓的上一条边的朝向 判断 定位点事 起点还是终点)
|
||
*/
|
||
if (preFlag == 'toUp') {
|
||
fakeStartPoint =
|
||
{
|
||
x: border.StartPoint.m_X,
|
||
y: border.StartPoint.m_Y
|
||
}
|
||
} else if (preFlag == 'toRight') {
|
||
fakeStartPoint =
|
||
{
|
||
x: border.EndPoint.m_X,
|
||
y: border.EndPoint.m_Y
|
||
}
|
||
} else {
|
||
console.log('理论上有异常 排查')
|
||
}
|
||
newPoint.x = fakeStartPoint.x - p_x
|
||
newPoint.y = fakeStartPoint.y - p_y
|
||
newPoint.z = point.y
|
||
newPoint.buls = point.curve
|
||
newPoint.depth = sideModel.depth
|
||
break
|
||
case 13:
|
||
// console.log('左上造型',sideModel.modelId)
|
||
|
||
// 底边
|
||
var x = Math.abs(border.StartPoint.m_X) - Math.abs(border.EndPoint.m_X)
|
||
// 竖边
|
||
var y = Math.abs(border.StartPoint.m_Y) - Math.abs(border.EndPoint.m_Y)
|
||
|
||
|
||
// 实际点坐标的 偏移值
|
||
var p_x = Math.abs(x * rate)
|
||
var p_y = Math.abs(y * rate)
|
||
|
||
var fakeStartPoint: any = null
|
||
// 二次计算的原点坐标
|
||
|
||
/**
|
||
* 根据 造型的坐标系的定位点 进行偏移 (边框的起点 或者终点)
|
||
* 根据preFlag (小板的轮廓的上一条边的朝向 判断 定位点事 起点还是终点)
|
||
*/
|
||
if (preFlag == 'toLeft') {
|
||
fakeStartPoint =
|
||
{
|
||
x: border.StartPoint.m_X,
|
||
y: border.StartPoint.m_Y
|
||
}
|
||
} else if (preFlag == 'toUp') {
|
||
fakeStartPoint =
|
||
{
|
||
x: border.EndPoint.m_X,
|
||
y: border.EndPoint.m_Y
|
||
}
|
||
} else {
|
||
console.log('理论上有异常 排查')
|
||
}
|
||
|
||
|
||
newPoint.x = fakeStartPoint.x - p_x
|
||
newPoint.y = fakeStartPoint.y - p_y
|
||
newPoint.z = point.y
|
||
newPoint.buls = point.curve
|
||
newPoint.depth = sideModel.depth
|
||
break
|
||
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
|
||
return newPoint;
|
||
}
|
||
// 获取侧面造型的朝向
|
||
export function getModelDirection(block: PlaceBlock, sideModel) {
|
||
|
||
console.log('getModelDirection', block);
|
||
let detail = block.blockDetail
|
||
|
||
|
||
const borders = detail?.borderContour?.borderFinal
|
||
// if(borders==undefined){
|
||
// return
|
||
// }
|
||
|
||
const border = borders[sideModel.face]
|
||
|
||
let polygon: any = []
|
||
|
||
borders.forEach(br => {
|
||
let temp = {
|
||
x: br.StartPoint.m_X,
|
||
y: br.StartPoint.m_Y
|
||
}
|
||
polygon.push(temp)
|
||
});
|
||
|
||
|
||
// 假定的坐标轴 定义坐标点
|
||
let p1 = { x: 0, y: 0 }
|
||
let p2 = { x: 0, y: 100 }
|
||
let p3 = { x: 100, y: 0 }
|
||
// 朝向
|
||
let direction = -2;
|
||
|
||
// 注: 根据上一条边和下一条的朝向判断 造型的 朝向
|
||
// 板件轮廓 上一条边的朝向
|
||
let preFlag = '';
|
||
// 板件轮廓 下一条边的朝向
|
||
let nextFlag = '';
|
||
|
||
|
||
|
||
let flagX = false
|
||
let flagY = false
|
||
|
||
// 线段的起点 距离X轴的距离
|
||
let len1 = getDis_PointLine(p1.x, p1.y, p3.x, p3.y, border.StartPoint.m_X, border.StartPoint.m_Y)
|
||
// 线段的终点 距离X轴的距离
|
||
let len2 = getDis_PointLine(p1.x, p1.y, p3.x, p3.y, border.EndPoint.m_X, border.EndPoint.m_Y)
|
||
|
||
if (len1 == len2) {
|
||
flagX = true
|
||
}
|
||
// 距离Y轴的距离是否相等
|
||
// 线段起点距离Y轴的距离
|
||
let len3 = getDis_PointLine(p1.x, p1.y, p2.x, p2.y, border.StartPoint.m_X, border.StartPoint.m_Y)
|
||
// 线段终点距离Y轴的距离
|
||
let len4 = getDis_PointLine(p1.x, p1.y, p2.x, p2.y, border.EndPoint.m_X, border.EndPoint.m_Y)
|
||
if (len3 == len4) {
|
||
flagY = true
|
||
}
|
||
let xx = (border.StartPoint.m_X + border.EndPoint.m_X) / 2
|
||
let yy = (border.StartPoint.m_Y + border.EndPoint.m_Y) / 2
|
||
if (flagY == false && flagX == false) {
|
||
// 斜的
|
||
direction = -1
|
||
// 获取 上一条边 和下一条边 (忽略弧形 弧线也按照线段处理 不会影响方向的判断)
|
||
let preborderId = sideModel.face - 1
|
||
let nextBorderId = sideModel.face + 1
|
||
|
||
|
||
if (preborderId < 0) {
|
||
preborderId = borders.length - 1
|
||
}
|
||
|
||
if (nextBorderId > borders.length - 1) {
|
||
nextBorderId = 0
|
||
}
|
||
|
||
let preborder = borders[preborderId]
|
||
let nextborder = borders[nextBorderId]
|
||
|
||
|
||
|
||
let preX = preborder.StartPoint.m_X - preborder.EndPoint.m_X
|
||
let preY = preborder.StartPoint.m_Y - preborder.EndPoint.m_Y
|
||
|
||
let nextX = nextborder.StartPoint.m_X - nextborder.EndPoint.m_X
|
||
let nextY = nextborder.StartPoint.m_Y - nextborder.EndPoint.m_Y
|
||
|
||
if (preX == 0) {
|
||
// 上下
|
||
if (preY > 0) {
|
||
// 向下
|
||
preFlag = 'toDown'
|
||
} else if (preY < 0) {
|
||
// 向上
|
||
preFlag = 'toUp'
|
||
}
|
||
}
|
||
|
||
if (preY == 0) {
|
||
// 左右
|
||
if (preX > 0) {
|
||
// 向左
|
||
preFlag = 'toLeft'
|
||
} else if (preX < 0) {
|
||
// 向右
|
||
preFlag = 'toRight'
|
||
}
|
||
}
|
||
|
||
if (nextX == 0) {
|
||
// 上下
|
||
if (nextY > 0) {
|
||
// 向下
|
||
nextFlag = 'toDown'
|
||
} else if (nextY < 0) {
|
||
// 向上
|
||
nextFlag = 'toUp'
|
||
}
|
||
}
|
||
|
||
if (nextY == 0) {
|
||
// 左右
|
||
if (nextX > 0) {
|
||
// 向左
|
||
nextFlag = 'toLeft'
|
||
} else if (nextX < 0) {
|
||
// 向右
|
||
nextFlag = 'toRight'
|
||
}
|
||
}
|
||
// 理论只有下面的情况 不符合的都是异常情况 或者不存在的情况
|
||
switch (preFlag) {
|
||
case 'toDown':
|
||
if (nextFlag == 'toLeft') {
|
||
// 造型在 右下斜面
|
||
direction = 11
|
||
} else if (nextFlag == 'toRight') {
|
||
// 造型在 左下斜面
|
||
direction = 10
|
||
}
|
||
break;
|
||
case 'toRight':
|
||
if (nextFlag == 'toUp') {
|
||
// 造型在 右下斜面
|
||
direction = 11
|
||
} else if (nextFlag == 'toDown') {
|
||
// 造型在 右上斜面
|
||
direction = 12
|
||
}
|
||
break;
|
||
case 'toUp':
|
||
if (nextFlag == 'toLeft') {
|
||
// 造型在 右上斜面
|
||
direction = 12
|
||
} else if (nextFlag == 'toRight') {
|
||
// 造型在 左上斜面
|
||
direction = 13
|
||
}
|
||
break;
|
||
case 'toLeft':
|
||
if (nextFlag == 'toUp') {
|
||
// 造型在 左下斜面
|
||
direction = 10
|
||
|
||
} else if (nextFlag == 'toDown') {
|
||
// 造型在 左上斜面
|
||
direction = 13
|
||
}
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
|
||
} else if (flagX == true) {
|
||
// 上下
|
||
|
||
const p1 = { x: xx, y: yy - 1 }
|
||
const p2 = { x: xx, y: yy + 1 }
|
||
const isTop = isPointInPolygon(p1, polygon)
|
||
if (isTop) {
|
||
direction = 2
|
||
} else {
|
||
const isBottom = isPointInPolygon(p2, polygon)
|
||
if (isBottom) {
|
||
direction = 0
|
||
}
|
||
if (direction == -2) {
|
||
|
||
}
|
||
}
|
||
|
||
|
||
} else if (flagY == true) {
|
||
// 左右
|
||
const p3 = { x: xx - 1, y: yy }
|
||
const p4 = { x: xx + 1, y: yy }
|
||
const isRight = isPointInPolygon(p3, polygon)
|
||
if (isRight) {
|
||
direction = 1
|
||
} else {
|
||
const isLeft = isPointInPolygon(p4, polygon)
|
||
if (isLeft) {
|
||
direction = 3
|
||
}
|
||
|
||
if (direction == -2) {
|
||
|
||
}
|
||
}
|
||
|
||
|
||
}
|
||
|
||
|
||
const directionRes = {
|
||
direction, preFlag, nextFlag
|
||
}
|
||
|
||
return directionRes
|
||
}
|
||
/** 判断 点 是否在轮廓内 射线法 */
|
||
export function isPointInPolygon(point, polygon) {
|
||
const x = point.x;
|
||
const y = point.y;
|
||
let inside = false;
|
||
|
||
for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
|
||
const xi = polygon[i].x;
|
||
const yi = polygon[i].y;
|
||
const xj = polygon[j].x;
|
||
const yj = polygon[j].y;
|
||
|
||
// 检查点是否位于当前边的水平线上
|
||
const intersect = ((yi > y) != (yj > y)) &&
|
||
(x < (xj - xi) * (y - yi) / (yj - yi) + xi);
|
||
if (intersect) inside = !inside;
|
||
}
|
||
|
||
return inside;
|
||
}
|
||
|
||
export function createSideModelRealKnifePoints(block: PlaceBlock, sideModel: SideModel) {
|
||
let directionRes = getModelDirection(block, sideModel)
|
||
|
||
// 确定 轮廓的中点
|
||
let x = { min: 0, max: 0 }
|
||
let y = { min: 0, max: 0 }
|
||
let z = { min: 0, max: 0 }
|
||
sideModel.pointList.forEach((p, i) => {
|
||
if (i == 0) {
|
||
x.min = p.pointX
|
||
x.max = p.pointX
|
||
|
||
y.min = p.pointY
|
||
y.max = p.pointY
|
||
|
||
z.min = p.pointZ
|
||
z.max = p.pointZ
|
||
} else {
|
||
x.min = Math.min(x.min, p.pointX)
|
||
x.max = Math.max(x.max, p.pointX)
|
||
|
||
y.min = Math.min(y.min, p.pointY)
|
||
y.max = Math.max(y.max, p.pointY)
|
||
|
||
z.min = Math.min(z.min, p.pointZ)
|
||
z.max = Math.max(z.max, p.pointZ)
|
||
}
|
||
});
|
||
|
||
let centerPoint = {
|
||
x: (x.min + x.max) / 2,
|
||
y: (y.min + y.max) / 2,
|
||
z: (z.min + z.max) / 2
|
||
}
|
||
|
||
|
||
|
||
if (equal(sideModel.realKnifeRadius, sideModel.knifeRadius)) {
|
||
let realPointList: any = [];
|
||
if (directionRes.direction == 0 || directionRes.direction == 2) {
|
||
let tempPoints: any = []
|
||
|
||
sideModel.pointList.forEach((p) => {
|
||
tempPoints.push({ x: p.pointY, y: p.pointZ })
|
||
})
|
||
var newPointList = shrinkRectangle(tempPoints, centerPoint.y, centerPoint.z, sideModel.realKnifeRadius)
|
||
|
||
realPointList = sideModel.pointList.map((point, i) => {
|
||
let temp = JSON.parse(JSON.stringify(point))
|
||
temp.pointY = newPointList[i].x
|
||
temp.pointZ = newPointList[i].y
|
||
return temp
|
||
})
|
||
} else if (directionRes.direction == 1 || directionRes.direction == 3) {
|
||
let tempPoints: any = []
|
||
sideModel.pointList.forEach(p => {
|
||
tempPoints.push({ x: p.pointX, y: p.pointZ })
|
||
|
||
})
|
||
var newPointList = shrinkRectangle(tempPoints, centerPoint.x, centerPoint.z, sideModel.realKnifeRadius)
|
||
realPointList = sideModel.pointList.map((point, i) => {
|
||
let temp = JSON.parse(JSON.stringify(point))
|
||
temp.pointX = newPointList[i].x
|
||
temp.pointZ = newPointList[i].y
|
||
return temp
|
||
})
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
// 刀路 向内铣
|
||
/**
|
||
* 得到 点阵 向内缩小的 新的点阵
|
||
* @param points 点阵
|
||
* @param centerX 造型的中心点x
|
||
* @param centerY 造型的中心点y
|
||
* @param shrinkAmount 向内的偏移量
|
||
* @returns
|
||
*/
|
||
function shrinkRectangle(points, centerX, centerY, shrinkAmount) {
|
||
return points.map(point => {
|
||
// 计算到中心点的偏移量
|
||
const dx = point.x - centerX;
|
||
const dy = point.y - centerY;
|
||
|
||
|
||
|
||
// 为了避免除以0的错误和保持简单性,我们可以使用下面的方法:
|
||
// 如果dx或dy的绝对值小于shrinkAmount的一半,则将其设置为0(即该点保持在中心点上或非常接近)。
|
||
// 否则,我们按照比例减少dx和dy。
|
||
const absDx = Math.abs(dx);
|
||
const absDy = Math.abs(dy);
|
||
const halfShrink = shrinkAmount;
|
||
const newDx = (absDx > halfShrink) ? dx - (Math.sign(dx) * halfShrink) : 0;
|
||
const newDy = (absDy > halfShrink) ? dy - (Math.sign(dy) * halfShrink) : 0;
|
||
|
||
return {
|
||
x: centerX + newDx,
|
||
y: centerY + newDy
|
||
};
|
||
});
|
||
}
|
||
|
||
// 刀路 向外铣
|
||
/**
|
||
* 得到 点阵 向外放大的 新的点阵
|
||
* @param points 点坐标
|
||
* @param centerX 造型的中心点x
|
||
* @param centerY 造型的中心点y
|
||
* @param expansionAmount 向外的偏移量
|
||
* @returns
|
||
*/
|
||
function expandRectangleCorrect(points, centerX, centerY, expansionAmount) {
|
||
const halfExpansion = expansionAmount; // 在本例中,这将是0.5
|
||
return points.map(point => ({
|
||
// 只加一次halfExpansion,因为我们在两个方向上都会加。
|
||
x: centerX + (point.x - centerX) + halfExpansion,
|
||
y: centerY + (point.y - centerY) + halfExpansion
|
||
}));
|
||
|
||
}
|
||
|
||
/** 造型轮廓(含封边),扣除封边, 变成开料坐标 */
|
||
export function resetModelContour(bd: PlaceBlockDetail) {
|
||
let ox = bd.offsetX
|
||
let oy = bd.offsetY
|
||
for (let m of bd.models) {
|
||
if (m.hasContour()) {
|
||
let ptsArr = m.originModeling.outline.map(e => e.pts)
|
||
for (let pt of ptsArr) {
|
||
// 23.8.5 发现矩形的挖穿轮廓坐标是不含封边的
|
||
pt.x -= ox
|
||
pt.y -= oy
|
||
}
|
||
}
|
||
}
|
||
}
|
||
export function resetModelKnife(block: PlaceBlock, toolsHelper:ToolsHelper, isUseOffset?: boolean) {
|
||
let _isUseOffset = false
|
||
if (isUseOffset) {
|
||
_isUseOffset = isUseOffset
|
||
}
|
||
let processModelIdList: number[] = [];
|
||
// console.log(block)
|
||
for (let m_i = 0; m_i < block.blockDetail.models.length; m_i++) {
|
||
let model = block.blockDetail.models[m_i]
|
||
|
||
if (model.isVKnifeModel())
|
||
continue // 二维刀路 不处理
|
||
// if (model.realKnifeRadius != 0)
|
||
// continue // 已处理
|
||
let knife = toolsHelper.getKnifeByParams({knifeName : model.knifeName}) //sysConfig.getModelKnife(model)
|
||
if (knife == null) {
|
||
model.realKnifeRadius = -1
|
||
}
|
||
else {
|
||
model.realKnifeRadius = knife.diameter / 2
|
||
model.realKnifeId = knife.knifeId
|
||
// 修复问题 如果是弧线的情况下 出现 弧线生成异常
|
||
let checkIsOk = true
|
||
for (const p of model.pointList) {
|
||
if ((p.curve != 0 && p.radius == 0) || (p.radius != 0 && p.curve == 0)) {
|
||
checkIsOk = false
|
||
break
|
||
}
|
||
}
|
||
|
||
if (equal(model.realKnifeRadius, model.knifeRadius) && checkIsOk) {
|
||
model.realPointList = model.pointList
|
||
}
|
||
else {
|
||
model.originModeling.knifeRadius = knife.diameter / 2
|
||
model.originModeling.thickness = model.depth
|
||
model.originModeling.brThickness = block.thickness
|
||
model.originModeling.boardContour = getOrgContour()
|
||
|
||
let newData: any = null
|
||
if (model.originModeling && Array.isArray(model.originModeling.outline)) {
|
||
newData = JSON.parse(JSON.stringify(model.originModeling))
|
||
let newOutLine = { pts: newData.outline.map(e => e.pts), buls: newData.outline.map(e => e.buls) }
|
||
let newHoles = newData?.holes?.map(x => { return { pts: x.map(e => e.pts), buls: x.map(e => e.buls) } })
|
||
newData.outline = newOutLine
|
||
newData.holes = newHoles || []
|
||
} else {
|
||
newData = model.originModeling
|
||
}
|
||
|
||
let custborders: any = []
|
||
|
||
try {
|
||
if (model.originModeling.outline) {
|
||
custborders = Production.GetChaiDanFeedingPath(newData, 0)
|
||
}
|
||
} catch (error) {
|
||
console.error(error, block.blockNo, model.modelId, model);
|
||
}
|
||
let offx = _isUseOffset ? block.offsetX() : 0// block.OffsetX;
|
||
let offy = _isUseOffset ? block.offsetY() : 0// block.OffsetY;
|
||
let ps1: BlockModelPoint[] = []
|
||
if (custborders.length > 0) {
|
||
let ct = custborders[0]
|
||
|
||
if (processModelIdList.includes(model.modelId)) {
|
||
ct = custborders[model.lineId - 1]
|
||
} else {
|
||
processModelIdList.push(model.modelId)
|
||
}
|
||
if (ct) {
|
||
for (let i = 0; i < ct.buls.length; i++) {
|
||
var r = 0
|
||
if (ct.buls[i] != 0) {
|
||
let j = i + 1
|
||
if (j == ct.buls.length)
|
||
j = 0
|
||
r = CADExt.getR(ct.pts[i].x, ct.pts[i].y, ct.pts[j].x, ct.pts[j].y, ct.buls[i])
|
||
}
|
||
|
||
ps1.push(new BlockModelPoint({ pointX: ct.pts[i].x - offx, pointY: ct.pts[i].y - offy, curve: ct.buls[i], radius: r, depth: model.depth }))
|
||
}
|
||
}
|
||
}
|
||
|
||
if (ps1.length > 0) {
|
||
model.realPointList = ps1
|
||
}
|
||
else {
|
||
model.realKnifeId = -1
|
||
model.realKnifeRadius = -1
|
||
model.realPointList = []
|
||
}
|
||
}
|
||
}
|
||
}
|
||
/** 获取轮廓 */
|
||
function getOrgContour() {
|
||
if (!block.blockDetail) {
|
||
console.error('resetModelKnife=>getOrgContour: blockDetail is undefind')
|
||
return
|
||
}
|
||
if (!block.blockDetail.orgContourData) {
|
||
let pts: any = []
|
||
let buls: any = []
|
||
if (!block.isUnRegular) {
|
||
pts.push({ x: 0, y: 0 })
|
||
pts.push({ x: block.cutWidth, y: 0 })
|
||
pts.push({ x: block.cutWidth, y: block.cutLength })
|
||
pts.push({ x: 0, y: block.cutLength })
|
||
buls.push(0)
|
||
buls.push(0)
|
||
buls.push(0)
|
||
buls.push(0)
|
||
}
|
||
else // 矩形板
|
||
{
|
||
for (let p of block.blockDetail.points) {
|
||
pts.push({ x: p.pointX, y: p.pointY })
|
||
buls.push(p.curve)
|
||
}
|
||
}
|
||
|
||
block.blockDetail.orgContourData = { pts, buls }
|
||
}
|
||
return block.blockDetail.orgContourData
|
||
}
|
||
}
|
||
|
||
export async function resetSideModelKnife(block: PlaceBlock, tools: ToolsHelper) {
|
||
if (!block.blockDetail) {
|
||
console.error('resetModelKnife=>getOrgContour: blockDetail is undefind')
|
||
return
|
||
}
|
||
|
||
for (let model of block.blockDetail.modelListSide) {
|
||
|
||
|
||
let knife = model.knife || tools.getKnifeByParams({ knifeName: model.knifeName })
|
||
if (knife == null) {
|
||
model.realKnifeRadius = -1
|
||
}
|
||
else {
|
||
model.knife = knife
|
||
model.realKnifeRadius = knife.diameter / 2
|
||
model.realKnifeId = knife.knifeId
|
||
|
||
// if(model.pointList.length ==0){
|
||
// await initSideModel(block)
|
||
// }
|
||
|
||
if (equal(model.realKnifeRadius, model.knifeRadius)) {
|
||
model.realPointList = model.pointList
|
||
}
|
||
else {
|
||
|
||
model.originModeling.knifeRadius = knife.diameter / 2
|
||
model.originModeling.thickness = model.depth
|
||
model.originModeling.brThickness = block.thickness
|
||
model.originModeling.boardContour = getOrgContour()
|
||
console.log('侧面造型生成新刀路:', model.modelId, model)
|
||
|
||
let newData: any = null
|
||
|
||
if (model.originModeling && Array.isArray(model.originModeling.outline)) {
|
||
newData = JSON.parse(JSON.stringify(model.originModeling))
|
||
let newOutLine = { pts: newData.outline.map(e => e.pts), buls: newData.outline.map(e => e.buls) }
|
||
let newHoles = newData?.holes?.map(x => { return { pts: x.map(e => e.pts), buls: x.map(e => e.buls) } })
|
||
newData.outline = newOutLine
|
||
newData.holes = newHoles || []
|
||
} else {
|
||
newData = model.originModeling
|
||
}
|
||
|
||
|
||
|
||
let custborders = model.originModeling.outline ? Production.GetChaiDanFeedingPath(newData) : []
|
||
let offx = 0// block.OffsetX;
|
||
let offy = 0// block.OffsetY;
|
||
let ps1: BlockSideModelPoint[] = []
|
||
if (custborders.length > 0) {
|
||
if (custborders.length == 1) {
|
||
let ct = custborders[0]
|
||
model.lineId = 1
|
||
|
||
for (let i = 0; i < ct.buls.length; i++) {
|
||
let r = 0
|
||
if (ct.buls[i] != 0) {
|
||
let j = i + 1
|
||
if (j == ct.buls.length)
|
||
j = 0
|
||
r = CADExt.getR(ct.pts[i].x, ct.pts[i].y, ct.pts[j].x, ct.pts[j].y, ct.buls[i])
|
||
}
|
||
ps1.push(new BlockSideModelPoint({ pointX: ct.pts[i].x - offx, pointY: ct.pts[i].y - offy, pointZ: 0, curve: ct.buls[i], radius: r, depth: model.depth }))
|
||
}
|
||
|
||
// 要处理下坐标
|
||
if (ps1.length > 0) {
|
||
let directionRes = getModelDirection(block, model)
|
||
const borders = block.blockDetail?.borderContour?.borderFinal
|
||
if (!borders) {
|
||
console.error('resetModelKnife=>getOrgContour: blockDetail is undefind')
|
||
return
|
||
}
|
||
const border = borders[model.face]
|
||
let newRealPointList: BlockSideModelPoint[] = []
|
||
for (const linePoint of ps1) {
|
||
let tempPoint = {
|
||
curve: linePoint.buls,
|
||
depth: model.depth,
|
||
radius: 1 / linePoint.buls,
|
||
x: linePoint.pointX || 0,
|
||
y: linePoint.pointY || 0,
|
||
z: linePoint.pointZ || 0,
|
||
}
|
||
let temp = transformSideModelPoint(tempPoint, directionRes, border, model, 'linePoint')
|
||
let sideModelPoint = new BlockSideModelPoint(temp)
|
||
newRealPointList.push(sideModelPoint);
|
||
}
|
||
|
||
model.realPointList = newRealPointList
|
||
}
|
||
else {
|
||
model.realKnifeId = -1
|
||
model.realKnifeRadius = -1
|
||
model.realPointList = []
|
||
}
|
||
} else {
|
||
for (const ct_key in custborders) {
|
||
let tempModel = new SideModel(model)
|
||
ps1 = []
|
||
let ct = custborders[ct_key]
|
||
tempModel.lineId = parseFloat(ct_key) + 1
|
||
|
||
for (let i = 0; i < ct.buls.length; i++) {
|
||
let r = 0
|
||
if (ct.buls[i] != 0) {
|
||
let j = i + 1
|
||
if (j == ct.buls.length)
|
||
j = 0
|
||
r = CADExt.getR(ct.pts[i].x, ct.pts[i].y, ct.pts[j].x, ct.pts[j].y, ct.buls[i])
|
||
}
|
||
ps1.push(new BlockSideModelPoint({ pointX: ct.pts[i].x - offx, pointY: ct.pts[i].y - offy, pointZ: 0, curve: ct.buls[i], radius: r, depth: tempModel.depth }))
|
||
}
|
||
|
||
if (ps1.length > 0) {
|
||
let directionRes = getModelDirection(block, tempModel)
|
||
const borders = block.blockDetail?.borderContour?.borderFinal
|
||
const border = borders[tempModel.face]
|
||
let newRealPointList: BlockSideModelPoint[] = []
|
||
for (const linePoint of ps1) {
|
||
let tempPoint = {
|
||
curve: linePoint.buls,
|
||
depth: tempModel.depth,
|
||
radius: 1 / linePoint.buls,
|
||
x: linePoint.pointX || 0,
|
||
y: linePoint.pointY || 0,
|
||
z: linePoint.pointZ || 0,
|
||
}
|
||
let temp = transformSideModelPoint(tempPoint, directionRes, border, tempModel, 'linePoint')
|
||
let sideModelPoint = new BlockSideModelPoint(temp)
|
||
newRealPointList.push(sideModelPoint);
|
||
}
|
||
|
||
tempModel.realPointList = newRealPointList
|
||
}
|
||
else {
|
||
tempModel.realKnifeId = -1
|
||
tempModel.realKnifeRadius = -1
|
||
tempModel.realPointList = []
|
||
}
|
||
|
||
// 避免拆分的刀路造型 重复插入
|
||
if (block.blockDetail.modelListSide.findIndex(e => e.modelId == tempModel.modelId && e.lineId == tempModel.lineId) == -1) {
|
||
block.blockDetail.modelListSide.push(tempModel)
|
||
} else {
|
||
model = tempModel
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
}
|
||
|
||
}
|
||
}
|
||
/** 获取轮廓 */
|
||
function getOrgContour() {
|
||
if (!block.blockDetail) {
|
||
console.error('resetModelKnife=>getOrgContour: blockDetail is undefind')
|
||
return
|
||
}
|
||
if (!block.blockDetail.orgContourData) {
|
||
let pts: any = []
|
||
let buls: any = []
|
||
if (!block.isUnRegular) {
|
||
pts.push({ x: 0, y: 0 })
|
||
pts.push({ x: block.cutWidth, y: 0 })
|
||
pts.push({ x: block.cutWidth, y: block.cutLength })
|
||
pts.push({ x: 0, y: block.cutLength })
|
||
buls.push(0)
|
||
buls.push(0)
|
||
buls.push(0)
|
||
buls.push(0)
|
||
}
|
||
else // 矩形板
|
||
{
|
||
for (let p of block.blockDetail.points) {
|
||
pts.push({ x: p.pointX, y: p.pointY })
|
||
buls.push(p.curve)
|
||
}
|
||
}
|
||
|
||
block.blockDetail.orgContourData = { pts, buls }
|
||
}
|
||
return block.blockDetail.orgContourData
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
/** 二维刀路初始化 */
|
||
export function init2VModel(blockDetail: PlaceBlockDetail, tools: ToolsHelper, isCNC = false) {
|
||
for (let model of blockDetail.models) {
|
||
if (!model.isVKnifeModel())
|
||
continue
|
||
let vModels: any[] = []
|
||
model.VLines = vModels
|
||
let isFaceB = model.face == FaceType.BACK
|
||
if (model.pointList.length < 1)
|
||
continue
|
||
let ps = model.pointList.map((t) => { return { x: t.pointX, y: t.pointY, bul: t.curve } })
|
||
let pl = PolylineHelper.create(ps)
|
||
if (model.VLines?.length > 0)
|
||
return // 已经分析了
|
||
model.VLines = []
|
||
for (let os of model.offsetList) {
|
||
// 根据刀名称找刀
|
||
let knife1 = isCNC ? null : tools.getKnifeByParams({ knifeName: os.name })
|
||
let knifeR = os.radius
|
||
let knifeId = knife1 ? knife1.knifeId : -1
|
||
try {
|
||
let vps_1 = PolylineHelper.getVModelPoints_offset(pl, os.offset, os.depth, os.angle)
|
||
let vLine = { isFaceB, name: os.name, value: os.offset, knife: knife1, knifeId, knifeRadius: knifeR, depth: os.depth, points: vps_1, offset: os }
|
||
vModels.push(vLine) // 偏移路径
|
||
model.VLines.push(vLine)
|
||
}
|
||
catch (err) {
|
||
console.log('v型刀走刀路径算法出错。' + err)
|
||
}
|
||
}
|
||
model.VLines = vModels
|
||
}
|
||
}
|
||
|
||
/** 异形板 封边值 */
|
||
export function resetBorderValue(block: PlaceBlock) {
|
||
if (!block.blockDetail) {
|
||
console.error('resetBorderValue: blockDetail is undefind')
|
||
return
|
||
}
|
||
if (block.isUnRegular) {
|
||
block.cutWidth = block.blockDetail.cutWidth
|
||
block.cutLength = block.blockDetail.cutLength
|
||
}
|
||
|
||
block.blockDetail.cutWidth = block.cutWidth
|
||
block.blockDetail.cutLength = block.cutLength
|
||
|
||
if (block.isUnRegular == false)
|
||
return
|
||
|
||
// 计算异形板 的上下左右 封边值
|
||
block.sealLeft = getSealEdge('LEFT')
|
||
block.sealRight = getSealEdge('RIGHT')
|
||
block.sealTop = getSealEdge('TOP')
|
||
block.sealBottom = getSealEdge('BOTTOM')
|
||
|
||
function getSealEdge(sealEdge) {
|
||
let closetP
|
||
let dis = 1000000
|
||
for (let i = 0; i < block.orgPoints.length; i++) {
|
||
let p0 = block.orgPoints[i]
|
||
let p1 = i == block.orgPoints.length - 1 ? block.orgPoints[0] : block.orgPoints[i + 1]
|
||
|
||
if (sealEdge == 'LEFT') {
|
||
if (equal(p0.pointX, 0) && equal(p1.pointX, 0))
|
||
return p0.sealSize
|
||
let dis_t = (p0.pointX + p1.pointX) * 0.5
|
||
if (dis_t < dis) {
|
||
closetP = p0
|
||
dis = dis_t
|
||
}
|
||
}
|
||
if (sealEdge == 'RIGHT') {
|
||
if (equal(p0.pointX, block.width) && equal(p1.pointX, block.width))
|
||
return p0.sealSize
|
||
let dis_t = (p0.pointX + p1.pointX) * 0.5
|
||
if (block.width - dis_t < dis) {
|
||
closetP = p0
|
||
dis = block.width - dis_t
|
||
}
|
||
}
|
||
if (sealEdge == 'TOP') {
|
||
if (equal(p0.pointY, block.length) && equal(p1.pointY, block.length))
|
||
return p0.sealSize
|
||
let dis_t = (p0.pointY + p1.pointY) * 0.5
|
||
if (block.length - dis_t < dis) {
|
||
closetP = p0
|
||
dis = dis_t
|
||
}
|
||
}
|
||
if (sealEdge == 'BOTTOM') {
|
||
if (equal(p0.pointY, 0) && equal(p1.pointY, 0))
|
||
return p0.sealSize
|
||
let dis_t = (p0.pointY + p1.pointY) * 0.5
|
||
if (dis_t < dis) {
|
||
closetP = p0
|
||
dis = dis_t
|
||
}
|
||
}
|
||
}
|
||
// 找最接近边的点
|
||
return closetP ? closetP.sealSize : 0
|
||
}
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
* 设置小板是否反面排版优化
|
||
* @param block 小板
|
||
* @param processMode 加工模式(0开料机(雕刻机)加工 1开料机CNC组合 2定制加工)
|
||
*/
|
||
export function setFaceToPlace(block: PlaceBlock, config) {
|
||
// let processMode = 0;
|
||
// if(sys.isCutProcess) processMode = 0;
|
||
// if(sys.isCutAndCNCProcess) processMode = 1;
|
||
// if(sys.isCustomized) processMode = 2;
|
||
const {
|
||
processMode = 0
|
||
} = config
|
||
block.isTurnFaceToPlace = !getDoFace(block, processMode)
|
||
}
|
||
|
||
|