@cornerstonejs/adapters 3.14.3 → 3.15.0
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/adapters/Cornerstone3D/Angle.d.ts +66 -14
- package/dist/esm/adapters/Cornerstone3D/Angle.js +102 -2
- package/dist/esm/adapters/Cornerstone3D/ArrowAnnotate.d.ts +27 -15
- package/dist/esm/adapters/Cornerstone3D/ArrowAnnotate.js +110 -1
- package/dist/esm/adapters/Cornerstone3D/BaseAdapter3D.d.ts +18 -9
- package/dist/esm/adapters/Cornerstone3D/BaseAdapter3D.js +25 -1
- package/dist/esm/adapters/Cornerstone3D/Bidirectional.d.ts +84 -14
- package/dist/esm/adapters/Cornerstone3D/Bidirectional.js +133 -9
- package/dist/esm/adapters/Cornerstone3D/CircleROI.d.ts +33 -15
- package/dist/esm/adapters/Cornerstone3D/CircleROI.js +97 -2
- package/dist/esm/adapters/Cornerstone3D/CobbAngle.d.ts +66 -14
- package/dist/esm/adapters/Cornerstone3D/CobbAngle.js +107 -2
- package/dist/esm/adapters/Cornerstone3D/EllipticalROI.d.ts +30 -15
- package/dist/esm/adapters/Cornerstone3D/EllipticalROI.js +151 -2
- package/dist/esm/adapters/Cornerstone3D/KeyImage.d.ts +17 -15
- package/dist/esm/adapters/Cornerstone3D/Length.d.ts +46 -14
- package/dist/esm/adapters/Cornerstone3D/Length.js +93 -6
- package/dist/esm/adapters/Cornerstone3D/MeasurementReport.d.ts +82 -12
- package/dist/esm/adapters/Cornerstone3D/MeasurementReport.js +181 -44
- package/dist/esm/adapters/Cornerstone3D/PlanarFreehandROI.d.ts +41 -15
- package/dist/esm/adapters/Cornerstone3D/PlanarFreehandROI.js +112 -2
- package/dist/esm/adapters/Cornerstone3D/Probe.d.ts +39 -14
- package/dist/esm/adapters/Cornerstone3D/Probe.js +112 -1
- package/dist/esm/adapters/Cornerstone3D/RectangleROI.d.ts +31 -15
- package/dist/esm/adapters/Cornerstone3D/RectangleROI.js +82 -2
- package/dist/esm/adapters/Cornerstone3D/UltrasoundDirectional.d.ts +8 -9
- package/dist/esm/version.d.ts +1 -1
- package/package.json +5 -5
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { utilities, derivations, normalizers, data } from 'dcmjs';
|
|
2
|
+
import { cache } from '@cornerstonejs/core';
|
|
2
3
|
import CORNERSTONE_3D_TAG from './cornerstone3DTag.js';
|
|
3
4
|
import { toArray } from '../helpers/toArray.js';
|
|
4
5
|
import { codeMeaningEquals } from '../helpers/codeMeaningEquals.js';
|
|
@@ -92,15 +93,13 @@ class MeasurementReport {
|
|
|
92
93
|
};
|
|
93
94
|
return _meta;
|
|
94
95
|
}
|
|
95
|
-
static
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
const NUMGroup = contentSequenceArr.find(group => group.ValueType === "NUM");
|
|
103
|
-
const SCOORDGroup = toArray(NUMGroup.ContentSequence).find(group => group.ValueType === "SCOORD");
|
|
96
|
+
static processSCOORDGroup(_ref) {
|
|
97
|
+
let {
|
|
98
|
+
SCOORDGroup,
|
|
99
|
+
toolType,
|
|
100
|
+
sopInstanceUIDToImageIdMap,
|
|
101
|
+
metadata
|
|
102
|
+
} = _ref;
|
|
104
103
|
const {
|
|
105
104
|
ReferencedSOPSequence
|
|
106
105
|
} = SCOORDGroup.ContentSequence;
|
|
@@ -110,23 +109,101 @@ class MeasurementReport {
|
|
|
110
109
|
} = ReferencedSOPSequence;
|
|
111
110
|
const referencedImageId = sopInstanceUIDToImageIdMap[ReferencedSOPInstanceUID];
|
|
112
111
|
const imagePlaneModule = metadata.get("imagePlaneModule", referencedImageId);
|
|
112
|
+
return {
|
|
113
|
+
SCOORDGroup,
|
|
114
|
+
ReferencedSOPSequence,
|
|
115
|
+
ReferencedSOPInstanceUID,
|
|
116
|
+
ReferencedFrameNumber,
|
|
117
|
+
state: {
|
|
118
|
+
description: undefined,
|
|
119
|
+
sopInstanceUid: ReferencedSOPInstanceUID,
|
|
120
|
+
annotation: {
|
|
121
|
+
annotationUID: DicomMetaDictionary.uid(),
|
|
122
|
+
metadata: {
|
|
123
|
+
toolName: toolType,
|
|
124
|
+
referencedImageId,
|
|
125
|
+
FrameOfReferenceUID: imagePlaneModule.frameOfReferenceUID,
|
|
126
|
+
label: ""
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
static processSCOORD3DGroup(_ref2) {
|
|
133
|
+
let {
|
|
134
|
+
SCOORD3DGroup,
|
|
135
|
+
toolType
|
|
136
|
+
} = _ref2;
|
|
137
|
+
return {
|
|
138
|
+
SCOORD3DGroup,
|
|
139
|
+
FrameOfReferenceUID: SCOORD3DGroup.ReferencedFrameOfReferenceUID,
|
|
140
|
+
state: {
|
|
141
|
+
description: undefined,
|
|
142
|
+
annotation: {
|
|
143
|
+
annotationUID: DicomMetaDictionary.uid(),
|
|
144
|
+
metadata: {
|
|
145
|
+
toolName: toolType,
|
|
146
|
+
FrameOfReferenceUID: SCOORD3DGroup.ReferencedFrameOfReferenceUID,
|
|
147
|
+
label: ""
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
static getSpatialCoordinatesState(_ref3) {
|
|
154
|
+
let {
|
|
155
|
+
NUMGroup,
|
|
156
|
+
sopInstanceUIDToImageIdMap,
|
|
157
|
+
metadata,
|
|
158
|
+
toolType
|
|
159
|
+
} = _ref3;
|
|
160
|
+
const SCOORDGroup = toArray(NUMGroup.ContentSequence).find(group => group.ValueType === "SCOORD");
|
|
161
|
+
const SCOORD3DGroup = toArray(NUMGroup.ContentSequence).find(group => group.ValueType === "SCOORD3D");
|
|
162
|
+
if (SCOORDGroup) {
|
|
163
|
+
return this.processSCOORDGroup({
|
|
164
|
+
SCOORDGroup,
|
|
165
|
+
toolType,
|
|
166
|
+
metadata,
|
|
167
|
+
sopInstanceUIDToImageIdMap
|
|
168
|
+
});
|
|
169
|
+
} else if (SCOORD3DGroup) {
|
|
170
|
+
return this.processSCOORD3DGroup({
|
|
171
|
+
SCOORD3DGroup,
|
|
172
|
+
toolType
|
|
173
|
+
});
|
|
174
|
+
} else {
|
|
175
|
+
throw new Error("No spatial coordinates group found.");
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
static processSpatialCoordinatesGroup(_ref4) {
|
|
179
|
+
let {
|
|
180
|
+
NUMGroup,
|
|
181
|
+
sopInstanceUIDToImageIdMap,
|
|
182
|
+
metadata,
|
|
183
|
+
findingGroup,
|
|
184
|
+
findingSiteGroups,
|
|
185
|
+
toolType
|
|
186
|
+
} = _ref4;
|
|
187
|
+
const {
|
|
188
|
+
state,
|
|
189
|
+
SCOORDGroup,
|
|
190
|
+
ReferencedSOPSequence,
|
|
191
|
+
ReferencedSOPInstanceUID,
|
|
192
|
+
ReferencedFrameNumber,
|
|
193
|
+
SCOORD3DGroup,
|
|
194
|
+
FrameOfReferenceUID
|
|
195
|
+
} = this.getSpatialCoordinatesState({
|
|
196
|
+
NUMGroup,
|
|
197
|
+
sopInstanceUIDToImageIdMap,
|
|
198
|
+
metadata,
|
|
199
|
+
toolType
|
|
200
|
+
});
|
|
113
201
|
const finding = findingGroup ? addAccessors(findingGroup.ConceptCodeSequence) : undefined;
|
|
114
202
|
const findingSites = findingSiteGroups.map(fsg => {
|
|
115
203
|
return addAccessors(fsg.ConceptCodeSequence);
|
|
116
204
|
});
|
|
117
205
|
const defaultState = {
|
|
118
|
-
|
|
119
|
-
sopInstanceUid: ReferencedSOPInstanceUID,
|
|
120
|
-
annotation: {
|
|
121
|
-
annotationUID: DicomMetaDictionary.uid(),
|
|
122
|
-
metadata: {
|
|
123
|
-
toolName: toolType,
|
|
124
|
-
referencedImageId,
|
|
125
|
-
FrameOfReferenceUID: imagePlaneModule.frameOfReferenceUID,
|
|
126
|
-
label: ""
|
|
127
|
-
},
|
|
128
|
-
data: undefined
|
|
129
|
-
},
|
|
206
|
+
...state,
|
|
130
207
|
finding,
|
|
131
208
|
findingSites
|
|
132
209
|
};
|
|
@@ -140,39 +217,96 @@ class MeasurementReport {
|
|
|
140
217
|
SCOORDGroup,
|
|
141
218
|
ReferencedSOPSequence,
|
|
142
219
|
ReferencedSOPInstanceUID,
|
|
143
|
-
ReferencedFrameNumber
|
|
220
|
+
ReferencedFrameNumber,
|
|
221
|
+
SCOORD3DGroup,
|
|
222
|
+
FrameOfReferenceUID
|
|
144
223
|
};
|
|
145
224
|
}
|
|
225
|
+
static getSetupMeasurementData(MeasurementGroup, sopInstanceUIDToImageIdMap, metadata, toolType) {
|
|
226
|
+
const {
|
|
227
|
+
ContentSequence
|
|
228
|
+
} = MeasurementGroup;
|
|
229
|
+
const contentSequenceArr = toArray(ContentSequence);
|
|
230
|
+
const findingGroup = contentSequenceArr.find(group => this.codeValueMatch(group, FINDING));
|
|
231
|
+
const findingSiteGroups = contentSequenceArr.filter(group => this.codeValueMatch(group, FINDING_SITE, FINDING_SITE_OLD)) || [];
|
|
232
|
+
const NUMGroup = contentSequenceArr.find(group => group.ValueType === "NUM");
|
|
233
|
+
return this.processSpatialCoordinatesGroup({
|
|
234
|
+
NUMGroup,
|
|
235
|
+
sopInstanceUIDToImageIdMap,
|
|
236
|
+
metadata,
|
|
237
|
+
findingGroup,
|
|
238
|
+
findingSiteGroups,
|
|
239
|
+
toolType
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
static generateReferencedSOPSequence(_ref5) {
|
|
243
|
+
let {
|
|
244
|
+
toolData,
|
|
245
|
+
toolTypes,
|
|
246
|
+
metadataProvider,
|
|
247
|
+
imageId,
|
|
248
|
+
sopInstanceUIDsToSeriesInstanceUIDMap,
|
|
249
|
+
derivationSourceDatasets
|
|
250
|
+
} = _ref5;
|
|
251
|
+
const effectiveImageId = imageId === "none" ? this.getImageIdFromVolume({
|
|
252
|
+
toolData,
|
|
253
|
+
toolTypes
|
|
254
|
+
}) : imageId;
|
|
255
|
+
const sopCommonModule = metadataProvider.get("sopCommonModule", effectiveImageId);
|
|
256
|
+
const instance = metadataProvider.get("instance", effectiveImageId);
|
|
257
|
+
const {
|
|
258
|
+
sopInstanceUID,
|
|
259
|
+
sopClassUID
|
|
260
|
+
} = sopCommonModule;
|
|
261
|
+
const {
|
|
262
|
+
SeriesInstanceUID: seriesInstanceUID
|
|
263
|
+
} = instance;
|
|
264
|
+
sopInstanceUIDsToSeriesInstanceUIDMap[sopInstanceUID] = seriesInstanceUID;
|
|
265
|
+
if (!derivationSourceDatasets.find(dsd => dsd.SeriesInstanceUID === seriesInstanceUID)) {
|
|
266
|
+
const derivationSourceDataset = MeasurementReport.generateDerivationSourceDataset(instance);
|
|
267
|
+
derivationSourceDatasets.push(derivationSourceDataset);
|
|
268
|
+
}
|
|
269
|
+
const frameNumber = metadataProvider.get("frameNumber", effectiveImageId);
|
|
270
|
+
const ReferencedSOPSequence = {
|
|
271
|
+
ReferencedSOPClassUID: sopClassUID,
|
|
272
|
+
ReferencedSOPInstanceUID: sopInstanceUID,
|
|
273
|
+
ReferencedFrameNumber: undefined
|
|
274
|
+
};
|
|
275
|
+
if (instance && instance.NumberOfFrames && instance.NumberOfFrames > 1 || Normalizer.isMultiframeSOPClassUID(sopClassUID)) {
|
|
276
|
+
ReferencedSOPSequence.ReferencedFrameNumber = frameNumber;
|
|
277
|
+
}
|
|
278
|
+
return ReferencedSOPSequence;
|
|
279
|
+
}
|
|
280
|
+
static getImageIdFromVolume(_ref6) {
|
|
281
|
+
let {
|
|
282
|
+
toolData,
|
|
283
|
+
toolTypes
|
|
284
|
+
} = _ref6;
|
|
285
|
+
const referenceToolData = toolData?.[toolTypes?.[0]]?.data?.[0];
|
|
286
|
+
const volumeId = referenceToolData?.metadata?.volumeId;
|
|
287
|
+
const volume = cache.getVolume(volumeId);
|
|
288
|
+
const imageId = volume.imageIds[0];
|
|
289
|
+
return imageId;
|
|
290
|
+
}
|
|
146
291
|
static generateReport(toolState, metadataProvider, worldToImageCoords, options) {
|
|
147
292
|
let allMeasurementGroups = [];
|
|
148
293
|
const sopInstanceUIDsToSeriesInstanceUIDMap = {};
|
|
149
294
|
const derivationSourceDatasets = [];
|
|
150
295
|
const _meta = MeasurementReport.generateDatasetMeta();
|
|
296
|
+
let is3DSR = false;
|
|
151
297
|
Object.keys(toolState).forEach(imageId => {
|
|
152
|
-
const sopCommonModule = metadataProvider.get("sopCommonModule", imageId);
|
|
153
|
-
const instance = metadataProvider.get("instance", imageId);
|
|
154
|
-
const {
|
|
155
|
-
sopInstanceUID,
|
|
156
|
-
sopClassUID
|
|
157
|
-
} = sopCommonModule;
|
|
158
|
-
const {
|
|
159
|
-
SeriesInstanceUID: seriesInstanceUID
|
|
160
|
-
} = instance;
|
|
161
|
-
sopInstanceUIDsToSeriesInstanceUIDMap[sopInstanceUID] = seriesInstanceUID;
|
|
162
|
-
if (!derivationSourceDatasets.find(dsd => dsd.SeriesInstanceUID === seriesInstanceUID)) {
|
|
163
|
-
const derivationSourceDataset = MeasurementReport.generateDerivationSourceDataset(instance);
|
|
164
|
-
derivationSourceDatasets.push(derivationSourceDataset);
|
|
165
|
-
}
|
|
166
|
-
const frameNumber = metadataProvider.get("frameNumber", imageId);
|
|
167
298
|
const toolData = toolState[imageId];
|
|
168
299
|
const toolTypes = Object.keys(toolData);
|
|
169
|
-
const ReferencedSOPSequence = {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
300
|
+
const ReferencedSOPSequence = this.generateReferencedSOPSequence({
|
|
301
|
+
toolData,
|
|
302
|
+
toolTypes,
|
|
303
|
+
metadataProvider,
|
|
304
|
+
imageId,
|
|
305
|
+
sopInstanceUIDsToSeriesInstanceUIDMap,
|
|
306
|
+
derivationSourceDatasets
|
|
307
|
+
});
|
|
308
|
+
if (imageId === "none") {
|
|
309
|
+
is3DSR = true;
|
|
176
310
|
}
|
|
177
311
|
const measurementGroups = [];
|
|
178
312
|
toolTypes.forEach(toolType => {
|
|
@@ -194,6 +328,9 @@ class MeasurementReport {
|
|
|
194
328
|
report.dataset = Object.assign(report.dataset, contentItem);
|
|
195
329
|
report.dataset._meta = _meta;
|
|
196
330
|
report.SpecificCharacterSet = "ISO_IR 192";
|
|
331
|
+
if (is3DSR) {
|
|
332
|
+
report.dataset.SOPClassUID = DicomMetaDictionary.sopClassUIDsByName.Comprehensive3DSR;
|
|
333
|
+
}
|
|
197
334
|
return report;
|
|
198
335
|
}
|
|
199
336
|
static generateToolState(dataset, sopInstanceUIDToImageIdMap, imageToWorldCoords, metadata, hooks) {
|
|
@@ -1,23 +1,47 @@
|
|
|
1
1
|
import BaseAdapter3D from "./BaseAdapter3D";
|
|
2
2
|
declare class PlanarFreehandROI extends BaseAdapter3D {
|
|
3
3
|
static closedContourThreshold: number;
|
|
4
|
-
static getMeasurementData(MeasurementGroup: any, sopInstanceUIDToImageIdMap: any, imageToWorldCoords: any, metadata: any):
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
4
|
+
static getMeasurementData(MeasurementGroup: any, sopInstanceUIDToImageIdMap: any, imageToWorldCoords: any, metadata: any): any;
|
|
5
|
+
static getMeasurementDataFromScoord({ defaultState, SCOORDGroup, imageToWorldCoords, NUMGroup, ReferencedFrameNumber }: {
|
|
6
|
+
defaultState: any;
|
|
7
|
+
SCOORDGroup: any;
|
|
8
|
+
imageToWorldCoords: any;
|
|
9
|
+
NUMGroup: any;
|
|
10
|
+
ReferencedFrameNumber: any;
|
|
11
|
+
}): any;
|
|
12
|
+
static getMeasurementDataFromScoord3D({ defaultState, SCOORD3DGroup }: {
|
|
13
|
+
defaultState: any;
|
|
14
|
+
SCOORD3DGroup: any;
|
|
15
|
+
}): any;
|
|
16
|
+
static getTID300RepresentationArguments(tool: any, worldToImageCoords: any): {
|
|
17
|
+
points: any;
|
|
18
|
+
area: any;
|
|
19
|
+
areaUnit: any;
|
|
20
|
+
perimeter: any;
|
|
21
|
+
modalityUnit: any;
|
|
22
|
+
mean: any;
|
|
23
|
+
max: any;
|
|
24
|
+
stdDev: any;
|
|
25
|
+
trackingIdentifierTextValue: string;
|
|
17
26
|
finding: any;
|
|
18
|
-
findingSites: any
|
|
27
|
+
findingSites: any;
|
|
28
|
+
ReferencedFrameOfReferenceUID: any;
|
|
29
|
+
use3DSpatialCoordinates: boolean;
|
|
30
|
+
} | {
|
|
31
|
+
points: any;
|
|
32
|
+
area: any;
|
|
33
|
+
areaUnit: any;
|
|
34
|
+
perimeter: any;
|
|
35
|
+
modalityUnit: any;
|
|
36
|
+
mean: any;
|
|
37
|
+
max: any;
|
|
38
|
+
stdDev: any;
|
|
39
|
+
trackingIdentifierTextValue: string;
|
|
40
|
+
finding: any;
|
|
41
|
+
findingSites: any;
|
|
42
|
+
use3DSpatialCoordinates: boolean;
|
|
19
43
|
};
|
|
20
|
-
static
|
|
44
|
+
static getTID300RepresentationArgumentsSCOORD3D(tool: any): {
|
|
21
45
|
points: any;
|
|
22
46
|
area: any;
|
|
23
47
|
areaUnit: any;
|
|
@@ -29,6 +53,8 @@ declare class PlanarFreehandROI extends BaseAdapter3D {
|
|
|
29
53
|
trackingIdentifierTextValue: string;
|
|
30
54
|
finding: any;
|
|
31
55
|
findingSites: any;
|
|
56
|
+
ReferencedFrameOfReferenceUID: any;
|
|
57
|
+
use3DSpatialCoordinates: boolean;
|
|
32
58
|
};
|
|
33
59
|
}
|
|
34
60
|
export default PlanarFreehandROI;
|
|
@@ -13,8 +13,34 @@ class PlanarFreehandROI extends BaseAdapter3D {
|
|
|
13
13
|
defaultState,
|
|
14
14
|
NUMGroup,
|
|
15
15
|
SCOORDGroup,
|
|
16
|
+
SCOORD3DGroup,
|
|
16
17
|
ReferencedFrameNumber
|
|
17
18
|
} = MeasurementReport.getSetupMeasurementData(MeasurementGroup, sopInstanceUIDToImageIdMap, metadata, PlanarFreehandROI.toolType);
|
|
19
|
+
if (SCOORDGroup) {
|
|
20
|
+
return this.getMeasurementDataFromScoord({
|
|
21
|
+
defaultState,
|
|
22
|
+
SCOORDGroup,
|
|
23
|
+
imageToWorldCoords,
|
|
24
|
+
NUMGroup,
|
|
25
|
+
ReferencedFrameNumber
|
|
26
|
+
});
|
|
27
|
+
} else if (SCOORD3DGroup) {
|
|
28
|
+
return this.getMeasurementDataFromScoord3D({
|
|
29
|
+
defaultState,
|
|
30
|
+
SCOORD3DGroup
|
|
31
|
+
});
|
|
32
|
+
} else {
|
|
33
|
+
throw new Error("Can't get measurement data with missing SCOORD and SCOORD3D groups.");
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
static getMeasurementDataFromScoord(_ref) {
|
|
37
|
+
let {
|
|
38
|
+
defaultState,
|
|
39
|
+
SCOORDGroup,
|
|
40
|
+
imageToWorldCoords,
|
|
41
|
+
NUMGroup,
|
|
42
|
+
ReferencedFrameNumber
|
|
43
|
+
} = _ref;
|
|
18
44
|
const referencedImageId = defaultState.annotation.metadata.referencedImageId;
|
|
19
45
|
const {
|
|
20
46
|
GraphicData
|
|
@@ -56,6 +82,46 @@ class PlanarFreehandROI extends BaseAdapter3D {
|
|
|
56
82
|
};
|
|
57
83
|
return state;
|
|
58
84
|
}
|
|
85
|
+
static getMeasurementDataFromScoord3D(_ref2) {
|
|
86
|
+
let {
|
|
87
|
+
defaultState,
|
|
88
|
+
SCOORD3DGroup
|
|
89
|
+
} = _ref2;
|
|
90
|
+
const {
|
|
91
|
+
GraphicData
|
|
92
|
+
} = SCOORD3DGroup;
|
|
93
|
+
const worldCoords = [];
|
|
94
|
+
for (let i = 0; i < GraphicData.length; i += 3) {
|
|
95
|
+
const point = [GraphicData[i], GraphicData[i + 1], GraphicData[i + 2]];
|
|
96
|
+
worldCoords.push(point);
|
|
97
|
+
}
|
|
98
|
+
const distanceBetweenFirstAndLastPoint = vec3.distance(worldCoords[worldCoords.length - 1], worldCoords[0]);
|
|
99
|
+
let isOpenContour = true;
|
|
100
|
+
if (distanceBetweenFirstAndLastPoint < this.closedContourThreshold) {
|
|
101
|
+
worldCoords.pop();
|
|
102
|
+
isOpenContour = false;
|
|
103
|
+
}
|
|
104
|
+
const points = [];
|
|
105
|
+
if (isOpenContour) {
|
|
106
|
+
points.push(worldCoords[0], worldCoords[worldCoords.length - 1]);
|
|
107
|
+
}
|
|
108
|
+
const state = defaultState;
|
|
109
|
+
state.annotation.data = {
|
|
110
|
+
contour: {
|
|
111
|
+
polyline: worldCoords,
|
|
112
|
+
closed: !isOpenContour
|
|
113
|
+
},
|
|
114
|
+
handles: {
|
|
115
|
+
points,
|
|
116
|
+
activeHandleIndex: null,
|
|
117
|
+
textBox: {
|
|
118
|
+
hasMoved: false
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
cachedStats: {}
|
|
122
|
+
};
|
|
123
|
+
return state;
|
|
124
|
+
}
|
|
59
125
|
static getTID300RepresentationArguments(tool, worldToImageCoords) {
|
|
60
126
|
const {
|
|
61
127
|
data,
|
|
@@ -72,7 +138,7 @@ class PlanarFreehandROI extends BaseAdapter3D {
|
|
|
72
138
|
referencedImageId
|
|
73
139
|
} = metadata;
|
|
74
140
|
if (!referencedImageId) {
|
|
75
|
-
|
|
141
|
+
return this.getTID300RepresentationArgumentsSCOORD3D(tool);
|
|
76
142
|
}
|
|
77
143
|
const points = polyline.map(worldPos => worldToImageCoords(referencedImageId, worldPos));
|
|
78
144
|
if (!isOpenContour) {
|
|
@@ -99,7 +165,51 @@ class PlanarFreehandROI extends BaseAdapter3D {
|
|
|
99
165
|
stdDev,
|
|
100
166
|
trackingIdentifierTextValue: this.trackingIdentifierTextValue,
|
|
101
167
|
finding,
|
|
102
|
-
findingSites: findingSites || []
|
|
168
|
+
findingSites: findingSites || [],
|
|
169
|
+
use3DSpatialCoordinates: false
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
static getTID300RepresentationArgumentsSCOORD3D(tool) {
|
|
173
|
+
const {
|
|
174
|
+
data,
|
|
175
|
+
finding,
|
|
176
|
+
findingSites,
|
|
177
|
+
metadata
|
|
178
|
+
} = tool;
|
|
179
|
+
const {
|
|
180
|
+
polyline,
|
|
181
|
+
closed
|
|
182
|
+
} = data.contour;
|
|
183
|
+
const isOpenContour = closed !== true;
|
|
184
|
+
const points = polyline;
|
|
185
|
+
if (!isOpenContour) {
|
|
186
|
+
const firstPoint = points[0];
|
|
187
|
+
points.push([firstPoint[0], firstPoint[1], firstPoint[2]]);
|
|
188
|
+
}
|
|
189
|
+
const cachedStatsKeys = Object.keys(data.cachedStats)[0];
|
|
190
|
+
const {
|
|
191
|
+
area,
|
|
192
|
+
areaUnit,
|
|
193
|
+
modalityUnit,
|
|
194
|
+
perimeter,
|
|
195
|
+
mean,
|
|
196
|
+
max,
|
|
197
|
+
stdDev
|
|
198
|
+
} = cachedStatsKeys ? data.cachedStats[cachedStatsKeys] : {};
|
|
199
|
+
return {
|
|
200
|
+
points,
|
|
201
|
+
area,
|
|
202
|
+
areaUnit,
|
|
203
|
+
perimeter,
|
|
204
|
+
modalityUnit,
|
|
205
|
+
mean,
|
|
206
|
+
max,
|
|
207
|
+
stdDev,
|
|
208
|
+
trackingIdentifierTextValue: this.trackingIdentifierTextValue,
|
|
209
|
+
finding,
|
|
210
|
+
findingSites: findingSites || [],
|
|
211
|
+
ReferencedFrameOfReferenceUID: metadata.FrameOfReferenceUID,
|
|
212
|
+
use3DSpatialCoordinates: true
|
|
103
213
|
};
|
|
104
214
|
}
|
|
105
215
|
}
|
|
@@ -1,20 +1,45 @@
|
|
|
1
1
|
import BaseAdapter3D from "./BaseAdapter3D";
|
|
2
2
|
declare class Probe extends BaseAdapter3D {
|
|
3
|
-
static getMeasurementData(MeasurementGroup: any, sopInstanceUIDToImageIdMap: any, imageToWorldCoords: any, metadata: any, trackingIdentifier: any):
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
3
|
+
static getMeasurementData(MeasurementGroup: any, sopInstanceUIDToImageIdMap: any, imageToWorldCoords: any, metadata: any, trackingIdentifier: any): any;
|
|
4
|
+
static getMeasurementDataFromScoord({ state, defaultState, SCOORDGroup, imageToWorldCoords }: {
|
|
5
|
+
state: any;
|
|
6
|
+
defaultState: any;
|
|
7
|
+
SCOORDGroup: any;
|
|
8
|
+
imageToWorldCoords: any;
|
|
9
|
+
}): any;
|
|
10
|
+
static getMeasurementDataFromScoord3D({ state, SCOORD3DGroup }: {
|
|
11
|
+
state: any;
|
|
12
|
+
SCOORD3DGroup: any;
|
|
13
|
+
}): any;
|
|
14
|
+
static getTID300RepresentationArguments(tool: any, worldToImageCoords: any): {
|
|
15
|
+
points: {
|
|
16
|
+
x: any;
|
|
17
|
+
y: any;
|
|
18
|
+
z: any;
|
|
19
|
+
}[];
|
|
20
|
+
trackingIdentifierTextValue: string;
|
|
21
|
+
ReferencedFrameOfReferenceUID: any;
|
|
22
|
+
findingSites: any;
|
|
16
23
|
finding: any;
|
|
17
|
-
|
|
24
|
+
use3DSpatialCoordinates: boolean;
|
|
25
|
+
} | {
|
|
26
|
+
points: any;
|
|
27
|
+
trackingIdentifierTextValue: string;
|
|
28
|
+
findingSites: any;
|
|
29
|
+
finding: any;
|
|
30
|
+
use3DSpatialCoordinates: boolean;
|
|
31
|
+
};
|
|
32
|
+
static getTID300RepresentationArgumentsSCOORD3D(tool: any): {
|
|
33
|
+
points: {
|
|
34
|
+
x: any;
|
|
35
|
+
y: any;
|
|
36
|
+
z: any;
|
|
37
|
+
}[];
|
|
38
|
+
trackingIdentifierTextValue: string;
|
|
39
|
+
ReferencedFrameOfReferenceUID: any;
|
|
40
|
+
findingSites: any;
|
|
41
|
+
finding: any;
|
|
42
|
+
use3DSpatialCoordinates: boolean;
|
|
18
43
|
};
|
|
19
44
|
}
|
|
20
45
|
export default Probe;
|
|
@@ -11,8 +11,32 @@ class Probe extends BaseAdapter3D {
|
|
|
11
11
|
const state = super.getMeasurementData(MeasurementGroup, sopInstanceUIDToImageIdMap, imageToWorldCoords, metadata, trackingIdentifier);
|
|
12
12
|
const {
|
|
13
13
|
defaultState,
|
|
14
|
-
SCOORDGroup
|
|
14
|
+
SCOORDGroup,
|
|
15
|
+
SCOORD3DGroup
|
|
15
16
|
} = MeasurementReport.getSetupMeasurementData(MeasurementGroup, sopInstanceUIDToImageIdMap, metadata, Probe.toolType);
|
|
17
|
+
if (SCOORDGroup) {
|
|
18
|
+
return this.getMeasurementDataFromScoord({
|
|
19
|
+
state,
|
|
20
|
+
defaultState,
|
|
21
|
+
SCOORDGroup,
|
|
22
|
+
imageToWorldCoords
|
|
23
|
+
});
|
|
24
|
+
} else if (SCOORD3DGroup) {
|
|
25
|
+
return this.getMeasurementDataFromScoord3D({
|
|
26
|
+
state,
|
|
27
|
+
SCOORD3DGroup
|
|
28
|
+
});
|
|
29
|
+
} else {
|
|
30
|
+
throw new Error("Can't get measurement data with missing SCOORD and SCOORD3D groups.");
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
static getMeasurementDataFromScoord(_ref) {
|
|
34
|
+
let {
|
|
35
|
+
state,
|
|
36
|
+
defaultState,
|
|
37
|
+
SCOORDGroup,
|
|
38
|
+
imageToWorldCoords
|
|
39
|
+
} = _ref;
|
|
16
40
|
const referencedImageId = defaultState.annotation.metadata.referencedImageId;
|
|
17
41
|
const {
|
|
18
42
|
GraphicData
|
|
@@ -34,6 +58,93 @@ class Probe extends BaseAdapter3D {
|
|
|
34
58
|
};
|
|
35
59
|
return state;
|
|
36
60
|
}
|
|
61
|
+
static getMeasurementDataFromScoord3D(_ref2) {
|
|
62
|
+
let {
|
|
63
|
+
state,
|
|
64
|
+
SCOORD3DGroup
|
|
65
|
+
} = _ref2;
|
|
66
|
+
const {
|
|
67
|
+
GraphicData
|
|
68
|
+
} = SCOORD3DGroup;
|
|
69
|
+
const worldCoords = [];
|
|
70
|
+
for (let i = 0; i < GraphicData.length; i += 3) {
|
|
71
|
+
const point = [GraphicData[i], GraphicData[i + 1], GraphicData[i + 2]];
|
|
72
|
+
worldCoords.push(point);
|
|
73
|
+
}
|
|
74
|
+
state.annotation.data = {
|
|
75
|
+
...state.annotation.data,
|
|
76
|
+
handles: {
|
|
77
|
+
points: worldCoords,
|
|
78
|
+
activeHandleIndex: null,
|
|
79
|
+
textBox: {
|
|
80
|
+
hasMoved: false
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
return state;
|
|
85
|
+
}
|
|
86
|
+
static getTID300RepresentationArguments(tool, worldToImageCoords) {
|
|
87
|
+
const {
|
|
88
|
+
data,
|
|
89
|
+
metadata
|
|
90
|
+
} = tool;
|
|
91
|
+
const {
|
|
92
|
+
finding,
|
|
93
|
+
findingSites
|
|
94
|
+
} = tool;
|
|
95
|
+
const {
|
|
96
|
+
referencedImageId
|
|
97
|
+
} = metadata;
|
|
98
|
+
if (!referencedImageId) {
|
|
99
|
+
return this.getTID300RepresentationArgumentsSCOORD3D(tool);
|
|
100
|
+
}
|
|
101
|
+
const {
|
|
102
|
+
handles: {
|
|
103
|
+
points = []
|
|
104
|
+
}
|
|
105
|
+
} = data;
|
|
106
|
+
const pointsImage = points.map(point => {
|
|
107
|
+
const pointImage = worldToImageCoords(referencedImageId, point);
|
|
108
|
+
return {
|
|
109
|
+
x: pointImage[0],
|
|
110
|
+
y: pointImage[1]
|
|
111
|
+
};
|
|
112
|
+
});
|
|
113
|
+
return {
|
|
114
|
+
points: pointsImage,
|
|
115
|
+
trackingIdentifierTextValue: this.trackingIdentifierTextValue,
|
|
116
|
+
findingSites: findingSites || [],
|
|
117
|
+
finding,
|
|
118
|
+
use3DSpatialCoordinates: false
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
static getTID300RepresentationArgumentsSCOORD3D(tool) {
|
|
122
|
+
const {
|
|
123
|
+
data,
|
|
124
|
+
finding,
|
|
125
|
+
findingSites,
|
|
126
|
+
metadata
|
|
127
|
+
} = tool;
|
|
128
|
+
const {
|
|
129
|
+
handles: {
|
|
130
|
+
points = []
|
|
131
|
+
}
|
|
132
|
+
} = data;
|
|
133
|
+
const point = points[0];
|
|
134
|
+
const pointXYZ = {
|
|
135
|
+
x: point[0],
|
|
136
|
+
y: point[1],
|
|
137
|
+
z: point[2]
|
|
138
|
+
};
|
|
139
|
+
return {
|
|
140
|
+
points: [pointXYZ],
|
|
141
|
+
trackingIdentifierTextValue: this.trackingIdentifierTextValue,
|
|
142
|
+
ReferencedFrameOfReferenceUID: metadata.FrameOfReferenceUID,
|
|
143
|
+
findingSites: findingSites || [],
|
|
144
|
+
finding,
|
|
145
|
+
use3DSpatialCoordinates: true
|
|
146
|
+
};
|
|
147
|
+
}
|
|
37
148
|
}
|
|
38
149
|
_Probe = Probe;
|
|
39
150
|
(() => {
|