|
|
@@ -357,15 +357,55 @@ export class AnnotationManager {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 通过 SOP Instance UID 检查 viewport 是否包含指定图像
|
|
|
+ * @param viewport Stack viewport 实例
|
|
|
+ * @param imageId 要检查的图像ID
|
|
|
+ * @returns 是否包含该图像
|
|
|
+ */
|
|
|
+ private hasImageBySopInstanceUid(viewport: IStackViewport, imageId: string): boolean {
|
|
|
+ try {
|
|
|
+ // 1. 提取传入 imageId 的 SOP Instance UID
|
|
|
+ const targetSopUid = extractSopInstanceUid(imageId);
|
|
|
+ if (!targetSopUid) {
|
|
|
+ console.warn('【annotationmanager】无法提取目标图像的 SOP Instance UID:', imageId);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 获取 viewport 中的所有 imageIds
|
|
|
+ const imageIds = viewport.getImageIds?.();
|
|
|
+ if (!imageIds || imageIds.length === 0) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 遍历比较每个 imageId 的 SOP Instance UID
|
|
|
+ for (const vpImageId of imageIds) {
|
|
|
+ const vpSopUid = extractSopInstanceUid(vpImageId);
|
|
|
+ if (vpSopUid && vpSopUid === targetSopUid) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+ } catch (error) {
|
|
|
+ console.error('【annotationmanager】比较 SOP Instance UID 时出错:', error);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
// 用 FrameOfReferenceUID 查找 viewport elements
|
|
|
private findElementsByFOR(imageId: string): any[] {
|
|
|
const elements: any[] = [];
|
|
|
- if (!!getRenderingEngines) {
|
|
|
- const renderingEngines = getRenderingEngines();
|
|
|
- renderingEngines?.forEach((re: IRenderingEngine) => {
|
|
|
+ const renderingEngines = getRenderingEngines();
|
|
|
+
|
|
|
+ if (renderingEngines) {
|
|
|
+ renderingEngines.forEach((re: IRenderingEngine) => {
|
|
|
re.getViewports().forEach((vp: IStackViewport) => {
|
|
|
- if (vp && vp.hasImageId(imageId) === true && vp.element) {
|
|
|
- elements.push(vp.element);
|
|
|
+ if (vp && vp.element) {
|
|
|
+ const stackVp = vp as IStackViewport;
|
|
|
+ if (this.hasImageBySopInstanceUid(stackVp, imageId)) {
|
|
|
+ elements.push(vp.element);
|
|
|
+ }
|
|
|
}
|
|
|
});
|
|
|
});
|
|
|
@@ -373,7 +413,6 @@ export class AnnotationManager {
|
|
|
console.warn('【annotationmanager】getRenderingEngines 方法不可用,无法查找元素');
|
|
|
}
|
|
|
|
|
|
-
|
|
|
return elements;
|
|
|
}
|
|
|
|
|
|
@@ -385,10 +424,43 @@ export class AnnotationManager {
|
|
|
// 反序列化为Cornerstone格式
|
|
|
const deserializedAnnotation = this.serializer.deserialize(annotationString);
|
|
|
|
|
|
- // 添加到Cornerstone注释状态
|
|
|
- corAnnotation.state.addAnnotation(deserializedAnnotation, deserializedAnnotation.metadata?.toolName || 'UnknownTool');
|
|
|
+ // 1. 从注释元数据中获取图像ID
|
|
|
+ const imageId = deserializedAnnotation.metadata?.referencedImageId;
|
|
|
+ if (!imageId) {
|
|
|
+ console.warn('【annotationmanager】注释缺少 referencedImageId,跳过');
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 找到包含该图像的 viewport element
|
|
|
+ const renderingEngines = getRenderingEngines();
|
|
|
+ let targetElement: HTMLDivElement | null = null;
|
|
|
+
|
|
|
+ if (renderingEngines) {
|
|
|
+ for (const engine of renderingEngines) {
|
|
|
+ const viewports = engine.getViewports();
|
|
|
+ for (const viewport of viewports) {
|
|
|
+ // 使用类型断言处理 IStackViewport
|
|
|
+ const stackViewport = viewport as IStackViewport;
|
|
|
+ if (stackViewport) {
|
|
|
+ if (this.hasImageBySopInstanceUid(stackViewport, imageId)) {
|
|
|
+ targetElement = stackViewport.element;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (targetElement) break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!targetElement) {
|
|
|
+ console.warn('【annotationmanager】未找到对应的 viewport,跳过');
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. ✅ 使用正确的 element 参数添加注释
|
|
|
+ corAnnotation.state.addAnnotation(deserializedAnnotation, targetElement);
|
|
|
|
|
|
- console.log(`【annotationmanager】✅ 注释渲染成功`);
|
|
|
+ console.log(`【annotationmanager】✅ 注释渲染成功到 viewport`);
|
|
|
} catch (error) {
|
|
|
console.error(`【annotationmanager】❌ 注释渲染失败:`, error);
|
|
|
// 继续处理其他注释
|