diff --git a/src/views/dictionary/template/browser/tip.vue b/src/views/dictionary/template/browser/tip.vue
index a88e10d1..391ea8ec 100644
--- a/src/views/dictionary/template/browser/tip.vue
+++ b/src/views/dictionary/template/browser/tip.vue
@@ -68,7 +68,8 @@ export default {
let { width, height } = allInfo.screen; // 分辨率
// let discrete = allInfo.webgl.gpuType.discrete; // 是否独立显卡
// let estimatedMemory = allInfo.webgl.memoryInfo.estimatedMemory; // 显卡内存
- if (parseFloat(deviceMemory) < 16 || width < 1920 || height < 1080) {
+ // parseFloat(deviceMemory) < 16 ||
+ if (width < 1920 || height < 1080) {
if (this.tip) {
this.tip += `
`
}
diff --git a/src/views/trials/trials-panel/reading/dicoms/components/DicomViewer.vue b/src/views/trials/trials-panel/reading/dicoms/components/DicomViewer.vue
index ec2dbdc5..5957f7b7 100644
--- a/src/views/trials/trials-panel/reading/dicoms/components/DicomViewer.vue
+++ b/src/views/trials/trials-panel/reading/dicoms/components/DicomViewer.vue
@@ -2491,7 +2491,8 @@ export default {
let { width, height } = allInfo.screen; // 分辨率
let discrete = allInfo.webgl.gpuType.discrete; // 是否独立显卡
let estimatedMemory = allInfo.webgl.memoryInfo.estimatedMemory; // 显卡内存
- if (parseFloat(deviceMemory) < 16 || width < 1920 || height < 1080 || !discrete || parseFloat(estimatedMemory) < 2) {
+ // parseFloat(deviceMemory) < 16 ||
+ if (width < 1920 || height < 1080 || !discrete || parseFloat(estimatedMemory) < 2) {
let res = await this.$confirm(this.$t('browser:tip:ReadingConfiguration'))
resolve(res)
} else {
diff --git a/src/views/trials/trials-panel/reading/dicoms3D/components/ReadPage.vue b/src/views/trials/trials-panel/reading/dicoms3D/components/ReadPage.vue
index e7adbdeb..1af9c593 100644
--- a/src/views/trials/trials-panel/reading/dicoms3D/components/ReadPage.vue
+++ b/src/views/trials/trials-panel/reading/dicoms3D/components/ReadPage.vue
@@ -317,7 +317,7 @@
@dblclick="toggleFullScreen($event, index)" @click="activeViewport(index)">
@@ -673,7 +673,18 @@ export default {
ManualsClose: false,
isMPR: false,
- volumeToolGroupId: "share-viewport-volume"
+ volumeToolGroupId: "share-viewport-volume",
+ MPRInfo: {
+ AXIAL: {
+ imageNum: 0
+ },
+ CORONAL: {
+ imageNum: 0
+ },
+ SAGITTAL: {
+ imageNum: 0
+ },
+ }
}
},
computed: {
@@ -801,6 +812,10 @@ export default {
document.addEventListener("click", this.foo);
},
methods: {
+ setMPRInfo(obj) {
+ let { type, key, value } = obj
+ this.$set(this.MPRInfo[type], key, value)
+ },
handleReadingChart(row) {
let { e, data } = row
let obj = Object.assign({}, data)
@@ -3478,7 +3493,8 @@ export default {
let { width, height } = allInfo.screen; // 分辨率
let discrete = allInfo.webgl.gpuType.discrete; // 是否独立显卡
let estimatedMemory = allInfo.webgl.memoryInfo.estimatedMemory; // 显卡内存
- if (parseFloat(deviceMemory) < 16 || width < 1920 || height < 1080 || !discrete || parseFloat(estimatedMemory) < 2) {
+ // parseFloat(deviceMemory) < 16 ||
+ if (width < 1920 || height < 1080 || !discrete || parseFloat(estimatedMemory) < 2) {
let res = await this.$confirm(this.$t('browser:tip:ReadingConfiguration'), this.$t('system:menu:confirm:title:warning'), {
type: 'warning'
})
diff --git a/src/views/trials/trials-panel/reading/dicoms3D/components/VolumeViewport.vue b/src/views/trials/trials-panel/reading/dicoms3D/components/VolumeViewport.vue
index dd44c9c7..427f84bb 100644
--- a/src/views/trials/trials-panel/reading/dicoms3D/components/VolumeViewport.vue
+++ b/src/views/trials/trials-panel/reading/dicoms3D/components/VolumeViewport.vue
@@ -70,6 +70,7 @@ import {
metaData,
getRenderingEngine,
utilities as csUtils,
+ cache
} from '@cornerstonejs/core'
import * as cornerstoneTools from '@cornerstonejs/tools'
import { createImageIdsAndCacheMetaData } from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/createImageIdsAndCacheMetaData'
@@ -91,6 +92,12 @@ export default {
type: Number,
required: true
},
+ MPRInfo: {
+ type: Object,
+ default: () => {
+ return {}
+ }
+ }
},
data() {
return {
@@ -142,6 +149,25 @@ export default {
this.initViewport()
})
},
+ watch: {
+ MPRInfo: {
+ handler() {
+ if (!this.series.orientation) return false
+ switch (this.series.orientation) {
+ case 'AXIAL':
+ this.imageInfo.size = `${this.MPRInfo.SAGITTAL.imageNum}*${this.MPRInfo.CORONAL.imageNum}`
+ break;
+ case 'CORONAL':
+ this.imageInfo.size = `${this.MPRInfo.SAGITTAL.imageNum}*${this.MPRInfo.AXIAL.imageNum}`
+ break;
+ case 'SAGITTAL':
+ this.imageInfo.size = `${this.MPRInfo.CORONAL.imageNum}*${this.MPRInfo.AXIAL.imageNum}`
+ break;
+ }
+ },
+ deep: true
+ }
+ },
methods: {
initViewport() {
this.element = this.$refs['viewport-volume']
@@ -185,6 +211,58 @@ export default {
})
},
+
+ determineImagePlane(imageOrientationPatient) {
+ // imageOrientationPatient 是 [rowX, rowY, rowZ, colX, colY, colZ]
+ // 我们只关心行方向向量 (rowX, rowY, rowZ)
+ const [rowX, rowY, rowZ] = imageOrientationPatient;
+
+ // 计算行方向向量与 X, Y, Z 轴的点积(因为轴向量是单位向量,所以点积就是投影长度)
+ const dotX = Math.abs(rowX);
+ const dotY = Math.abs(rowY);
+ const dotZ = Math.abs(rowZ);
+
+ // 找到最大的点积,确定主方向
+ const maxDot = Math.max(dotX, dotY, dotZ);
+
+ // 根据主方向判断解剖面
+ if (maxDot === dotX) {
+ // 行方向接近 X 轴,说明视线方向接近 Y 或 Z 轴。
+ // 更准确的判断是看视线方向(由行和列向量叉乘得到)。
+ // 但一个简化的、在大多数情况下都成立的规则是:
+ // 如果行向量主要在 X-Y 平面 (rowZ 很小),则为 Axial。
+ // 如果行向量主要在 X-Z 平面 (rowY 很小),则为 Sagittal。
+ // 为了简化,我们可以直接根据视线方向(法线)来判断。
+ // 法线方向 = 行向量 × 列向量
+ const [colX, colY, colZ] = imageOrientationPatient.slice(3);
+ const normalX = rowY * colZ - rowZ * colY;
+ const normalY = rowZ * colX - rowX * colZ;
+ const normalZ = rowX * colY - rowY * colX;
+
+ const absNormalX = Math.abs(normalX);
+ const absNormalY = Math.abs(normalY);
+ const absNormalZ = Math.abs(normalZ);
+
+ const maxNormal = Math.max(absNormalX, absNormalY, absNormalZ);
+
+ if (maxNormal === absNormalZ) {
+ return 'AXIAL';
+ } else if (maxNormal === absNormalY) {
+ return 'SAGITTAL';
+ } else if (maxNormal === absNormalX) {
+ return 'CORONAL';
+ }
+
+ } else if (maxDot === dotY) {
+ // 行方向接近 Y 轴,通常是 Coronal 面。
+ return 'SAGITTAL';
+ } else if (maxDot === dotZ) {
+ // 行方向接近 Z 轴,通常是 Sagittal 面。
+ return 'CORONAL';
+ }
+
+ return 'unknown';
+ },
stackNewImage(e) {
const { detail } = e
this.series.SliceIndex = detail.imageIndex
@@ -195,26 +273,16 @@ export default {
this.imageInfo.zoom = zoom.toFixed(4)
let imageIds = viewport.getImageIds(this.volumeId)
let imageId = imageIds[0]
+ let volume = cache.getVolume(this.volumeId)
+ let { spacing } = volume
// if (this.series.orientation === 'AXIAL') imageId = viewport.getCurrentImageId()
if (imageId) {
+ this.$emit('setMPRInfo', { type: this.series.orientation, key: "imageNum", value: detail.numberOfSlices })
const imagePlaneModule = metaData.get('imagePlaneModule', imageId)
- if (this.series.orientation === 'AXIAL') {
- this.imageInfo.size = `${imagePlaneModule.columns}*${imagePlaneModule.rows}`
- this.imageInfo.location = imagePlaneModule.sliceLocation
- this.imageInfo.total = imageIds.length
- this.imageInfo.sliceThickness = imagePlaneModule.sliceThickness
- }
- if (this.series.orientation === 'CORONAL') {
- this.imageInfo.size = `${imagePlaneModule.columns}*${imageIds.length}`
- this.imageInfo.total = imagePlaneModule.rows
- this.imageInfo.sliceThickness = imagePlaneModule.rowPixelSpacing
- }
- if (this.series.orientation === 'SAGITTAL') {
- this.imageInfo.size = `${imagePlaneModule.rows}*${imageIds.length}`
- this.imageInfo.total = imagePlaneModule.columns
- this.imageInfo.sliceThickness = imagePlaneModule.columnPixelSpacing
- }
-
+ let type = this.determineImagePlane(imagePlaneModule.imageOrientationPatient)
+ this.imageInfo.location = type === this.series.orientation ? imagePlaneModule.sliceLocation : ''
+ this.imageInfo.sliceThickness = type === this.series.orientation ? spacing[2] : spacing[0]
+ this.imageInfo.total = detail.numberOfSlices
this.getOrientationMarker()
let properties = viewport.getProperties(this.volumeId)
if (properties && properties.voiRange) {