Ver Fonte

胫骨内侧平台线和胫骨功能轴线垂线(轴线垂线)相交后,绘制出延长虚线,延长150

sw há 1 mês atrás
pai
commit
caf4667783

+ 33 - 3
src/components/measures/TibialPlateauAngleTool.README.md

@@ -178,14 +178,22 @@ const TPA = Math.round(degrees(angleRad));
 #### **5. 可视化元素**
 1. **胫骨内侧平台线**(点1→点2): 白色/蓝色实线(选中时)
 2. **胫骨功能轴线**(点3→点4): 白色/蓝色实线(选中时)
-3. **平台线延长虚线**: 灰色虚线,从平台线的**较近端点延伸到交汇点**
-4. **功能轴线延长虚线**: 灰色虚线,从功能轴线的**较近端点延伸到交汇点**
+3. **平台线延长虚线**: 灰色虚线,从平台线的**较近端点经过交汇点继续延伸50像素**
+4. **功能轴线延长虚线**: 灰色虚线,从功能轴线的**较近端点经过交汇点继续延伸50像素**
 5. **交汇点**: 延长虚线的交汇处,即平台线与功能轴线的数学交点
 6. **平台线中垂线**: 绿色虚线,从交汇点向两端延伸,垂直于平台线
 7. **角度弧线**: 黄色,在交汇点处绘制,表示TPA角度
 8. **TPA文本**: 黄色,可拖拽,显示角度值
 9. **手柄点**: 4个白色圆圈,可拖拽
 
+**延长线实现细节**:
+- **延长线起点**: 自动选择离交汇点较近的端点作为延长线起点
+- **延长逻辑**: 
+  1. 计算从端点到交汇点的方向向量
+  2. 归一化该方向向量
+  3. 从交汇点沿该方向继续延伸额外的50像素
+- **视觉效果**: 延长线从端点穿过交汇点后继续延伸,使两条线的交汇更加清晰明显
+
 ---
 
 ## 三、开发人员使用指南
@@ -569,11 +577,33 @@ utilities.triggerAnnotationRenderForViewportIds(viewportIdsToRender);
 
 ### 5.2 可视化要点
 1. **实线**: 功能轴线、平台线使用实线绘制(白色/蓝色)
-2. **灰色虚线**: 平台线和功能轴线的延长线,从交点延伸,清晰显示两线的交汇
+2. **灰色虚线**: 平台线和功能轴线的延长线
+   - 从各自较近的端点出发
+   - 经过交汇点后继续延伸50像素
+   - 清晰显示两线的交汇关系
 3. **绿色虚线**: 平台线的中垂线,从交点延伸,垂直于平台线
 4. **角度弧线**: 在交点处绘制,半径适中(如30px)
 5. **文本框**: 黄色显示,支持拖拽,避免遮挡关键线段
 
+**延长线绘制技术细节**:
+```typescript
+// 1. 选择离交点较近的端点
+const dist1 = distance(intersection, point1);
+const dist2 = distance(intersection, point2);
+const extensionStart = dist1 < dist2 ? point1 : point2;
+
+// 2. 计算从端点到交点的方向向量并归一化
+const directionVector = subtract(intersection, extensionStart);
+const normalizedDir = normalize(directionVector);
+
+// 3. 计算延长线的终点(交点后继续延伸50像素)
+const extraExtensionLength = 50;
+const extensionEnd = add(intersection, scale(normalizedDir, extraExtensionLength));
+
+// 4. 绘制从端点到延长终点的完整虚线
+drawLine(extensionStart, extensionEnd, { lineDash: '4,4' });
+```
+
 ### 5.3 交互要点
 1. **手柄点识别**: 检测鼠标与点的距离,设置合理的proximity阈值
 2. **文本框拖拽**: 记录初始偏移量,避免跳跃

+ 50 - 9
src/components/measures/TibialPlateauAngleTool.ts

@@ -1,3 +1,4 @@
+import { Point3, Point2 } from './mathUtils';
 import {
   utilities as csUtils,
   Types as CoreTypes,
@@ -191,9 +192,9 @@ export default class TibialPlateauAngleTool extends AnnotationTool {
       TPA: cachedStats.TPA,
       textBoxPosition: annotation.data.handles.textBoxTPA,
       metadata: {
-        viewPlaneNormal: annotation?.metadata?.viewPlaneNormal || [0, 0, 1],
-        viewUp: annotation?.metadata?.viewUp || [0, 1, 0],
-        FrameOfReferenceUID: annotation?.metadata?.FrameOfReferenceUID || '',
+        viewPlaneNormal: annotation.metadata?.viewPlaneNormal || [0, 0, 1],
+        viewUp: annotation.metadata?.viewUp || [0, 1, 0],
+        FrameOfReferenceUID: annotation.metadata?.FrameOfReferenceUID || '',
         referencedImageId: annotation.metadata?.referencedImageId || '',
       },
     };
@@ -732,7 +733,7 @@ export default class TibialPlateauAngleTool extends AnnotationTool {
           { color: lineColor, width: 2 }
         );
 
-        // 绘制胫骨内侧平台线的延长线(虚线):从最近的端点延伸到交点
+        // 绘制胫骨内侧平台线的延长线(虚线):从最近的端点延伸到交点,并在交点后继续延长
         if (cachedStats && cachedStats.intersectionPoint && points.length >= 2) {
           const point1 = points[0];  // 平台线起点
           const point2 = points[1];  // 平台线终点
@@ -751,20 +752,40 @@ export default class TibialPlateauAngleTool extends AnnotationTool {
           // 选择离交点较近的端点作为延长线起点
           const extensionStart = dist1 < dist2 ? point1 : point2;
           
+          // 计算从端点到交点的方向向量
+          const directionVector: CoreTypes.Point3 = [
+            intersection[0] - extensionStart[0],
+            intersection[1] - extensionStart[1],
+            intersection[2] - extensionStart[2]
+          ];
+          
+          // 归一化方向向量
+          const normalizedDir = this._normalizeVector(directionVector);
+          
+          // 在交点后继续延长的长度(像素)
+          const extraExtensionLength = 150;
+          
+          // 计算延长线的最终终点:交点 + 延长距离
+          const extensionEnd = vectorAdd(
+            intersection,
+            vectorScale(normalizedDir, extraExtensionLength)
+          );
+          
           const extensionStartCanvas = viewport.worldToCanvas(extensionStart);
-          const intersectionCanvas = viewport.worldToCanvas(intersection);
+          const extensionEndCanvas = viewport.worldToCanvas(extensionEnd);
           
+          // 绘制完整的延长线:从端点经过交点到延伸终点
           drawLineSvg(
             svgDrawingHelper,
             annotationUID,
             `${annotationUID}-plateauExtension`,
             extensionStartCanvas,
-            intersectionCanvas,
+            extensionEndCanvas,
             { color: 'rgb(200, 200, 200)', width: 1, lineDash: '4,4' }
           );
         }
 
-        // 绘制功能轴线的延长线(虚线):从最近的端点延伸到交点
+        // 绘制功能轴线的延长线(虚线):从最近的端点延伸到交点,并在交点后继续延长
         if (cachedStats && cachedStats.intersectionPoint && points.length >= 4) {
           const point3 = points[2];  // 功能轴线起点
           const point4 = points[3];  // 功能轴线终点
@@ -783,15 +804,35 @@ export default class TibialPlateauAngleTool extends AnnotationTool {
           // 选择离交点较近的端点作为延长线起点
           const extensionStart = dist3 < dist4 ? point3 : point4;
           
+          // 计算从端点到交点的方向向量
+          const directionVector: CoreTypes.Point3 = [
+            intersection[0] - extensionStart[0],
+            intersection[1] - extensionStart[1],
+            intersection[2] - extensionStart[2]
+          ];
+          
+          // 归一化方向向量
+          const normalizedDir = this._normalizeVector(directionVector);
+          
+          // 在交点后继续延长的长度(像素)
+          const extraExtensionLength = 150;
+          
+          // 计算延长线的最终终点:交点 + 延长距离
+          const extensionEnd = vectorAdd(
+            intersection,
+            vectorScale(normalizedDir, extraExtensionLength)
+          );
+          
           const extensionStartCanvas = viewport.worldToCanvas(extensionStart);
-          const intersectionCanvas = viewport.worldToCanvas(intersection);
+          const extensionEndCanvas = viewport.worldToCanvas(extensionEnd);
           
+          // 绘制完整的延长线:从端点经过交点到延伸终点
           drawLineSvg(
             svgDrawingHelper,
             annotationUID,
             `${annotationUID}-axisExtension`,
             extensionStartCanvas,
-            intersectionCanvas,
+            extensionEndCanvas,
             { color: 'rgb(200, 200, 200)', width: 1, lineDash: '4,4' }
           );
         }