volview 4.0.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.
Files changed (315) hide show
  1. package/.browserslistrc +4 -0
  2. package/.editorconfig +6 -0
  3. package/.env +6 -0
  4. package/.eslintrc.js +109 -0
  5. package/.gitattributes +1 -0
  6. package/.github/workflows/checks.yml +16 -0
  7. package/.github/workflows/publish.yml +52 -0
  8. package/.prettierignore +5 -0
  9. package/CONTRIBUTING.md +29 -0
  10. package/LICENSE +202 -0
  11. package/README.md +44 -0
  12. package/babel.config.js +3 -0
  13. package/documentation/config.js +15 -0
  14. package/documentation/content/KWVolViewLogo.png +0 -0
  15. package/documentation/content/KWVolViewLogo.svg +35 -0
  16. package/documentation/content/VolViewLogo.png +0 -0
  17. package/documentation/content/VolViewLogo.svg +22 -0
  18. package/documentation/content/doc/index.md +64 -0
  19. package/documentation/content/doc/loading_data.md +30 -0
  20. package/documentation/content/doc/mouse_controls.md +34 -0
  21. package/documentation/content/doc/quick_start_guide.md +75 -0
  22. package/documentation/content/doc/rendering.md +27 -0
  23. package/documentation/content/doc/state_files.md +18 -0
  24. package/documentation/content/doc/toolbar.md +20 -0
  25. package/documentation/content/doc/welcome_screen.md +23 -0
  26. package/documentation/content/gallery/01-volview-welcome-notes.jpg +0 -0
  27. package/documentation/content/gallery/01-volview-welcome.jpg +0 -0
  28. package/documentation/content/gallery/02-volview-about.jpg +0 -0
  29. package/documentation/content/gallery/02-volview-notifications.jpg +0 -0
  30. package/documentation/content/gallery/02-volview-settings.jpg +0 -0
  31. package/documentation/content/gallery/03-volview-sample-datasets.jpg +0 -0
  32. package/documentation/content/gallery/04-volview-active-data.jpg +0 -0
  33. package/documentation/content/gallery/05-volview-select-data-to-delete.jpg +0 -0
  34. package/documentation/content/gallery/06-volview-corner-annotation.jpg +0 -0
  35. package/documentation/content/gallery/07-volview-layout-notes.jpg +0 -0
  36. package/documentation/content/gallery/07-volview-layout.jpg +0 -0
  37. package/documentation/content/gallery/09-volview-layout-3DPrimary.jpg +0 -0
  38. package/documentation/content/gallery/10-volview-wl-pan-zoom-notes.jpg +0 -0
  39. package/documentation/content/gallery/10-volview-wl-pan-zoom.jpg +0 -0
  40. package/documentation/content/gallery/11-volview-paint-notes.jpg +0 -0
  41. package/documentation/content/gallery/11-volview-paint.jpg +0 -0
  42. package/documentation/content/gallery/12-volview-paint-options.jpg +0 -0
  43. package/documentation/content/gallery/13-volview-crop-notes.jpg +0 -0
  44. package/documentation/content/gallery/13-volview-crop.jpg +0 -0
  45. package/documentation/content/gallery/14-volview-ruler.jpg +0 -0
  46. package/documentation/content/gallery/15-volview-crosshairs.jpg +0 -0
  47. package/documentation/content/gallery/16-volview-rendering.jpg +0 -0
  48. package/documentation/content/gallery/17-volview-colormap-notes.jpg +0 -0
  49. package/documentation/content/gallery/17-volview-colormap.jpg +0 -0
  50. package/documentation/content/gallery/17-volview-opacity-notes.jpg +0 -0
  51. package/documentation/content/gallery/17-volview-opacity.jpg +0 -0
  52. package/documentation/content/gallery/17-volview-opacity2.jpg +0 -0
  53. package/documentation/content/gallery/18-volview-presets.jpg +0 -0
  54. package/documentation/content/gallery/19-volview-color.jpg +0 -0
  55. package/documentation/content/gallery/19-volview-color2.jpg +0 -0
  56. package/documentation/content/gallery/20-volview-lightfollowcamera0.jpg +0 -0
  57. package/documentation/content/gallery/20-volview-lightfollowcamera1.jpg +0 -0
  58. package/documentation/content/gallery/20-volview-lightfollowcamera2.jpg +0 -0
  59. package/documentation/content/gallery/20-volview-lightfollowcamera3.jpg +0 -0
  60. package/documentation/content/gallery/21-volview-hybrid-final.jpg +0 -0
  61. package/documentation/content/gallery/21-volview-hybrid0.0.jpg +0 -0
  62. package/documentation/content/gallery/21-volview-hybrid0.5.jpg +0 -0
  63. package/documentation/content/gallery/21-volview-hybrid1.0.jpg +0 -0
  64. package/documentation/content/gallery/LocalAmbientOcclusion.jpg +0 -0
  65. package/documentation/content/gallery/Notes.pptx +0 -0
  66. package/documentation/content/gallery/VolView-Overview.jpg +0 -0
  67. package/documentation/content/gallery/index.md +53 -0
  68. package/documentation/content/icon/favicon-16x16.png +0 -0
  69. package/documentation/content/icon/favicon-196x196.png +0 -0
  70. package/documentation/content/icon/favicon-32x32.png +0 -0
  71. package/documentation/content/icon/favicon-96x96.png +0 -0
  72. package/documentation/content/index.pug +43 -0
  73. package/documentation/content/logo.png +0 -0
  74. package/documentation/content/logo.svg +20 -0
  75. package/documentation/data/menu.yml +3 -0
  76. package/documentation/themes/navy/layout/partial/footer.swig +22 -0
  77. package/documentation/tpl/__en__ +31 -0
  78. package/documentation/tpl/__sidebar__ +11 -0
  79. package/package.json +96 -0
  80. package/patches/jsdom-global+3.0.2.patch +12 -0
  81. package/patches/vue-toastification+1.7.14.patch +41 -0
  82. package/patches/vuetify+2.6.10.patch +13 -0
  83. package/prettier.config.js +9 -0
  84. package/public/favicon.ico +0 -0
  85. package/public/global.css +20 -0
  86. package/public/index.html +28 -0
  87. package/public/pvm-sample.png +0 -0
  88. package/server/helper.py +147 -0
  89. package/server/host.js +134 -0
  90. package/server/serialize.js +111 -0
  91. package/server/serialize.py +203 -0
  92. package/server/server.py +84 -0
  93. package/server/test.py +17 -0
  94. package/src/assets/KitwareHeadAndNeck.jpg +0 -0
  95. package/src/assets/logo.png +0 -0
  96. package/src/assets/logo.svg +20 -0
  97. package/src/assets/samples/3DUS-Fetus.jpg +0 -0
  98. package/src/assets/samples/CTA-Head_and_Neck.jpg +0 -0
  99. package/src/assets/samples/MRA-Head_and_Neck.jpg +0 -0
  100. package/src/assets/samples/MRI-Cardiac.jpg +0 -0
  101. package/src/assets/samples/MRI-PROSTATEx.jpg +0 -0
  102. package/src/components/AboutBox.vue +157 -0
  103. package/src/components/AiModule.vue +60 -0
  104. package/src/components/AnnotationsModule.vue +37 -0
  105. package/src/components/App.vue +539 -0
  106. package/src/components/ColorFunctionSlider.vue +181 -0
  107. package/src/components/DataBrowser.vue +173 -0
  108. package/src/components/DragAndDrop.vue +107 -0
  109. package/src/components/GroupableItem.vue +30 -0
  110. package/src/components/ImageDataBrowser.vue +186 -0
  111. package/src/components/ImageListCard.vue +114 -0
  112. package/src/components/ItemGroup.vue +74 -0
  113. package/src/components/LabelmapList.vue +36 -0
  114. package/src/components/LayoutGrid.vue +96 -0
  115. package/src/components/MeasurementsList.vue +134 -0
  116. package/src/components/MessageCenter.vue +189 -0
  117. package/src/components/MessageItem.vue +83 -0
  118. package/src/components/MessageNotificationContent.vue +20 -0
  119. package/src/components/MessageNotifications.vue +84 -0
  120. package/src/components/ModelBrowser.vue +83 -0
  121. package/src/components/ModulePanel.vue +137 -0
  122. package/src/components/PaintControls.vue +174 -0
  123. package/src/components/PatientBrowser.vue +280 -0
  124. package/src/components/PatientStudyVolumeBrowser.vue +325 -0
  125. package/src/components/RenderingModule.vue +49 -0
  126. package/src/components/ResizableNavDrawer.vue +158 -0
  127. package/src/components/SampleDataBrowser.vue +198 -0
  128. package/src/components/SaveSession.vue +57 -0
  129. package/src/components/Settings.vue +35 -0
  130. package/src/components/SliceSlider.vue +182 -0
  131. package/src/components/SpleenModule.vue +101 -0
  132. package/src/components/ToolButton.vue +58 -0
  133. package/src/components/ToolStrip.vue +186 -0
  134. package/src/components/ViewOverlayGrid.vue +84 -0
  135. package/src/components/VolumePresets.vue +165 -0
  136. package/src/components/VolumeProperties.vue +171 -0
  137. package/src/components/VolumeRendering.vue +365 -0
  138. package/src/components/VtkThreeView.vue +512 -0
  139. package/src/components/VtkTwoView.vue +665 -0
  140. package/src/components/__tests__/ResizableNavDrawer.spec.js +32 -0
  141. package/src/components/__tests__/ToolButton.spec.js +46 -0
  142. package/src/components/icons/KitwareLogoIcon.vue +54 -0
  143. package/src/components/icons/VolViewFullLogo.vue +139 -0
  144. package/src/components/icons/VolViewLogo.vue +78 -0
  145. package/src/components/styles/utils.css +16 -0
  146. package/src/components/styles/vtk-view.css +116 -0
  147. package/src/components/tools/CropTool.vue +61 -0
  148. package/src/components/tools/CrosshairsTool.vue +93 -0
  149. package/src/components/tools/MouseManipulatorTool.vue +108 -0
  150. package/src/components/tools/PaintTool.vue +54 -0
  151. package/src/components/tools/PanTool.vue +35 -0
  152. package/src/components/tools/RulerTool.vue +202 -0
  153. package/src/components/tools/SliceScrollTool.vue +123 -0
  154. package/src/components/tools/WindowLevelTool.vue +191 -0
  155. package/src/components/tools/ZoomTool.vue +35 -0
  156. package/src/components/tools/crop/Crop2D.vue +367 -0
  157. package/src/components/tools/crop/Crop2DLineHandle.vue +103 -0
  158. package/src/components/tools/crop/Crop3D.vue +192 -0
  159. package/src/components/tools/crop/CropControls.vue +38 -0
  160. package/src/components/tools/crop/types.ts +12 -0
  161. package/src/components/tools/crosshairs/CrosshairSVG2D.vue +125 -0
  162. package/src/components/tools/crosshairs/CrosshairsWidget2D.vue +100 -0
  163. package/src/components/tools/paint/PaintWidget2D.vue +192 -0
  164. package/src/components/tools/ruler/RulerSVG2D.vue +181 -0
  165. package/src/components/tools/ruler/RulerWidget2D.vue +154 -0
  166. package/src/composables/__tests__/useDoubleRecord.spec.ts +57 -0
  167. package/src/composables/__tests__/useOrientationLabels.spec.ts +29 -0
  168. package/src/composables/isViewAnimating.ts +25 -0
  169. package/src/composables/manageVTKSubscription.ts +6 -0
  170. package/src/composables/onProxyManagerEvent.ts +50 -0
  171. package/src/composables/proxyManager.ts +13 -0
  172. package/src/composables/sync/__tests__/createPrimitiveSyncContext.spec.ts +41 -0
  173. package/src/composables/sync/__tests__/useWindowingSync.spec.ts +51 -0
  174. package/src/composables/sync/createPrimitiveSyncContext.ts +83 -0
  175. package/src/composables/sync/useWindowingSync.ts +48 -0
  176. package/src/composables/useAppLoadingNotifications.ts +73 -0
  177. package/src/composables/useCameraOrientation.ts +34 -0
  178. package/src/composables/useCurrentImage.ts +74 -0
  179. package/src/composables/useCurrentSlice.ts +43 -0
  180. package/src/composables/useDoubleRecord.ts +77 -0
  181. package/src/composables/useEventListener.ts +26 -0
  182. package/src/composables/useGlobalErrorHook.ts +18 -0
  183. package/src/composables/useMultiSelection.ts +29 -0
  184. package/src/composables/useOrientationLabels.ts +62 -0
  185. package/src/composables/usePanels.ts +42 -0
  186. package/src/composables/usePersistCameraConfig.ts +138 -0
  187. package/src/composables/useResizeObserver.ts +37 -0
  188. package/src/composables/useResizeToFit.ts +50 -0
  189. package/src/composables/useSceneBuilder.ts +96 -0
  190. package/src/composables/useToast.js +11 -0
  191. package/src/composables/useVTKCallback.ts +33 -0
  192. package/src/composables/useVTKWorldToDisplay.ts +141 -0
  193. package/src/composables/useViewProxy.ts +87 -0
  194. package/src/composables/useVolumeThumbnailing.ts +173 -0
  195. package/src/composables/useWebGLWatchdog.ts +32 -0
  196. package/src/composables/useWidgetManager.ts +41 -0
  197. package/src/config.ts +182 -0
  198. package/src/constants.ts +38 -0
  199. package/src/core/id.ts +18 -0
  200. package/src/core/provider.ts +31 -0
  201. package/src/core/proxies.ts +90 -0
  202. package/src/core/thumbnailers/__tests__/vtk-image.spec.ts +58 -0
  203. package/src/core/thumbnailers/index.ts +5 -0
  204. package/src/core/thumbnailers/volume-thumbnailer.ts +130 -0
  205. package/src/core/thumbnailers/vtk-image.ts +142 -0
  206. package/src/core/tools/__tests__/paint.spec.ts +101 -0
  207. package/src/core/tools/__tests__/ruler.spec.ts +73 -0
  208. package/src/core/tools/paint/brush.ts +20 -0
  209. package/src/core/tools/paint/ellipse-brush.ts +96 -0
  210. package/src/core/tools/paint/index.ts +141 -0
  211. package/src/core/tools/ruler.ts +149 -0
  212. package/src/global.d.ts +24 -0
  213. package/src/io/__tests__/io.spec.ts +26 -0
  214. package/src/io/dicom.ts +187 -0
  215. package/src/io/index.ts +11 -0
  216. package/src/io/io.ts +157 -0
  217. package/src/io/itk/itkConfig.js +8 -0
  218. package/src/io/itk-dicom/dicom.cpp +327 -0
  219. package/src/io/itk-dicom/web-build/dicom.js +16 -0
  220. package/src/io/itk-dicom/web-build/dicom.umd.js +21 -0
  221. package/src/io/itk-dicom/web-build/dicom.umd.wasm +0 -0
  222. package/src/io/itk-dicom/web-build/dicom.wasm +0 -0
  223. package/src/io/manifest.ts +30 -0
  224. package/src/io/readers.ts +36 -0
  225. package/src/io/state-file/index.ts +170 -0
  226. package/src/io/state-file/schema.ts +277 -0
  227. package/src/io/state-file/utils.ts +33 -0
  228. package/src/io/types.ts +4 -0
  229. package/src/io/vtk/async.reader.worker.ts +50 -0
  230. package/src/io/vtk/async.ts +58 -0
  231. package/src/io/vtk/async.writer.worker.ts +46 -0
  232. package/src/io/vtk/common.ts +30 -0
  233. package/src/io/zip.ts +31 -0
  234. package/src/main.js +66 -0
  235. package/src/main.ts +1 -0
  236. package/src/plugins/vuetify.js +25 -0
  237. package/src/shims-itk.d.ts +67 -0
  238. package/src/shims-misc.d.ts +4 -0
  239. package/src/shims-tsx.d.ts +13 -0
  240. package/src/shims-vtk.d.ts +1042 -0
  241. package/src/shims-vue.d.ts +5 -0
  242. package/src/store/__tests__/datasets.spec.ts +75 -0
  243. package/src/store/__tests__/messages.spec.ts +74 -0
  244. package/src/store/__tests__/rulers.spec.ts +77 -0
  245. package/src/store/__tests__/view-configs.spec.ts +37 -0
  246. package/src/store/datasets-dicom.ts +398 -0
  247. package/src/store/datasets-files.ts +35 -0
  248. package/src/store/datasets-images.ts +118 -0
  249. package/src/store/datasets-labelmaps.ts +136 -0
  250. package/src/store/datasets-models.ts +25 -0
  251. package/src/store/datasets.ts +341 -0
  252. package/src/store/messages.ts +144 -0
  253. package/src/store/tools/crop.ts +136 -0
  254. package/src/store/tools/crosshairs.ts +131 -0
  255. package/src/store/tools/index.ts +95 -0
  256. package/src/store/tools/paint.ts +191 -0
  257. package/src/store/tools/rulers.ts +305 -0
  258. package/src/store/tools/types.ts +54 -0
  259. package/src/store/view-configs/camera.ts +51 -0
  260. package/src/store/view-configs/common.ts +61 -0
  261. package/src/store/view-configs/slicing.ts +86 -0
  262. package/src/store/view-configs/types.ts +39 -0
  263. package/src/store/view-configs/volume-coloring.ts +193 -0
  264. package/src/store/view-configs/windowing.ts +69 -0
  265. package/src/store/view-configs.ts +78 -0
  266. package/src/store/views.ts +130 -0
  267. package/src/types/index.ts +16 -0
  268. package/src/types/layout.ts +10 -0
  269. package/src/types/lps.ts +40 -0
  270. package/src/types/views.ts +65 -0
  271. package/src/types/vtk-types.ts +29 -0
  272. package/src/utils/__tests__/lps.spec.ts +102 -0
  273. package/src/utils/color.ts +23 -0
  274. package/src/utils/errors.js +3 -0
  275. package/src/utils/fetch.ts +101 -0
  276. package/src/utils/hacks.ts +14 -0
  277. package/src/utils/index.ts +83 -0
  278. package/src/utils/lps.ts +129 -0
  279. package/src/utils/manipulators.ts +35 -0
  280. package/src/utils/promise-worker.ts +45 -0
  281. package/src/utils/vtk-helpers.ts +215 -0
  282. package/src/utils/workerHandler.js +42 -0
  283. package/src/vtk/ColorMaps.ts +72 -0
  284. package/src/vtk/CrosshairsWidget/behavior.ts +112 -0
  285. package/src/vtk/CrosshairsWidget/index.d.ts +22 -0
  286. package/src/vtk/CrosshairsWidget/index.js +73 -0
  287. package/src/vtk/CrosshairsWidget/state.ts +51 -0
  288. package/src/vtk/IJKSliceRepresentationProxy/index.d.ts +9 -0
  289. package/src/vtk/IJKSliceRepresentationProxy/index.js +59 -0
  290. package/src/vtk/LPSView2DProxy/index.d.ts +18 -0
  291. package/src/vtk/LPSView2DProxy/index.js +89 -0
  292. package/src/vtk/LPSView3DProxy/index.d.ts +16 -0
  293. package/src/vtk/LPSView3DProxy/index.js +78 -0
  294. package/src/vtk/LabelMap/index.d.ts +16 -0
  295. package/src/vtk/LabelMap/index.js +49 -0
  296. package/src/vtk/LabelMapSliceRepProxy/index.d.ts +6 -0
  297. package/src/vtk/LabelMapSliceRepProxy/index.js +104 -0
  298. package/src/vtk/MedicalColorPresets.json +1448 -0
  299. package/src/vtk/PaintBrushContextRepresentation/index.js +191 -0
  300. package/src/vtk/PaintWidget/behavior.ts +101 -0
  301. package/src/vtk/PaintWidget/index.d.ts +28 -0
  302. package/src/vtk/PaintWidget/index.js +56 -0
  303. package/src/vtk/PaintWidget/state.ts +41 -0
  304. package/src/vtk/PiecewiseWidget/index.js +203 -0
  305. package/src/vtk/RulerWidget/behavior.ts +185 -0
  306. package/src/vtk/RulerWidget/index.d.ts +25 -0
  307. package/src/vtk/RulerWidget/index.js +79 -0
  308. package/src/vtk/RulerWidget/state.ts +63 -0
  309. package/src/vtk/TreJsonConverter/index.js +150 -0
  310. package/src/vtk/proxy.js +66 -0
  311. package/src/vtk/proxyUtils.js +16 -0
  312. package/src/vtk/webvr-empty.js +1 -0
  313. package/tests/testUtils.js +12 -0
  314. package/tsconfig.json +46 -0
  315. package/vue.config.js +86 -0
@@ -0,0 +1,185 @@
1
+ import { vtkSubscription } from '@kitware/vtk.js/interfaces';
2
+ import macro from '@kitware/vtk.js/macro';
3
+ import { Vector3 } from '@kitware/vtk.js/types';
4
+ import { InteractionState, RulerPointWidgetState } from './state';
5
+
6
+ export function shouldIgnoreEvent(e: any) {
7
+ return e.altKey || e.controlKey || e.shiftKey;
8
+ }
9
+
10
+ export default function widgetBehavior(publicAPI: any, model: any) {
11
+ model.classHierarchy.push('vtkRulerWidgetProp');
12
+
13
+ const superClass = { ...publicAPI };
14
+
15
+ const subscriptions: vtkSubscription[] = [];
16
+ let dragging: RulerPointWidgetState | null = null;
17
+
18
+ // support setting per-view widget manipulators
19
+ macro.setGet(publicAPI, model, ['manipulator']);
20
+ // support forwarding events
21
+ macro.event(publicAPI, model, 'RightClickEvent');
22
+
23
+ publicAPI.setFirstPoint = (coord: Vector3) => {
24
+ const point = model.widgetState.getFirstPoint();
25
+ point.setOrigin(coord);
26
+ };
27
+
28
+ publicAPI.setSecondPoint = (coord: Vector3) => {
29
+ const point = model.widgetState.getSecondPoint();
30
+ point.setOrigin(coord);
31
+ };
32
+
33
+ /**
34
+ * Places or drags a point.
35
+ */
36
+ publicAPI.handleLeftButtonPress = (eventData: any) => {
37
+ if (!model.manipulator || shouldIgnoreEvent(eventData)) {
38
+ return macro.VOID;
39
+ }
40
+
41
+ const intState = model.widgetState.getInteractionState();
42
+
43
+ // in order to place points, we should be...
44
+ if (
45
+ // focused
46
+ model.hasFocus &&
47
+ // not be settled
48
+ intState !== InteractionState.Settled
49
+ ) {
50
+ const worldCoords = model.manipulator.handleEvent(
51
+ eventData,
52
+ model._apiSpecificRenderWindow
53
+ );
54
+ if (worldCoords.length) {
55
+ if (intState === InteractionState.PlacingFirst) {
56
+ publicAPI.setFirstPoint(worldCoords);
57
+ model.widgetState.setInteractionState(InteractionState.PlacingSecond);
58
+ } else if (intState === InteractionState.PlacingSecond) {
59
+ publicAPI.setSecondPoint(worldCoords);
60
+ model.widgetState.setInteractionState(InteractionState.Settled);
61
+ }
62
+ publicAPI.invokeInteractionEvent();
63
+ return macro.EVENT_ABORT;
64
+ }
65
+ }
66
+
67
+ // widget is considered settled, so see if we
68
+ // are trying to drag a point.
69
+ if (model.activeState?.getActive() && model.pickable) {
70
+ dragging = model.activeState;
71
+ model._apiSpecificRenderWindow.setCursor('grabbing');
72
+ model._interactor.requestAnimation(publicAPI);
73
+ publicAPI.invokeStartInteractionEvent();
74
+ return macro.EVENT_ABORT;
75
+ }
76
+
77
+ return macro.VOID;
78
+ };
79
+
80
+ /**
81
+ * Moves a point around.
82
+ */
83
+ publicAPI.handleMouseMove = (eventData: any) => {
84
+ const intState = model.widgetState.getInteractionState();
85
+
86
+ if (model.hasFocus && intState === InteractionState.Settled) {
87
+ publicAPI.loseFocus();
88
+ return macro.VOID;
89
+ }
90
+
91
+ if (
92
+ dragging || // moving an existing point
93
+ intState !== InteractionState.Settled // placing a point
94
+ ) {
95
+ const worldCoords = model.manipulator.handleEvent(
96
+ eventData,
97
+ model._apiSpecificRenderWindow
98
+ );
99
+
100
+ if (worldCoords.length) {
101
+ if (dragging) {
102
+ dragging.setOrigin(worldCoords);
103
+ } else if (intState === InteractionState.PlacingFirst) {
104
+ model.widgetState.getFirstPoint().setVisible(true);
105
+ publicAPI.setFirstPoint(worldCoords);
106
+ } else if (intState === InteractionState.PlacingSecond) {
107
+ model.widgetState.getSecondPoint().setVisible(true);
108
+ publicAPI.setSecondPoint(worldCoords);
109
+ }
110
+ publicAPI.invokeInteractionEvent();
111
+ }
112
+
113
+ return macro.EVENT_ABORT;
114
+ }
115
+
116
+ return macro.VOID;
117
+ };
118
+
119
+ /**
120
+ * Finishes dragging
121
+ */
122
+ publicAPI.handleLeftButtonRelease = (eventData: any) => {
123
+ if (dragging) {
124
+ const worldCoords = model.manipulator.handleEvent(
125
+ eventData,
126
+ model._apiSpecificRenderWindow
127
+ );
128
+ if (worldCoords.length) {
129
+ dragging.setOrigin(worldCoords);
130
+ }
131
+
132
+ dragging = null;
133
+ model._apiSpecificRenderWindow.setCursor('pointer');
134
+ model.widgetState.deactivate();
135
+ model._interactor.cancelAnimation(publicAPI);
136
+ publicAPI.invokeEndInteractionEvent();
137
+ // model._widgetManager.enablePicking();
138
+ // model._interactor.render();
139
+ }
140
+ };
141
+
142
+ publicAPI.handleRightButtonPress = (eventData: any) => {
143
+ if (
144
+ shouldIgnoreEvent(eventData) ||
145
+ model.widgetState.getInteractionState() !== InteractionState.Settled || // ignore when still placing
146
+ !model.activeState?.getActive() || // ignore when no selected state
147
+ model.hasFocus || // ignore when focused
148
+ dragging // ignore when dragging
149
+ ) {
150
+ return macro.VOID;
151
+ }
152
+ publicAPI.invokeRightClickEvent(eventData);
153
+ return macro.EVENT_ABORT;
154
+ };
155
+
156
+ publicAPI.grabFocus = () => {
157
+ if (
158
+ !model.hasFocus &&
159
+ // only allow focus if placing points
160
+ model.widgetState.getInteractionState() !== InteractionState.Settled
161
+ ) {
162
+ model.hasFocus = true;
163
+ // render the (invisible) point handles
164
+ model._interactor.requestAnimation(publicAPI);
165
+ publicAPI.invokeStartInteractionEvent();
166
+ }
167
+ };
168
+
169
+ publicAPI.loseFocus = () => {
170
+ if (model.hasFocus) {
171
+ model._interactor.cancelAnimation(publicAPI);
172
+ publicAPI.invokeEndInteractionEvent();
173
+ }
174
+ model.hasFocus = false;
175
+ // model._widgetManager.enablePicking();
176
+ // model._interactor.render();
177
+ };
178
+
179
+ publicAPI.delete = () => {
180
+ superClass.delete();
181
+ while (subscriptions.length) {
182
+ subscriptions.pop()!.unsubscribe();
183
+ }
184
+ };
185
+ }
@@ -0,0 +1,25 @@
1
+ import { vtkSubscription } from '@kitware/vtk.js/interfaces';
2
+ import vtkAbstractWidget from '@kitware/vtk.js/Widgets/Core/AbstractWidget';
3
+ import vtkAbstractWidgetFactory from '@kitware/vtk.js/Widgets/Core/AbstractWidgetFactory';
4
+ import vtkPlaneManipulator from '@kitware/vtk.js/Widgets/Manipulators/PlaneManipulator';
5
+ import { RulerWidgetState } from './state';
6
+
7
+ export interface vtkRulerViewWidget extends vtkAbstractWidget {
8
+ setManipulator(manipulator: vtkPlaneManipulator): boolean;
9
+ getManipulator(): vtkPlaneManipulator;
10
+ onRightClickEvent(cb: (eventData: any) => void): vtkSubscription;
11
+ }
12
+
13
+ export interface vtkRulerWidget extends vtkAbstractWidgetFactory {
14
+ getLength(): number;
15
+ getWidgetState(): RulerWidgetState;
16
+ }
17
+
18
+ export function newInstance(): vtkRulerWidget;
19
+
20
+ export function shouldIgnoreEvent(ev: any): boolean;
21
+
22
+ export declare const vtkRulerWidget: {
23
+ newInstance: typeof newInstance;
24
+ };
25
+ export default vtkRulerWidget;
@@ -0,0 +1,79 @@
1
+ import macro from '@kitware/vtk.js/macro';
2
+ import vtkAbstractWidgetFactory from '@kitware/vtk.js/Widgets/Core/AbstractWidgetFactory';
3
+ import vtkPlanePointManipulator from '@kitware/vtk.js/Widgets/Manipulators/PlaneManipulator';
4
+ import vtkSphereHandleRepresentation from '@kitware/vtk.js/Widgets/Representations/SphereHandleRepresentation';
5
+ import { distance2BetweenPoints } from '@kitware/vtk.js/Common/Core/Math';
6
+
7
+ import widgetBehavior from './behavior';
8
+ import stateGenerator from './state';
9
+
10
+ export { shouldIgnoreEvent } from './behavior';
11
+
12
+ // ----------------------------------------------------------------------------
13
+ // Factory
14
+ // ----------------------------------------------------------------------------
15
+
16
+ function vtkRulerWidget(publicAPI, model) {
17
+ model.classHierarchy.push('vtkRulerWidget');
18
+
19
+ // --- Widget Requirement ---------------------------------------------------
20
+
21
+ // model.methodsToLink = [
22
+ // 'activeScaleFactor',
23
+ // 'activeColor',
24
+ // 'useActiveColor',
25
+ // 'glyphResolution',
26
+ // 'defaultScale',
27
+ // 'text',
28
+ // 'textStateIndex',
29
+ // ];
30
+
31
+ publicAPI.getRepresentationsForViewType = () => [
32
+ {
33
+ builder: vtkSphereHandleRepresentation,
34
+ labels: ['points'],
35
+ initialValues: {
36
+ scaleInPixels: true,
37
+ },
38
+ },
39
+ ];
40
+
41
+ publicAPI.getLength = () => {
42
+ const first = model.widgetState.getFirstPoint().getOrigin();
43
+ const second = model.widgetState.getSecondPoint().getOrigin();
44
+ if (!first || !second) {
45
+ return 0;
46
+ }
47
+ return Math.sqrt(distance2BetweenPoints(first, second));
48
+ };
49
+
50
+ // Default manipulator
51
+ model.manipulator = vtkPlanePointManipulator.newInstance();
52
+ }
53
+
54
+ // ----------------------------------------------------------------------------
55
+
56
+ const DEFAULT_VALUES = {};
57
+
58
+ // ----------------------------------------------------------------------------
59
+
60
+ export function extend(publicAPI, model, initialValues = {}) {
61
+ Object.assign(model, DEFAULT_VALUES, initialValues);
62
+
63
+ vtkAbstractWidgetFactory.extend(publicAPI, model, {
64
+ ...initialValues,
65
+ behavior: widgetBehavior,
66
+ widgetState: stateGenerator(),
67
+ });
68
+ macro.get(publicAPI, model, ['manipulator']);
69
+
70
+ vtkRulerWidget(publicAPI, model);
71
+ }
72
+
73
+ // ----------------------------------------------------------------------------
74
+
75
+ export const newInstance = macro.newInstance(extend, 'vtkRulerWidget');
76
+
77
+ // ----------------------------------------------------------------------------
78
+
79
+ export default { newInstance, extend };
@@ -0,0 +1,63 @@
1
+ import { Vector3 } from '@kitware/vtk.js/types';
2
+ import vtkStateBuilder from '@kitware/vtk.js/Widgets/Core/StateBuilder';
3
+ import vtkWidgetState from '@kitware/vtk.js/Widgets/Core/WidgetState';
4
+
5
+ export enum InteractionState {
6
+ Settled = 0,
7
+ PlacingFirst = 1,
8
+ PlacingSecond = 2,
9
+ }
10
+
11
+ export interface RulerPointWidgetState extends vtkWidgetState {
12
+ setOrigin(origin: Vector3 | null): boolean;
13
+ getOrigin(): Vector3 | null;
14
+ setScale1(scale: number): boolean;
15
+ getScale1(): number;
16
+ setVisible(visible: boolean): boolean;
17
+ getVisible(): boolean;
18
+ setColor(color: number): boolean;
19
+ getColor(): number;
20
+ }
21
+
22
+ export interface RulerWidgetState extends vtkWidgetState {
23
+ getFirstPoint(): RulerPointWidgetState;
24
+ getSecondPoint(): RulerPointWidgetState;
25
+ getInteractionState(): InteractionState;
26
+ setInteractionState(state: InteractionState): boolean;
27
+ }
28
+
29
+ export default function generateState() {
30
+ return vtkStateBuilder
31
+ .createBuilder()
32
+ .addStateFromMixin({
33
+ labels: ['points'],
34
+ name: 'firstPoint',
35
+ mixins: ['origin', 'scale1', 'visible', 'color'],
36
+ initialValues: {
37
+ // diameter
38
+ scale1: 20,
39
+ origin: null,
40
+ visible: false,
41
+ },
42
+ })
43
+ .addStateFromMixin({
44
+ labels: ['points'],
45
+ name: 'secondPoint',
46
+ mixins: ['origin', 'scale1', 'visible', 'color'],
47
+ initialValues: {
48
+ // diameter
49
+ scale1: 20,
50
+ origin: null,
51
+ visible: false,
52
+ },
53
+ })
54
+ .addField({
55
+ name: 'interactionState',
56
+ initialValue: InteractionState.PlacingFirst,
57
+ })
58
+ .addField({
59
+ name: 'ID',
60
+ initialValue: '',
61
+ })
62
+ .build() as RulerWidgetState;
63
+ }
@@ -0,0 +1,150 @@
1
+ import vtkPolyData from '@kitware/vtk.js/Common/DataModel/PolyData';
2
+ import vtkDataArray from '@kitware/vtk.js/Common/Core/DataArray';
3
+ import vtkAppendPolyData from '@kitware/vtk.js/Filters/General/AppendPolyData';
4
+ import vtkPoints from '@kitware/vtk.js/Common/Core/Points';
5
+ import vtkTubeFilter from '@kitware/vtk.js/Filters/General/TubeFilter';
6
+ import { VaryRadius } from '@kitware/vtk.js/Filters/General/TubeFilter/Constants';
7
+ import { VtkDataTypes } from '@kitware/vtk.js/Common/Core/DataArray/Constants';
8
+
9
+ function concatPointData(pointDataList, arrayName) {
10
+ const length = pointDataList.reduce(
11
+ (len, pd) => len + pd[arrayName].getData().length,
12
+ 0
13
+ );
14
+
15
+ // use first array to initialize our copy
16
+ const first = pointDataList[0][arrayName];
17
+
18
+ const outData = new (first.getData().constructor)(length);
19
+ const da = vtkDataArray.newInstance({
20
+ name: arrayName,
21
+ numberOfComponents: first.getNumberOfComponents(),
22
+ values: outData,
23
+ });
24
+
25
+ for (let i = 0, offset = 0; i < pointDataList.length; i += 1) {
26
+ const array = pointDataList[i][arrayName];
27
+ const data = array.getData();
28
+ outData.set(data, offset);
29
+ offset += data.length;
30
+ }
31
+
32
+ return da;
33
+ }
34
+
35
+ function centerlineToTube(centerline) {
36
+ const pd = vtkPolyData.newInstance();
37
+ const pts = vtkPoints.newInstance({
38
+ dataType: VtkDataTypes.FLOAT,
39
+ numberOfComponents: 3,
40
+ });
41
+ pts.setNumberOfPoints(centerline.length);
42
+
43
+ const pointData = new Float32Array(3 * centerline.length);
44
+ const lines = new Uint32Array(centerline.length + 1);
45
+
46
+ lines[0] = centerline.length;
47
+ for (let i = 0; i < centerline.length; i += 1) {
48
+ const [x, y, z] = centerline[i].PositionInWorldSpace;
49
+ pointData[3 * i + 0] = x;
50
+ pointData[3 * i + 1] = y;
51
+ pointData[3 * i + 2] = z;
52
+ lines[i + 1] = i;
53
+ }
54
+
55
+ const radii = centerline.map((pt) => pt.RadiusInWorldSpace);
56
+ const radiusData = new Float32Array(radii);
57
+ const radius = vtkDataArray.newInstance({
58
+ name: 'Radius',
59
+ values: radiusData,
60
+ });
61
+
62
+ pts.setData(pointData);
63
+ pd.setPoints(pts);
64
+ pd.getLines().setData(lines);
65
+ pd.getPointData().addArray(radius);
66
+
67
+ const filter = vtkTubeFilter.newInstance({
68
+ capping: true,
69
+ radius: 1, // scaling factor
70
+ varyRadius: VaryRadius.VARY_RADIUS_BY_ABSOLUTE_SCALAR,
71
+ numberOfSides: 5,
72
+ });
73
+
74
+ filter.setInputArrayToProcess(0, 'Radius', 'PointData', 'Scalars');
75
+ filter.setInputData(pd);
76
+
77
+ return filter.getOutputData();
78
+ }
79
+
80
+ function convertCenterlinesToTubes(centerlines) {
81
+ const appendPolyData = vtkAppendPolyData.newInstance();
82
+ appendPolyData.setInputData(vtkPolyData.newInstance());
83
+
84
+ let numberOfCells = 0;
85
+
86
+ // convert each centerline to polydata,
87
+ // and prepare to concatenate them
88
+ const cellCounts = Array(centerlines.length);
89
+ const pointData = [];
90
+ for (let i = 0; i < centerlines.length; i += 1) {
91
+ const cline = centerlines[i];
92
+ const tubePd = centerlineToTube(cline);
93
+ const data = tubePd.getPointData();
94
+ pointData.push({
95
+ Radius: data.getArray('Radius'),
96
+ TubeNormals: data.getArray('TubeNormals'),
97
+ });
98
+ appendPolyData.addInputData(tubePd);
99
+
100
+ cellCounts[i] = tubePd.getNumberOfCells();
101
+ numberOfCells += cellCounts[i];
102
+ }
103
+
104
+ const polyData = appendPolyData.getOutputData();
105
+
106
+ // copy over point data
107
+ polyData.getPointData().setScalars(concatPointData(pointData, 'Radius'));
108
+ polyData.getPointData().setNormals(concatPointData(pointData, 'TubeNormals'));
109
+
110
+ // add colors
111
+ const colorData = new Uint8Array(4 * numberOfCells);
112
+ for (let i = 0, colorIdx = 0; i < centerlines.length; i += 1, colorIdx += 4) {
113
+ const cline = centerlines[i];
114
+ const cellCount = cellCounts[i]; // # of cells for ith tube
115
+ for (let j = 0; j < cellCount; j += 1) {
116
+ colorData[colorIdx + 0] = cline.Red * 255;
117
+ colorData[colorIdx + 1] = cline.Green * 255;
118
+ colorData[colorIdx + 2] = cline.Blue * 255;
119
+ colorData[colorIdx + 3] = 255; // ignore specified alpha for now
120
+ }
121
+ }
122
+
123
+ const colors = vtkDataArray.newInstance({
124
+ name: 'Colors',
125
+ values: colorData,
126
+ numberOfComponents: 4,
127
+ });
128
+ polyData.getCellData().addArray(colors);
129
+
130
+ return polyData;
131
+ }
132
+
133
+ function flattenTreHierarchy(treJson) {
134
+ const list = [];
135
+ if (treJson.Points) {
136
+ list.push(treJson.Points);
137
+ }
138
+
139
+ const children = treJson.Children ?? [];
140
+ for (let i = 0; i < children.length; i += 1) {
141
+ list.push(...flattenTreHierarchy(children[i]));
142
+ }
143
+
144
+ return list;
145
+ }
146
+
147
+ export default function convertJsonToTre(treJson) {
148
+ const centerlines = flattenTreHierarchy(treJson);
149
+ return convertCenterlinesToTubes(centerlines);
150
+ }
@@ -0,0 +1,66 @@
1
+ import vtkLookupTableProxy from '@kitware/vtk.js/Proxy/Core/LookupTableProxy';
2
+ import vtkPiecewiseFunctionProxy from '@kitware/vtk.js/Proxy/Core/PiecewiseFunctionProxy';
3
+
4
+ import vtkSourceProxy from '@kitware/vtk.js/Proxy/Core/SourceProxy';
5
+
6
+ import vtkVolumeRepresentationProxy from '@kitware/vtk.js/Proxy/Representations/VolumeRepresentationProxy';
7
+ import vtkGeometryRepresentationProxy from '@kitware/vtk.js/Proxy/Representations/GeometryRepresentationProxy';
8
+
9
+ import vtkLPSView3DProxy from '@/src/vtk/LPSView3DProxy';
10
+ import vtkLPSView2DProxy from '@/src/vtk/LPSView2DProxy';
11
+ import vtkIJKSliceRepresentationProxy from '@/src/vtk/IJKSliceRepresentationProxy';
12
+ import vtkLabelMapSliceRepProxy from '@/src/vtk/LabelMapSliceRepProxy';
13
+
14
+ function createProxyDefinition(
15
+ classFactory,
16
+ ui = [],
17
+ links = [],
18
+ definitionOptions = {},
19
+ props = {}
20
+ ) {
21
+ return {
22
+ class: classFactory,
23
+ options: { links, ui, ...definitionOptions },
24
+ props,
25
+ };
26
+ }
27
+
28
+ function createDefaultView(classFactory, options = [], props = {}) {
29
+ return createProxyDefinition(classFactory, [], [], options, props);
30
+ }
31
+
32
+ // ----------------------------------------------------------------------------
33
+
34
+ export default {
35
+ definitions: {
36
+ Proxy: {
37
+ LookupTable: createProxyDefinition(vtkLookupTableProxy, [], [], {
38
+ presetName: 'Default (Cool to Warm)',
39
+ }),
40
+ PiecewiseFunction: createProxyDefinition(vtkPiecewiseFunctionProxy),
41
+ },
42
+ Sources: {
43
+ TrivialProducer: createProxyDefinition(vtkSourceProxy),
44
+ },
45
+ Representations: {
46
+ ImageSlice: createProxyDefinition(vtkIJKSliceRepresentationProxy),
47
+ LabelMapSlice: createProxyDefinition(vtkLabelMapSliceRepProxy),
48
+ Volume: createProxyDefinition(vtkVolumeRepresentationProxy),
49
+ Geometry: createProxyDefinition(vtkGeometryRepresentationProxy),
50
+ },
51
+ Views: {
52
+ View3D: createDefaultView(vtkLPSView3DProxy),
53
+ View2D: createDefaultView(vtkLPSView2DProxy),
54
+ },
55
+ },
56
+ representations: {
57
+ View3D: {
58
+ vtkImageData: { name: 'Volume' },
59
+ vtkPolyData: { name: 'Geometry' },
60
+ },
61
+ View2D: {
62
+ vtkImageData: { name: 'ImageSlice' },
63
+ vtkLabelMap: { name: 'LabelMapSlice' },
64
+ },
65
+ },
66
+ };
@@ -0,0 +1,16 @@
1
+ export function createOrGetView(proxyManager, viewType, name) {
2
+ const views = proxyManager.getViews();
3
+ const view = views.find((v) => v.getName() === name);
4
+ if (view) {
5
+ return view;
6
+ }
7
+
8
+ return proxyManager.createProxy('Views', viewType, { name });
9
+ }
10
+
11
+ export function createFourUpViews(proxyManager) {
12
+ createOrGetView(proxyManager, 'ViewX', 'X:1');
13
+ createOrGetView(proxyManager, 'ViewY', 'Y:1');
14
+ createOrGetView(proxyManager, 'ViewZ', 'Z:1');
15
+ createOrGetView(proxyManager, 'View3D', '3D:1');
16
+ }
@@ -0,0 +1 @@
1
+ export default function () {}
@@ -0,0 +1,12 @@
1
+ export function makeEmptyFile(name) {
2
+ return new File([], name);
3
+ }
4
+
5
+ export function makeDicomFile(name) {
6
+ const buffer = new Uint8Array(132);
7
+ buffer[128] = 'D'.charCodeAt(0);
8
+ buffer[129] = 'I'.charCodeAt(0);
9
+ buffer[130] = 'C'.charCodeAt(0);
10
+ buffer[131] = 'M'.charCodeAt(0);
11
+ return new File([buffer.buffer], name);
12
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "es2019",
4
+ "module": "esnext",
5
+ "strict": true,
6
+ "jsx": "preserve",
7
+ "importHelpers": true,
8
+ "moduleResolution": "node",
9
+ "allowJs": true,
10
+ "skipLibCheck": true,
11
+ "esModuleInterop": true,
12
+ "allowSyntheticDefaultImports": true,
13
+ "sourceMap": true,
14
+ "baseUrl": ".",
15
+ "resolveJsonModule": true,
16
+ "types": [
17
+ "webpack-env",
18
+ "mocha",
19
+ "chai"
20
+ ],
21
+ "paths": {
22
+ "@/*": [
23
+ "./*"
24
+ ],
25
+ "@src/*": [
26
+ "src/*"
27
+ ]
28
+ },
29
+ "lib": [
30
+ "esnext",
31
+ "dom",
32
+ "dom.iterable",
33
+ "scripthost"
34
+ ]
35
+ },
36
+ "include": [
37
+ "src/**/*.ts",
38
+ "src/**/*.tsx",
39
+ "src/**/*.vue",
40
+ "tests/**/*.ts",
41
+ "tests/**/*.tsx"
42
+ ],
43
+ "exclude": [
44
+ "node_modules"
45
+ ]
46
+ }