From fb2bd200743fc288e5b1e8b4f4e744eba0fcaa1a Mon Sep 17 00:00:00 2001 From: LinkunGao Date: Wed, 22 Nov 2023 14:37:42 +1300 Subject: [PATCH 1/3] Fix bugs on zoom, sphere and crosshair --- docs/source/conf.py | 2 +- docs/source/release/release.md | 14 +++ src/Utils/segmentation/DrawToolCore.ts | 160 +++++++++++++++++++++--- src/Utils/segmentation/NrrdTools.ts | 116 +---------------- src/Utils/segmentation/coreTools/gui.ts | 16 +-- src/index.ts | 4 +- 6 files changed, 177 insertions(+), 135 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index f081b4c..3618d38 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -23,7 +23,7 @@ # The full version, including alpha/beta/rc tags -release = 'v2.0.5' +release = 'v2.0.6' diff --git a/docs/source/release/release.md b/docs/source/release/release.md index 9a2c34e..348a51e 100644 --- a/docs/source/release/release.md +++ b/docs/source/release/release.md @@ -1933,3 +1933,17 @@ Huge update: ## Release v2.0.2 Fixed cursor not switch issue when user click eraser and pencil buttons. + +## Release v2.0.5 + +- fix sphere function bugs +- solve the zoom function bugs + +## Release v2.0.6 + +- fix Zoom affect sphere origin functions +- update sphere origin and radius export + - sphere origin and radius exports are based on sizeFactor:1. +- Fix sphere and crosshair function + - all based on sizeFactor:1 + - after zoom, scale them. diff --git a/src/Utils/segmentation/DrawToolCore.ts b/src/Utils/segmentation/DrawToolCore.ts index c9cc3fa..6629d63 100644 --- a/src/Utils/segmentation/DrawToolCore.ts +++ b/src/Utils/segmentation/DrawToolCore.ts @@ -273,10 +273,16 @@ export class DrawToolCore extends CommToolsData { e.offsetX / this.nrrd_states.sizeFoctor; this.nrrd_states.cursorPageY = e.offsetY / this.nrrd_states.sizeFoctor; + this.enableCrosshair(); - } else if (this.gui_states.sphere) { - let mouseX = e.offsetX; - let mouseY = e.offsetY; + + } else if (this.gui_states.sphere && !this.nrrd_states.enableCursorChoose) { + this.protectedData.canvases.drawingCanvas.removeEventListener( + "wheel", + this.drawingPrameters.handleZoomWheel + ); + let mouseX = e.offsetX / this.nrrd_states.sizeFoctor; + let mouseY = e.offsetY / this.nrrd_states.sizeFoctor; // record mouseX,Y, and enable crosshair function this.nrrd_states.sphereOrigin[this.protectedData.axis] = [ @@ -290,7 +296,7 @@ export class DrawToolCore extends CommToolsData { this.enableCrosshair(); // draw circle setup width/height for sphere canvas - this.drawSphere(mouseX, mouseY, this.nrrd_states.sphereRadius); + this.drawSphere(e.offsetX , e.offsetY, this.nrrd_states.sphereRadius); this.protectedData.canvases.drawingCanvas.addEventListener( "wheel", this.drawingPrameters.handleSphereWheel, @@ -485,17 +491,28 @@ export class DrawToolCore extends CommToolsData { } !!this.nrrd_states.getSphere && - this.nrrd_states.getSphere( - this.nrrd_states.sphereOrigin.z, - this.nrrd_states.sphereRadius - ); + this.nrrd_states.getSphere( + this.nrrd_states.sphereOrigin.z, + this.nrrd_states.sphereRadius / this.nrrd_states.sizeFoctor + ); + + this.protectedData.canvases.drawingCanvas.addEventListener( + "wheel", + this.drawingPrameters.handleZoomWheel + ); this.protectedData.canvases.drawingCanvas.removeEventListener( "wheel", this.drawingPrameters.handleSphereWheel, true ); - } + } else if(this.gui_states.sphere && + this.nrrd_states.enableCursorChoose){ + this.protectedData.canvases.drawingCanvas.addEventListener( + "wheel", + this.drawingPrameters.handleZoomWheel + ); + } } else if (e.button === 2) { rightclicked = false; this.protectedData.canvases.drawingCanvas.style.cursor = "grab"; @@ -891,6 +908,7 @@ export class DrawToolCore extends CommToolsData { const mouseX = this.nrrd_states.sphereOrigin[axis][0]; const mouseY = this.nrrd_states.sphereOrigin[axis][1]; + const originIndex = this.nrrd_states.sphereOrigin[axis][2]; const preIndex = originIndex - decay; const nextIndex = originIndex + decay; @@ -902,14 +920,15 @@ export class DrawToolCore extends CommToolsData { // ) // return; if (preIndex === nextIndex) { - this.drawSphereCore(ctx, mouseX, mouseY, this.nrrd_states.sphereRadius); + this.drawSphereCore(ctx, mouseX, mouseY, this.nrrd_states.sphereRadius / this.nrrd_states.sizeFoctor); + this.drawSphereCore(ctx, mouseX, mouseY, this.nrrd_states.sphereRadius / this.nrrd_states.sizeFoctor); this.storeSphereImages(preIndex, axis); } else { this.drawSphereCore( ctx, mouseX, mouseY, - this.nrrd_states.sphereRadius - decay + (this.nrrd_states.sphereRadius - decay) / this.nrrd_states.sizeFoctor ); this.drawImageOnEmptyImage(canvas); this.storeSphereImages(preIndex, axis); @@ -925,7 +944,7 @@ export class DrawToolCore extends CommToolsData { radius: number ) { ctx.beginPath(); - ctx.arc(x, y, radius * this.nrrd_states.sizeFoctor, 0, 2 * Math.PI); + ctx.arc(x, y, radius, 0, 2 * Math.PI); ctx.fillStyle = this.gui_states.fillColor; ctx.fill(); ctx.closePath(); @@ -969,8 +988,8 @@ export class DrawToolCore extends CommToolsData { Math.min(this.nrrd_states.sphereRadius, 50) ); // get mouse position - const mouseX = this.nrrd_states.sphereOrigin[this.protectedData.axis][0]; - const mouseY = this.nrrd_states.sphereOrigin[this.protectedData.axis][1]; + const mouseX = this.nrrd_states.sphereOrigin[this.protectedData.axis][0] * this.nrrd_states.sizeFoctor; + const mouseY = this.nrrd_states.sphereOrigin[this.protectedData.axis][1] * this.nrrd_states.sizeFoctor; this.drawSphere(mouseX, mouseY, this.nrrd_states.sphereRadius); }; return sphereEvent; @@ -1000,7 +1019,118 @@ export class DrawToolCore extends CommToolsData { ); } + /** + * We generate the MRI slice from threejs based on mm, but when we display it is based on pixel size/distance. + * So, the index munber on each axis (sagittal, axial, coronal) is the slice's depth in mm distance. And the width and height displayed on screen is the slice's width and height in pixel distance. + * + * When we switch into different axis' views, we need to convert current view's the depth to the pixel distance in other views width or height, and convert the current view's width or height from pixel distance to mm distance as other views' depth (slice index) in general. + * + * Then as for the crosshair (Cursor Inspector), we also need to convert the cursor point (x, y, z) to other views' (x, y, z). + * + * @param from "x" | "y" | "z", current view axis, "x: sagittle, y: coronal, z: axial". + * @param to "x" | "y" | "z", target view axis (where you want jump to), "x: sagittle, y: coronal, z: axial". + * @param cursorNumX number, cursor point x on current axis's slice. (pixel distance) + * @param cursorNumY number, cursor point y on current axis's slice. (pixel distance) + * @param currentSliceIndex number, current axis's slice's index/depth. (mm distance) + * @returns + */ + convertCursorPoint( + from: "x" | "y" | "z", + to: "x" | "y" | "z", + cursorNumX: number, + cursorNumY: number, + currentSliceIndex: number + ) { + + const nrrd = this.nrrd_states; + const dimensions = nrrd.dimensions; + const ratios = nrrd.ratios; + const { nrrd_x_mm, nrrd_y_mm, nrrd_z_mm } = nrrd; + + let currentIndex = 0; + let oldIndex = 0; + let convertCursorNumX = 0; + let convertCursorNumY = 0; + + const convertIndex = { + x: { + y: (val: number) => Math.ceil((val / nrrd_x_mm) * dimensions[0]), + z: (val: number) => Math.ceil((val / nrrd_z_mm) * dimensions[2]), + }, + y: { + x: (val: number) => Math.ceil((val / nrrd_y_mm) * dimensions[1]), + z: (val: number) => Math.ceil((val / nrrd_z_mm) * dimensions[2]), + }, + z: { + x: (val: number) => Math.ceil((val / nrrd_x_mm) * dimensions[0]), + y: (val: number) => Math.ceil((val / nrrd_y_mm) * dimensions[1]), + }, + }; + + + const convertCursor = { + x: { + y: (sliceIndex: number) => + Math.ceil((sliceIndex / dimensions[0]) * nrrd_x_mm), + z: (sliceIndex: number) => + Math.ceil((sliceIndex / dimensions[0]) * nrrd_x_mm), + }, + y: { + x: (sliceIndex: number) => + Math.ceil((sliceIndex / dimensions[1]) * nrrd_y_mm), + z: (sliceIndex: number) => + Math.ceil((sliceIndex / dimensions[1]) * nrrd_y_mm), + }, + z: { + x: (sliceIndex: number) => + Math.ceil((sliceIndex / dimensions[2]) * nrrd_z_mm), + y: (sliceIndex: number) => + Math.ceil((sliceIndex / dimensions[2]) * nrrd_z_mm), + }, + }; + + if (from === to) { + return; + } + if (from === "z" && to === "x") { + currentIndex = convertIndex[from][to](cursorNumX); + oldIndex = currentIndex * ratios[to]; + convertCursorNumX = convertCursor[from][to](currentSliceIndex); + convertCursorNumY = cursorNumY; + } else if (from === "y" && to === "x") { + currentIndex = convertIndex[from][to](cursorNumX); + oldIndex = currentIndex * ratios.x; + convertCursorNumY = convertCursor[from][to](currentSliceIndex); + convertCursorNumX = cursorNumY; + } else if (from === "z" && to === "y") { + currentIndex = convertIndex[from][to](cursorNumY); + oldIndex = currentIndex * ratios[to]; + convertCursorNumY = convertCursor[from][to](currentSliceIndex); + convertCursorNumX = cursorNumX; + } else if (from === "x" && to === "y") { + currentIndex = convertIndex[from][to](cursorNumY); + oldIndex = currentIndex * ratios[to]; + convertCursorNumX = convertCursor[from][to](currentSliceIndex); + convertCursorNumY = cursorNumX; + } else if (from === "x" && to === "z") { + currentIndex = convertIndex[from][to](cursorNumX); + oldIndex = currentIndex * ratios[to]; + convertCursorNumX = convertCursor[from][to](currentSliceIndex); + convertCursorNumY = cursorNumY; + } else if (from === "y" && to === "z") { + currentIndex = convertIndex[from][to](cursorNumY); + oldIndex = currentIndex * ratios.z; + convertCursorNumY = convertCursor[from][to](currentSliceIndex); + convertCursorNumX = cursorNumX; + } else { + return; + } + + return { currentIndex, oldIndex, convertCursorNumX, convertCursorNumY }; + } + private setUpSphereOrigins(mouseX: number, mouseY: number) { + const convertCursor = (from: "x" | "y" | "z", to: "x" | "y" | "z") => { const convertObj = this.convertCursorPoint( from, @@ -1009,6 +1139,7 @@ export class DrawToolCore extends CommToolsData { mouseY, this.nrrd_states.currentIndex ) as IConvertObjType; + return { convertCursorNumX: convertObj?.convertCursorNumX, convertCursorNumY: convertObj?.convertCursorNumY, @@ -1026,6 +1157,7 @@ export class DrawToolCore extends CommToolsData { axisTo1: "x" | "y" | "z"; axisTo2: "x" | "y" | "z"; }; + this.nrrd_states.sphereOrigin[axisTo1] = [ convertCursor(this.protectedData.axis, axisTo1).convertCursorNumX, convertCursor(this.protectedData.axis, axisTo1).convertCursorNumY, diff --git a/src/Utils/segmentation/NrrdTools.ts b/src/Utils/segmentation/NrrdTools.ts index 0d6babe..25273b9 100644 --- a/src/Utils/segmentation/NrrdTools.ts +++ b/src/Utils/segmentation/NrrdTools.ts @@ -413,120 +413,13 @@ export class NrrdTools extends DrawToolCore { } } - /** - * We generate the MRI slice from threejs based on mm, but when we display it is based on pixel size/distance. - * So, the index munber on each axis (sagittal, axial, coronal) is the slice's depth in mm distance. And the width and height displayed on screen is the slice's width and height in pixel distance. - * - * When we switch into different axis' views, we need to convert current view's the depth to the pixel distance in other views width or height, and convert the current view's width or height from pixel distance to mm distance as other views' depth (slice index) in general. - * - * Then as for the crosshair (Cursor Inspector), we also need to convert the cursor point (x, y, z) to other views' (x, y, z). - * - * @param from "x" | "y" | "z", current view axis, "x: sagittle, y: coronal, z: axial". - * @param to "x" | "y" | "z", target view axis (where you want jump to), "x: sagittle, y: coronal, z: axial". - * @param cursorNumX number, cursor point x on current axis's slice. (pixel distance) - * @param cursorNumY number, cursor point y on current axis's slice. (pixel distance) - * @param currentSliceIndex number, current axis's slice's index/depth. (mm distance) - * @returns - */ - convertCursorPoint( - from: "x" | "y" | "z", - to: "x" | "y" | "z", - cursorNumX: number, - cursorNumY: number, - currentSliceIndex: number - ) { - const nrrd = this.nrrd_states; - const dimensions = nrrd.dimensions; - const ratios = nrrd.ratios; - const { nrrd_x_mm, nrrd_y_mm, nrrd_z_mm } = nrrd; - - let currentIndex = 0; - let oldIndex = 0; - let convertCursorNumX = 0; - let convertCursorNumY = 0; - - const convertIndex = { - x: { - y: (val: number) => Math.ceil((val / nrrd_x_mm) * dimensions[0]), - z: (val: number) => Math.ceil((val / nrrd_z_mm) * dimensions[2]), - }, - y: { - x: (val: number) => Math.ceil((val / nrrd_y_mm) * dimensions[1]), - z: (val: number) => Math.ceil((val / nrrd_z_mm) * dimensions[2]), - }, - z: { - x: (val: number) => Math.ceil((val / nrrd_x_mm) * dimensions[0]), - y: (val: number) => Math.ceil((val / nrrd_y_mm) * dimensions[1]), - }, - }; - - const convertCursor = { - x: { - y: (sliceIndex: number) => - Math.ceil((sliceIndex / dimensions[0]) * nrrd_x_mm), - z: (sliceIndex: number) => - Math.ceil((sliceIndex / dimensions[0]) * nrrd_x_mm), - }, - y: { - x: (sliceIndex: number) => - Math.ceil((sliceIndex / dimensions[1]) * nrrd_y_mm), - z: (sliceIndex: number) => - Math.ceil((sliceIndex / dimensions[1]) * nrrd_y_mm), - }, - z: { - x: (sliceIndex: number) => - Math.ceil((sliceIndex / dimensions[2]) * nrrd_z_mm), - y: (sliceIndex: number) => - Math.ceil((sliceIndex / dimensions[2]) * nrrd_z_mm), - }, - }; - - if (from === to) { - return; - } - if (from === "z" && to === "x") { - currentIndex = convertIndex[from][to](cursorNumX); - oldIndex = currentIndex * ratios[to]; - convertCursorNumX = convertCursor[from][to](currentSliceIndex); - convertCursorNumY = cursorNumY; - } else if (from === "y" && to === "x") { - currentIndex = convertIndex[from][to](cursorNumX); - oldIndex = currentIndex * ratios.x; - convertCursorNumY = convertCursor[from][to](currentSliceIndex); - convertCursorNumX = cursorNumY; - } else if (from === "z" && to === "y") { - currentIndex = convertIndex[from][to](cursorNumY); - oldIndex = currentIndex * ratios[to]; - convertCursorNumY = convertCursor[from][to](currentSliceIndex); - convertCursorNumX = cursorNumX; - } else if (from === "x" && to === "y") { - currentIndex = convertIndex[from][to](cursorNumY); - oldIndex = currentIndex * ratios[to]; - convertCursorNumX = convertCursor[from][to](currentSliceIndex); - convertCursorNumY = cursorNumX; - } else if (from === "x" && to === "z") { - currentIndex = convertIndex[from][to](cursorNumX); - oldIndex = currentIndex * ratios[to]; - convertCursorNumX = convertCursor[from][to](currentSliceIndex); - convertCursorNumY = cursorNumY; - } else if (from === "y" && to === "z") { - currentIndex = convertIndex[from][to](cursorNumY); - oldIndex = currentIndex * ratios.z; - convertCursorNumY = convertCursor[from][to](currentSliceIndex); - convertCursorNumX = cursorNumX; - } else { - return; - } - - return { currentIndex, oldIndex, convertCursorNumX, convertCursorNumY }; - } - /** * Switch all contrast slices' orientation * @param {string} aixs:"x" | "y" | "z" * */ setSliceOrientation(axisTo: "x" | "y" | "z") { let convetObj; + if (this.nrrd_states.enableCursorChoose || this.gui_states.sphere) { if (this.protectedData.axis === "z") { this.cursorPage.z.index = this.nrrd_states.currentIndex; @@ -573,6 +466,7 @@ export class NrrdTools extends DrawToolCore { } } else if (axisTo === "x") { if (this.nrrd_states.isCursorSelect && !this.cursorPage.x.updated) { + if (this.protectedData.axis === "z") { // convert z to x convetObj = this.convertCursorPoint( @@ -583,6 +477,7 @@ export class NrrdTools extends DrawToolCore { this.cursorPage.z.index ); } + if (this.protectedData.axis === "y") { // convert y to x convetObj = this.convertCursorPoint( @@ -639,6 +534,7 @@ export class NrrdTools extends DrawToolCore { this.nrrd_states.oldIndex = convetObj.oldIndex; this.nrrd_states.cursorPageX = convetObj.convertCursorNumX; this.nrrd_states.cursorPageY = convetObj.convertCursorNumY; + convetObj = undefined; switch (axisTo) { case "x": @@ -668,8 +564,8 @@ export class NrrdTools extends DrawToolCore { // for sphere plan a if (this.gui_states.sphere && !this.nrrd_states.spherePlanB) { this.drawSphere( - this.nrrd_states.sphereOrigin[axisTo][0], - this.nrrd_states.sphereOrigin[axisTo][1], + this.nrrd_states.sphereOrigin[axisTo][0] * this.nrrd_states.sizeFoctor, + this.nrrd_states.sphereOrigin[axisTo][1] * this.nrrd_states.sizeFoctor, this.nrrd_states.sphereRadius ); } diff --git a/src/Utils/segmentation/coreTools/gui.ts b/src/Utils/segmentation/coreTools/gui.ts index 1fd0a4a..53dc9b0 100644 --- a/src/Utils/segmentation/coreTools/gui.ts +++ b/src/Utils/segmentation/coreTools/gui.ts @@ -330,16 +330,16 @@ function setupGui(configs: IConfigGUI) { const updateGuiSphereState = () => { if (configs.gui_states.sphere) { - configs.drawingCanvas.removeEventListener( - "wheel", - configs.drawingPrameters.handleZoomWheel - ); + // configs.drawingCanvas.removeEventListener( + // "wheel", + // configs.drawingPrameters.handleZoomWheel + // ); configs.removeDragMode(); } else { - configs.drawingCanvas.addEventListener( - "wheel", - configs.drawingPrameters.handleZoomWheel - ); + // configs.drawingCanvas.addEventListener( + // "wheel", + // configs.drawingPrameters.handleZoomWheel + // ); configs.configDragMode(); // clear canvas diff --git a/src/index.ts b/src/index.ts index ba6693a..a9b9182 100644 --- a/src/index.ts +++ b/src/index.ts @@ -44,10 +44,10 @@ import { IPaintImage } from "./Utils/segmentation/coreTools/coreType"; import "./css/style.css"; -export const REVISION = "v2.0.5"; +export const REVISION = "v2.0.6"; console.log( - "%cCopper3D Visualisation %cBeta:v2.0.5", + "%cCopper3D Visualisation %cBeta:v2.0.6", "padding: 3px;color:white; background:#023047", "padding: 3px;color:white; background:#f50a25" ); From 072be05e8184da6babc2b35523df8c32c6b31569 Mon Sep 17 00:00:00 2001 From: LinkunGao Date: Wed, 22 Nov 2023 14:37:51 +1300 Subject: [PATCH 2/3] 2.0.6 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 765cfa7..213d70a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "copper3d", - "version": "2.0.5", + "version": "2.0.6", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "copper3d", - "version": "2.0.5", + "version": "2.0.6", "license": "Apache-2.0", "dependencies": { "@types/dat.gui": "^0.7.9", diff --git a/package.json b/package.json index ff7ae5d..f4992e2 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "copper3d", "description": "A 3d visualisation package base on threejs provides multiple scenes and Nrrd image load funtion.", - "version": "2.0.5", + "version": "2.0.6", "main": "dist/bundle.umd.js", "moudle": "dist/bundle.esm.js", "types": "dist/types/index.d.ts", From 549a4bc5771a836f0909b1521f5efd4de36aef73 Mon Sep 17 00:00:00 2001 From: LinkunGao Date: Wed, 22 Nov 2023 14:55:15 +1300 Subject: [PATCH 3/3] remove unnecessary codes --- src/Utils/segmentation/DrawToolCore.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/Utils/segmentation/DrawToolCore.ts b/src/Utils/segmentation/DrawToolCore.ts index 6629d63..00471df 100644 --- a/src/Utils/segmentation/DrawToolCore.ts +++ b/src/Utils/segmentation/DrawToolCore.ts @@ -914,13 +914,8 @@ export class DrawToolCore extends CommToolsData { const nextIndex = originIndex + decay; const ctx = this.protectedData.ctxes.drawingSphereCtx; const canvas = this.protectedData.canvases.drawingSphereCanvas; - // if ( - // preIndex < this.nrrd_states.minIndex || - // nextIndex > this.nrrd_states.maxIndex - // ) - // return; + if (preIndex === nextIndex) { - this.drawSphereCore(ctx, mouseX, mouseY, this.nrrd_states.sphereRadius / this.nrrd_states.sizeFoctor); this.drawSphereCore(ctx, mouseX, mouseY, this.nrrd_states.sphereRadius / this.nrrd_states.sizeFoctor); this.storeSphereImages(preIndex, axis); } else {