فهرست منبع

Merge branch 'master' of http://git.ius.plus:88/melon.yin/fis_lib_measure

gavin.chen 2 سال پیش
والد
کامیت
da6ca58110

+ 0 - 9
lib/interfaces/process/calculators/calculator.dart

@@ -3,18 +3,9 @@ import 'package:fis_common/event/event_type.dart';
 import 'output.dart';
 
 abstract class ICalculator<TValue> {
-  /// 输出结果
-  OutputItem<TValue>? get output;
-
-  /// 结果记录集合
-  List<OutputItem<TValue>> get outputs;
-
   /// 计算
   void calculate();
 
   /// 结束一次测算
   void finishOnce();
-
-  /// 输出结果变化事件
-  late FEventHandler<OutputItem<TValue>?> outputChanged;
 }

+ 4 - 0
lib/measure_page_test.dart

@@ -16,6 +16,8 @@ import 'package:fis_measure/view/measure/measure_main_view.dart';
 import 'package:flutter/material.dart';
 import 'package:get/get.dart';
 
+import 'process/workspace/measure_handler.dart';
+
 class MeasureDataTester {
   static Future<List<RemedicalItemList>> getRemedicalList(
     String patientCode,
@@ -111,6 +113,7 @@ class _MeasureTestPageState extends State<MeasureTestPage> {
     MeasureDataTester.getCommentsByApplicationAsync,
     MeasureDataTester.saveUserDefinedCommentsAsync,
   ));
+  final measureHandler = Get.put(MeasureHandler());
   final controller = Get.put<IMeasureController>(MeasureController(
     "12345",
     imagesFetchFunc: (code) async {
@@ -127,6 +130,7 @@ class _MeasureTestPageState extends State<MeasureTestPage> {
 
   @override
   void initState() {
+    measureHandler.changeImageLoaded;
     controller.load().then((value) {
       // 加载指定图像
       controller.examInfo.selectedImageIndex = 0;

+ 0 - 5
lib/process/calcuators/area.dart

@@ -21,11 +21,6 @@ class TraceAreaCal extends Calculator<Trace, double> {
         ref.feature!.innerPoints.map((e) => viewport.convert(e)).toList();
 
     double value = clacArea(points);
-    final outputItem = createOutput(MeasureTypes.Area, value, VidUsUnit.cm2);
-    final description = "${ref.description}: ${roundDouble(value)}cm²";
-    outputItem.updateDescription(description: description);
-    output = outputItem;
-
     updateFloatValue(value);
   }
 

+ 8 - 32
lib/process/calcuators/calculator.dart

@@ -8,39 +8,19 @@ import 'package:vid/us/vid_us_unit.dart';
 
 abstract class Calculator<T extends IMeasureItem, TValue>
     implements ICalculator<TValue> {
-  final List<OutputItem<TValue>> _outputs = [];
-  OutputItem<TValue>? _outputItem;
   late T _ref;
 
   Calculator(T ref) {
     _ref = ref;
   }
 
-  @override
-  OutputItem<TValue>? get output => _outputItem;
-  @protected
-  set output(OutputItem<TValue>? value) {
-    if (value != _outputItem) {
-      _outputItem = value;
-      outputChanged.emit(this, value);
-    }
-  }
-
-  @override
-  List<OutputItem<TValue>> get outputs => _outputs;
-
   T get ref => _ref;
 
   @override
   var outputChanged = FEventHandler<OutputItem<TValue>?>();
 
   @override
-  void finishOnce() {
-    if (output != null) {
-      outputs.add(output!);
-      output = null;
-    }
-  }
+  void finishOnce() {}
 
   @protected
   void updateFloatValue(double value) {
@@ -50,6 +30,13 @@ abstract class Calculator<T extends IMeasureItem, TValue>
     feature.updateFloatValue(ref.meta.outputs.first, value, viewport.xUnit);
   }
 
+  @protected
+  void updateStringValue(String value) {
+    if (ref.feature == null) return;
+    final feature = ref.feature! as MeasureItemFeature;
+    feature.updateStringValue(ref.meta.outputs.first, value);
+  }
+
   /// 对double四舍五入
   double roundDouble(double value, [int digits = 2]) {
     final digitsStr = value.toStringAsFixed(digits);
@@ -57,17 +44,6 @@ abstract class Calculator<T extends IMeasureItem, TValue>
     return result;
   }
 
-  /// 创建计算结果
-  @protected
-  OutputItem<TValue> createOutput(String name, TValue value, VidUsUnit unit) {
-    return OutputItem<TValue>(
-      id: ref.assignId(),
-      value: value,
-      name: name,
-      unit: unit,
-    );
-  }
-
   /// 获取结果精度
   @protected
   int getResultDigits(OutputItem item) {

+ 13 - 15
lib/process/calcuators/carotid_imt.dart

@@ -24,7 +24,6 @@ class CarotidCal extends Calculator<CarotidIMT, double> {
     //右下顶点
     final rightBottomPoint =
         DPoint(p1.x > p2.x ? p1.x : p2.x, p1.y > p2.y ? p1.y : p2.y);
-    final outputItem = createOutput(type, 0.0, VidUsUnit.cm);
     //图片尺寸
     final imageSize = ref.application.carotid2DSize;
     //画布尺寸
@@ -91,6 +90,7 @@ class CarotidCal extends Calculator<CarotidIMT, double> {
         "{'MeasureItemType':'$measureItemType','IntimaRect':{'Left':$rectLeft,'Top':$rectTop,'Width':$rectWidth,'Height':$rectHeight}}";
 
     String description = "IMT\n Measuring";
+    updateStringValue(description);
     List<Offset> getPointsFromStrList(List pointsStr) {
       final points = <Offset>[];
       for (var point in pointsStr) {
@@ -107,14 +107,15 @@ class CarotidCal extends Calculator<CarotidIMT, double> {
         'then',
         [
           (result) {
+            final feature = ref.feature!;
             // print("getMeasureResult: $result");
             if (result == 'error') {
-              outputs.add(outputItem);
-              outputs.last
-                  .updateDescription(description: "$type\n Measure failed");
+              description = "$type\n Measure failed";
+              updateStringValue(description);
               ref.application.updateRenderReady.emit(this, null);
               return;
             }
+
             final res = jsonDecode(result);
             if (res['ErrorCode'].toString() == "1000") {
               if (type != 'Both.CCA IMT') {
@@ -125,25 +126,24 @@ class CarotidCal extends Calculator<CarotidIMT, double> {
                     "$type\n Ant Max: ${res['LowerMeasureResult']['MaxThickness'].toStringAsFixed(2)}mm\n Ant.Min: ${res['LowerMeasureResult']['MinThickness'].toStringAsFixed(2)}mm\n Ant.Avg: ${res['LowerMeasureResult']['AverageThickness'].toStringAsFixed(2)}mm\n Ant.SD: ${res['LowerMeasureResult']['SdThickness'].toStringAsFixed(2)}mm\n Post.Max: ${res['UpperMeasureResult']['MaxThickness'].toStringAsFixed(2)}mm\n Post.Min: ${res['UpperMeasureResult']['MinThickness'].toStringAsFixed(2)}mm\n Post.Avg: ${res['UpperMeasureResult']['AverageThickness'].toStringAsFixed(2)}mm\n Post.SD: ${res['UpperMeasureResult']['SdThickness'].toStringAsFixed(2)}mm";
               }
               if (type != 'Both.CCA IMT') {
-                ref.feature!.offsetsList
+                feature.offsetsList
                     .add(getPointsFromStrList(res['PointLower']));
-                ref.feature!.offsetsList
+                feature.offsetsList
                     .add(getPointsFromStrList(res['PointUpper']));
               } else {
-                ref.feature!.offsetsList.add(getPointsFromStrList(
+                feature.offsetsList.add(getPointsFromStrList(
                     res['LowerMeasureResult']['PointLower']));
-                ref.feature!.offsetsList.add(getPointsFromStrList(
+                feature.offsetsList.add(getPointsFromStrList(
                     res['LowerMeasureResult']['PointUpper']));
-                ref.feature!.offsetsList.add(getPointsFromStrList(
+                feature.offsetsList.add(getPointsFromStrList(
                     res['UpperMeasureResult']['PointLower']));
-                ref.feature!.offsetsList.add(getPointsFromStrList(
+                feature.offsetsList.add(getPointsFromStrList(
                     res['UpperMeasureResult']['PointUpper']));
               }
             } else {
               description = "$type\n Measure failed";
             }
-            outputs.add(outputItem);
-            outputs.last.updateDescription(description: description);
+            updateStringValue(description);
 
             /// [Carotid] ✅在此处通知canvas 重绘结果
 
@@ -152,9 +152,7 @@ class CarotidCal extends Calculator<CarotidIMT, double> {
         ],
       );
     } catch (e) {
-      outputs.add(outputItem);
-      outputs.last
-          .updateDescription(description: "Ant.CCA IMT\n Measure failed");
+      updateStringValue("Ant.CCA IMT\n Measure failed");
       //
     }
   }

+ 0 - 15
lib/process/calcuators/depth.dart

@@ -19,13 +19,6 @@ class TissueDepthCal extends Calculator<Location, double> {
     final point = ref.feature!.innerPoints.first;
     final physicalPoint = viewport.physical!.convert(point);
     final value = physicalPoint.y * viewport.region.height;
-
-    final outputItem = createOutput(MeasureTypes.Depth, value, VidUsUnit.cm);
-    final description =
-        "${ref.description}: ${roundDouble(value)}${VidUsUnit.cm.name}";
-    outputItem.updateDescription(description: description);
-    output = outputItem;
-
     updateFloatValue(value);
   }
 }
@@ -50,15 +43,7 @@ class TissueConvexDepthCal extends Calculator<Location, double> {
     final distance = (physicalPoint - physicalZeroPoint).length;
     final depth = distance - physical.zeroRadius;
 
-    final valueDesc =
-        depth < 0 ? '' : '${roundDouble(depth)}${VidUsUnit.cm.name}';
-    final description = "${ref.description}: $valueDesc";
-
     final double value = depth < 0 ? 0 : depth;
-    final outputItem = createOutput(MeasureTypes.Depth, value, VidUsUnit.cm);
-
-    outputItem.updateDescription(description: description);
-    output = outputItem;
     updateFloatValue(value);
   }
 }

+ 11 - 12
lib/process/calcuators/detection.dart

@@ -16,7 +16,6 @@ class CarotidDetectionCal extends Calculator<CarotidDetection, double> {
   @override
   void calculate() {
     if (ref.feature == null) return;
-    final outputItem = createOutput(type, 0.0, VidUsUnit.cm);
     //图片尺寸
     final imageSize = ref.application.carotid2DSize;
     //画布尺寸
@@ -40,6 +39,7 @@ class CarotidDetectionCal extends Calculator<CarotidDetection, double> {
     final params = "{'MeasureItemType':'$measureItemType'}";
 
     String description = "Waiting $type";
+    updateStringValue(description);
     List<Offset> getPointsFromStrList(List pointsStr) {
       final points = <Offset>[];
       for (var point in pointsStr) {
@@ -57,27 +57,28 @@ class CarotidDetectionCal extends Calculator<CarotidDetection, double> {
         [
           (result) {
             if (result == 'error') {
-              outputs.add(outputItem);
-              outputs.last.updateDescription(description: "$type failed");
+              description = "$type failed";
+              updateStringValue(description);
               ref.application.updateRenderReady.emit(this, null);
               return;
             }
+            final feature = ref.feature!;
             final res = jsonDecode(result);
             // print('getMeasureResult res: $res');
             if (res.length > 0) {
               if (type == 'Plaque Detection') {
                 description =
                     "$type\n Area: ${res[0]['PlaqueArea'].toStringAsFixed(2)}mm²";
-                ref.feature!.offsetsList
+                feature.offsetsList
                     .add(getPointsFromStrList(res[0]['PlaqueEdgePoints']));
               } else {
                 if (res['LowerIntimaResult']['ErrorCode'].toString() ==
                     "1000") {
                   description =
                       "$type\n Ant Max: ${res['LowerIntimaResult']['MaxThickness'].toStringAsFixed(2)}mm\n Ant.Min: ${res['LowerIntimaResult']['MinThickness'].toStringAsFixed(2)}mm\n Ant.Avg: ${res['LowerIntimaResult']['AverageThickness'].toStringAsFixed(2)}mm\n Ant.SD: ${res['LowerIntimaResult']['SdThickness'].toStringAsFixed(2)}mm\n";
-                  ref.feature!.offsetsList.add(getPointsFromStrList(
+                  feature.offsetsList.add(getPointsFromStrList(
                       res['LowerIntimaResult']['PointLower']));
-                  ref.feature!.offsetsList.add(getPointsFromStrList(
+                  feature.offsetsList.add(getPointsFromStrList(
                       res['LowerIntimaResult']['PointUpper']));
                 } else {
                   description = "$type\n Ant failed\n";
@@ -86,9 +87,9 @@ class CarotidDetectionCal extends Calculator<CarotidDetection, double> {
                     "1000") {
                   description +=
                       " Post Max: ${res['UpperIntimaResult']['MaxThickness'].toStringAsFixed(2)}mm\n Post.Min: ${res['UpperIntimaResult']['MinThickness'].toStringAsFixed(2)}mm\n Post.Avg: ${res['UpperIntimaResult']['AverageThickness'].toStringAsFixed(2)}mm\n Post.SD: ${res['UpperIntimaResult']['SdThickness'].toStringAsFixed(2)}mm\n";
-                  ref.feature!.offsetsList.add(getPointsFromStrList(
+                  feature.offsetsList.add(getPointsFromStrList(
                       res['UpperIntimaResult']['PointLower']));
-                  ref.feature!.offsetsList.add(getPointsFromStrList(
+                  feature.offsetsList.add(getPointsFromStrList(
                       res['UpperIntimaResult']['PointUpper']));
                 } else {
                   description += " Post failed";
@@ -97,8 +98,7 @@ class CarotidDetectionCal extends Calculator<CarotidDetection, double> {
             } else {
               description = "$type failed";
             }
-            outputs.add(outputItem);
-            outputs.last.updateDescription(description: description);
+            updateStringValue(description);
 
             /// [Carotid] ✅在此处通知canvas 重绘结果
             ref.application.updateRenderReady.emit(this, null);
@@ -106,8 +106,7 @@ class CarotidDetectionCal extends Calculator<CarotidDetection, double> {
         ],
       );
     } catch (e) {
-      outputs.add(outputItem);
-      outputs.last.updateDescription(description: "$type failed");
+      updateStringValue("$type failed");
       //
     }
   }

+ 0 - 11
lib/process/calcuators/distance.dart

@@ -20,19 +20,8 @@ class DistanceCal extends Calculator<StraightLine, double> {
     final p2 = feature.endPoint;
     final pp1 = viewport.convert(p1);
     final pp2 = viewport.convert(p2);
-    // final pp1 =
-    //     DPoint(p1.x * viewport.region.width, p1.y * viewport.region.height);
-    // final pp2 =
-    //     DPoint(p2.x * viewport.region.width, p2.y * viewport.region.height);
 
     final value = (pp2 - pp1).length.abs();
-    // final value =  ref.feature!.length;
-    final outputItem = createOutput(MeasureTypes.Distance, value, VidUsUnit.cm);
-    final description =
-        "${ref.description}: ${roundDouble(value)}${VidUsUnit.cm.name}";
-    outputItem.updateDescription(description: description);
-    output = outputItem;
-
     updateFloatValue(value);
   }
 }

+ 0 - 9
lib/process/calcuators/perimeter.dart

@@ -1,9 +1,6 @@
 import 'package:fis_measure/interfaces/date_types/point.dart';
-import 'package:fis_measure/interfaces/process/calculators/output.dart';
 import 'package:fis_measure/interfaces/process/items/types.dart';
 import 'package:fis_measure/process/primitives/ellipse.dart';
-import 'package:flutter/cupertino.dart';
-import 'package:vid/us/vid_us_unit.dart';
 
 import '../primitives/trace.dart';
 import 'calculator.dart';
@@ -26,12 +23,6 @@ class TracePerimeterCal extends Calculator<Trace, double> {
     //     threshold = ref.Threshold.Value;
     // }
     double value = calcPerimeter(points, ref.feature!.isClosed, threshold);
-    final outputItem =
-        createOutput(MeasureTypes.Perimeter, value, VidUsUnit.cm);
-    final description =
-        "${ref.description}: ${roundDouble(value)}${VidUsUnit.cm.name}";
-    outputItem.updateDescription(description: description);
-    output = outputItem;
     updateFloatValue(value);
   }
 

+ 18 - 22
lib/process/calcuators/volume.dart

@@ -1,4 +1,5 @@
 import 'package:fis_measure/interfaces/process/calculators/output.dart';
+import 'package:fis_measure/interfaces/process/calculators/values.dart';
 import 'package:fis_measure/process/calcuators/formulas/general.dart';
 import 'package:fis_measure/process/primitives/combos/lwh_straightline.dart';
 import 'package:fis_measure/process/primitives/ellipse.dart';
@@ -13,41 +14,36 @@ class VolumeThreeDistanceCal extends Calculator<LWHStraightLine, double> {
   void calculate() {
     if (ref.feature == null) return;
 
-    final outputMeta = ref.meta.outputs.first;
-    final outputItem = createOutput(outputMeta.name, 0, outputMeta.unit);
-    final l = _pickChildOutput(ref.l);
-    final w = _pickChildOutput(ref.w);
-    final h = _pickChildOutput(ref.h);
+    final l = _pickChildValue(ref.l);
+    final w = _pickChildValue(ref.w);
+    final h = _pickChildValue(ref.h);
 
-    String description;
     final feature = ref.feature!;
     final viewport = feature.hostVisualArea!.viewport!;
+
     if (l != null && w != null && h != null) {
       final value = GeneralFormulas.volumeWithCoefficient(
-        l.value,
-        w.value,
-        h.value,
+        l,
+        w,
+        h,
         GeneralFormulas.VolumeCofficient,
       );
       updateFloatValue(value);
-      outputItem.value = value;
-      description = "${ref.description}  ${roundDouble(value)}cm³";
-    } else {
-      description = ref.description;
     }
-
-    outputItem.updateDescription(description: description);
-    output = outputItem;
   }
 
-  OutputItem? _pickChildOutput(StraightLine item) {
+  double? _pickChildValue(StraightLine item) {
     if (item.calculator == null) return null;
-
-    if (item.calculator!.outputs.isEmpty) {
-      return item.calculator!.output;
-    } else {
-      return item.calculator!.outputs.first;
+    ValueBase? value;
+    if (item.measuredFeatures.isNotEmpty) {
+      value = item.measuredFeatures.first.value;
+    } else if (item.feature != null) {
+      value = item.feature!.value;
+    }
+    if (value != null) {
+      return (value as FloatValue).value ?? 0;
     }
+    return null;
   }
 }
 

+ 0 - 1
lib/process/items/item.dart

@@ -107,7 +107,6 @@ abstract class MeasureItem<T extends MeasureItemFeature> extends IMeasureItem {
     feature = null;
     if (calculator != null) {
       calculator!.finishOnce();
-      calculator!.outputs.clear();
     }
 
     measuredFeatures.clear();

+ 22 - 1
lib/process/items/item_feature.dart

@@ -81,8 +81,12 @@ abstract class MeasureItemFeature implements IMeasureItemFeature {
   @override
   ValueBase? get value => _values.isNotEmpty ? _values.first : null;
 
+  /// 更新浮点型结果值
   void updateFloatValue(
-      ItemOutputMeta outputMeta, double value, VidUsUnit unit) {
+    ItemOutputMeta outputMeta,
+    double value,
+    VidUsUnit unit,
+  ) {
     final valueBase = values.firstWhereOrNull((e) => e.name == outputMeta.name);
     if (valueBase == null) {
       final floatValue = FloatValue(outputMeta, value, unit);
@@ -94,6 +98,23 @@ abstract class MeasureItemFeature implements IMeasureItemFeature {
     }
   }
 
+  /// 更新字符串结果值
+  void updateStringValue(
+    ItemOutputMeta outputMeta,
+    String value, [
+    VidUsUnit unit = VidUsUnit.None,
+  ]) {
+    final valueBase = values.firstWhereOrNull((e) => e.name == outputMeta.name);
+    if (valueBase == null) {
+      final stringValue = StringValue(outputMeta, value, unit);
+      values.add(stringValue);
+    } else {
+      final floatValue = valueBase as StringValue;
+      floatValue.value = value;
+      floatValue.unit = unit;
+    }
+  }
+
   @protected
   DPoint convert2ViewPoint(Size size, DPoint logicPoint) {
     final x = size.width * logicPoint.x;

+ 3 - 0
lib/process/primitives/utils/auto_snap.dart

@@ -40,7 +40,10 @@ mixin AutoSnapMixin<T extends MeasureItemFeature> on MeasureItem<T> {
       isSmartMove = true;
     }
     if (length < autoSnapThreshold && isSmartMove) {
+      // feature!.innerPoints.removeLast();
+      feature!.innerPoints.last = feature!.innerPoints.first.clone();
       HapticFeedback.heavyImpact();
+      doCalculate();
       doFeatureFinish();
       isSmartMove = false;
       return true;

+ 0 - 2
lib/process/workspace/application.dart

@@ -571,8 +571,6 @@ class Application implements IApplication {
   }
 
   void _clearFrameCache() {
-    ///TODO: delete me
-    // clearRecords();
     _recorder.clear();
     _measureItems.clear();
     _annotationItems.clear();

+ 1 - 1
lib/process/workspace/recorder.dart

@@ -71,7 +71,7 @@ class MeasureRecorder implements IMeasureRecorder {
         item.cancelOnce();
       } else if (item.measuredFeatures.isNotEmpty) {
         item.measuredFeatures.removeLast();
-        item.calculator?.outputs.removeLast();
+        // item.calculator?.outputs.removeLast();
       }
       return true;
     }

+ 78 - 0
lib/view/measure/capture_image.dart

@@ -1,6 +1,84 @@
 import 'dart:typed_data';
+import 'dart:ui' as ui;
 
+import 'package:fis_common/event/event_type.dart';
+import 'package:fis_measure/interfaces/process/items/item_feature.dart';
+import 'package:fis_measure/interfaces/process/workspace/application.dart';
+import 'package:fis_measure/process/workspace/measure_data_controller.dart';
 import 'package:flutter/material.dart';
+import 'package:flutter/rendering.dart';
+import 'package:get/get.dart';
+
+import 'measure_result.dart';
+
+class MeasureImageCapturer {
+  bool state = false;
+
+  MeasureImageCapturer(
+    this.globalKey,
+    this.application,
+    this.dataController, {
+    this.onImageSaveBefore,
+    this.onImageSavedAfter,
+    this.onImageSaveDuring,
+  });
+
+  final GlobalKey globalKey;
+  final IApplication application;
+  final IMeasureDataController dataController;
+  final VoidCallback? onImageSaveBefore;
+  final VoidCallback? onImageSavedAfter;
+  final VoidCallback? onImageSaveDuring;
+
+  /// 保存图片
+  void saveImage() async {
+    if (state) return;
+
+    state = true;
+    onImageSaveBefore?.call();
+
+    final features = <IMeasureItemFeature>[];
+    for (var item in application.measureItems) {
+      if (item.measuredFeatures.isNotEmpty) {
+        features.addAll(item.measuredFeatures);
+      }
+      if (item.feature != null) {
+        features.add(item.feature!);
+      }
+    }
+    MeasureResult measureResult = MeasureResult(
+      measureApplicationName: application.applicationName,
+      features: features,
+    );
+    print(measureResult.toDisplay());
+
+    await Future.delayed(const Duration(milliseconds: 10), () async {
+      final RenderRepaintBoundary? boundary = globalKey.currentContext
+          ?.findRenderObject() as RenderRepaintBoundary?;
+
+      if (boundary != null) {
+        final image = await boundary.toImage();
+        final byteData = await image.toByteData(format: ui.ImageByteFormat.png);
+        final pngBytes = byteData!.buffer.asUint8List();
+        Get.dialog(
+          CaptureImage(
+            bytes: pngBytes,
+          ),
+          transitionCurve: Curves.bounceInOut,
+        );
+        // await (dataController as MeasureDataController).saveImage.call(
+        //       pngBytes,
+        //       dataController.measureImageData.patientCode ?? '',
+        //       dataController.measureImageData.recordCode ?? '',
+        //       dataController.measureImageData.remedicalCode ?? '',
+        //       measureResult.toDisplay(),
+        //     );
+        state = false;
+        onImageSavedAfter?.call();
+      }
+    });
+  }
+}
 
 class CaptureImage extends StatelessWidget {
   final Uint8List bytes;

+ 9 - 8
lib/view/measure/measure_main_view.dart

@@ -5,6 +5,7 @@ import 'package:fis_jsonrpc/rpc.dart';
 import 'package:fis_measure/interfaces/date_types/int_size.dart';
 import 'package:fis_measure/interfaces/enums/operate.dart';
 import 'package:fis_measure/interfaces/process/calculators/output.dart';
+import 'package:fis_measure/interfaces/process/items/item_feature.dart';
 import 'package:fis_measure/interfaces/process/player/play_controller.dart';
 import 'package:fis_measure/interfaces/process/standard_line/calibration.dart';
 import 'package:fis_measure/interfaces/process/workspace/application.dart';
@@ -159,19 +160,19 @@ class _MeasureMainViewState extends State<MeasureMainView> {
   void capturePng() async {
     isCaptureState = true;
     setState(() {});
+
+    final features = <IMeasureItemFeature>[];
     for (var item in application.measureItems) {
-      if (item.calculator != null) {
-        // 添加历史测量值
-        outputs.addAll(item.calculator!.outputs);
-        if (item.feature?.isActive == true && item.calculator!.output != null) {
-          // 添加活动测量值
-          outputs.add(item.calculator!.output!);
-        }
+      if (item.measuredFeatures.isNotEmpty) {
+        features.addAll(item.measuredFeatures);
+      }
+      if (item.feature != null) {
+        features.add(item.feature!);
       }
     }
     MeasureResult measureResult = MeasureResult(
       measureApplicationName: application.applicationName,
-      outputList: outputs,
+      features: features,
     );
     await Future.delayed(const Duration(milliseconds: 10), () async {
       final RenderRepaintBoundary? boundary =

+ 10 - 7
lib/view/measure/measure_result.dart

@@ -1,26 +1,29 @@
 import 'package:fis_measure/interfaces/process/calculators/output.dart';
+import 'package:fis_measure/interfaces/process/items/item_feature.dart';
+import 'package:fis_measure/view/result/converter.dart';
 
 class MeasureResult {
   final String measureApplicationName;
-  final List<OutputItem> outputList;
+  final List<IMeasureItemFeature> features;
   MeasureResult({
     required this.measureApplicationName,
-    required this.outputList,
+    required this.features,
   });
   Map<String, dynamic> toJson() {
     final map = <String, dynamic>{};
     map['MeasureApplicationName'] = measureApplicationName;
-    map['OutputList'] = outputList;
+    map['Features'] = features;
     return map;
   }
 
   String toDisplay() {
     List<String> results = [];
-    String resultString = '';
-    for (var element in outputList) {
-      results.add('${element.id} ${element.description} \n');
+    final idLength = features.length.toString().length;
+    for (var feature in features) {
+      final strList = FeatureValueDescConverter(feature).generate(idLength);
+      results.addAll(strList);
     }
-    resultString = '$measureApplicationName \n${results.join()}';
+    final resultString = '$measureApplicationName \n${results.join("\n")}';
     return resultString;
   }
 }

+ 9 - 9
lib/view/mobile_view/mobile_measure_main_view.dart

@@ -5,6 +5,7 @@ import 'package:fis_jsonrpc/rpc.dart';
 import 'package:fis_measure/interfaces/date_types/int_size.dart';
 import 'package:fis_measure/interfaces/enums/operate.dart';
 import 'package:fis_measure/interfaces/process/calculators/output.dart';
+import 'package:fis_measure/interfaces/process/items/item_feature.dart';
 import 'package:fis_measure/interfaces/process/player/play_controller.dart';
 import 'package:fis_measure/interfaces/process/standard_line/calibration.dart';
 import 'package:fis_measure/interfaces/process/workspace/application.dart';
@@ -164,20 +165,19 @@ class _MobileMeasureMainViewState extends State<MobileMeasureMainView> {
       setState(() {
         isCaptureState = true;
       });
+
+      final features = <IMeasureItemFeature>[];
       for (var item in application.measureItems) {
-        if (item.calculator != null) {
-          // 添加历史测量值
-          outputs.addAll(item.calculator!.outputs);
-          if (item.feature?.isActive == true &&
-              item.calculator!.output != null) {
-            // 添加活动测量值
-            outputs.add(item.calculator!.output!);
-          }
+        if (item.measuredFeatures.isNotEmpty) {
+          features.addAll(item.measuredFeatures);
+        }
+        if (item.feature != null) {
+          features.add(item.feature!);
         }
       }
       MeasureResult measureResult = MeasureResult(
         measureApplicationName: application.applicationName,
-        outputList: outputs,
+        features: features,
       );
       await Future.delayed(const Duration(milliseconds: 10), () async {
         final RenderRepaintBoundary? boundary =

+ 107 - 0
lib/view/result/converter.dart

@@ -0,0 +1,107 @@
+import 'package:fis_measure/interfaces/process/calculators/values.dart';
+import 'package:fis_measure/interfaces/process/items/item.dart';
+import 'package:fis_measure/interfaces/process/items/item_feature.dart';
+import 'package:fis_measure/values/unit_desc.dart';
+
+class FeatureValueDescConverter {
+  final IMeasureItemFeature feature;
+  FeatureValueDescConverter(this.feature);
+
+  String idPlaceStr = ' ';
+  String idStr = ' ';
+
+  List<String> generate(int idLength) {
+    idPlaceStr = ' '.padRight(idLength, ' ');
+    idStr = feature.id.toString().padRight(idLength, ' ');
+
+    final List<String> arr = [];
+    final mainLines = _findFeatureLines(feature);
+    arr.addAll(mainLines);
+
+    final ref = feature.refItem;
+    if (ref is ITopMeasureItem) {
+      for (var child in ref.childItems) {
+        for (var feature in child.measuredFeatures) {
+          final str = _findChildLine(feature);
+          if (str != null && str.isNotEmpty) {
+            arr.add(str);
+          }
+        }
+        if (child.feature != null) {
+          final str = _findChildLine(child.feature!);
+          if (str != null && str.isNotEmpty) {
+            arr.add(str);
+          }
+        }
+      }
+    }
+
+    return arr;
+  }
+
+  String? _findChildLine(IMeasureItemFeature feature) {
+    if (feature.value == null) return null;
+
+    final value = feature.value!;
+    final valueStr = _pickValueStr(value);
+
+    final name = feature.refItem.description;
+
+    return ' $idPlaceStr $name: $valueStr';
+  }
+
+  List<String> _findFeatureLines(IMeasureItemFeature feature) {
+    final count = feature.values.length;
+    if (count == 0) {
+      final output = feature.refItem.meta.outputs.first;
+      final name =
+          _findDisplayName(output.description, output.briefAnnotation, false);
+      return ['$idStr $name'];
+    }
+
+    List<String> arr = [];
+    for (var i = 0; i < count; i++) {
+      final val = feature.values[i];
+      final meta = val.meta;
+      final valueStr = _pickValueStr(val);
+      final name =
+          _findDisplayName(meta.description, meta.briefAnnotation, false);
+
+      if (i == 0) {
+        arr.add('$idStr $name: $valueStr');
+      } else {
+        arr.add('$idPlaceStr $name: $valueStr');
+      }
+    }
+
+    return arr;
+  }
+
+  String _pickValueStr(ValueBase value) {
+    if (value is FloatValue) {
+      final floatVal =
+          _roundDouble(value.value!, value.meta.fractionalDigits).toString();
+      final unitStr = UnitDescriptionMap.getDesc(value.meta.unit);
+      return '$floatVal $unitStr';
+    } else if (value is StringValue) {
+      return value.value!;
+    }
+    return '';
+  }
+
+  String _findDisplayName(String description, String? briefAnnotation,
+      [bool showAnnotation = false]) {
+    if (showAnnotation) {
+      if (briefAnnotation != null && briefAnnotation.isNotEmpty) {
+        return briefAnnotation;
+      }
+    }
+    return description;
+  }
+
+  double _roundDouble(double value, [int digits = 2]) {
+    final digitsStr = value.toStringAsFixed(digits);
+    final result = double.parse(digitsStr);
+    return result;
+  }
+}

+ 3 - 106
lib/view/result/results_panel.dart

@@ -12,6 +12,8 @@ import 'package:fis_ui/index.dart';
 import 'package:flutter/material.dart';
 import 'package:get/get.dart';
 
+import 'converter.dart';
+
 class MeasureResultPanel extends StatefulWidget {
   const MeasureResultPanel({this.resultFontSize = 16.0, Key? key})
       : super(key: key);
@@ -175,7 +177,7 @@ class _MeasureResultPanelState extends State<MeasureResultPanel> {
     }
     final idLength = features.length.toString().length;
     for (var feature in features) {
-      final strList = _FeatureDescConverter(feature).generate(idLength);
+      final strList = FeatureValueDescConverter(feature).generate(idLength);
       lines.addAll(strList);
     }
   }
@@ -189,108 +191,3 @@ class _MeasureResultPanelState extends State<MeasureResultPanel> {
     });
   }
 }
-
-class _FeatureDescConverter {
-  final IMeasureItemFeature feature;
-  _FeatureDescConverter(this.feature);
-
-  String idPlaceStr = ' ';
-  String idStr = ' ';
-
-  List<String> generate(int idLength) {
-    idPlaceStr = ' '.padRight(idLength, ' ');
-    idStr = feature.id.toString().padRight(idLength, ' ');
-
-    final List<String> arr = [];
-    final mainLines = _findFeatureLines(feature);
-    arr.addAll(mainLines);
-
-    final ref = feature.refItem;
-    if (ref is ITopMeasureItem) {
-      for (var child in ref.childItems) {
-        for (var feature in child.measuredFeatures) {
-          final str = _findChildLine(feature);
-          if (str != null && str.isNotEmpty) {
-            arr.add(str);
-          }
-        }
-        if (child.feature != null) {
-          final str = _findChildLine(child.feature!);
-          if (str != null && str.isNotEmpty) {
-            arr.add(str);
-          }
-        }
-      }
-    }
-
-    return arr;
-  }
-
-  String? _findChildLine(IMeasureItemFeature feature) {
-    if (feature.value == null) return null;
-
-    final value = feature.value!;
-    final valueStr = _pickValueStr(value);
-
-    final name = feature.refItem.description;
-    final unitStr = UnitDescriptionMap.getDesc(value.meta.unit);
-    // final output = feature.refItem.meta.outputs.first;
-    // final name =
-    //     _findDisplayName(output.description, output.briefAnnotation, false);
-
-    return ' $idPlaceStr $name: $valueStr$unitStr';
-  }
-
-  List<String> _findFeatureLines(IMeasureItemFeature feature) {
-    final count = feature.values.length;
-    if (count == 0) {
-      final output = feature.refItem.meta.outputs.first;
-      final name =
-          _findDisplayName(output.description, output.briefAnnotation, false);
-      return ['$idStr $name'];
-    }
-
-    List<String> arr = [];
-    for (var i = 0; i < count; i++) {
-      final val = feature.values[i];
-      final meta = val.meta;
-      final valueStr = _pickValueStr(val);
-      final name =
-          _findDisplayName(meta.description, meta.briefAnnotation, false);
-      final unitStr = UnitDescriptionMap.getDesc(meta.unit);
-
-      if (i == 0) {
-        arr.add('$idStr $name: $valueStr$unitStr');
-      } else {
-        arr.add('$idPlaceStr $name: $valueStr$unitStr');
-      }
-    }
-
-    return arr;
-  }
-
-  String _pickValueStr(ValueBase value) {
-    if (value is FloatValue) {
-      return _roundDouble(value.value!, value.meta.fractionalDigits).toString();
-    } else if (value is StringValue) {
-      return value.value!;
-    }
-    return '';
-  }
-
-  String _findDisplayName(String description, String? briefAnnotation,
-      [bool showAnnotation = false]) {
-    if (showAnnotation) {
-      if (briefAnnotation != null && briefAnnotation.isNotEmpty) {
-        return briefAnnotation;
-      }
-    }
-    return description;
-  }
-
-  double _roundDouble(double value, [int digits = 2]) {
-    final digitsStr = value.toStringAsFixed(digits);
-    final result = double.parse(digitsStr);
-    return result;
-  }
-}