diff --git a/__test__/Board/2dpath.test.ts b/__test__/Board/2dpath.test.ts new file mode 100644 index 000000000..579c0cfae --- /dev/null +++ b/__test__/Board/2dpath.test.ts @@ -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((res, rej) => + { + end((new Entity()).AsyncUpdated, function () + { + res(); + }); + }); + + expect(br.MeshGeometry.getAttribute("position").count).toMatchNumberSnapshot(0); + expect(br.EdgeGeometry.getAttribute("position").count).toMatchNumberSnapshot(0); +}); diff --git a/__test__/Board/__snapshots__/2dpath.test.ts.snap b/__test__/Board/__snapshots__/2dpath.test.ts.snap new file mode 100644 index 000000000..86bb21d85 --- /dev/null +++ b/__test__/Board/__snapshots__/2dpath.test.ts.snap @@ -0,0 +1,5 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`二维刀路测试(常规) 1`] = `"1125"`; + +exports[`二维刀路测试(常规) 2`] = `"1118"`; diff --git a/package.json b/package.json index 622957d59..6dc537c78 100644 --- a/package.json +++ b/package.json @@ -137,6 +137,9 @@ "@types/react": "17.0.44" }, "jest": { + "setupFiles": [ + "/src/Geometry/CSGSubtract/RegisterCSGSyncMode.ts" + ], "transform": { "^.+\\.(js|ts|tsx)$": "ts-jest", "\\.(vs|fs)$": "//utils//transform//File2StringTransformer.js" diff --git a/src/Add-on/ShareView/ShareViewEntry.tsx b/src/Add-on/ShareView/ShareViewEntry.tsx index f18e74c7b..9ababc827 100644 --- a/src/Add-on/ShareView/ShareViewEntry.tsx +++ b/src/Add-on/ShareView/ShareViewEntry.tsx @@ -14,6 +14,7 @@ import { CADFiler } from "../../DatabaseServices/CADFiler"; import { Board } from "../../DatabaseServices/Entity/Board"; import { commandMachine } from "../../Editor/CommandMachine"; import { userConfig } from "../../Editor/UserConfig"; +import { RegisterCSGWebWorker } from "../../Geometry/CSGSubtract/RegisterCSGWebWorker"; import { ARC_DRAW_CONFIG } from "../../Geometry/ExtrudeMeshGeomBuilder/SplitCurveParams"; import { RenderType } from "../../GraphicsSystem/RenderType"; import { LoadDefaultExr, LoadMetalEnv } from "../../Loader/EnvLoader"; @@ -195,6 +196,8 @@ window.onload = async function () ARC_DRAW_CONFIG.Arc_MinSplitCount = 8; ARC_DRAW_CONFIG.ARC_MaxSplitCount = 60; + RegisterCSGWebWorker(); + LogEnable.Display = true; // ReportErrorWrap.ReportError = ReportError; diff --git a/src/Common/ThreadPool/Task.ts b/src/Common/ThreadPool/Task.ts new file mode 100644 index 000000000..afa7619a0 --- /dev/null +++ b/src/Common/ThreadPool/Task.ts @@ -0,0 +1,8 @@ + +export interface Task +{ + key: any; //关键key + data: any; + then: Function; + workerCtor: (new () => Worker); +} diff --git a/src/Common/ThreadPool/WorkerPool.ts b/src/Common/ThreadPool/WorkerPool.ts new file mode 100644 index 000000000..d7310d9e6 --- /dev/null +++ b/src/Common/ThreadPool/WorkerPool.ts @@ -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) + { + 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(); diff --git a/src/DatabaseServices/Entity/Board.ts b/src/DatabaseServices/Entity/Board.ts index 06b76ed21..040a439c5 100644 --- a/src/DatabaseServices/Entity/Board.ts +++ b/src/DatabaseServices/Entity/Board.ts @@ -1,11 +1,11 @@ import geom2, { Geom2 } from '@jscad/modeling/src/geometries/geom2'; import geom3, { transform } from '@jscad/modeling/src/geometries/geom3'; 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 { Vec2 } from '@jscad/modeling/src/maths/vec2'; 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 extrudeRotate from '@jscad/modeling/src/operations/extrusions/extrudeRotate'; import retessellate from '@jscad/modeling/src/operations/modifiers/retessellate'; @@ -21,12 +21,14 @@ import { EBoardKeyList } from '../../Common/BoardKeyList'; import { Geom3Res } from '../../Common/CSGIntersect'; import { ColorMaterial } from '../../Common/ColorPalette'; import { DisposeThreeObj } from '../../Common/Dispose'; +import { Log, LogType } from '../../Common/Log'; import { MakeMirrorMtx, TransformVector, Vector2ApplyMatrix4, ZMirrorMatrix, tempMatrix1 } from '../../Common/Matrix4Utils'; import { UpdateDraw } from '../../Common/Status'; import { FixIndex } from '../../Common/Utils'; import { ObjectSnapMode } from '../../Editor/ObjectSnapMode'; import { boardUVGenerator, boardUVGenerator2 } from '../../Geometry/BoardUVGenerator'; import { BufferGeometryUtils } from '../../Geometry/BufferGeometryUtils'; +import { AddCSGSubtractTask, CSGTask, TerminateCSGTask } from '../../Geometry/CSGSubtract/CSGSubtractTaskManager'; import { EdgesGeometry } from '../../Geometry/EdgeGeometry'; import { GetArcDrawCount } from '../../Geometry/ExtrudeMeshGeomBuilder/SplitCurveParams'; 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 { RenderType } from '../../GraphicsSystem/RenderType'; import { VData2Curve, VKnifToolPath } from '../../GraphicsSystem/ToolPath/VKnifToolPath'; -import { Max } from '../../Nest/Common/Util'; import { BoardProcessOption } from "../../UI/Store/OptionInterface/BoardProcessOption"; import { FuzzyFactory } from '../../csg/core/FuzzyFactory'; import { CSG2Geometry2, Geometry2CSG2 } from '../../csg/core/Geometry2CSG'; @@ -318,6 +319,8 @@ export class Board extends ExtrudeSolid } private _CustomNumberTextEntity: DbText; + private _AsyncIngTextEntity: DbText; + get CustomNumber() { return this._CustomNumber; } set CustomNumber(n: number | null) { @@ -1596,95 +1599,65 @@ export class Board extends ExtrudeSolid //#endregion 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 //二维刀路切割后返回几何体 override UpdateMeshGeom(geo: Geometry): BufferGeometry { - let path2dCsgs = this.Get2DPathCsgs(); - if (!path2dCsgs.length || !HostApplicationServices.show2DPathObject) + if (!this._workerCalcedGeom) { - if (geo instanceof Geometry) - return new BufferGeometry().fromGeometry(geo); - 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) + let path2dCsgs = this.Get2DPathCsgs(); + if (!path2dCsgs.length || !HostApplicationServices.show2DPathObject) { - 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; - } + if (geo instanceof Geometry) + return new BufferGeometry().fromGeometry(geo); + return geo; } - 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 geom = Geometry2CSG2(geo); + this._async2DPathIng = true; + // 使用线程池 + const task: CSGTask = { + key: this, + data: [path2dCsgs, geom], + then: (e) => { - let poly = polyGroup[i]; - - for (let v of poly.vertices) + let data = e.data as { status: number, geom: Geom3; }; + if (data.status) { - let key = v["__key__"]; - let arr = vmap.get(key); - - for (let vpoly of arr) - { - if (calcs.has(vpoly)) continue; + this._AsyncIngTextEntity.TextString = "二维刀路建模失败"; + Log(`板:${this.Name}二维刀路建模失败!`, LogType.Error, [this]); + return; + } - 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); const geometry = CSG2Geometry2(newGeom); @@ -1848,6 +1821,7 @@ export class Board extends ExtrudeSolid { obj = super.InitDrawObject(renderType); this.UpdateDrawObjectByBoardInfo(renderType, obj); + this.DrawAsyncText(obj); } return obj; } @@ -1915,9 +1889,43 @@ export class Board extends ExtrudeSolid this.UpdateDrawObjectByBoardInfo(renderType, obj); + this.DrawAsyncText(obj); + 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; } //排版面网格 diff --git a/src/Geometry/CSGSubtract/CSGSubtract.ts b/src/Geometry/CSGSubtract/CSGSubtract.ts new file mode 100644 index 000000000..d6ae8aa24 --- /dev/null +++ b/src/Geometry/CSGSubtract/CSGSubtract.ts @@ -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; +} diff --git a/src/Geometry/CSGSubtract/CSGSubtract.worker.ts b/src/Geometry/CSGSubtract/CSGSubtract.worker.ts new file mode 100644 index 000000000..36aff50d6 --- /dev/null +++ b/src/Geometry/CSGSubtract/CSGSubtract.worker.ts @@ -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); diff --git a/src/Geometry/CSGSubtract/CSGSubtractTaskManager.ts b/src/Geometry/CSGSubtract/CSGSubtractTaskManager.ts new file mode 100644 index 000000000..58f3a64d1 --- /dev/null +++ b/src/Geometry/CSGSubtract/CSGSubtractTaskManager.ts @@ -0,0 +1,20 @@ +import { Task } from "../../Common/ThreadPool/Task"; + +export type CSGTask = Pick; + +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; +type TerminateCSGTaskFunction = (task: TaskKey) => void; +export const _TerminateTaskInjectInteractionFunctions: TerminateCSGTaskFunction[] = []; +export function TerminateCSGTask(task: TaskKey) +{ + for (let f of _TerminateTaskInjectInteractionFunctions) + f(task); +} diff --git a/src/Geometry/CSGSubtract/RegisterCSGSyncMode.ts b/src/Geometry/CSGSubtract/RegisterCSGSyncMode.ts new file mode 100644 index 000000000..0754625f9 --- /dev/null +++ b/src/Geometry/CSGSubtract/RegisterCSGSyncMode.ts @@ -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(); diff --git a/src/Geometry/CSGSubtract/RegisterCSGWebWorker.ts b/src/Geometry/CSGSubtract/RegisterCSGWebWorker.ts new file mode 100644 index 000000000..20688fdb8 --- /dev/null +++ b/src/Geometry/CSGSubtract/RegisterCSGWebWorker.ts @@ -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; +} diff --git a/src/index.tsx b/src/index.tsx index a9aa47a0d..1e7759c70 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -6,6 +6,7 @@ import { ErrorMonitoring, ReportError } from './Common/ErrorMonitoring'; import { LogEnable, ReportErrorWrap } from './Common/Log'; import { copyTextToClipboard } from './Common/Utils'; import { userConfig } from './Editor/UserConfig'; +import { RegisterCSGWebWorker } from './Geometry/CSGSubtract/RegisterCSGWebWorker'; import { LoadDefaultExr, LoadMetalEnv } from './Loader/EnvLoader'; import { AppToaster } from './UI/Components/Toaster'; import './UI/Css/blue.less'; @@ -197,6 +198,8 @@ window.onload = function () HostApplicationServices.ProxyObject = userConfig; + RegisterCSGWebWorker(); + new WebCAD(); LoadDefaultExr();