From 9f418a2a3d04019e47f32213d9f5114eb4f13a1a Mon Sep 17 00:00:00 2001 From: Alireza Date: Fri, 28 Oct 2022 14:53:27 -0400 Subject: [PATCH 1/3] fix: flip based on the camera not actor user matrix --- packages/core/src/RenderingEngine/Viewport.ts | 107 +++++++----------- 1 file changed, 40 insertions(+), 67 deletions(-) diff --git a/packages/core/src/RenderingEngine/Viewport.ts b/packages/core/src/RenderingEngine/Viewport.ts index 5ca231709a..2327ed35df 100644 --- a/packages/core/src/RenderingEngine/Viewport.ts +++ b/packages/core/src/RenderingEngine/Viewport.ts @@ -230,82 +230,55 @@ class Viewport implements IViewport { return; } - // In Cornerstone gpu rendering pipeline, the images are positioned - // in the space according to their origin, and direction (even StackViewport - // with one slice only). In order to flip the images, we need to flip them - // around their center axis (either horizontal or vertical). Since the images - // are positioned in the space according to their origin and direction, for a - // proper scaling (flipping), they should be transformed to the origin and - // then flipped. The following code does this transformation. - - const origin = imageData.getOrigin(); - const direction = imageData.getDirection(); - const spacing = imageData.getSpacing(); - const size = imageData.getDimensions(); - - const iVector = direction.slice(0, 3); - const jVector = direction.slice(3, 6); - const kVector = direction.slice(6, 9); - - // finding the center of the image - const center = vec3.create(); - vec3.scaleAndAdd(center, origin, iVector, (size[0] / 2.0) * spacing[0]); - vec3.scaleAndAdd(center, center, jVector, (size[1] / 2.0) * spacing[1]); - vec3.scaleAndAdd(center, center, kVector, (size[2] / 2.0) * spacing[2]); - - let flipHTx, flipVTx; - - const transformToOriginTx = vtkMatrixBuilder - .buildFromRadian() - .identity() - .translate(center[0], center[1], center[2]) - .rotateFromDirections(jVector, [0, 1, 0]) - .rotateFromDirections(iVector, [1, 0, 0]); - - const transformBackFromOriginTx = vtkMatrixBuilder - .buildFromRadian() - .identity() - .rotateFromDirections([1, 0, 0], iVector) - .rotateFromDirections([0, 1, 0], jVector) - .translate(-center[0], -center[1], -center[2]); + const { viewPlaneNormal, viewUp, focalPoint, position } = this.getCamera(); - if (flipH) { - this.flipHorizontal = flipHorizontal; - flipHTx = vtkMatrixBuilder - .buildFromRadian() - .multiply(transformToOriginTx.getMatrix()) - .scale(-1, 1, 1) - .multiply(transformBackFromOriginTx.getMatrix()); - } + const viewRight = vec3.create(); + vec3.cross(viewRight, viewPlaneNormal, viewUp); - if (flipV) { - this.flipVertical = flipVertical; - flipVTx = vtkMatrixBuilder - .buildFromRadian() - .multiply(transformToOriginTx.getMatrix()) - .scale(1, -1, 1) - .multiply(transformBackFromOriginTx.getMatrix()); - } + let viewUpToSet = vec3.create(); + vec3.copy(viewUpToSet, viewUp); - const actorEntries = this.getActors(); + let viewPlaneNormalToSet = vec3.create(); + viewPlaneNormalToSet = vec3.negate(viewPlaneNormalToSet, viewPlaneNormal); - actorEntries.forEach((actorEntry) => { - const actor = actorEntry.actor; + const positionToSet = vec3.create(); - const mat = actor.getUserMatrix(); + // for both flip horizontal and vertical we need to move the camera to the + // other side of the image + const distance = vec3.distance(position, focalPoint); - if (flipHTx) { - mat4.multiply(mat, mat, flipHTx.getMatrix()); - } + vec3.scaleAndAdd( + positionToSet, + position, + viewPlaneNormalToSet, + 2 * distance + ); - if (flipVTx) { - mat4.multiply(mat, mat, flipVTx.getMatrix()); - } + // Flipping horizontal mean that the camera should move + // to the other side of the image but looking at the + // same direction and same focal point + if (flipH) { + this.setCamera({ + viewPlaneNormal: viewPlaneNormalToSet as Point3, + position: positionToSet as Point3, + focalPoint, + }); + } - actor.setUserMatrix(mat); - }); + // Flipping vertical mean that the camera should negate the view up + // and also move to the other side of the image but looking at the + if (flipV) { + viewUpToSet = vec3.negate(viewUpToSet, viewUp); + + this.setCamera({ + focalPoint, + viewPlaneNormal: viewPlaneNormalToSet as Point3, + viewUp: viewUpToSet as Point3, + position: positionToSet as Point3, + }); + } - this.getRenderingEngine().render(); + this.render(); } private getDefaultImageData(): any { From 902adde833467854624a420917bfc6492bc89670 Mon Sep 17 00:00:00 2001 From: Alireza Date: Fri, 28 Oct 2022 19:06:06 -0400 Subject: [PATCH 2/3] fix: fix the panned image flip --- packages/core/src/RenderingEngine/Viewport.ts | 80 ++++++++++++++++--- 1 file changed, 68 insertions(+), 12 deletions(-) diff --git a/packages/core/src/RenderingEngine/Viewport.ts b/packages/core/src/RenderingEngine/Viewport.ts index 2327ed35df..de3e52ff3b 100644 --- a/packages/core/src/RenderingEngine/Viewport.ts +++ b/packages/core/src/RenderingEngine/Viewport.ts @@ -241,27 +241,67 @@ class Viewport implements IViewport { let viewPlaneNormalToSet = vec3.create(); viewPlaneNormalToSet = vec3.negate(viewPlaneNormalToSet, viewPlaneNormal); - const positionToSet = vec3.create(); - // for both flip horizontal and vertical we need to move the camera to the // other side of the image const distance = vec3.distance(position, focalPoint); - vec3.scaleAndAdd( - positionToSet, - position, - viewPlaneNormalToSet, - 2 * distance - ); + // If the pan has been applied, we need to be able + // apply the pan back + const resetFocalPoint = vec3.create(); + const dimensions = imageData.getDimensions(); + const middleIJK = dimensions.map((d) => Math.floor(d / 2)); + + const idx = [middleIJK[0], middleIJK[1], middleIJK[2]]; + imageData.indexToWorld(idx, resetFocalPoint); + + // what is the difference right now between the rested focal point and + // the current focal point + // Todo: this needs to be retrieved from the function that considers maintainFrame + // just now trying it on stack Viewport + const panDir = vec3.create(); + vec3.subtract(panDir, focalPoint, resetFocalPoint); + + const panValue = vec3.length(panDir); + + const getPanDir = (mirrorVec) => { + const panDirMirror = vec3.create(); + vec3.scale(panDirMirror, mirrorVec, 2 * vec3.dot(panDir, mirrorVec)); + vec3.subtract(panDirMirror, panDirMirror, panDir); + vec3.normalize(panDirMirror, panDirMirror); + + return panDirMirror; + }; // Flipping horizontal mean that the camera should move // to the other side of the image but looking at the // same direction and same focal point if (flipH) { + // we need to apply the pan value to the new focal point but in the direction + // that is mirrored on the viewUp for the flip horizontal and + // viewRight for the flip vertical + const newFocalPoint = vec3.create(); + + // mirror the pan direction based on the viewUp + const panDirMirror = getPanDir(viewUpToSet); + + // move focal point from the resetFocalPoint to the newFocalPoint + // based on the panDirMirror and panValue + vec3.scaleAndAdd(newFocalPoint, resetFocalPoint, panDirMirror, panValue); + + // move the camera position also the same way as the focal point + const newPosition = vec3.create(); + + vec3.scaleAndAdd( + newPosition, + newFocalPoint, + viewPlaneNormalToSet, + distance + ); + this.setCamera({ viewPlaneNormal: viewPlaneNormalToSet as Point3, - position: positionToSet as Point3, - focalPoint, + position: newPosition as Point3, + focalPoint: newFocalPoint as Point3, }); } @@ -270,11 +310,27 @@ class Viewport implements IViewport { if (flipV) { viewUpToSet = vec3.negate(viewUpToSet, viewUp); + // we need to apply the pan value to the new focal point but in the direction + const panDirMirror = getPanDir(viewRight); + + const newFocalPoint = vec3.create(); + + vec3.scaleAndAdd(newFocalPoint, resetFocalPoint, panDirMirror, panValue); + + const newPosition = vec3.create(); + + vec3.scaleAndAdd( + newPosition, + newFocalPoint, + viewPlaneNormalToSet, + distance + ); + this.setCamera({ - focalPoint, + focalPoint: newFocalPoint as Point3, viewPlaneNormal: viewPlaneNormalToSet as Point3, viewUp: viewUpToSet as Point3, - position: positionToSet as Point3, + position: newPosition as Point3, }); } From 2bb066a6aa9be0125fcbd7ccf52d1238fb09d868 Mon Sep 17 00:00:00 2001 From: Alireza Date: Mon, 31 Oct 2022 19:59:33 -0400 Subject: [PATCH 3/3] fix broken test --- packages/core/test/stackViewport_gpu_render_test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/core/test/stackViewport_gpu_render_test.js b/packages/core/test/stackViewport_gpu_render_test.js index a245958119..51ca62c525 100644 --- a/packages/core/test/stackViewport_gpu_render_test.js +++ b/packages/core/test/stackViewport_gpu_render_test.js @@ -946,7 +946,7 @@ describe('renderingCore -- Stack', () => { } }); - it('Should be able to flip a stack viewport horizontally and rotate it', function (done) { + it('Should be able to flip a stack viewport vertically and rotate it', function (done) { const element = createViewport(this.renderingEngine, AXIAL, 256, 256); this.DOMElements.push(element); @@ -971,9 +971,9 @@ describe('renderingCore -- Stack', () => { rotation: 90, }); - vp.setCamera({ flipHorizontal: true }); - vp.render(); + + vp.setCamera({ flipVertical: true }); }); } catch (e) { done.fail(e);