Skip to content

Commit

Permalink
Merge branch 'develop' into feature/EPMUII-8317
Browse files Browse the repository at this point in the history
  • Loading branch information
DanilRostov authored Nov 17, 2023
2 parents 3029c79 + e4cd136 commit 73e38a6
Show file tree
Hide file tree
Showing 32 changed files with 549 additions and 265 deletions.
20 changes: 11 additions & 9 deletions public/sprite.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
115 changes: 98 additions & 17 deletions src/engine/Graphics2d.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class Graphics2d extends React.Component {
this.onMouseUp = this.onMouseUp.bind(this);
this.onMouseMove = this.onMouseMove.bind(this);
this.onMouseWheel = this.onMouseWheel.bind(this);
this.setDataWindow = this.setDataWindow.bind(this);

this.m_sliceRatio = 0.5;
this.m_mode2d = Modes2d.TRANSVERSE;
Expand All @@ -56,11 +57,17 @@ class Graphics2d extends React.Component {
stateMouseDown: false,
xMouse: -1,
yMouse: -1,
startX: 0,
startY: 0,
};

// segm 2d
this.segm2d = new Segm2d(this);
this.m_isSegmented = false;
// data window
this.m_winRight = 1;
this.m_winLeft = 0;
this.m_newWin = false;

// tools2d
this.m_toolPick = new ToolPick(this);
Expand Down Expand Up @@ -103,6 +110,13 @@ class Graphics2d extends React.Component {
return this.m_mount.current.toDataURL();
}

setDataWindow(value) {
const [min, max] = value;
this.m_winLeft = min;
this.m_winRight = max;
this.forceUpdate();
}

prepareImageForRender(volIndexArg) {
//TODO: center the image by click
const objCanvas = this.m_mount.current; // Canvas HTML element reference
Expand All @@ -123,6 +137,11 @@ class Graphics2d extends React.Component {

const store = this.props;
const volSet = store.volumeSet;
const dicom = store.loaderDicom;
if (dicom != null && !this.props.is16bit) {
this.m_winRight = dicom.m_winRight;
this.m_winLeft = dicom.m_winLeft;
}
// const volIndex = this.m_volumeIndex;
const volIndex = volIndexArg !== undefined ? volIndexArg : store.volumeIndex;

Expand All @@ -140,7 +159,10 @@ class Graphics2d extends React.Component {
const yDim = vol.m_yDim;
const zDim = vol.m_zDim;
const xyDim = xDim * yDim;
const dataSrc = vol.m_dataArray; // 1 or 4 bytes array of pixels
let dataSrc = vol.m_dataArray; // 1 or 4 bytes array of pixels
if (dicom != null && this.props.is16bit) {
dataSrc = vol.m_dataArray16; // 2 bytes array of pixels
}
if (dataSrc.length !== xDim * yDim * zDim * vol.m_bytesPerVoxel) {
console.log(`Bad src data len = ${dataSrc.length}, but expect ${xDim}*${yDim}*${zDim}`);
}
Expand Down Expand Up @@ -224,9 +246,16 @@ class Graphics2d extends React.Component {
for (let x = 0; x < wScreen; x++) {
const xSrc = Math.floor(x * xStep);
const val = dataSrc[zOff + yOff + xSrc];
dataDst[j + 0] = val;
dataDst[j + 1] = val;
dataDst[j + 2] = val;
let newVal = val;
if (dicom != null && this.props.is16bit) {
const scale = 255 / ((this.m_winRight - this.m_winLeft) * (dicom.m_maxVal - dicom.m_minVal));
newVal = Math.floor((val - this.m_winLeft * (dicom.m_maxVal - dicom.m_minVal)) * scale);
}
if (newVal < 0) newVal = 0;
if (newVal > 255) newVal = 255;
dataDst[j + 0] = newVal;
dataDst[j + 1] = newVal;
dataDst[j + 2] = newVal;
dataDst[j + 3] = 255; // opacity
j += 4;
} // for (x)
Expand Down Expand Up @@ -309,12 +338,17 @@ class Graphics2d extends React.Component {
const ySrc = Math.floor(x * yStep);
const yOff = ySrc * xDim;
const val = dataSrc[zOff + yOff + xSlice];

dataDst[j + 0] = val;
dataDst[j + 1] = val;
dataDst[j + 2] = val;
let newVal = val;
if (dicom != null) {
const scale = 255 / ((this.m_winRight - this.m_winLeft) * (dicom.m_maxVal - dicom.m_minVal));
newVal = Math.floor((val - this.m_winLeft * (dicom.m_maxVal - dicom.m_minVal)) * scale);
}
if (newVal < 0) newVal = 0;
if (newVal > 255) newVal = 255;
dataDst[j + 0] = newVal;
dataDst[j + 1] = newVal;
dataDst[j + 2] = newVal;
dataDst[j + 3] = 255; // opacity

j += 4;
} // for (x)
} // for (y)
Expand Down Expand Up @@ -398,12 +432,17 @@ class Graphics2d extends React.Component {
for (let x = 0; x < wScreen; x++) {
const xSrc = Math.floor(x * xStep);
const val = dataSrc[zOff + yOff + xSrc];

dataDst[j + 0] = val;
dataDst[j + 1] = val;
dataDst[j + 2] = val;
let newVal = val;
if (dicom != null) {
const scale = 255 / ((this.m_winRight - this.m_winLeft) * (dicom.m_maxVal - dicom.m_minVal));
newVal = Math.floor((val - this.m_winLeft * (dicom.m_maxVal - dicom.m_minVal)) * scale);
}
if (newVal < 0) newVal = 0;
if (newVal > 255) newVal = 255;
dataDst[j + 0] = newVal;
dataDst[j + 1] = newVal;
dataDst[j + 2] = newVal;
dataDst[j + 3] = 255; // opacity

j += 4;
} // for (x)
} // for (y)
Expand Down Expand Up @@ -458,6 +497,13 @@ class Graphics2d extends React.Component {
const canvasHeight = objCanvas.height;
const newImgWidth = canvasWidth / zoom;
const newImgHeight = canvasHeight / zoom;
const indexTools2d = store.indexTools2d;

if (indexTools2d === Tools2dType.HAND && !this.state.stateMouseDown) {
objCanvas.classList.add('cursor-hand');
} else {
objCanvas.classList.remove('cursor-hand');
}

if (!this.m_isMounted) {
return;
Expand Down Expand Up @@ -545,8 +591,12 @@ class Graphics2d extends React.Component {
}

onMouseUp(evt) {
const objCanvas = this.m_mount.current;
const store = this.props;
const indexTools2d = store.indexTools2d;

this.setState({ stateMouseDown: false });

if (indexTools2d === Tools2dType.DISTANCE) {
const store = this.props;
const box = this.m_mount.current.getBoundingClientRect();
Expand Down Expand Up @@ -589,10 +639,17 @@ class Graphics2d extends React.Component {
const yScr = evt.clientY - box.top;
this.m_toolDelete.onMouseUp(xScr, yScr, store);
}
if (store.indexTools2d === Tools2dType.HAND) {
objCanvas.classList.remove('cursor-grab');
objCanvas.classList.add('cursor-hand');
}
}

onMouseMove(evt) {
const store = this.props;
let xPos = store.render2dxPos;
let yPos = store.render2dyPos;
const zoom = store.render2dZoom;
const indexTools2d = store.indexTools2d;
const box = this.m_mount.current.getBoundingClientRect();
const xContainer = evt.clientX - box.left;
Expand All @@ -618,10 +675,26 @@ class Graphics2d extends React.Component {
if (indexTools2d === Tools2dType.DELETE) {
this.m_toolDelete.onMouseMove(xScr, yScr, store);
}
if (indexTools2d === Tools2dType.HAND && this.state.stateMouseDown) {
const deltaX = evt.clientX - this.state.startX;
const deltaY = evt.clientY - this.state.startY;
const newXPos = xPos - deltaX * zoom;
const newYPos = yPos - deltaY * zoom;

this.props.dispatch({ type: StoreActionType.SET_2D_X_POS, render2dxPos: newXPos });
this.props.dispatch({ type: StoreActionType.SET_2D_Y_POS, render2dyPos: newYPos });

this.setState({
startX: evt.clientX,
startY: evt.clientY,
});
}
store.graphics2d.forceUpdate();
}

onMouseDown(evt) {
const box = this.m_mount.current.getBoundingClientRect();
const objCanvas = this.m_mount.current;
const box = objCanvas.getBoundingClientRect();
const xContainer = evt.clientX - box.left;
const yContainer = evt.clientY - box.top;
const xScr = xContainer;
Expand All @@ -632,6 +705,12 @@ class Graphics2d extends React.Component {
const indexTools2d = store.indexTools2d;
// console.log(`onMouseDown. tool index = ${indexTools2d}`);

this.setState({
stateMouseDown: true,
startX: evt.clientX,
startY: evt.clientY,
});

switch (indexTools2d) {
case Tools2dType.INTENSITY:
this.m_toolPick.onMouseDown(xScr, yScr, store);
Expand All @@ -657,6 +736,10 @@ class Graphics2d extends React.Component {
case Tools2dType.DELETE:
this.m_toolDelete.onMouseDown(xScr, yScr, store);
break;
case Tools2dType.HAND:
objCanvas.classList.remove('cursor-hand');
objCanvas.classList.add('cursor-grab');
break;
default:
// not defined
} // switch
Expand Down Expand Up @@ -706,8 +789,6 @@ class Graphics2d extends React.Component {
* Main component render func callback
*/
render() {
// const store = this.props;
// const volSet = store.volumeSet;
this.m_sliceRatio = this.props.sliderValue;
this.m_mode2d = this.props.mode2d;
return (
Expand Down
1 change: 1 addition & 0 deletions src/engine/Volume.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class Volume extends React.Component {
this.m_zDim = 0;
this.m_bytesPerVoxel = 0;
this.m_dataArray = null;
this.m_dataArray16 = null;
this.m_dataSize = 0;
this.m_boxSize = {
x: 0.0,
Expand Down
2 changes: 2 additions & 0 deletions src/engine/lib/services/StoreService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ export class MRIStoreService {
{ type: StoreActionType.SET_LOADER_DICOM, loaderDicom },
{ type: StoreActionType.SET_VOLUME_INDEX, volumeIndex },
{ type: StoreActionType.SET_SPINNER, spinner: false },
{ type: StoreActionType.SET_IS_16_BIT, is16bit: true },
{ type: StoreActionType.SET_SHOW_MODAL_CONFIRMATION, showModalConfirmation: true },
];

this.dispatchActions(actions);
Expand Down
31 changes: 31 additions & 0 deletions src/engine/loaders/LoaderDicom.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,10 @@ class LoaderDicom {
this.m_padValue = -LARGE_NUMBER;
this.m_windowCenter = LARGE_NUMBER; // TAG_WINDOW_CENTER
this.m_windowWidth = LARGE_NUMBER; // TAG_WINDOW_WIDTH
this.m_winMin = 0;
this.m_winMax = 1;
this.m_minVal = 0;
this.m_maxVal = 0;
this.m_rescaleIntercept = 0; // TAG_RESCALE_INTERCEPT, used as v` = v * rescaleSlope + rescaleIntercept
this.m_rescaleSlope = 1; // TAG_RESCALE_SLOPE
this.m_rescaleHounsfield = false;
Expand Down Expand Up @@ -263,6 +267,7 @@ class LoaderDicom {
console.assert(volSet instanceof VolumeSet, 'Should be volume set');
console.assert(typeof indexSelected === 'number', 'index should be number');
console.assert(typeof hashSelected === 'number', 'index should be number');
const is16bit = true;

let volDst = null;
if (indexSelected < volSet.getNumVolumes()) {
Expand Down Expand Up @@ -327,6 +332,7 @@ class LoaderDicom {
let i;
let dataSize = 0;
let dataArray = null;
let dataArray16 = null;

// convert big endian in slices
if (!this.m_littleEndian) {
Expand Down Expand Up @@ -395,6 +401,8 @@ class LoaderDicom {
} // for (i) all slice pixels
} // for sl
} // for ser
this.m_minVal = minVal;
this.m_maxVal = maxVal;

console.log(`Build Volume. min/max value=${minVal}/${maxVal}. Volume dim = ${this.m_xDim}*${this.m_yDim}*${this.m_zDim}`);
console.log(`Min slice number = ${serie.m_minSlice}`);
Expand Down Expand Up @@ -452,13 +460,19 @@ class LoaderDicom {

dataSize = this.m_xDim * this.m_yDim * this.m_zDim;
dataArray = new Uint8Array(dataSize);
if (is16bit) dataArray16 = new Uint16Array(dataSize);
if (dataArray === null) {
console.log('no memory');
return LoadResult.ERROR_NO_MEMORY;
}
for (i = 0; i < dataSize; i++) {
dataArray[i] = 0;
}
if (is16bit) {
for (i = 0; i < dataSize; i++) {
dataArray16[i] = 0;
}
}

// convert slices data into volume set data (16 bpp -> 8 bpp, etc)
const MAX_BYTE = 255;
Expand All @@ -480,6 +494,17 @@ class LoaderDicom {

if (dataSrc16 !== null) {
const offZ = z * xyDim;
const BITS_16 = 16;
const max16 = 1 << BITS_16;
if (is16bit) {
for (i = 0; i < xyDim; i++) {
let val_16 = dataSrc16[i] * this.m_rescaleSlope + this.m_rescaleIntercept;
//let val = (val_16 - minVal) * max16 / (maxVal - minVal);
let val = val_16 - minVal;
val = Math.floor(val);
dataArray16[offZ + i] = val;
} // for i
}

if (this.m_windowCenter !== LARGE_NUMBER && this.m_windowWidth !== LARGE_NUMBER) {
const winMin = this.m_windowCenter - this.m_windowWidth * 0.5;
Expand Down Expand Up @@ -508,6 +533,11 @@ class LoaderDicom {
dataArray[offZ + i] = val;
} // for i
} // no defined window center, width

if (this.m_windowCenter !== LARGE_NUMBER && this.m_windowWidth !== LARGE_NUMBER && !this.m_rescaleHounsfield) {
this.m_winRight = (-this.m_minVal + this.m_windowCenter + this.m_windowWidth / 2) / (this.m_maxVal - this.m_minVal);
this.m_winLeft = (-this.m_minVal + this.m_windowCenter - this.m_windowWidth / 2) / (this.m_maxVal - this.m_minVal);
}
} // if has slice data
} // for(s) all slices

Expand Down Expand Up @@ -739,6 +769,7 @@ class LoaderDicom {
volDst.m_yDim = this.m_yDim;
volDst.m_zDim = this.m_zDim;
volDst.m_dataArray = dataArray;
volDst.m_dataArray16 = dataArray16;
volDst.m_dataSize = dataSize;
volDst.m_bytesPerVoxel = ONE;
volDst.m_boxSize.x = this.m_boxSize.x;
Expand Down
2 changes: 1 addition & 1 deletion src/engine/tools2d/ToolTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@ const Tools2dType = {
ZOOM_OUT: 10,
ZOOM_100: 11,
FILTER: 12,
NONE: 13,
HAND: 13,
};
export default Tools2dType;
Loading

0 comments on commit 73e38a6

Please sign in to comment.