@cornerstonejs/tools 1.18.0 → 1.19.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cornerstonejs/tools",
3
- "version": "1.18.0",
3
+ "version": "1.19.0",
4
4
  "description": "Cornerstone3D Tools",
5
5
  "main": "dist/umd/index.js",
6
6
  "types": "dist/esm/index.d.ts",
@@ -29,7 +29,7 @@
29
29
  "webpack:watch": "webpack --mode development --progress --watch --config ./.webpack/webpack.dev.js"
30
30
  },
31
31
  "dependencies": {
32
- "@cornerstonejs/core": "^1.18.0",
32
+ "@cornerstonejs/core": "^1.19.0",
33
33
  "lodash.clonedeep": "4.5.0",
34
34
  "lodash.get": "^4.4.2"
35
35
  },
@@ -52,5 +52,5 @@
52
52
  "type": "individual",
53
53
  "url": "https://ohif.org/donate"
54
54
  },
55
- "gitHead": "a3a41620de2a91c64588493e6a332c3808145e91"
55
+ "gitHead": "4caa1d79544a3076d89de80d02fbb9a18c1ad186"
56
56
  }
@@ -11,7 +11,6 @@ import { addAnnotation } from '../stateManagement/annotation/annotationState';
11
11
  import { drawLine as drawLineSvg } from '../drawingSvg';
12
12
  import { filterViewportsWithToolEnabled } from '../utilities/viewportFilters';
13
13
  import triggerAnnotationRenderForViewportIds from '../utilities/triggerAnnotationRenderForViewportIds';
14
-
15
14
  import { PublicToolProps, ToolProps, SVGDrawingHelper } from '../types';
16
15
  import { ReferenceLineAnnotation } from '../types/ToolSpecificAnnotationTypes';
17
16
  import { StyleSpecifier } from '../types/AnnotationStyle';
@@ -43,6 +42,7 @@ class ReferenceLines extends AnnotationDisplayTool {
43
42
  supportedInteractionTypes: ['Mouse', 'Touch'],
44
43
  configuration: {
45
44
  sourceViewportId: '',
45
+ showFullDimension: false,
46
46
  },
47
47
  }
48
48
  ) {
@@ -177,7 +177,7 @@ class ReferenceLines extends AnnotationDisplayTool {
177
177
  const bottomLeft = annotation.data.handles.points[2];
178
178
  const bottomRight = annotation.data.handles.points[3];
179
179
 
180
- const { focalPoint, viewPlaneNormal } = targetViewport.getCamera();
180
+ const { focalPoint, viewPlaneNormal, viewUp } = targetViewport.getCamera();
181
181
  const { viewPlaneNormal: sourceViewPlaneNormal } =
182
182
  sourceViewport.getCamera();
183
183
 
@@ -239,10 +239,21 @@ class ReferenceLines extends AnnotationDisplayTool {
239
239
  const color = this.getStyle('color', styleSpecifier, annotation);
240
240
  const shadow = this.getStyle('shadow', styleSpecifier, annotation);
241
241
 
242
- const canvasCoordinates = [lineStartWorld, lineEndWorld].map((world) =>
242
+ let canvasCoordinates = [lineStartWorld, lineEndWorld].map((world) =>
243
243
  targetViewport.worldToCanvas(world)
244
244
  );
245
245
 
246
+ if (this.configuration.showFullDimension) {
247
+ canvasCoordinates = this.handleFullDimension(
248
+ targetViewport,
249
+ lineStartWorld,
250
+ viewPlaneNormal,
251
+ viewUp,
252
+ lineEndWorld,
253
+ canvasCoordinates
254
+ );
255
+ }
256
+
246
257
  const dataId = `${annotationUID}-line`;
247
258
  const lineUID = '1';
248
259
  drawLineSvg(
@@ -270,9 +281,126 @@ class ReferenceLines extends AnnotationDisplayTool {
270
281
  return Math.abs(dot) < EPSILON;
271
282
  };
272
283
 
284
+ private handleFullDimension(
285
+ targetViewport: Types.IStackViewport | Types.IVolumeViewport,
286
+ lineStartWorld: Types.Point3,
287
+ viewPlaneNormal: Types.Point3,
288
+ viewUp: Types.Point3,
289
+ lineEndWorld: Types.Point3,
290
+ canvasCoordinates: Types.Point2[]
291
+ ) {
292
+ const renderingEngine = targetViewport.getRenderingEngine();
293
+ const targetId = this.getTargetId(targetViewport);
294
+ const targetImage = this.getTargetIdImage(targetId, renderingEngine);
295
+
296
+ const referencedImageId = this.getReferencedImageId(
297
+ targetViewport,
298
+ lineStartWorld,
299
+ viewPlaneNormal,
300
+ viewUp
301
+ );
302
+
303
+ if (referencedImageId && targetImage) {
304
+ try {
305
+ const { imageData, dimensions } = targetImage;
306
+
307
+ // Calculate bound image coordinates
308
+ const [
309
+ topLeftImageCoord,
310
+ topRightImageCoord,
311
+ bottomRightImageCoord,
312
+ bottomLeftImageCoord,
313
+ ] = [
314
+ imageData.indexToWorld([0, 0, 0]) as Types.Point3,
315
+ imageData.indexToWorld([dimensions[0] - 1, 0, 0]) as Types.Point3,
316
+ imageData.indexToWorld([
317
+ dimensions[0] - 1,
318
+ dimensions[1] - 1,
319
+ 0,
320
+ ]) as Types.Point3,
321
+ imageData.indexToWorld([0, dimensions[1] - 1, 0]) as Types.Point3,
322
+ ].map((world) => csUtils.worldToImageCoords(referencedImageId, world));
323
+
324
+ // Calculate line start and end image coordinates
325
+ const [lineStartImageCoord, lineEndImageCoord] = [
326
+ lineStartWorld,
327
+ lineEndWorld,
328
+ ].map((world) => csUtils.worldToImageCoords(referencedImageId, world));
329
+
330
+ // Calculate intersection points between line and image bounds
331
+ canvasCoordinates = [
332
+ [topLeftImageCoord, topRightImageCoord],
333
+ [topRightImageCoord, bottomRightImageCoord],
334
+ [bottomLeftImageCoord, bottomRightImageCoord],
335
+ [topLeftImageCoord, bottomLeftImageCoord],
336
+ ]
337
+ .map(([start, end]) =>
338
+ this.intersectInfiniteLines(
339
+ start,
340
+ end,
341
+ lineStartImageCoord,
342
+ lineEndImageCoord
343
+ )
344
+ )
345
+ .filter((point) => point && this.isInBound(point, dimensions))
346
+ .map((point) => {
347
+ const world = csUtils.imageToWorldCoords(
348
+ referencedImageId,
349
+ point as Types.Point2
350
+ );
351
+ return targetViewport.worldToCanvas(world);
352
+ });
353
+ } catch (err) {
354
+ console.log(err);
355
+ }
356
+ }
357
+ return canvasCoordinates;
358
+ }
359
+
360
+ // get the intersection point between two infinite lines, not line segments
361
+ intersectInfiniteLines(
362
+ line1Start: Types.Point2,
363
+ line1End: Types.Point2,
364
+ line2Start: Types.Point2,
365
+ line2End: Types.Point2
366
+ ) {
367
+ const [x1, y1] = line1Start;
368
+ const [x2, y2] = line1End;
369
+ const [x3, y3] = line2Start;
370
+ const [x4, y4] = line2End;
371
+
372
+ // Compute a1, b1, c1, where line joining points 1 and 2 is "a1 x + b1 y + c1 = 0"
373
+ const a1 = y2 - y1;
374
+ const b1 = x1 - x2;
375
+ const c1 = x2 * y1 - x1 * y2;
376
+
377
+ // Compute a2, b2, c2
378
+ const a2 = y4 - y3;
379
+ const b2 = x3 - x4;
380
+ const c2 = x4 * y3 - x3 * y4;
381
+
382
+ if (Math.abs(a1 * b2 - a2 * b1) < EPSILON) {
383
+ return;
384
+ }
385
+
386
+ const x = (b1 * c2 - b2 * c1) / (a1 * b2 - a2 * b1);
387
+ const y = (a2 * c1 - a1 * c2) / (a1 * b2 - a2 * b1);
388
+
389
+ return [x, y];
390
+ }
391
+
273
392
  isParallel(vec1: Types.Point3, vec2: Types.Point3): boolean {
274
393
  return Math.abs(vec3.dot(vec1, vec2)) > 1 - EPSILON;
275
394
  }
395
+
396
+ isInBound(point: number[], dimensions: Types.Point3): boolean {
397
+ return (
398
+ point[0] >= 0 &&
399
+ point[0] <= dimensions[0] &&
400
+ point[1] >= 0 &&
401
+ point[1] <= dimensions[1]
402
+ );
403
+ }
276
404
  }
277
405
 
278
406
  ReferenceLines.toolName = 'ReferenceLines';
@@ -102,6 +102,10 @@ abstract class AnnotationDisplayTool extends BaseTool {
102
102
 
103
103
  // for this specific tool
104
104
  toolSpecificAnnotations.forEach((annotation) => {
105
+ if (!annotation.metadata?.referencedImageId) {
106
+ return;
107
+ }
108
+
105
109
  // if the annotation is drawn on the same imageId
106
110
  const referencedImageURI = utilities.imageIdToURI(
107
111
  annotation.metadata.referencedImageId