From 304526294c2cefec6ddd66728b01e00a5fa26ba2 Mon Sep 17 00:00:00 2001 From: Sankhesh Jhaveri Date: Wed, 24 May 2023 18:10:23 -0400 Subject: [PATCH 1/5] vtk-js: Update version number --- package-lock.json | 259 ++++++++++++++++++++++++++++++++++++++++------ package.json | 4 +- 2 files changed, 227 insertions(+), 36 deletions(-) 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", From c9251690b18fe17abe18c83e4dd64443498b1934 Mon Sep 17 00:00:00 2001 From: Sankhesh Jhaveri Date: Wed, 24 May 2023 18:12:23 -0400 Subject: [PATCH 2/5] feat(Representation): Added a new ResliceRepresentation --- src/core/ResliceRepresentation.js | 141 ++++++++++++++++++++++++++++++ src/core/index.js | 3 + src/light.js | 1 + 3 files changed, 145 insertions(+) create mode 100644 src/core/ResliceRepresentation.js diff --git a/src/core/ResliceRepresentation.js b/src/core/ResliceRepresentation.js new file mode 100644 index 0000000..20ad2af --- /dev/null +++ b/src/core/ResliceRepresentation.js @@ -0,0 +1,141 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import { ViewContext, RepresentationContext, DownstreamContext } from './View'; +import vtkSliceRepresentation from './SliceRepresentation'; +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 (slicePlane && (!previous || slicePlane !== previous.slicePlane)) { + changed = this.slicePlane.set(slicePlane) || changed; + } + if ( + slicePolyData && + (!previous || slicePolyData !== previous.slicePolyData) + ) { + changed = this.slicePolyData.set(slicePolyData) || changed; + } + if (this.validData) { + if (slabType != null && (!previous || slabType !== previous.slabType)) { + 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.propTypes = { + /** + * Slice plane + */ + slicePlane: PropTypes.object, + + /** + * Optional slice polydata + */ + slicePolyData: PropTypes.object, + + /** + * Slab type + */ + slabType: PropTypes.arrayOf(PropTypes.oneOf(SlabTypes)), + + /** + * 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; From 74cb090bb4e14d5ac586d8857c6b80b7cb2b8380 Mon Sep 17 00:00:00 2001 From: Sankhesh Jhaveri Date: Wed, 24 May 2023 18:13:29 -0400 Subject: [PATCH 3/5] test(Rendering): Added an example for ResliceRepresentation --- usage/package-lock.json | 2 +- usage/src/App.jsx | 11 +- usage/src/Volume/ResliceRendering.jsx | 292 ++++++++++++++++++++++++++ usage/src/Volume/SliceRendering.jsx | 4 +- 4 files changed, 305 insertions(+), 4 deletions(-) create mode 100644 usage/src/Volume/ResliceRendering.jsx 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..4b4a064 --- /dev/null +++ b/usage/src/Volume/ResliceRendering.jsx @@ -0,0 +1,292 @@ +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 { + View, + ShareDataSet, + ResliceRepresentation, + Reader, + Contexts, + VolumeController, + VolumeRepresentation, +} from 'react-vtk-js'; + +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); + console.log(props.options); + 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 = 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 Example(props) { + const [iSlice, setISlice] = useState(128); + const [jSlice, setJSlice] = useState(128); + const [kSlice, setKSlice] = useState(47); + const [slabThickness, setSlabThickness] = useState(0); + const [slabType, setSlabType] = useState(SlabTypes.MAX); + 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); + 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) => ( - + ))} ); From b4746f97b51da1a467414c170d7c10151555315b Mon Sep 17 00:00:00 2001 From: Sankhesh Jhaveri Date: Fri, 26 May 2023 13:16:28 -0400 Subject: [PATCH 4/5] fix(ResliceRepresentation): Ensure that the slice function is set --- src/core/ResliceRepresentation.js | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/core/ResliceRepresentation.js b/src/core/ResliceRepresentation.js index 20ad2af..626a80a 100644 --- a/src/core/ResliceRepresentation.js +++ b/src/core/ResliceRepresentation.js @@ -1,8 +1,9 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { ViewContext, RepresentationContext, DownstreamContext } from './View'; 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'; @@ -70,17 +71,19 @@ export default class ResliceRepresentation extends vtkSliceRepresentation { slabTrapezoidIntegration, } = props; let changed = false; - if (slicePlane && (!previous || slicePlane !== previous.slicePlane)) { - changed = this.slicePlane.set(slicePlane) || changed; + if (!previous || slicePlane !== previous.slicePlane) { + changed = this.mapper.setSlicePlane(slicePlane); } - if ( - slicePolyData && - (!previous || slicePolyData !== previous.slicePolyData) - ) { - changed = this.slicePolyData.set(slicePolyData) || changed; + if (!previous || slicePolyData !== previous.slicePolyData) { + changed = this.mapper.setSlicePolyData(slicePolyData); } if (this.validData) { - if (slabType != null && (!previous || slabType !== previous.slabType)) { + if ( + slabType != null && + (!previous || slabType !== previous.slabType) && + slabType >= SlabTypes.MIN && + slabType <= SlabTypes.SUM + ) { changed = this.mapper.setSlabType(slabType); } if ( @@ -108,6 +111,12 @@ export default class ResliceRepresentation extends vtkSliceRepresentation { } } +ResliceRepresentation.defaultProps = { + sliceThickness: 0.0, + slabType: SlabTypes.MEAN, + slabTrapezoidIntegration: false, +}; + ResliceRepresentation.propTypes = { /** * Slice plane @@ -122,7 +131,7 @@ ResliceRepresentation.propTypes = { /** * Slab type */ - slabType: PropTypes.arrayOf(PropTypes.oneOf(SlabTypes)), + slabType: PropTypes.number, /** * Slab thickness From 46cd8cc4a09312fa96514bb3d2df2af6c2d6ac99 Mon Sep 17 00:00:00 2001 From: Sankhesh Jhaveri Date: Fri, 26 May 2023 13:17:17 -0400 Subject: [PATCH 5/5] test(ResliceRepresentation): Example for switchable slice function --- usage/src/Volume/ResliceRendering.jsx | 176 +++++++++++++++++++------- 1 file changed, 130 insertions(+), 46 deletions(-) diff --git a/usage/src/Volume/ResliceRendering.jsx b/usage/src/Volume/ResliceRendering.jsx index 4b4a064..5d930f2 100644 --- a/usage/src/Volume/ResliceRendering.jsx +++ b/usage/src/Volume/ResliceRendering.jsx @@ -1,6 +1,9 @@ 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, @@ -12,6 +15,18 @@ import { 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) => { @@ -50,16 +65,13 @@ function Slider(props) { function DropDown(props) { const view = useContext(Contexts.ViewContext); - console.log(props.options); function onChange(e) { const value = e.currentTarget.value; props.setValue(value); setTimeout(view.renderView, 0); } return ( - + {props.label} + + ); } function EnumDropDown(props) { const view = useContext(Contexts.ViewContext); function onChange(e) { - const value = e.currentTarget.value; + const value = parseInt(e.currentTarget.value); props.setValue(value); setTimeout(view.renderView, 0); } @@ -103,8 +126,6 @@ function EnumDropDown(props) { style={{ position: 'sticky', zIndex: 100, - // left: '15px', - // top: '5px', ...props.style, }} > @@ -153,18 +174,73 @@ function CheckBox(props) { ); } +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 [iSlice, setISlice] = useState(128); - const [jSlice, setJSlice] = useState(128); - const [kSlice, setKSlice] = useState(47); const [slabThickness, setSlabThickness] = useState(0); const [slabType, setSlabType] = useState(SlabTypes.MAX); - const [slabTrapezoidIntegration, setSlabTrapezoidIntegration] = useState(false); + 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 (
@@ -173,7 +249,7 @@ function Example(props) { cameraPosition={[1, 0, 0]} cameraViewUp={[0, 0, -1]} cameraParallelProjection={false} - background={[1, 1, 1]} + background={[0.34, 0.35, 0.34]} > - - - + + - +