mirror of https://gitee.com/cf-fz/WebCAD.git
!1407 功能:前置余料和余料自动分析
parent
5cd43ff1c0
commit
b7e635625a
@ -1,33 +1,45 @@
|
||||
import { Vector3 } from "three";
|
||||
import { ClipType, PolyFillType } from "js-angusj-clipper/web";
|
||||
import { Vector2 } from "three";
|
||||
import { app } from "../../ApplicationServices/Application";
|
||||
import { EntityRef } from "../../DatabaseServices/Entity/EntityRef";
|
||||
import { Polyline } from "../../DatabaseServices/Entity/Polyline";
|
||||
import { Command } from "../../Editor/CommandMachine";
|
||||
import { PromptStatus } from "../../Editor/PromptResult";
|
||||
import { HotCMD } from "../../Hot/HotCommand";
|
||||
import { clipperCpp, InitClipperCpp } from "../../Nest/Common/ClipperCpp";
|
||||
import { Path2Polyline } from "../../Nest/Converter/Path2Polyline";
|
||||
import { PathScale } from "../../Nest/Core/Path";
|
||||
import { TestDraw } from "../test/TestUtil";
|
||||
|
||||
@HotCMD
|
||||
export class Test implements Command
|
||||
{
|
||||
async exec()
|
||||
{
|
||||
for (let i = 1; i < 6; i++)
|
||||
{
|
||||
let e = new EntityRef("/Data/ASSETS/DXAA_000" + i);
|
||||
e.Position = new Vector3((i - 1) * 5000);
|
||||
app.Database.ModelSpace.Append(e);
|
||||
}
|
||||
let promise = InitClipperCpp();
|
||||
|
||||
for (let i = 1; i < 98; i++)
|
||||
{
|
||||
let e = new EntityRef("/Data/ASSETS/DZAA_000" + i);
|
||||
e.Position = new Vector3((i - 1) * 5000, 3000);
|
||||
app.Database.ModelSpace.Append(e);
|
||||
}
|
||||
let plss = await app.Editor.GetSelection({ Filter: { filterTypes: [Polyline] } });
|
||||
if (plss.Status !== PromptStatus.OK) return;
|
||||
|
||||
let pls = plss.SelectSet.SelectEntityList as Polyline[];
|
||||
|
||||
let bin = pls.shift();
|
||||
|
||||
|
||||
await promise;
|
||||
|
||||
let finalNfp = clipperCpp.lib.clipToPaths({
|
||||
subjectInputs: [{ data: PathScale(bin.GetStretchPoints(), 1e4), closed: true }],
|
||||
clipInputs: pls.map(pl => { return { data: PathScale(pl.GetStretchPoints(), 1e4) }; }),
|
||||
clipType: ClipType.Difference,
|
||||
subjectFillType: PolyFillType.NonZero
|
||||
});
|
||||
|
||||
finalNfp = clipperCpp.lib.simplifyPolygons(finalNfp);
|
||||
|
||||
for (let i = 1; i < 67; i++)
|
||||
for (let nfp of finalNfp)
|
||||
{
|
||||
let e = new EntityRef("/Data/ASSETS/DYAA_000" + i);
|
||||
e.Position = new Vector3((i - 1) * 5000, 5000);
|
||||
app.Database.ModelSpace.Append(e);
|
||||
let pl = Path2Polyline(nfp.map(p => new Vector2(p.x * 1e-4, p.y * 1e-4)));
|
||||
TestDraw(pl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,80 @@
|
||||
import { ClipInput, ClipType, EndType, JoinType, PolyFillType } from "js-angusj-clipper/web";
|
||||
import { clipperCpp } from "../Common/ClipperCpp";
|
||||
import { Container } from "./Container";
|
||||
import { NestCache } from "./NestCache";
|
||||
import { Path, PathScale, TranslatePath } 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=3.5] 刀半径(以便我们再次偏移)
|
||||
* @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 };
|
||||
});
|
||||
|
||||
//所有的余料(使用布尔差集)
|
||||
let oddmentsPolygon = clipperCpp.lib.clipToPaths({
|
||||
subjectInputs: [{ data: binPath.BigIntPoints, closed: true }],
|
||||
clipInputs: partPaths,
|
||||
clipType: ClipType.Difference,
|
||||
subjectFillType: PolyFillType.NonZero
|
||||
});
|
||||
|
||||
//简化结果,避免自交
|
||||
oddmentsPolygon = clipperCpp.lib.simplifyPolygons(oddmentsPolygon);
|
||||
|
||||
let OddmentsPaths: Path[] = [];
|
||||
for (let polygon of oddmentsPolygon)
|
||||
{
|
||||
let polygonPath = new Path(PathScale(polygon, 1e-4));
|
||||
//先获取内部的nfp
|
||||
let insideNFPS = polygonPath.GetInsideNFP(squarePath);
|
||||
|
||||
if (!insideNFPS) continue;
|
||||
|
||||
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(PathScale(poly, 1e-4));
|
||||
if (canPutPaths.some(p => tempPath.GetInsideNFP(p)?.length))//能塞的下制定的轮廓才会被留下
|
||||
{
|
||||
//设置轮廓的位置
|
||||
tempPath.OrigionMinPoint.x += nfpPath.OrigionMinPoint.x + polygonPath.OrigionMinPoint.x;
|
||||
tempPath.OrigionMinPoint.y += nfpPath.OrigionMinPoint.x + polygonPath.OrigionMinPoint.x;
|
||||
OddmentsPaths.push(tempPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return OddmentsPaths;
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
import { TestDraw } from "../../Add-on/test/TestUtil";
|
||||
import { app } from "../../ApplicationServices/Application";
|
||||
import { Polyline } from "../../DatabaseServices/Entity/Polyline";
|
||||
import { Command } from "../../Editor/CommandMachine";
|
||||
import { PromptStatus } from "../../Editor/PromptResult";
|
||||
import { AsVector3 } from "../../Geometry/GeUtils";
|
||||
import { clipperCpp, InitClipperCpp } from "../Common/ClipperCpp";
|
||||
import { Path2Polyline } from "../Converter/Path2Polyline";
|
||||
import { NestCache } from "../Core/NestCache";
|
||||
import { Path, PathScale } from "../Core/Path";
|
||||
|
||||
let sqPath = NestCache.CreatePath(60, 60, 0);
|
||||
|
||||
let paths = [
|
||||
NestCache.CreatePath(200, 200, 0),
|
||||
NestCache.CreatePath(600, 100, 0),
|
||||
NestCache.CreatePath(100, 600, 0)
|
||||
];
|
||||
|
||||
|
||||
export class Command_TestSimplyOddments implements Command
|
||||
{
|
||||
async exec()
|
||||
{
|
||||
let promise = InitClipperCpp();
|
||||
let plsRes = await app.Editor.GetSelection({
|
||||
Msg: "选择多段线",
|
||||
Filter: {
|
||||
filterTypes: [Polyline]
|
||||
}
|
||||
});
|
||||
|
||||
if (plsRes.Status !== PromptStatus.OK) return;
|
||||
await promise;
|
||||
|
||||
let pls = plsRes.SelectSet.SelectEntityList as Polyline[];
|
||||
|
||||
for (let pl of pls)
|
||||
{
|
||||
let path = new Path(pl.GetStretchPoints(), 0);
|
||||
|
||||
let insideNFPS = path.GetInsideNFP(sqPath);
|
||||
if (insideNFPS)
|
||||
for (let nfp of insideNFPS)
|
||||
{
|
||||
let pts = PathScale(nfp, 1e-4);
|
||||
let pl2 = Path2Polyline(pts);
|
||||
pl2.Position = pl.BoundingBox.min;
|
||||
// TestDraw(pl2, 1);
|
||||
|
||||
let nfpPath = new Path(pts);
|
||||
//还原正确的轮廓
|
||||
let sum = clipperCpp.lib.minkowskiSumPath(nfpPath.BigIntPoints, sqPath.BigIntPoints, true);
|
||||
sum = clipperCpp.lib.simplifyPolygons(sum);
|
||||
|
||||
for (let poly of sum)
|
||||
{
|
||||
if (clipperCpp.lib.area(poly) < 0) continue;
|
||||
|
||||
let pts = PathScale(poly, 1e-4);
|
||||
|
||||
let tempPath = new Path(pts);
|
||||
if (paths.some(p => tempPath.GetInsideNFP(p)?.length))
|
||||
{
|
||||
let pl = Path2Polyline(pts);
|
||||
pl.Position = pl2.Position.add(AsVector3(nfpPath.OrigionMinPoint));
|
||||
TestDraw(pl, 6);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
import { TestDraw } from "../../Add-on/test/TestUtil";
|
||||
import { app } from "../../ApplicationServices/Application";
|
||||
import { Circle } from "../../DatabaseServices/Entity/Circle";
|
||||
import { Polyline } from "../../DatabaseServices/Entity/Polyline";
|
||||
import { Command } from "../../Editor/CommandMachine";
|
||||
import { PromptStatus } from "../../Editor/PromptResult";
|
||||
import { AsVector3 } from "../../Geometry/GeUtils";
|
||||
import { clipperCpp, InitClipperCpp } from "../Common/ClipperCpp";
|
||||
import { Curves2Points } from "../Converter/ConverBoard2Part";
|
||||
import { Path2Polyline } from "../Converter/Path2Polyline";
|
||||
import { NestCache } from "../Core/NestCache";
|
||||
import { Path, PathScale } from "../Core/Path";
|
||||
|
||||
export class Command_TestSum implements Command
|
||||
{
|
||||
async exec()
|
||||
{
|
||||
let w = InitClipperCpp();
|
||||
let plsRes = await app.Editor.GetSelection({
|
||||
Msg: "先选择不动的,在选择动的。",
|
||||
Filter: {
|
||||
filterTypes: [Polyline, Circle]
|
||||
}
|
||||
});
|
||||
|
||||
await w;
|
||||
if (plsRes.Status !== PromptStatus.OK)
|
||||
return;
|
||||
|
||||
let pls = plsRes.SelectSet.SelectEntityList as (Polyline | Circle)[];
|
||||
if (pls.length < 2)
|
||||
{
|
||||
if (pls.length === 1)
|
||||
{
|
||||
plsRes = await app.Editor.GetSelection({
|
||||
Msg: "选择动的。",
|
||||
Filter: {
|
||||
filterTypes: [Polyline, Circle]
|
||||
}
|
||||
});
|
||||
if (plsRes.Status === PromptStatus.OK)
|
||||
{
|
||||
pls.push(...plsRes.SelectSet.SelectEntityList as (Polyline | Circle)[]);
|
||||
if (pls.length < 2) return;
|
||||
}
|
||||
}
|
||||
else
|
||||
return;
|
||||
};
|
||||
|
||||
let binpl = pls.shift();
|
||||
let binPath = new Path(Curves2Points(binpl, false, 0)[1]);
|
||||
|
||||
let paths: Path[] = pls.map(pl => { return new Path(Curves2Points(pl, true, 0)[1]); });
|
||||
|
||||
for (let i = 0; i < paths.length; i++)
|
||||
{
|
||||
let sum = clipperCpp.lib.minkowskiSumPath(binPath.BigIntPoints, paths[i].BigIntPoints, true);
|
||||
sum = clipperCpp.lib.simplifyPolygons(sum);
|
||||
|
||||
for (let poly of sum)
|
||||
{
|
||||
if (clipperCpp.lib.area(poly) < 0) continue;
|
||||
|
||||
let pts = PathScale(poly, 1e-4);
|
||||
let pl = Path2Polyline(pts);
|
||||
pl.ColorIndex = 6;
|
||||
pl.Position = AsVector3(binPath.OrigionMinPoint);
|
||||
TestDraw(pl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in new issue