diff --git a/package-lock.json b/package-lock.json index 5ccb516..cf87a32 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,7 @@ "@babel/plugin-transform-runtime": "^7.12.10", "@babel/preset-env": "^7.12.11", "@babel/preset-react": "^7.12.10", - "@kitware/vtk.js": "^26.5.3", + "@kitware/vtk.js": "^28.0.0", "@rollup/plugin-babel": "^5.2.2", "@rollup/plugin-commonjs": "17.0.0", "@rollup/plugin-eslint": "^8.0.1", @@ -46,7 +46,7 @@ "semantic-release": "17.3.1" }, "peerDependencies": { - "@kitware/vtk.js": "^26.5.3", + "@kitware/vtk.js": "^28.0.0", "react": "^16.0.0" } }, @@ -2226,9 +2226,9 @@ } }, "node_modules/@kitware/vtk.js": { - "version": "26.5.3", - "resolved": "https://registry.npmjs.org/@kitware/vtk.js/-/vtk.js-26.5.3.tgz", - "integrity": "sha512-TkXS7KgZf3cr0cEsv9nTYgsXIK+B60b0q2cpHXHhTdD9ReHRyD3FbCF0cOi95lO0KlpyuDy58Fe6yFZwjmnnpw==", + "version": "28.2.0", + "resolved": "https://registry.npmjs.org/@kitware/vtk.js/-/vtk.js-28.2.0.tgz", + "integrity": "sha512-5d+y1fTqjfBPqjrFH/Bs6bzyLLscN/wrWM6YQX2GC1Vj7QmWB4zl7XlEYzL/DlHLH3TZb7Ua3MX/RpABIZjChw==", "dev": true, "dependencies": { "@babel/runtime": "7.17.9", @@ -2252,6 +2252,8 @@ "xml2json": "Utilities/XMLConverter/xml2json-cli.js" }, "peerDependencies": { + "@babel/preset-env": "^7.17.10", + "autoprefixer": "^10.4.7", "wslink": "^1.1.0" } }, @@ -4095,6 +4097,40 @@ "node": ">= 4.5.0" } }, + "node_modules/autoprefixer": { + "version": "10.4.14", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz", + "integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + } + ], + "peer": true, + "dependencies": { + "browserslist": "^4.21.5", + "caniuse-lite": "^1.0.30001464", + "fraction.js": "^4.2.0", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, "node_modules/babel-eslint": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", @@ -4265,9 +4301,9 @@ } }, "node_modules/browserslist": { - "version": "4.21.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", - "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "version": "4.21.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", + "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", "dev": true, "funding": [ { @@ -4280,10 +4316,10 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001400", - "electron-to-chromium": "^1.4.251", - "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.9" + "caniuse-lite": "^1.0.30001449", + "electron-to-chromium": "^1.4.284", + "node-releases": "^2.0.8", + "update-browserslist-db": "^1.0.10" }, "bin": { "browserslist": "cli.js" @@ -4388,9 +4424,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001439", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001439.tgz", - "integrity": "sha512-1MgUzEkoMO6gKfXflStpYgZDlFM7M/ck/bgfVCACO5vnAf0fXoNVHdWtqGU+MYca+4bL9Z5bpOVmR33cWW9G2A==", + "version": "1.0.30001489", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001489.tgz", + "integrity": "sha512-x1mgZEXK8jHIfAxm+xgdpHpk50IN3z3q3zP261/WS+uvePxW8izXuCu6AHz0lkuYTlATDehiZ/tNyYBdSQsOUQ==", "dev": true, "funding": [ { @@ -4400,6 +4436,10 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ] }, @@ -7102,6 +7142,20 @@ "node": ">=0.10.0" } }, + "node_modules/fraction.js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", + "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==", + "dev": true, + "peer": true, + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://www.patreon.com/infusion" + } + }, "node_modules/fragment-cache": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", @@ -9155,6 +9209,25 @@ "integrity": "sha512-r65nCZhrbXXb6dXOACihYApHw2Q6pV0M3V0PSxd74N0+D8nzAdEAITq2oAjA1jVnKI+tGvEBUpqiMh0+rW6zDQ==", "dev": true }, + "node_modules/nanoid": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", + "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "peer": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, "node_modules/nanomatch": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", @@ -9231,9 +9304,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", - "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.11.tgz", + "integrity": "sha512-+M0PwXeU80kRohZ3aT4J/OnR+l9/KD2nVLNNoRgFtnf+umQVFdGBAO2N8+nCnEi0xlh/Wk3zOGC+vNNx+uM79Q==", "dev": true }, "node_modules/normalize-package-data": { @@ -9257,6 +9330,16 @@ "semver": "bin/semver" } }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/normalize-url": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz", @@ -12885,6 +12968,42 @@ "node": ">=0.10.0" } }, + "node_modules/postcss": { + "version": "8.4.23", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.23.tgz", + "integrity": "sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "peer": true, + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, + "peer": true + }, "node_modules/prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", @@ -14270,6 +14389,16 @@ "node": ">=0.10.0" } }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-resolve": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", @@ -17613,9 +17742,9 @@ } }, "@kitware/vtk.js": { - "version": "26.5.3", - "resolved": "https://registry.npmjs.org/@kitware/vtk.js/-/vtk.js-26.5.3.tgz", - "integrity": "sha512-TkXS7KgZf3cr0cEsv9nTYgsXIK+B60b0q2cpHXHhTdD9ReHRyD3FbCF0cOi95lO0KlpyuDy58Fe6yFZwjmnnpw==", + "version": "28.2.0", + "resolved": "https://registry.npmjs.org/@kitware/vtk.js/-/vtk.js-28.2.0.tgz", + "integrity": "sha512-5d+y1fTqjfBPqjrFH/Bs6bzyLLscN/wrWM6YQX2GC1Vj7QmWB4zl7XlEYzL/DlHLH3TZb7Ua3MX/RpABIZjChw==", "dev": true, "requires": { "@babel/runtime": "7.17.9", @@ -19089,6 +19218,21 @@ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", "dev": true }, + "autoprefixer": { + "version": "10.4.14", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz", + "integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==", + "dev": true, + "peer": true, + "requires": { + "browserslist": "^4.21.5", + "caniuse-lite": "^1.0.30001464", + "fraction.js": "^4.2.0", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + } + }, "babel-eslint": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", @@ -19229,15 +19373,15 @@ } }, "browserslist": { - "version": "4.21.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", - "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "version": "4.21.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", + "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001400", - "electron-to-chromium": "^1.4.251", - "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.9" + "caniuse-lite": "^1.0.30001449", + "electron-to-chromium": "^1.4.284", + "node-releases": "^2.0.8", + "update-browserslist-db": "^1.0.10" } }, "buffer-from": { @@ -19309,9 +19453,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001439", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001439.tgz", - "integrity": "sha512-1MgUzEkoMO6gKfXflStpYgZDlFM7M/ck/bgfVCACO5vnAf0fXoNVHdWtqGU+MYca+4bL9Z5bpOVmR33cWW9G2A==", + "version": "1.0.30001489", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001489.tgz", + "integrity": "sha512-x1mgZEXK8jHIfAxm+xgdpHpk50IN3z3q3zP261/WS+uvePxW8izXuCu6AHz0lkuYTlATDehiZ/tNyYBdSQsOUQ==", "dev": true }, "cardinal": { @@ -21372,6 +21516,13 @@ "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", "dev": true }, + "fraction.js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", + "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==", + "dev": true, + "peer": true + }, "fragment-cache": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", @@ -22924,6 +23075,13 @@ "integrity": "sha512-r65nCZhrbXXb6dXOACihYApHw2Q6pV0M3V0PSxd74N0+D8nzAdEAITq2oAjA1jVnKI+tGvEBUpqiMh0+rW6zDQ==", "dev": true }, + "nanoid": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", + "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "dev": true, + "peer": true + }, "nanomatch": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", @@ -22986,9 +23144,9 @@ } }, "node-releases": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", - "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.11.tgz", + "integrity": "sha512-+M0PwXeU80kRohZ3aT4J/OnR+l9/KD2nVLNNoRgFtnf+umQVFdGBAO2N8+nCnEi0xlh/Wk3zOGC+vNNx+uM79Q==", "dev": true }, "normalize-package-data": { @@ -23011,6 +23169,13 @@ } } }, + "normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true, + "peer": true + }, "normalize-url": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz", @@ -25621,6 +25786,25 @@ "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==", "dev": true }, + "postcss": { + "version": "8.4.23", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.23.tgz", + "integrity": "sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==", + "dev": true, + "peer": true, + "requires": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + } + }, + "postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, + "peer": true + }, "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", @@ -26681,6 +26865,13 @@ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true }, + "source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true, + "peer": true + }, "source-map-resolve": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", diff --git a/package.json b/package.json index 378a639..86e7c8c 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "dev": "rollup ./src/index.js -c --watch" }, "peerDependencies": { - "@kitware/vtk.js": "^26.8.0", + "@kitware/vtk.js": "^28.0.0", "react": "^16.0.0" }, "devDependencies": { @@ -50,7 +50,7 @@ "@babel/plugin-transform-runtime": "^7.12.10", "@babel/preset-env": "^7.12.11", "@babel/preset-react": "^7.12.10", - "@kitware/vtk.js": "^26.5.3", + "@kitware/vtk.js": "^28.0.0", "@rollup/plugin-babel": "^5.2.2", "@rollup/plugin-commonjs": "17.0.0", "@rollup/plugin-eslint": "^8.0.1", diff --git a/src/core/ResliceRepresentation.js b/src/core/ResliceRepresentation.js new file mode 100644 index 0000000..626a80a --- /dev/null +++ b/src/core/ResliceRepresentation.js @@ -0,0 +1,150 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import vtkSliceRepresentation from './SliceRepresentation'; +import { ViewContext, RepresentationContext, DownstreamContext } from './View'; + +import vtkImageResliceMapper from '@kitware/vtk.js/Rendering/Core/ImageResliceMapper.js'; +import { SlabTypes } from '@kitware/vtk.js/Rendering/Core/ImageResliceMapper/Constants.js'; + +/** + * ResliceRepresentation is an image slice representation that allows: + * - Orthogonal slicing + * - Oblique slicing + * - Slab mode (thick slices) + * - Slice a volume using arbitary geometry + */ +export default class ResliceRepresentation extends vtkSliceRepresentation { + constructor(props) { + super(props); + // Create the vtk.js objects + this.mapper = props.mapperInstance ?? vtkImageResliceMapper.newInstance(); + this.actor.setMapper(this.mapper); + this.actor.getProperty().setRGBTransferFunction(0, this.lookupTable); + // this.actor.getProperty().setScalarOpacity(0, this.piecewiseFunction); + this.actor.getProperty().setInterpolationTypeToLinear(); + } + + render() { + return ( + + {(view) => { + if (!this.view) { + view.renderer.addActor(this.actor); + this.view = view; + } + return ( + + +
+ {this.props.children} +
+
+
+ ); + }} +
+ ); + } + + componentDidMount() { + this.update(this.props); + } + + componentDidUpdate(prevProps, prevState, snapshot) { + this.update(this.props, prevProps); + } + + componentWillUnmount() { + super.componentWillUnmount(); + if (this.view && this.view.renderer) { + this.view.renderer.removeActor(this.actor); + } + } + + update(props, previous) { + const { + slicePlane, + slicePolyData, + slabType, + slabThickness, + slabTrapezoidIntegration, + } = props; + let changed = false; + if (!previous || slicePlane !== previous.slicePlane) { + changed = this.mapper.setSlicePlane(slicePlane); + } + if (!previous || slicePolyData !== previous.slicePolyData) { + changed = this.mapper.setSlicePolyData(slicePolyData); + } + if (this.validData) { + if ( + slabType != null && + (!previous || slabType !== previous.slabType) && + slabType >= SlabTypes.MIN && + slabType <= SlabTypes.SUM + ) { + changed = this.mapper.setSlabType(slabType); + } + if ( + slabThickness != null && + (!previous || slabThickness !== previous.slabThickness) + ) { + changed = this.mapper.setSlabThickness(slabThickness); + } + if ( + slabTrapezoidIntegration != null && + (!previous || + slabTrapezoidIntegration !== previous.slabTrapezoidIntegration) + ) { + changed = this.mapper.setSlabTrapezoidIntegration( + slabTrapezoidIntegration + ); + } + } + super.update(props, previous); + + // trigger render + if (changed) { + super.dataChanged(); + } + } +} + +ResliceRepresentation.defaultProps = { + sliceThickness: 0.0, + slabType: SlabTypes.MEAN, + slabTrapezoidIntegration: false, +}; + +ResliceRepresentation.propTypes = { + /** + * Slice plane + */ + slicePlane: PropTypes.object, + + /** + * Optional slice polydata + */ + slicePolyData: PropTypes.object, + + /** + * Slab type + */ + slabType: PropTypes.number, + + /** + * Slab thickness + */ + slabThickness: PropTypes.number, + + /** + * Slab trapezoid integration + */ + slabTrapezoidIntegration: PropTypes.bool, + + children: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.node), + PropTypes.node, + ]), +}; diff --git a/src/core/index.js b/src/core/index.js index f60601c..2aa1bc8 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -1,5 +1,6 @@ import vtkVolumeRepresentation from './VolumeRepresentation'; import vtkSliceRepresentation from './SliceRepresentation'; +import vtkResliceRepresentation from './ResliceRepresentation'; import vtkVolumeController from './VolumeController'; import vtkPointData from './PointData'; import vtkPolyData from './PolyData'; @@ -20,6 +21,7 @@ import vtkMultiViewRoot from './MultiViewRoot'; export const VolumeRepresentation = vtkVolumeRepresentation; export const SliceRepresentation = vtkSliceRepresentation; +export const ResliceRepresentation = vtkResliceRepresentation; export const VolumeController = vtkVolumeController; export const PointData = vtkPointData; export const PolyData = vtkPolyData; @@ -41,6 +43,7 @@ export const MultiViewRoot = vtkMultiViewRoot; export default { VolumeRepresentation: vtkVolumeRepresentation, SliceRepresentation: vtkSliceRepresentation, + ResliceRepresentation: vtkResliceRepresentation, VolumeController: vtkVolumeController, PointData: vtkPointData, PolyData: vtkPolyData, diff --git a/src/light.js b/src/light.js index a719d08..804df36 100644 --- a/src/light.js +++ b/src/light.js @@ -13,6 +13,7 @@ import { // Core export const VolumeRepresentation = Core.VolumeRepresentation; export const SliceRepresentation = Core.SliceRepresentation; +export const ResliceRepresentation = Core.ResliceRepresentation; export const VolumeController = Core.VolumeController; export const PointData = Core.PointData; export const PolyData = Core.PolyData; diff --git a/usage/package-lock.json b/usage/package-lock.json index 5a196e9..fec5513 100644 --- a/usage/package-lock.json +++ b/usage/package-lock.json @@ -28,7 +28,7 @@ "@babel/plugin-transform-runtime": "^7.12.10", "@babel/preset-env": "^7.12.11", "@babel/preset-react": "^7.12.10", - "@kitware/vtk.js": "^26.8.0", + "@kitware/vtk.js": "^26.5.3", "@rollup/plugin-babel": "^5.2.2", "@rollup/plugin-commonjs": "17.0.0", "@rollup/plugin-eslint": "^8.0.1", diff --git a/usage/src/App.jsx b/usage/src/App.jsx index 4f681e5..fa7c3aa 100644 --- a/usage/src/App.jsx +++ b/usage/src/App.jsx @@ -12,7 +12,10 @@ const SourceViewer = lazy(() => import('./Geometry/SourceViewer')); const Glyph = lazy(() => import('./Geometry/Glyph')); const CutterExample = lazy(() => import('./Geometry/CutterExample')); const SliceRendering = lazy(() => import('./Volume/SliceRendering')); -const ImageSeriesRendering = lazy(() => import('./Volume/ImageSeriesRendering')); +const ResliceRendering = lazy(() => import('./Volume/ResliceRendering')); +const ImageSeriesRendering = lazy(() => + import('./Volume/ImageSeriesRendering') +); const SyntheticVolumeRendering = lazy(() => import('./Volume/SyntheticVolumeRendering') ); @@ -31,6 +34,7 @@ const demos = [ 'Geometry/Glyph', 'Geometry/CutterExample', 'Volume/SliceRendering', + 'Volume/ResliceRendering', 'Volume/ImageSeriesRendering', 'Volume/SyntheticVolumeRendering', 'Volume/VolumeRendering', @@ -91,8 +95,11 @@ function App() { {example === 'Geometry/SourceViewer' && } {example === 'Geometry/Glyph' && } {example === 'Geometry/CutterExample' && } + {example === 'Volume/ResliceRendering' && } {example === 'Volume/SliceRendering' && } - {example === 'Volume/ImageSeriesRendering' && } + {example === 'Volume/ImageSeriesRendering' && ( + + )} {example === 'Volume/SyntheticVolumeRendering' && ( )} diff --git a/usage/src/Volume/ResliceRendering.jsx b/usage/src/Volume/ResliceRendering.jsx new file mode 100644 index 0000000..5d930f2 --- /dev/null +++ b/usage/src/Volume/ResliceRendering.jsx @@ -0,0 +1,376 @@ +import React, { useState, useContext } from 'react'; +import vtkColorMaps from '@kitware/vtk.js/Rendering/Core/ColorTransferFunction/ColorMaps.js'; +import { SlabTypes } from '@kitware/vtk.js/Rendering/Core/ImageResliceMapper/Constants.js'; +import { InterpolationType } from '@kitware/vtk.js/Rendering/Core/ImageProperty/Constants.js'; +import { newInstance as newVtkCylinderInstance } from '@kitware/vtk.js/Filters/Sources/CylinderSource.js'; +import { newInstance as newVtkPlaneInstance } from '@kitware/vtk.js/Common/DataModel/Plane.js'; + +import { + View, + ShareDataSet, + ResliceRepresentation, + Reader, + Contexts, + VolumeController, + VolumeRepresentation, +} from 'react-vtk-js'; + +const plane = newVtkPlaneInstance({ + origin: [127, 0, 0], + normal: [1, 0, 0], +}); +const cyl = newVtkCylinderInstance({ + height: 255, + radius: 50, + resolution: 20, + capping: 1, + center: [127, 127, 94], +}); + +function Slider(props) { + const view = useContext(Contexts.ViewContext); + const onChange = (e) => { + const value = Number(e.currentTarget.value); + props.setValue(value); + setTimeout(view.renderView, 0); + }; + return ( + + ); +} + +function DropDown(props) { + const view = useContext(Contexts.ViewContext); + function onChange(e) { + const value = e.currentTarget.value; + props.setValue(value); + setTimeout(view.renderView, 0); + } + return ( + + ); +} + +function EnumDropDown(props) { + const view = useContext(Contexts.ViewContext); + function onChange(e) { + const value = parseInt(e.currentTarget.value); + props.setValue(value); + setTimeout(view.renderView, 0); + } + return ( + + ); +} + +function CheckBox(props) { + const view = useContext(Contexts.ViewContext); + function onChange(e) { + const value = e.currentTarget.checked; + props.setValue(value); + setTimeout(view.renderView, 0); + } + return ( + + ); +} + +function SliceFunction(props) { + const view = useContext(Contexts.ViewContext); + function onChange(e) { + const value = e.currentTarget.checked; + if (value) { + // Using a slice polydata + cyl.update(); + props.setSlicePolyData(cyl.getOutputData()); + } else { + // plane.update(); + // props.setSlicePolyData(plane.getOutputData()); + props.setSlicePolyData(null); + props.setSlicePlane(plane); + } + props.setValue(value); + setTimeout(view.renderView, 0); + setTimeout(view.resetCamera, 0); + } + return ( + + ); +} + +function PosSlider(props) { + const s = Slider(props); + plane.setOrigin(props.value, 0, 0); + return s; +} + +function Example(props) { + const [slabThickness, setSlabThickness] = useState(0); + const [slabType, setSlabType] = useState(SlabTypes.MAX); + const [interpolationType, setInterpolationType] = useState( + InterpolationType.LINEAR + ); + const [slabTrapezoidIntegration, setSlabTrapezoidIntegration] = + useState(false); + const [colorWindow, setColorWindow] = useState(2095); + const [colorLevel, setColorLevel] = useState(1000); + const [colorPreset, setColorPreset] = useState('Grayscale'); + const [useLookupTableScalarRange, setUseLookupTableScalarRange] = + useState(false); + const [usePolyData, setUsePolyData] = useState(false); + const [slicePolyData, setSlicePolyData] = useState(null); + const [slicePlane, setSlicePlane] = useState(plane); + const [slicePos, setSlicePos] = useState(127); + return ( +
+
+ + + + + + + + + + + + + + + + + + +
+
+ + +
+ +
+ +
+
+
+
+ ); +} + +export default Example; diff --git a/usage/src/Volume/SliceRendering.jsx b/usage/src/Volume/SliceRendering.jsx index b0c3d75..dfdaefa 100644 --- a/usage/src/Volume/SliceRendering.jsx +++ b/usage/src/Volume/SliceRendering.jsx @@ -67,7 +67,9 @@ function DropDown(props) { }} > {props.options.map((opt) => ( - + ))} );