Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | import { inv, multiply } from 'mathjs';
// TODO -> This is pulled out of some internal logic from Dicom Microscopy Viewer,
// We should likely just expose this there.
export default function coordinateFormatScoord3d2Geometry(coordinates, pyramid) {
let transform = false;
if (!Array.isArray(coordinates[0])) {
coordinates = [coordinates];
transform = true;
}
const metadata = pyramid[pyramid.length - 1];
const orientation = metadata.ImageOrientationSlide;
const spacing = _getPixelSpacing(metadata);
const origin = metadata.TotalPixelMatrixOriginSequence[0];
const offset = [
Number(origin.XOffsetInSlideCoordinateSystem),
Number(origin.YOffsetInSlideCoordinateSystem),
];
coordinates = coordinates.map(c => {
const slideCoord = [c[0], c[1]];
const pixelCoord = mapSlideCoord2PixelCoord({
offset,
orientation,
spacing,
point: slideCoord,
});
return [pixelCoord[0], -(pixelCoord[1] + 1), 0];
});
if (transform) {
return coordinates[0];
}
return coordinates;
}
function _getPixelSpacing(metadata) {
if (metadata.PixelSpacing) {
return metadata.PixelSpacing;
}
const functionalGroup = metadata.SharedFunctionalGroupsSequence[0];
const pixelMeasures = functionalGroup.PixelMeasuresSequence[0];
return pixelMeasures.PixelSpacing;
}
function mapSlideCoord2PixelCoord(options) {
// X and Y Offset in Slide Coordinate System
if (!('offset' in options)) {
throw new Error('Option "offset" is required.');
}
if (!Array.isArray(options.offset)) {
throw new Error('Option "offset" must be an array.');
}
if (options.offset.length !== 2) {
throw new Error('Option "offset" must be an array with 2 elements.');
}
const offset = options.offset;
// Image Orientation Slide with direction cosines for Row and Column direction
if (!('orientation' in options)) {
throw new Error('Option "orientation" is required.');
}
if (!Array.isArray(options.orientation)) {
throw new Error('Option "orientation" must be an array.');
}
if (options.orientation.length !== 6) {
throw new Error('Option "orientation" must be an array with 6 elements.');
}
const orientation = options.orientation;
// Pixel Spacing along the Row and Column direction
if (!('spacing' in options)) {
throw new Error('Option "spacing" is required.');
}
if (!Array.isArray(options.spacing)) {
throw new Error('Option "spacing" must be an array.');
}
if (options.spacing.length !== 2) {
throw new Error('Option "spacing" must be an array with 2 elements.');
}
const spacing = options.spacing;
// X and Y coordinate in the Slide Coordinate System
if (!('point' in options)) {
throw new Error('Option "point" is required.');
}
if (!Array.isArray(options.point)) {
throw new Error('Option "point" must be an array.');
}
if (options.point.length !== 2) {
throw new Error('Option "point" must be an array with 2 elements.');
}
const point = options.point;
const m = [
[orientation[0] * spacing[1], orientation[3] * spacing[0], offset[0]],
[orientation[1] * spacing[1], orientation[4] * spacing[0], offset[1]],
[0, 0, 1],
];
const mInverted = inv(m);
const vSlide = [[point[0]], [point[1]], [1]];
const vImage = multiply(mInverted, vSlide);
const row = Number(vImage[1][0].toFixed(4));
const col = Number(vImage[0][0].toFixed(4));
return [col, row];
}
|