!2439 优化:二维刀路的布尔运算在异步线程中计算

pull/2444/MERGE
张子涵 11 months ago committed by ChenX
parent 06f0bc6fec
commit 7683c254e4

@ -0,0 +1,26 @@
import { end } from "xaop";
import { HostApplicationServices } from "../../src/ApplicationServices/HostApplicationServices";
import { Entity } from "../../src/DatabaseServices/Entity/Entity";
import { LoadBoardsFromFileData } from "../Utils/LoadEntity.util";
import "../Utils/jest.util";
HostApplicationServices.show2DPathObject = true;
test('二维刀路测试(常规)', async () =>
{
let brd = { "file": [1, "Board", 10, 2, 100, 0, 1, 3, 71, [1, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 809.3041405064287, 638.3657841841923, 0, 1], 0, 0, 1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 809.3041405064287, 638.3657841841923, 0, 1], 0, 0, 1, 3, 800, 500, 18, true, "Polyline", 10, 2, 0, 0, 0, 7, 71, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 0, 0, 1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 0, 0, 1, 2, 4, [0, 0], 0, [500, 0], 0, [500, 800], 0, [0, 800], 0, true, 0, 3, 0, 0, 0, 0, 0, 13, 2, "背板", "", "", "", "", "", 0, 0, "阿萨S", 2, 0, "0", "0", "0", "0", "", "", "", 4, "阿萨S", "阿萨S", "阿萨S", "阿萨S", true, true, 1, "1", "1", 0, 0, 0, 0, 0, 0, 0, true, 1, "Polyline", 10, 2, 0, 0, 0, 1, 71, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 0, 0, 1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 0, 0, 1, 2, 3, [264.1772151898734, 924.5569620253166], 0, [264.1772151898734, 492.1518987341773], 0, [792.2784810126584, 492.1518987341773], 0, false, 0, 1, 10, 0, "4472", 3, 0, "12号刀(1)", 0, null, 1, "4472", "Polyline", 10, 2, 0, 0, 0, 7, 71, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -9.99999999999909, -4.547473508864641e-13, 0, 1], 0, 0, 1, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -11939.567631031936, -1853.7579836292566, 0, 1], 0, 0, 1, 2, 31, [19.99999999999818, 2.2737367544323206e-13], 0, [0, 0], 0, [-1.500000000003638, 1.0000000000002274], 0, [-10.000000000120053, 1.0000000004658887], 0, [-10.000000000032742, 4.500000000465889], 0, [-1.500000000003638, 4.500000000465889], 0, [-3.637978807091713e-12, 5.500000000465889], 0, [-1.2005330063402653e-10, 8.499999999883812], 0, [-1.5000000001200533, 9.499999999883812], 0, [-20.000000000120053, 9.500000000611408], 0, [-20.000000000120053, 13.500000000465889], 0, [-11.499999772295268, 13.500000000611408], 0, [-9.999999772411684, 14.50000000069872], 0, [-9.999999772564479, 17.50000000046589], 0, [-11.499999772613592, 18.500000000466116], 0, [-11.499999772613592, 48.500000000466116], 0, [31.499999772609954, 48.50000000046589], 0, [31.499999772609954, 18.50000000046589], 0, [29.999999772559022, 17.50000000046589], 0, [29.999999772406227, 14.50000000069872], 0, [31.49999977228981, 13.500000000611408], 0, [40.000000000114596, 13.500000000465889], 0, [40.000000000114596, 9.500000000611408], 0, [21.500000000114596, 9.499999999883812], 0, [20.000000000114596, 8.499999999883812], 0, [19.99999999999818, 5.500000000465889], 0, [21.49999999999818, 4.500000000465889], 0, [30.000000000027285, 4.500000000465889], 0, [30.000000000114596, 1.0000000004658887], 0, [21.49999999999818, 1.0000000000002274], 0, [19.99999999999818, 2.2737367544323206e-13], 0, false, 0], "basePt": { "x": 809.3041405064287, "y": 620.3657841841923, "z": 0 }, "ucs": [1, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1] };
let br = LoadBoardsFromFileData(brd)[0];
br.MeshGeometry;//预读取
await new Promise<void>((res, rej) =>
{
end((new Entity()).AsyncUpdated, function ()
{
res();
});
});
expect(br.MeshGeometry.getAttribute("position").count).toMatchNumberSnapshot(0);
expect(br.EdgeGeometry.getAttribute("position").count).toMatchNumberSnapshot(0);
});

@ -0,0 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`二维刀路测试(常规) 1`] = `"1125"`;
exports[`二维刀路测试(常规) 2`] = `"1118"`;

@ -137,6 +137,9 @@
"@types/react": "17.0.44" "@types/react": "17.0.44"
}, },
"jest": { "jest": {
"setupFiles": [
"<rootDir>/src/Geometry/CSGSubtract/RegisterCSGSyncMode.ts"
],
"transform": { "transform": {
"^.+\\.(js|ts|tsx)$": "ts-jest", "^.+\\.(js|ts|tsx)$": "ts-jest",
"\\.(vs|fs)$": "<rootDir>//utils//transform//File2StringTransformer.js" "\\.(vs|fs)$": "<rootDir>//utils//transform//File2StringTransformer.js"

@ -14,6 +14,7 @@ import { CADFiler } from "../../DatabaseServices/CADFiler";
import { Board } from "../../DatabaseServices/Entity/Board"; import { Board } from "../../DatabaseServices/Entity/Board";
import { commandMachine } from "../../Editor/CommandMachine"; import { commandMachine } from "../../Editor/CommandMachine";
import { userConfig } from "../../Editor/UserConfig"; import { userConfig } from "../../Editor/UserConfig";
import { RegisterCSGWebWorker } from "../../Geometry/CSGSubtract/RegisterCSGWebWorker";
import { ARC_DRAW_CONFIG } from "../../Geometry/ExtrudeMeshGeomBuilder/SplitCurveParams"; import { ARC_DRAW_CONFIG } from "../../Geometry/ExtrudeMeshGeomBuilder/SplitCurveParams";
import { RenderType } from "../../GraphicsSystem/RenderType"; import { RenderType } from "../../GraphicsSystem/RenderType";
import { LoadDefaultExr, LoadMetalEnv } from "../../Loader/EnvLoader"; import { LoadDefaultExr, LoadMetalEnv } from "../../Loader/EnvLoader";
@ -195,6 +196,8 @@ window.onload = async function ()
ARC_DRAW_CONFIG.Arc_MinSplitCount = 8; ARC_DRAW_CONFIG.Arc_MinSplitCount = 8;
ARC_DRAW_CONFIG.ARC_MaxSplitCount = 60; ARC_DRAW_CONFIG.ARC_MaxSplitCount = 60;
RegisterCSGWebWorker();
LogEnable.Display = true; LogEnable.Display = true;
// ReportErrorWrap.ReportError = ReportError; // ReportErrorWrap.ReportError = ReportError;

@ -0,0 +1,8 @@
export interface Task
{
key: any; //关键key
data: any;
then: Function;
workerCtor: (new () => Worker);
}

@ -0,0 +1,159 @@
import { Task } from "./Task";
/** 是否输出测试信息 */
const isLog = false;
/** 调试输出 */
const log = isLog ? console.log.bind(console) : () => { };
interface Thread
{
id: number;
task: Task;
worker: Worker;
workerCtor: (new () => Worker);
}
/**
*/
class WorkerPool
{
/** 线程池 */
private _Pool: Thread[] = [];
/** 调度队列 */
private _TaskQueue: Task[] = [];
/** 最大线程数 */
THREAD_MAX_COUNT = 4;
/** 线程ID */
private threadId = 0;
/** 添加任务 */
AppendTask(task: Task)
{
const thread = this._Pool.find(thread => thread.task?.key === task.key && thread.workerCtor === task.workerCtor);
if (thread)
{
thread.worker.terminate();
thread.worker = new task.workerCtor;
this.UpdateTask(thread, task);
log(`重启线程任务`);
return;
}
const taskIndex = this._TaskQueue.findIndex(e => e.key === task.key && e.workerCtor === task.workerCtor);
if (taskIndex !== -1)
{
this._TaskQueue[taskIndex] = task;
}
else
{
this._TaskQueue.push(task);
this.Loop();
}
}
TerminateTask(task: Pick<Task, "key" | "workerCtor">)
{
const thread = this._Pool.find(thread => thread.task?.key === task.key && thread.workerCtor === task.workerCtor);
let index = this._TaskQueue.findIndex(t => t.key === task.key && t.workerCtor === task.workerCtor);
if (index !== -1)
this._TaskQueue.splice(index, 1);
if (thread)
{
thread.worker.terminate();
thread.worker = undefined;
thread.workerCtor = undefined;
thread.task = undefined;
this.Loop();
}
}
/** 更换任务 */
UpdateTask(thread: Thread, task: Task)
{
thread.task = task;
if (thread.workerCtor !== task.workerCtor)
{
if (thread.worker) thread.worker.terminate();
thread.worker = new task.workerCtor;
thread.workerCtor = task.workerCtor;
}
log(`设置【${thread.id}号线程】执行【任务${task.key}`);
thread.worker.postMessage(thread.task.data);
// 返回结果
thread.worker.onmessage = e =>
{
const res = {
id: thread.id,
taskId: task.key,
data: e.data
};
log(`${res.id}号线程】完成【任务${res.taskId}`, res.data);
thread.task = null;
this.Loop();//先开启下一个任务 在进行主线程同步
task.then(res);
};
}
/** 循环调度 */
Loop()
{
if (!this._TaskQueue.length)
{
//没有任务时,我们杀掉worker 避免占据内存
for (let thread of this._Pool)
{
if (thread.task) continue;
if (thread.worker)
thread.worker.terminate();
thread.worker = undefined;
thread.workerCtor = undefined;
}
return;
};
const freeThread = this.GetFreeThread();
if (freeThread)
{
const task = this._TaskQueue.shift();
this.UpdateTask(freeThread, task);
}
}
/** 获取闲置线程 */
GetFreeThread(): Thread | undefined
{
let thread = this._Pool.find(thread => !thread.task);
if (thread) return thread;
if (this._Pool.length < this.THREAD_MAX_COUNT)
{
thread = {
id: ++this.threadId,
worker: undefined,
task: undefined,
workerCtor: undefined
};
this._Pool.push(thread);
return thread;
}
}
}
/**
* 线
* @example
* const task = {
* data: 100, // 输入的数据
* then: e => console.log(e.data) // 输出的结果
* };
* // 添加任务
* THREAD_POOL.AppendTask(task);
*/
export const WORKER_POOL = new WorkerPool();

@ -1,11 +1,11 @@
import geom2, { Geom2 } from '@jscad/modeling/src/geometries/geom2'; import geom2, { Geom2 } from '@jscad/modeling/src/geometries/geom2';
import geom3, { transform } from '@jscad/modeling/src/geometries/geom3'; import geom3, { transform } from '@jscad/modeling/src/geometries/geom3';
import Geom3 from '@jscad/modeling/src/geometries/geom3/type'; import Geom3 from '@jscad/modeling/src/geometries/geom3/type';
import poly3, { measureArea } from '@jscad/modeling/src/geometries/poly3'; import poly3 from '@jscad/modeling/src/geometries/poly3';
import { Mat4 } from '@jscad/modeling/src/maths/mat4'; import { Mat4 } from '@jscad/modeling/src/maths/mat4';
import { Vec2 } from '@jscad/modeling/src/maths/vec2'; import { Vec2 } from '@jscad/modeling/src/maths/vec2';
import { Vec3 } from '@jscad/modeling/src/maths/vec3'; import { Vec3 } from '@jscad/modeling/src/maths/vec3';
import { intersect, subtract, union } from '@jscad/modeling/src/operations/booleans'; import { intersect } from '@jscad/modeling/src/operations/booleans';
import extrudeLinear from '@jscad/modeling/src/operations/extrusions/extrudeLinear'; import extrudeLinear from '@jscad/modeling/src/operations/extrusions/extrudeLinear';
import extrudeRotate from '@jscad/modeling/src/operations/extrusions/extrudeRotate'; import extrudeRotate from '@jscad/modeling/src/operations/extrusions/extrudeRotate';
import retessellate from '@jscad/modeling/src/operations/modifiers/retessellate'; import retessellate from '@jscad/modeling/src/operations/modifiers/retessellate';
@ -21,12 +21,14 @@ import { EBoardKeyList } from '../../Common/BoardKeyList';
import { Geom3Res } from '../../Common/CSGIntersect'; import { Geom3Res } from '../../Common/CSGIntersect';
import { ColorMaterial } from '../../Common/ColorPalette'; import { ColorMaterial } from '../../Common/ColorPalette';
import { DisposeThreeObj } from '../../Common/Dispose'; import { DisposeThreeObj } from '../../Common/Dispose';
import { Log, LogType } from '../../Common/Log';
import { MakeMirrorMtx, TransformVector, Vector2ApplyMatrix4, ZMirrorMatrix, tempMatrix1 } from '../../Common/Matrix4Utils'; import { MakeMirrorMtx, TransformVector, Vector2ApplyMatrix4, ZMirrorMatrix, tempMatrix1 } from '../../Common/Matrix4Utils';
import { UpdateDraw } from '../../Common/Status'; import { UpdateDraw } from '../../Common/Status';
import { FixIndex } from '../../Common/Utils'; import { FixIndex } from '../../Common/Utils';
import { ObjectSnapMode } from '../../Editor/ObjectSnapMode'; import { ObjectSnapMode } from '../../Editor/ObjectSnapMode';
import { boardUVGenerator, boardUVGenerator2 } from '../../Geometry/BoardUVGenerator'; import { boardUVGenerator, boardUVGenerator2 } from '../../Geometry/BoardUVGenerator';
import { BufferGeometryUtils } from '../../Geometry/BufferGeometryUtils'; import { BufferGeometryUtils } from '../../Geometry/BufferGeometryUtils';
import { AddCSGSubtractTask, CSGTask, TerminateCSGTask } from '../../Geometry/CSGSubtract/CSGSubtractTaskManager';
import { EdgesGeometry } from '../../Geometry/EdgeGeometry'; import { EdgesGeometry } from '../../Geometry/EdgeGeometry';
import { GetArcDrawCount } from '../../Geometry/ExtrudeMeshGeomBuilder/SplitCurveParams'; import { GetArcDrawCount } from '../../Geometry/ExtrudeMeshGeomBuilder/SplitCurveParams';
import { IdentityMtx4, XAxis, XAxisN, YAxis, YAxisN, ZAxis, ZeroVec, equaln, equalv3 } from '../../Geometry/GeUtils'; import { IdentityMtx4, XAxis, XAxisN, YAxis, YAxisN, ZAxis, ZeroVec, equaln, equalv3 } from '../../Geometry/GeUtils';
@ -35,7 +37,6 @@ import { SweepGeometrySimple } from '../../Geometry/SweepGeometry';
import { GetBoardHighSeal, GetBoardSealingCurves, SetBoardTopDownLeftRightSealData } from '../../GraphicsSystem/CalcEdgeSealing'; import { GetBoardHighSeal, GetBoardSealingCurves, SetBoardTopDownLeftRightSealData } from '../../GraphicsSystem/CalcEdgeSealing';
import { RenderType } from '../../GraphicsSystem/RenderType'; import { RenderType } from '../../GraphicsSystem/RenderType';
import { VData2Curve, VKnifToolPath } from '../../GraphicsSystem/ToolPath/VKnifToolPath'; import { VData2Curve, VKnifToolPath } from '../../GraphicsSystem/ToolPath/VKnifToolPath';
import { Max } from '../../Nest/Common/Util';
import { BoardProcessOption } from "../../UI/Store/OptionInterface/BoardProcessOption"; import { BoardProcessOption } from "../../UI/Store/OptionInterface/BoardProcessOption";
import { FuzzyFactory } from '../../csg/core/FuzzyFactory'; import { FuzzyFactory } from '../../csg/core/FuzzyFactory';
import { CSG2Geometry2, Geometry2CSG2 } from '../../csg/core/Geometry2CSG'; import { CSG2Geometry2, Geometry2CSG2 } from '../../csg/core/Geometry2CSG';
@ -318,6 +319,8 @@ export class Board extends ExtrudeSolid
} }
private _CustomNumberTextEntity: DbText; private _CustomNumberTextEntity: DbText;
private _AsyncIngTextEntity: DbText;
get CustomNumber() { return this._CustomNumber; } get CustomNumber() { return this._CustomNumber; }
set CustomNumber(n: number | null) set CustomNumber(n: number | null)
{ {
@ -1596,95 +1599,65 @@ export class Board extends ExtrudeSolid
//#endregion //#endregion
protected get Has2DPath() { return this._2DModelingList.length > 0; } protected get Has2DPath() { return this._2DModelingList.length > 0; }
private _workerCalcedGeom: Geom3 = null;//worker计算后,暂时存入到这里
private _async2DPathIng = false;
override GoodBye(): void
{
super.GoodBye();
TerminateCSGTask({ key: this });
}
//del_exp2_start //del_exp2_start
//二维刀路切割后返回几何体 //二维刀路切割后返回几何体
override UpdateMeshGeom(geo: Geometry): BufferGeometry override UpdateMeshGeom(geo: Geometry): BufferGeometry
{ {
let path2dCsgs = this.Get2DPathCsgs(); if (!this._workerCalcedGeom)
if (!path2dCsgs.length || !HostApplicationServices.show2DPathObject)
{ {
if (geo instanceof Geometry) let path2dCsgs = this.Get2DPathCsgs();
return new BufferGeometry().fromGeometry(geo); if (!path2dCsgs.length || !HostApplicationServices.show2DPathObject)
return geo;
}
// TestDrawGeom3s(path2dCsgs);
let gemUnion = path2dCsgs[0];
for (let i = 1; i < path2dCsgs.length; i++)
gemUnion = union(gemUnion, path2dCsgs[i]);
let geom = Geometry2CSG2(geo);
let newGeom = subtract(geom, gemUnion);
//删除小面积(只留一个)
{
let fuzz = new FuzzyFactory;
let vmap = new Map;
for (let poly of newGeom.polygons)
{ {
for (let v of poly.vertices) if (geo instanceof Geometry)
{ return new BufferGeometry().fromGeometry(geo);
let key = fuzz.lookupOrCreate(v, v); return geo;
let arr = vmap.get(key);
if (!arr)
{
arr = [];
vmap.set(key, arr);
}
arr.push(poly);
v["__key__"] = key;
}
} }
let polys = newGeom.polygons.concat(); let geom = Geometry2CSG2(geo);
let polyGroups = []; this._async2DPathIng = true;
// 使用线程池
let calcs = new Set; const task: CSGTask = {
while (polys.length) key: this,
{ data: [path2dCsgs, geom],
let poly1 = polys.pop(); then: (e) =>
calcs.add(poly1);
let polyGroup = [poly1];
polyGroups.push(polyGroup);
for (let i = 0; i < polyGroup.length; i++)
{ {
let poly = polyGroup[i]; let data = e.data as { status: number, geom: Geom3; };
if (data.status)
for (let v of poly.vertices)
{ {
let key = v["__key__"]; this._AsyncIngTextEntity.TextString = "二维刀路建模失败";
let arr = vmap.get(key); Log(`板:${this.Name}二维刀路建模失败!`, LogType.Error, [this]);
return;
for (let vpoly of arr) }
{
if (calcs.has(vpoly)) continue;
calcs.add(vpoly); this.UpdateDrawGeometry();
this._workerCalcedGeom = data.geom;
this.Update();
this.AsyncUpdated();
this.MeshGeometry;//保证刷新这个
polyGroup.push(vpoly); this._workerCalcedGeom = null;
}
}
} }
// arrayRemoveIf(polys, poly => !calcs.has(poly)); //加上这个无法提高性能 };
}
let areas = polyGroups.map(polys =>
{
let area = 0;
for (let poly of polys)
area += measureArea(poly);
return area;
});
let maxIndex = Max(areas, (t1, t2) => t2 > t1); AddCSGSubtractTask(task); // 往线程池里添加任务
newGeom.polygons = polyGroups[maxIndex]; //进入到异步后,直接先返回
if (geo instanceof Geometry)
return new BufferGeometry().fromGeometry(geo);
return geo;
} }
this._async2DPathIng = false;
const newGeom = this._workerCalcedGeom;
this._workerCalcedGeom = undefined;//保护
this._EdgeGeometry = new EdgesGeometry().FromCSG(newGeom as unknown as Geom3Res); this._EdgeGeometry = new EdgesGeometry().FromCSG(newGeom as unknown as Geom3Res);
const geometry = CSG2Geometry2(newGeom); const geometry = CSG2Geometry2(newGeom);
@ -1848,6 +1821,7 @@ export class Board extends ExtrudeSolid
{ {
obj = super.InitDrawObject(renderType); obj = super.InitDrawObject(renderType);
this.UpdateDrawObjectByBoardInfo(renderType, obj); this.UpdateDrawObjectByBoardInfo(renderType, obj);
this.DrawAsyncText(obj);
} }
return obj; return obj;
} }
@ -1915,9 +1889,43 @@ export class Board extends ExtrudeSolid
this.UpdateDrawObjectByBoardInfo(renderType, obj); this.UpdateDrawObjectByBoardInfo(renderType, obj);
this.DrawAsyncText(obj);
return o; return o;
} }
private DrawAsyncText(obj: Object3D)
{
if (this._async2DPathIng)
{
//#region 添加文字
if (!this._AsyncIngTextEntity)
{
this._AsyncIngTextEntity = new DbText();
this._AsyncIngTextEntity.TextAligen = TextAligen.Mid;
this._AsyncIngTextEntity.IsDoubleMesh = true;
this._AsyncIngTextEntity.IsFsText = this._BoardType === BoardType.Layer;
this._AsyncIngTextEntity.IsEmbedEntity = true;
}
if (this._BoardType === BoardType.Layer)
this._AsyncIngTextEntity.OCSNoClone.makeRotationZ(-Math.PI / 2).setPosition(this.width * 0.5, this.height * 0.5, this.thickness * 0.5);
else
this._AsyncIngTextEntity.OCSNoClone.identity().setPosition(this.width * 0.5, this.height * 0.5, this.thickness * 0.5);
this._AsyncIngTextEntity.TextString = "二维刀路建模中!";
let o = this._AsyncIngTextEntity.GetDrawObjectFromRenderType(RenderType.Conceptual);
if (o)
{
o.traverse(obj => obj.userData = {});
AddEntityDrawObject(obj, this._AsyncIngTextEntity, RenderType.Conceptual);
}
//#endregion
}
}
//绘制排版面时使用的颜色 //绘制排版面时使用的颜色
private get PlaceColor() { return this._Color === 8 ? 9 : this._Color; } private get PlaceColor() { return this._Color === 8 ? 9 : this._Color; }
//排版面网格 //排版面网格

@ -0,0 +1,82 @@
import { measureArea } from '@jscad/modeling/src/geometries/poly3';
import { subtract, union } from '@jscad/modeling/src/operations/booleans';
import { Max } from '../../Nest/Common/Util';
import { FuzzyFactory } from '../../csg/core/FuzzyFactory';
//并集path2dCsgs 差集 删除小面积结果
export function CSGSubtract(geom: geom3.Geom3[], path2dCsgs: geom3.Geom3[])
{
let gemUnion = path2dCsgs[0];
for (let i = 1; i < path2dCsgs.length; i++)
gemUnion = union(gemUnion, path2dCsgs[i]);
let newGeom = subtract(geom, gemUnion);
//删除小面积(只留一个)
{
let fuzz = new FuzzyFactory;
let vmap = new Map;
for (let poly of newGeom.polygons)
{
for (let v of poly.vertices)
{
let key = fuzz.lookupOrCreate(v, v);
let arr = vmap.get(key);
if (!arr)
{
arr = [];
vmap.set(key, arr);
}
arr.push(poly);
v["__key__"] = key;
}
}
let polys = newGeom.polygons.concat();
let polyGroups = [];
let calcs = new Set;
while (polys.length)
{
let poly1 = polys.pop();
calcs.add(poly1);
let polyGroup = [poly1];
polyGroups.push(polyGroup);
for (let i = 0; i < polyGroup.length; i++)
{
let poly = polyGroup[i];
for (let v of poly.vertices)
{
let key = v["__key__"];
let arr = vmap.get(key);
for (let vpoly of arr)
{
if (calcs.has(vpoly)) continue;
calcs.add(vpoly);
polyGroup.push(vpoly);
}
}
}
// arrayRemoveIf(polys, poly => !calcs.has(poly)); //加上这个无法提高性能
}
let areas = polyGroups.map(polys =>
{
let area = 0;
for (let poly of polys)
area += measureArea(poly);
return area;
});
let maxIndex = Max(areas, (t1, t2) => t2 > t1);
newGeom.polygons = polyGroups[maxIndex];
}
return newGeom;
}

@ -0,0 +1,27 @@
/* __JEST_WEBWORKER_SEPARATOR__ */
import { CSGSubtract } from './CSGSubtract';
const ctx: Worker = self as any;
ctx.addEventListener("message", e =>
{
const [path2dCsgs, geom]: geom3.Geom3[][] = e.data;
try
{
const newGeom = CSGSubtract(geom, path2dCsgs);
postMessage({
status: 0,
geom: newGeom
});
}
catch (error)
{
postMessage({
status: 1,
error
});
}
});
export default {} as typeof Worker & (new () => Worker);

@ -0,0 +1,20 @@
import { Task } from "../../Common/ThreadPool/Task";
export type CSGTask = Pick<Task, "key" | "data" | "then">;
type CSGSubtractFunction = (task: CSGTask) => void;
export const _CSGSubtractInjectInteractionFunctions: CSGSubtractFunction[] = [];
export function AddCSGSubtractTask(task: CSGTask)
{
for (let f of _CSGSubtractInjectInteractionFunctions)
f(task);
}
export type TaskKey = Pick<Task, "key">;
type TerminateCSGTaskFunction = (task: TaskKey) => void;
export const _TerminateTaskInjectInteractionFunctions: TerminateCSGTaskFunction[] = [];
export function TerminateCSGTask(task: TaskKey)
{
for (let f of _TerminateTaskInjectInteractionFunctions)
f(task);
}

@ -0,0 +1,39 @@
import { CSGSubtract } from "./CSGSubtract";
import { CSGTask, _CSGSubtractInjectInteractionFunctions, _TerminateTaskInjectInteractionFunctions } from "./CSGSubtractTaskManager";
//因为jest不支持测试 所以这里使用了异步模式,模仿和webworker一样的结果
export function RegisterCSGSyncMode()
{
_CSGSubtractInjectInteractionFunctions.push(async (task: CSGTask) =>
{
let [path2dCsgs, geom] = task.data;
await undefined;//保证它是异步的
try
{
const newGeom = CSGSubtract(geom, path2dCsgs);
task.then({
data: {
status: 0,
geom: newGeom
}
});
}
catch (error)
{
task.then({
data: {
status: 1,
error
}
});
}
});
_TerminateTaskInjectInteractionFunctions.push((task) =>
{
});
}
RegisterCSGSyncMode();

@ -0,0 +1,23 @@
import { Task } from "../../Common/ThreadPool/Task";
import { WORKER_POOL } from "../../Common/ThreadPool/WorkerPool";
import CSGWorker from "../../Geometry/CSGSubtract/CSGSubtract.worker";
import { CSGTask, _CSGSubtractInjectInteractionFunctions, _TerminateTaskInjectInteractionFunctions } from "./CSGSubtractTaskManager";
export function RegisterCSGWebWorker()
{
_CSGSubtractInjectInteractionFunctions.push((task: CSGTask) =>
{
let workerTask = task as Task;
workerTask.workerCtor = CSGWorker;
WORKER_POOL.AppendTask(workerTask);
});
_TerminateTaskInjectInteractionFunctions.push((task) =>
{
let workerTask = task as Task;
workerTask.workerCtor = CSGWorker;
WORKER_POOL.TerminateTask(workerTask);
});
WORKER_POOL.THREAD_MAX_COUNT = navigator.hardwareConcurrency / 2;
}

@ -6,6 +6,7 @@ import { ErrorMonitoring, ReportError } from './Common/ErrorMonitoring';
import { LogEnable, ReportErrorWrap } from './Common/Log'; import { LogEnable, ReportErrorWrap } from './Common/Log';
import { copyTextToClipboard } from './Common/Utils'; import { copyTextToClipboard } from './Common/Utils';
import { userConfig } from './Editor/UserConfig'; import { userConfig } from './Editor/UserConfig';
import { RegisterCSGWebWorker } from './Geometry/CSGSubtract/RegisterCSGWebWorker';
import { LoadDefaultExr, LoadMetalEnv } from './Loader/EnvLoader'; import { LoadDefaultExr, LoadMetalEnv } from './Loader/EnvLoader';
import { AppToaster } from './UI/Components/Toaster'; import { AppToaster } from './UI/Components/Toaster';
import './UI/Css/blue.less'; import './UI/Css/blue.less';
@ -197,6 +198,8 @@ window.onload = function ()
HostApplicationServices.ProxyObject = userConfig; HostApplicationServices.ProxyObject = userConfig;
RegisterCSGWebWorker();
new WebCAD(); new WebCAD();
LoadDefaultExr(); LoadDefaultExr();

Loading…
Cancel
Save