@cornerstonejs/tools 1.38.1 → 1.39.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/cjs/index.d.ts +2 -2
- package/dist/cjs/index.js +3 -2
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/tools/annotation/LivewireContourTool.d.ts +44 -0
- package/dist/cjs/tools/annotation/LivewireContourTool.js +442 -0
- package/dist/cjs/tools/annotation/LivewireContourTool.js.map +1 -0
- package/dist/cjs/tools/index.d.ts +2 -1
- package/dist/cjs/tools/index.js +3 -1
- package/dist/cjs/tools/index.js.map +1 -1
- package/dist/cjs/types/ToolSpecificAnnotationTypes.d.ts +10 -0
- package/dist/cjs/utilities/BucketQueue.d.ts +20 -0
- package/dist/cjs/utilities/BucketQueue.js +83 -0
- package/dist/cjs/utilities/BucketQueue.js.map +1 -0
- package/dist/cjs/utilities/livewire/LiveWirePath.d.ts +16 -0
- package/dist/cjs/utilities/livewire/LiveWirePath.js +64 -0
- package/dist/cjs/utilities/livewire/LiveWirePath.js.map +1 -0
- package/dist/cjs/utilities/livewire/LivewireScissors.d.ts +37 -0
- package/dist/cjs/utilities/livewire/LivewireScissors.js +281 -0
- package/dist/cjs/utilities/livewire/LivewireScissors.js.map +1 -0
- package/dist/cjs/utilities/math/vec2/liangBarksyClip.d.ts +1 -1
- package/dist/esm/index.js +2 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/tools/annotation/LivewireContourTool.js +439 -0
- package/dist/esm/tools/annotation/LivewireContourTool.js.map +1 -0
- package/dist/esm/tools/index.js +2 -1
- package/dist/esm/tools/index.js.map +1 -1
- package/dist/esm/utilities/BucketQueue.js +79 -0
- package/dist/esm/utilities/BucketQueue.js.map +1 -0
- package/dist/esm/utilities/livewire/LiveWirePath.js +60 -0
- package/dist/esm/utilities/livewire/LiveWirePath.js.map +1 -0
- package/dist/esm/utilities/livewire/LivewireScissors.js +277 -0
- package/dist/esm/utilities/livewire/LivewireScissors.js.map +1 -0
- package/dist/types/index.d.ts +2 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/tools/annotation/LivewireContourTool.d.ts +45 -0
- package/dist/types/tools/annotation/LivewireContourTool.d.ts.map +1 -0
- package/dist/types/tools/index.d.ts +2 -1
- package/dist/types/tools/index.d.ts.map +1 -1
- package/dist/types/types/ToolSpecificAnnotationTypes.d.ts +10 -0
- package/dist/types/types/ToolSpecificAnnotationTypes.d.ts.map +1 -1
- package/dist/types/utilities/BucketQueue.d.ts +21 -0
- package/dist/types/utilities/BucketQueue.d.ts.map +1 -0
- package/dist/types/utilities/livewire/LiveWirePath.d.ts +17 -0
- package/dist/types/utilities/livewire/LiveWirePath.d.ts.map +1 -0
- package/dist/types/utilities/livewire/LivewireScissors.d.ts +38 -0
- package/dist/types/utilities/livewire/LivewireScissors.d.ts.map +1 -0
- package/dist/types/utilities/math/vec2/liangBarksyClip.d.ts +1 -1
- package/dist/umd/index.js +1 -1
- package/dist/umd/index.js.map +1 -1
- package/package.json +3 -3
- package/src/index.ts +2 -0
- package/src/tools/annotation/LivewireContourTool.ts +799 -0
- package/src/tools/index.ts +2 -0
- package/src/types/ToolSpecificAnnotationTypes.ts +12 -0
- package/src/utilities/BucketQueue.ts +154 -0
- package/src/utilities/livewire/LiveWirePath.ts +131 -0
- package/src/utilities/livewire/LivewireScissors.ts +582 -0
package/src/tools/index.ts
CHANGED
|
@@ -28,6 +28,7 @@ import EllipticalROITool from './annotation/EllipticalROITool';
|
|
|
28
28
|
import CircleROITool from './annotation/CircleROITool';
|
|
29
29
|
import SplineROITool from './annotation/SplineROITool';
|
|
30
30
|
import PlanarFreehandROITool from './annotation/PlanarFreehandROITool';
|
|
31
|
+
import LivewireContourTool from './annotation/LivewireContourTool';
|
|
31
32
|
import ArrowAnnotateTool from './annotation/ArrowAnnotateTool';
|
|
32
33
|
import AngleTool from './annotation/AngleTool';
|
|
33
34
|
import CobbAngleTool from './annotation/CobbAngleTool';
|
|
@@ -76,6 +77,7 @@ export {
|
|
|
76
77
|
CircleROITool,
|
|
77
78
|
SplineROITool,
|
|
78
79
|
PlanarFreehandROITool,
|
|
80
|
+
LivewireContourTool,
|
|
79
81
|
ArrowAnnotateTool,
|
|
80
82
|
AngleTool,
|
|
81
83
|
CobbAngleTool,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Types } from '@cornerstonejs/core';
|
|
2
2
|
import { Annotation } from './AnnotationTypes';
|
|
3
3
|
import { ISpline } from './';
|
|
4
|
+
import { LivewirePath } from '../utilities/livewire/LiveWirePath';
|
|
4
5
|
|
|
5
6
|
interface ROICachedStats {
|
|
6
7
|
[targetId: string]: {
|
|
@@ -152,6 +153,17 @@ export interface SplineROIAnnotation extends Annotation {
|
|
|
152
153
|
};
|
|
153
154
|
}
|
|
154
155
|
|
|
156
|
+
export interface LivewireContourAnnotation extends Annotation {
|
|
157
|
+
data: {
|
|
158
|
+
polyline: Types.Point3[];
|
|
159
|
+
label?: string;
|
|
160
|
+
handles: {
|
|
161
|
+
points: Types.Point3[];
|
|
162
|
+
activeHandleIndex: number | null;
|
|
163
|
+
};
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
155
167
|
export interface EllipticalROIAnnotation extends Annotation {
|
|
156
168
|
data: {
|
|
157
169
|
handles: {
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
type BucketNode<T> = {
|
|
2
|
+
value: T;
|
|
3
|
+
next: BucketNode<T>;
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Circular Bucket Queue.
|
|
8
|
+
*
|
|
9
|
+
* Returns input'd points in sorted order. All operations run in roughly O(1)
|
|
10
|
+
* time (for input with small cost values), but it has a strict requirement:
|
|
11
|
+
*
|
|
12
|
+
* If the most recent point had a cost of c, any points added should have a cost
|
|
13
|
+
* c' in the range c <= c' <= c + (capacity - 1).
|
|
14
|
+
*/
|
|
15
|
+
export class BucketQueue<T> {
|
|
16
|
+
private _bucketCount: number;
|
|
17
|
+
private _mask: number;
|
|
18
|
+
private _size: number;
|
|
19
|
+
private _currentBucketIndex: number;
|
|
20
|
+
private _getPriority: (item: T) => number;
|
|
21
|
+
private _areEqual: (itemA: T, itemB: T) => boolean;
|
|
22
|
+
private _buckets: BucketNode<T>[];
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @param bits - Number of bits.
|
|
26
|
+
* @param getPriority - A function that returns the priority of an item
|
|
27
|
+
*/
|
|
28
|
+
constructor({
|
|
29
|
+
numBits,
|
|
30
|
+
getPriority,
|
|
31
|
+
areEqual,
|
|
32
|
+
}: {
|
|
33
|
+
numBits: number;
|
|
34
|
+
getPriority?: (item: T) => number;
|
|
35
|
+
areEqual?: (itemA: T, itemB: T) => boolean;
|
|
36
|
+
}) {
|
|
37
|
+
this._bucketCount = 1 << numBits; // # of buckets = 2^numBits
|
|
38
|
+
this._mask = this._bucketCount - 1; // 2^numBits - 1 = index mask
|
|
39
|
+
this._size = 0;
|
|
40
|
+
this._currentBucketIndex = 0;
|
|
41
|
+
this._buckets = this._buildArray(this._bucketCount);
|
|
42
|
+
|
|
43
|
+
this._getPriority =
|
|
44
|
+
typeof getPriority !== 'undefined'
|
|
45
|
+
? getPriority
|
|
46
|
+
: (item) => item as unknown as number;
|
|
47
|
+
|
|
48
|
+
this._areEqual =
|
|
49
|
+
typeof areEqual === 'function'
|
|
50
|
+
? areEqual
|
|
51
|
+
: (itemA, itemB) => itemA === itemB;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Prepend item to the list in the appropriate bucket
|
|
56
|
+
* @param item - Item to be added to the queue based on its priority
|
|
57
|
+
*/
|
|
58
|
+
public push(item: T) {
|
|
59
|
+
const bucketIndex = this._getBucketIndex(item);
|
|
60
|
+
const oldHead = this._buckets[bucketIndex];
|
|
61
|
+
const newHead: BucketNode<T> = {
|
|
62
|
+
value: item,
|
|
63
|
+
next: oldHead,
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
this._buckets[bucketIndex] = newHead;
|
|
67
|
+
this._size++;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
public pop(): T {
|
|
71
|
+
if (this._size === 0) {
|
|
72
|
+
throw new Error('Cannot pop because the queue is empty.');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Find first empty bucket
|
|
76
|
+
while (this._buckets[this._currentBucketIndex] === null) {
|
|
77
|
+
this._currentBucketIndex =
|
|
78
|
+
(this._currentBucketIndex + 1) % this._bucketCount;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// All items in bucket have same cost, return the first one
|
|
82
|
+
const ret = this._buckets[this._currentBucketIndex];
|
|
83
|
+
|
|
84
|
+
this._buckets[this._currentBucketIndex] = ret.next;
|
|
85
|
+
this._size--;
|
|
86
|
+
|
|
87
|
+
return ret.value;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Tries to remove item from queue.
|
|
92
|
+
* @param item - Item to be removed from the queue
|
|
93
|
+
* @returns True if the item is found and removed or false otherwise
|
|
94
|
+
*/
|
|
95
|
+
public remove(item: T): boolean {
|
|
96
|
+
if (!item) {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// To find node, go to bucket and search through unsorted list.
|
|
101
|
+
const bucketIndex = this._getBucketIndex(item);
|
|
102
|
+
const firstBucketNode = this._buckets[bucketIndex];
|
|
103
|
+
let node = firstBucketNode;
|
|
104
|
+
let prevNode: BucketNode<T>;
|
|
105
|
+
|
|
106
|
+
while (node !== null) {
|
|
107
|
+
if (this._areEqual(item, node.value)) {
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
prevNode = node;
|
|
112
|
+
node = node.next;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Item not found
|
|
116
|
+
if (node === null) {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Item found and it needs to be removed from the list
|
|
121
|
+
if (node === firstBucketNode) {
|
|
122
|
+
this._buckets[bucketIndex] = node.next;
|
|
123
|
+
} else {
|
|
124
|
+
prevNode.next = node.next;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
this._size--;
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
public isEmpty(): boolean {
|
|
132
|
+
return this._size === 0;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Return the bucket index
|
|
137
|
+
* @param item - Item for which the bucket shall be returned
|
|
138
|
+
* @returns Bucket index for the item provided
|
|
139
|
+
*/
|
|
140
|
+
private _getBucketIndex(item): number {
|
|
141
|
+
return this._getPriority(item) & this._mask;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Create array and initialze pointers to null
|
|
146
|
+
* @param size - Size of the new array
|
|
147
|
+
* @returns An array with `N` buckets pointing to null
|
|
148
|
+
*/
|
|
149
|
+
private _buildArray(size) {
|
|
150
|
+
const buckets = new Array(size);
|
|
151
|
+
buckets.fill(null);
|
|
152
|
+
return buckets;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { Types } from '@cornerstonejs/core';
|
|
2
|
+
/**
|
|
3
|
+
* Path that contains points and control points to draw a path
|
|
4
|
+
* used by the livewire tool
|
|
5
|
+
*/
|
|
6
|
+
export class LivewirePath {
|
|
7
|
+
/**
|
|
8
|
+
* List of points.
|
|
9
|
+
*/
|
|
10
|
+
public pointArray: Types.Point2[];
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* List of control points indexes
|
|
14
|
+
*/
|
|
15
|
+
private _controlPointIndexes: number[];
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @param inputPointArray - The list of Point2D that make the path (optional).
|
|
19
|
+
* @param inputControlPointIndexArray - The list of control point of path, as indexes (optional).
|
|
20
|
+
* Note: first and last point do not need to be equal.
|
|
21
|
+
*/
|
|
22
|
+
constructor(
|
|
23
|
+
inputPointArray?: Types.Point2[],
|
|
24
|
+
inputControlPointIndexArray?: number[]
|
|
25
|
+
) {
|
|
26
|
+
this.pointArray = inputPointArray ? inputPointArray.slice() : [];
|
|
27
|
+
this._controlPointIndexes = inputControlPointIndexArray
|
|
28
|
+
? inputControlPointIndexArray.slice()
|
|
29
|
+
: [];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Get a point of the list.
|
|
34
|
+
*
|
|
35
|
+
* @param index - The index of the point to get
|
|
36
|
+
* @returns The Point2D at the given index.
|
|
37
|
+
*/
|
|
38
|
+
public getPoint(index: number): Types.Point2 {
|
|
39
|
+
return this.pointArray[index];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Get the last point of the list.
|
|
44
|
+
*
|
|
45
|
+
* @returns The last point of the list.
|
|
46
|
+
*/
|
|
47
|
+
public getLastPoint(): Types.Point2 {
|
|
48
|
+
return this.pointArray[this.pointArray.length - 1];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Is the given point a control point.
|
|
53
|
+
*
|
|
54
|
+
* @param point - The 2D point to check.
|
|
55
|
+
* @returns True if a control point, false otherwise.
|
|
56
|
+
*/
|
|
57
|
+
public isControlPoint(point: Types.Point2): boolean {
|
|
58
|
+
const index = this.pointArray.indexOf(point);
|
|
59
|
+
if (index !== -1) {
|
|
60
|
+
return this._controlPointIndexes.indexOf(index) !== -1;
|
|
61
|
+
} else {
|
|
62
|
+
throw new Error('Error: isControlPoint called with not in list point.');
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Add a point to the path.
|
|
68
|
+
*
|
|
69
|
+
* @param point - The 2D point to add.
|
|
70
|
+
*/
|
|
71
|
+
public addPoint(point: Types.Point2) {
|
|
72
|
+
this.pointArray.push(point);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Add a control point to the path.
|
|
77
|
+
*
|
|
78
|
+
* @param point - The 2D point to make a control point.
|
|
79
|
+
*/
|
|
80
|
+
public addControlPoint(point: Types.Point2) {
|
|
81
|
+
const index = this.pointArray.indexOf(point);
|
|
82
|
+
|
|
83
|
+
if (index !== -1) {
|
|
84
|
+
this._controlPointIndexes.push(index);
|
|
85
|
+
} else {
|
|
86
|
+
throw new Error('Cannot mark a non registered point as control point.');
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
public getControlPoints() {
|
|
91
|
+
return this._controlPointIndexes.map((i) => this.pointArray[i]);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
public getNumControlPoints(): number {
|
|
95
|
+
return this._controlPointIndexes.length;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
public removeLastControlPoint(): void {
|
|
99
|
+
if (this._controlPointIndexes.length) {
|
|
100
|
+
this._controlPointIndexes.pop();
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Add points to the path.
|
|
106
|
+
*
|
|
107
|
+
* @param newPointArray - The list of 2D points to add.
|
|
108
|
+
*/
|
|
109
|
+
public addPoints(newPointArray: Types.Point2[]) {
|
|
110
|
+
this.pointArray = this.pointArray.concat(newPointArray);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Prepend a path to this one.
|
|
115
|
+
*
|
|
116
|
+
* @param other - The path to append.
|
|
117
|
+
*/
|
|
118
|
+
public prependPath(other: LivewirePath): void {
|
|
119
|
+
const otherSize = other.pointArray.length;
|
|
120
|
+
const shiftedIndexArray: number[] = [];
|
|
121
|
+
|
|
122
|
+
this.pointArray = other.pointArray.concat(this.pointArray);
|
|
123
|
+
|
|
124
|
+
for (let i = 0; i < this._controlPointIndexes.length; ++i) {
|
|
125
|
+
shiftedIndexArray[i] = this._controlPointIndexes[i] + otherSize;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
this._controlPointIndexes =
|
|
129
|
+
other._controlPointIndexes.concat(shiftedIndexArray);
|
|
130
|
+
}
|
|
131
|
+
}
|