Merge branch 'main' of https://gitea.frp.extimaging.com/XCKJ/irc_web
continuous-integration/drone/push Build is running
Details
continuous-integration/drone/push Build is running
Details
commit
c9be5678bd
|
|
@ -1,7 +1,12 @@
|
|||
<template>
|
||||
<div ref="viewport-fusion" class="viewport-wrapper" v-loading="loading" :element-loading-text="NSTip"
|
||||
element-loading-background="rgba(0, 0, 0, 0.8)" @mouseup="sliderMouseup" @mousemove="sliderMousemove"
|
||||
@mouseleave="sliderMouseleave" :style="{ color: series.Modality === 'PT' || isMip ? '#666' : '#ddd' }">
|
||||
@mouseleave="sliderMouseleave" :style="{ color: series.Modality === 'PT' || series.Modality === 'NM' || isMip ? '#666' : '#ddd' }">
|
||||
<div v-if="isFusion && series.Modality === 'NM'" class="opacity-slider-wrapper" @mousedown.stop @mousemove.stop @mouseup.stop @wheel.stop>
|
||||
<div class="slider-title">{{ Math.round(nmOpacity * 100) }}%</div>
|
||||
<input type="range" min="0" max="1" step="0.05" v-model.number="nmOpacity" @input="applyNmOpacity"
|
||||
class="opacity-slider" />
|
||||
</div>
|
||||
<div v-if="series && taskInfo" class="left-top-text">
|
||||
<div v-if="taskInfo.IsExistsClinicalData && !isMip && !isFusion" class="cd-info"
|
||||
:title="$t('trials:reading:button:clinicalData')">
|
||||
|
|
@ -104,9 +109,14 @@ import {
|
|||
import * as cornerstoneTools from '@cornerstonejs/tools'
|
||||
import cornerstoneDICOMImageLoader from '@cornerstonejs/dicom-image-loader';
|
||||
import vtkColorMaps from '@kitware/vtk.js/Rendering/Core/ColorTransferFunction/ColorMaps'
|
||||
import vtkPiecewiseFunction from '@kitware/vtk.js/Common/DataModel/PiecewiseFunction'
|
||||
import { createImageIdsAndCacheMetaData } from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/createImageIdsAndCacheMetaData'
|
||||
import setCtTransferFunctionForVolumeActor from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/setCtTransferFunctionForVolumeActor'
|
||||
import { setPetColorMapTransferFunctionForVolumeActor } from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/setPetColorMapTransferFunctionForVolumeActor'
|
||||
import {
|
||||
setMipTransferFunctionForVolumeActor,
|
||||
setPetTransferFunctionForVolumeActor
|
||||
} from './helpers/index.js'
|
||||
const { BlendModes, OrientationAxis } = Enums;
|
||||
const { getColormap } = csUtils.colormap;
|
||||
import { vec3, mat4 } from 'gl-matrix'
|
||||
|
|
@ -172,7 +182,10 @@ export default {
|
|||
isMove: false
|
||||
},
|
||||
ptVolumeId: null,
|
||||
loading: false
|
||||
loading: false,
|
||||
Colorbar: null,
|
||||
nmOpacity: 0.6,
|
||||
nmFusionVolumeActor: null
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
|
@ -220,7 +233,9 @@ export default {
|
|||
},
|
||||
stackNewImage(e) {
|
||||
const { detail } = e
|
||||
this.series.SliceIndex = detail.imageIndex
|
||||
if (this.series) {
|
||||
this.series.SliceIndex = detail.imageIndex
|
||||
}
|
||||
this.sliderInfo.height = detail.imageIndex * 100 / detail.numberOfSlices
|
||||
const renderingEngine = getRenderingEngine(this.renderingEngineId)
|
||||
const viewport = renderingEngine.getViewport(this.viewportId)
|
||||
|
|
@ -267,7 +282,7 @@ export default {
|
|||
const viewport = renderingEngine.getViewport(this.viewportId)
|
||||
let properties = viewport.getProperties()
|
||||
if (this.isFusion) {
|
||||
properties = viewport.getProperties(this.volumeId)
|
||||
properties = viewport.getProperties(this.ptVolumeId || this.volumeId)
|
||||
}
|
||||
if (properties && properties.voiRange) {
|
||||
var { lower, upper } = properties.voiRange
|
||||
|
|
@ -445,6 +460,18 @@ export default {
|
|||
ctx.fillStyle = gradient
|
||||
ctx.fillRect(0, 0, rectWidth, rectHeight)
|
||||
},
|
||||
applyNmOpacity() {
|
||||
if (!this.nmFusionVolumeActor?.getProperty) {
|
||||
return;
|
||||
}
|
||||
const ofun = vtkPiecewiseFunction.newInstance();
|
||||
ofun.addPoint(0, 0.0);
|
||||
ofun.addPoint(0.1, 0.9 * this.nmOpacity);
|
||||
ofun.addPoint(5, 1.0 * this.nmOpacity);
|
||||
this.nmFusionVolumeActor.getProperty().setScalarOpacity(0, ofun);
|
||||
const renderingEngine = getRenderingEngine(this.renderingEngineId)
|
||||
renderingEngine?.render?.();
|
||||
},
|
||||
setPreset(presetName) {
|
||||
this.presetName = presetName
|
||||
},
|
||||
|
|
@ -482,13 +509,13 @@ export default {
|
|||
if (this.series && data.Id === this.series.Id && data.Description === this.series.Description && !isLocate) {
|
||||
data.SliceIndex = this.series.SliceIndex
|
||||
}
|
||||
// this.series = { ...data }
|
||||
const renderingEngine = getRenderingEngine(this.renderingEngineId)
|
||||
const viewport = renderingEngine.getViewport(this.viewportId)
|
||||
if (isLocate) return csUtils.jumpToSlice(viewport.element, { imageIndex: data.SliceIndex });
|
||||
this.volumeId = data.SeriesInstanceUid
|
||||
this.ptVolumeId = null
|
||||
this.series = {}
|
||||
this.nmFusionVolumeActor = null
|
||||
let { isFusion, isMip, colorMap } = option
|
||||
this.isFusion = isFusion;
|
||||
this.isMip = isMip;
|
||||
|
|
@ -499,33 +526,34 @@ export default {
|
|||
this.ptVolumeId = `fusion_${this.volumeId}`
|
||||
let { ct, data } = obj
|
||||
this.series = { ...data }
|
||||
this.ctSeries = { ...ct }
|
||||
this.petSeries = { ...data }
|
||||
await viewport
|
||||
.setVolumes([
|
||||
{
|
||||
volumeId: this.volumeId, callback: (r) => {
|
||||
setPetColorMapTransferFunctionForVolumeActor(r)
|
||||
console.log("融合pet渲染成功");
|
||||
let volumes = [
|
||||
{
|
||||
volumeId: ct.SeriesInstanceUid, callback: (r) => {
|
||||
setCtTransferFunctionForVolumeActor(r)
|
||||
console.log("融合ct渲染成功")
|
||||
}
|
||||
},
|
||||
{
|
||||
volumeId: data.SeriesInstanceUid, callback: (r) => {
|
||||
setPetColorMapTransferFunctionForVolumeActor(r)
|
||||
if (this.series.Modality === 'NM') {
|
||||
this.nmFusionVolumeActor = r.volumeActor
|
||||
this.applyNmOpacity()
|
||||
}
|
||||
},
|
||||
{
|
||||
volumeId: ct.SeriesInstanceUid, callback: (r) => {
|
||||
setCtTransferFunctionForVolumeActor(r)
|
||||
console.log("融合ct渲染成功")
|
||||
}
|
||||
},
|
||||
{
|
||||
volumeId: this.ptVolumeId, callback: (r) => {
|
||||
setPetColorMapTransferFunctionForVolumeActor(r)
|
||||
console.log("融合pet渲染成功");
|
||||
}
|
||||
},
|
||||
]).then(res => {
|
||||
if (colorMap) {
|
||||
this.setColorMap(this.presetName)
|
||||
console.log("融合pet渲染成功")
|
||||
}
|
||||
},
|
||||
]
|
||||
if (this.series.Modality !== 'NM') {
|
||||
volumes.unshift({
|
||||
volumeId: this.volumeId, callback: (r) => {
|
||||
// setPetColorMapTransferFunctionForVolumeActor(r)
|
||||
console.log("融合pet渲染成功");
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
await viewport.setVolumes(volumes)
|
||||
} else {
|
||||
this.series = { ...data }
|
||||
if (this.isMip) {
|
||||
|
|
@ -540,7 +568,12 @@ export default {
|
|||
.setVolumes([{
|
||||
volumeId: this.volumeId,
|
||||
callback: (r) => {
|
||||
setPetColorMapTransferFunctionForVolumeActor(r)
|
||||
if (this.series.Modality === 'NM') {
|
||||
setMipTransferFunctionForVolumeActor({ ...r, volumeId: this.volumeId })
|
||||
} else {
|
||||
setPetTransferFunctionForVolumeActor(r)
|
||||
}
|
||||
// setPetColorMapTransferFunctionForVolumeActor(r)
|
||||
console.log("mip渲染成功")
|
||||
},
|
||||
slabThickness,
|
||||
|
|
@ -548,30 +581,19 @@ export default {
|
|||
defaultOptions: {
|
||||
orientation: OrientationAxis.CORONAL
|
||||
}
|
||||
}]).then(res => {
|
||||
if (colorMap) {
|
||||
this.setColorMap(this.presetName)
|
||||
}
|
||||
if (isLocate) {
|
||||
setTimeout(() => { csUtils.jumpToSlice(viewport.element, { imageIndex: data.SliceIndex }); })
|
||||
}
|
||||
})
|
||||
}])
|
||||
} else {
|
||||
viewport
|
||||
.setVolumes([{
|
||||
volumeId: this.volumeId, callback: (r) => {
|
||||
if (this.series.Modality === 'PT') {
|
||||
setPetColorMapTransferFunctionForVolumeActor(r, true)
|
||||
if (this.series.Modality === 'PT' || this.series.Modality === 'NM') {
|
||||
// setPetColorMapTransferFunctionForVolumeActor(r, true)
|
||||
setPetTransferFunctionForVolumeActor(r)
|
||||
} else {
|
||||
setCtTransferFunctionForVolumeActor(r)
|
||||
}
|
||||
console.log("渲染成功")
|
||||
}
|
||||
}]).then(res => {
|
||||
if (colorMap) {
|
||||
this.setColorMap(this.presetName)
|
||||
}
|
||||
})
|
||||
}])
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -751,7 +773,11 @@ export default {
|
|||
e.stopImmediatePropagation()
|
||||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
}
|
||||
},
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.series = null
|
||||
this.nmFusionVolumeActor = null
|
||||
},
|
||||
computed: {
|
||||
NSTip() {
|
||||
|
|
@ -767,6 +793,41 @@ export default {
|
|||
position: relative;
|
||||
cursor: default !important;
|
||||
|
||||
.opacity-slider-wrapper {
|
||||
position: absolute;
|
||||
right: 15px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 10;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
width: 40px;
|
||||
|
||||
.slider-title {
|
||||
font-size: 12px;
|
||||
color: #ddd;
|
||||
margin-bottom: 10px;
|
||||
width: 30px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.opacity-slider {
|
||||
-webkit-appearance: slider-vertical;
|
||||
writing-mode: bt-lr;
|
||||
width: 10px;
|
||||
height: 150px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
.left-top-text {
|
||||
position: absolute;
|
||||
left: 5px;
|
||||
|
|
@ -943,4 +1004,4 @@ export default {
|
|||
cursor: move
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -273,7 +273,9 @@
|
|||
</div>
|
||||
<!-- 伪彩 -->
|
||||
<template v-if="readingTool === 2">
|
||||
<colorMap v-show="isFusion" ref="colorMap" @setColorMap="setColorMap" @voiChange="voiChange" />
|
||||
<colorMap v-show="isFusion" ref="colorMap" :unit="fusionOverlayModality === 'NM' ? 'counts' : 'g/ml'"
|
||||
:modality="fusionOverlayModality"
|
||||
@setColorMap="setColorMap" @voiChange="voiChange" />
|
||||
</template>
|
||||
</div>
|
||||
|
||||
|
|
@ -299,11 +301,9 @@
|
|||
<!-- viewports -->
|
||||
<div class="viewports-wrapper">
|
||||
<div ref="container" class="grid-container">
|
||||
<!-- isMPR && index === 2 ? 'grid-cell-3' : '', -->
|
||||
<div :class="['viewports-box', isFusion || isMPR ? 'viewports-box-down' : '']" :style="gridStyle">
|
||||
<div :class="['viewports-box', isFusion || isMPR ? 'viewports-box-down' : '', fullScreenIndex !== null ? 'viewports-box-full-screen' : '']" :style="gridStyle">
|
||||
<div v-for="(v, index) in cellsMax" v-show="index < cells.length" :key="`viewport-${index}`"
|
||||
:style="cellStyle"
|
||||
:class="['grid-cell', index === activeViewportIndex ? 'cell_active' : '', index === fullScreenIndex ? 'cell-full-screen' : '']"
|
||||
:class="['grid-cell', isMPR && index === 2 ? 'grid-cell-3' : '', index === activeViewportIndex ? 'cell_active' : '', index === fullScreenIndex ? 'cell-full-screen' : '']"
|
||||
@dblclick="toggleFullScreen($event, index)" @click="activeViewport(index)">
|
||||
<VolumeViewport :ref="`viewport-${index}`" :data-viewport-uid="`viewport-${index}`"
|
||||
:rendering-engine-id="renderingEngineId" :viewport-id="`viewport-${index}`" :viewport-index="index"
|
||||
|
|
@ -315,10 +315,12 @@
|
|||
@renderAnnotations="renderAnnotations" @contentMouseup="contentMouseup" v-else />
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="(criterionType === 0 && readingTool === 0) || readingTool === 3"
|
||||
:class="['viewports-box', !isMPR ? 'viewports-box-down' : '']" :style="gridStyleMPR">
|
||||
<div v-for="(v, index) in 3" :key="`viewport-MPR-${index}`" :style="cellStyle"
|
||||
:class="['grid-cell', index === 0 ? 'grid-cell-3' : '', index === activeViewportIndex ? 'cell_active' : '', index === fullScreenIndex ? 'cell-full-screen' : '']"
|
||||
<div v-if="criterionType === 0 && readingTool === 0 || readingTool === 3"
|
||||
:class="['viewports-box', !isMPR ? 'viewports-box-down' : '', fullScreenIndex !== null ? 'viewports-box-full-screen' : '']" :style="gridStyleMPR">
|
||||
<div v-for="(v, index) in 3" :key="`viewport-MPR-${index}`"
|
||||
v-show="index < cells.length"
|
||||
:style="cellStyle"
|
||||
:class="['grid-cell', isMPR && index === 0 ? 'grid-cell-3' : '', index === activeViewportIndex ? 'cell_active' : '', index === fullScreenIndex ? 'cell-full-screen' : '']"
|
||||
@dblclick="toggleFullScreen($event, index)" @click="activeViewport(index)">
|
||||
<MPRViewport :ref="`viewport-MPR-${index}`" :data-viewport-uid="`viewport-MPR-${index}`"
|
||||
:rendering-engine-id="renderingEngineId" :viewport-id="`viewport-MPR-${index}`"
|
||||
|
|
@ -327,8 +329,7 @@
|
|||
@renderAnnotations="renderAnnotations" @contentMouseup="contentMouseup" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="readingTool === 2"
|
||||
:class="['viewports-box', !isFusion ? 'viewports-box-down' : '', fullScreenIndex !== null ? 'viewports-box-full-screen' : '']"
|
||||
<div v-if="readingTool === 2" :class="['viewports-box', !isFusion ? 'viewports-box-down' : '', fullScreenIndex !== null ? 'viewports-box-full-screen' : '']"
|
||||
:style="gridStyle">
|
||||
<div v-for="(v, index) in cellsMax" v-show="index < cells.length" :key="`viewport-fusion-${index}`"
|
||||
:class="['grid-cell', index === activeViewportIndex ? 'cell_active' : '', index === fullScreenIndex ? 'cell-full-screen' : '']"
|
||||
|
|
@ -500,7 +501,7 @@ import {
|
|||
RenderingEngine,
|
||||
Enums,
|
||||
// imageLoader,
|
||||
// metaData,
|
||||
metaData,
|
||||
volumeLoader,
|
||||
getRenderingEngine,
|
||||
eventTarget,
|
||||
|
|
@ -862,7 +863,7 @@ export default {
|
|||
} else {
|
||||
this.tools = getTools(this.criterionType)
|
||||
}
|
||||
console.log(toolsEvents, 'toolsEvents')
|
||||
|
||||
this.trialId = this.$route.query.trialId
|
||||
this.readingTaskState = this.taskInfo.ReadingTaskState
|
||||
if (!this.taskInfo.IsBaseLine && this.taskInfo.IsReadingTaskViewInOrder !== 0) {
|
||||
|
|
@ -1336,6 +1337,7 @@ export default {
|
|||
if (volumeViewportIds.includes(viewportId)) {
|
||||
toolGroupId = this.volumeToolGroupId
|
||||
}
|
||||
|
||||
const toolGroup = ToolGroupManager.getToolGroup(toolGroupId) ? ToolGroupManager.getToolGroup(toolGroupId) : ToolGroupManager.createToolGroup(toolGroupId)
|
||||
toolGroup.addViewport(viewportId, renderingEngineId)
|
||||
toolGroup.addTool(StackScrollTool.toolName, {
|
||||
|
|
@ -1659,6 +1661,7 @@ export default {
|
|||
this.$refs[`ecrf_${this.lastViewportTaskId}`][0].setAnnotation({ annotation, toolName: annotation.metadata.toolName })
|
||||
this.markedSeriesIds.push(series.Id)
|
||||
}
|
||||
|
||||
this.setToolsPassive()
|
||||
},
|
||||
annotationModifiedListener(e) {
|
||||
|
|
@ -1753,6 +1756,7 @@ export default {
|
|||
// }
|
||||
}
|
||||
}
|
||||
|
||||
this.setToolsPassive()
|
||||
},
|
||||
validMarkName(markName) {
|
||||
|
|
@ -3071,7 +3075,7 @@ export default {
|
|||
}
|
||||
if (this.isFusion) {
|
||||
this.activeViewportIndex = 0
|
||||
if (series.Modality === 'PT') {
|
||||
if (series.Modality === 'PT' || series.Modality === 'NM') {
|
||||
this.activeViewportIndex = 2
|
||||
}
|
||||
series = {
|
||||
|
|
@ -3128,7 +3132,7 @@ export default {
|
|||
}
|
||||
if (this.isFusion) {
|
||||
this.activeViewportIndex = 0
|
||||
if (series.Modality === 'PT') {
|
||||
if (series.Modality === 'PT' || series.Modality === 'NM') {
|
||||
this.activeViewportIndex = 2
|
||||
}
|
||||
series = {
|
||||
|
|
@ -3493,9 +3497,9 @@ export default {
|
|||
syncColormap: false
|
||||
})
|
||||
let viewportIds = [
|
||||
`viewport-MPR-0`,
|
||||
`viewport-MPR-1`,
|
||||
`viewport-MPR-2`
|
||||
`viewport-volume-0`,
|
||||
`viewport-volume-1`,
|
||||
`viewport-volume-2`
|
||||
]
|
||||
viewportIds.forEach((viewportId) => {
|
||||
MPRVoiSynchronizer.add({
|
||||
|
|
@ -3519,7 +3523,8 @@ export default {
|
|||
synchronizer.setEnabled(false);
|
||||
},
|
||||
setColorMap(rgbPresetName) {
|
||||
const fusionViewportIds = [`viewport-fusion-1`, `viewport-fusion-2`, `viewport-fusion-3`]
|
||||
const fusionViewportIds = [`viewport-fusion-2`]
|
||||
// const fusionViewportIds = [`viewport-fusion-1`, `viewport-fusion-2`, `viewport-fusion-3`]
|
||||
fusionViewportIds.forEach(id => {
|
||||
this.$refs[id][0].setPreset(rgbPresetName)
|
||||
this.$refs[id][0].renderColorBar(rgbPresetName)
|
||||
|
|
@ -3581,6 +3586,7 @@ export default {
|
|||
this.$refs[`ecrf_${this.taskInfo.VisitTaskId}`][0].removeAllNoSaveAnnotation()
|
||||
}
|
||||
const { ct, pt } = data
|
||||
this.fusionOverlayModality = pt?.Modality || null
|
||||
if (ct.ImageIds.length > 400) {
|
||||
let res = await this.getSystemInfo()
|
||||
if (!res) return false
|
||||
|
|
@ -3629,12 +3635,26 @@ export default {
|
|||
this.$refs[`viewport-3`][0].setSeriesInfo(pt)
|
||||
|
||||
this.$refs[`viewport-fusion-0`][0].setSeriesInfo(ctData)
|
||||
this.$refs[`viewport-fusion-1`][0].setSeriesInfo(ptData, false, { colorMap: true })
|
||||
this.$refs[`viewport-fusion-1`][0].setSeriesInfo(ptData, false, { colorMap: false })
|
||||
this.$refs[`viewport-fusion-2`][0].setSeriesInfo(fusionData, false, { isFusion: true, colorMap: true })
|
||||
this.$refs[`viewport-fusion-3`][0].setSeriesInfo(ptData, false, { isMip: true, colorMap: true })
|
||||
this.$refs[`viewport-fusion-3`][0].setSeriesInfo(ptData, false, { isMip: true, colorMap: false })
|
||||
// this.resetAnnotation = false
|
||||
this.$nextTick(() => {
|
||||
this.$refs[`colorMap`].init()
|
||||
if (this.fusionOverlayModality === 'NM') {
|
||||
const imageIds = this.sortImageIdsByImagePositionPatient(pt.ImageIds)
|
||||
const imageId = imageIds?.[0]
|
||||
const voiLutModule = imageId ? metaData.get('voiLutModule', imageId) : null
|
||||
const rawWidth = Array.isArray(voiLutModule?.windowWidth) ? voiLutModule.windowWidth[0] : voiLutModule?.windowWidth
|
||||
const nmMax = Number(rawWidth)
|
||||
if (Number.isFinite(nmMax) && nmMax > 0) {
|
||||
const halfMax = Math.round(nmMax * 0.5)
|
||||
this.$refs.colorMap.range = Math.round(nmMax)
|
||||
this.$refs.colorMap.upper = halfMax
|
||||
this.$refs.colorMap.upperRangeChange(Math.round(nmMax))
|
||||
this.voiChange(halfMax)
|
||||
}
|
||||
}
|
||||
})
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
|
|
@ -3656,12 +3676,56 @@ export default {
|
|||
volume = cache.getVolume(volumeId)
|
||||
} else {
|
||||
await this.$refs[`${this.viewportKey}-0`][0].createImageIdsAndCacheMetaData(serie)
|
||||
volume = await volumeLoader.createAndCacheVolume(volumeId, { imageIds: serie.ImageIds })
|
||||
let imageIds = this.sortImageIdsByImagePositionPatient(serie.ImageIds)
|
||||
volume = await volumeLoader.createAndCacheVolume(volumeId, { imageIds: imageIds })
|
||||
volume.load()
|
||||
}
|
||||
res({ volumeId, volume })
|
||||
})
|
||||
},
|
||||
sortImageIdsByImagePositionPatient(imageIds) {
|
||||
if (!Array.isArray(imageIds) || imageIds.length < 2) {
|
||||
return imageIds;
|
||||
}
|
||||
|
||||
const firstPlane = metaData.get('imagePlaneModule', imageIds[0]);
|
||||
if (!firstPlane?.imagePositionPatient || !firstPlane?.imageOrientationPatient) {
|
||||
return imageIds;
|
||||
}
|
||||
|
||||
const reference = firstPlane.imagePositionPatient.map((v) => Number(v));
|
||||
const iop = firstPlane.imageOrientationPatient.map((v) => Number(v));
|
||||
const row = [iop[0], iop[1], iop[2]];
|
||||
const col = [iop[3], iop[4], iop[5]];
|
||||
const normal = [
|
||||
row[1] * col[2] - row[2] * col[1],
|
||||
row[2] * col[0] - row[0] * col[2],
|
||||
row[0] * col[1] - row[1] * col[0],
|
||||
];
|
||||
|
||||
const pairs = [];
|
||||
for (const imageId of imageIds) {
|
||||
const plane = metaData.get('imagePlaneModule', imageId);
|
||||
const ipp = plane?.imagePositionPatient;
|
||||
if (!ipp) {
|
||||
return imageIds;
|
||||
}
|
||||
const pos = ipp.map((v) => Number(v));
|
||||
const positionVector = [
|
||||
reference[0] - pos[0],
|
||||
reference[1] - pos[1],
|
||||
reference[2] - pos[2],
|
||||
];
|
||||
const distance =
|
||||
positionVector[0] * normal[0] +
|
||||
positionVector[1] * normal[1] +
|
||||
positionVector[2] * normal[2];
|
||||
pairs.push({ imageId, distance });
|
||||
}
|
||||
|
||||
pairs.sort((a, b) => b.distance - a.distance);
|
||||
return pairs.map((p) => p.imageId);
|
||||
},
|
||||
upperRangeChange(upper) {
|
||||
this.$refs.colorMap.upper = upper
|
||||
this.$refs.colorMap.upperRangeChange(upper)
|
||||
|
|
@ -3671,6 +3735,7 @@ export default {
|
|||
},
|
||||
closeFusion() {
|
||||
this.fusionVisible = false
|
||||
this.fusionOverlayModality = null
|
||||
},
|
||||
getTrialCriterion() {
|
||||
getCriterionReadingInfo({
|
||||
|
|
@ -4091,17 +4156,17 @@ export default {
|
|||
}
|
||||
|
||||
.viewports-box-down {
|
||||
>.grid-cell {
|
||||
> .grid-cell {
|
||||
border-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.viewports-box-full-screen {
|
||||
>.grid-cell {
|
||||
> .grid-cell {
|
||||
display: none;
|
||||
}
|
||||
|
||||
>.grid-cell.cell-full-screen {
|
||||
> .grid-cell.cell-full-screen {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -498,7 +498,7 @@ export default {
|
|||
viewport
|
||||
.setVolumes([{
|
||||
volumeId: this.volumeId, callback: (r) => {
|
||||
if (this.series.Modality === 'PT') {
|
||||
if (this.series.Modality === 'PT' || this.series.Modality === 'NM') {
|
||||
setPetColorMapTransferFunctionForVolumeActor(r, true)
|
||||
} else {
|
||||
setCtTransferFunctionForVolumeActor(r)
|
||||
|
|
|
|||
|
|
@ -30,11 +30,11 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin-left:-1px;border: 1px solid #424242;">
|
||||
<el-input v-model="range" size="mini" style="width:120px" maxlength="3"
|
||||
<div v-if="modality !== 'NM'" style="margin-left:-1px;border: 1px solid #424242;">
|
||||
<el-input v-model="range" size="mini" style="width:120px" :maxlength="maxLength"
|
||||
oninput="if(value){value=value.replace(/[^\d]/g,'')} if(value<=0){value=''}"
|
||||
@change="upperRangeChange">
|
||||
<template slot="append">g/ml</template>
|
||||
<template slot="append">{{ unit }}</template>
|
||||
</el-input>
|
||||
</div>
|
||||
<div id="slider" style="position: absolute;left: 6px;top:5px;cursor: pointer;">
|
||||
|
|
@ -54,6 +54,20 @@ import vtkColorMaps from '@kitware/vtk.js/Rendering/Core/ColorTransferFunction/C
|
|||
const { registerColormap, getColormapNames, getColormap } = csUtils.colormap
|
||||
export default {
|
||||
name: "colorMap",
|
||||
props: {
|
||||
unit: {
|
||||
type: String,
|
||||
default: 'g/ml'
|
||||
},
|
||||
modality: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
maxLength: {
|
||||
type: [Number, String],
|
||||
default: 6
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
colorMaps: [],
|
||||
|
|
@ -111,7 +125,11 @@ export default {
|
|||
var positionValue = document.getElementById('slider-position')
|
||||
var upper = this.range
|
||||
position = parseInt((position / maxLeft) * upper)
|
||||
positionValue.textContent = position
|
||||
if (this.modality === 'NM') {
|
||||
positionValue.textContent = Math.round((position / upper) * 100) + '%'
|
||||
} else {
|
||||
positionValue.textContent = position
|
||||
}
|
||||
this.upper = position
|
||||
this.voiChange(position)
|
||||
}
|
||||
|
|
@ -138,7 +156,11 @@ export default {
|
|||
var slider = document.getElementById('slider')
|
||||
slider.style.left = left + 'px'
|
||||
var positionValue = document.getElementById('slider-position')
|
||||
positionValue.textContent = this.upper
|
||||
if (this.modality === 'NM') {
|
||||
positionValue.textContent = Math.round((this.upper / this.range) * 100) + '%'
|
||||
} else {
|
||||
positionValue.textContent = this.upper
|
||||
}
|
||||
},
|
||||
createColorBar(rgbPresetName, elId, width, height) {
|
||||
var colorMap = null
|
||||
|
|
@ -322,4 +344,4 @@ export default {
|
|||
color: #ddd;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
import setPetTransferFunctionForVolumeActor from "./setPetTransferFunctionForVolumeActor";
|
||||
import setMipTransferFunctionForVolumeActor from "./setMipTransferFunctionForVolumeActor";
|
||||
|
||||
|
||||
export {
|
||||
setPetTransferFunctionForVolumeActor,
|
||||
setMipTransferFunctionForVolumeActor
|
||||
};
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
import { cache, metaData, utilities } from "@cornerstonejs/core";
|
||||
import vtkPiecewiseFunction from "@kitware/vtk.js/Common/DataModel/PiecewiseFunction";
|
||||
|
||||
export default function setMipTransferFunctionForVolumeActor({
|
||||
volumeActor,
|
||||
volumeId,
|
||||
}) {
|
||||
const mapper = volumeActor.getMapper?.();
|
||||
if (mapper?.setSampleDistance) {
|
||||
mapper.setSampleDistance(1.0);
|
||||
}
|
||||
const rgbTransferFunction = volumeActor
|
||||
.getProperty()
|
||||
.getRGBTransferFunction(0);
|
||||
let range = null;
|
||||
const imageVolume = volumeId ? cache.getVolume(volumeId) : null;
|
||||
const imageId = imageVolume?.imageIds?.[0];
|
||||
if (imageId) {
|
||||
const voiLutModule = metaData.get("voiLutModule", imageId);
|
||||
const rawCenter = Array.isArray(voiLutModule?.windowCenter)
|
||||
? voiLutModule.windowCenter[0]
|
||||
: voiLutModule?.windowCenter;
|
||||
const rawWidth = Array.isArray(voiLutModule?.windowWidth)
|
||||
? voiLutModule.windowWidth[0]
|
||||
: voiLutModule?.windowWidth;
|
||||
const center = Number(rawCenter);
|
||||
const width = Number(rawWidth);
|
||||
if (Number.isFinite(center) && Number.isFinite(width) && width > 0) {
|
||||
const upper = center + width / 2;
|
||||
range = [0, upper];
|
||||
} else if (Number.isFinite(center)) {
|
||||
range = [0, center];
|
||||
}
|
||||
}
|
||||
if (!range) {
|
||||
range = [0, 5];
|
||||
}
|
||||
|
||||
rgbTransferFunction.setRange(range[0], range[1]);
|
||||
utilities.invertRgbTransferFunction(rgbTransferFunction);
|
||||
const upper = Number(range[1]);
|
||||
if (Number.isFinite(upper) && upper > 0) {
|
||||
const ofun = vtkPiecewiseFunction.newInstance();
|
||||
ofun.addPoint(0, 0.0);
|
||||
ofun.addPoint(upper * 0.02, 0.9);
|
||||
ofun.addPoint(upper, 1.0);
|
||||
volumeActor.getProperty().setScalarOpacity(0, ofun);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
import { utilities } from '@cornerstonejs/core';
|
||||
|
||||
export default function setPetTransferFunction({ volumeActor }) {
|
||||
const rgbTransferFunction = volumeActor
|
||||
.getProperty()
|
||||
.getRGBTransferFunction(0);
|
||||
|
||||
rgbTransferFunction.setRange(0, 5);
|
||||
|
||||
utilities.invertRgbTransferFunction(rgbTransferFunction);
|
||||
}
|
||||
Loading…
Reference in New Issue