feat:提交
This commit is contained in:
238
tests/dev1/dataHandle/common/core/ParseOddments.ts
Normal file
238
tests/dev1/dataHandle/common/core/ParseOddments.ts
Normal file
@@ -0,0 +1,238 @@
|
||||
import { ClipType, EndType, JoinType, PolyFillType } from 'js-angusj-clipper/web'
|
||||
import type { ClipInput } from 'js-angusj-clipper/web'
|
||||
import { Box2 } from '..//Box2'
|
||||
import { clipperCpp } from '../ClipperCpp'
|
||||
import type { Container } from './Container'
|
||||
import { NestCache } from './NestCache'
|
||||
import { Path, PathScale, TranslatePath, TranslatePath_Self } from './Path'
|
||||
|
||||
const SquarePath = NestCache.CreatePath(60, 60, 0)
|
||||
const CanPutPaths = [
|
||||
NestCache.CreatePath(200, 200, 0),
|
||||
NestCache.CreatePath(600, 100, 0),
|
||||
NestCache.CreatePath(100, 600, 0),
|
||||
]
|
||||
|
||||
/**
|
||||
* 分析排料结果的余料
|
||||
* @param container 排料结果的容器
|
||||
* @param binPath 容器的bin
|
||||
* @param [knifeRadius] 刀半径(以便我们再次偏移)
|
||||
* @param squarePath 使用一个正方形路径来简化余料轮廓
|
||||
* @param canPutPaths 使用可以放置的路径列表来测试余料是否可用,如果可用,则保留
|
||||
* @returns Path[] 轮廓的位置存储在OrigionMinPoint中
|
||||
*/
|
||||
export function ParseOddments(container: Container, binPath: Path, knifeRadius: number = 3.5, squarePath: Path = SquarePath, canPutPaths: Path[] = CanPutPaths): Path[]
|
||||
{
|
||||
// 构建轮廓数据
|
||||
let partPaths: ClipInput[] = container.PlacedParts.map((part) =>
|
||||
{
|
||||
// 直接在这里偏移,而不缓存,应该没有性能问题
|
||||
let newPts = clipperCpp.lib.offsetToPaths({
|
||||
delta: knifeRadius * 1e4,
|
||||
offsetInputs: [{ data: part.State.Contour.BigIntPoints, joinType: JoinType.Miter, endType: EndType.ClosedPolygon }],
|
||||
})[0]
|
||||
|
||||
let path = TranslatePath(newPts, { x: part.PlacePosition.x - 5e3, y: part.PlacePosition.y - 5e3 })// 因为移动了0.5,0.5,所以这里也要移动0.5
|
||||
return { data: path }
|
||||
})
|
||||
// console.log('构建轮廓数据', partPaths)
|
||||
// 所有的余料(使用布尔差集)
|
||||
let oddmentsPolygon = clipperCpp.lib.clipToPolyTree({
|
||||
subjectInputs: [{ data: binPath.BigIntPoints, closed: true }],
|
||||
clipInputs: partPaths,
|
||||
clipType: ClipType.Difference,
|
||||
subjectFillType: PolyFillType.NonZero,
|
||||
})
|
||||
|
||||
// 现在我们用树状结构,应该不会自交了?(文档写了,返回的结果不可能重叠或者自交)
|
||||
// 简化结果,避免自交
|
||||
// oddmentsPolygon = clipperCpp.lib.simplifyPolygons(oddmentsPolygon);
|
||||
|
||||
function CreatePolygon(minx: number, miny: number, maxx: number, maxy: number)
|
||||
{
|
||||
return [
|
||||
{ x: minx, y: miny },
|
||||
{ x: maxx, y: miny },
|
||||
{ x: maxx, y: maxy },
|
||||
{ x: minx, y: maxy },
|
||||
]
|
||||
}
|
||||
|
||||
let clipedPaths: Path[] = []// 已经减去网洞投影的余料轮廓列表
|
||||
|
||||
// 由于手动排版可能造成余料网洞,我们将网洞的盒子投影,然后裁剪余料,避免余料有网洞
|
||||
for (let node of oddmentsPolygon.childs)
|
||||
{
|
||||
let nodePolygon = node.contour
|
||||
// 减去网洞
|
||||
if (node.childs.length)
|
||||
{
|
||||
let box = new Box2().setFromPoints(nodePolygon)
|
||||
|
||||
let childBoxPolygon = node.childs.map((cnode) =>
|
||||
{
|
||||
let cbox = new Box2().setFromPoints(cnode.contour)
|
||||
let type = 0// 0左1右2上3下
|
||||
let minDist = Number.POSITIVE_INFINITY
|
||||
|
||||
let letftDist = cbox.min.x - box.min.x
|
||||
let rightDist = box.max.x - cbox.max.x
|
||||
let topDist = box.max.y - cbox.max.y
|
||||
let downDist = cbox.min.y - box.min.y
|
||||
|
||||
if (rightDist < letftDist)
|
||||
{
|
||||
type = 1
|
||||
minDist = rightDist
|
||||
}
|
||||
|
||||
if (topDist < minDist)
|
||||
{
|
||||
type = 2
|
||||
minDist = topDist
|
||||
}
|
||||
|
||||
if (downDist < minDist)
|
||||
type = 3
|
||||
|
||||
if (type === 0)
|
||||
return CreatePolygon(box.min.x, cbox.min.y, cbox.max.x, cbox.max.y)
|
||||
if (type === 1)
|
||||
return CreatePolygon(cbox.min.x, cbox.min.y, box.max.x, cbox.max.y)
|
||||
if (type === 2)
|
||||
return CreatePolygon(cbox.min.x, cbox.min.y, cbox.max.x, box.max.y)
|
||||
if (type === 3)
|
||||
return CreatePolygon(cbox.min.x, box.min.y, cbox.max.x, cbox.max.y)
|
||||
})
|
||||
|
||||
let splits = clipperCpp.lib.clipToPaths({
|
||||
subjectInputs: [{ data: nodePolygon, closed: true }],
|
||||
clipInputs: childBoxPolygon.map((polygon) => { return { data: polygon } }),
|
||||
clipType: ClipType.Difference,
|
||||
subjectFillType: PolyFillType.NonZero,
|
||||
})
|
||||
|
||||
for (let p of splits)
|
||||
clipedPaths.push(new Path(PathScale(p, 1e-4)))
|
||||
}
|
||||
else
|
||||
clipedPaths.push(new Path(node.contour.map((p) => { return { x: p.x * 1e-4, y: p.y * 1e-4 } })))
|
||||
}
|
||||
|
||||
let OddmentsPaths: Path[] = []
|
||||
for (let polygonPath of clipedPaths)
|
||||
{
|
||||
// 先获取内部的nfp
|
||||
let insideNFPS = polygonPath.GetInsideNFP(squarePath)
|
||||
|
||||
if (!insideNFPS)
|
||||
continue
|
||||
|
||||
let beferPolygons: ClipInput[] = []
|
||||
|
||||
for (let nfp of insideNFPS)
|
||||
{
|
||||
let nfpPath = new Path(PathScale(nfp, 1e-4))
|
||||
// 通过内部nfp还原实际轮廓
|
||||
let sumPolygons = clipperCpp.lib.minkowskiSumPath(nfpPath.BigIntPoints, squarePath.BigIntPoints, true)
|
||||
sumPolygons = clipperCpp.lib.simplifyPolygons(sumPolygons)
|
||||
|
||||
for (let poly of sumPolygons)
|
||||
{
|
||||
if (clipperCpp.lib.area(poly) < 0)
|
||||
continue// 移除内部的,无意义的
|
||||
|
||||
let tempPath = new Path(poly.map((p) => { return { x: p.x * 1e-4, y: p.y * 1e-4 } }))// 这里new一个新的,下面就复用这个
|
||||
if (canPutPaths.some(p => tempPath.GetInsideNFP(p)?.length))// 能塞的下指定的轮廓才会被留下
|
||||
{
|
||||
if (beferPolygons.length)
|
||||
{
|
||||
// 移动到实际位置
|
||||
TranslatePath_Self(poly, (polygonPath.OrigionMinPoint.x + nfpPath.OrigionMinPoint.x) * 1e4, (polygonPath.OrigionMinPoint.y + nfpPath.OrigionMinPoint.y) * 1e4)
|
||||
|
||||
// 在这里裁剪之前的余料轮廓
|
||||
let tree = clipperCpp.lib.clipToPolyTree({
|
||||
subjectInputs: [{ data: poly, closed: true }],
|
||||
clipInputs: beferPolygons,
|
||||
clipType: ClipType.Difference,
|
||||
subjectFillType: PolyFillType.NonZero,
|
||||
})
|
||||
|
||||
for (let node of tree.childs)
|
||||
{
|
||||
if (node.childs.length)
|
||||
continue
|
||||
|
||||
tempPath = new Path(node.contour.map((p) => { return { x: p.x * 1e-4, y: p.y * 1e-4 } }))
|
||||
|
||||
// 继续简化
|
||||
tempPath = SimplifyPathOfSqPath(tempPath, squarePath)
|
||||
|
||||
if (!tempPath)
|
||||
continue
|
||||
|
||||
OddmentsPaths.push(tempPath)
|
||||
|
||||
// 偏移2把刀
|
||||
let offsetedPolygon = clipperCpp.lib.offsetToPaths({
|
||||
delta: knifeRadius * 2e4,
|
||||
offsetInputs: [{ data: node.contour, joinType: JoinType.Miter, endType: EndType.ClosedPolygon }],
|
||||
})[0]
|
||||
beferPolygons.push({ data: offsetedPolygon })// 用于裁剪后续的余料
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 设置轮廓的位置
|
||||
tempPath.OrigionMinPoint.x += nfpPath.OrigionMinPoint.x + polygonPath.OrigionMinPoint.x
|
||||
tempPath.OrigionMinPoint.y += nfpPath.OrigionMinPoint.y + polygonPath.OrigionMinPoint.y
|
||||
OddmentsPaths.push(tempPath)
|
||||
|
||||
// 将余料轮廓加入到裁剪轮廓中,用于裁剪后续的余料
|
||||
if (insideNFPS.length)
|
||||
{
|
||||
// 移动到实际位置
|
||||
TranslatePath_Self(poly, (polygonPath.OrigionMinPoint.x + nfpPath.OrigionMinPoint.x) * 1e4, (polygonPath.OrigionMinPoint.y + nfpPath.OrigionMinPoint.y) * 1e4)
|
||||
// 偏移2把刀
|
||||
let offsetedPolygon = clipperCpp.lib.offsetToPaths({
|
||||
delta: knifeRadius * 2e4,
|
||||
offsetInputs: [{ data: poly, joinType: JoinType.Miter, endType: EndType.ClosedPolygon }],
|
||||
})[0]
|
||||
beferPolygons.push({ data: offsetedPolygon })// 用于裁剪后续的余料
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// console.log('ParseOddments end', OddmentsPaths)
|
||||
return OddmentsPaths
|
||||
}
|
||||
|
||||
// 使用矩形轮廓来简化余料轮廓(通常一进一出)
|
||||
function SimplifyPathOfSqPath(polygonPath: Path, sqPath: Path): Path | undefined
|
||||
{
|
||||
// 先获取内部的nfp
|
||||
let insideNFPS = polygonPath.GetInsideNFP(sqPath)
|
||||
if (insideNFPS.length > 0)// 目前一般只有1个,不知道会不会有多个
|
||||
{
|
||||
let nfp = insideNFPS[0]
|
||||
let nfpPath = new Path(PathScale(nfp, 1e-4))
|
||||
// 通过内部nfp还原实际轮廓
|
||||
let sumPolygons = clipperCpp.lib.minkowskiSumPath(nfpPath.BigIntPoints, sqPath.BigIntPoints, true)
|
||||
sumPolygons = clipperCpp.lib.simplifyPolygons(sumPolygons)
|
||||
|
||||
for (let poly of sumPolygons)// 通常是一个内部的+一个外部的
|
||||
{
|
||||
if (clipperCpp.lib.area(poly) < 0)
|
||||
continue// 移除内部的,无意义的
|
||||
|
||||
let tempPath = new Path(PathScale(poly, 1e-4))
|
||||
|
||||
tempPath.OrigionMinPoint.x += nfpPath.OrigionMinPoint.x + polygonPath.OrigionMinPoint.x
|
||||
tempPath.OrigionMinPoint.y += nfpPath.OrigionMinPoint.y + polygonPath.OrigionMinPoint.y
|
||||
return tempPath
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user