BoxWidget.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. import macro from '@kitware/vtk.js/macros';
  2. import vtkAbstractWidgetFactory from '@kitware/vtk.js/Widgets/Core/AbstractWidgetFactory';
  3. import vtkConvexFaceContextRepresentation from '@kitware/vtk.js/Widgets/Representations/ConvexFaceContextRepresentation';
  4. import vtkPlaneManipulator from '@kitware/vtk.js/Widgets/Manipulators/PlaneManipulator';
  5. import vtkSphereHandleRepresentation from '@kitware/vtk.js/Widgets/Representations/SphereHandleRepresentation';
  6. import vtkStateBuilder from '@kitware/vtk.js/Widgets/Core/StateBuilder';
  7. import { ViewTypes } from '@kitware/vtk.js/Widgets/Core/WidgetManager/Constants';
  8. // ----------------------------------------------------------------------------
  9. // Widget linked to a view
  10. // ----------------------------------------------------------------------------
  11. function widgetBehavior(publicAPI, model) {
  12. let isDragging = null;
  13. publicAPI.setDisplayCallback = (callback) =>
  14. model.representations[0].setDisplayCallback(callback);
  15. publicAPI.handleLeftButtonPress = () => {
  16. if (
  17. !model.activeState ||
  18. !model.activeState.getActive() ||
  19. !model.pickable
  20. ) {
  21. return macro.VOID;
  22. }
  23. isDragging = true;
  24. model._interactor.requestAnimation(publicAPI);
  25. return macro.EVENT_ABORT;
  26. };
  27. publicAPI.handleMouseMove = (callData) => {
  28. if (isDragging && model.pickable) {
  29. return publicAPI.handleEvent(callData);
  30. }
  31. return macro.VOID;
  32. };
  33. publicAPI.handleLeftButtonRelease = () => {
  34. if (isDragging && model.pickable) {
  35. model._interactor.cancelAnimation(publicAPI);
  36. }
  37. isDragging = false;
  38. model.widgetState.deactivate();
  39. };
  40. publicAPI.handleEvent = (callData) => {
  41. if (
  42. model.pickable &&
  43. model.manipulator &&
  44. model.activeState &&
  45. model.activeState.getActive()
  46. ) {
  47. // model.manipulator.setNormal(model.camera.getDirectionOfProjection());
  48. const { worldCoords } = model.manipulator.handleEvent(
  49. callData,
  50. model._apiSpecificRenderWindow
  51. );
  52. if (worldCoords.length) {
  53. model.activeState.setOrigin(...worldCoords);
  54. }
  55. return macro.EVENT_ABORT;
  56. }
  57. return macro.VOID;
  58. };
  59. // --------------------------------------------------------------------------
  60. // initialization
  61. // --------------------------------------------------------------------------
  62. model.camera = model._renderer.getActiveCamera();
  63. model.classHierarchy.push('vtkBoxWidgetProp');
  64. }
  65. // ----------------------------------------------------------------------------
  66. // Factory
  67. // ----------------------------------------------------------------------------
  68. function vtkBoxWidget(publicAPI, model) {
  69. model.classHierarchy.push('vtkBoxWidget');
  70. // --- Widget Requirement ---------------------------------------------------
  71. model.behavior = widgetBehavior;
  72. model.methodsToLink = ['scaleInPixels'];
  73. publicAPI.getRepresentationsForViewType = (viewType) => {
  74. switch (viewType) {
  75. case ViewTypes.DEFAULT:
  76. case ViewTypes.GEOMETRY:
  77. case ViewTypes.SLICE:
  78. case ViewTypes.VOLUME:
  79. default:
  80. return [
  81. { builder: vtkSphereHandleRepresentation, labels: ['handles'] },
  82. {
  83. builder: vtkConvexFaceContextRepresentation,
  84. labels: ['---', '--+', '-++', '-+-'],
  85. },
  86. {
  87. builder: vtkConvexFaceContextRepresentation,
  88. labels: ['---', '+--', '+-+', '--+'],
  89. },
  90. {
  91. builder: vtkConvexFaceContextRepresentation,
  92. labels: ['+--', '++-', '+++', '+-+'],
  93. },
  94. {
  95. builder: vtkConvexFaceContextRepresentation,
  96. labels: ['++-', '-+-', '-++', '+++'],
  97. },
  98. {
  99. builder: vtkConvexFaceContextRepresentation,
  100. labels: ['--+', '+-+', '+++', '-++'],
  101. },
  102. {
  103. builder: vtkConvexFaceContextRepresentation,
  104. labels: ['---', '+--', '++-', '-+-'],
  105. },
  106. ];
  107. }
  108. };
  109. // --- Widget Requirement ---------------------------------------------------
  110. // Default state
  111. model.widgetState = vtkStateBuilder
  112. .createBuilder()
  113. .addStateFromMixin({
  114. labels: ['handles', '---'],
  115. mixins: ['origin', 'color', 'scale1', 'manipulator'],
  116. name: 'handle',
  117. initialValues: {
  118. scale1: 0.1,
  119. origin: [-1, -1, -1],
  120. },
  121. })
  122. .addStateFromMixin({
  123. labels: ['handles', '-+-'],
  124. mixins: ['origin', 'color', 'scale1', 'manipulator'],
  125. name: 'handle',
  126. initialValues: {
  127. scale1: 0.1,
  128. origin: [-1, 1, -1],
  129. },
  130. })
  131. .addStateFromMixin({
  132. labels: ['handles', '+--'],
  133. mixins: ['origin', 'color', 'scale1', 'manipulator'],
  134. name: 'handle',
  135. initialValues: {
  136. scale1: 0.1,
  137. origin: [1, -1, -1],
  138. },
  139. })
  140. .addStateFromMixin({
  141. labels: ['handles', '++-'],
  142. mixins: ['origin', 'color', 'scale1', 'manipulator'],
  143. name: 'handle',
  144. initialValues: {
  145. scale1: 0.1,
  146. origin: [1, 1, -1],
  147. },
  148. })
  149. .addStateFromMixin({
  150. labels: ['handles', '--+'],
  151. mixins: ['origin', 'color', 'scale1', 'manipulator'],
  152. name: 'handle',
  153. initialValues: {
  154. scale1: 0.1,
  155. origin: [-1, -1, 1],
  156. },
  157. })
  158. .addStateFromMixin({
  159. labels: ['handles', '-++'],
  160. mixins: ['origin', 'color', 'scale1', 'manipulator'],
  161. name: 'handle',
  162. initialValues: {
  163. scale1: 0.1,
  164. origin: [-1, 1, 1],
  165. },
  166. })
  167. .addStateFromMixin({
  168. labels: ['handles', '+-+'],
  169. mixins: ['origin', 'color', 'scale1', 'manipulator'],
  170. name: 'handle',
  171. initialValues: {
  172. scale1: 0.1,
  173. origin: [1, -1, 1],
  174. },
  175. })
  176. .addStateFromMixin({
  177. labels: ['handles', '+++'],
  178. mixins: ['origin', 'color', 'scale1', 'manipulator'],
  179. name: 'handle',
  180. initialValues: {
  181. scale1: 0.1,
  182. origin: [1, 1, 1],
  183. },
  184. })
  185. .build();
  186. const handles = model.widgetState.getStatesWithLabel('handles');
  187. // Default manipulator
  188. model.manipulator = vtkPlaneManipulator.newInstance({
  189. useCameraNormal: true,
  190. });
  191. handles.forEach((handle) => handle.setManipulator(model.manipulator));
  192. }
  193. // ----------------------------------------------------------------------------
  194. const DEFAULT_VALUES = {
  195. manipulator: null,
  196. };
  197. // ----------------------------------------------------------------------------
  198. export function extend(publicAPI, model, initialValues = {}) {
  199. Object.assign(model, DEFAULT_VALUES, initialValues);
  200. vtkAbstractWidgetFactory.extend(publicAPI, model, initialValues);
  201. macro.setGet(publicAPI, model, ['manipulator']);
  202. vtkBoxWidget(publicAPI, model);
  203. }
  204. // ----------------------------------------------------------------------------
  205. export const newInstance = macro.newInstance(extend, 'vtkBoxWidget');
  206. // ----------------------------------------------------------------------------
  207. export default { newInstance, extend };