Skip to content

Commit 2d2aa4b

Browse files
authored
Merge pull request #181 from LinkunGao/release/v1.13.17
Release/v1.13.17
2 parents 21305c6 + 3246caf commit 2d2aa4b

File tree

8 files changed

+231
-103
lines changed

8 files changed

+231
-103
lines changed

docs/source/release/release.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1437,3 +1437,7 @@ const resetMainAreaSize = (factor: number) => {
14371437
## Release v1.13.16 - version for Nuxt - heart app
14381438

14391439
- fixed the gui bug
1440+
1441+
## Release v1.13.17
1442+
1443+
- add web work in nrrd tools for export/download masks.

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "copper3d_visualisation",
33
"description": "A 3d visualisation package base on threejs provides multiple scenes and Nrrd image load funtion.",
4-
"version": "1.13.16",
4+
"version": "1.13.17",
55
"main": "dist/bundle.umd.js",
66
"moudle": "dist/bundle.esm.js",
77
"types": "dist/types/index.d.ts",

src/Renderer/baseRenderer.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { environments, environmentType } from "../lib/environment/index";
55
import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader";
66
import Stats from "three/examples/jsm/libs/stats.module";
77
import { GUI, GUIController } from "dat.gui";
8+
import ExportGltf from "../Utils/gltfExporter";
89
import { optType, stateType, modelVisualisationDataType } from "../types/types";
910

1011
export default class baseRenderer {
@@ -23,6 +24,7 @@ export default class baseRenderer {
2324
private visualiseFolder: GUI | null;
2425
private visualCtrls: Array<GUIController> = [];
2526
private cameraFolder: GUI | null;
27+
private exporter: ExportGltf | null = null;
2628

2729
constructor(container: HTMLDivElement, options?: optType) {
2830
this.container = container;
@@ -69,6 +71,14 @@ export default class baseRenderer {
6971
directColor: 0xffffff,
7072
bgColor1: "#5454ad",
7173
bgColor2: "#18e5a7",
74+
exportGltf: () => {
75+
if (!this.exporter) {
76+
this.exporter = new ExportGltf({
77+
animations: this.currentScene.exportContent.animations,
78+
});
79+
}
80+
this.exporter.export(this.currentScene.exportContent);
81+
},
7282
};
7383
this.visualiseFolder = null;
7484
this.cameraFolder = null;
@@ -186,7 +196,7 @@ export default class baseRenderer {
186196
);
187197
}
188198

189-
// gui.add(this.state, "exportGltf");
199+
gui.add(this.state, "exportGltf");
190200
}
191201

192202
updateGui() {

src/Utils/gltfExporter.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { GLTFExporter } from "three/examples/jsm/exporters/GLTFExporter";
2+
import { optionsGltfExporterType } from "../types/types";
3+
4+
export default class ExportGltf {
5+
private gltfExporter: GLTFExporter = new GLTFExporter();
6+
private options: optionsGltfExporterType = {
7+
trs: false,
8+
onlyVisible: true,
9+
truncateDrawRange: true,
10+
binary: false,
11+
maxTextureSize: 40960000000,
12+
animations: [],
13+
};
14+
private link: HTMLAnchorElement;
15+
16+
constructor(opts: optionsGltfExporterType) {
17+
Object.assign(this.options, opts);
18+
this.link = document.createElement("a");
19+
this.link.style.display = "none";
20+
document.body.appendChild(this.link);
21+
}
22+
23+
export(input: any) {
24+
const name: string = input.name ? input.name : "export";
25+
this.gltfExporter.parse(
26+
input,
27+
(result) => {
28+
if (result instanceof ArrayBuffer) {
29+
this.saveArrayBuffer(result, name + ".glb");
30+
} else {
31+
const output = JSON.stringify(result, null, 2);
32+
this.saveString(output, name + ".gltf");
33+
}
34+
},
35+
function (error) {
36+
console.log("An error happened during parsing", error);
37+
},
38+
this.options
39+
);
40+
}
41+
42+
save(blob: Blob, fileName: string) {
43+
this.link.href = URL.createObjectURL(blob);
44+
this.link.download = fileName;
45+
this.link.click();
46+
}
47+
saveString(text: string, fileName: string) {
48+
this.save(new Blob([text], { type: "text/plain" }), fileName);
49+
}
50+
saveArrayBuffer(buffer: ArrayBuffer, fileName: string) {
51+
this.save(
52+
new Blob([buffer], { type: "application/octet-stream" }),
53+
fileName
54+
);
55+
}
56+
}

src/Utils/nrrd_tool.ts

Lines changed: 30 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
1818
import copperMScene from "../Scene/copperMScene";
1919
import copperScene from "../Scene/copperScene";
2020
import { throttle } from "./raycaster";
21-
import { saveFileAsJson } from "./download";
2221
import { switchEraserSize } from "./utils";
22+
import { saveFileAsJson } from "./download";
2323

2424
export class nrrd_tools {
2525
container: HTMLDivElement;
@@ -2433,107 +2433,39 @@ export class nrrd_tools {
24332433
// this.paintImages.y,
24342434
// this.paintImages.y.length
24352435
// );
2436-
exportDataFormat.z = this.restructData(
2437-
this.paintImages.z,
2438-
this.paintImages.z.length,
2439-
this.nrrd_states.nrrd_x_centimeter,
2440-
this.nrrd_states.nrrd_y_centimeter
2441-
);
24422436

2443-
window.alert("Export all images, starting!!!");
2444-
try {
2445-
for (let i = 0; i < 3; i++) {
2446-
switch (i) {
2447-
case 0:
2448-
if (exportDataFormat.x.length > 0) {
2449-
const blob = new Blob([JSON.stringify(exportDataFormat.x)], {
2450-
type: "text/plain;charset=utf-8",
2451-
});
2452-
saveFileAsJson(blob, "copper3D_export data_x.json");
2453-
}
2454-
break;
2455-
2456-
case 1:
2457-
if (exportDataFormat.y.length > 0) {
2458-
const blob1 = new Blob([JSON.stringify(exportDataFormat.y)], {
2459-
type: "text/plain;charset=utf-8",
2460-
});
2461-
saveFileAsJson(blob1, "copper3D_export data_y.json");
2462-
}
2463-
break;
2464-
case 2:
2465-
if (exportDataFormat.z.length > 0) {
2466-
const blob2 = new Blob([JSON.stringify(exportDataFormat.z)], {
2467-
type: "text/plain;charset=utf-8",
2468-
});
2469-
saveFileAsJson(blob2, "copper3D_export data_z.json");
2470-
}
2471-
break;
2472-
}
2437+
const worker = new Worker(
2438+
new URL("./workers/reformatSaveDataWorker.ts", import.meta.url),
2439+
{
2440+
type: "module",
24732441
}
2442+
);
2443+
window.alert("Export masks, starting!!!");
2444+
worker.postMessage({
2445+
masksData: this.paintImages.z,
2446+
len: this.paintImages.z.length,
2447+
width: this.nrrd_states.nrrd_x_centimeter,
2448+
height: this.nrrd_states.nrrd_y_centimeter,
2449+
type: "reformat",
2450+
});
24742451

2475-
window.alert("Export all images successfully!!!");
2476-
} catch (error) {
2477-
console.log(error);
2452+
worker.onmessage = (ev: MessageEvent) => {
2453+
const result = ev.data;
2454+
if (result.type === "reformat") {
2455+
exportDataFormat.z = result.masks;
24782456

2479-
window.alert("Export failed!");
2480-
}
2481-
}
2482-
restructData(
2483-
originArr: paintImageType[],
2484-
len: number,
2485-
width: number,
2486-
height: number
2487-
) {
2488-
const reformatData = [];
2489-
// const convertCanvas = document.createElement("canvas");
2490-
// const convertCtx = convertCanvas.getContext(
2491-
// "2d"
2492-
// ) as CanvasRenderingContext2D;
2493-
for (let i = 0; i < len; i++) {
2494-
let exportTemp: exportPaintImageType = {
2495-
sliceIndex: 0,
2496-
dataFormat:
2497-
"RGBA - Each successive 4-digit number forms a pixel point in data array",
2498-
width,
2499-
height,
2500-
voxelSpacing: this.nrrd_states.voxelSpacing,
2501-
spaceOrigin: this.nrrd_states.spaceOrigin,
2502-
data: [],
2503-
};
2504-
exportTemp.sliceIndex = originArr[i].index;
2505-
2506-
// this.setEmptyCanvasSize();
2507-
// convertCanvas.width = this.nrrd_states.originWidth;
2508-
// convertCanvas.height = this.nrrd_states.originHeight;
2509-
// this.emptyCtx.putImageData(originArr[i].image, 0, 0);
2510-
2511-
// convertCtx.drawImage(
2512-
// this.emptyCanvas,
2513-
// 0,
2514-
// 0,
2515-
// convertCanvas.width,
2516-
// convertCanvas.height
2517-
// );
2518-
2519-
// const imageData = convertCtx.getImageData(
2520-
// 0,
2521-
// 0,
2522-
// convertCanvas.width,
2523-
// convertCanvas.height
2524-
// );
2525-
2526-
const imageData = originArr[i].image;
2527-
2528-
const temp = [];
2529-
for (let j = 0; j < imageData.data.length; j++) {
2530-
temp.push(imageData.data[j]);
2457+
worker.postMessage({
2458+
masksData: exportDataFormat.z,
2459+
type: "saveBlob",
2460+
});
2461+
} else if (result.type === "saveBlob") {
2462+
if (result.data) {
2463+
saveFileAsJson(result.data, "copper3D_export data_z.json");
2464+
window.alert("Export masks successfully!!!");
2465+
} else {
2466+
window.alert("Export failed!");
2467+
}
25312468
}
2532-
2533-
exportTemp.data = temp;
2534-
reformatData.push(exportTemp);
2535-
}
2536-
2537-
return reformatData;
2469+
};
25382470
}
25392471
}
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import { paintImageType } from "../../types/types";
2+
3+
addEventListener("message", (event) => {
4+
const data = event.data;
5+
if (data.type === "reformat") {
6+
// 在 Worker 中执行计算量大的代码
7+
const masks = restructData(
8+
data.masksData,
9+
data.len,
10+
data.width,
11+
data.height
12+
);
13+
const result = {
14+
masks,
15+
type: "reformat",
16+
};
17+
// 发送计算结果到主线程
18+
postMessage(result);
19+
} else if (data.type === "saveBlob") {
20+
const result = convertReformatDataToBlob(data.maskData);
21+
postMessage({
22+
type: "saveBlob",
23+
data: result,
24+
});
25+
}
26+
});
27+
28+
function deepCopy(obj: any): unknown {
29+
if (obj === null || typeof obj !== "object") {
30+
return obj;
31+
}
32+
33+
if (obj instanceof Date) {
34+
return new Date(obj);
35+
}
36+
37+
if (obj instanceof Array) {
38+
let copiedArray = [];
39+
for (let i = 0; i < obj.length; i++) {
40+
copiedArray[i] = deepCopy(obj[i]);
41+
}
42+
return copiedArray;
43+
}
44+
45+
if (obj instanceof Object) {
46+
let copiedObject: any = {};
47+
for (let key in obj) {
48+
if (obj.hasOwnProperty(key)) {
49+
copiedObject[key] = deepCopy(obj[key]);
50+
}
51+
}
52+
return copiedObject;
53+
}
54+
55+
throw new Error("Unable to copy obj! Its type isn't supported.");
56+
}
57+
58+
function pruningData(originArr: paintImageType[]) {
59+
let pruningArray = [];
60+
for (let i = 0; i < originArr.length; i++) {
61+
pruningArray.push(originArr[i].image.data);
62+
}
63+
return pruningArray;
64+
}
65+
66+
function restructData(
67+
originArr: paintImageType[],
68+
len: number,
69+
width: number,
70+
height: number
71+
) {
72+
const reformatData = [];
73+
74+
let start: unknown = new Date();
75+
76+
const copiedArray = deepCopy(originArr) as paintImageType[];
77+
78+
let end: unknown = new Date();
79+
let timeDiff = (end as number) - (start as number); // time difference in milliseconds
80+
81+
let start_c: unknown = new Date();
82+
for (let i = 0; i < len; i++) {
83+
let exportTemp = {
84+
sliceIndex: 0,
85+
dataFormat:
86+
"RGBA - Each successive 4-digit number forms a pixel point in data array",
87+
width,
88+
height,
89+
voxelSpacing: 0,
90+
spaceOrigin: 0,
91+
data: [],
92+
};
93+
94+
exportTemp.sliceIndex = originArr[i].index;
95+
96+
const imageData = copiedArray[i].image;
97+
98+
// const temp = Array.from(imageData.data).map((x) => Number(x));
99+
const temp = [];
100+
for (let j = 0; j < imageData.data.length; j++) {
101+
temp.push(imageData.data[j]);
102+
}
103+
104+
(exportTemp as any).data = temp;
105+
reformatData.push(exportTemp);
106+
}
107+
let end_c: unknown = new Date();
108+
let timeDiff_c = (end_c as number) - (start_c as number);
109+
return reformatData;
110+
}
111+
112+
function convertReformatDataToBlob(maskData: paintImageType[]) {
113+
try {
114+
const blob = new Blob([JSON.stringify(maskData)], {
115+
type: "text/plain;charset=utf-8",
116+
});
117+
// saveFileAsJson(blob, name);
118+
return blob;
119+
} catch (error) {
120+
console.log(error);
121+
122+
return false;
123+
}
124+
}
125+
126+
export { pruningData, restructData };

0 commit comments

Comments
 (0)