分割标记渲染结构变更
parent
5a7fa1fb77
commit
312ab754e1
|
|
@ -16,6 +16,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-s3": "3.726.1",
|
"@aws-sdk/client-s3": "3.726.1",
|
||||||
"@cornerstonejs/adapters": "^4.19.2",
|
"@cornerstonejs/adapters": "^4.19.2",
|
||||||
|
"@cornerstonejs/polymorphic-segmentation": "4.19.2",
|
||||||
"@cornerstonejs/calculate-suv": "^1.1.0",
|
"@cornerstonejs/calculate-suv": "^1.1.0",
|
||||||
"@cornerstonejs/core": "^4.19.2",
|
"@cornerstonejs/core": "^4.19.2",
|
||||||
"@cornerstonejs/dicom-image-loader": "^4.19.2",
|
"@cornerstonejs/dicom-image-loader": "^4.19.2",
|
||||||
|
|
@ -124,4 +125,4 @@
|
||||||
"not dead",
|
"not dead",
|
||||||
"not op_mini all"
|
"not op_mini all"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
@ -81,6 +81,19 @@ import {
|
||||||
} from './helpers/index.js'
|
} from './helpers/index.js'
|
||||||
import { vec3, mat4 } from 'gl-matrix'
|
import { vec3, mat4 } from 'gl-matrix'
|
||||||
import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent'
|
import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent'
|
||||||
|
import {
|
||||||
|
renderSegmentation,
|
||||||
|
readingSegmentByConfig,
|
||||||
|
selectSegmentation,
|
||||||
|
selectSegment,
|
||||||
|
createSegmentationRepresentation,
|
||||||
|
viewSegmentation,
|
||||||
|
viewSegment,
|
||||||
|
jumpBidirectional,
|
||||||
|
viewBidirectional,
|
||||||
|
changeColor,
|
||||||
|
resetViewport
|
||||||
|
} from "./helpers/segmentations"
|
||||||
export default {
|
export default {
|
||||||
name: 'MPRViewport',
|
name: 'MPRViewport',
|
||||||
props: {
|
props: {
|
||||||
|
|
@ -105,6 +118,32 @@ export default {
|
||||||
histogramVisible: {
|
histogramVisible: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
|
},
|
||||||
|
actionConfiguration: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SegmentConfig: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
curSegSeries: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
segmentIndex: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
segmentationId: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
|
@ -155,6 +194,39 @@ export default {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.initViewport()
|
this.initViewport()
|
||||||
})
|
})
|
||||||
|
DicomEvent.$on('createSegmentationRepresentation', (segmentationId) => {
|
||||||
|
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
|
||||||
|
createSegmentationRepresentation(this.viewportId, segmentationId)
|
||||||
|
})
|
||||||
|
DicomEvent.$on('viewSegmentation', (obj) => {
|
||||||
|
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
|
||||||
|
viewSegmentation(obj, this.viewportId)
|
||||||
|
})
|
||||||
|
DicomEvent.$on('viewSegment', (obj) => {
|
||||||
|
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
|
||||||
|
viewSegment(obj, this.viewportId)
|
||||||
|
})
|
||||||
|
DicomEvent.$on('jumpBidirectional', (obj) => {
|
||||||
|
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
|
||||||
|
jumpBidirectional(obj, this.viewportId, this.volumeId)
|
||||||
|
})
|
||||||
|
DicomEvent.$on('viewBidirectional', (obj) => {
|
||||||
|
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
|
||||||
|
viewBidirectional(obj, this.viewportId)
|
||||||
|
})
|
||||||
|
DicomEvent.$on('changeColor', (obj) => {
|
||||||
|
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
|
||||||
|
changeColor(obj, this.viewportId)
|
||||||
|
})
|
||||||
|
DicomEvent.$on('resetViewport', () => {
|
||||||
|
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
|
||||||
|
resetViewport(this.viewportId)
|
||||||
|
})
|
||||||
|
DicomEvent.$on('renderSegmentation', async (viewportId) => {
|
||||||
|
// if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
|
||||||
|
if (this.viewportId !== viewportId) return false
|
||||||
|
await renderSegmentation(this.series, this.series.TaskInfo, this.viewportId, this.SegmentConfig, this.segmentationId, this.segmentIndex, this.renderingEngineId, null, this.actionConfiguration)
|
||||||
|
})
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
MPRInfo: {
|
MPRInfo: {
|
||||||
|
|
@ -173,6 +245,25 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
deep: true
|
deep: true
|
||||||
|
},
|
||||||
|
SegmentConfig: {
|
||||||
|
handler() {
|
||||||
|
if (!this.segmentationId) return false
|
||||||
|
if (!this.series.TaskInfo) return false
|
||||||
|
readingSegmentByConfig(this.series, this.series.TaskInfo, this.viewportId, this.segmentationId, this.SegmentConfig)
|
||||||
|
},
|
||||||
|
deep: true
|
||||||
|
},
|
||||||
|
segmentIndex() {
|
||||||
|
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
|
||||||
|
if (this.segmentIndex <= 0) return false
|
||||||
|
selectSegment(this.viewportId, this.segmentationId, this.segmentIndex)
|
||||||
|
},
|
||||||
|
segmentationId() {
|
||||||
|
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
|
||||||
|
if (!this.segmentationId) return false
|
||||||
|
selectSegmentation(this.viewportId, this.segmentationId)
|
||||||
|
readingSegmentByConfig(this.series, this.series.TaskInfo, this.viewportId, this.segmentationId, this.SegmentConfig)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
@ -505,7 +596,6 @@ export default {
|
||||||
setCtTransferFunctionForVolumeActor(r)
|
setCtTransferFunctionForVolumeActor(r)
|
||||||
}
|
}
|
||||||
console.log("渲染成功")
|
console.log("渲染成功")
|
||||||
DicomEvent.$emit("isloaded", { isChange: false })
|
|
||||||
}
|
}
|
||||||
}]).then(r => {
|
}]).then(r => {
|
||||||
if (data.isLocation || !this.imageInfo.zoom) {
|
if (data.isLocation || !this.imageInfo.zoom) {
|
||||||
|
|
@ -522,6 +612,7 @@ export default {
|
||||||
renderingEngine.render()
|
renderingEngine.render()
|
||||||
}, 100)
|
}, 100)
|
||||||
}
|
}
|
||||||
|
await renderSegmentation(this.series, this.series.TaskInfo, this.viewportId, this.SegmentConfig, this.segmentationId, this.segmentIndex, this.renderingEngineId, null, this.actionConfiguration)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e)
|
console.log(e)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -313,7 +313,9 @@
|
||||||
@dblclick="toggleFullScreen($event, index)" @click="activeViewport(index)">
|
@dblclick="toggleFullScreen($event, index)" @click="activeViewport(index)">
|
||||||
<VolumeViewport :ref="`viewport-${index}`" :data-viewport-uid="`viewport-${index}`"
|
<VolumeViewport :ref="`viewport-${index}`" :data-viewport-uid="`viewport-${index}`"
|
||||||
:rendering-engine-id="renderingEngineId" :viewport-id="`viewport-${index}`" :viewport-index="index"
|
:rendering-engine-id="renderingEngineId" :viewport-id="`viewport-${index}`" :viewport-index="index"
|
||||||
:histogramVisible="histogramVisible" @activeViewport="activeViewport"
|
:histogramVisible="histogramVisible" :actionConfiguration="actionConfiguration"
|
||||||
|
:SegmentConfig="SegmentConfig" :segmentationId.sync="segId" :segmentIndex.sync="segIndex"
|
||||||
|
:curSegSeries.sync="curSegSeries" @activeViewport="activeViewport"
|
||||||
@toggleTaskByViewport="toggleTaskByViewport" @previewCD="previewCD"
|
@toggleTaskByViewport="toggleTaskByViewport" @previewCD="previewCD"
|
||||||
@renderAnnotations="renderAnnotations" @contentMouseup="contentMouseup"
|
@renderAnnotations="renderAnnotations" @contentMouseup="contentMouseup"
|
||||||
@resetViewport="resetViewport" v-if="readingTool === 3"
|
@resetViewport="resetViewport" v-if="readingTool === 3"
|
||||||
|
|
@ -333,7 +335,10 @@
|
||||||
@dblclick="toggleFullScreen($event, index)" @click="activeViewport(index)">
|
@dblclick="toggleFullScreen($event, index)" @click="activeViewport(index)">
|
||||||
<MPRViewport :ref="`viewport-MPR-${index}`" :data-viewport-uid="`viewport-MPR-${index}`"
|
<MPRViewport :ref="`viewport-MPR-${index}`" :data-viewport-uid="`viewport-MPR-${index}`"
|
||||||
:rendering-engine-id="renderingEngineId" :viewport-id="`viewport-MPR-${index}`"
|
:rendering-engine-id="renderingEngineId" :viewport-id="`viewport-MPR-${index}`"
|
||||||
:viewport-index="index" :MPRInfo="MPRInfo" @activeViewport="activeViewport" @setMPRInfo="setMPRInfo"
|
:viewport-index="index" :histogramVisible="histogramVisible"
|
||||||
|
:actionConfiguration="actionConfiguration" :SegmentConfig="SegmentConfig"
|
||||||
|
:segmentationId.sync="segId" :segmentIndex.sync="segIndex" :curSegSeries.sync="curSegSeries"
|
||||||
|
:MPRInfo="MPRInfo" @activeViewport="activeViewport" @setMPRInfo="setMPRInfo"
|
||||||
@toggleTaskByViewport="toggleTaskByViewport" @previewCD="previewCD"
|
@toggleTaskByViewport="toggleTaskByViewport" @previewCD="previewCD"
|
||||||
@renderAnnotations="renderAnnotations" @contentMouseup="contentMouseup"
|
@renderAnnotations="renderAnnotations" @contentMouseup="contentMouseup"
|
||||||
v-resize="(e) => handleSizeChange(e, `viewport-MPR-${index}`)" />
|
v-resize="(e) => handleSizeChange(e, `viewport-MPR-${index}`)" />
|
||||||
|
|
@ -362,9 +367,11 @@
|
||||||
<Segmentations ref="Segmentations" :visitInfo="taskInfo" :isMPR="isMPR"
|
<Segmentations ref="Segmentations" :visitInfo="taskInfo" :isMPR="isMPR"
|
||||||
:volumeToolGroupId="volumeToolGroupId" :viewportKey="viewportKey" :global-loading.sync="loading"
|
:volumeToolGroupId="volumeToolGroupId" :viewportKey="viewportKey" :global-loading.sync="loading"
|
||||||
:loadingText.sync="loadingText" :rendering-engine-id="renderingEngineId"
|
:loadingText.sync="loadingText" :rendering-engine-id="renderingEngineId"
|
||||||
:activeViewportIndex="activeViewportIndex" :activeTool.sync="activeTool"
|
:SegmentConfig="SegmentConfig" :segId.sync="segId" :segIndex.sync="segIndex"
|
||||||
:actionConfiguration="actionConfiguration" :histogramVisible="histogramVisible"
|
:curSegSeries.sync="curSegSeries" :activeViewportIndex="activeViewportIndex"
|
||||||
@setToolsPassive="setToolsPassive" @resetQuestion="resetQuestion" />
|
:activeTool.sync="activeTool" :actionConfiguration="actionConfiguration"
|
||||||
|
:histogramVisible="histogramVisible" @setToolsPassive="setToolsPassive"
|
||||||
|
@resetQuestion="resetQuestion" />
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane :label="$t('trials:reading:dicom3D:tabs:ecrf')" name="ecrf">
|
<el-tab-pane :label="$t('trials:reading:dicom3D:tabs:ecrf')" name="ecrf">
|
||||||
<div v-for="s in visitTaskList" v-show="lastViewportTaskId === s.VisitTaskId" :key="s.VisitTaskId"
|
<div v-for="s in visitTaskList" v-show="lastViewportTaskId === s.VisitTaskId" :key="s.VisitTaskId"
|
||||||
|
|
@ -498,6 +505,11 @@
|
||||||
<!--直方图-->
|
<!--直方图-->
|
||||||
<histogram ref="histogram" v-if="readingTool === 3" :visible.sync="histogramVisible" :activeTool.sync="activeTool"
|
<histogram ref="histogram" v-if="readingTool === 3" :visible.sync="histogramVisible" :activeTool.sync="activeTool"
|
||||||
:viewportKey="viewportKey" :rendering-engine-id="renderingEngineId" :activeViewportIndex="activeViewportIndex" />
|
:viewportKey="viewportKey" :rendering-engine-id="renderingEngineId" :activeViewportIndex="activeViewportIndex" />
|
||||||
|
<!--分割可视化窗口-->
|
||||||
|
<!-- <SurfaceViewport ref="surfaceViewport" viewportId="surfaceViewport" v-if="readingTool === 3"
|
||||||
|
:visible.sync="surfaceVisible" :renderingEngineId="renderingEngineId" :visitInfo="taskInfo" />
|
||||||
|
<ContourViewport ref="contourViewport" viewportId="contourViewport" v-if="readingTool === 3"
|
||||||
|
:renderingEngineId="renderingEngineId" :visitInfo="taskInfo" /> -->
|
||||||
<upload-dicom-and-nonedicom v-if="uploadImageVisible" :subject-id="uploadSubjectId"
|
<upload-dicom-and-nonedicom v-if="uploadImageVisible" :subject-id="uploadSubjectId"
|
||||||
:subject-code="uploadSubjectCode" :criterion="uploadTrialCriterion" :visible.sync="uploadImageVisible"
|
:subject-code="uploadSubjectCode" :criterion="uploadTrialCriterion" :visible.sync="uploadImageVisible"
|
||||||
:visit-task-id="taskId" :is-reading-task-view-in-order="isReadingTaskViewInOrder" />
|
:visit-task-id="taskId" :is-reading-task-view-in-order="isReadingTaskViewInOrder" />
|
||||||
|
|
@ -516,6 +528,7 @@ import {
|
||||||
RenderingEngine,
|
RenderingEngine,
|
||||||
Enums,
|
Enums,
|
||||||
// imageLoader,
|
// imageLoader,
|
||||||
|
// CONSTANTS,
|
||||||
metaData,
|
metaData,
|
||||||
volumeLoader,
|
volumeLoader,
|
||||||
getRenderingEngine,
|
getRenderingEngine,
|
||||||
|
|
@ -537,6 +550,8 @@ import MPRViewport from './MPRViewport'
|
||||||
import VolumeViewport from './VolumeViewport'
|
import VolumeViewport from './VolumeViewport'
|
||||||
import Segmentations from './Segmentations'
|
import Segmentations from './Segmentations'
|
||||||
import histogram from "./histogram"
|
import histogram from "./histogram"
|
||||||
|
// import SurfaceViewport from "./SurfaceViewport"
|
||||||
|
// import ContourViewport from "./ContourViewport"
|
||||||
import mRecisit from './mRecist/QuestionList'
|
import mRecisit from './mRecist/QuestionList'
|
||||||
import recisit from './Recist/QuestionList'
|
import recisit from './Recist/QuestionList'
|
||||||
import customizeQuestionList from './customize/QuestionList'
|
import customizeQuestionList from './customize/QuestionList'
|
||||||
|
|
@ -567,6 +582,9 @@ const {
|
||||||
ToolGroupManager,
|
ToolGroupManager,
|
||||||
Enums: csToolsEnums,
|
Enums: csToolsEnums,
|
||||||
StackScrollTool,
|
StackScrollTool,
|
||||||
|
TrackballRotateTool,
|
||||||
|
PlanarFreehandContourSegmentationTool,
|
||||||
|
SplineContourSegmentationTool,
|
||||||
// ScaleOverlayTool,
|
// ScaleOverlayTool,
|
||||||
PanTool,
|
PanTool,
|
||||||
ZoomTool,
|
ZoomTool,
|
||||||
|
|
@ -629,6 +647,8 @@ export default {
|
||||||
VolumeViewport,
|
VolumeViewport,
|
||||||
Segmentations,
|
Segmentations,
|
||||||
histogram,
|
histogram,
|
||||||
|
// SurfaceViewport,
|
||||||
|
// ContourViewport,
|
||||||
mRecisit,
|
mRecisit,
|
||||||
recisit,
|
recisit,
|
||||||
customizeQuestionList,
|
customizeQuestionList,
|
||||||
|
|
@ -662,7 +682,7 @@ export default {
|
||||||
activeTaskIndex: -1,
|
activeTaskIndex: -1,
|
||||||
activeStudyIndex: -1,
|
activeStudyIndex: -1,
|
||||||
activeSeriesIndex: -1,
|
activeSeriesIndex: -1,
|
||||||
currentVisitInfo: null,
|
currentVisitInfo: {},
|
||||||
layout: 1,
|
layout: 1,
|
||||||
cellsMax: 4,
|
cellsMax: 4,
|
||||||
rows: 1,
|
rows: 1,
|
||||||
|
|
@ -772,14 +792,28 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
SegmentConfig: {
|
||||||
|
renderOutline: true,
|
||||||
|
renderFill: true,
|
||||||
|
fillAlpha: 0.5,
|
||||||
|
outlineWidth: 1,
|
||||||
|
InactiveSegmentations: {
|
||||||
|
show: true,
|
||||||
|
fillAlpha: 0.3,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
segId: null,
|
||||||
|
segIndex: null,
|
||||||
|
curSegSeries: {},
|
||||||
fusionOverlayModality: null,
|
fusionOverlayModality: null,
|
||||||
lastUpper: null,
|
lastUpper: null,
|
||||||
hasFusionUpperInitialized: false,
|
hasFusionUpperInitialized: false,
|
||||||
timer: null,
|
timer: {},
|
||||||
FullTimerOut: null,
|
FullTimerOut: null,
|
||||||
isDelay: false,
|
isDelay: false,
|
||||||
|
|
||||||
histogramVisible: false
|
histogramVisible: false,
|
||||||
|
// surfaceVisible: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
|
@ -951,6 +985,11 @@ export default {
|
||||||
this.getSystemInfoReading();
|
this.getSystemInfoReading();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
showSurface(obj) {
|
||||||
|
// this.surfaceVisible = true
|
||||||
|
// this.$refs.contourViewport.setSeriesInfo(obj)
|
||||||
|
// this.$refs.surfaceViewport.setSeriesInfo(obj)
|
||||||
|
},
|
||||||
async openHistogram() {
|
async openHistogram() {
|
||||||
this.histogramVisible = true
|
this.histogramVisible = true
|
||||||
this.setToolsPassive()
|
this.setToolsPassive()
|
||||||
|
|
@ -958,8 +997,8 @@ export default {
|
||||||
|
|
||||||
},
|
},
|
||||||
handleSizeChange(e, viewportId) {
|
handleSizeChange(e, viewportId) {
|
||||||
// console.log('handleSizeChange', e)
|
let index = this.$refs[viewportId][0].series.SliceIndex
|
||||||
this.resetRenderingEngine(viewportId)
|
this.resetRenderingEngine(viewportId, index)
|
||||||
},
|
},
|
||||||
resetQuestion() {
|
resetQuestion() {
|
||||||
this.$refs[`ecrf_${this.lastViewportTaskId}`][0].getQuestions(false)
|
this.$refs[`ecrf_${this.lastViewportTaskId}`][0].getQuestions(false)
|
||||||
|
|
@ -1297,6 +1336,27 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
// let element5 = this.$refs.surfaceViewport.$el
|
||||||
|
// let element6 = this.$refs.contourViewport.$el
|
||||||
|
// viewportInputArray.push({
|
||||||
|
// viewportId: 'surfaceViewport',
|
||||||
|
// type: ViewportType.VOLUME_3D,
|
||||||
|
// element: element5,
|
||||||
|
// defaultOptions: {
|
||||||
|
// orientation: Enums.OrientationAxis.CORONAL,
|
||||||
|
// background: [1, 1, 1]
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// viewportInputArray.push({
|
||||||
|
// viewportId: 'contourViewport',
|
||||||
|
// type: ViewportType.ORTHOGRAPHIC,
|
||||||
|
// element: element6,
|
||||||
|
// defaultOptions: {
|
||||||
|
// orientation: Enums.OrientationAxis.AXIAL
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// viewportIds.push('surfaceViewport')
|
||||||
|
// viewportIds.push('contourViewport')
|
||||||
}
|
}
|
||||||
if ((this.criterionType === 0 && this.readingTool === 0) || this.readingTool === 3) {
|
if ((this.criterionType === 0 && this.readingTool === 0) || this.readingTool === 3) {
|
||||||
const volumeElement1 = this.$refs['viewport-MPR-0'][0].$el
|
const volumeElement1 = this.$refs['viewport-MPR-0'][0].$el
|
||||||
|
|
@ -1377,6 +1437,7 @@ export default {
|
||||||
}
|
}
|
||||||
renderingEngine.setViewports(viewportInputArray)
|
renderingEngine.setViewports(viewportInputArray)
|
||||||
this.addAnnotationListeners()
|
this.addAnnotationListeners()
|
||||||
|
// cornerstoneTools.addTool(TrackballRotateTool)
|
||||||
cornerstoneTools.addTool(StackScrollTool)
|
cornerstoneTools.addTool(StackScrollTool)
|
||||||
cornerstoneTools.addTool(PanTool)
|
cornerstoneTools.addTool(PanTool)
|
||||||
cornerstoneTools.addTool(ZoomTool)
|
cornerstoneTools.addTool(ZoomTool)
|
||||||
|
|
@ -1401,6 +1462,8 @@ export default {
|
||||||
cornerstoneTools.addTool(LabelMapEditWithContourTool)
|
cornerstoneTools.addTool(LabelMapEditWithContourTool)
|
||||||
cornerstoneTools.addTool(BrushTool)
|
cornerstoneTools.addTool(BrushTool)
|
||||||
cornerstoneTools.addTool(SegmentBidirectionalTool)
|
cornerstoneTools.addTool(SegmentBidirectionalTool)
|
||||||
|
// cornerstoneTools.addTool(PlanarFreehandContourSegmentationTool);
|
||||||
|
// cornerstoneTools.addTool(SplineContourSegmentationTool);
|
||||||
viewportIds.forEach((viewportId, i) => {
|
viewportIds.forEach((viewportId, i) => {
|
||||||
// const toolGroupId = `viewport-${i}`
|
// const toolGroupId = `viewport-${i}`
|
||||||
let toolGroupId = viewportId
|
let toolGroupId = viewportId
|
||||||
|
|
@ -1410,196 +1473,222 @@ export default {
|
||||||
|
|
||||||
const toolGroup = ToolGroupManager.getToolGroup(toolGroupId) ? ToolGroupManager.getToolGroup(toolGroupId) : ToolGroupManager.createToolGroup(toolGroupId)
|
const toolGroup = ToolGroupManager.getToolGroup(toolGroupId) ? ToolGroupManager.getToolGroup(toolGroupId) : ToolGroupManager.createToolGroup(toolGroupId)
|
||||||
toolGroup.addViewport(viewportId, renderingEngineId)
|
toolGroup.addViewport(viewportId, renderingEngineId)
|
||||||
toolGroup.addTool(StackScrollTool.toolName, {
|
if (toolGroupId.includes('surface')) {
|
||||||
loop: true, // 启用循环滚动
|
// toolGroup.addTool(TrackballRotateTool.toolName, {
|
||||||
})
|
// rotateSampleDistanceFactor: 0,
|
||||||
toolGroup.addTool(ScaleOverlayTool.toolName)
|
// });
|
||||||
|
// toolGroup.setToolActive(TrackballRotateTool.toolName, {
|
||||||
toolGroup.addTool(PanTool.toolName)
|
// bindings: [
|
||||||
toolGroup.addTool(ZoomTool.toolName)
|
// {
|
||||||
toolGroup.addTool(BrushTool.toolName)
|
// mouseButton: MouseBindings.Primary,
|
||||||
if (this.readingTool === 3 || toolGroupId === this.volumeToolGroupId) {
|
// },
|
||||||
toolGroup.addToolInstance(
|
// ],
|
||||||
'histogram_RectangleROI',
|
// });
|
||||||
RectangleROITool.toolName,
|
} else if (toolGroupId.includes('contour')) {
|
||||||
);
|
// toolGroup.addTool(PlanarFreehandContourSegmentationTool.toolName);
|
||||||
toolGroup.addToolInstance(
|
// toolGroup.addTool(SplineContourSegmentationTool.toolName);
|
||||||
'histogram_CircleROI',
|
// toolGroup.setToolActive(PlanarFreehandContourSegmentationTool.toolName, {
|
||||||
CircleROITool.toolName,
|
// bindings: [
|
||||||
);
|
// {
|
||||||
toolGroup.addToolInstance(
|
// mouseButton: MouseBindings.Primary, // Middle Click
|
||||||
'histogram_PlanarFreehandROI',
|
// },
|
||||||
PlanarFreehandROITool.toolName,
|
// ],
|
||||||
);
|
// });
|
||||||
toolGroup.addToolInstance(
|
|
||||||
'CircularBrush',
|
|
||||||
BrushTool.toolName,
|
|
||||||
{
|
|
||||||
activeStrategy: 'FILL_INSIDE_CIRCLE',
|
|
||||||
preview: {
|
|
||||||
previewColors: {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
toolGroup.addToolInstance(
|
|
||||||
'CircularEraser',
|
|
||||||
BrushTool.toolName,
|
|
||||||
{
|
|
||||||
activeStrategy: 'ERASE_INSIDE_CIRCLE',
|
|
||||||
preview: {
|
|
||||||
previewColors: {}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
)
|
|
||||||
toolGroup.addToolInstance(
|
|
||||||
'ThresholdCircle',
|
|
||||||
BrushTool.toolName,
|
|
||||||
{
|
|
||||||
activeStrategy: 'THRESHOLD_INSIDE_CIRCLE',
|
|
||||||
}
|
|
||||||
)
|
|
||||||
toolGroup.addToolInstance(
|
|
||||||
'ThresholdSphere',
|
|
||||||
BrushTool.toolName,
|
|
||||||
{
|
|
||||||
activeStrategy: 'THRESHOLD_INSIDE_SPHERE',
|
|
||||||
}
|
|
||||||
)
|
|
||||||
toolGroup.addTool(LabelMapEditWithContourTool.toolName);
|
|
||||||
toolGroup.addTool(SegmentBidirectionalTool.toolName, {
|
|
||||||
getTextLines: this.getBidirectionalToolTextLines
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (volumeViewportIds.includes(viewportId)) {
|
|
||||||
toolGroup.addTool(WindowLevelTool.toolName, {
|
|
||||||
targetViewportIds: volumeViewportIds
|
|
||||||
})
|
|
||||||
toolGroup.addTool(CrosshairsTool.toolName, {
|
|
||||||
getReferenceLineColor: this.setCrosshairsToolLineColor
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
|
toolGroup.addTool(StackScrollTool.toolName, {
|
||||||
|
loop: true, // 启用循环滚动
|
||||||
|
})
|
||||||
|
|
||||||
|
toolGroup.addTool(ScaleOverlayTool.toolName)
|
||||||
|
|
||||||
|
toolGroup.addTool(PanTool.toolName)
|
||||||
|
toolGroup.addTool(ZoomTool.toolName)
|
||||||
|
toolGroup.addTool(BrushTool.toolName)
|
||||||
|
if (this.readingTool === 3 || toolGroupId === this.volumeToolGroupId) {
|
||||||
|
toolGroup.addToolInstance(
|
||||||
|
'histogram_RectangleROI',
|
||||||
|
RectangleROITool.toolName,
|
||||||
|
);
|
||||||
|
toolGroup.addToolInstance(
|
||||||
|
'histogram_CircleROI',
|
||||||
|
CircleROITool.toolName,
|
||||||
|
);
|
||||||
|
toolGroup.addToolInstance(
|
||||||
|
'histogram_PlanarFreehandROI',
|
||||||
|
PlanarFreehandROITool.toolName,
|
||||||
|
);
|
||||||
|
toolGroup.addToolInstance(
|
||||||
|
'CircularBrush',
|
||||||
|
BrushTool.toolName,
|
||||||
|
{
|
||||||
|
activeStrategy: 'FILL_INSIDE_CIRCLE',
|
||||||
|
preview: {
|
||||||
|
previewColors: {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
toolGroup.addToolInstance(
|
||||||
|
'CircularEraser',
|
||||||
|
BrushTool.toolName,
|
||||||
|
{
|
||||||
|
activeStrategy: 'ERASE_INSIDE_CIRCLE',
|
||||||
|
preview: {
|
||||||
|
previewColors: {}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
)
|
||||||
|
toolGroup.addToolInstance(
|
||||||
|
'ThresholdCircle',
|
||||||
|
BrushTool.toolName,
|
||||||
|
{
|
||||||
|
activeStrategy: 'THRESHOLD_INSIDE_CIRCLE',
|
||||||
|
}
|
||||||
|
)
|
||||||
|
toolGroup.addToolInstance(
|
||||||
|
'ThresholdSphere',
|
||||||
|
BrushTool.toolName,
|
||||||
|
{
|
||||||
|
activeStrategy: 'THRESHOLD_INSIDE_SPHERE',
|
||||||
|
}
|
||||||
|
)
|
||||||
|
toolGroup.addTool(LabelMapEditWithContourTool.toolName);
|
||||||
|
toolGroup.addTool(SegmentBidirectionalTool.toolName, {
|
||||||
|
getTextLines: this.getBidirectionalToolTextLines
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (volumeViewportIds.includes(viewportId)) {
|
||||||
|
toolGroup.addTool(WindowLevelTool.toolName, {
|
||||||
|
targetViewportIds: volumeViewportIds
|
||||||
|
})
|
||||||
|
toolGroup.addTool(CrosshairsTool.toolName, {
|
||||||
|
getReferenceLineColor: this.setCrosshairsToolLineColor
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
toolGroup.addTool(WindowLevelTool.toolName)
|
||||||
|
}
|
||||||
toolGroup.addTool(WindowLevelTool.toolName)
|
toolGroup.addTool(WindowLevelTool.toolName)
|
||||||
}
|
toolGroup.addTool(WindowLevelRegionTool.toolName)
|
||||||
toolGroup.addTool(WindowLevelTool.toolName)
|
toolGroup.addTool(PlanarRotateTool.toolName)
|
||||||
toolGroup.addTool(WindowLevelRegionTool.toolName)
|
toolGroup.addTool(ArrowAnnotateTool.toolName, {
|
||||||
toolGroup.addTool(PlanarRotateTool.toolName)
|
arrowHeadStyle: 'standard',
|
||||||
toolGroup.addTool(ArrowAnnotateTool.toolName, {
|
changeTextCallback: async (data, eventData, doneChangingTextCallback) => {
|
||||||
arrowHeadStyle: 'standard',
|
return doneChangingTextCallback(data.text)
|
||||||
changeTextCallback: async (data, eventData, doneChangingTextCallback) => {
|
},
|
||||||
return doneChangingTextCallback(data.text)
|
getTextCallback: async (doneChangingTextCallback) => {
|
||||||
},
|
return doneChangingTextCallback('Annotation')
|
||||||
getTextCallback: async (doneChangingTextCallback) => {
|
}
|
||||||
return doneChangingTextCallback('Annotation')
|
})
|
||||||
|
toolGroup.addTool(RectangleROITool.toolName, {
|
||||||
|
cachedStats: false,
|
||||||
|
getTextLines: this.criterionType === 0 ? this.getCustomRectangleROIToolTextLines : this.getRectangleROIToolTextLines
|
||||||
|
})
|
||||||
|
toolGroup.addTool(PlanarFreehandROITool.toolName, {
|
||||||
|
allowOpenContours: false,
|
||||||
|
cachedStats: false,
|
||||||
|
getTextLines: this.getPlanarFreehandROIToolTextLines
|
||||||
|
})
|
||||||
|
|
||||||
|
toolGroup.addTool(EraserTool.toolName)
|
||||||
|
toolGroup.addTool(LengthTool.toolName, {
|
||||||
|
getTextLines: this.getLengthToolTextLines
|
||||||
|
// cachedStats: false
|
||||||
|
})
|
||||||
|
toolGroup.addTool(BidirectionalTool.toolName, {
|
||||||
|
// cachedStats: true,
|
||||||
|
actions: this.actionConfiguration,
|
||||||
|
getTextLines: this.getBidirectionalToolTextLines
|
||||||
|
})
|
||||||
|
toolGroup.addTool(CircleROITool.toolName, {
|
||||||
|
getTextLines: this.getCircleROIToolTextLines
|
||||||
|
})
|
||||||
|
toolGroup.addTool(EllipticalROITool.toolName, {
|
||||||
|
getTextLines: this.getEllipticalROIToolTextLines
|
||||||
|
})
|
||||||
|
toolGroup.addTool(FixedRadiusCircleROITool.toolName), {
|
||||||
|
getTextLines: this.getCircleROIToolTextLines
|
||||||
}
|
}
|
||||||
})
|
toolGroup.addTool(AngleTool.toolName, {
|
||||||
toolGroup.addTool(RectangleROITool.toolName, {
|
getTextLines: this.getAngleToolTextLines
|
||||||
cachedStats: false,
|
|
||||||
getTextLines: this.criterionType === 0 ? this.getCustomRectangleROIToolTextLines : this.getRectangleROIToolTextLines
|
|
||||||
})
|
|
||||||
toolGroup.addTool(PlanarFreehandROITool.toolName, {
|
|
||||||
allowOpenContours: false,
|
|
||||||
cachedStats: false,
|
|
||||||
getTextLines: this.getPlanarFreehandROIToolTextLines
|
|
||||||
})
|
|
||||||
|
|
||||||
toolGroup.addTool(EraserTool.toolName)
|
|
||||||
toolGroup.addTool(LengthTool.toolName, {
|
|
||||||
getTextLines: this.getLengthToolTextLines
|
|
||||||
// cachedStats: false
|
|
||||||
})
|
|
||||||
toolGroup.addTool(BidirectionalTool.toolName, {
|
|
||||||
// cachedStats: true,
|
|
||||||
actions: this.actionConfiguration,
|
|
||||||
getTextLines: this.getBidirectionalToolTextLines
|
|
||||||
})
|
|
||||||
toolGroup.addTool(CircleROITool.toolName, {
|
|
||||||
getTextLines: this.getCircleROIToolTextLines
|
|
||||||
})
|
|
||||||
toolGroup.addTool(EllipticalROITool.toolName, {
|
|
||||||
getTextLines: this.getEllipticalROIToolTextLines
|
|
||||||
})
|
|
||||||
toolGroup.addTool(FixedRadiusCircleROITool.toolName), {
|
|
||||||
getTextLines: this.getCircleROIToolTextLines
|
|
||||||
}
|
|
||||||
toolGroup.addTool(AngleTool.toolName, {
|
|
||||||
getTextLines: this.getAngleToolTextLines
|
|
||||||
})
|
|
||||||
toolGroup.addTool(CobbAngleTool.toolName, {
|
|
||||||
getTextLines: this.getCobbAngleToolTextLines
|
|
||||||
})
|
|
||||||
if (toolGroupId === 'viewport-fusion-3') {
|
|
||||||
toolGroup.addTool(VolumeRotateTool.toolName)
|
|
||||||
toolGroup.setToolActive(VolumeRotateTool.toolName, {
|
|
||||||
bindings: [
|
|
||||||
{
|
|
||||||
mouseButton: MouseBindings.Wheel // mouse wheel
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
})
|
||||||
toolGroup.addTool(MIPJumpToClickTool.toolName, {
|
toolGroup.addTool(CobbAngleTool.toolName, {
|
||||||
targetViewportIds: fusionViewportIds.filter((id) => id !== toolGroupId)
|
getTextLines: this.getCobbAngleToolTextLines
|
||||||
})
|
})
|
||||||
|
if (toolGroupId === 'viewport-fusion-3') {
|
||||||
|
toolGroup.addTool(VolumeRotateTool.toolName)
|
||||||
|
toolGroup.setToolActive(VolumeRotateTool.toolName, {
|
||||||
|
bindings: [
|
||||||
|
{
|
||||||
|
mouseButton: MouseBindings.Wheel // mouse wheel
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
toolGroup.addTool(MIPJumpToClickTool.toolName, {
|
||||||
|
targetViewportIds: fusionViewportIds.filter((id) => id !== toolGroupId)
|
||||||
|
})
|
||||||
|
|
||||||
// Set the initial state of the tools, here we set one tool active on left click.
|
// Set the initial state of the tools, here we set one tool active on left click.
|
||||||
// This means left click will draw that tool.
|
// This means left click will draw that tool.
|
||||||
toolGroup.setToolActive(MIPJumpToClickTool.toolName, {
|
toolGroup.setToolActive(MIPJumpToClickTool.toolName, {
|
||||||
bindings: [
|
bindings: [
|
||||||
{
|
{
|
||||||
mouseButton: MouseBindings.Primary // Left Click
|
mouseButton: MouseBindings.Primary // Left Click
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
}
|
|
||||||
toolGroup.setToolConfiguration(
|
|
||||||
ScaleOverlayTool.toolName,
|
|
||||||
{
|
|
||||||
scaleLocation: 'bottom'
|
|
||||||
},
|
|
||||||
true // overwrite
|
|
||||||
)
|
|
||||||
toolGroup.setToolActive(StackScrollTool.toolName, {
|
|
||||||
bindings: [{ mouseButton: MouseBindings.Wheel }]
|
|
||||||
})
|
|
||||||
toolGroup.setToolActive(ZoomTool.toolName, {
|
|
||||||
bindings: [{ mouseButton: MouseBindings.Secondary }]
|
|
||||||
})
|
|
||||||
toolGroup.setToolActive(PanTool.toolName, {
|
|
||||||
bindings: [{ mouseButton: MouseBindings.Auxiliary }]
|
|
||||||
})
|
|
||||||
toolGroup.setToolPassive(WindowLevelTool.toolName)
|
|
||||||
toolGroup.setToolPassive(WindowLevelRegionTool.toolName)
|
|
||||||
toolGroup.setToolPassive(PlanarRotateTool.toolName)
|
|
||||||
|
|
||||||
if (this.readingTaskState < 2) {
|
|
||||||
toolGroup.setToolPassive(ArrowAnnotateTool.toolName)
|
|
||||||
toolGroup.setToolPassive(RectangleROITool.toolName)
|
|
||||||
toolGroup.setToolPassive(PlanarFreehandROITool.toolName)
|
|
||||||
toolGroup.setToolPassive(LengthTool.toolName)
|
|
||||||
toolGroup.setToolPassive(BidirectionalTool.toolName)
|
|
||||||
toolGroup.setToolPassive(CircleROITool.toolName)
|
|
||||||
toolGroup.setToolPassive(EllipticalROITool.toolName)
|
|
||||||
toolGroup.setToolPassive(FixedRadiusCircleROITool.toolName)
|
|
||||||
toolGroup.setToolPassive(AngleTool.toolName)
|
|
||||||
toolGroup.setToolPassive(CobbAngleTool.toolName)
|
|
||||||
if (this.readingTool === 3) {
|
|
||||||
toolGroup.setToolPassive(LabelMapEditWithContourTool.toolName)
|
|
||||||
toolGroup.setToolPassive(SegmentBidirectionalTool.toolName, {});
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
toolGroup.setToolEnabled(ArrowAnnotateTool.toolName)
|
toolGroup.setToolConfiguration(
|
||||||
toolGroup.setToolEnabled(RectangleROITool.toolName)
|
ScaleOverlayTool.toolName,
|
||||||
toolGroup.setToolEnabled(PlanarFreehandROITool.toolName)
|
{
|
||||||
toolGroup.setToolEnabled(LengthTool.toolName)
|
scaleLocation: 'bottom'
|
||||||
toolGroup.setToolEnabled(BidirectionalTool.toolName)
|
},
|
||||||
toolGroup.setToolEnabled(CircleROITool.toolName)
|
true // overwrite
|
||||||
toolGroup.setToolEnabled(EllipticalROITool.toolName)
|
)
|
||||||
toolGroup.setToolEnabled(FixedRadiusCircleROITool.toolName)
|
toolGroup.setToolActive(StackScrollTool.toolName, {
|
||||||
toolGroup.setToolEnabled(AngleTool.toolName)
|
bindings: [{ mouseButton: MouseBindings.Wheel }]
|
||||||
toolGroup.setToolEnabled(CobbAngleTool.toolName)
|
})
|
||||||
if (this.readingTool === 3) toolGroup.setToolEnabled(LabelMapEditWithContourTool.toolName)
|
toolGroup.setToolActive(ZoomTool.toolName, {
|
||||||
|
bindings: [{ mouseButton: MouseBindings.Secondary }]
|
||||||
|
})
|
||||||
|
toolGroup.setToolActive(PanTool.toolName, {
|
||||||
|
bindings: [{ mouseButton: MouseBindings.Auxiliary }]
|
||||||
|
})
|
||||||
|
toolGroup.setToolPassive(WindowLevelTool.toolName)
|
||||||
|
toolGroup.setToolPassive(WindowLevelRegionTool.toolName)
|
||||||
|
toolGroup.setToolPassive(PlanarRotateTool.toolName)
|
||||||
|
|
||||||
|
if (this.readingTaskState < 2) {
|
||||||
|
toolGroup.setToolPassive(ArrowAnnotateTool.toolName)
|
||||||
|
toolGroup.setToolPassive(RectangleROITool.toolName)
|
||||||
|
toolGroup.setToolPassive(PlanarFreehandROITool.toolName)
|
||||||
|
toolGroup.setToolPassive(LengthTool.toolName)
|
||||||
|
toolGroup.setToolPassive(BidirectionalTool.toolName)
|
||||||
|
toolGroup.setToolPassive(CircleROITool.toolName)
|
||||||
|
toolGroup.setToolPassive(EllipticalROITool.toolName)
|
||||||
|
toolGroup.setToolPassive(FixedRadiusCircleROITool.toolName)
|
||||||
|
toolGroup.setToolPassive(AngleTool.toolName)
|
||||||
|
toolGroup.setToolPassive(CobbAngleTool.toolName)
|
||||||
|
if (this.readingTool === 3) {
|
||||||
|
toolGroup.setToolPassive(LabelMapEditWithContourTool.toolName)
|
||||||
|
toolGroup.setToolPassive(SegmentBidirectionalTool.toolName, {});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
toolGroup.setToolEnabled(ArrowAnnotateTool.toolName)
|
||||||
|
toolGroup.setToolEnabled(RectangleROITool.toolName)
|
||||||
|
toolGroup.setToolEnabled(PlanarFreehandROITool.toolName)
|
||||||
|
toolGroup.setToolEnabled(LengthTool.toolName)
|
||||||
|
toolGroup.setToolEnabled(BidirectionalTool.toolName)
|
||||||
|
toolGroup.setToolEnabled(CircleROITool.toolName)
|
||||||
|
toolGroup.setToolEnabled(EllipticalROITool.toolName)
|
||||||
|
toolGroup.setToolEnabled(FixedRadiusCircleROITool.toolName)
|
||||||
|
toolGroup.setToolEnabled(AngleTool.toolName)
|
||||||
|
toolGroup.setToolEnabled(CobbAngleTool.toolName)
|
||||||
|
if (this.readingTool === 3) toolGroup.setToolEnabled(LabelMapEditWithContourTool.toolName)
|
||||||
|
}
|
||||||
|
toolGroup.setToolPassive(EraserTool.toolName)
|
||||||
}
|
}
|
||||||
toolGroup.setToolPassive(EraserTool.toolName)
|
|
||||||
})
|
})
|
||||||
eventTarget.addEventListener('cornerstoneimageloadprogress', this.imageLoadProgress)
|
eventTarget.addEventListener('cornerstoneimageloadprogress', this.imageLoadProgress)
|
||||||
// console.log(Events, toolsEvents)
|
// console.log(Events, toolsEvents)
|
||||||
|
|
@ -2627,7 +2716,7 @@ export default {
|
||||||
viewport.render()
|
viewport.render()
|
||||||
renderingEngine.render()
|
renderingEngine.render()
|
||||||
if (this.readingTool === 3) {
|
if (this.readingTool === 3) {
|
||||||
DicomEvent.$emit('isloaded', { isChange: false })
|
DicomEvent.$emit('isloaded', { isChange: false, viewportId })
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// 更改视图布局
|
// 更改视图布局
|
||||||
|
|
@ -2907,25 +2996,25 @@ export default {
|
||||||
this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].resize(forceFitToWindow)
|
this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].resize(forceFitToWindow)
|
||||||
},
|
},
|
||||||
// 重置视口
|
// 重置视口
|
||||||
resetRenderingEngine(viewportId = null) {
|
resetRenderingEngine(viewportId = null, i) {
|
||||||
if (this.timer) {
|
if (this.timer[viewportId]) {
|
||||||
clearInterval(this.timer)
|
clearInterval(this.timer[viewportId])
|
||||||
this.timer = null
|
this.timer[viewportId] = null
|
||||||
}
|
}
|
||||||
const renderingEngine = getRenderingEngine(renderingEngineId)
|
const renderingEngine = getRenderingEngine(renderingEngineId)
|
||||||
const viewport = renderingEngine.getViewport(viewportId)
|
const viewport = renderingEngine.getViewport(viewportId)
|
||||||
if (!viewport) return false
|
if (!viewport) return false
|
||||||
if (viewport.volumeIds.size <= 0) return false
|
if (viewport.volumeIds.size <= 0) return false
|
||||||
let index = null
|
let index = null
|
||||||
this.timer = setTimeout(() => {
|
this.timer[viewportId] = setTimeout(() => {
|
||||||
index = index || index === 0 ? index : this.$refs[viewportId ? viewportId : `${this.viewportKey}-${this.activeViewportIndex}`][0].series.SliceIndex
|
index = i || i === 0 ? i : this.$refs[viewportId ? viewportId : `${this.viewportKey}-${this.activeViewportIndex}`][0].series.SliceIndex
|
||||||
renderingEngine.resize(true, false)
|
renderingEngine.resize(true, false)
|
||||||
renderingEngine.render()
|
renderingEngine.render()
|
||||||
this.$refs[viewportId ? viewportId : `${this.viewportKey}-${this.activeViewportIndex}`][0].setFullScreen(index)
|
this.$refs[viewportId ? viewportId : `${this.viewportKey}-${this.activeViewportIndex}`][0].setFullScreen(index)
|
||||||
clearTimeout(this.timer)
|
clearTimeout(this.timer[viewportId])
|
||||||
this.timer = null
|
this.timer[viewportId] = null
|
||||||
if (this.readingTool === 3) {
|
if (this.readingTool === 3) {
|
||||||
DicomEvent.$emit('isloaded', { isChange: false })
|
DicomEvent.$emit('isloaded', { isChange: false, viewportId })
|
||||||
}
|
}
|
||||||
}, 100)
|
}, 100)
|
||||||
},
|
},
|
||||||
|
|
@ -2946,7 +3035,7 @@ export default {
|
||||||
if (this.readingTool === 3 || this.isMPR) {
|
if (this.readingTool === 3 || this.isMPR) {
|
||||||
// this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].setSeriesInfo(this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series)
|
// this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].setSeriesInfo(this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series)
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.resetRenderingEngine()
|
// this.resetRenderingEngine(`${this.viewportKey}-${index}`)
|
||||||
this.isDelay = true
|
this.isDelay = true
|
||||||
this.setDelay(2000)
|
this.setDelay(2000)
|
||||||
// if (this.readingTool === 3) {
|
// if (this.readingTool === 3) {
|
||||||
|
|
@ -4048,8 +4137,13 @@ export default {
|
||||||
this.saveCustomAnnotationTimer = null
|
this.saveCustomAnnotationTimer = null
|
||||||
}
|
}
|
||||||
if (this.timer) {
|
if (this.timer) {
|
||||||
clearInterval(this.timer)
|
Object.keys(this.timer).forEach(key => {
|
||||||
this.timer = null
|
if (this.timer[key]) {
|
||||||
|
clearInterval(this.timer[key])
|
||||||
|
this.timer[key] = null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.timer = {}
|
||||||
}
|
}
|
||||||
if (this.FullTimerOut) {
|
if (this.FullTimerOut) {
|
||||||
clearTimeout(this.FullTimerOut)
|
clearTimeout(this.FullTimerOut)
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,8 @@
|
||||||
@click.stop="changeShowSegmentConfig" />
|
@click.stop="changeShowSegmentConfig" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div class="addSegmentBox viewHover" @click.stop="addSegment" v-if="segmentList.length <= 0">
|
<div class="addSegmentBox viewHover" @click.stop="addSegment"
|
||||||
|
v-if="segmentList.length <= 0 && readingTaskState < 2">
|
||||||
<span><i class="el-icon-plus"></i>
|
<span><i class="el-icon-plus"></i>
|
||||||
{{ $t('trials:reading:Segmentations:button:addSegmention') }}
|
{{ $t('trials:reading:Segmentations:button:addSegmention') }}
|
||||||
</span>
|
</span>
|
||||||
|
|
@ -124,16 +125,11 @@
|
||||||
$t('trials:reading:Segmentations:title:InactiveSegmentationsShow')
|
$t('trials:reading:Segmentations:title:InactiveSegmentationsShow')
|
||||||
}}</span>
|
}}</span>
|
||||||
</div>
|
</div>
|
||||||
<!-- <div class="SegmentConfig" v-if="SegmentConfig.InactiveSegmentations.show">
|
|
||||||
<span>{{ $t('trials:reading:Segmentations:title:Opacity') }}</span>
|
|
||||||
<el-slider v-model="SegmentConfig.InactiveSegmentations.fillAlpha" show-input :step="0.1"
|
|
||||||
:max="1" input-size="mini" :show-input-controls="false" />
|
|
||||||
</div> -->
|
|
||||||
</div>
|
</div>
|
||||||
<template v-if="segmentList.length > 0">
|
<template v-if="segmentList.length > 0">
|
||||||
<div class="SegmentGroupBox">
|
<div class="SegmentGroupBox">
|
||||||
<div style="display: flex;align-items: center;">
|
<div style="display: flex;align-items: center;">
|
||||||
<el-popover placement="left" width="40" trigger="click">
|
<el-popover placement="left" width="40" trigger="click" v-if="readingTaskState < 2">
|
||||||
<div class="SegmentGroupBtnBox">
|
<div class="SegmentGroupBtnBox">
|
||||||
<div class="SegmentGroupBtn" @click.stop="addSegmentGroup">
|
<div class="SegmentGroupBtn" @click.stop="addSegmentGroup">
|
||||||
{{ $t('trials:reading:Segmentations:button:addSegmentGroup') }}
|
{{ $t('trials:reading:Segmentations:button:addSegmentGroup') }}
|
||||||
|
|
@ -156,7 +152,7 @@
|
||||||
</el-option>
|
</el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
</div>
|
</div>
|
||||||
<div style="display: flex;align-items: center;">
|
<div style="display: flex;align-items: center;" v-if="readingTaskState < 2">
|
||||||
<i class="el-icon-warning-outline" style="color:red;margin-right: 5px;"
|
<i class="el-icon-warning-outline" style="color:red;margin-right: 5px;"
|
||||||
:title="$t('trials:reading:Segmentations:tip:segmentationIsNotSave')"
|
:title="$t('trials:reading:Segmentations:tip:segmentationIsNotSave')"
|
||||||
v-if="!curSegmentGroup.isSaved"></i>
|
v-if="!curSegmentGroup.isSaved"></i>
|
||||||
|
|
@ -167,7 +163,8 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="addSegmentBox" @click.stop="addSegment"
|
<div class="addSegmentBox" @click.stop="addSegment"
|
||||||
style="display: flex;align-items: center;justify-content: space-between;">
|
style="display: flex;align-items: center;justify-content: space-between;"
|
||||||
|
v-if="readingTaskState < 2">
|
||||||
<span><i class="el-icon-plus"></i>
|
<span><i class="el-icon-plus"></i>
|
||||||
{{ $t('trials:reading:Segmentations:button:addSegment') }}
|
{{ $t('trials:reading:Segmentations:button:addSegment') }}
|
||||||
</span>
|
</span>
|
||||||
|
|
@ -220,7 +217,7 @@
|
||||||
<i class="el-icon-lock" v-if="item.lock" @click.stop="lockSegment(item, false)"></i>
|
<i class="el-icon-lock" v-if="item.lock" @click.stop="lockSegment(item, false)"></i>
|
||||||
<el-popover placement="bottom" width="40" trigger="click" class="docShow"
|
<el-popover placement="bottom" width="40" trigger="click" class="docShow"
|
||||||
:value="popoverId === `popover-${item.segmentationId}_${item.segmentIndex}`"
|
:value="popoverId === `popover-${item.segmentationId}_${item.segmentIndex}`"
|
||||||
@show="handleClickPopover(item)">
|
@show="handleClickPopover(item)" v-if="readingTaskState < 2">
|
||||||
<div class="SegmentGroupBtnBox">
|
<div class="SegmentGroupBtnBox">
|
||||||
<div class="SegmentGroupBtn" @click.stop="rename('segment', item)">
|
<div class="SegmentGroupBtn" @click.stop="rename('segment', item)">
|
||||||
{{ $t('trials:reading:Segmentations:button:renameSegmentGroup') }}
|
{{ $t('trials:reading:Segmentations:button:renameSegmentGroup') }}
|
||||||
|
|
@ -245,7 +242,7 @@
|
||||||
</template>
|
</template>
|
||||||
</el-collapse-item>
|
</el-collapse-item>
|
||||||
</el-collapse>
|
</el-collapse>
|
||||||
<div class="saveBtnBox">
|
<div class="saveBtnBox" v-if="readingTaskState < 2">
|
||||||
<el-button type="success" size="small" :disabled="saveLoading" @click="saveSegmentGroup()">
|
<el-button type="success" size="small" :disabled="saveLoading" @click="saveSegmentGroup()">
|
||||||
{{ $t("trials:reading:Segmentations:button:saveAll") }}
|
{{ $t("trials:reading:Segmentations:button:saveAll") }}
|
||||||
</el-button>
|
</el-button>
|
||||||
|
|
@ -261,6 +258,8 @@ import * as cornerstoneAdapters from "@cornerstonejs/adapters";
|
||||||
import cornerstoneDICOMImageLoader from '@cornerstonejs/dicom-image-loader'
|
import cornerstoneDICOMImageLoader from '@cornerstonejs/dicom-image-loader'
|
||||||
import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent'
|
import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent'
|
||||||
import { getCustomizeStandardsSegmentDicomTools } from './toolConfig'
|
import { getCustomizeStandardsSegmentDicomTools } from './toolConfig'
|
||||||
|
import * as polySeg from '@cornerstonejs/polymorphic-segmentation'
|
||||||
|
cornerstoneTools.init({ addons: { polySeg } })
|
||||||
const {
|
const {
|
||||||
ToolGroupManager,
|
ToolGroupManager,
|
||||||
Enums: csToolsEnums,
|
Enums: csToolsEnums,
|
||||||
|
|
@ -271,6 +270,7 @@ const {
|
||||||
CrosshairsTool,
|
CrosshairsTool,
|
||||||
utilities: CStUtils,
|
utilities: CStUtils,
|
||||||
} = cornerstoneTools;
|
} = cornerstoneTools;
|
||||||
|
|
||||||
const { MouseBindings, Events: toolsEvents } = csToolsEnums
|
const { MouseBindings, Events: toolsEvents } = csToolsEnums
|
||||||
const { segmentation: segmentationUtils } = CStUtils;
|
const { segmentation: segmentationUtils } = CStUtils;
|
||||||
const { cache, getRenderingEngine, imageLoader, eventTarget, metaData, utilities: csUtils, volumeLoader } = cornerstone;
|
const { cache, getRenderingEngine, imageLoader, eventTarget, metaData, utilities: csUtils, volumeLoader } = cornerstone;
|
||||||
|
|
@ -305,12 +305,32 @@ export default {
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
SegmentConfig: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
actionConfiguration: {
|
actionConfiguration: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => {
|
default: () => {
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
curSegSeries: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
segId: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
segIndex: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
renderingEngineId: {
|
renderingEngineId: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true
|
required: true
|
||||||
|
|
@ -343,16 +363,6 @@ export default {
|
||||||
ThresholdTools: ['ThresholdCircle', 'ThresholdSphere'],
|
ThresholdTools: ['ThresholdCircle', 'ThresholdSphere'],
|
||||||
thresholdType: null,
|
thresholdType: null,
|
||||||
showSegmentConfig: false,
|
showSegmentConfig: false,
|
||||||
SegmentConfig: {
|
|
||||||
renderOutline: true,
|
|
||||||
renderFill: true,
|
|
||||||
fillAlpha: 0.5,
|
|
||||||
outlineWidth: 1,
|
|
||||||
InactiveSegmentations: {
|
|
||||||
show: true,
|
|
||||||
fillAlpha: 0.3,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
segmentList: [],
|
segmentList: [],
|
||||||
segmentationId: "",
|
segmentationId: "",
|
||||||
segmentIndex: null,
|
segmentIndex: null,
|
||||||
|
|
@ -368,7 +378,7 @@ export default {
|
||||||
'#ff994d',
|
'#ff994d',
|
||||||
'#fb628b',
|
'#fb628b',
|
||||||
],
|
],
|
||||||
viewprotIds: ['viewport-0', 'viewport-1', 'viewport-2', 'viewport-3', 'viewport-MPR-0', 'viewport-MPR-1', 'viewport-MPR-2'], //
|
viewportIds: [], //
|
||||||
statsKey: [],
|
statsKey: [],
|
||||||
drawing: false, // 是否正在分割
|
drawing: false, // 是否正在分割
|
||||||
// isDel: false,
|
// isDel: false,
|
||||||
|
|
@ -388,14 +398,24 @@ export default {
|
||||||
this.segmentationModifiedCallback
|
this.segmentationModifiedCallback
|
||||||
);
|
);
|
||||||
DicomEvent.$on('activeSeries', (series) => {
|
DicomEvent.$on('activeSeries', (series) => {
|
||||||
|
console.log(series, 'series')
|
||||||
|
let { TaskInfo = {}, Id } = series
|
||||||
|
if (Id === this.series.Id && TaskInfo.VisitTaskId === this.visitInfo.VisitTaskId) return false
|
||||||
this.series = series
|
this.series = series
|
||||||
|
this.$emit("update:curSegSeries", Object.assign(series, {}))
|
||||||
|
this.getSegmentationList()
|
||||||
})
|
})
|
||||||
DicomEvent.$on('isloaded', (data) => {
|
DicomEvent.$on('isloaded', (data) => {
|
||||||
if (this.isloaded) return false
|
let { segment, isChange = true, viewportId, series } = data
|
||||||
this.isloaded = true
|
DicomEvent.$emit('renderSegmentation', viewportId)
|
||||||
let { segment, isChange = true } = data
|
// if (!series.TaskInfo || series.TaskInfo.VisitTaskId !== this.visitInfo.VisitTaskId) return false
|
||||||
this.delAllSegment(isChange)
|
// if (this.isloaded) return false
|
||||||
this.getSegmentationList(segment)
|
// this.isloaded = true
|
||||||
|
// this.series = series
|
||||||
|
// this.viewportIds = []
|
||||||
|
// this.viewportIds.push(viewportId)
|
||||||
|
// // this.delAllSegment(isChange)
|
||||||
|
// this.readingSegmentToViewport(segment)
|
||||||
})
|
})
|
||||||
const digitPlaces = Number(localStorage.getItem('digitPlaces'))
|
const digitPlaces = Number(localStorage.getItem('digitPlaces'))
|
||||||
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
|
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
|
||||||
|
|
@ -414,12 +434,15 @@ export default {
|
||||||
s = this.curSegmentGroup.segments.find(item => item.segmentIndex === this.segmentIndex)
|
s = this.curSegmentGroup.segments.find(item => item.segmentIndex === this.segmentIndex)
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
|
},
|
||||||
|
readingTaskState() {
|
||||||
|
return this.series.TaskInfo ? this.series.TaskInfo.ReadingTaskState : 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
SegmentConfig: {
|
SegmentConfig: {
|
||||||
handler() {
|
handler() {
|
||||||
this.readingSegmentByConfig()
|
// this.readingSegmentByConfig()
|
||||||
},
|
},
|
||||||
deep: true
|
deep: true
|
||||||
},
|
},
|
||||||
|
|
@ -434,9 +457,23 @@ export default {
|
||||||
this.setBrushThreshold()
|
this.setBrushThreshold()
|
||||||
},
|
},
|
||||||
deep: true
|
deep: true
|
||||||
|
},
|
||||||
|
segmentIndex() {
|
||||||
|
this.$emit('update:segIndex', this.segmentIndex)
|
||||||
|
},
|
||||||
|
segmentationId() {
|
||||||
|
this.$emit('update:segId', this.segmentationId)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
showSurface(item) {
|
||||||
|
this.$emit("showSurface", {
|
||||||
|
segmentationId: item.segmentationId,
|
||||||
|
segmentIndex: item.segmentIndex,
|
||||||
|
volumeId: this.series.SeriesInstanceUid,
|
||||||
|
segmentations: this.curSegmentGroup
|
||||||
|
})
|
||||||
|
},
|
||||||
handleClickPopover(item) {
|
handleClickPopover(item) {
|
||||||
this.popoverId = `popover-${item.segmentationId}_${item.segmentIndex}`
|
this.popoverId = `popover-${item.segmentationId}_${item.segmentIndex}`
|
||||||
},
|
},
|
||||||
|
|
@ -504,7 +541,6 @@ export default {
|
||||||
segmentationId: list[0].segmentationId,
|
segmentationId: list[0].segmentationId,
|
||||||
segmentIndices: list.map(item => item.segmentIndex),
|
segmentIndices: list.map(item => item.segmentIndex),
|
||||||
});
|
});
|
||||||
console.log(bidirectionalData, list[0].segmentationId, 'bidirectionalData')
|
|
||||||
if (bidirectionalData.length <= 0) {
|
if (bidirectionalData.length <= 0) {
|
||||||
list.forEach(item => {
|
list.forEach(item => {
|
||||||
let annotations = annotation.state.getAllAnnotations().filter(i => i.metadata.segmentationId === item.segmentationId && i.metadata.segmentIndex === item.segmentIndex);
|
let annotations = annotation.state.getAllAnnotations().filter(i => i.metadata.segmentationId === item.segmentationId && i.metadata.segmentIndex === item.segmentIndex);
|
||||||
|
|
@ -563,6 +599,7 @@ export default {
|
||||||
|
|
||||||
},
|
},
|
||||||
setToolActive(toolName) {
|
setToolActive(toolName) {
|
||||||
|
// if (!this.series.TaskInfo || this.series.TaskInfo.VisitTaskId !== this.visitInfo.VisitTaskId) return false
|
||||||
if (this.segmentList.length <= 0) return false
|
if (this.segmentList.length <= 0) return false
|
||||||
if (this.curSegment.lock) return false
|
if (this.curSegment.lock) return false
|
||||||
if (this.histogramVisible && !this.ThresholdTools.includes(toolName)) return false
|
if (this.histogramVisible && !this.ThresholdTools.includes(toolName)) return false
|
||||||
|
|
@ -602,71 +639,33 @@ export default {
|
||||||
viewBidirectional(arr, view) {
|
viewBidirectional(arr, view) {
|
||||||
for (let j = 0; j < arr.length; j++) {
|
for (let j = 0; j < arr.length; j++) {
|
||||||
let item = arr[j]
|
let item = arr[j]
|
||||||
let bidirectional = annotation.state.getAllAnnotations().find(i => i.metadata.segmentationId === item.segmentationId && i.metadata.segmentIndex === item.segmentIndex && i.metadata.toolName === "SegmentBidirectional");
|
|
||||||
item.bidirectionalView = view
|
item.bidirectionalView = view
|
||||||
if (!bidirectional) continue
|
// let bidirectional = annotation.state.getAllAnnotations().find(i => i.metadata.segmentationId === item.segmentationId && i.metadata.segmentIndex === item.segmentIndex && i.metadata.toolName === "SegmentBidirectional");
|
||||||
annotation.visibility.setAnnotationVisibility(bidirectional.annotationUID, view)
|
// item.bidirectionalView = view
|
||||||
|
// if (!bidirectional) continue
|
||||||
|
// annotation.visibility.setAnnotationVisibility(bidirectional.annotationUID, view)
|
||||||
}
|
}
|
||||||
this.resetViewport()
|
DicomEvent.$emit('viewBidirectional', arr)
|
||||||
|
// this.resetViewport()
|
||||||
},
|
},
|
||||||
async jumpBidirectional(item) {
|
async jumpBidirectional(item) {
|
||||||
if (item.bidirectional) {
|
DicomEvent.$emit('jumpBidirectional', item)
|
||||||
let an = annotation.state.getAllAnnotations().find(i => i.metadata.segmentationId === item.segmentationId && i.metadata.segmentIndex === item.segmentIndex && i.metadata.toolName === "SegmentBidirectional");
|
|
||||||
console.log(an, 'an')
|
|
||||||
if (!an) return false
|
|
||||||
|
|
||||||
const renderingEngine = getRenderingEngine(this.renderingEngineId)
|
|
||||||
const viewportId = `${this.viewportKey}-${this.activeViewportIndex}`
|
|
||||||
const viewport = renderingEngine.getViewport(viewportId)
|
|
||||||
let key = Object.keys(an.data.cachedStats)[0]; // referencedImageId
|
|
||||||
if (key) {
|
|
||||||
let sliceIndex = key.split("?")[1].split("&")[0].split("=")[1]
|
|
||||||
csUtils.jumpToSlice(viewport.element, { imageIndex: sliceIndex });
|
|
||||||
} else {
|
|
||||||
const points = an.data.handles.points;
|
|
||||||
const worldPoint = points[0]; // 取一个点
|
|
||||||
let volume = cache.getVolume(this.series.SeriesInstanceUid)
|
|
||||||
let { imageData, numFrames } = volume
|
|
||||||
const ijk = imageData.worldToIndex(worldPoint);
|
|
||||||
const sliceIndex = Math.abs(Math.round(ijk[2]));
|
|
||||||
// console.log(sliceIndex, 'sliceIndex')
|
|
||||||
csUtils.jumpToSlice(viewport.element, { imageIndex: numFrames - sliceIndex - 1 });
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
viewSegmentGroup(item) {
|
viewSegmentGroup(item) {
|
||||||
let view = !item.view
|
item.view = !item.view
|
||||||
this.viewprotIds.forEach(id => {
|
|
||||||
segmentation.config.visibility.setSegmentationRepresentationVisibility(
|
|
||||||
id,
|
|
||||||
{
|
|
||||||
segmentationId: item.segmentationId,
|
|
||||||
type: csToolsEnums.SegmentationRepresentations.Labelmap,
|
|
||||||
},
|
|
||||||
view
|
|
||||||
);
|
|
||||||
})
|
|
||||||
item.view = view
|
|
||||||
|
|
||||||
item.segments.forEach(i => {
|
item.segments.forEach(i => {
|
||||||
i.view = view
|
i.view = item.view
|
||||||
// this.viewBidirectional(i, view)
|
|
||||||
})
|
})
|
||||||
this.viewBidirectional(item.segments, view)
|
DicomEvent.$emit('viewSegmentation', item)
|
||||||
|
// this.viewBidirectional(item.segments, view)
|
||||||
},
|
},
|
||||||
viewSegment(item, view) {
|
viewSegment(item, view) {
|
||||||
this.viewprotIds.forEach(id => {
|
|
||||||
segmentation.config.visibility.setSegmentIndexVisibility(id, {
|
|
||||||
segmentationId: item.segmentationId,
|
|
||||||
type: csToolsEnums.SegmentationRepresentations.Labelmap,
|
|
||||||
}, item.segmentIndex, view)
|
|
||||||
})
|
|
||||||
item.view = view
|
item.view = view
|
||||||
this.viewBidirectional([item], view)
|
|
||||||
this.$emit('setToolsPassive')
|
this.$emit('setToolsPassive')
|
||||||
|
DicomEvent.$emit('viewSegment', item)
|
||||||
},
|
},
|
||||||
lockSegment(item, lock) {
|
lockSegment(item, lock) {
|
||||||
|
if (this.readingTaskState >= 2) return false
|
||||||
segmentation.segmentLocking.setSegmentIndexLocked(item.segmentationId, item.segmentIndex, lock)
|
segmentation.segmentLocking.setSegmentIndexLocked(item.segmentationId, item.segmentIndex, lock)
|
||||||
item.lock = lock
|
item.lock = lock
|
||||||
if (!lock) this.changeSegmentationSavedStatus(item.segmentationId, lock)
|
if (!lock) this.changeSegmentationSavedStatus(item.segmentationId, lock)
|
||||||
|
|
@ -676,7 +675,7 @@ export default {
|
||||||
this.segmentationId = item.segmentationId;
|
this.segmentationId = item.segmentationId;
|
||||||
this.segmentIndex = item.segmentIndex;
|
this.segmentIndex = item.segmentIndex;
|
||||||
}
|
}
|
||||||
segmentation.segmentIndex.setActiveSegmentIndex(item.segmentationId, item.segmentIndex);
|
// segmentation.segmentIndex.setActiveSegmentIndex(item.segmentationId, item.segmentIndex);
|
||||||
if (isChange) { this.jumpBidirectional(item) }
|
if (isChange) { this.jumpBidirectional(item) }
|
||||||
|
|
||||||
if (item.lock) {
|
if (item.lock) {
|
||||||
|
|
@ -685,15 +684,14 @@ export default {
|
||||||
// this.resetViewport()
|
// this.resetViewport()
|
||||||
},
|
},
|
||||||
selectSegmentGroup(s) {
|
selectSegmentGroup(s) {
|
||||||
this.viewprotIds.forEach(id => {
|
// segmentation.activeSegmentation.setActiveSegmentation(`${this.viewportKey}-${this.activeViewportIndex}`, this.segmentationId)
|
||||||
segmentation.activeSegmentation.setActiveSegmentation(id, this.segmentationId)
|
|
||||||
})
|
|
||||||
let segment = s ? s : this.segmentList.find(item => item.segmentationId === this.segmentationId).segments[0]
|
let segment = s ? s : this.segmentList.find(item => item.segmentationId === this.segmentationId).segments[0]
|
||||||
this.selectSegment(segment, s ? false : true)
|
this.segmentIndex = segment.segmentIndex
|
||||||
this.readingSegmentByConfig()
|
// this.selectSegment(segment, s ? false : true)
|
||||||
|
// this.readingSegmentByConfig()
|
||||||
},
|
},
|
||||||
async addSegmentGroup() {
|
async addSegmentGroup() {
|
||||||
let viewprotIds = this.viewprotIds
|
let viewportIds = this.viewportIds
|
||||||
// let segmentationId = this.$guid();
|
// let segmentationId = this.$guid();
|
||||||
let obj = {
|
let obj = {
|
||||||
name: this.$t('trials:reading:Segmentations:name:SegmentGroup') + (this.segmentList.length + 1),
|
name: this.$t('trials:reading:Segmentations:name:SegmentGroup') + (this.segmentList.length + 1),
|
||||||
|
|
@ -723,13 +721,14 @@ export default {
|
||||||
await this.createSegmentation(obj.segmentationId)
|
await this.createSegmentation(obj.segmentationId)
|
||||||
this.createSegmentationRepresentation(obj.segmentationId)
|
this.createSegmentationRepresentation(obj.segmentationId)
|
||||||
this.segmentIndex = 1
|
this.segmentIndex = 1
|
||||||
viewprotIds.forEach(id => {
|
this.changeColor(this.colors[0], { segmentationId: obj.segmentationId, segmentIndex: 1, color: this.colors[0] })
|
||||||
segmentation.config.color.setSegmentIndexColor(id, obj.segmentationId, 1, this.hex2Rgb(this.colors[0]))
|
// viewportIds.forEach(id => {
|
||||||
})
|
// segmentation.config.color.setSegmentIndexColor(id, obj.segmentationId, 1, this.hex2Rgb(this.colors[0]))
|
||||||
|
// })
|
||||||
this.selectSegmentGroup()
|
this.selectSegmentGroup()
|
||||||
},
|
},
|
||||||
async addSegment() {
|
async addSegment() {
|
||||||
let viewprotIds = this.viewprotIds;
|
let viewportIds = this.viewportIds;
|
||||||
if (this.segmentList.length <= 0) {
|
if (this.segmentList.length <= 0) {
|
||||||
let obj = {
|
let obj = {
|
||||||
name: this.$t('trials:reading:Segmentations:name:SegmentGroup') + 1,
|
name: this.$t('trials:reading:Segmentations:name:SegmentGroup') + 1,
|
||||||
|
|
@ -759,10 +758,11 @@ export default {
|
||||||
this.createSegmentationRepresentation(this.segmentationId)
|
this.createSegmentationRepresentation(this.segmentationId)
|
||||||
this.segmentIndex = 1
|
this.segmentIndex = 1
|
||||||
segmentation.segmentIndex.setActiveSegmentIndex(this.segmentList[0].segmentationId, 1);
|
segmentation.segmentIndex.setActiveSegmentIndex(this.segmentList[0].segmentationId, 1);
|
||||||
viewprotIds.forEach(id => {
|
this.changeColor(this.colors[0], { segmentationId: this.segmentList[0].segmentationId, segmentIndex: 1, color: this.colors[0] })
|
||||||
segmentation.config.color.setSegmentIndexColor(id, this.segmentList[0].segmentationId, 1, this.hex2Rgb(this.colors[0]))
|
// viewportIds.forEach(id => {
|
||||||
})
|
// segmentation.config.color.setSegmentIndexColor(id, this.segmentList[0].segmentationId, 1, this.hex2Rgb(this.colors[0]))
|
||||||
this.readingSegmentByConfig()
|
// })
|
||||||
|
// this.readingSegmentByConfig()
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
let item = this.segmentList.find(i => i.segmentationId === this.segmentationId)
|
let item = this.segmentList.find(i => i.segmentationId === this.segmentationId)
|
||||||
|
|
@ -787,19 +787,22 @@ export default {
|
||||||
let id = await this.addOrUpdateSegment({ name: obj.SegmentLabel, color: obj.color, segmentIndex: obj.segmentIndex, segmentationId: obj.segmentationId })
|
let id = await this.addOrUpdateSegment({ name: obj.SegmentLabel, color: obj.color, segmentIndex: obj.segmentIndex, segmentationId: obj.segmentationId })
|
||||||
obj.id = id
|
obj.id = id
|
||||||
item.segments.push(obj)
|
item.segments.push(obj)
|
||||||
segmentation.segmentIndex.setActiveSegmentIndex(obj.segmentationId, obj.segmentIndex);
|
|
||||||
viewprotIds.forEach(id => {
|
|
||||||
segmentation.config.color.setSegmentIndexColor(id, obj.segmentationId, obj.segmentIndex, this.hex2Rgb(obj.color))
|
|
||||||
})
|
|
||||||
this.segmentIndex = obj.segmentIndex
|
this.segmentIndex = obj.segmentIndex
|
||||||
|
segmentation.segmentIndex.setActiveSegmentIndex(obj.segmentationId, obj.segmentIndex);
|
||||||
|
this.changeColor(obj.color, { segmentationId: obj.segmentationId, segmentIndex: obj.segmentIndex, color: obj.color })
|
||||||
|
// viewportIds.forEach(id => {
|
||||||
|
// segmentation.config.color.setSegmentIndexColor(id, obj.segmentationId, obj.segmentIndex, this.hex2Rgb(obj.color))
|
||||||
|
// })
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
},
|
},
|
||||||
changeColor(e, item) {
|
changeColor(e, item) {
|
||||||
this.viewprotIds.forEach(id => {
|
DicomEvent.$emit('changeColor', item)
|
||||||
segmentation.config.color.setSegmentIndexColor(id, item.segmentationId, item.segmentIndex, this.hex2Rgb(e))
|
// this.viewportIds.forEach(id => {
|
||||||
})
|
// segmentation.config.color.setSegmentIndexColor(id, item.segmentationId, item.segmentIndex, this.hex2Rgb(e))
|
||||||
|
// })
|
||||||
},
|
},
|
||||||
// 清空所有分割
|
// 清空所有分割
|
||||||
delAllSegment(isChange) {
|
delAllSegment(isChange) {
|
||||||
|
|
@ -836,7 +839,7 @@ export default {
|
||||||
} else {
|
} else {
|
||||||
this.segmentationId = ''
|
this.segmentationId = ''
|
||||||
}
|
}
|
||||||
this.readingSegmentByConfig()
|
// this.readingSegmentByConfig()
|
||||||
this.resetViewport()
|
this.resetViewport()
|
||||||
this.$emit('resetQuestion')
|
this.$emit('resetQuestion')
|
||||||
},
|
},
|
||||||
|
|
@ -868,11 +871,7 @@ export default {
|
||||||
|
|
||||||
},
|
},
|
||||||
resetViewport(passive = true) {
|
resetViewport(passive = true) {
|
||||||
let renderingEngine = getRenderingEngine(this.renderingEngineId)
|
DicomEvent.$emit('resetViewport')
|
||||||
this.viewprotIds.forEach(id => {
|
|
||||||
const viewport = renderingEngine.getViewport(id)
|
|
||||||
viewport.render()
|
|
||||||
})
|
|
||||||
if (passive) this.$emit('setToolsPassive')
|
if (passive) this.$emit('setToolsPassive')
|
||||||
},
|
},
|
||||||
async rename(key, item) {
|
async rename(key, item) {
|
||||||
|
|
@ -925,7 +924,7 @@ export default {
|
||||||
// 切换非当前分组分割标记显示
|
// 切换非当前分组分割标记显示
|
||||||
changeInactiveSegmentShow() {
|
changeInactiveSegmentShow() {
|
||||||
let segmentList = this.segmentList.filter(item => item.segmentationId !== this.segmentationId)
|
let segmentList = this.segmentList.filter(item => item.segmentationId !== this.segmentationId)
|
||||||
this.viewprotIds.forEach(id => {
|
this.viewportIds.forEach(id => {
|
||||||
segmentation.config.visibility.setSegmentationRepresentationVisibility(
|
segmentation.config.visibility.setSegmentationRepresentationVisibility(
|
||||||
id,
|
id,
|
||||||
{
|
{
|
||||||
|
|
@ -967,113 +966,118 @@ export default {
|
||||||
this.exportSegmentation(this.segmentationId, group, true)
|
this.exportSegmentation(this.segmentationId, group, true)
|
||||||
},
|
},
|
||||||
exportSegmentation(segmentationId, group, isFile = false) {
|
exportSegmentation(segmentationId, group, isFile = false) {
|
||||||
const segmentationIds = segmentation.state
|
try {
|
||||||
.getSegmentations()
|
const segmentationIds = segmentation.state
|
||||||
.map(x => x.segmentationId);
|
.getSegmentations()
|
||||||
if (!segmentationIds.length) {
|
.map(x => x.segmentationId);
|
||||||
return;
|
if (!segmentationIds.length) {
|
||||||
}
|
return;
|
||||||
const segmentGroup =
|
|
||||||
segmentation.state.getSegmentation(segmentationId);
|
|
||||||
|
|
||||||
let { imageIds } = segmentGroup.representationData.Labelmap;
|
|
||||||
|
|
||||||
let segImages = imageIds.map(imageId => cache.getImage(imageId));
|
|
||||||
segImages = segImages.reverse()
|
|
||||||
let referencedImages = segImages.map(image =>
|
|
||||||
cache.getImage(image.referencedImageId)
|
|
||||||
);
|
|
||||||
const labelmaps2D = [];
|
|
||||||
|
|
||||||
let z = 0;
|
|
||||||
|
|
||||||
for (const segImage of segImages) {
|
|
||||||
const segmentsOnLabelmap = new Set();
|
|
||||||
const pixelData = segImage.getPixelData();
|
|
||||||
const { rows, columns } = segImage;
|
|
||||||
|
|
||||||
for (let i = 0; i < pixelData.length; i++) {
|
|
||||||
const segment = pixelData[i];
|
|
||||||
if (segment !== 0) {
|
|
||||||
segmentsOnLabelmap.add(segment);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
const segmentGroup =
|
||||||
|
segmentation.state.getSegmentation(segmentationId);
|
||||||
|
|
||||||
labelmaps2D[z++] = {
|
let { imageIds } = segmentGroup.representationData.Labelmap;
|
||||||
segmentsOnLabelmap: Array.from(segmentsOnLabelmap),
|
|
||||||
pixelData,
|
|
||||||
rows,
|
|
||||||
columns
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const allSegmentsOnLabelmap = labelmaps2D.map(
|
let segImages = imageIds.map(imageId => cache.getImage(imageId));
|
||||||
labelmap => labelmap.segmentsOnLabelmap
|
segImages = segImages.reverse()
|
||||||
);
|
let referencedImages = segImages.map(image =>
|
||||||
|
cache.getImage(image.referencedImageId)
|
||||||
const labelmap3D = {
|
|
||||||
segmentsOnLabelmap: Array.from(new Set(allSegmentsOnLabelmap.flat())),
|
|
||||||
metadata: [],
|
|
||||||
labelmaps2D
|
|
||||||
};
|
|
||||||
let segmentIndexs = []
|
|
||||||
labelmap3D.segmentsOnLabelmap.forEach(segmentIndex => {
|
|
||||||
const color = segmentation.config.color.getSegmentIndexColor(
|
|
||||||
`${this.viewportKey}-${this.activeViewportIndex}`,
|
|
||||||
segmentationId,
|
|
||||||
segmentIndex
|
|
||||||
);
|
);
|
||||||
const RecommendedDisplayCIELabValue = dcmjs.data.Colors.rgb2DICOMLAB(
|
const labelmaps2D = [];
|
||||||
color.slice(0, 3).map(value => value / 255)
|
|
||||||
).map(value => Math.round(value));
|
let z = 0;
|
||||||
let segment = group.segments.find(item => item.segmentIndex === segmentIndex)
|
|
||||||
if (segment) {
|
for (const segImage of segImages) {
|
||||||
segmentIndexs.push(segmentIndex)
|
const segmentsOnLabelmap = new Set();
|
||||||
let SegmentLabel = segment.SegmentLabel
|
const pixelData = segImage.getPixelData();
|
||||||
const segmentMetadata = {
|
const { rows, columns } = segImage;
|
||||||
SegmentNumber: segmentIndex.toString(),
|
|
||||||
SegmentLabel: SegmentLabel,
|
for (let i = 0; i < pixelData.length; i++) {
|
||||||
SegmentAlgorithmType: "MANUAL",
|
const segment = pixelData[i];
|
||||||
SegmentAlgorithmName: "OHIF Brush",
|
if (segment !== 0) {
|
||||||
RecommendedDisplayCIELabValue,
|
segmentsOnLabelmap.add(segment);
|
||||||
SegmentedPropertyCategoryCodeSequence: {
|
|
||||||
CodeValue: "T-D0050",
|
|
||||||
CodingSchemeDesignator: "SRT",
|
|
||||||
CodeMeaning: "Tissue"
|
|
||||||
},
|
|
||||||
SegmentedPropertyTypeCodeSequence: {
|
|
||||||
CodeValue: "T-D0050",
|
|
||||||
CodingSchemeDesignator: "SRT",
|
|
||||||
CodeMeaning: "Tissue"
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
labelmaps2D[z++] = {
|
||||||
|
segmentsOnLabelmap: Array.from(segmentsOnLabelmap),
|
||||||
|
pixelData,
|
||||||
|
rows,
|
||||||
|
columns
|
||||||
};
|
};
|
||||||
|
|
||||||
if (segment.stats) labelmap3D.metadata[segmentIndex] = segmentMetadata;
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
if (labelmap3D.metadata.length <= 0) {
|
const allSegmentsOnLabelmap = labelmaps2D.map(
|
||||||
return false
|
labelmap => labelmap.segmentsOnLabelmap
|
||||||
}
|
|
||||||
const generatedSegmentation =
|
|
||||||
Cornerstone3D.Segmentation.generateSegmentation(
|
|
||||||
referencedImages,
|
|
||||||
labelmap3D,
|
|
||||||
metaData
|
|
||||||
);
|
);
|
||||||
segmentIndexs.forEach((item, index) => {
|
|
||||||
if (generatedSegmentation.dataset.SegmentSequence[index]) {
|
|
||||||
generatedSegmentation.dataset.SegmentSequence[index].SegmentNumber = item.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
const labelmap3D = {
|
||||||
generatedSegmentation.dataset.SegmentSequence.sort((a, b) => a.SegmentNumber - b.SegmentNumber)
|
segmentsOnLabelmap: Array.from(new Set(allSegmentsOnLabelmap.flat())),
|
||||||
if (!isFile) {
|
metadata: [],
|
||||||
const buffer = Buffer.from(dcmjs.data.datasetToDict(generatedSegmentation.dataset).write());
|
labelmaps2D
|
||||||
let blob = new Blob([buffer], { type: "application/dicom" });
|
};
|
||||||
return blob
|
let segmentIndexs = []
|
||||||
} else {
|
labelmap3D.segmentsOnLabelmap.forEach(segmentIndex => {
|
||||||
this.downloadDICOMData(generatedSegmentation.dataset, `${group.name}.dcm`);
|
const color = segmentation.config.color.getSegmentIndexColor(
|
||||||
|
`${this.viewportKey}-${this.activeViewportIndex}`,
|
||||||
|
segmentationId,
|
||||||
|
segmentIndex
|
||||||
|
);
|
||||||
|
const RecommendedDisplayCIELabValue = dcmjs.data.Colors.rgb2DICOMLAB(
|
||||||
|
color.slice(0, 3).map(value => value / 255)
|
||||||
|
).map(value => Math.round(value));
|
||||||
|
let segment = group.segments.find(item => item.segmentIndex === segmentIndex)
|
||||||
|
if (segment) {
|
||||||
|
segmentIndexs.push(segmentIndex)
|
||||||
|
let SegmentLabel = segment.SegmentLabel
|
||||||
|
const segmentMetadata = {
|
||||||
|
SegmentNumber: segmentIndex.toString(),
|
||||||
|
SegmentLabel: SegmentLabel,
|
||||||
|
SegmentAlgorithmType: "MANUAL",
|
||||||
|
SegmentAlgorithmName: "OHIF Brush",
|
||||||
|
RecommendedDisplayCIELabValue,
|
||||||
|
SegmentedPropertyCategoryCodeSequence: {
|
||||||
|
CodeValue: "T-D0050",
|
||||||
|
CodingSchemeDesignator: "SRT",
|
||||||
|
CodeMeaning: "Tissue"
|
||||||
|
},
|
||||||
|
SegmentedPropertyTypeCodeSequence: {
|
||||||
|
CodeValue: "T-D0050",
|
||||||
|
CodingSchemeDesignator: "SRT",
|
||||||
|
CodeMeaning: "Tissue"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (segment.stats) labelmap3D.metadata[segmentIndex] = segmentMetadata;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (labelmap3D.metadata.length <= 0) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const generatedSegmentation =
|
||||||
|
Cornerstone3D.Segmentation.generateSegmentation(
|
||||||
|
referencedImages,
|
||||||
|
labelmap3D,
|
||||||
|
metaData
|
||||||
|
);
|
||||||
|
segmentIndexs.forEach((item, index) => {
|
||||||
|
if (generatedSegmentation.dataset.SegmentSequence[index]) {
|
||||||
|
generatedSegmentation.dataset.SegmentSequence[index].SegmentNumber = item.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
generatedSegmentation.dataset.SegmentSequence.sort((a, b) => a.SegmentNumber - b.SegmentNumber)
|
||||||
|
if (!isFile) {
|
||||||
|
const buffer = Buffer.from(dcmjs.data.datasetToDict(generatedSegmentation.dataset).write());
|
||||||
|
let blob = new Blob([buffer], { type: "application/dicom" });
|
||||||
|
return blob
|
||||||
|
} else {
|
||||||
|
this.downloadDICOMData(generatedSegmentation.dataset, `${group.name}.dcm`);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
downloadDICOMData(bufferOrDataset, filename) {
|
downloadDICOMData(bufferOrDataset, filename) {
|
||||||
let blob;
|
let blob;
|
||||||
|
|
@ -1123,7 +1127,7 @@ export default {
|
||||||
|
|
||||||
const arrayBuffer = image.data.byteArray.buffer;
|
const arrayBuffer = image.data.byteArray.buffer;
|
||||||
await this.loadSegmentation(arrayBuffer, obj.segmentationId);
|
await this.loadSegmentation(arrayBuffer, obj.segmentationId);
|
||||||
this.createSegmentationRepresentation(obj.segmentationId);
|
// this.createSegmentationRepresentation(obj.segmentationId);
|
||||||
},
|
},
|
||||||
async loadSegmentation(arrayBuffer, segmentationId) {
|
async loadSegmentation(arrayBuffer, segmentationId) {
|
||||||
const generateToolState =
|
const generateToolState =
|
||||||
|
|
@ -1306,51 +1310,49 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
createSegmentationRepresentation(segmentationId) {
|
createSegmentationRepresentation(segmentationId) {
|
||||||
this.viewprotIds.forEach(id => {
|
DicomEvent.$emit('createSegmentationRepresentation', segmentationId)
|
||||||
segmentation.addSegmentationRepresentations(id, [
|
|
||||||
{
|
|
||||||
segmentationId,
|
|
||||||
type: csToolsEnums.SegmentationRepresentations.Labelmap,
|
|
||||||
},
|
|
||||||
])
|
|
||||||
})
|
|
||||||
this.$emit('setToolsPassive')
|
this.$emit('setToolsPassive')
|
||||||
},
|
},
|
||||||
contentMouseup() {
|
contentMouseup() {
|
||||||
// console.log("segment contentMouseup")
|
try {
|
||||||
if (!this.drawing) return false
|
// console.log("segment contentMouseup")
|
||||||
if (this.timeoutId) {
|
if (!this.drawing) return false
|
||||||
clearTimeout(this.timeoutId);
|
if (this.timeoutId) {
|
||||||
this.timeoutId = null;
|
clearTimeout(this.timeoutId);
|
||||||
}
|
this.timeoutId = null;
|
||||||
this.timeoutId = setTimeout(() => {
|
|
||||||
this.timeoutId = null;
|
|
||||||
this.drawing = false;
|
|
||||||
let segmentGroup = this.segmentList.find(item => item.segmentationId === this.segmentationId)
|
|
||||||
if (segmentGroup && segmentGroup.segments && segmentGroup.segments.length > 0) {
|
|
||||||
let segmentIndexs = []
|
|
||||||
segmentGroup.segments.forEach(item => {
|
|
||||||
segmentIndexs.push(item.segmentIndex)
|
|
||||||
item.bidirectional = null
|
|
||||||
item.stats = null
|
|
||||||
})
|
|
||||||
annotation.state.getAllAnnotations().forEach(i => {
|
|
||||||
if (i.metadata.segmentationId === this.segmentationId && i.metadata.toolName === "SegmentBidirectional") {
|
|
||||||
annotation.state.removeAnnotation(i.annotationUID)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
this.calculateStatistics(segmentIndexs, this.segmentationId, 'individual');
|
|
||||||
this.resetViewport(false)
|
|
||||||
// this.getBidirectional(segmentGroup.segments)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}, 500);
|
this.timeoutId = setTimeout(() => {
|
||||||
|
this.timeoutId = null;
|
||||||
|
this.drawing = false;
|
||||||
|
let segmentGroup = this.segmentList.find(item => item.segmentationId === this.segmentationId)
|
||||||
|
if (segmentGroup && segmentGroup.segments && segmentGroup.segments.length > 0) {
|
||||||
|
let segmentIndexs = []
|
||||||
|
segmentGroup.segments.forEach(item => {
|
||||||
|
segmentIndexs.push(item.segmentIndex)
|
||||||
|
item.bidirectional = null
|
||||||
|
item.stats = null
|
||||||
|
})
|
||||||
|
annotation.state.getAllAnnotations().forEach(i => {
|
||||||
|
if (i.metadata.segmentationId === this.segmentationId && i.metadata.toolName === "SegmentBidirectional") {
|
||||||
|
annotation.state.removeAnnotation(i.annotationUID)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.calculateStatistics(segmentIndexs, this.segmentationId, 'individual');
|
||||||
|
this.resetViewport(false)
|
||||||
|
// this.getBidirectional(segmentGroup.segments)
|
||||||
|
|
||||||
|
}
|
||||||
|
}, 500);
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err)
|
||||||
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
// 获取当前任务分割标记与问题绑定关系
|
// 获取当前任务分割标记与问题绑定关系
|
||||||
async getSegmentBindingList(param = {}) {
|
async getSegmentBindingList(param = {}) {
|
||||||
try {
|
try {
|
||||||
let data = {
|
let data = {
|
||||||
VisitTaskId: this.visitInfo.VisitTaskId,
|
VisitTaskId: this.series.TaskInfo.VisitTaskId,
|
||||||
PageSize: 9999,
|
PageSize: 9999,
|
||||||
PageIndex: 1,
|
PageIndex: 1,
|
||||||
}
|
}
|
||||||
|
|
@ -1367,7 +1369,7 @@ export default {
|
||||||
async saveSegmentBindingAndAnswer(list) {
|
async saveSegmentBindingAndAnswer(list) {
|
||||||
try {
|
try {
|
||||||
let data = {
|
let data = {
|
||||||
VisitTaskId: this.visitInfo.VisitTaskId,
|
VisitTaskId: this.series.TaskInfo.VisitTaskId,
|
||||||
BindingList: list
|
BindingList: list
|
||||||
}
|
}
|
||||||
let res = await saveSegmentBindingAndAnswer(data)
|
let res = await saveSegmentBindingAndAnswer(data)
|
||||||
|
|
@ -1482,7 +1484,7 @@ export default {
|
||||||
|
|
||||||
let bidirectional = bidirectionalData[0]
|
let bidirectional = bidirectionalData[0]
|
||||||
const { segmentIndex } = bidirectional;
|
const { segmentIndex } = bidirectional;
|
||||||
const { majorAxis, minorAxis, maxMajor, maxMinor } = bidirectional;
|
const { majorAxis, minorAxis } = bidirectional;
|
||||||
let item = list.find(i => i.segmentIndex === segmentIndex)
|
let item = list.find(i => i.segmentIndex === segmentIndex)
|
||||||
SegmentBidirectionalTool.hydrate(viewportId, [majorAxis, minorAxis], {
|
SegmentBidirectionalTool.hydrate(viewportId, [majorAxis, minorAxis], {
|
||||||
segmentIndex,
|
segmentIndex,
|
||||||
|
|
@ -1491,7 +1493,7 @@ export default {
|
||||||
let an = annotation.state.getAllAnnotations().find(i => i.metadata.segmentationId === item.segmentationId && i.metadata.segmentIndex === bidirectional.segmentIndex && i.metadata.toolName === "SegmentBidirectional");
|
let an = annotation.state.getAllAnnotations().find(i => i.metadata.segmentationId === item.segmentationId && i.metadata.segmentIndex === bidirectional.segmentIndex && i.metadata.toolName === "SegmentBidirectional");
|
||||||
if (an) {
|
if (an) {
|
||||||
annotation.locking.setAnnotationLocked(an.annotationUID, true)
|
annotation.locking.setAnnotationLocked(an.annotationUID, true)
|
||||||
annotation.visibility.setAnnotationVisibility(an.annotationUID, item.bidirectionalView)
|
annotation.visibility.setAnnotationVisibility(an.annotationUID, true)
|
||||||
}
|
}
|
||||||
item.bidirectional = bidirectional
|
item.bidirectional = bidirectional
|
||||||
reslove(true)
|
reslove(true)
|
||||||
|
|
@ -1536,7 +1538,7 @@ export default {
|
||||||
SegmentId: item.SegmentId,
|
SegmentId: item.SegmentId,
|
||||||
SegmentationId: item.SegmentationId,
|
SegmentationId: item.SegmentationId,
|
||||||
TableQuestionId: item.TableQuestionId,
|
TableQuestionId: item.TableQuestionId,
|
||||||
VisitTaskId: this.visitInfo.VisitTaskId,
|
VisitTaskId: this.series.TaskInfo.VisitTaskId,
|
||||||
}
|
}
|
||||||
bindingList.push(o)
|
bindingList.push(o)
|
||||||
}
|
}
|
||||||
|
|
@ -1554,7 +1556,7 @@ export default {
|
||||||
SubjectId: this.visitInfo.SubjectId,
|
SubjectId: this.visitInfo.SubjectId,
|
||||||
SubjectVisitId: this.visitInfo.VisistId,
|
SubjectVisitId: this.visitInfo.VisistId,
|
||||||
TrialId: this.$route.query.trialId,
|
TrialId: this.$route.query.trialId,
|
||||||
VisitTaskId: this.visitInfo.VisitTaskId,
|
VisitTaskId: this.series.TaskInfo.VisitTaskId,
|
||||||
}
|
}
|
||||||
if (url) data.SegUrl = url;
|
if (url) data.SegUrl = url;
|
||||||
if (id) data.Id = id;
|
if (id) data.Id = id;
|
||||||
|
|
@ -1574,7 +1576,7 @@ export default {
|
||||||
try {
|
try {
|
||||||
let data = {
|
let data = {
|
||||||
SeriesId: this.series.Id,
|
SeriesId: this.series.Id,
|
||||||
VisitTaskId: this.visitInfo.VisitTaskId,
|
VisitTaskId: this.series.TaskInfo.VisitTaskId,
|
||||||
PageSize: 9999,
|
PageSize: 9999,
|
||||||
PageIndex: 1,
|
PageIndex: 1,
|
||||||
}
|
}
|
||||||
|
|
@ -1583,6 +1585,8 @@ export default {
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
if (res.IsSuccess) {
|
if (res.IsSuccess) {
|
||||||
this.segmentList = []
|
this.segmentList = []
|
||||||
|
this.segmentationId = null;
|
||||||
|
this.segmentIndex = null;
|
||||||
let list = res.Result.CurrentPageData;
|
let list = res.Result.CurrentPageData;
|
||||||
for (let i = 0; i < list.length; i++) {
|
for (let i = 0; i < list.length; i++) {
|
||||||
let item = list[i]
|
let item = list[i]
|
||||||
|
|
@ -1597,12 +1601,12 @@ export default {
|
||||||
segments: []
|
segments: []
|
||||||
}
|
}
|
||||||
this.segmentList.push(obj)
|
this.segmentList.push(obj)
|
||||||
if (item.SEGUrl) {
|
// if (item.SEGUrl) {
|
||||||
await this.readSegmentation(obj)
|
// await this.readSegmentation(obj)
|
||||||
} else {
|
// } else {
|
||||||
await this.createSegmentation(obj.segmentationId)
|
// await this.createSegmentation(obj.segmentationId)
|
||||||
this.createSegmentationRepresentation(obj.segmentationId)
|
// // this.createSegmentationRepresentation(obj.segmentationId)
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
if (!this.segmentationId) {
|
if (!this.segmentationId) {
|
||||||
this.segmentationId = obj.segmentationId
|
this.segmentationId = obj.segmentationId
|
||||||
|
|
@ -1621,45 +1625,41 @@ export default {
|
||||||
bidirectional: SegmentJson.bidirectional,
|
bidirectional: SegmentJson.bidirectional,
|
||||||
bidirectionalView: true,
|
bidirectionalView: true,
|
||||||
view: true,
|
view: true,
|
||||||
lock: item.locked,
|
lock: true,
|
||||||
id: s.Id
|
id: s.Id
|
||||||
}
|
}
|
||||||
obj.segments.push(o)
|
obj.segments.push(o)
|
||||||
this.selectSegment(o, false)
|
// this.selectSegment(o, false)
|
||||||
this.changeColor(s.ColorRgb, o)
|
// this.changeColor(s.ColorRgb, o)
|
||||||
this.lockSegment(o, true)
|
// this.lockSegment(o, true)
|
||||||
}
|
}
|
||||||
if (!this.segmentIndex) {
|
if (!this.segmentIndex) {
|
||||||
this.segmentIndex = s.SegmentNumber
|
this.segmentIndex = s.SegmentNumber
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
this.$nextTick(() => {
|
// this.$nextTick(() => {
|
||||||
if (SEGMENT) {
|
// if (SEGMENT) {
|
||||||
// console.log(SEGMENT, 'SEGMENT')
|
// // console.log(SEGMENT, 'SEGMENT')
|
||||||
return this.getBidirectional(obj.segments, SEGMENT)
|
// return this.getBidirectional(obj.segments, SEGMENT)
|
||||||
}
|
// }
|
||||||
this.getBidirectional(obj.segments, null, false)
|
// this.getBidirectional(obj.segments, null, false)
|
||||||
})
|
// })
|
||||||
}
|
|
||||||
if (this.segmentationId && this.segmentIndex && this.segmentList && this.segmentList.length > 0) {
|
|
||||||
let o = this.segmentList.find(item => item.segmentationId === this.segmentationId)
|
|
||||||
if (o) {
|
|
||||||
let s = o.segments.find(item => item.segmentIndex === this.segmentIndex)
|
|
||||||
this.selectSegmentGroup(s)
|
|
||||||
} else {
|
|
||||||
this.segmentationId = this.segmentList[0].segmentationId
|
|
||||||
this.segmentIndex = this.segmentationId ? this.segmentList[0].segments[0].segmentIndex : null
|
|
||||||
if (this.segmentationId && this.segmentIndex) {
|
|
||||||
this.selectSegmentGroup(this.segmentList[0].segments[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
// console.log(segment, 'segment')
|
|
||||||
|
|
||||||
// this.selectSegment(segment)
|
|
||||||
}
|
}
|
||||||
|
// if (this.segmentationId && this.segmentIndex && this.segmentList && this.segmentList.length > 0) {
|
||||||
|
// let o = this.segmentList.find(item => item.segmentationId === this.segmentationId)
|
||||||
|
// if (o) {
|
||||||
|
// let s = o.segments.find(item => item.segmentIndex === this.segmentIndex)
|
||||||
|
// this.selectSegmentGroup(s)
|
||||||
|
// } else {
|
||||||
|
// this.segmentationId = this.segmentList[0].segmentationId
|
||||||
|
// this.segmentIndex = this.segmentationId ? this.segmentList[0].segments[0].segmentIndex : null
|
||||||
|
// if (this.segmentationId && this.segmentIndex) {
|
||||||
|
// this.selectSegmentGroup(this.segmentList[0].segments[0])
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
this.isloaded = false
|
this.isloaded = false
|
||||||
this.readingSegmentByConfig()
|
// this.readingSegmentByConfig()
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.loading = false
|
this.loading = false
|
||||||
|
|
@ -1688,7 +1688,7 @@ export default {
|
||||||
SegmentName: name,
|
SegmentName: name,
|
||||||
SegmentNumber: segmentIndex,
|
SegmentNumber: segmentIndex,
|
||||||
SegmentationId: segmentationId,
|
SegmentationId: segmentationId,
|
||||||
VisitTaskId: this.visitInfo.VisitTaskId,
|
VisitTaskId: this.series.TaskInfo.VisitTaskId,
|
||||||
SegmentJson: segmentJson
|
SegmentJson: segmentJson
|
||||||
}
|
}
|
||||||
if (id) data.Id = id
|
if (id) data.Id = id
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,25 @@
|
||||||
<div v-if="imageInfo.total">Image: #{{ `${series.SliceIndex + 1}/${imageInfo.total}` }}</div>
|
<div v-if="imageInfo.total">Image: #{{ `${series.SliceIndex + 1}/${imageInfo.total}` }}</div>
|
||||||
<div>{{ series.Modality }}</div>
|
<div>{{ series.Modality }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="series && taskInfo && taskInfo.IsReadingTaskViewInOrder === 1" class="top-center-tool">
|
||||||
|
<div class="toggle-visit-container">
|
||||||
|
<div class="arrw_icon"
|
||||||
|
:style="{ cursor: series.TaskInfo && series.TaskInfo.VisitTaskNum !== 0 ? 'pointer' : 'not-allowed', color: series.TaskInfo && series.TaskInfo.VisitTaskNum !== 0 ? '#fff' : '#6b6b6b' }"
|
||||||
|
@click.stop.prevent="toggleTask($event, series.TaskInfo.VisitTaskNum, -1)"
|
||||||
|
@dblclick.stop="preventDefault($event)">
|
||||||
|
<i class="el-icon-caret-left" />
|
||||||
|
</div>
|
||||||
|
<div class="arrow_text">
|
||||||
|
{{ series.TaskInfo ? series.TaskInfo.TaskBlindName : '' }}
|
||||||
|
</div>
|
||||||
|
<div class="arrw_icon"
|
||||||
|
:style="{ cursor: series.TaskInfo && series.TaskInfo.VisitTaskNum < taskInfo.VisitNum ? 'pointer' : 'not-allowed', color: series.TaskInfo && series.TaskInfo.VisitTaskNum < taskInfo.VisitNum ? '#fff' : '#6b6b6b' }"
|
||||||
|
@click.stop.prevent="toggleTask($event, series.TaskInfo.VisitTaskNum, 1)"
|
||||||
|
@dblclick.stop="preventDefault($event)">
|
||||||
|
<i class="el-icon-caret-right" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div v-if="series" class="right-top-text">
|
<div v-if="series" class="right-top-text">
|
||||||
<div>{{ series.Description }}</div>
|
<div>{{ series.Description }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -40,10 +59,10 @@
|
||||||
<div v-if="series" class="right-bottom-text">
|
<div v-if="series" class="right-bottom-text">
|
||||||
<div v-show="imageInfo.location">Location: {{
|
<div v-show="imageInfo.location">Location: {{
|
||||||
`${Number(imageInfo.location).toFixed(digitPlaces)} mm`
|
`${Number(imageInfo.location).toFixed(digitPlaces)} mm`
|
||||||
}}</div>
|
}}</div>
|
||||||
<div v-show="imageInfo.sliceThickness">Slice Thickness: {{
|
<div v-show="imageInfo.sliceThickness">Slice Thickness: {{
|
||||||
`${Number(imageInfo.sliceThickness).toFixed(digitPlaces)} mm`
|
`${Number(imageInfo.sliceThickness).toFixed(digitPlaces)} mm`
|
||||||
}}</div>
|
}}</div>
|
||||||
<div v-show="imageInfo.wwwc">WW/WL: {{ imageInfo.wwwc }}</div>
|
<div v-show="imageInfo.wwwc">WW/WL: {{ imageInfo.wwwc }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="orientation-top">
|
<div class="orientation-top">
|
||||||
|
|
@ -83,6 +102,19 @@ import {
|
||||||
setPetTransferFunctionForVolumeActor
|
setPetTransferFunctionForVolumeActor
|
||||||
} from './helpers/index.js'
|
} from './helpers/index.js'
|
||||||
import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent'
|
import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent'
|
||||||
|
import {
|
||||||
|
renderSegmentation,
|
||||||
|
readingSegmentByConfig,
|
||||||
|
selectSegmentation,
|
||||||
|
selectSegment,
|
||||||
|
createSegmentationRepresentation,
|
||||||
|
viewSegmentation,
|
||||||
|
viewSegment,
|
||||||
|
jumpBidirectional,
|
||||||
|
viewBidirectional,
|
||||||
|
changeColor,
|
||||||
|
resetViewport
|
||||||
|
} from "./helpers/segmentations"
|
||||||
export default {
|
export default {
|
||||||
name: 'MPRViewport',
|
name: 'MPRViewport',
|
||||||
props: {
|
props: {
|
||||||
|
|
@ -101,6 +133,32 @@ export default {
|
||||||
histogramVisible: {
|
histogramVisible: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
|
},
|
||||||
|
actionConfiguration: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SegmentConfig: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
curSegSeries: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
segmentIndex: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
segmentationId: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
|
@ -154,6 +212,39 @@ export default {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.initViewport()
|
this.initViewport()
|
||||||
})
|
})
|
||||||
|
DicomEvent.$on('createSegmentationRepresentation', (segmentationId) => {
|
||||||
|
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
|
||||||
|
createSegmentationRepresentation(this.viewportId, segmentationId)
|
||||||
|
})
|
||||||
|
DicomEvent.$on('viewSegmentation', (obj) => {
|
||||||
|
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
|
||||||
|
viewSegmentation(obj, this.viewportId)
|
||||||
|
})
|
||||||
|
DicomEvent.$on('viewSegment', (obj) => {
|
||||||
|
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
|
||||||
|
viewSegment(obj, this.viewportId)
|
||||||
|
})
|
||||||
|
DicomEvent.$on('jumpBidirectional', (obj) => {
|
||||||
|
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
|
||||||
|
jumpBidirectional(obj, this.viewportId, this.volumeId)
|
||||||
|
})
|
||||||
|
DicomEvent.$on('viewBidirectional', (obj) => {
|
||||||
|
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
|
||||||
|
viewBidirectional(obj, this.viewportId)
|
||||||
|
})
|
||||||
|
DicomEvent.$on('changeColor', (obj) => {
|
||||||
|
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
|
||||||
|
changeColor(obj, this.viewportId)
|
||||||
|
})
|
||||||
|
DicomEvent.$on('resetViewport', () => {
|
||||||
|
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
|
||||||
|
resetViewport(this.viewportId)
|
||||||
|
})
|
||||||
|
DicomEvent.$on('renderSegmentation', async (viewportId) => {
|
||||||
|
// if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
|
||||||
|
if (this.viewportId !== viewportId) return false
|
||||||
|
await renderSegmentation(this.series, this.series.TaskInfo, this.viewportId, this.SegmentConfig, this.segmentationId, this.segmentIndex, this.renderingEngineId, null, this.actionConfiguration)
|
||||||
|
})
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
MPRInfo: {
|
MPRInfo: {
|
||||||
|
|
@ -172,6 +263,25 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
deep: true
|
deep: true
|
||||||
|
},
|
||||||
|
SegmentConfig: {
|
||||||
|
handler() {
|
||||||
|
if (!this.segmentationId) return false
|
||||||
|
if (!this.series.TaskInfo) return false
|
||||||
|
readingSegmentByConfig(this.series, this.series.TaskInfo, this.viewportId, this.segmentationId, this.SegmentConfig)
|
||||||
|
},
|
||||||
|
deep: true
|
||||||
|
},
|
||||||
|
segmentIndex() {
|
||||||
|
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
|
||||||
|
if (this.segmentIndex <= 0) return false
|
||||||
|
selectSegment(this.viewportId, this.segmentationId, this.segmentIndex)
|
||||||
|
},
|
||||||
|
segmentationId() {
|
||||||
|
if (this.curSegSeries.Id !== this.series.Id || this.curSegSeries.VisitTaskId !== this.series.VisitTaskId) return false
|
||||||
|
if (!this.segmentationId) return false
|
||||||
|
selectSegmentation(this.viewportId, this.segmentationId)
|
||||||
|
readingSegmentByConfig(this.series, this.series.TaskInfo, this.viewportId, this.segmentationId, this.SegmentConfig)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
@ -549,13 +659,9 @@ export default {
|
||||||
console.log("渲染成功")
|
console.log("渲染成功")
|
||||||
}
|
}
|
||||||
}]).then(r => {
|
}]).then(r => {
|
||||||
if (data.segment) {
|
|
||||||
return DicomEvent.$emit("isloaded", { segment: data.segment, isChange: data.isChange })
|
|
||||||
}
|
|
||||||
if (data.isLocation) {
|
if (data.isLocation) {
|
||||||
setTimeout(() => { csUtils.jumpToSlice(viewport.element, { imageIndex: data.SliceIndex }); })
|
setTimeout(() => { csUtils.jumpToSlice(viewport.element, { imageIndex: data.SliceIndex }); })
|
||||||
}
|
}
|
||||||
DicomEvent.$emit("isloaded", { isChange: data.isChange })
|
|
||||||
})
|
})
|
||||||
viewport.render()
|
viewport.render()
|
||||||
if (this.series.Modality === 'PT' || this.series.Modality === 'NM') {
|
if (this.series.Modality === 'PT' || this.series.Modality === 'NM') {
|
||||||
|
|
@ -567,11 +673,10 @@ export default {
|
||||||
renderingEngine.render()
|
renderingEngine.render()
|
||||||
}, 100)
|
}, 100)
|
||||||
}
|
}
|
||||||
|
await renderSegmentation(this.series, this.series.TaskInfo, this.viewportId, this.SegmentConfig, this.segmentationId, this.segmentIndex, this.renderingEngineId, data.segment, this.actionConfiguration)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e)
|
console.log(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
cornerstoneToolsMouseMove(e) {
|
cornerstoneToolsMouseMove(e) {
|
||||||
const { currentPoints } = e.detail
|
const { currentPoints } = e.detail
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,430 @@
|
||||||
|
import * as cornerstoneTools from '@cornerstonejs/tools';
|
||||||
|
import * as cornerstone from "@cornerstonejs/core";
|
||||||
|
import dcmjs from '@/utils/dcmUpload/dcmjs'
|
||||||
|
import * as cornerstoneAdapters from "@cornerstonejs/adapters";
|
||||||
|
import cornerstoneDICOMImageLoader from '@cornerstonejs/dicom-image-loader'
|
||||||
|
import * as polySeg from '@cornerstonejs/polymorphic-segmentation'
|
||||||
|
cornerstoneTools.init({ addons: { polySeg } })
|
||||||
|
import { getSegmentationList, getSegmentList } from '@/api/reading'
|
||||||
|
import Vue from 'vue'
|
||||||
|
const {
|
||||||
|
ToolGroupManager,
|
||||||
|
Enums: csToolsEnums,
|
||||||
|
segmentation,
|
||||||
|
annotation,
|
||||||
|
LabelMapEditWithContourTool,
|
||||||
|
SegmentBidirectionalTool,
|
||||||
|
CrosshairsTool,
|
||||||
|
utilities: CStUtils,
|
||||||
|
} = cornerstoneTools;
|
||||||
|
const { MouseBindings, Events: toolsEvents } = csToolsEnums
|
||||||
|
const { segmentation: segmentationUtils } = CStUtils;
|
||||||
|
const { cache, getRenderingEngine, imageLoader, eventTarget, metaData, utilities: csUtils, volumeLoader } = cornerstone;
|
||||||
|
const { Cornerstone3D } = cornerstoneAdapters.adaptersSEG;
|
||||||
|
let viewportInfo = {}
|
||||||
|
let renderingEngineId = null
|
||||||
|
async function createSegmentation(toolGroupId, volumeId, segmentationId) {
|
||||||
|
const toolGroup = ToolGroupManager.getToolGroup(toolGroupId) || ToolGroupManager.getToolGroup('share-viewport-volume')
|
||||||
|
toolGroup.setToolActive(
|
||||||
|
LabelMapEditWithContourTool.toolName,
|
||||||
|
);
|
||||||
|
if (!cache.getVolume(segmentationId)) {
|
||||||
|
await volumeLoader.createAndCacheDerivedLabelmapVolume(
|
||||||
|
volumeId,
|
||||||
|
{
|
||||||
|
volumeId: segmentationId
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (!segmentation.state.getSegmentation(segmentationId)) {
|
||||||
|
segmentation.addSegmentations([
|
||||||
|
{
|
||||||
|
segmentationId,
|
||||||
|
representation: {
|
||||||
|
type: cornerstoneTools.Enums.SegmentationRepresentations
|
||||||
|
.Labelmap,
|
||||||
|
data: {
|
||||||
|
volumeId: segmentationId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async function createSegmentationRepresentation(viewportId, segmentationId) {
|
||||||
|
segmentation.addSegmentationRepresentations(viewportId, [
|
||||||
|
{
|
||||||
|
segmentationId,
|
||||||
|
type: csToolsEnums.SegmentationRepresentations.Labelmap,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
}
|
||||||
|
async function readSegmentation(obj, series, segmentationId, isFile = false) {
|
||||||
|
let imageId = null
|
||||||
|
if (isFile) {
|
||||||
|
imageId = cornerstoneDICOMImageLoader.wadouri.fileManager.add(obj);
|
||||||
|
} else {
|
||||||
|
const imageIdObj = await cornerstoneDICOMImageLoader.wadouri.loadImage(`wadouri:${Vue.prototype.OSSclientConfig.basePath}${obj}`).promise
|
||||||
|
imageId = imageIdObj.imageId
|
||||||
|
}
|
||||||
|
const image = await imageLoader.loadAndCacheImage(imageId);
|
||||||
|
|
||||||
|
if (!image) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const instance = metaData.get("instance", imageId);
|
||||||
|
|
||||||
|
if (instance.Modality !== "SEG") {
|
||||||
|
console.error("This is not segmentation: " + file.name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const arrayBuffer = image.data.byteArray.buffer;
|
||||||
|
await loadSegmentation(arrayBuffer, series, segmentationId);
|
||||||
|
}
|
||||||
|
async function loadSegmentation(arrayBuffer, series, segmentationId) {
|
||||||
|
const generateToolState =
|
||||||
|
await Cornerstone3D.Segmentation.generateToolState(
|
||||||
|
series.ImageIds,
|
||||||
|
arrayBuffer,
|
||||||
|
metaData,
|
||||||
|
);
|
||||||
|
if (generateToolState.labelmapBufferArray.length !== 1) {
|
||||||
|
alert(
|
||||||
|
"Overlapping segments in your segmentation are not supported yet. You can turn on the skipOverlapping option but it will override the overlapping segments."
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// await createSegmentation(segmentationId);
|
||||||
|
let arr = []
|
||||||
|
generateToolState.segMetadata.data.forEach(item => {
|
||||||
|
if (item) {
|
||||||
|
let Target = JSON.parse(JSON.stringify(item))
|
||||||
|
arr.push(Target)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
let mapping = {}
|
||||||
|
|
||||||
|
arr.forEach((item, index) => {
|
||||||
|
mapping[index + 1] = Number(item.SegmentNumber)
|
||||||
|
})
|
||||||
|
const megmentGroup =
|
||||||
|
segmentation.state.getSegmentation(segmentationId);
|
||||||
|
const { imageIds } = megmentGroup.representationData.Labelmap;
|
||||||
|
const derivedSegmentationImages = imageIds.map(imageId =>
|
||||||
|
cache.getImage(imageId)
|
||||||
|
);
|
||||||
|
|
||||||
|
const volumeScalarData = new Uint8Array(
|
||||||
|
generateToolState.labelmapBufferArray[0]
|
||||||
|
);
|
||||||
|
const remappedData = new Uint8Array(volumeScalarData.length);
|
||||||
|
for (let i = 0; i < volumeScalarData.length; i++) {
|
||||||
|
const value = volumeScalarData[i];
|
||||||
|
remappedData[i] = value === 0 ? 0 : (mapping[value] ? mapping[value] : value);
|
||||||
|
}
|
||||||
|
for (let i = 0; i < derivedSegmentationImages.length; i++) {
|
||||||
|
const voxelManager = derivedSegmentationImages[i].voxelManager;
|
||||||
|
const scalarData = voxelManager.getScalarData();
|
||||||
|
scalarData.set(
|
||||||
|
remappedData.slice(
|
||||||
|
i * scalarData.length,
|
||||||
|
(i + 1) * scalarData.length
|
||||||
|
)
|
||||||
|
);
|
||||||
|
voxelManager.setScalarData(scalarData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function hex2Rgb(hexValue, alpha = 1) {
|
||||||
|
const rgx = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
|
||||||
|
const hex = hexValue.replace(rgx, (m, r, g, b) => r + r + g + g + b + b);
|
||||||
|
const rgb = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
||||||
|
if (!rgb) {
|
||||||
|
return hexValue;
|
||||||
|
}
|
||||||
|
const r = parseInt(rgb[1], 16),
|
||||||
|
g = parseInt(rgb[2], 16),
|
||||||
|
b = parseInt(rgb[3], 16);
|
||||||
|
return [r, g, b, alpha * 255];
|
||||||
|
}
|
||||||
|
function removeSegmentFromViewport(viewportId) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
if (viewportInfo[viewportId] && viewportInfo[viewportId].length > 0) {
|
||||||
|
viewportInfo[viewportId].forEach(async segmentationId => {
|
||||||
|
segmentation.removeSegmentation(segmentationId)
|
||||||
|
segmentation.state.removeSegmentation(segmentationId)
|
||||||
|
let annotations = annotation.state.getAllAnnotations().filter(item => item.metadata.segmentationId && segmentationId === item.metadata.segmentationId && item.metadata.segmentIndex && item.metadata.toolName === "SegmentBidirectional");
|
||||||
|
annotations.forEach(item => {
|
||||||
|
annotation.state.removeAnnotation(item.annotationUID)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
viewportInfo[viewportId] = []
|
||||||
|
resolve(true)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
function createSegmentConfiguration(segmentIndex, segmentationId, viewportId, actionConfiguration, otherSegments) {
|
||||||
|
const containedSegmentIndices = otherSegments
|
||||||
|
? { has: (segmentIndex) => otherSegments.indexOf(segmentIndex) !== -1 }
|
||||||
|
: undefined;
|
||||||
|
const colorConfig = segmentation.config.color.getSegmentIndexColor(
|
||||||
|
viewportId,
|
||||||
|
segmentationId,
|
||||||
|
segmentIndex
|
||||||
|
);
|
||||||
|
// Allow null style to skip style set
|
||||||
|
let color, activeColor;
|
||||||
|
if (colorConfig?.length) {
|
||||||
|
color = `rgb(${colorConfig.join(',')})`;
|
||||||
|
activeColor = color;
|
||||||
|
}
|
||||||
|
const style = {
|
||||||
|
color,
|
||||||
|
colorHighlightedActive: activeColor,
|
||||||
|
colorActive: activeColor,
|
||||||
|
textBoxColor: color,
|
||||||
|
textBoxColorActive: activeColor,
|
||||||
|
textBoxColorHighlightedActive: activeColor,
|
||||||
|
};
|
||||||
|
const label = otherSegments
|
||||||
|
? `Combined ${segmentIndex} with ${otherSegments.join(', ')}`
|
||||||
|
: `Segment ${segmentIndex}`;
|
||||||
|
|
||||||
|
actionConfiguration.contourBidirectional.data.segmentData.set(segmentIndex, {
|
||||||
|
containedSegmentIndices,
|
||||||
|
label,
|
||||||
|
style,
|
||||||
|
});
|
||||||
|
actionConfiguration.contourBidirectional.data.segmentationId = segmentationId
|
||||||
|
actionConfiguration.contourBidirectional.data.segmentIndex = segmentIndex
|
||||||
|
}
|
||||||
|
async function readingSegmentByConfig(series, visitInfo, viewportId, segmentationId, SegmentConfig) {
|
||||||
|
let data = {
|
||||||
|
SeriesId: series.Id,
|
||||||
|
VisitTaskId: visitInfo.VisitTaskId,
|
||||||
|
PageSize: 9999,
|
||||||
|
PageIndex: 1,
|
||||||
|
}
|
||||||
|
let res = await getSegmentationList(data);
|
||||||
|
if (res.IsSuccess) {
|
||||||
|
let list = res.Result.CurrentPageData;
|
||||||
|
changeInactiveSegmentShow(list, viewportId, segmentationId, SegmentConfig)
|
||||||
|
}
|
||||||
|
segmentation.config.style.setStyle(
|
||||||
|
{
|
||||||
|
type: csToolsEnums.SegmentationRepresentations.Labelmap,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
renderFill: SegmentConfig.renderFill,
|
||||||
|
renderOutline: SegmentConfig.renderOutline,
|
||||||
|
outlineWidth: Number(SegmentConfig.outlineWidth),
|
||||||
|
fillAlpha: Number(SegmentConfig.fillAlpha),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
function selectSegmentation(viewportId, segmentationId) {
|
||||||
|
segmentation.activeSegmentation.setActiveSegmentation(viewportId, segmentationId)
|
||||||
|
}
|
||||||
|
function selectSegment(viewportId, segmentationId, segmentIndex) {
|
||||||
|
selectSegmentation(viewportId, segmentationId)
|
||||||
|
segmentation.segmentIndex.setActiveSegmentIndex(segmentationId, segmentIndex);
|
||||||
|
}
|
||||||
|
async function changeInactiveSegmentShow(list, viewportId, segmentationId, SegmentConfig) {
|
||||||
|
let segmentList = list
|
||||||
|
segmentList.forEach(segment => {
|
||||||
|
segmentation.config.visibility.setSegmentationRepresentationVisibility(
|
||||||
|
viewportId,
|
||||||
|
{
|
||||||
|
segmentationId: segment.Id,
|
||||||
|
type: csToolsEnums.SegmentationRepresentations.Labelmap,
|
||||||
|
},
|
||||||
|
SegmentConfig.InactiveSegmentations.show
|
||||||
|
);
|
||||||
|
})
|
||||||
|
segmentation.config.visibility.setSegmentationRepresentationVisibility(
|
||||||
|
viewportId,
|
||||||
|
{
|
||||||
|
segmentationId: segmentationId,
|
||||||
|
type: csToolsEnums.SegmentationRepresentations.Labelmap,
|
||||||
|
},
|
||||||
|
true
|
||||||
|
);
|
||||||
|
let arr = []
|
||||||
|
for (let i = 0; i < segmentList.length; i++) {
|
||||||
|
let item = segmentList[i]
|
||||||
|
let params = {
|
||||||
|
SegmentationId: item.Id,
|
||||||
|
PageSize: 9999,
|
||||||
|
PageIndex: 1,
|
||||||
|
}
|
||||||
|
let r = await getSegmentList(params)
|
||||||
|
if (r.IsSuccess) {
|
||||||
|
let segments = r.Result.CurrentPageData
|
||||||
|
segments.forEach(s => {
|
||||||
|
let obj = {
|
||||||
|
segmentationId: item.Id,
|
||||||
|
segmentIndex: s.SegmentNumber,
|
||||||
|
view: SegmentConfig.InactiveSegmentations.show
|
||||||
|
}
|
||||||
|
if (item.Id === segmentationId) {
|
||||||
|
obj.view = true
|
||||||
|
}
|
||||||
|
arr.push(obj)
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
viewBidirectional(arr, viewportId)
|
||||||
|
}
|
||||||
|
function viewSegmentation(item, viewportId) {
|
||||||
|
segmentation.config.visibility.setSegmentationRepresentationVisibility(
|
||||||
|
viewportId,
|
||||||
|
{
|
||||||
|
segmentationId: item.segmentationId,
|
||||||
|
type: csToolsEnums.SegmentationRepresentations.Labelmap,
|
||||||
|
},
|
||||||
|
item.view
|
||||||
|
);
|
||||||
|
viewBidirectional(item.segments, viewportId)
|
||||||
|
}
|
||||||
|
async function jumpBidirectional(item, viewportId, volumeId) {
|
||||||
|
// DicomEvent.$emit('jumpBidirectional', item)
|
||||||
|
if (item.bidirectional) {
|
||||||
|
let an = annotation.state.getAllAnnotations().find(i => i.metadata.segmentationId === item.segmentationId && i.metadata.segmentIndex === item.segmentIndex && i.metadata.toolName === "SegmentBidirectional");
|
||||||
|
console.log(an, 'an')
|
||||||
|
if (!an) return false
|
||||||
|
const renderingEngine = getRenderingEngine(renderingEngineId)
|
||||||
|
const viewport = renderingEngine.getViewport(viewportId)
|
||||||
|
let key = Object.keys(an.data.cachedStats)[0]; // referencedImageId
|
||||||
|
if (key) {
|
||||||
|
let sliceIndex = key.split("?")[1].split("&")[0].split("=")[1]
|
||||||
|
csUtils.jumpToSlice(viewport.element, { imageIndex: sliceIndex });
|
||||||
|
} else {
|
||||||
|
const points = an.data.handles.points;
|
||||||
|
const worldPoint = points[0]; // 取一个点
|
||||||
|
let volume = cache.getVolume(volumeId)
|
||||||
|
let { imageData, numFrames } = volume
|
||||||
|
const ijk = imageData.worldToIndex(worldPoint);
|
||||||
|
const sliceIndex = Math.abs(Math.round(ijk[2]));
|
||||||
|
// console.log(sliceIndex, 'sliceIndex')
|
||||||
|
csUtils.jumpToSlice(viewport.element, { imageIndex: numFrames - sliceIndex - 1 });
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function viewSegment(item, viewportId) {
|
||||||
|
segmentation.config.visibility.setSegmentIndexVisibility(viewportId, {
|
||||||
|
segmentationId: item.segmentationId,
|
||||||
|
type: csToolsEnums.SegmentationRepresentations.Labelmap,
|
||||||
|
}, item.segmentIndex, item.view)
|
||||||
|
viewBidirectional([item], viewportId)
|
||||||
|
}
|
||||||
|
function viewBidirectional(arr, viewportId) {
|
||||||
|
for (let j = 0; j < arr.length; j++) {
|
||||||
|
let item = arr[j]
|
||||||
|
let bidirectional = annotation.state.getAllAnnotations().find(i => i.metadata.segmentationId === item.segmentationId && i.metadata.segmentIndex === item.segmentIndex && i.metadata.toolName === "SegmentBidirectional");
|
||||||
|
// item.bidirectionalView = view
|
||||||
|
if (!bidirectional) continue
|
||||||
|
annotation.visibility.setAnnotationVisibility(bidirectional.annotationUID, item.view)
|
||||||
|
}
|
||||||
|
resetViewport(viewportId)
|
||||||
|
}
|
||||||
|
function resetViewport(viewportId) {
|
||||||
|
let renderingEngine = getRenderingEngine(renderingEngineId)
|
||||||
|
const viewport = renderingEngine.getViewport(viewportId)
|
||||||
|
viewport.render()
|
||||||
|
}
|
||||||
|
function changeColor(item, viewportId) {
|
||||||
|
segmentation.config.color.setSegmentIndexColor(viewportId, item.segmentationId, item.segmentIndex, hex2Rgb(item.color))
|
||||||
|
}
|
||||||
|
async function renderSegmentation(series, visitInfo, viewportId, SegmentConfig, segmentationId, segmentIndex, RenderingEngineId, Segment = null, actionConfiguration) {
|
||||||
|
try {
|
||||||
|
// console.log(segmentation, 'segmentation')
|
||||||
|
renderingEngineId = RenderingEngineId
|
||||||
|
await removeSegmentFromViewport(viewportId)
|
||||||
|
let data = {
|
||||||
|
SeriesId: series.Id,
|
||||||
|
VisitTaskId: visitInfo.VisitTaskId,
|
||||||
|
PageSize: 9999,
|
||||||
|
PageIndex: 1,
|
||||||
|
}
|
||||||
|
let res = await getSegmentationList(data);
|
||||||
|
if (res.IsSuccess) {
|
||||||
|
let list = res.Result.CurrentPageData;
|
||||||
|
for (let i = 0; i < list.length; i++) {
|
||||||
|
let item = list[i]
|
||||||
|
|
||||||
|
await createSegmentation(viewportId, series.SeriesInstanceUid, item.Id)
|
||||||
|
if (item.SEGUrl) await readSegmentation(item.SEGUrl, series, item.Id)
|
||||||
|
createSegmentationRepresentation(viewportId, item.Id)
|
||||||
|
if (!viewportInfo[viewportId]) {
|
||||||
|
viewportInfo[viewportId] = [item.Id]
|
||||||
|
} else {
|
||||||
|
viewportInfo[viewportId].push(item.Id)
|
||||||
|
}
|
||||||
|
let params = {
|
||||||
|
SegmentationId: item.Id,
|
||||||
|
PageSize: 9999,
|
||||||
|
PageIndex: 1,
|
||||||
|
}
|
||||||
|
let r = await getSegmentList(params)
|
||||||
|
if (r.IsSuccess) {
|
||||||
|
let segments = r.Result.CurrentPageData
|
||||||
|
segments.forEach(s => {
|
||||||
|
let SegmentJson = s.SegmentJson ? JSON.parse(s.SegmentJson) : {};
|
||||||
|
segmentation.segmentIndex.setActiveSegmentIndex(s.SegmentationId, s.SegmentNumber);
|
||||||
|
segmentation.config.color.setSegmentIndexColor(viewportId, s.SegmentationId, s.SegmentNumber, hex2Rgb(s.ColorRgb))
|
||||||
|
segmentation.segmentLocking.setSegmentIndexLocked(s.SegmentationId, s.SegmentNumber, true)
|
||||||
|
if (SegmentJson.bidirectional) {
|
||||||
|
let { majorAxis, minorAxis } = SegmentJson.bidirectional
|
||||||
|
// createSegmentConfiguration(s.SegmentNumber, s.SegmentationId, viewportId, actionConfiguration)
|
||||||
|
SegmentBidirectionalTool.hydrate(viewportId, [majorAxis, minorAxis], {
|
||||||
|
segmentIndex: s.SegmentNumber,
|
||||||
|
segmentationId: s.SegmentationId,
|
||||||
|
})
|
||||||
|
let an = annotation.state.getAllAnnotations().find(i => i.metadata.segmentationId === s.SegmentationId && i.metadata.segmentIndex === SegmentJson.bidirectional.segmentIndex && i.metadata.toolName === "SegmentBidirectional");
|
||||||
|
if (an) {
|
||||||
|
annotation.locking.setAnnotationLocked(an.annotationUID, true)
|
||||||
|
annotation.visibility.setAnnotationVisibility(an.annotationUID, item.bidirectionalView)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// this.$nextTick(() => {
|
||||||
|
// if (SEGMENT) {
|
||||||
|
// // console.log(SEGMENT, 'SEGMENT')
|
||||||
|
// return this.getBidirectional(obj.segments, SEGMENT)
|
||||||
|
// }
|
||||||
|
// this.getBidirectional(obj.segments, null, false)
|
||||||
|
// })
|
||||||
|
selectSegment(viewportId, segmentationId, segmentIndex)
|
||||||
|
if (Segment) {
|
||||||
|
jumpBidirectional(Segment, viewportId, series.SeriesInstanceUid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
readingSegmentByConfig(series, visitInfo, viewportId, segmentationId, SegmentConfig)
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
createSegmentation,
|
||||||
|
createSegmentationRepresentation,
|
||||||
|
readSegmentation,
|
||||||
|
renderSegmentation,
|
||||||
|
readingSegmentByConfig,
|
||||||
|
selectSegment,
|
||||||
|
selectSegmentation,
|
||||||
|
viewSegmentation,
|
||||||
|
viewSegment,
|
||||||
|
jumpBidirectional,
|
||||||
|
viewBidirectional,
|
||||||
|
changeColor,
|
||||||
|
resetViewport
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue