Browse Source

polyline area&perimeter

melon.yin 2 years ago
parent
commit
dbcb480822

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

@@ -28,6 +28,9 @@ class MeasureTypes {
   /// 椭圆测体积
   static const String VolumeEllipse = "VolumeEllipse";
 
+  /// 折线多边型测面积周长
+  static const String AreaPerimeterPolyline = "AreaPerimeterEllipse";
+
   /// 前壁
   static const String AntCCA_IMT = "Ant.CCA IMT";
 

+ 3 - 3
lib/process/calcuators/area.dart

@@ -5,11 +5,11 @@ import 'package:fis_measure/interfaces/process/items/types.dart';
 import 'package:fis_measure/process/primitives/ellipse.dart';
 import 'package:vid/us/vid_us_unit.dart';
 
-import '../primitives/poyline.dart';
+import '../primitives/trace.dart';
 import 'calculator.dart';
 
-class PolyLineAreaCal extends Calculator<PolyLine, double> {
-  PolyLineAreaCal(PolyLine ref) : super(ref);
+class TraceAreaCal extends Calculator<Trace, double> {
+  TraceAreaCal(Trace ref) : super(ref);
 
   @override
   void calculate() {

+ 3 - 3
lib/process/calcuators/perimeter.dart

@@ -5,11 +5,11 @@ import 'package:fis_measure/process/primitives/ellipse.dart';
 import 'package:flutter/cupertino.dart';
 import 'package:vid/us/vid_us_unit.dart';
 
-import '../primitives/poyline.dart';
+import '../primitives/trace.dart';
 import 'calculator.dart';
 
-class PolyLinePerimeterCal extends Calculator<PolyLine, double> {
-  PolyLinePerimeterCal(PolyLine ref) : super(ref);
+class TracePerimeterCal extends Calculator<Trace, double> {
+  TracePerimeterCal(Trace ref) : super(ref);
 
   @override
   void calculate() {

+ 5 - 0
lib/process/items/factory.dart

@@ -4,6 +4,7 @@ import 'package:fis_measure/interfaces/process/items/types.dart';
 import 'package:fis_measure/process/items/item.dart';
 import 'package:fis_measure/process/primitives/combos/lwh_straightline.dart';
 import 'package:fis_measure/process/primitives/ellipse.dart';
+import 'package:fis_measure/process/primitives/polyline.dart';
 import 'package:fis_measure/process/primitives/straightline.dart';
 
 /// 测量项创建器
@@ -74,5 +75,9 @@ class MeasureItemFactory {
     _singleton._register(
         MeasureTypes.AreaPerimeterEllipse, Ellipse.createAreaPerimeter);
     _singleton._register(MeasureTypes.VolumeEllipse, Ellipse.createVolume);
+
+    //Polylines
+    _singleton._register(
+        MeasureTypes.AreaPerimeterPolyline, Polyline.createAreaPerimeter);
   }
 }

+ 204 - 0
lib/process/primitives/polyline.dart

@@ -0,0 +1,204 @@
+import 'dart:ui';
+
+import 'package:fis_measure/interfaces/date_types/point.dart';
+import 'package:fis_measure/interfaces/enums/items.dart';
+import 'package:fis_measure/interfaces/process/items/item_metas.dart';
+
+import 'package:fis_measure/interfaces/process/items/item.dart';
+import 'package:fis_measure/interfaces/process/items/types.dart';
+import 'package:fis_measure/interfaces/process/workspace/point_info.dart';
+import 'package:fis_measure/process/calcuators/calculator.dart';
+import 'package:fis_measure/process/items/item.dart';
+import 'package:fis_measure/process/items/item_feature.dart';
+import 'package:fis_measure/utils/canvas.dart';
+
+class Polyline extends MeasureItem<PolylineFeature> {
+  Polyline(ItemMeta meta, IMeasureItem? parent) : super(meta, parent);
+
+  static Polyline createAreaPerimeter(ItemMeta meta, [IMeasureItem? parent]) {
+    Polyline polygon = Polyline(meta, parent);
+    polygon.calculator = _AreaPerimeterCalc(polygon);
+    return polygon;
+  }
+
+  @override
+  bool onExecuteMouse(PointInfo args) {
+    if (state == ItemStates.finished) {
+      if (args.pointType == PointInfoType.mouseDown) {
+        state = ItemStates.waiting;
+      }
+    }
+
+    if (state == ItemStates.waiting) {
+      if (args.pointType == PointInfoType.mouseDown) {
+        handleMouseDownWhileWaiting(args);
+      }
+    } else if (state == ItemStates.running) {
+      if (feature == null) return false;
+      if (args.pointType == PointInfoType.mouseUp) return false;
+
+      final f = feature!;
+
+      if (args.pointType == PointInfoType.mouseDown) {
+        f.innerPoints.add(args);
+      } else {
+        f.innerPoints.last = args;
+      }
+      doCalculate();
+
+      if (false) {
+        doFeatureFinish();
+      }
+    }
+    return true;
+  }
+
+  @override
+  bool onExecuteTouch(PointInfo args) {
+    // TODO: implement onExecuteTouch
+    throw UnimplementedError();
+  }
+
+  void handleMouseDownWhileWaiting(PointInfo args) {
+    // TODO: 判断是否当前area
+    // 转换为Area逻辑位置
+    final point = args.toAreaLogicPoint();
+    feature = PolylineFeature(this, point);
+    if (args.hostVisualArea != null) {
+      feature!.hostVisualArea = args.hostVisualArea;
+    }
+    state = ItemStates.running;
+  }
+}
+
+class PolylineFeature extends MeasureItemFeature {
+  bool _isClosed = false;
+  double _splineTension = 0.0;
+  PolylineFeature(IMeasureItem refItem, DPoint point) : super(refItem) {
+    innerPoints.add(point);
+  }
+
+  DPoint get startPoint => innerPoints.first;
+  DPoint get endPoint => innerPoints.last;
+
+  bool get isClosed => _isClosed;
+  set isClosed(bool val) {
+    if (val != _isClosed) {
+      _isClosed = val;
+    }
+  }
+
+  double get splineTension => _splineTension;
+  set splineTension(double val) {
+    if (val != _splineTension) {
+      _splineTension = val;
+    }
+  }
+
+  @override
+  void paint(Canvas canvas, Size size) {
+    if (innerPoints.isEmpty) return;
+
+    drawId(canvas, size);
+
+    final startOffset = convert2ViewPoint(size, startPoint).toOffset();
+
+    if (innerPoints.length == 1) {
+      drawVertex(canvas, startOffset, true);
+      return;
+    } else {
+      drawVertex(canvas, startOffset);
+    }
+
+    final len = innerPoints.length;
+    for (var i = 1; i < len; i++) {
+      final a = innerPoints[i - 1];
+      final b = innerPoints[i];
+      final offsetA = convert2ViewPoint(size, a).toOffset();
+      final offsetB = convert2ViewPoint(size, b).toOffset();
+      canvas.drawDashLine(offsetA, offsetB, 1, 10, paintPan);
+      final isLast = len - i == 1;
+      drawVertex(canvas, offsetB, isLast);
+    }
+  }
+}
+
+class _AreaPerimeterCalc extends Calculator<Polyline, double> {
+  _AreaPerimeterCalc(Polyline ref) : super(ref);
+
+  @override
+  void calculate() {
+    if (ref.feature == null) return;
+
+    final feature = ref.feature!;
+    final viewport = feature.hostVisualArea!.viewport!;
+    final points = feature.innerPoints.map((e) => viewport.convert(e)).toList();
+
+    feature.values.clear();
+
+    double area;
+    double perimeter;
+    if ((feature.splineTension - 0).abs() > 0) {
+      // TODO: CreateSpline - Polyline.cs 850
+      perimeter = 0;
+      area = 0;
+    } else {
+      double threshold = 0.0;
+      area = calcArea(points);
+      perimeter = calcPerimeter(points, feature.isClosed, threshold);
+    }
+    for (var output in ref.meta.outputs) {
+      if (output.name == MeasureTypes.Perimeter) {
+        var value = roundDouble(perimeter, output.fractionalDigits);
+        feature.updateFloatValue(output, value, output.unit);
+      } else if (output.name == MeasureTypes.Area) {
+        var value = roundDouble(area, output.fractionalDigits);
+        feature.updateFloatValue(output, value, output.unit);
+      }
+    }
+  }
+
+  static double calcArea(List<DPoint> points) {
+    if (points.isEmpty) {
+      return 0;
+    }
+
+    double sum = 0;
+    var ax = points[0].x;
+    var ay = points[0].y;
+    for (var i = 1; i < points.length - 1; i++) {
+      var bx = points[i].x;
+      var by = points[i].y;
+      var cx = points[i + 1].x;
+      var cy = points[i + 1].y;
+      sum += ax * by - ay * bx + ay * cx - ax * cy + bx * cy - cx * by;
+    }
+    return (-sum / 2).abs();
+  }
+
+  static double calcPerimeter(
+    List<DPoint> points,
+    bool isClosed,
+    double threshold,
+  ) {
+    final len = points.length;
+    if (points.length < 2) {
+      return 0;
+    }
+
+    double sum = 0;
+    for (int i = 1, j = 0; j < len && i < len; i++) {
+      var length = (points[i] - points[j]).length;
+      if ((length).abs() > threshold) {
+        sum += length;
+        j = i;
+      }
+    }
+
+    if (isClosed) {
+      sum += (points[len - 1] - points[0]).length;
+    }
+
+    return sum;
+  }
+}

+ 0 - 175
lib/process/primitives/poyline.dart

@@ -1,175 +0,0 @@
-import 'dart:ui';
-
-import 'package:fis_measure/interfaces/date_types/point.dart';
-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/interfaces/process/workspace/point_info.dart';
-import 'package:fis_measure/utils/canvas.dart';
-import 'package:path_drawing/path_drawing.dart';
-
-import '../calcuators/area.dart';
-import '../calcuators/perimeter.dart';
-import '../items/item.dart';
-import '../items/item_feature.dart';
-
-class PolyLine extends MeasureItem<PolyLineFeature> {
-  final bool _initialClosed = false;
-  PointInfo? _firstPoint;
-
-  PolyLine(ItemMeta meta, IMeasureItem? parent) : super(meta, parent);
-
-  @override
-  bool onExecuteMouse(PointInfo args) {
-    if (state == ItemStates.finished) {
-      if (args.pointType == PointInfoType.mouseDown) {
-        state = ItemStates.waiting;
-      }
-    }
-
-    if (state == ItemStates.waiting) {
-      if (args.pointType == PointInfoType.mouseDown) {
-        handleMouseDownWhileWaiting(args);
-      }
-    } else if (state == ItemStates.running) {
-      if (args.pointType == PointInfoType.mouseUp) return false;
-
-      feature?.adopt(args);
-      doCalculate();
-      if (args.pointType == PointInfoType.mouseDown) {
-        doFeatureFinish();
-      } else {
-        _checkAutoFinish(args);
-      }
-    }
-    return true;
-  }
-
-  void _doFinish() {
-    doFeatureFinish();
-    _firstPoint = null;
-  }
-
-  void _checkAutoFinish(PointInfo current) {
-    if (feature == null || feature!.innerPoints.length < 3) return;
-
-    double autoSnapDistance = 0.01; //TODO: from config
-    double autoSnapThreshold = 0.05;
-    bool isAutoSnap = true; //TODO: from config
-    if (isAutoSnap == false) return;
-
-    // final viewport = feature!.hostVisualArea!.viewport!;
-    var length = (feature!.firstPoint - current).length;
-    if (length > autoSnapThreshold * 2.0 && !feature!.isSmartMove) {
-      feature!.isSmartMove = true;
-    }
-    if (length < autoSnapThreshold && feature!.isSmartMove) {
-      _doFinish();
-    }
-    // final logicStart = feature!.innerPoints.first;
-    // final logicEnd = feature!.innerPoints.last;
-
-    // // isSmartMove
-    // if (logicEnd.almostEquals(logicStart, 0.01)) {
-    //   feature!.innerPoints.add(feature!.innerPoints.first); // 强制闭合
-    //   doFeatureFinish();
-    // }
-  }
-
-  void handleMouseDownWhileWaiting(PointInfo args) {
-    // TODO: 判断是否当前area
-    // 转换为Area逻辑位置
-    feature = PolyLineFeature(this);
-    feature!.isClosed = _initialClosed;
-    if (args.hostVisualArea != null) {
-      feature!.hostVisualArea = args.hostVisualArea;
-    }
-    final point = args.toAreaLogicPoint();
-    feature!.adopt(point);
-    _firstPoint = args;
-    state = ItemStates.running;
-  }
-
-  @override
-  bool onExecuteTouch(PointInfo args) {
-    return true;
-  }
-
-  /// 创建面积测量
-  static PolyLine createArea(
-    ItemMeta meta, [
-    IMeasureItem? parent,
-  ]) {
-    PolyLine poyline = PolyLine(meta, parent);
-    poyline.calculator = PolyLineAreaCal(poyline);
-    return poyline;
-  }
-
-  /// 创建周长测量
-  static PolyLine createPerimeter(
-    ItemMeta meta, [
-    IMeasureItem? parent,
-  ]) {
-    PolyLine poyline = PolyLine(meta, parent);
-    poyline.calculator = PolyLinePerimeterCal(poyline);
-    return poyline;
-  }
-}
-
-class PolyLineFeature extends MeasureItemFeature {
-  bool _isClosed = false;
-  bool _isSmartMove = false;
-
-  PolyLineFeature(IMeasureItem refItem) : super(refItem);
-
-  /// 是否闭合?抄自超声机
-  bool get isClosed => _isClosed;
-  set isClosed(bool value) {
-    if (value != _isClosed) {
-      _isClosed = value;
-    }
-  }
-
-  /// 是否启动智能定位
-  bool get isSmartMove => _isSmartMove;
-  set isSmartMove(bool value) {
-    if (value != _isSmartMove) {
-      _isSmartMove = value;
-    }
-  }
-
-  /// 首节点
-  DPoint get firstPoint => innerPoints.first;
-
-  /// 接收新坐标
-  void adopt(DPoint point) {
-    innerPoints.add(point);
-  }
-
-  @override
-  void paint(Canvas canvas, Size size) {
-    if (innerPoints.isEmpty) return;
-
-    drawId(canvas, size);
-
-    final points = innerPoints.map((e) => convert2ViewPoint(size, e)).toList();
-    final startPoint = points.first;
-    drawVertex(canvas, startPoint.toOffset(), points.length == 1);
-
-    if (points.length > 1) {
-      final Path path = Path();
-      path.moveTo(startPoint.x, startPoint.y);
-      for (var i = 1; i < points.length; i++) {
-        final point = points[i];
-        path.lineTo(point.x, point.y);
-      }
-      path.lineTo(startPoint.x, startPoint.y);
-      canvas.drawPath(
-        dashPath(path, dashArray: CircularIntervalList([2.0, 10.0])),
-        paintPan,
-      );
-    }
-
-    drawVertex(canvas, points.last.toOffset(), isActive);
-  }
-}

+ 169 - 3
lib/process/primitives/trace.dart

@@ -1,9 +1,175 @@
-import 'package:fis_measure/interfaces/process/items/item_metas.dart';
+import 'dart:ui';
 
+import 'package:fis_measure/interfaces/date_types/point.dart';
+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/interfaces/process/workspace/point_info.dart';
+import 'package:fis_measure/utils/canvas.dart';
+import 'package:path_drawing/path_drawing.dart';
 
-import 'poyline.dart';
+import '../calcuators/area.dart';
+import '../calcuators/perimeter.dart';
+import '../items/item.dart';
+import '../items/item_feature.dart';
+
+class Trace extends MeasureItem<TraceFeature> {
+  final bool _initialClosed = false;
+  PointInfo? _firstPoint;
 
-class Trace extends PolyLine {
   Trace(ItemMeta meta, IMeasureItem? parent) : super(meta, parent);
+
+  @override
+  bool onExecuteMouse(PointInfo args) {
+    if (state == ItemStates.finished) {
+      if (args.pointType == PointInfoType.mouseDown) {
+        state = ItemStates.waiting;
+      }
+    }
+
+    if (state == ItemStates.waiting) {
+      if (args.pointType == PointInfoType.mouseDown) {
+        handleMouseDownWhileWaiting(args);
+      }
+    } else if (state == ItemStates.running) {
+      if (args.pointType == PointInfoType.mouseUp) return false;
+
+      feature?.adopt(args);
+      doCalculate();
+      if (args.pointType == PointInfoType.mouseDown) {
+        doFeatureFinish();
+      } else {
+        _checkAutoFinish(args);
+      }
+    }
+    return true;
+  }
+
+  void _doFinish() {
+    doFeatureFinish();
+    _firstPoint = null;
+  }
+
+  void _checkAutoFinish(PointInfo current) {
+    if (feature == null || feature!.innerPoints.length < 3) return;
+
+    double autoSnapDistance = 0.01; //TODO: from config
+    double autoSnapThreshold = 0.05;
+    bool isAutoSnap = true; //TODO: from config
+    if (isAutoSnap == false) return;
+
+    // final viewport = feature!.hostVisualArea!.viewport!;
+    var length = (feature!.firstPoint - current).length;
+    if (length > autoSnapThreshold * 2.0 && !feature!.isSmartMove) {
+      feature!.isSmartMove = true;
+    }
+    if (length < autoSnapThreshold && feature!.isSmartMove) {
+      _doFinish();
+    }
+    // final logicStart = feature!.innerPoints.first;
+    // final logicEnd = feature!.innerPoints.last;
+
+    // // isSmartMove
+    // if (logicEnd.almostEquals(logicStart, 0.01)) {
+    //   feature!.innerPoints.add(feature!.innerPoints.first); // 强制闭合
+    //   doFeatureFinish();
+    // }
+  }
+
+  void handleMouseDownWhileWaiting(PointInfo args) {
+    // TODO: 判断是否当前area
+    // 转换为Area逻辑位置
+    feature = TraceFeature(this);
+    feature!.isClosed = _initialClosed;
+    if (args.hostVisualArea != null) {
+      feature!.hostVisualArea = args.hostVisualArea;
+    }
+    final point = args.toAreaLogicPoint();
+    feature!.adopt(point);
+    _firstPoint = args;
+    state = ItemStates.running;
+  }
+
+  @override
+  bool onExecuteTouch(PointInfo args) {
+    return true;
+  }
+
+  /// 创建面积测量
+  static Trace createArea(
+    ItemMeta meta, [
+    IMeasureItem? parent,
+  ]) {
+    Trace poyline = Trace(meta, parent);
+    poyline.calculator = TraceAreaCal(poyline);
+    return poyline;
+  }
+
+  /// 创建周长测量
+  static Trace createPerimeter(
+    ItemMeta meta, [
+    IMeasureItem? parent,
+  ]) {
+    Trace poyline = Trace(meta, parent);
+    poyline.calculator = TracePerimeterCal(poyline);
+    return poyline;
+  }
+}
+
+class TraceFeature extends MeasureItemFeature {
+  bool _isClosed = false;
+  bool _isSmartMove = false;
+
+  TraceFeature(IMeasureItem refItem) : super(refItem);
+
+  /// 是否闭合?抄自超声机
+  bool get isClosed => _isClosed;
+  set isClosed(bool value) {
+    if (value != _isClosed) {
+      _isClosed = value;
+    }
+  }
+
+  /// 是否启动智能定位
+  bool get isSmartMove => _isSmartMove;
+  set isSmartMove(bool value) {
+    if (value != _isSmartMove) {
+      _isSmartMove = value;
+    }
+  }
+
+  /// 首节点
+  DPoint get firstPoint => innerPoints.first;
+
+  /// 接收新坐标
+  void adopt(DPoint point) {
+    innerPoints.add(point);
+  }
+
+  @override
+  void paint(Canvas canvas, Size size) {
+    if (innerPoints.isEmpty) return;
+
+    drawId(canvas, size);
+
+    final points = innerPoints.map((e) => convert2ViewPoint(size, e)).toList();
+    final startPoint = points.first;
+    drawVertex(canvas, startPoint.toOffset(), points.length == 1);
+
+    if (points.length > 1) {
+      final Path path = Path();
+      path.moveTo(startPoint.x, startPoint.y);
+      for (var i = 1; i < points.length; i++) {
+        final point = points[i];
+        path.lineTo(point.x, point.y);
+      }
+      path.lineTo(startPoint.x, startPoint.y);
+      canvas.drawPath(
+        dashPath(path, dashArray: CircularIntervalList([2.0, 10.0])),
+        paintPan,
+      );
+    }
+
+    drawVertex(canvas, points.last.toOffset(), isActive);
+  }
 }

+ 3 - 3
lib/process/workspace/application.dart

@@ -29,7 +29,7 @@ import 'package:vid/us/vid_us_image.dart';
 import 'package:vid/us/vid_us_probe.dart';
 import 'package:vid/us/vid_us_unit.dart';
 import 'dart:math';
-import '../primitives/poyline.dart';
+import '../primitives/trace.dart';
 import 'recorder.dart';
 import 'visual_loader.dart';
 
@@ -313,7 +313,7 @@ class Application implements IApplication {
     }
 
     if (name == MeasureTypes.Perimeter) {
-      activeMeasureItem = PolyLine.createPerimeter(
+      activeMeasureItem = Trace.createPerimeter(
         ItemMeta(
           MeasureTypes.Perimeter,
           measureType: MeasureTypes.Perimeter,
@@ -328,7 +328,7 @@ class Application implements IApplication {
       return;
     }
     if (name == MeasureTypes.Area) {
-      activeMeasureItem = PolyLine.createArea(
+      activeMeasureItem = Trace.createArea(
         ItemMeta(
           MeasureTypes.Area,
           measureType: MeasureTypes.Area,