Browse Source

Merge branch 'master' of http://git.ius.plus/Project-Wing/fis_lib_measure

Melon 9 months ago
parent
commit
570dfd3869
27 changed files with 1162 additions and 109 deletions
  1. 3 0
      lib/interfaces/process/items/item_feature.dart
  2. 24 23
      lib/interfaces/process/items/terms.dart
  3. 263 0
      lib/process/calcuators/urm_calcuators/urm_ab_ratio.dart
  4. 34 7
      lib/process/calcuators/urm_calcuators/urm_curve_curvature_line.dart
  5. 43 0
      lib/process/calcuators/urm_calcuators/urm_ellipse_den_measure.dart
  6. 6 4
      lib/process/calcuators/urm_calcuators/urm_ellipse_density.dart
  7. 3 30
      lib/process/calcuators/urm_calcuators/urm_ellipse_measure.dart
  8. 1 1
      lib/process/calcuators/urm_calcuators/urm_ellipse_perfusion.dart
  9. 43 0
      lib/process/calcuators/urm_calcuators/urm_rect_den_measure.dart
  10. 54 1
      lib/process/calcuators/urm_calcuators/urm_shell_den_measure.dart
  11. 10 0
      lib/process/calcuators/urm_calcuators/urm_shell_den_vel_measure.dart
  12. 10 0
      lib/process/calcuators/urm_calcuators/urm_shell_density_measure.dart
  13. 10 1
      lib/process/calcuators/urm_calcuators/urm_shell_fractal_dim_measure.dart
  14. 10 1
      lib/process/calcuators/urm_calcuators/urm_shell_vel_measure.dart
  15. 43 0
      lib/process/calcuators/urm_calcuators/urm_trace_den_measure.dart
  16. 5 5
      lib/process/calcuators/urm_calcuators/urm_vel.dart
  17. 142 0
      lib/process/calcuators/urm_calcuators/urm_vessel_measure.dart
  18. 22 4
      lib/process/items/factory.dart
  19. 7 0
      lib/process/items/item_feature.dart
  20. 36 16
      lib/process/primitives/ellipse.dart
  21. 26 7
      lib/process/primitives/urm_measure/ab_ratio.dart
  22. 18 0
      lib/process/primitives/urm_measure/urm_curvature_measure.dart
  23. 1 0
      lib/process/primitives/urm_measure/urm_ellipse_measure.dart
  24. 27 1
      lib/process/primitives/urm_measure/urm_shell_measure.dart
  25. 255 0
      lib/process/primitives/urm_measure/urm_two_rect_den.dart
  26. 5 6
      lib/process/primitives/urm_measure/urm_vel.dart
  27. 61 2
      lib/process/primitives/urm_measure/urm_vessel_measure.dart

+ 3 - 0
lib/interfaces/process/items/item_feature.dart

@@ -46,6 +46,9 @@ abstract class IMeasureItemFeature {
 
   /// 灌注图 绘制
   void paintPerfusion(Canvas canvas, Size size);
+
+  /// 设置URM 双幅图
+  void setURMDualImages(bool? isURMDualImages);
 }
 
 /// 测试项单次快照样式配置

+ 24 - 23
lib/interfaces/process/items/terms.dart

@@ -121,34 +121,34 @@ class MeasureTerms {
   static const URMDenMin = "Min";
   static const URMDenMean = "Mean";
   static const URMDenStd = "Std";
-  static const URMDenROIIn = "Vessel ratio(In)";
-  static const URMDenFractalDimIn = "Complexity level(In)";
-  static const URMDenMaxIn = "Max(In)";
-  static const URMDenMinIn = "Min(In)";
-  static const URMDenMeanIn = "Mean(In)";
-  static const URMDenStdIn = "Std(In)";
-  static const URMDenROIOut = "Vessel ratio(Out)";
-  static const URMDenFractalDimOut = "Complexity level(Out)";
-  static const URMDenMaxOut = "Max(Out)";
-  static const URMDenMinOut = "Min(Out)";
-  static const URMDenMeanOut = "Mean(Out)";
-  static const URMDenStdOut = "Std(Out)";
+  // static const URMDenROIIn = "Vessel ratio(In)";
+  // static const URMDenFractalDimIn = "Complexity level(In)";
+  // static const URMDenMaxIn = "Max(In)";
+  // static const URMDenMinIn = "Min(In)";
+  // static const URMDenMeanIn = "Mean(In)";
+  // static const URMDenStdIn = "Std(In)";
+  // static const URMDenROIOut = "Vessel ratio(Out)";
+  // static const URMDenFractalDimOut = "Complexity level(Out)";
+  // static const URMDenMaxOut = "Max(Out)";
+  // static const URMDenMinOut = "Min(Out)";
+  // static const URMDenMeanOut = "Mean(Out)";
+  // static const URMDenStdOut = "Std(Out)";
 
   static const URMVelMax = "Max";
   static const URMVelMin = "Min";
   static const URMVelMean = "Mean";
   static const URMVelStd = "Std";
-  static const URMVelMaxIn = "Max(In)";
-  static const URMVelMinIn = "Min(In)";
-  static const URMVelMeanIn = "Mean(In)";
-  static const URMVelStdIn = "Std(In)";
-  static const URMVelMaxOut = "Max(Out)";
-  static const URMVelMinOut = "Min(Out)";
-  static const URMVelMeanOut = "Mean(Out)";
-  static const URMVelStdOut = "Std(Out)";
-
-  static const URMAreaIn = "Area(In)";
-  static const URMAreaOut = "Area(Out)";
+  // static const URMVelMaxIn = "Max(In)";
+  // static const URMVelMinIn = "Min(In)";
+  // static const URMVelMeanIn = "Mean(In)";
+  // static const URMVelStdIn = "Std(In)";
+  // static const URMVelMaxOut = "Max(Out)";
+  // static const URMVelMinOut = "Min(Out)";
+  // static const URMVelMeanOut = "Mean(Out)";
+  // static const URMVelStdOut = "Std(Out)";
+
+  // static const URMAreaIn = "Area(In)";
+  // static const URMAreaOut = "Area(Out)";
 
   static const MaxVessDistance = "Max Distance";
   static const MinVessDistance = "Min Distance";
@@ -160,6 +160,7 @@ class MeasureTerms {
   static const StdVessDiameter = "Std Diameter";
   static const MaxPos = "MaxPos";
   static const MinPos = "MinPos";
+  static const VesselCount = "VesselCount";
 
   static const URMPerfusionIndex = "Perfusion Index";
 

+ 263 - 0
lib/process/calcuators/urm_calcuators/urm_ab_ratio.dart

@@ -0,0 +1,263 @@
+import 'package:fis_measure/interfaces/process/calculators/values.dart';
+import 'package:fis_measure/process/calcuators/calculator.dart';
+import 'package:fis_measure/process/items/item.dart';
+import 'package:fis_measure/process/primitives/urm_measure/urm_two_rect_den.dart';
+
+class AbRatioCal extends Calculator<TwoURMRectDen, double> {
+  AbRatioCal(TwoURMRectDen ref) : super(ref);
+
+  @override
+  void calculate() {
+    if (ref.feature == null) return;
+
+    final a1 = _pickChildValue(ref.child1);
+    final a2 = _pickChildValue(ref.child2);
+
+    final feature = ref.feature!;
+    final viewport = feature.hostVisualArea!.viewport!;
+
+    // if (a1 != null && a2 != null) {
+    //   final value = GeneralFormulas.countStenosis(
+    //     a1,
+    //     a2,
+    //   );
+    //   updateFloatValue(value);
+    // }
+  }
+
+  double? _pickChildValue(MeasureItem item) {
+    if (item.calculator == null) return null;
+    ValueBase? value;
+    if (item.measuredFeatures.isNotEmpty) {
+      value = item.measuredFeatures.first.value;
+    } else if (item.feature != null) {
+      value = item.feature!.value;
+    }
+    if (value != null && value is FloatValue) {
+      return (value).value ?? 0;
+    }
+    return null;
+  }
+}
+
+class TwoURMRectDenCal extends Calculator<TwoURMRectDen, double> {
+  TwoURMRectDenCal(TwoURMRectDen ref) : super(ref);
+
+  @override
+  void calculate() {
+    if (ref.feature == null) return;
+
+    final a1 = _pickChildValue(ref.child1);
+    final a2 = _pickChildValue(ref.child2);
+
+    final feature = ref.feature!;
+    final viewport = feature.hostVisualArea!.viewport!;
+
+    // if (a1 != null && a2 != null) {
+    //   final value = GeneralFormulas.countStenosis(
+    //     a1,
+    //     a2,
+    //   );
+    //   updateFloatValue(value);
+    // }
+  }
+
+  double? _pickChildValue(MeasureItem item) {
+    if (item.calculator == null) return null;
+    ValueBase? value;
+    if (item.measuredFeatures.isNotEmpty) {
+      value = item.measuredFeatures.first.value;
+    } else if (item.feature != null) {
+      value = item.feature!.value;
+    }
+    if (value != null && value is FloatValue) {
+      return (value).value ?? 0;
+    }
+    return null;
+  }
+}
+
+class TwoURMTraceDenCal extends Calculator<TwoURMTraceDen, double> {
+  TwoURMTraceDenCal(TwoURMTraceDen ref) : super(ref);
+
+  @override
+  void calculate() {
+    if (ref.feature == null) return;
+
+    final a1 = _pickChildValue(ref.child1);
+    final a2 = _pickChildValue(ref.child2);
+
+    final feature = ref.feature!;
+    final viewport = feature.hostVisualArea!.viewport!;
+
+    // if (a1 != null && a2 != null) {
+    //   final value = GeneralFormulas.countStenosis(
+    //     a1,
+    //     a2,
+    //   );
+    //   updateFloatValue(value);
+    // }
+  }
+
+  double? _pickChildValue(MeasureItem item) {
+    if (item.calculator == null) return null;
+    ValueBase? value;
+    if (item.measuredFeatures.isNotEmpty) {
+      value = item.measuredFeatures.first.value;
+    } else if (item.feature != null) {
+      value = item.feature!.value;
+    }
+    if (value != null && value is FloatValue) {
+      return (value).value ?? 0;
+    }
+    return null;
+  }
+}
+
+class TwoURMEllipseDenCal extends Calculator<TwoURMEllipseDen, double> {
+  TwoURMEllipseDenCal(TwoURMEllipseDen ref) : super(ref);
+
+  @override
+  void calculate() {
+    if (ref.feature == null) return;
+
+    final a1 = _pickChildValue(ref.child1);
+    final a2 = _pickChildValue(ref.child2);
+
+    final feature = ref.feature!;
+    final viewport = feature.hostVisualArea!.viewport!;
+
+    // if (a1 != null && a2 != null) {
+    //   final value = GeneralFormulas.countStenosis(
+    //     a1,
+    //     a2,
+    //   );
+    //   updateFloatValue(value);
+    // }
+  }
+
+  double? _pickChildValue(MeasureItem item) {
+    if (item.calculator == null) return null;
+    ValueBase? value;
+    if (item.measuredFeatures.isNotEmpty) {
+      value = item.measuredFeatures.first.value;
+    } else if (item.feature != null) {
+      value = item.feature!.value;
+    }
+    if (value != null && value is FloatValue) {
+      return (value).value ?? 0;
+    }
+    return null;
+  }
+}
+
+class TwoURMRectFractalCal extends Calculator<TwoURMRectFractal, double> {
+  TwoURMRectFractalCal(TwoURMRectFractal ref) : super(ref);
+
+  @override
+  void calculate() {
+    if (ref.feature == null) return;
+
+    final a1 = _pickChildValue(ref.child1);
+    final a2 = _pickChildValue(ref.child2);
+
+    final feature = ref.feature!;
+    final viewport = feature.hostVisualArea!.viewport!;
+
+    // if (a1 != null && a2 != null) {
+    //   final value = GeneralFormulas.countStenosis(
+    //     a1,
+    //     a2,
+    //   );
+    //   updateFloatValue(value);
+    // }
+  }
+
+  double? _pickChildValue(MeasureItem item) {
+    if (item.calculator == null) return null;
+    ValueBase? value;
+    if (item.measuredFeatures.isNotEmpty) {
+      value = item.measuredFeatures.first.value;
+    } else if (item.feature != null) {
+      value = item.feature!.value;
+    }
+    if (value != null && value is FloatValue) {
+      return (value).value ?? 0;
+    }
+    return null;
+  }
+}
+
+class TwoURMTraceFractalCal extends Calculator<TwoURMTraceFractal, double> {
+  TwoURMTraceFractalCal(TwoURMTraceFractal ref) : super(ref);
+
+  @override
+  void calculate() {
+    if (ref.feature == null) return;
+
+    final a1 = _pickChildValue(ref.child1);
+    final a2 = _pickChildValue(ref.child2);
+
+    final feature = ref.feature!;
+    final viewport = feature.hostVisualArea!.viewport!;
+
+    // if (a1 != null && a2 != null) {
+    //   final value = GeneralFormulas.countStenosis(
+    //     a1,
+    //     a2,
+    //   );
+    //   updateFloatValue(value);
+    // }
+  }
+
+  double? _pickChildValue(MeasureItem item) {
+    if (item.calculator == null) return null;
+    ValueBase? value;
+    if (item.measuredFeatures.isNotEmpty) {
+      value = item.measuredFeatures.first.value;
+    } else if (item.feature != null) {
+      value = item.feature!.value;
+    }
+    if (value != null && value is FloatValue) {
+      return (value).value ?? 0;
+    }
+    return null;
+  }
+}
+
+class TwoURMEllipseFractalCal extends Calculator<TwoURMEllipseFractal, double> {
+  TwoURMEllipseFractalCal(TwoURMEllipseFractal ref) : super(ref);
+
+  @override
+  void calculate() {
+    if (ref.feature == null) return;
+
+    final a1 = _pickChildValue(ref.child1);
+    final a2 = _pickChildValue(ref.child2);
+
+    final feature = ref.feature!;
+    final viewport = feature.hostVisualArea!.viewport!;
+
+    // if (a1 != null && a2 != null) {
+    //   final value = GeneralFormulas.countStenosis(
+    //     a1,
+    //     a2,
+    //   );
+    //   updateFloatValue(value);
+    // }
+  }
+
+  double? _pickChildValue(MeasureItem item) {
+    if (item.calculator == null) return null;
+    ValueBase? value;
+    if (item.measuredFeatures.isNotEmpty) {
+      value = item.measuredFeatures.first.value;
+    } else if (item.feature != null) {
+      value = item.feature!.value;
+    }
+    if (value != null && value is FloatValue) {
+      return (value).value ?? 0;
+    }
+    return null;
+  }
+}

+ 34 - 7
lib/process/calcuators/urm_calcuators/urm_curve_curvature_line.dart

@@ -1,6 +1,8 @@
 import 'package:fis_common/logger/logger.dart';
+import 'package:fis_measure/interfaces/process/items/item.dart';
 import 'package:fis_measure/interfaces/process/items/terms.dart';
 import 'package:fis_measure/process/primitives/trace.dart';
+import 'package:fis_measure/process/primitives/urm_measure/urm_curvature_measure.dart';
 import 'package:fis_measure/process/workspace/urm/application.dart';
 import 'package:fis_jsonrpc/rpc.dart';
 import 'package:vid/us/vid_us_unit.dart';
@@ -33,16 +35,41 @@ class URMCurveCurvatureLineCal extends Calculator<Trace, double> {
         rOIType: URMROIType.URMTrace,
         srcDPoints: srcDPoints,
       );
-      if (result != null) {
-        print(
-            "URM Measure curvature: ${result.resultData} nums: ${result.resultDPoints?.length}");
+      if (result == null) return;
+      if (result.resultFlag) {
         final feature = ref.feature!;
-        for (var output in ref.meta.outputs) {
-          if (output.name == MeasureTerms.URMCurvature) {
-            output.unit = VidUsUnit.None;
-            feature.updateFloatValue(output, result.resultData, output.unit);
+        if (feature.refItem.parent is URMCurvatureMeasure) {
+          IMeasureItem? parent = feature.refItem.parent;
+          var revert =
+              parent?.meta.description == URMCurvatureMeasure.revertRatioName;
+          if (revert) {
+            for (var output in ref.meta.outputs) {
+              if (output.name == URMCurvatureMeasure.revertRatioName) {
+                output.unit = VidUsUnit.None;
+                feature.updateFloatValue(
+                    output, 1 / result.resultData, output.unit);
+              }
+            }
+          } else {
+            for (var output in ref.meta.outputs) {
+              if (output.name == URMCurvatureMeasure.ratioName) {
+                output.unit = VidUsUnit.None;
+                feature.updateFloatValue(
+                    output, result.resultData, output.unit);
+              }
+            }
+          }
+        } else {
+          /// TODO 后端配置 需要测试
+          for (var output in ref.meta.outputs) {
+            if (output.name == MeasureTerms.URMCurvature) {
+              output.unit = VidUsUnit.None;
+              feature.updateFloatValue(output, result.resultData, output.unit);
+            }
           }
         }
+        print(
+            "URM Measure curvature: ${result.resultData} nums: ${result.resultDPoints?.length}");
       } else {
         throw Exception("URM Measure API error");
       }

+ 43 - 0
lib/process/calcuators/urm_calcuators/urm_ellipse_den_measure.dart

@@ -51,6 +51,49 @@ class URMEllipseDenMeasureCal extends URMEllipseMeasureCal {
             output.unit = VidUsUnit.None;
             feature.updateFloatValue(
                 output, math.sqrt(result.varianceDensity), output.unit);
+          } else if (output.name == MeasureTerms.InURMDenROI) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(
+                output, result.inRoiDen * 100, output.unit);
+          } else if (output.name == MeasureTerms.InURMDenFractalDim) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(
+                output, result.inRoiFractalDim, output.unit);
+          } else if (output.name == MeasureTerms.InURMDenMax) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(output, result.inMaxDensity, output.unit);
+          } else if (output.name == MeasureTerms.InURMDenMin) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(output, result.inMinDensity, output.unit);
+          } else if (output.name == MeasureTerms.InURMDenMean) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(output, result.inMeanDensity, output.unit);
+          } else if (output.name == MeasureTerms.InURMDenStd) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(
+                output, math.sqrt(result.inVarianceDensity), output.unit);
+          } else if (output.name == MeasureTerms.OutURMDenROI) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(
+                output, result.outRoiDen * 100, output.unit);
+          } else if (output.name == MeasureTerms.OutURMDenFractalDim) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(
+                output, result.outRoiFractalDim, output.unit);
+          } else if (output.name == MeasureTerms.OutURMDenMax) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(output, result.outMaxDensity, output.unit);
+          } else if (output.name == MeasureTerms.OutURMDenMin) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(output, result.outMinDensity, output.unit);
+          } else if (output.name == MeasureTerms.OutURMDenMean) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(
+                output, result.outMeanDensity, output.unit);
+          } else if (output.name == MeasureTerms.OutURMDenStd) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(
+                output, math.sqrt(result.outVarianceDensity), output.unit);
           } else if (output.name == MeasureTerms.Area) {
             output.unit = VidUsUnit.cm2;
             feature.updateFloatValue(output, result.roiArea, output.unit);

+ 6 - 4
lib/process/calcuators/urm_calcuators/urm_ellipse_density.dart

@@ -25,16 +25,18 @@ class URMEllipseDensityCal extends URMEllipseMeasureCal {
         rOIType: URMROIType.URMEllipse,
         srcDPoints: param!.srcDPoints,
       );
-      var result = outResult?.denMeasureResult;
-      var velResult = outResult?.velMeasureResult;
 
-      if (result != null && velResult != null) {
+      if (outResult != null) {
         final feature = ref.feature!;
 
         for (var output in ref.meta.outputs) {
           if (output.name == MeasureTerms.URMDenROI) {
             output.unit = VidUsUnit.percent;
-            feature.updateFloatValue(output, result.roiDen * 100, output.unit);
+            feature.updateFloatValue(
+              output,
+              outResult.resultData * 100,
+              output.unit,
+            );
           }
         }
       } else {

+ 3 - 30
lib/process/calcuators/urm_calcuators/urm_ellipse_measure.dart

@@ -17,35 +17,6 @@ class URMEllipseMeasureCal extends Calculator<URMEllipseMeasure, double> {
   @override
   void calculate() {}
 
-  @override
-  Future<void> calculateAsync() async {
-    if (ref.feature == null) return;
-    try {
-      if (ref.application is! URMApplication) {
-        return;
-      }
-
-      Size urmResultSize = const Size(0, 0);
-      final URMApplication urmApplication = ref.application as URMApplication;
-      urmResultSize = Size(urmApplication.resultWidth.toDouble(),
-          urmApplication.resultHeight.toDouble());
-      final List<UrmPoint> points = ref.feature!.innerPoints
-          .map(
-            (e) => UrmPoint(
-              x: e.scale2Size(urmResultSize).x,
-              y: e.scale2Size(urmResultSize).y,
-            ),
-          )
-          .toList();
-
-      String description = "URM\n Calculating...";
-      updateStringValue(description);
-    } catch (e) {
-      logger.e('URM Measure error: $e');
-      return;
-    }
-  }
-
   /// 处理获取到的URM参数
   void handleURMSimpleMeasureParams() {
     if (ref.feature == null) return;
@@ -61,10 +32,12 @@ class URMEllipseMeasureCal extends Calculator<URMEllipseMeasure, double> {
 
       // 添加入参
       List<UrmPoint> srcDPoints = [];
+      // if (ref.feature is! EllipseFeature) {
+      //   srcDPoints = [];
+      // }
       for (var point in ref.feature!.innerPoints) {
         srcDPoints.add(urmApplication.localToView(point));
       }
-
       param = URMSimpleMeasureParams(
         urmMeasureType: URMMeasureType.URMCurvature,
         rOIType: URMROIType.URMEllipse,

+ 1 - 1
lib/process/calcuators/urm_calcuators/urm_ellipse_perfusion.dart

@@ -27,7 +27,7 @@ class URMEllipsePerfusionCal extends URMEllipseMeasureCal {
       URMMeasureProcessResult? outResult =
           await urmApplication.getURMMeasureResult(
         urmMeasureType: URMMeasureType.URMPerfusion,
-        rOIType: URMROIType.URMRect,
+        rOIType: URMROIType.URMEllipse,
         srcDPoints: param!.srcDPoints,
       );
 

+ 43 - 0
lib/process/calcuators/urm_calcuators/urm_rect_den_measure.dart

@@ -51,6 +51,49 @@ class URMRectDenMeasureCal extends URMRectMeasureCal {
             output.unit = VidUsUnit.None;
             feature.updateFloatValue(
                 output, math.sqrt(result.varianceDensity), output.unit);
+          } else if (output.name == MeasureTerms.InURMDenROI) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(
+                output, result.inRoiDen * 100, output.unit);
+          } else if (output.name == MeasureTerms.InURMDenFractalDim) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(
+                output, result.inRoiFractalDim, output.unit);
+          } else if (output.name == MeasureTerms.InURMDenMax) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(output, result.inMaxDensity, output.unit);
+          } else if (output.name == MeasureTerms.InURMDenMin) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(output, result.inMinDensity, output.unit);
+          } else if (output.name == MeasureTerms.InURMDenMean) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(output, result.inMeanDensity, output.unit);
+          } else if (output.name == MeasureTerms.InURMDenStd) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(
+                output, math.sqrt(result.inVarianceDensity), output.unit);
+          } else if (output.name == MeasureTerms.OutURMDenROI) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(
+                output, result.outRoiDen * 100, output.unit);
+          } else if (output.name == MeasureTerms.OutURMDenFractalDim) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(
+                output, result.outRoiFractalDim, output.unit);
+          } else if (output.name == MeasureTerms.OutURMDenMax) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(output, result.outMaxDensity, output.unit);
+          } else if (output.name == MeasureTerms.OutURMDenMin) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(output, result.outMinDensity, output.unit);
+          } else if (output.name == MeasureTerms.OutURMDenMean) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(
+                output, result.outMeanDensity, output.unit);
+          } else if (output.name == MeasureTerms.OutURMDenStd) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(
+                output, math.sqrt(result.outVarianceDensity), output.unit);
           } else if (output.name == MeasureTerms.Area) {
             output.unit = VidUsUnit.cm2;
             feature.updateFloatValue(output, result.roiArea, output.unit);

+ 54 - 1
lib/process/calcuators/urm_calcuators/urm_shell_den_measure.dart

@@ -1,5 +1,6 @@
 import 'package:fis_common/logger/logger.dart';
 import 'package:fis_jsonrpc/rpc.dart';
+import 'package:fis_measure/interfaces/date_types/point.dart';
 import 'package:fis_measure/interfaces/process/items/terms.dart';
 import 'package:fis_measure/process/calcuators/urm_calcuators/urm_shell_measure.dart';
 import 'package:fis_measure/process/primitives/urm_measure/urm_shell_measure.dart';
@@ -26,11 +27,20 @@ class URMShellDenMeasureCal extends URMShellMeasureCal {
         urmMeasureType: URMMeasureType.URMDenMeasure,
         rOIType: URMROIType.URMShell,
         srcDPoints: param!.srcDPoints,
+        shellWidth: 0.1,
       );
       var result = outResult?.denMeasureResult;
 
-      if (result != null) {
+      if (outResult != null && result != null) {
         final feature = ref.feature!;
+        if (feature is! ShellImageFeature) return;
+        if (outResult.outerExterPoints != null) {
+          List<DPoint> outerExterPoints = [];
+          outResult.outerExterPoints?.forEach((element) {
+            outerExterPoints.add(urmApplication.viewToLocal(element));
+          });
+          feature.outerExterPoints = outerExterPoints;
+        }
 
         for (var output in ref.meta.outputs) {
           if (output.name == MeasureTerms.URMDenROI) {
@@ -52,6 +62,49 @@ class URMShellDenMeasureCal extends URMShellMeasureCal {
             output.unit = VidUsUnit.None;
             feature.updateFloatValue(
                 output, math.sqrt(result.varianceDensity), output.unit);
+          } else if (output.name == MeasureTerms.InURMDenROI) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(
+                output, result.inRoiDen * 100, output.unit);
+          } else if (output.name == MeasureTerms.InURMDenFractalDim) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(
+                output, result.inRoiFractalDim, output.unit);
+          } else if (output.name == MeasureTerms.InURMDenMax) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(output, result.inMaxDensity, output.unit);
+          } else if (output.name == MeasureTerms.InURMDenMin) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(output, result.inMinDensity, output.unit);
+          } else if (output.name == MeasureTerms.InURMDenMean) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(output, result.inMeanDensity, output.unit);
+          } else if (output.name == MeasureTerms.InURMDenStd) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(
+                output, math.sqrt(result.inVarianceDensity), output.unit);
+          } else if (output.name == MeasureTerms.OutURMDenROI) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(
+                output, result.outRoiDen * 100, output.unit);
+          } else if (output.name == MeasureTerms.OutURMDenFractalDim) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(
+                output, result.outRoiFractalDim, output.unit);
+          } else if (output.name == MeasureTerms.OutURMDenMax) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(output, result.outMaxDensity, output.unit);
+          } else if (output.name == MeasureTerms.OutURMDenMin) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(output, result.outMinDensity, output.unit);
+          } else if (output.name == MeasureTerms.OutURMDenMean) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(
+                output, result.outMeanDensity, output.unit);
+          } else if (output.name == MeasureTerms.OutURMDenStd) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(
+                output, math.sqrt(result.outVarianceDensity), output.unit);
           } else if (output.name == MeasureTerms.Area) {
             output.unit = VidUsUnit.cm2;
             feature.updateFloatValue(output, result.roiArea, output.unit);

+ 10 - 0
lib/process/calcuators/urm_calcuators/urm_shell_den_vel_measure.dart

@@ -1,5 +1,6 @@
 import 'package:fis_common/logger/logger.dart';
 import 'package:fis_jsonrpc/rpc.dart';
+import 'package:fis_measure/interfaces/date_types/point.dart';
 import 'package:fis_measure/interfaces/process/items/terms.dart';
 import 'package:fis_measure/process/calcuators/urm_calcuators/urm_shell_measure.dart';
 import 'package:fis_measure/process/primitives/urm_measure/urm_shell_measure.dart';
@@ -26,6 +27,7 @@ class URMShellDenVelMeasureCal extends URMShellMeasureCal {
         urmMeasureType: URMMeasureType.URMDenVelMeasure,
         rOIType: URMROIType.URMShell,
         srcDPoints: param!.srcDPoints,
+        shellWidth: 0.1,
       );
       if (outresult == null) {
         return;
@@ -34,6 +36,14 @@ class URMShellDenVelMeasureCal extends URMShellMeasureCal {
       URMVelMeasureResult? velresult = outresult.velMeasureResult;
       if (denresult != null && velresult != null) {
         final feature = ref.feature!;
+        if (feature is! ShellImageFeature) return;
+        if (outresult.outerExterPoints != null) {
+          List<DPoint> outerExterPoints = [];
+          outresult.outerExterPoints?.forEach((element) {
+            outerExterPoints.add(urmApplication.viewToLocal(element));
+          });
+          feature.outerExterPoints = outerExterPoints;
+        }
 
         for (var output in ref.meta.outputs) {
           if (output.name == MeasureTerms.URMDenROI) {

+ 10 - 0
lib/process/calcuators/urm_calcuators/urm_shell_density_measure.dart

@@ -1,5 +1,6 @@
 import 'package:fis_common/logger/logger.dart';
 import 'package:fis_jsonrpc/rpc.dart';
+import 'package:fis_measure/interfaces/date_types/point.dart';
 import 'package:fis_measure/process/calcuators/urm_calcuators/urm_shell_measure.dart';
 import 'package:fis_measure/process/primitives/urm_measure/urm_shell_measure.dart';
 
@@ -25,6 +26,7 @@ class URMShellDensityMeasureCal extends URMShellMeasureCal {
         urmMeasureType: URMMeasureType.URMDen,
         rOIType: URMROIType.URMShell,
         srcDPoints: param!.srcDPoints,
+        shellWidth: 0.1,
       );
       if (outresult == null) {
         return;
@@ -33,6 +35,14 @@ class URMShellDensityMeasureCal extends URMShellMeasureCal {
       if (ref.meta.outputs.isNotEmpty) {
         final first = ref.meta.outputs.first;
         first.unit = VidUsUnit.percent;
+        if (feature is! ShellImageFeature) return;
+        if (outresult.outerExterPoints != null) {
+          List<DPoint> outerExterPoints = [];
+          outresult.outerExterPoints?.forEach((element) {
+            outerExterPoints.add(urmApplication.viewToLocal(element));
+          });
+          feature.outerExterPoints = outerExterPoints;
+        }
 
         feature.updateFloatValue(first, outresult.resultData * 100, first.unit);
       }

+ 10 - 1
lib/process/calcuators/urm_calcuators/urm_shell_fractal_dim_measure.dart

@@ -1,5 +1,6 @@
 import 'package:fis_common/logger/logger.dart';
 import 'package:fis_jsonrpc/rpc.dart';
+import 'package:fis_measure/interfaces/date_types/point.dart';
 import 'package:fis_measure/process/calcuators/urm_calcuators/urm_shell_measure.dart';
 import 'package:fis_measure/process/primitives/urm_measure/urm_shell_measure.dart';
 
@@ -25,6 +26,7 @@ class URMShellFractalDimMeasureCal extends URMShellMeasureCal {
         urmMeasureType: URMMeasureType.URMFracetalDim,
         rOIType: URMROIType.URMShell,
         srcDPoints: param!.srcDPoints,
+        shellWidth: 0.1,
       );
       if (outresult == null) {
         return;
@@ -33,7 +35,14 @@ class URMShellFractalDimMeasureCal extends URMShellMeasureCal {
       if (ref.meta.outputs.isNotEmpty) {
         final first = ref.meta.outputs.first;
         first.unit = VidUsUnit.None;
-
+        if (feature is! ShellImageFeature) return;
+        if (outresult.outerExterPoints != null) {
+          List<DPoint> outerExterPoints = [];
+          outresult.outerExterPoints?.forEach((element) {
+            outerExterPoints.add(urmApplication.viewToLocal(element));
+          });
+          feature.outerExterPoints = outerExterPoints;
+        }
         feature.updateFloatValue(first, outresult.resultData, first.unit);
       }
     } catch (e) {

+ 10 - 1
lib/process/calcuators/urm_calcuators/urm_shell_vel_measure.dart

@@ -1,5 +1,6 @@
 import 'package:fis_common/logger/logger.dart';
 import 'package:fis_jsonrpc/rpc.dart';
+import 'package:fis_measure/interfaces/date_types/point.dart';
 import 'package:fis_measure/interfaces/process/items/terms.dart';
 import 'package:fis_measure/process/calcuators/urm_calcuators/urm_shell_measure.dart';
 import 'package:fis_measure/process/primitives/urm_measure/urm_shell_measure.dart';
@@ -26,6 +27,7 @@ class URMShellVelMeasureCal extends URMShellMeasureCal {
         urmMeasureType: URMMeasureType.URMVelMeasure,
         rOIType: URMROIType.URMShell,
         srcDPoints: param!.srcDPoints,
+        shellWidth: 0.1,
       );
       if (outresult == null) {
         return;
@@ -34,7 +36,14 @@ class URMShellVelMeasureCal extends URMShellMeasureCal {
 
       if (result != null) {
         final feature = ref.feature!;
-
+        if (feature is! ShellImageFeature) return;
+        if (outresult.outerExterPoints != null) {
+          List<DPoint> outerExterPoints = [];
+          outresult.outerExterPoints?.forEach((element) {
+            outerExterPoints.add(urmApplication.viewToLocal(element));
+          });
+          feature.outerExterPoints = outerExterPoints;
+        }
         for (var output in ref.meta.outputs) {
           if (output.name == MeasureTerms.URMVelMax) {
             output.unit = VidUsUnit.mms;

+ 43 - 0
lib/process/calcuators/urm_calcuators/urm_trace_den_measure.dart

@@ -54,6 +54,49 @@ class URMTraceDenMeasureCal extends URMTraceMeasureCal {
             output.unit = VidUsUnit.None;
             feature.updateFloatValue(
                 output, math.sqrt(result.varianceDensity), output.unit);
+          } else if (output.name == MeasureTerms.InURMDenROI) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(
+                output, result.inRoiDen * 100, output.unit);
+          } else if (output.name == MeasureTerms.InURMDenFractalDim) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(
+                output, result.inRoiFractalDim, output.unit);
+          } else if (output.name == MeasureTerms.InURMDenMax) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(output, result.inMaxDensity, output.unit);
+          } else if (output.name == MeasureTerms.InURMDenMin) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(output, result.inMinDensity, output.unit);
+          } else if (output.name == MeasureTerms.InURMDenMean) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(output, result.inMeanDensity, output.unit);
+          } else if (output.name == MeasureTerms.InURMDenStd) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(
+                output, math.sqrt(result.inVarianceDensity), output.unit);
+          } else if (output.name == MeasureTerms.OutURMDenROI) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(
+                output, result.outRoiDen * 100, output.unit);
+          } else if (output.name == MeasureTerms.OutURMDenFractalDim) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(
+                output, result.outRoiFractalDim, output.unit);
+          } else if (output.name == MeasureTerms.OutURMDenMax) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(output, result.outMaxDensity, output.unit);
+          } else if (output.name == MeasureTerms.OutURMDenMin) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(output, result.outMinDensity, output.unit);
+          } else if (output.name == MeasureTerms.OutURMDenMean) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(
+                output, result.outMeanDensity, output.unit);
+          } else if (output.name == MeasureTerms.OutURMDenStd) {
+            output.unit = VidUsUnit.None;
+            feature.updateFloatValue(
+                output, math.sqrt(result.outVarianceDensity), output.unit);
           } else if (output.name == MeasureTerms.Area) {
             output.unit = VidUsUnit.cm2;
             feature.updateFloatValue(output, result.roiArea, output.unit);

+ 5 - 5
lib/process/calcuators/urm_calcuators/urm_vel.dart

@@ -10,12 +10,12 @@ class URMVelCal extends Calculator<URMVelAbstract, double> {
   void calculate() {
     if (ref.feature == null) return;
 
-    final a1 = _pickChildValue(ref.child1);
-    final a2 = _pickChildValue(ref.child2);
-    final a3 = _pickChildValue(ref.child2);
+    // final a1 = _pickChildValue(ref.child1);
+    // final a2 = _pickChildValue(ref.child2);
+    // final a3 = _pickChildValue(ref.child2);
 
-    final feature = ref.feature!;
-    final viewport = feature.hostVisualArea!.viewport!;
+    // final feature = ref.feature!;
+    // final viewport = feature.hostVisualArea!.viewport!;
 
     // if (a1 != null && a2 != null) {
     //   final value = GeneralFormulas.countStenosis(

+ 142 - 0
lib/process/calcuators/urm_calcuators/urm_vessel_measure.dart

@@ -0,0 +1,142 @@
+import 'dart:math';
+
+import 'package:fis_common/logger/logger.dart';
+import 'package:fis_jsonrpc/rpc.dart';
+import 'package:fis_measure/interfaces/process/items/terms.dart';
+import 'package:fis_measure/process/primitives/urm_measure/urm_vessel_measure.dart';
+
+// import 'package:fis_measure/process/primitives/urm_straightline.dart';
+import 'package:fis_measure/process/workspace/urm/application.dart';
+// import 'package:fis_measure/view/measure/measure_images_bar.dart';
+import 'dart:math' as math;
+import '../calculator.dart';
+
+class URMVesselMeasureCal extends Calculator<URMVesselMeasure, double> {
+  URMVesselMeasureCal(
+    URMVesselMeasure ref,
+  ) : super(ref);
+  URMSimpleMeasureParams? param;
+  @override
+  void calculate() {}
+
+  @override
+  Future<void> calculateAsync() async {
+    handleURMSimpleMeasureParams();
+    try {
+      if (ref.feature == null) return;
+      if (ref.application is! URMApplication) return;
+      final URMApplication urmApplication = ref.application as URMApplication;
+
+      URMMeasureProcessResult? outresult =
+          await urmApplication.getURMMeasureResult(
+        urmMeasureType: URMMeasureType.URMVesselMeasure,
+        rOIType: URMROIType.placeHolder_0,
+        srcDPoints: param!.srcDPoints,
+      );
+      if (outresult == null) {
+        return;
+      }
+      URMVessMeasureResult? vessMeasureResult = outresult.vessMeasureResult;
+      if (vessMeasureResult == null) {
+        return;
+      }
+      if (ref.meta.outputs.isNotEmpty) {
+        final feature = ref.feature!;
+        if (feature == null) return;
+        final viewport = feature.hostVisualArea!.viewport!;
+        final p1 = feature.startPoint;
+        final p2 = feature.endPoint;
+        final pp1 = viewport.convert(p1);
+        final pp2 = viewport.convert(p2);
+        final cmlength = (pp2 - pp1).length.abs();
+
+        for (var output in ref.meta.outputs) {
+          if (output.name == MeasureTerms.MaxVessDistance) {
+            // output.unit = VidUsUnit.None;
+            feature.updateFloatValue(
+                output, vessMeasureResult.maxVessDistance, output.unit);
+          } else if (output.name == MeasureTerms.MinVessDistance) {
+            // output.unit = VidUsUnit.None;
+            feature.updateFloatValue(
+                output, vessMeasureResult.minVessDistance, output.unit);
+          } else if (output.name == MeasureTerms.MeanVessDistacne) {
+            // output.unit = VidUsUnit.None;
+            feature.updateFloatValue(
+                output, vessMeasureResult.meanVessDistacne, output.unit);
+          } else if (output.name == MeasureTerms.StdVessDistance) {
+            // output.unit = VidUsUnit.None;
+            feature.updateFloatValue(output,
+                math.sqrt(vessMeasureResult.varianceVessDistance), output.unit);
+          } else if (output.name == MeasureTerms.MaxVessDiameter) {
+            // output.unit = VidUsUnit.None;
+            feature.updateFloatValue(
+                output, vessMeasureResult.maxVessDiameter, output.unit);
+          } else if (output.name == MeasureTerms.MinVessDiameter) {
+            // output.unit = VidUsUnit.None;
+            feature.updateFloatValue(
+                output, vessMeasureResult.minVessDiameter, output.unit);
+          } else if (output.name == MeasureTerms.MeanVessDiameter) {
+            // output.unit = VidUsUnit.None;
+            feature.updateFloatValue(
+                output, vessMeasureResult.meanVessDiameter, output.unit);
+          } else if (output.name == MeasureTerms.StdVessDiameter) {
+            // output.unit = VidUsUnit.None;
+            feature.updateFloatValue(output,
+                math.sqrt(vessMeasureResult.varianceVessDiameter), output.unit);
+          } else if (output.name == MeasureTerms.VesselCount) {
+            // output.unit = VidUsUnit.None;
+            feature.updateFloatValue(
+                output, vessMeasureResult.vesselCount.toDouble(), output.unit);
+          } else if (output.name == MeasureTerms.Distance) {
+            // output.unit = VidUsUnit.None;
+
+            feature.updateFloatValue(output, cmlength, output.unit);
+          }
+          List<Point<num>> points = [];
+          outresult.resultDPoints?.forEach((element) {
+            points.add(Point(element.x, element.y));
+          });
+
+          urmApplication.onUpdateChart?.call(
+            URMChartParams(
+              cmlength: cmlength,
+              minPointIndex: vessMeasureResult.minPos,
+              maxPointIndex: vessMeasureResult.maxPos,
+              points: points,
+            ),
+          );
+        }
+      }
+    } catch (e) {
+      logger.e('URM Measure error: $e');
+      return;
+    }
+    ref.application.updateRenderReady.emit(this, null);
+  }
+
+  /// 处理获取到的URM参数
+  void handleURMSimpleMeasureParams() {
+    if (ref.feature == null) return;
+
+    try {
+      if (ref.application is! URMApplication) {
+        return;
+      }
+      final URMApplication urmApplication = ref.application as URMApplication;
+
+      final p1 = ref.feature!.startPoint;
+      final p2 = ref.feature!.endPoint;
+
+      param = URMSimpleMeasureParams(
+        urmMeasureType: URMMeasureType.URMVesselMeasure,
+        rOIType: URMROIType.placeHolder_0,
+        srcDPoints: [
+          urmApplication.localToView(p1),
+          urmApplication.localToView(p2)
+        ],
+      );
+    } catch (e) {
+      logger.e('URM handleURMSimpleMeasureParams error: $e');
+    }
+  }
+}

+ 22 - 4
lib/process/items/factory.dart

@@ -19,9 +19,9 @@ import 'package:fis_measure/process/primitives/combos/two_location.dart';
 import 'package:fis_measure/process/primitives/combos/two_ray.dart';
 import 'package:fis_measure/process/primitives/combos/two_straightline.dart';
 import 'package:fis_measure/process/primitives/combos/two_sv.dart';
-import 'package:fis_measure/process/primitives/urm_measure/ab_ratio.dart';
 import 'package:fis_measure/process/primitives/urm_measure/urm_den.dart';
 import 'package:fis_measure/process/primitives/urm_measure/urm_trace_measure.dart';
+import 'package:fis_measure/process/primitives/urm_measure/urm_two_rect_den.dart';
 import 'package:fis_measure/process/primitives/urm_measure/urm_vel.dart';
 import 'package:fis_measure/process/primitives/detection.dart';
 import 'package:fis_measure/process/primitives/ellipse.dart';
@@ -255,7 +255,7 @@ class MeasureItemFactory {
     // URM 超分辨
 
     // _singleton._register(MeasureTypes.URMCurvature,
-    //     URMStraightCurvatureLineMeasure.createURMStraightCurvatureLineMeasure);
+    //     URMCurvatureMeasure.createURMCurvatureMeasure);
     _singleton._register(MeasureTypes.URMStraightCurvatureLineMeasure,
         URMStraightCurvatureLineMeasure.createURMStraightCurvatureLineMeasure);
     _singleton._register(MeasureTypes.URMCurveCurvatureLineMeasure,
@@ -288,8 +288,9 @@ class MeasureItemFactory {
     //     AutoUterusVertical.CreateAutoUterusVertical);
     // _singleton._register(
     //     MeasureTypes.AutoUterusCross, AutoUterusCross.CreateAutoUterusCross);
-    _singleton._register(MeasureTypes.URMDensityRation, AbRatio.create);
-    _singleton._register(MeasureTypes.URMFractalDimRation, AbRatio.create);
+
+    // _singleton._register(MeasureTypes.URMDensityRation, AbRatio.create);
+    // _singleton._register(MeasureTypes.URMFractalDimRation, AbRatio.create);
     _singleton._register(
         MeasureTypes.URMRectDenMeasure, URMRectMeasure.createURMRectDenMeasure);
     _singleton._register(MeasureTypes.URMTraceDenMeasure,
@@ -354,6 +355,23 @@ class MeasureItemFactory {
     _singleton._register(MeasureTypes.URMShellDenVelMeasure,
         URMShellMeasure.createURMShellDenVelMeasure);
 
+    /// 新增的
+    _singleton._register(
+        MeasureTypes.DensityTwoURMRect, TwoURMRectDen.createTwoURMRectDen);
+
+    _singleton._register(
+        MeasureTypes.DensityTwoTrace, TwoURMTraceDen.createTwoURMTraceDen);
+    _singleton._register(MeasureTypes.DensityTwoEllipse,
+        TwoURMEllipseDen.createTwoURMEllipseDen);
+
+    /// 遗漏项
+    _singleton._register(MeasureTypes.FractalDimTwoURMRect,
+        TwoURMRectFractal.createTwoURMRectFractal);
+    _singleton._register(MeasureTypes.FractalDimTwoURMTrace,
+        TwoURMTraceFractal.createTwoURMTraceFractal);
+    _singleton._register(MeasureTypes.FractalDimTwoURMEllipse,
+        TwoURMEllipseFractal.createTwoURMEllipseFractal);
+
     _singleton._register(
       MeasureTypes.SemiautoTrace,
       SemiautoTrace.createTrace,

+ 7 - 0
lib/process/items/item_feature.dart

@@ -28,6 +28,8 @@ abstract class MeasureItemFeature implements IMeasureItemFeature {
   int _activeIndex = -1;
   Rect? zoomRect; // 当前缩放区域的归一化坐标
 
+  bool? isURMDualImages; // 是否是URM 双幅图
+
   @override
   int? frameIndex;
 
@@ -201,6 +203,11 @@ abstract class MeasureItemFeature implements IMeasureItemFeature {
     zoomRect = rect;
   }
 
+  @override
+  void setURMDualImages(bool? isURMDual) {
+    isURMDualImages = isURMDual;
+  }
+
   @override
   void paintPerfusion(
     Canvas canvas,

+ 36 - 16
lib/process/primitives/ellipse.dart

@@ -227,6 +227,7 @@ class EllipseFeature extends AreaItemFeatureAbstract {
         height: radiusY * 2,
       ),
     );
+
     canvas.drawPath(
       dashPath(
         path,
@@ -234,6 +235,7 @@ class EllipseFeature extends AreaItemFeatureAbstract {
       ),
       paintPan,
     );
+
     canvas.restore();
 
     if (activeIndex == 1) {
@@ -259,8 +261,10 @@ class EllipseFeature extends AreaItemFeatureAbstract {
     var p1 = xAxisStart;
     var p2 = xAxisEnd;
     if (fitSize != null) {
-      p1 = p1.scale2Size(fitSize);
-      p2 = p2.scale2Size(fitSize);
+      p1 = convert2ViewPoint(fitSize, p1);
+      p2 = convert2ViewPoint(fitSize, p2);
+      // p1 = p1.scale2Size(fitSize);
+      // p2 = p2.scale2Size(fitSize);
     }
     return (p2 - p1).length / 2;
   }
@@ -272,9 +276,12 @@ class EllipseFeature extends AreaItemFeatureAbstract {
       var p2 = yAxisEnd;
       var c = centroid;
       if (fitSize != null) {
-        p = p.scale2Size(fitSize);
-        p2 = p2.scale2Size(fitSize);
-        c = c.scale2Size(fitSize);
+        p = convert2ViewPoint(fitSize, p);
+        p2 = convert2ViewPoint(fitSize, p2);
+        c = convert2ViewPoint(fitSize, c);
+        // p = p.scale2Size(fitSize);
+        // p2 = p2.scale2Size(fitSize);
+        // c = c.scale2Size(fitSize);
       }
       return (p - p2).length / 2;
     } else {
@@ -301,27 +308,40 @@ class EllipseFeature extends AreaItemFeatureAbstract {
   /// 计算Y轴坐标点
   void adjustPoints(DPoint point) {
     if (activeIndex < 1) return;
-
-    final refSize = refItem.application.displaySize;
+    Size refSize;
+    if (refItem.feature?.isURMDualImages ?? false) {
+      refSize = Size(refItem.application.displaySize.width / 2,
+          refItem.application.displaySize.height);
+    } else {
+      refSize = refItem.application.displaySize;
+    }
+    // final refSize = Size(refItem.application.displaySize.width / 2,
+    //     refItem.application.displaySize.height);
     //  const refSize= Size(1000, 1000);
     // const restoreSize = Size(1 / 1000, 1 / 1000);
     final restoreSize = Size(1 / refSize.width, 1 / refSize.height);
-    final p = point.scale2Size(refSize);
-    final p1 = xAxisStart.scale2Size(refSize);
-    final p2 = xAxisEnd.scale2Size(refSize);
+    // final p = point.scale2Size(refSize);
+    // final p1 = xAxisStart.scale2Size(refSize);
+    // final p2 = xAxisEnd.scale2Size(refSize);
+
+    final p = convert2ViewPoint(refSize, point);
+    final p1 = convert2ViewPoint(refSize, xAxisStart);
+    final p2 = convert2ViewPoint(refSize, xAxisEnd);
     final double radius;
     if (activeIndex == 2) {
       radius = GeneralFormulas.distance2Line(p1, p2, p);
     } else {
       radius = getRadiusX(refSize);
     }
-    final crossPoints = _findCrossPoints(p2, p1, radius);
-    final p3Index = _findNearest(p, crossPoints);
-    innerPoints[2] = crossPoints[p3Index].scale2Size(restoreSize);
-    innerPoints[3] = crossPoints[1 - p3Index].scale2Size(restoreSize);
+    final crossPoints = findCrossPoints(p2, p1, radius);
+    final p3Index = findNearest(p, crossPoints);
+    // innerPoints[2] = crossPoints[p3Index].scale2Size(restoreSize);
+    // innerPoints[3] = crossPoints[1 - p3Index].scale2Size(restoreSize);
+    innerPoints[2] = convert2ViewPoint(restoreSize, crossPoints[p3Index]);
+    innerPoints[3] = convert2ViewPoint(restoreSize, crossPoints[1 - p3Index]);
   }
 
-  static List<DPoint> _findCrossPoints(DPoint a, DPoint b, distance) {
+  List<DPoint> findCrossPoints(DPoint a, DPoint b, distance) {
     final dx = b.x - a.x;
     final dy = b.y - a.y;
 
@@ -349,7 +369,7 @@ class EllipseFeature extends AreaItemFeatureAbstract {
     return [out1, out2];
   }
 
-  static int _findNearest(DPoint p, List<DPoint> source) {
+  int findNearest(DPoint p, List<DPoint> source) {
     int rst = 0;
     double minLen = (source[0] - p).length;
     for (var i = 1; i < source.length; i++) {

+ 26 - 7
lib/process/primitives/urm_measure/ab_ratio.dart

@@ -1,15 +1,34 @@
 import 'package:fis_measure/interfaces/process/items/item.dart';
 import 'package:fis_measure/interfaces/process/items/item_metas.dart';
-import 'package:fis_measure/process/calcuators/distance.dart';
-import 'package:fis_measure/process/primitives/straightline.dart';
+import 'package:fis_measure/process/items/item.dart';
+import 'package:fis_measure/process/items/item_feature.dart';
+import 'package:fis_measure/process/items/top_item.dart';
+import 'package:fis_measure/process/items/top_item_feature.dart';
 
 /// TODO 暂时这样写
-class AbRatio extends StraightLine {
-  AbRatio(super.meta, super.parent);
+class AbRatio {
+  AbRatio(meta, parent);
 
   static AbRatio create(ItemMeta meta, [IMeasureItem? parent]) {
-    AbRatio measureVessel = AbRatio(meta, parent);
-    measureVessel.calculator = DistanceCal(measureVessel);
-    return measureVessel;
+    var urmAbRatio = AbRatio(meta, parent);
+
+    return urmAbRatio;
   }
 }
+
+abstract class URMAbRatioAbstract<T extends MeasureItemFeature>
+    extends TopMeasureItem<T> {
+  URMAbRatioAbstract(ItemMeta meta) : super(meta);
+
+  MeasureItem get child1;
+  MeasureItem get child2;
+
+  @override
+  bool get finishAfterUnactive => true;
+}
+
+class URMAbRatioFeature extends TopMeasureItemFeature {
+  URMAbRatioFeature(
+    ITopMeasureItem refItem,
+  ) : super(refItem);
+}

+ 18 - 0
lib/process/primitives/urm_measure/urm_curvature_measure.dart

@@ -0,0 +1,18 @@
+import 'package:fis_measure/interfaces/process/items/item.dart';
+import 'package:fis_measure/interfaces/process/items/item_metas.dart';
+import 'package:fis_measure/interfaces/process/items/types.dart';
+
+class URMCurvatureMeasure {
+  static String revertRatioName = "URMCurvature(E/A)";
+  static String ratioName = "URMCurvature(A/E)";
+  URMCurvatureMeasure(ItemMeta meta, IMeasureItem parent);
+
+  static URMCurvatureMeasure createURMCurvatureMeasure(
+      ItemMeta meta, IMeasureItem parent) {
+    if (meta.measureType != MeasureTypes.URMCurvature) {
+      throw ArgumentError();
+    }
+    var item = URMCurvatureMeasure(meta, parent);
+    return item;
+  }
+}

+ 1 - 0
lib/process/primitives/urm_measure/urm_ellipse_measure.dart

@@ -187,6 +187,7 @@ class EllipsePerfusionImageFeature extends EllipseFeature {
       convert2ViewPoint(size, rightBottomPoint!);
       Rect dst = Rect.fromPoints(
           Offset(leftTop.x, leftTop.y), Offset(rightBottom.x, rightBottom.y));
+
       canvas.drawImageRect(perfusionImg!, src, dst, paint);
     }
   }

+ 27 - 1
lib/process/primitives/urm_measure/urm_shell_measure.dart

@@ -117,7 +117,12 @@ class URMShellMeasure extends Trace {
     if (meta.measureType == MeasureTypes.URMShellPerfusionMeasure) {
       feature = ShellPerfusionImageFeature(this);
     } else {
-      super.handleMouseDownWhileWaiting(args);
+      feature = ShellImageFeature(this);
+      // if (args.hostVisualArea != null) {
+      //   feature!.hostVisualArea = args.hostVisualArea;
+      // }
+      // final point = args.toAreaLogicPoint();
+      // feature!.adopt(point);
     }
     state = ItemStates.running;
   }
@@ -176,6 +181,27 @@ class URMShellMeasure extends Trace {
   }
 }
 
+class ShellImageFeature extends TraceFeature {
+  ShellImageFeature(AreaItemAbstract refItem) : super(refItem);
+
+  List<DPoint> outerExterPoints = [];
+
+  /// 绘制灌注图
+  @override
+  void paint(Canvas canvas, Size size) {
+    super.paint(canvas, size);
+
+    if (outerExterPoints.isEmpty) {
+      return;
+    }
+    final pixelPoints = outerExterPoints.map((e) {
+      return convert2ViewPoint(size, e).toOffset();
+    }).toList();
+
+    canvas.drawDashPointsLine(pixelPoints, 1, 10, paintLinePan, close: true);
+  }
+}
+
 class ShellPerfusionImageFeature extends TraceFeature {
   ShellPerfusionImageFeature(AreaItemAbstract refItem) : super(refItem);
 

+ 255 - 0
lib/process/primitives/urm_measure/urm_two_rect_den.dart

@@ -0,0 +1,255 @@
+import 'package:fis_measure/interfaces/process/items/item.dart';
+import 'package:fis_measure/interfaces/process/items/item_metas.dart';
+import 'package:fis_measure/process/calcuators/urm_calcuators/urm_ab_ratio.dart';
+import 'package:fis_measure/process/items/item.dart';
+import 'package:fis_measure/process/items/item_feature.dart';
+import 'package:fis_measure/process/items/top_item.dart';
+import 'package:fis_measure/process/items/top_item_feature.dart';
+import 'package:fis_measure/process/primitives/urm_measure/urm_ellipse_measure.dart';
+import 'package:fis_measure/process/primitives/urm_measure/urm_rect_measure.dart';
+import 'package:fis_measure/process/primitives/urm_measure/urm_trace_measure.dart';
+
+/// TODO 暂时这样写 -需要优化一下下
+///
+class TwoURMRectDen extends URMTwoURMRectDenAbstract<URMTwoURMRectDenFeature> {
+  static const String _area1Key = "Roi1";
+  static const String _area2Key = "Roi2";
+
+  late final URMRectMeasure a1;
+  late final URMRectMeasure a2;
+
+  TwoURMRectDen(ItemMeta meta) : super(meta) {
+    final metaA1 = meta.getChildByName(_area1Key)!;
+    final metaA2 = meta.getChildByName(_area2Key)!;
+    a1 = URMRectMeasure.createURMRectDensity(metaA1, this);
+    a2 = URMRectMeasure.createURMRectDensity(metaA2, this);
+    childItems.add(a1);
+    childItems.add(a2);
+  }
+
+  @override
+  URMRectMeasure get child1 => a1;
+
+  @override
+  URMRectMeasure get child2 => a2;
+
+  @override
+  URMTwoURMRectDenFeature buildFeature() => URMTwoURMRectDenFeature(this);
+
+  @override
+  void onCancelingOnce() {}
+
+  static TwoURMRectDen createTwoURMRectDen(ItemMeta meta,
+      [IMeasureItem? parent]) {
+    var urmTwoURMRectDen = TwoURMRectDen(meta);
+    urmTwoURMRectDen.calculator = TwoURMRectDenCal(urmTwoURMRectDen);
+
+    return urmTwoURMRectDen;
+  }
+}
+
+class TwoURMTraceDen extends URMTwoURMRectDenAbstract<URMTwoURMRectDenFeature> {
+  static const String _area1Key = "Roi1";
+  static const String _area2Key = "Roi2";
+
+  late final URMTraceMeasure a1;
+  late final URMTraceMeasure a2;
+
+  TwoURMTraceDen(ItemMeta meta) : super(meta) {
+    final metaA1 = meta.getChildByName(_area1Key)!;
+    final metaA2 = meta.getChildByName(_area2Key)!;
+    a1 = URMTraceMeasure.createURMTraceDensity(metaA1, this);
+    a2 = URMTraceMeasure.createURMTraceDensity(metaA2, this);
+    childItems.add(a1);
+    childItems.add(a2);
+  }
+
+  @override
+  URMTraceMeasure get child1 => a1;
+
+  @override
+  URMTraceMeasure get child2 => a2;
+
+  @override
+  URMTwoURMRectDenFeature buildFeature() => URMTwoURMRectDenFeature(this);
+
+  @override
+  void onCancelingOnce() {}
+
+  static TwoURMTraceDen createTwoURMTraceDen(ItemMeta meta,
+      [IMeasureItem? parent]) {
+    var urmTwoURMRectDen = TwoURMTraceDen(meta);
+    urmTwoURMRectDen.calculator = TwoURMTraceDenCal(urmTwoURMRectDen);
+
+    return urmTwoURMRectDen;
+  }
+}
+
+class TwoURMEllipseDen
+    extends URMTwoURMRectDenAbstract<URMTwoURMRectDenFeature> {
+  static const String _area1Key = "Roi1";
+  static const String _area2Key = "Roi2";
+
+  late final URMEllipseMeasure a1;
+  late final URMEllipseMeasure a2;
+
+  TwoURMEllipseDen(ItemMeta meta) : super(meta) {
+    final metaA1 = meta.getChildByName(_area1Key)!;
+    final metaA2 = meta.getChildByName(_area2Key)!;
+    a1 = URMEllipseMeasure.createURMEllipseDensity(metaA1, this);
+    a2 = URMEllipseMeasure.createURMEllipseDensity(metaA2, this);
+    childItems.add(a1);
+    childItems.add(a2);
+  }
+
+  @override
+  URMEllipseMeasure get child1 => a1;
+
+  @override
+  URMEllipseMeasure get child2 => a2;
+
+  @override
+  URMTwoURMRectDenFeature buildFeature() => URMTwoURMRectDenFeature(this);
+
+  @override
+  void onCancelingOnce() {}
+
+  static TwoURMEllipseDen createTwoURMEllipseDen(ItemMeta meta,
+      [IMeasureItem? parent]) {
+    var urmTwoURMRectDen = TwoURMEllipseDen(meta);
+    urmTwoURMRectDen.calculator = TwoURMEllipseDenCal(urmTwoURMRectDen);
+
+    return urmTwoURMRectDen;
+  }
+}
+
+class TwoURMRectFractal
+    extends URMTwoURMRectDenAbstract<URMTwoURMRectDenFeature> {
+  static const String _area1Key = "Roi1";
+  static const String _area2Key = "Roi2";
+
+  late final URMRectMeasure a1;
+  late final URMRectMeasure a2;
+
+  TwoURMRectFractal(ItemMeta meta) : super(meta) {
+    final metaA1 = meta.getChildByName(_area1Key)!;
+    final metaA2 = meta.getChildByName(_area2Key)!;
+    a1 = URMRectMeasure.createURMRectFractalDim(metaA1, this);
+    a2 = URMRectMeasure.createURMRectFractalDim(metaA2, this);
+    childItems.add(a1);
+    childItems.add(a2);
+  }
+
+  @override
+  URMRectMeasure get child1 => a1;
+
+  @override
+  URMRectMeasure get child2 => a2;
+
+  @override
+  URMTwoURMRectDenFeature buildFeature() => URMTwoURMRectDenFeature(this);
+
+  @override
+  void onCancelingOnce() {}
+
+  static TwoURMRectFractal createTwoURMRectFractal(ItemMeta meta,
+      [IMeasureItem? parent]) {
+    var urmTwoURMRectDen = TwoURMRectFractal(meta);
+    urmTwoURMRectDen.calculator = TwoURMRectFractalCal(urmTwoURMRectDen);
+
+    return urmTwoURMRectDen;
+  }
+}
+
+class TwoURMTraceFractal
+    extends URMTwoURMRectDenAbstract<URMTwoURMRectDenFeature> {
+  static const String _area1Key = "Roi1";
+  static const String _area2Key = "Roi2";
+
+  late final URMTraceMeasure a1;
+  late final URMTraceMeasure a2;
+
+  TwoURMTraceFractal(ItemMeta meta) : super(meta) {
+    final metaA1 = meta.getChildByName(_area1Key)!;
+    final metaA2 = meta.getChildByName(_area2Key)!;
+    a1 = URMTraceMeasure.createURMTraceFractalDim(metaA1, this);
+    a2 = URMTraceMeasure.createURMTraceFractalDim(metaA2, this);
+    childItems.add(a1);
+    childItems.add(a2);
+  }
+
+  @override
+  URMTraceMeasure get child1 => a1;
+
+  @override
+  URMTraceMeasure get child2 => a2;
+
+  @override
+  URMTwoURMRectDenFeature buildFeature() => URMTwoURMRectDenFeature(this);
+
+  @override
+  void onCancelingOnce() {}
+
+  static TwoURMTraceFractal createTwoURMTraceFractal(ItemMeta meta,
+      [IMeasureItem? parent]) {
+    var urmTwoURMRectDen = TwoURMTraceFractal(meta);
+    urmTwoURMRectDen.calculator = TwoURMTraceFractalCal(urmTwoURMRectDen);
+
+    return urmTwoURMRectDen;
+  }
+}
+
+class TwoURMEllipseFractal
+    extends URMTwoURMRectDenAbstract<URMTwoURMRectDenFeature> {
+  static const String _area1Key = "Roi1";
+  static const String _area2Key = "Roi2";
+
+  late final URMEllipseMeasure a1;
+  late final URMEllipseMeasure a2;
+
+  TwoURMEllipseFractal(ItemMeta meta) : super(meta) {
+    final metaA1 = meta.getChildByName(_area1Key)!;
+    final metaA2 = meta.getChildByName(_area2Key)!;
+    a1 = URMEllipseMeasure.createURMEllipseFractalDim(metaA1, this);
+    a2 = URMEllipseMeasure.createURMEllipseFractalDim(metaA2, this);
+    childItems.add(a1);
+    childItems.add(a2);
+  }
+
+  @override
+  URMEllipseMeasure get child1 => a1;
+
+  @override
+  URMEllipseMeasure get child2 => a2;
+
+  @override
+  URMTwoURMRectDenFeature buildFeature() => URMTwoURMRectDenFeature(this);
+
+  @override
+  void onCancelingOnce() {}
+
+  static TwoURMEllipseFractal createTwoURMEllipseFractal(ItemMeta meta,
+      [IMeasureItem? parent]) {
+    var urmTwoURMRectDen = TwoURMEllipseFractal(meta);
+    urmTwoURMRectDen.calculator = TwoURMEllipseFractalCal(urmTwoURMRectDen);
+
+    return urmTwoURMRectDen;
+  }
+}
+
+abstract class URMTwoURMRectDenAbstract<T extends MeasureItemFeature>
+    extends TopMeasureItem<T> {
+  URMTwoURMRectDenAbstract(ItemMeta meta) : super(meta);
+
+  MeasureItem get child1;
+  MeasureItem get child2;
+
+  @override
+  bool get finishAfterUnactive => true;
+}
+
+class URMTwoURMRectDenFeature extends TopMeasureItemFeature {
+  URMTwoURMRectDenFeature(
+    ITopMeasureItem refItem,
+  ) : super(refItem);
+}

+ 5 - 6
lib/process/primitives/urm_measure/urm_vel.dart

@@ -1,20 +1,19 @@
 import 'package:fis_measure/interfaces/process/items/item.dart';
 import 'package:fis_measure/interfaces/process/items/item_metas.dart';
-import 'package:fis_measure/process/calcuators/urm.dart';
 import 'package:fis_measure/process/calcuators/urm_calcuators/urm_vel.dart';
 import 'package:fis_measure/process/items/top_item_feature.dart';
 import 'package:fis_measure/process/primitives/straightline.dart';
-import 'package:fis_measure/process/primitives/urm_location.dart';
 import 'package:fis_measure/process/items/item.dart';
 import 'package:fis_measure/process/items/item_feature.dart';
 import 'package:fis_measure/process/items/top_item.dart';
+import 'package:fis_measure/process/primitives/urm_measure/urm_location_vel.dart';
 
 class URMVel extends URMVelAbstract<URMVelFeature> {
-  static const String _area1Key = "SRLoactionVel";
+  static const String _area1Key = "URMLocationVel";
   static const String _area2Key = "Vessel diameter";
   static const String _area3Key = "Vessel distance";
 
-  late final URMLoaction a1;
+  late final URMLocationVelMeasure a1;
   late final StraightLine a2;
   late final StraightLine a3;
 
@@ -22,7 +21,7 @@ class URMVel extends URMVelAbstract<URMVelFeature> {
     final metaA1 = meta.getChildByName(_area1Key)!;
     final metaA2 = meta.getChildByName(_area2Key)!;
     final metaA3 = meta.getChildByName(_area3Key)!;
-    a1 = URMLoaction.createURMLocation(metaA1, this);
+    a1 = URMLocationVelMeasure.createURMLocationVelMeasure(metaA1, this);
     a2 = StraightLine.createDistance(metaA2, this);
     a3 = StraightLine.createDistance(metaA3, this);
     childItems.add(a1);
@@ -31,7 +30,7 @@ class URMVel extends URMVelAbstract<URMVelFeature> {
   }
 
   @override
-  URMLoaction get child1 => a1;
+  URMLocationVelMeasure get child1 => a1;
 
   @override
   StraightLine get child2 => a2;

+ 61 - 2
lib/process/primitives/urm_measure/urm_vessel_measure.dart

@@ -1,7 +1,11 @@
+import 'package:fis_measure/interfaces/enums/items.dart';
 import 'package:fis_measure/interfaces/process/items/item.dart';
 import 'package:fis_measure/interfaces/process/items/item_metas.dart';
-import 'package:fis_measure/process/calcuators/distance.dart';
+import 'package:fis_measure/interfaces/process/workspace/point_info.dart';
+import 'package:fis_measure/process/calcuators/urm_calcuators/urm_vessel_measure.dart';
 import 'package:fis_measure/process/primitives/straightline.dart';
+import 'package:fis_measure/utils/prompt_box.dart';
+import 'package:fis_measure/view/gesture/cross_position_indicator.dart';
 
 class URMVesselMeasure extends StraightLine {
   URMVesselMeasure(super.meta, super.parent);
@@ -9,7 +13,62 @@ class URMVesselMeasure extends StraightLine {
   static URMVesselMeasure createURMVesselMeasure(ItemMeta meta,
       [IMeasureItem? parent]) {
     URMVesselMeasure measureVessel = URMVesselMeasure(meta, parent);
-    measureVessel.calculator = DistanceCal(measureVessel);
+    measureVessel.calculator = URMVesselMeasureCal(measureVessel);
+
     return measureVessel;
   }
+
+  @override
+  bool onExecuteMouse(PointInfo args) {
+    if (state == ItemStates.finished) {
+      if (args.pointType == PointInfoType.mouseDown) {
+        state = ItemStates.waiting;
+      } else {
+        return false;
+      }
+    }
+
+    if (state == ItemStates.waiting) {
+      if (args.pointType == PointInfoType.mouseDown) {
+        handleMouseDownWhileWaiting(args);
+      }
+    } else if (state == ItemStates.running) {
+      if (args.pointType == PointInfoType.mouseUp) return false;
+
+      feature?.endPoint = args;
+      doCalculate();
+      if (args.pointType == PointInfoType.mouseDown) {
+        handleFinish();
+
+        ///重置十字样式
+        changeCrossIndicatorStyle(CrossIndicatorStyle.nomal);
+      }
+    }
+    return true;
+  }
+
+  @override
+  void handleMouseDownWhileWaiting(PointInfo args) {
+    // TODO: 判断是否当前area
+    // 转换为Area逻辑位置
+    final point = args.toAreaLogicPoint();
+    // feature = StraightLineFeature(this, point, point);
+    if (args.hostVisualArea != null) {
+      handleTissueTM(args.hostVisualArea!.mode.modeType, point);
+      feature!.hostVisualArea = args.hostVisualArea;
+    }
+    state = ItemStates.running;
+  }
+
+  bool waitingResult = false;
+
+  void handleFinish() async {
+    feature!.isActive = false;
+    PromptBox.loading("计算中...");
+    waitingResult = true;
+    await doCalculateAsync();
+    doFeatureFinish();
+    PromptBox.dismiss();
+    waitingResult = false;
+  }
 }