Skip to content

Commit

Permalink
fix(croppingPlanes): use signs of direction vectors
Browse files Browse the repository at this point in the history
When the direction vectors of an image "mirror" the spacing,
the image cropping planes were outside the image.
  • Loading branch information
PaulHax committed May 18, 2023
1 parent e44b60f commit e4324ca
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 43 deletions.
37 changes: 1 addition & 36 deletions src/IO/MultiscaleSpatialImage.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import WebworkerPromise from 'webworker-promise'
import { chunkArray, CXYZT, ensuredDims, orderBy } from './dimensionUtils'
import { getDtype } from './dtypeUtils'
import { transformBounds } from '../transformBounds'
import { makeIndexToWorld } from '../internalUtils'

const imageDataFromChunksWorker = new Worker(
new URL('./ImageDataFromChunks.worker.js', import.meta.url),
Expand Down Expand Up @@ -96,42 +97,6 @@ export const ensure3dDirection = d => {
return [d[0], d[1], 0, d[2], d[3], 0, 0, 0, 1]
}

const makeMat4 = ({ direction, origin, spacing }) => {
const mat = mat4.create()
mat4.fromTranslation(mat, origin)

mat[0] = direction[0]
mat[1] = direction[1]
mat[2] = direction[2]
mat[4] = direction[3]
mat[5] = direction[4]
mat[6] = direction[5]
mat[8] = direction[6]
mat[9] = direction[7]
mat[10] = direction[8]

return mat4.scale(mat, mat, spacing)
}

const makeIndexToWorld = ({ direction: inDirection, origin, spacing }) => {
// ITK (and VTKMath) uses row-major index axis, but gl-matrix uses column-major. Transpose.
const DIMENSIONS = 3
const direction = Array(inDirection.length)
for (let idx = 0; idx < DIMENSIONS; ++idx) {
for (let col = 0; col < DIMENSIONS; ++col) {
direction[col + idx * 3] = inDirection[idx + col * DIMENSIONS]
}
}

const origin3d = [...origin]
if (origin3d[2] === undefined) origin3d[2] = 0

const spacing3d = [...spacing]
if (spacing3d[2] === undefined) spacing3d[2] = 1

return makeMat4({ direction, origin: origin3d, spacing: spacing3d })
}

export const worldBoundsToIndexBounds = ({
bounds,
fullIndexBounds,
Expand Down
15 changes: 8 additions & 7 deletions src/Rendering/VTKJS/Main/croppingPlanes.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { mat4, vec3, quat } from 'gl-matrix'
import { mat4, vec3, quat, vec4 } from 'gl-matrix'
import vtkImageData from 'vtk.js/Sources/Common/DataModel/ImageData'
import { transformVec3 } from 'vtk.js/Sources/Widgets/Widgets3D/ImageCroppingWidget/helpers'
import vtkMath from 'vtk.js/Sources/Common/Core/Math'
Expand All @@ -8,7 +8,7 @@ import vtkBoundingBox from 'vtk.js/Sources/Common/DataModel/BoundingBox'
import toggleCroppingPlanes from './toggleCroppingPlanes'
import HandlesInPixelsImageCroppingWidget from '../Widgets/HandlesInPixelsImageCroppingWidget'
import { transformBounds } from '../../../transformBounds'
import { arraysEqual } from '../../../internalUtils'
import { arraysEqual, makeIndexToWorld } from '../../../internalUtils'

export function getCropWidgetBounds(context, bounds = []) {
const { croppingWidget } = context.main
Expand Down Expand Up @@ -176,11 +176,12 @@ export function updateCroppingParameters(context) {
if (uninitialized) return

// Put global bounds in image oriented space
const orientation = quat.fromMat3([], croppingVirtualImage.getDirection())
const worldToImageDirection = mat4.fromQuat(
[],
quat.invert(orientation, orientation)
)

const worldToImageDirection = makeIndexToWorld({
direction: croppingVirtualImage.getDirection(),
origin: [0, 0, 0],
spacing: [1, 1, 1],
})

const orientedBox = transformBounds(
worldToImageDirection,
Expand Down
42 changes: 42 additions & 0 deletions src/internalUtils.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { mat4 } from 'gl-matrix'

export function arraysEqual(a, b) {
if (a === b) return true
if (a == null || b == null) return false
Expand All @@ -7,3 +9,43 @@ export function arraysEqual(a, b) {
}
return true
}

const makeMat4 = ({ direction, origin, spacing }) => {
const mat = mat4.create()
mat4.fromTranslation(mat, origin)

mat[0] = direction[0]
mat[1] = direction[1]
mat[2] = direction[2]
mat[4] = direction[3]
mat[5] = direction[4]
mat[6] = direction[5]
mat[8] = direction[6]
mat[9] = direction[7]
mat[10] = direction[8]

return mat4.scale(mat, mat, spacing)
}

export const makeIndexToWorld = ({
direction: inDirection,
origin,
spacing,
}) => {
// ITK (and VTKMath) uses row-major index axis, but gl-matrix uses column-major. Transpose.
const DIMENSIONS = 3
const direction = Array(inDirection.length)
for (let idx = 0; idx < DIMENSIONS; ++idx) {
for (let col = 0; col < DIMENSIONS; ++col) {
direction[col + idx * 3] = inDirection[idx + col * DIMENSIONS]
}
}

const origin3d = [...origin]
if (origin3d[2] === undefined) origin3d[2] = 0

const spacing3d = [...spacing]
if (spacing3d[2] === undefined) spacing3d[2] = 1

return makeMat4({ direction, origin: origin3d, spacing: spacing3d })
}

0 comments on commit e4324ca

Please sign in to comment.