@cornerstonejs/polymorphic-segmentation 3.0.0-beta.3 → 3.0.0-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/Contour/contourComputationStrategies.d.ts +8 -0
- package/dist/esm/Contour/contourComputationStrategies.js +104 -0
- package/dist/esm/Contour/utils/createAndAddContourSegmentationsFromClippedSurfaces.d.ts +3 -0
- package/dist/esm/Contour/utils/createAndAddContourSegmentationsFromClippedSurfaces.js +71 -0
- package/dist/esm/Contour/utils/extractContourData.d.ts +3 -0
- package/dist/esm/Contour/utils/extractContourData.js +16 -0
- package/dist/esm/Contour/utils/updateContoursOnCameraModified.d.ts +1 -0
- package/dist/esm/Contour/utils/updateContoursOnCameraModified.js +25 -0
- package/dist/esm/Labelmap/convertContourToLabelmap.d.ts +8 -0
- package/dist/esm/Labelmap/convertContourToLabelmap.js +144 -0
- package/dist/esm/Labelmap/convertSurfaceToLabelmap.d.ts +6 -0
- package/dist/esm/Labelmap/convertSurfaceToLabelmap.js +50 -0
- package/dist/esm/Labelmap/labelmapComputationStrategies.d.ts +6 -0
- package/dist/esm/Labelmap/labelmapComputationStrategies.js +97 -0
- package/dist/esm/Surface/convertContourToSurface.d.ts +3 -0
- package/dist/esm/Surface/convertContourToSurface.js +37 -0
- package/dist/esm/Surface/convertLabelmapToSurface.d.ts +3 -0
- package/dist/esm/Surface/convertLabelmapToSurface.js +45 -0
- package/dist/esm/Surface/createAndCacheSurfacesFromRaw.d.ts +5 -0
- package/dist/esm/Surface/createAndCacheSurfacesFromRaw.js +34 -0
- package/dist/esm/Surface/surfaceComputationStrategies.d.ts +12 -0
- package/dist/esm/Surface/surfaceComputationStrategies.js +76 -0
- package/dist/esm/Surface/updateSurfaceData.d.ts +1 -0
- package/dist/esm/Surface/updateSurfaceData.js +55 -0
- package/dist/esm/canComputeRequestedRepresentation.d.ts +4 -0
- package/dist/esm/canComputeRequestedRepresentation.js +59 -0
- package/dist/esm/index.d.ts +7 -0
- package/dist/esm/index.js +10 -0
- package/dist/esm/registerPolySegWorker.d.ts +1 -0
- package/dist/esm/registerPolySegWorker.js +23 -0
- package/dist/esm/types/PolySegConversionOptions.d.ts +6 -0
- package/dist/esm/types/PolySegConversionOptions.js +0 -0
- package/dist/esm/types/index.d.ts +2 -0
- package/dist/esm/types/index.js +0 -0
- package/dist/esm/utilities/clipAndCacheSurfacesForViewport.d.ts +16 -0
- package/dist/esm/utilities/clipAndCacheSurfacesForViewport.js +88 -0
- package/dist/esm/utilities/index.d.ts +2 -0
- package/dist/esm/utilities/index.js +2 -0
- package/dist/esm/workers/polySegConverters.d.ts +1 -0
- package/dist/esm/workers/polySegConverters.js +391 -0
- package/package.json +9 -6
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Enums, geometryLoader } from '@cornerstonejs/core';
|
|
2
|
+
import * as cornerstoneTools from '@cornerstonejs/tools';
|
|
3
|
+
const { getSegmentation } = cornerstoneTools.segmentation.state;
|
|
4
|
+
const { getSegmentIndexColor } = cornerstoneTools.segmentation.config.color;
|
|
5
|
+
export async function createAndCacheSurfacesFromRaw(segmentationId, rawSurfacesData, options = {}) {
|
|
6
|
+
const segmentation = getSegmentation(segmentationId);
|
|
7
|
+
const geometryIds = new Map();
|
|
8
|
+
const promises = Object.keys(rawSurfacesData).map(async (index) => {
|
|
9
|
+
const rawSurfaceData = rawSurfacesData[index];
|
|
10
|
+
const segmentIndex = rawSurfaceData.segmentIndex;
|
|
11
|
+
const color = getSegmentIndexColor(options.viewport.id, segmentation.segmentationId, segmentIndex).slice(0, 3);
|
|
12
|
+
if (!color) {
|
|
13
|
+
throw new Error('No color found for segment index, unable to create surface');
|
|
14
|
+
}
|
|
15
|
+
const closedSurface = {
|
|
16
|
+
id: `segmentation_${segmentation.segmentationId}_surface_${segmentIndex}`,
|
|
17
|
+
color,
|
|
18
|
+
frameOfReferenceUID: 'test-frameOfReferenceUID',
|
|
19
|
+
points: rawSurfaceData.data.points,
|
|
20
|
+
polys: rawSurfaceData.data.polys,
|
|
21
|
+
segmentIndex,
|
|
22
|
+
};
|
|
23
|
+
const geometryId = closedSurface.id;
|
|
24
|
+
geometryIds.set(segmentIndex, geometryId);
|
|
25
|
+
return geometryLoader.createAndCacheGeometry(geometryId, {
|
|
26
|
+
type: Enums.GeometryType.SURFACE,
|
|
27
|
+
geometryData: closedSurface,
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
await Promise.all(promises);
|
|
31
|
+
return {
|
|
32
|
+
geometryIds,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Types } from '@cornerstonejs/core';
|
|
2
|
+
import type { PolySegConversionOptions } from '../types';
|
|
3
|
+
export type RawSurfacesData = {
|
|
4
|
+
segmentIndex: number;
|
|
5
|
+
data: Types.SurfaceData;
|
|
6
|
+
}[];
|
|
7
|
+
export declare function computeSurfaceData(segmentationId: string, options?: PolySegConversionOptions): Promise<{
|
|
8
|
+
geometryIds: Map<number, string>;
|
|
9
|
+
}>;
|
|
10
|
+
declare function computeSurfaceFromLabelmapSegmentation(segmentationId: any, options?: PolySegConversionOptions): Promise<RawSurfacesData>;
|
|
11
|
+
declare function computeSurfaceFromContourSegmentation(segmentationId: string, options?: PolySegConversionOptions): Promise<RawSurfacesData>;
|
|
12
|
+
export { computeSurfaceFromContourSegmentation, computeSurfaceFromLabelmapSegmentation, };
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import * as cornerstoneTools from '@cornerstonejs/tools';
|
|
2
|
+
import { convertContourToSurface } from './convertContourToSurface';
|
|
3
|
+
import { createAndCacheSurfacesFromRaw } from './createAndCacheSurfacesFromRaw';
|
|
4
|
+
import { convertLabelmapToSurface } from './convertLabelmapToSurface';
|
|
5
|
+
const { getUniqueSegmentIndices } = cornerstoneTools.utilities.segmentation;
|
|
6
|
+
const { getSegmentation } = cornerstoneTools.segmentation.state;
|
|
7
|
+
export async function computeSurfaceData(segmentationId, options = {}) {
|
|
8
|
+
const segmentIndices = options.segmentIndices?.length
|
|
9
|
+
? options.segmentIndices
|
|
10
|
+
: getUniqueSegmentIndices(segmentationId);
|
|
11
|
+
let rawSurfacesData;
|
|
12
|
+
const segmentation = getSegmentation(segmentationId);
|
|
13
|
+
const representationData = segmentation.representationData;
|
|
14
|
+
try {
|
|
15
|
+
if (representationData.Contour) {
|
|
16
|
+
rawSurfacesData = await computeSurfaceFromContourSegmentation(segmentationId, {
|
|
17
|
+
segmentIndices,
|
|
18
|
+
...options,
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
else if (representationData.Labelmap) {
|
|
22
|
+
rawSurfacesData = await computeSurfaceFromLabelmapSegmentation(segmentation.segmentationId, {
|
|
23
|
+
segmentIndices,
|
|
24
|
+
...options,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
console.error(error);
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
if (!rawSurfacesData) {
|
|
33
|
+
throw new Error('Not enough data to convert to surface, currently only support converting volume labelmap to surface if available');
|
|
34
|
+
}
|
|
35
|
+
const surfacesData = await createAndCacheSurfacesFromRaw(segmentationId, rawSurfacesData, options);
|
|
36
|
+
return surfacesData;
|
|
37
|
+
}
|
|
38
|
+
async function computeSurfaceFromLabelmapSegmentation(segmentationId, options = {}) {
|
|
39
|
+
const segmentation = getSegmentation(segmentationId);
|
|
40
|
+
if (!segmentation?.representationData?.Labelmap) {
|
|
41
|
+
console.warn('Only support surface update from labelmaps');
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const labelmapRepresentationData = segmentation.representationData.Labelmap;
|
|
45
|
+
const segmentIndices = options.segmentIndices || getUniqueSegmentIndices(segmentationId);
|
|
46
|
+
const promises = segmentIndices.map((index) => {
|
|
47
|
+
const surface = convertLabelmapToSurface(labelmapRepresentationData, index);
|
|
48
|
+
return surface;
|
|
49
|
+
});
|
|
50
|
+
const surfaces = await Promise.allSettled(promises);
|
|
51
|
+
const errors = surfaces.filter((p) => p.status === 'rejected');
|
|
52
|
+
if (errors.length > 0) {
|
|
53
|
+
console.error(errors);
|
|
54
|
+
throw new Error('Failed to convert labelmap to surface');
|
|
55
|
+
}
|
|
56
|
+
const rawSurfacesData = surfaces
|
|
57
|
+
.map((surface, index) => {
|
|
58
|
+
if (surface.status === 'fulfilled') {
|
|
59
|
+
return { segmentIndex: segmentIndices[index], data: surface.value };
|
|
60
|
+
}
|
|
61
|
+
})
|
|
62
|
+
.filter(Boolean);
|
|
63
|
+
return rawSurfacesData;
|
|
64
|
+
}
|
|
65
|
+
async function computeSurfaceFromContourSegmentation(segmentationId, options = {}) {
|
|
66
|
+
const segmentation = getSegmentation(segmentationId);
|
|
67
|
+
const contourRepresentationData = segmentation.representationData.Contour;
|
|
68
|
+
const segmentIndices = options.segmentIndices || getUniqueSegmentIndices(segmentationId);
|
|
69
|
+
const promises = segmentIndices.map(async (index) => {
|
|
70
|
+
const surface = await convertContourToSurface(contourRepresentationData, index);
|
|
71
|
+
return { segmentIndex: index, data: surface };
|
|
72
|
+
});
|
|
73
|
+
const surfaces = await Promise.all(promises);
|
|
74
|
+
return surfaces;
|
|
75
|
+
}
|
|
76
|
+
export { computeSurfaceFromContourSegmentation, computeSurfaceFromLabelmapSegmentation, };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function updateSurfaceData(segmentationId: any): Promise<void>;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { cache } from '@cornerstonejs/core';
|
|
2
|
+
import * as cornerstoneTools from '@cornerstonejs/tools';
|
|
3
|
+
import { computeSurfaceFromLabelmapSegmentation } from './surfaceComputationStrategies';
|
|
4
|
+
import { createAndCacheSurfacesFromRaw } from './createAndCacheSurfacesFromRaw';
|
|
5
|
+
const { utilities: { segmentation: { getUniqueSegmentIndices }, }, segmentation: { state: { getViewportIdsWithSegmentation, getSegmentation, getSegmentationRepresentation, }, triggerSegmentationEvents: { triggerSegmentationModified }, }, Enums: { SegmentationRepresentations }, } = cornerstoneTools;
|
|
6
|
+
export async function updateSurfaceData(segmentationId) {
|
|
7
|
+
const surfacesObj = await computeSurfaceFromLabelmapSegmentation(segmentationId);
|
|
8
|
+
if (!surfacesObj) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
const segmentation = getSegmentation(segmentationId);
|
|
12
|
+
const indices = getUniqueSegmentIndices(segmentationId);
|
|
13
|
+
if (!indices.length) {
|
|
14
|
+
const geometryIds = segmentation.representationData.Surface.geometryIds;
|
|
15
|
+
geometryIds.forEach((geometryId) => {
|
|
16
|
+
const geometry = cache.getGeometry(geometryId);
|
|
17
|
+
const surface = geometry.data;
|
|
18
|
+
surface.points = [];
|
|
19
|
+
surface.polys = [];
|
|
20
|
+
});
|
|
21
|
+
triggerSegmentationModified(segmentationId);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const promises = surfacesObj.map(({ data, segmentIndex }) => {
|
|
25
|
+
const geometryId = `segmentation_${segmentationId}_surface_${segmentIndex}`;
|
|
26
|
+
const geometry = cache.getGeometry(geometryId);
|
|
27
|
+
if (!geometry) {
|
|
28
|
+
const viewportIds = getViewportIdsWithSegmentation(segmentationId);
|
|
29
|
+
return viewportIds.map((viewportId) => {
|
|
30
|
+
const surfaceRepresentation = getSegmentationRepresentation(viewportId, {
|
|
31
|
+
segmentationId,
|
|
32
|
+
type: SegmentationRepresentations.Surface,
|
|
33
|
+
});
|
|
34
|
+
return [surfaceRepresentation].map((surfaceRepresentation) => {
|
|
35
|
+
segmentation.representationData.Surface.geometryIds.set(segmentIndex, geometryId);
|
|
36
|
+
return createAndCacheSurfacesFromRaw(segmentationId, [{ segmentIndex, data }], {
|
|
37
|
+
segmentationId: surfaceRepresentation.segmentationId,
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
else if (indices.includes(segmentIndex)) {
|
|
43
|
+
const surface = geometry.data;
|
|
44
|
+
surface.points = data.points;
|
|
45
|
+
surface.polys = data.polys;
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
const surface = geometry.data;
|
|
49
|
+
surface.points = [];
|
|
50
|
+
surface.polys = [];
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
await Promise.all(promises);
|
|
54
|
+
triggerSegmentationModified(segmentationId);
|
|
55
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { Enums } from '@cornerstonejs/tools';
|
|
2
|
+
declare const SegmentationRepresentations: typeof Enums.SegmentationRepresentations;
|
|
3
|
+
declare function canComputeRequestedRepresentation(segmentationId: string, type: typeof SegmentationRepresentations): boolean;
|
|
4
|
+
export { canComputeRequestedRepresentation };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Enums, segmentation, utilities } from '@cornerstonejs/tools';
|
|
2
|
+
const { SegmentationRepresentations } = Enums;
|
|
3
|
+
const { getSegmentation } = segmentation.state;
|
|
4
|
+
const { validateLabelmap } = utilities.segmentation;
|
|
5
|
+
const conversionPaths = new Map([
|
|
6
|
+
[
|
|
7
|
+
SegmentationRepresentations.Labelmap,
|
|
8
|
+
new Set([
|
|
9
|
+
SegmentationRepresentations.Surface,
|
|
10
|
+
SegmentationRepresentations.Contour,
|
|
11
|
+
]),
|
|
12
|
+
],
|
|
13
|
+
[
|
|
14
|
+
SegmentationRepresentations.Contour,
|
|
15
|
+
new Set([
|
|
16
|
+
SegmentationRepresentations.Labelmap,
|
|
17
|
+
SegmentationRepresentations.Surface,
|
|
18
|
+
]),
|
|
19
|
+
],
|
|
20
|
+
[
|
|
21
|
+
SegmentationRepresentations.Surface,
|
|
22
|
+
new Set([SegmentationRepresentations.Labelmap]),
|
|
23
|
+
],
|
|
24
|
+
]);
|
|
25
|
+
function canComputeRequestedRepresentation(segmentationId, type) {
|
|
26
|
+
const { representationData } = getSegmentation(segmentationId);
|
|
27
|
+
const existingRepresentationTypes = getExistingRepresentationTypes(representationData);
|
|
28
|
+
return existingRepresentationTypes.some((existingRepresentationType) => canConvertFromTo(existingRepresentationType, type));
|
|
29
|
+
}
|
|
30
|
+
function getExistingRepresentationTypes(representationData) {
|
|
31
|
+
const supportedTypes = [];
|
|
32
|
+
Object.keys(representationData).forEach((representationType) => {
|
|
33
|
+
const representationTypeData = representationData[representationType];
|
|
34
|
+
let validateFn;
|
|
35
|
+
switch (representationType) {
|
|
36
|
+
case SegmentationRepresentations.Labelmap:
|
|
37
|
+
validateFn = validateLabelmap.validate;
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
if (validateFn) {
|
|
41
|
+
try {
|
|
42
|
+
validateFn(representationTypeData);
|
|
43
|
+
supportedTypes.push(representationType);
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
console.warn(`Validation failed for labelmap of type ${representationType}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
supportedTypes.push(representationType);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
return supportedTypes;
|
|
54
|
+
}
|
|
55
|
+
async function canConvertFromTo(fromRepresentationType, toRepresentationType) {
|
|
56
|
+
return (conversionPaths.get(fromRepresentationType)?.has(toRepresentationType) ||
|
|
57
|
+
false);
|
|
58
|
+
}
|
|
59
|
+
export { canComputeRequestedRepresentation };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { computeContourData } from './Contour/contourComputationStrategies';
|
|
2
|
+
import { computeLabelmapData } from './Labelmap/labelmapComputationStrategies';
|
|
3
|
+
import { computeSurfaceData } from './Surface/surfaceComputationStrategies';
|
|
4
|
+
import { canComputeRequestedRepresentation } from './canComputeRequestedRepresentation';
|
|
5
|
+
import { updateSurfaceData } from './Surface/updateSurfaceData';
|
|
6
|
+
declare function init(): void;
|
|
7
|
+
export { canComputeRequestedRepresentation, computeContourData, computeLabelmapData, computeSurfaceData, updateSurfaceData, init, };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { computeContourData } from './Contour/contourComputationStrategies';
|
|
2
|
+
import { computeLabelmapData } from './Labelmap/labelmapComputationStrategies';
|
|
3
|
+
import { computeSurfaceData } from './Surface/surfaceComputationStrategies';
|
|
4
|
+
import { canComputeRequestedRepresentation } from './canComputeRequestedRepresentation';
|
|
5
|
+
import { updateSurfaceData } from './Surface/updateSurfaceData';
|
|
6
|
+
import { registerPolySegWorker } from './registerPolySegWorker';
|
|
7
|
+
function init() {
|
|
8
|
+
registerPolySegWorker();
|
|
9
|
+
}
|
|
10
|
+
export { canComputeRequestedRepresentation, computeContourData, computeLabelmapData, computeSurfaceData, updateSurfaceData, init, };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function registerPolySegWorker(): void;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { getWebWorkerManager } from '@cornerstonejs/core';
|
|
2
|
+
let registered = false;
|
|
3
|
+
export function registerPolySegWorker() {
|
|
4
|
+
if (registered) {
|
|
5
|
+
return;
|
|
6
|
+
}
|
|
7
|
+
registered = true;
|
|
8
|
+
const workerFn = () => {
|
|
9
|
+
return new Worker(new URL('./workers/polySegConverters.js', import.meta.url), {
|
|
10
|
+
name: 'polySeg',
|
|
11
|
+
type: 'module',
|
|
12
|
+
});
|
|
13
|
+
};
|
|
14
|
+
const workerManager = getWebWorkerManager();
|
|
15
|
+
const options = {
|
|
16
|
+
maxWorkerInstances: 1,
|
|
17
|
+
autoTerminateOnIdle: {
|
|
18
|
+
enabled: true,
|
|
19
|
+
idleTimeThreshold: 2000,
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
workerManager.registerWorker('polySeg', workerFn, options);
|
|
23
|
+
}
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Types } from '@cornerstonejs/core';
|
|
2
|
+
export type SurfacesInfo = {
|
|
3
|
+
id: string;
|
|
4
|
+
points: number[];
|
|
5
|
+
polys: number[];
|
|
6
|
+
segmentIndex: number;
|
|
7
|
+
};
|
|
8
|
+
export type SurfaceClipResult = {
|
|
9
|
+
points: number[];
|
|
10
|
+
lines: number[];
|
|
11
|
+
numberOfCells: number;
|
|
12
|
+
};
|
|
13
|
+
export type PolyDataClipCacheType = Map<number, Map<string, SurfaceClipResult>>;
|
|
14
|
+
export declare function clipAndCacheSurfacesForViewport(surfacesInfo: SurfacesInfo[], viewport: Types.IVolumeViewport): Promise<PolyDataClipCacheType>;
|
|
15
|
+
export declare function generateCacheId(viewport: any, viewPlaneNormal: any, sliceIndex: any): string;
|
|
16
|
+
export declare function updatePolyDataCache(segmentIndex: number, cacheId: string, polyDataResult: SurfaceClipResult): void;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { Enums, getWebWorkerManager, eventTarget, triggerEvent, } from '@cornerstonejs/core';
|
|
2
|
+
import { Enums as ToolsEnums, utilities } from '@cornerstonejs/tools';
|
|
3
|
+
import { registerPolySegWorker } from '../registerPolySegWorker';
|
|
4
|
+
const workerManager = getWebWorkerManager();
|
|
5
|
+
const { WorkerTypes } = ToolsEnums;
|
|
6
|
+
const { pointToString } = utilities;
|
|
7
|
+
const polyDataCache = new Map();
|
|
8
|
+
const surfacesAABBCache = new Map();
|
|
9
|
+
const triggerWorkerProgress = (eventTarget, progress) => {
|
|
10
|
+
triggerEvent(eventTarget, Enums.Events.WEB_WORKER_PROGRESS, {
|
|
11
|
+
progress,
|
|
12
|
+
type: WorkerTypes.SURFACE_CLIPPING,
|
|
13
|
+
});
|
|
14
|
+
};
|
|
15
|
+
export async function clipAndCacheSurfacesForViewport(surfacesInfo, viewport) {
|
|
16
|
+
registerPolySegWorker();
|
|
17
|
+
const planesInfo = viewport.getSlicesClippingPlanes?.();
|
|
18
|
+
if (!planesInfo) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const currentSliceIndex = viewport.getSliceIndex();
|
|
22
|
+
planesInfo.sort((a, b) => {
|
|
23
|
+
const diffA = Math.abs(a.sliceIndex - currentSliceIndex);
|
|
24
|
+
const diffB = Math.abs(b.sliceIndex - currentSliceIndex);
|
|
25
|
+
return diffA - diffB;
|
|
26
|
+
});
|
|
27
|
+
triggerWorkerProgress(eventTarget, 0);
|
|
28
|
+
await updateSurfacesAABBCache(surfacesInfo);
|
|
29
|
+
const surfacesAABB = new Map();
|
|
30
|
+
surfacesInfo.forEach((surface) => {
|
|
31
|
+
surfacesAABB.set(surface.id, surfacesAABBCache.get(surface.id));
|
|
32
|
+
});
|
|
33
|
+
const camera = viewport.getCamera();
|
|
34
|
+
await workerManager
|
|
35
|
+
.executeTask('polySeg', 'cutSurfacesIntoPlanes', {
|
|
36
|
+
surfacesInfo,
|
|
37
|
+
planesInfo,
|
|
38
|
+
surfacesAABB,
|
|
39
|
+
}, {
|
|
40
|
+
callbacks: [
|
|
41
|
+
({ progress }) => {
|
|
42
|
+
triggerWorkerProgress(eventTarget, progress);
|
|
43
|
+
},
|
|
44
|
+
({ sliceIndex, polyDataResults }) => {
|
|
45
|
+
polyDataResults.forEach((polyDataResult, segmentIndex) => {
|
|
46
|
+
const segmentIndexNumber = Number(segmentIndex);
|
|
47
|
+
const cacheId = generateCacheId(viewport, camera.viewPlaneNormal, sliceIndex);
|
|
48
|
+
updatePolyDataCache(segmentIndexNumber, cacheId, polyDataResult);
|
|
49
|
+
});
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
})
|
|
53
|
+
.catch((error) => {
|
|
54
|
+
console.error(error);
|
|
55
|
+
});
|
|
56
|
+
triggerWorkerProgress(eventTarget, 100);
|
|
57
|
+
return polyDataCache;
|
|
58
|
+
}
|
|
59
|
+
async function updateSurfacesAABBCache(surfacesInfo) {
|
|
60
|
+
const surfacesWithoutAABB = surfacesInfo.filter((surface) => !surfacesAABBCache.has(surface.id));
|
|
61
|
+
if (!surfacesWithoutAABB.length) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const surfacesAABB = await workerManager.executeTask('polySeg', 'getSurfacesAABBs', {
|
|
65
|
+
surfacesInfo: surfacesWithoutAABB,
|
|
66
|
+
}, {
|
|
67
|
+
callbacks: [
|
|
68
|
+
({ progress }) => {
|
|
69
|
+
triggerWorkerProgress(eventTarget, progress);
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
});
|
|
73
|
+
surfacesAABB.forEach((aabb, id) => {
|
|
74
|
+
surfacesAABBCache.set(id, aabb);
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
export function generateCacheId(viewport, viewPlaneNormal, sliceIndex) {
|
|
78
|
+
return `${viewport.id}-${pointToString(viewPlaneNormal)}-${sliceIndex}`;
|
|
79
|
+
}
|
|
80
|
+
export function updatePolyDataCache(segmentIndex, cacheId, polyDataResult) {
|
|
81
|
+
const { points, lines, numberOfCells } = polyDataResult;
|
|
82
|
+
let segmentCache = polyDataCache.get(segmentIndex);
|
|
83
|
+
if (!segmentCache) {
|
|
84
|
+
segmentCache = new Map();
|
|
85
|
+
polyDataCache.set(segmentIndex, segmentCache);
|
|
86
|
+
}
|
|
87
|
+
segmentCache.set(cacheId, { points, lines, numberOfCells });
|
|
88
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|