Browse Source

record codes

melon.yin 2 years ago
parent
commit
32965ea022

+ 2 - 1
lib/interfaces/date_types/matrix.dart

@@ -346,7 +346,7 @@ class DMatrix {
     copyFrom(outcome);
   }
 
-  void rotateAt(double angle, double centerX, double centerY) {
+  DMatrix rotateAt(double angle, double centerX, double centerY) {
     angle = angle % 360.0;
     final outcome = this *
         createRotationRadiansAt(
@@ -355,6 +355,7 @@ class DMatrix {
           centerY,
         );
     copyFrom(outcome);
+    return outcome;
   }
 
   void scale(double scaleX, double scaleY) {

+ 6 - 0
lib/interfaces/date_types/point.dart

@@ -47,6 +47,12 @@ class DPoint {
     return this;
   }
 
+  DPoint update(DPoint target) {
+    x = target.x;
+    y = target.y;
+    return this;
+  }
+
   bool almostEquals(DPoint other, [double precision = 0.000001]) {
     return (_doubleAlmostEquals(x, other.x, precision)) &&
         (_doubleAlmostEquals(y, other.y, precision));

+ 2 - 1
lib/interfaces/process/workspace/point_info.dart

@@ -40,6 +40,7 @@ class PointInfo extends DPoint {
   DPoint toAreaLogicPoint() {
     if (hostVisualArea == null) return this;
     // TODO: 转换为Area内逻辑点
-    return DPoint(x, y);
+    return this;
+    // return DPoint(x, y);
   }
 }

+ 21 - 0
lib/process/calcuators/formulas/general.dart

@@ -2,6 +2,8 @@
 
 import 'dart:math' as math;
 
+import 'package:fis_measure/interfaces/date_types/point.dart';
+
 class GeneralFormulas {
   /// Volume:1/6 x π
   static const double VolumeCofficient = math.pi / 6.0;
@@ -29,4 +31,23 @@ class GeneralFormulas {
     if (num1.isNaN && num2.isNaN) return true;
     return (num1 - num2).abs() <= precision;
   }
+
+  /// 点到线的距离
+  ///
+  /// [pt1] 线端点1
+  ///
+  /// [pt2] 线端点2
+  ///
+  /// [pt] 点
+  static double distance2Line(DPoint pt1, DPoint pt2, DPoint pt) {
+    double dis = 0;
+    if (pt1.x == pt2.x) {
+      dis = (pt.x - pt1.x).abs();
+      return dis;
+    }
+    var lineK = (pt2.y - pt1.y) / (pt2.x - pt1.x);
+    var lineC = (pt2.x * pt1.y - pt1.x * pt2.y) / (pt2.x - pt1.x);
+    dis = (lineK * pt.x - pt.y + lineC).abs() / (math.sqrt(lineK * lineK + 1));
+    return dis;
+  }
 }

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

@@ -21,6 +21,7 @@ abstract class MeasureItemFeature implements IMeasureItemFeature {
   bool _isActive = true;
   int _id = 0;
   final List<ValueBase> _values = [];
+  int _activeIndex = -1;
 
   @protected
   final paintPan = Paint()
@@ -39,6 +40,14 @@ abstract class MeasureItemFeature implements IMeasureItemFeature {
 
     _innerPoints = [];
   }
+
+  int get activeIndex => _activeIndex;
+  set activeIndex(int val) {
+    if (val != _activeIndex) {
+      _activeIndex = val;
+    }
+  }
+
   @override
   List<DPoint> get innerPoints => _innerPoints;
 

+ 240 - 33
lib/process/primitives/ellipse.dart

@@ -1,9 +1,13 @@
 import 'dart:ui';
+import 'package:fis_measure/interfaces/date_types/matrix.dart';
 import 'package:fis_measure/interfaces/date_types/point.dart';
+import 'package:fis_measure/interfaces/date_types/rect.dart';
+import 'package:fis_measure/interfaces/date_types/vector.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/process/calcuators/formulas/general.dart';
 import 'package:fis_measure/process/calcuators/perimeter.dart';
 import 'package:fis_measure/process/calcuators/volume.dart';
 import 'package:fis_measure/utils/canvas.dart';
@@ -28,22 +32,35 @@ class Ellipse extends MeasureItem<EllipseFeature> {
       }
     } else if (state == ItemStates.running) {
       if (feature == null) return false;
-      if (args.pointType == PointInfoType.mouseUp) return false;
+      final f = feature!;
+      final activeIndex = f.activeIndex;
 
-      final points = feature!.innerPoints;
-      if (points.length < 2) {
-        points.add(args);
-      } else if (points.length < 3) {
-        points[1] = args;
-      } else {
-        points[2] = args;
+      switch (args.pointType) {
+        case PointInfoType.mouseMove:
+          f.innerPoints[activeIndex] = args;
+          f.adjustPoints(args);
+          break;
+        case PointInfoType.mouseDown:
+          if (activeIndex == 1) {
+            if (f.xAxisEnd == f.xAxisStart) {
+              break;
+            }
+            f.activeIndex = 2;
+            f.innerPoints[activeIndex] = args;
+            f.adjustPoints(args);
+          } else if (activeIndex == 2) {
+            doFeatureFinish();
+          }
+          break;
+        default:
+          return false;
       }
+
       doCalculate();
-      if (points.length == 3 && args.pointType == PointInfoType.mouseDown) {
-        doFeatureFinish();
-      }
+
+      return true;
     }
-    return true;
+    return false;
   }
 
   @override
@@ -59,6 +76,7 @@ class Ellipse extends MeasureItem<EllipseFeature> {
     if (args.hostVisualArea != null) {
       feature!.hostVisualArea = args.hostVisualArea;
     }
+    feature!.activeIndex = 1;
     state = ItemStates.running;
   }
 
@@ -77,16 +95,24 @@ class Ellipse extends MeasureItem<EllipseFeature> {
 
 class EllipseFeature extends MeasureItemFeature {
   EllipseFeature(IMeasureItem refItem, DPoint point) : super(refItem) {
-    innerPoints.add(point);
+    innerPoints.add(point.clone());
+    innerPoints.add(point.clone());
+    innerPoints.add(point.clone());
+    innerPoints.add(point.clone());
   }
 
   /// 质心
   DPoint get centroid {
-    final x = (innerPoints[1].x + innerPoints[0].x) * 0.5;
-    final y = (innerPoints[1].y + innerPoints[0].y) * 0.5;
+    final x = (xAxisStart.x + xAxisEnd.x) * 0.5;
+    final y = (xAxisStart.y + xAxisEnd.y) * 0.5;
     return DPoint(x, y);
   }
 
+  DPoint get xAxisStart => innerPoints[0];
+  DPoint get xAxisEnd => innerPoints[1];
+  DPoint get yAxisStart => innerPoints[2];
+  DPoint get yAxisEnd => innerPoints[2];
+
   @override
   void paint(Canvas canvas, Size size) {
     if (innerPoints.isEmpty) return;
@@ -94,33 +120,214 @@ class EllipseFeature extends MeasureItemFeature {
     var idText = '$id.${refItem.briefAnnotation}';
     drawId(canvas, size, idText);
 
-    final startOffset = convert2ViewPoint(size, innerPoints.first).toOffset();
+    final xStartOffset = convert2ViewPoint(size, xAxisStart).toOffset();
 
-    if (innerPoints.length < 2) {
-      drawVertex(canvas, startOffset, true);
+    if (activeIndex < 1) {
+      drawVertex(canvas, xStartOffset, true);
       return;
     }
-    drawVertex(canvas, startOffset);
+    drawVertex(canvas, xStartOffset);
 
-    final secondOffset = convert2ViewPoint(size, innerPoints[1]).toOffset();
-    canvas.drawDashLine(startOffset, secondOffset, 1, 10, paintPan);
+    final xEndOffset = convert2ViewPoint(size, xAxisEnd).toOffset();
+    canvas.drawDashLine(xStartOffset, xEndOffset, 1, 10, paintPan);
 
-    final radius = (secondOffset - startOffset).distance.abs() / 2;
+    final yStartOffset = convert2ViewPoint(size, yAxisStart).toOffset();
+    final yEndOffset = convert2ViewPoint(size, yAxisEnd).toOffset();
     final centroidOffset = convert2ViewPoint(size, centroid).toOffset();
-    canvas.drawCircle(centroidOffset, radius, paintPan);
-    // canvas.drawOval(rect, paint)
-    // final path = Path();
-    // path.moveTo(centroidOffset.dx, centroidOffset.dy);
-    // path.conicTo(x1, y1, x2, y2, w)
-    // canvas.drawPath(
-    //   dashPath(path, dashArray: CircularIntervalList([2.0, 10.0])),
-    //   paintPan,
-    // );
+    canvas.drawDashLine(yStartOffset, centroidOffset, 1, 10, paintPan);
+
+    final radiusX = getRadiusX(size);
+    final radiusY = getRadiusY(size);
+
+    final path = Path();
+    path.moveTo(xStartOffset.dx, xStartOffset.dy);
+    path.arcToPoint(
+      xEndOffset,
+      radius: Radius.elliptical(radiusX, radiusY),
+    );
+    path.arcToPoint(
+      xStartOffset,
+      radius: Radius.elliptical(radiusX, -radiusY),
+    );
+    canvas.drawPath(
+      dashPath(
+        path,
+        dashArray: CircularIntervalList<double>(<double>[2.0, 10.0]),
+      ),
+      paintPan,
+    );
 
     if (innerPoints.length < 3) {
-      drawVertex(canvas, secondOffset, true);
+      drawVertex(canvas, xEndOffset, true);
+      return;
+    }
+    drawVertex(canvas, xEndOffset);
+  }
+
+  /// X轴半径
+  double getRadiusX([Size? fitSize]) {
+    if (innerPoints.length < 2) {
+      return 0;
+    }
+    var p1 = xAxisStart;
+    var p2 = xAxisEnd;
+    if (fitSize != null) {
+      p1 = p1.scale2Size(fitSize);
+      p2 = p2.scale2Size(fitSize);
+    }
+    return (p2 - p1).length / 2;
+  }
+
+  /// Y轴半径
+  double getRadiusY([Size? fitSize]) {
+    if (innerPoints.length == 4) {
+      var p = yAxisStart;
+      var c = centroid;
+      if (fitSize != null) {
+        p = p.scale2Size(fitSize);
+        c = c.scale2Size(fitSize);
+      }
+      return (p - c).length;
+    } else {
+      return getRadiusX(fitSize);
+    }
+  }
+
+  void adjustPoints(DPoint point) {
+    final List<DPoint> crossPoints;
+    if (activeIndex == 2) {
+      final radius = GeneralFormulas.distance2Line(xAxisStart, xAxisEnd, point);
+      crossPoints = _findCrossPoints(xAxisStart, xAxisEnd, radius);
+    } else {
+      crossPoints = _findCrossPoints(xAxisStart, xAxisEnd);
+    }
+    final p3Index = _findNearest(point, crossPoints);
+    innerPoints[2] = crossPoints.removeAt(p3Index);
+    innerPoints[3] = crossPoints.first;
+  }
+
+  /// 计算Y轴坐标点
+  void adjustPoints2(DPoint adjustPoint, bool keepYAxisLength) {
+    if (innerPoints.length != 4) {
       return;
     }
-    drawVertex(canvas, secondOffset);
+    var p3 = innerPoints[2];
+    var p4 = innerPoints[3];
+
+    if (activeIndex == 0 || activeIndex == 1) {
+      _calculateYAxisPoints(
+        p3,
+        p4,
+        innerPoints[1 - activeIndex],
+        adjustPoint,
+        adjustPoint,
+        keepYAxisLength,
+      );
+    } else {
+      print(DateTime.now());
+      print(p3);
+      print(p4);
+      _calculateYAxisPoints(
+        p3,
+        p4,
+        xAxisStart,
+        xAxisEnd,
+        adjustPoint,
+        false,
+      );
+      print(p3);
+      print(p4);
+    }
+  }
+
+  static void _calculateYAxisPoints(
+    DPoint yAxisStart,
+    DPoint yAxisEnd,
+    DPoint xAxisStart,
+    DPoint xAxisEnd,
+    DPoint adjustYAxisPoint,
+    bool keepYAxisLength,
+  ) {
+    var reverseMatrix = DMatrix();
+
+    var vertical = DVector(1, 0);
+    var angleBetweenVertical = _calculateAngel(xAxisEnd, xAxisStart, vertical);
+
+    var centroidX = (xAxisStart.x + xAxisEnd.x) * 0.5;
+    var centroidY = (xAxisStart.y + xAxisEnd.y) * 0.5;
+    var centroid = DPoint(centroidX, centroidY);
+
+    reverseMatrix.rotateAt(angleBetweenVertical, centroid.x, centroid.y);
+
+    var convertMatrix = reverseMatrix..invert();
+
+    double length;
+    if (adjustYAxisPoint == xAxisEnd) {
+      if (keepYAxisLength) {
+        length = (yAxisStart - yAxisEnd).length / 2;
+      } else {
+        length = (xAxisEnd - xAxisStart).length / 2;
+      }
+    } else {
+      length =
+          GeneralFormulas.distance2Line(xAxisStart, xAxisEnd, adjustYAxisPoint);
+    }
+
+    var pt3 = DPoint(centroid.x, centroid.y + length);
+    var pt4 = DPoint(centroid.x, centroid.y - length);
+
+    var yAxisStartTrans = convertMatrix.transformWidthPoint(pt3);
+    var yAxisEndTrans = convertMatrix.transformWidthPoint(pt4);
+    yAxisStart.update(yAxisStartTrans);
+    yAxisEnd.update(yAxisEndTrans);
+  }
+
+  static double _calculateAngel(DPoint pt1, DPoint pt2, DVector axis) {
+    DVector xAxis = pt2 - pt1;
+    var angle = DVector.angleBetween(xAxis, axis);
+    return angle;
+  }
+
+  static List<DPoint> _findCrossPoints(DPoint a, DPoint b, [double? radius]) {
+    var centroidX = (a.x + b.x) * 0.5;
+    var centroidY = (a.y + b.y) * 0.5;
+    var centroid = Offset(centroidX, centroidY);
+
+    final dx = b.x - a.x;
+    final dy = b.y - a.y;
+
+    final len = (b - a).length;
+
+    /// 单位长度轴上距离增加量
+    final udx = dx / len;
+    final udy = dy / len;
+
+    final px = -udy;
+    final py = udx;
+
+    final distance = radius ?? len / 2;
+
+    final x1 = centroid.dx + px * distance;
+    final y1 = centroid.dy + py * distance;
+    final out1 = DPoint(x1, y1);
+
+    final x2 = centroid.dx - px * distance;
+    final y2 = centroid.dy - py * distance;
+    final out2 = DPoint(x2, y2);
+
+    return [out1, out2];
+  }
+
+  static int _findNearest(DPoint p, List<DPoint> source) {
+    int rst = 0;
+    double minLen = (source[0] - p).length;
+    for (var i = 1; i < source.length; i++) {
+      final len = (source[i] - p).length;
+      if (len < minLen) {
+        minLen = len;
+        rst = i;
+      }
+    }
+    return rst;
   }
 }

+ 67 - 0
test/ellipse.dart

@@ -0,0 +1,67 @@
+import 'dart:math' as math;
+import 'package:fis_measure/interfaces/date_types/matrix.dart';
+import 'package:fis_measure/interfaces/date_types/point.dart';
+import 'package:fis_measure/interfaces/date_types/vector.dart';
+
+class EllipseTest {
+  static void calculateYAxisPoints(
+    DPoint yAxisStart,
+    DPoint yAxisEnd,
+    DPoint xAxisStart,
+    DPoint xAxisEnd,
+    DPoint adjustYAxisPoint,
+    bool keepYAxisLength,
+  ) {
+    var reverseMatrix = DMatrix();
+
+    var vertical = DVector(1, 0);
+    var angleAngleBetweenVertical =
+        calculateAngel(xAxisEnd, xAxisStart, vertical);
+
+    var centroidX = (xAxisStart.x + xAxisEnd.x) * 0.5;
+    var centroidY = (xAxisStart.y + xAxisEnd.y) * 0.5;
+    var centroid = DPoint(centroidX, centroidY);
+
+    reverseMatrix.rotateAt(angleAngleBetweenVertical, centroid.x, centroid.y);
+
+    var convertMatrix = reverseMatrix;
+    convertMatrix.invert();
+
+    double length;
+    if (adjustYAxisPoint == xAxisEnd) {
+      if (keepYAxisLength) {
+        length = (yAxisStart - yAxisEnd).length / 2;
+      } else {
+        length = (xAxisEnd - xAxisStart).length / 2;
+      }
+    } else {
+      length = distance(xAxisStart, xAxisEnd, adjustYAxisPoint);
+    }
+
+    var pt3 = DPoint(centroid.x, centroid.y + length);
+    var pt4 = DPoint(centroid.x, centroid.y - length);
+
+    var yAxisStartTrans = convertMatrix.transformWidthPoint(pt3);
+    var yAxisEndTrans = convertMatrix.transformWidthPoint(pt4);
+    yAxisStart.update(yAxisStartTrans);
+    yAxisStart.update(yAxisEndTrans);
+  }
+
+  static double calculateAngel(DPoint pt1, DPoint pt2, DVector axis) {
+    DVector xAxis = pt2 - pt1;
+    var angle = DVector.angleBetween(xAxis, axis);
+    return angle;
+  }
+
+  static double distance(DPoint pt1, DPoint pt2, DPoint pt) {
+    double dis = 0;
+    if (pt1.x == pt2.x) {
+      dis = (pt.x - pt1.x).abs();
+      return dis;
+    }
+    var lineK = (pt2.y - pt1.y) / (pt2.x - pt1.x);
+    var lineC = (pt2.x * pt1.y - pt1.x * pt2.y) / (pt2.x - pt1.x);
+    dis = (lineK * pt.x - pt.y + lineC).abs() / (math.sqrt(lineK * lineK + 1));
+    return dis;
+  }
+}

+ 10 - 0
test/widget_test.dart

@@ -11,7 +11,17 @@ import 'package:fis_measure/values/unit_desc.dart';
 import 'package:flutter_test/flutter_test.dart';
 import 'package:vid/us/vid_us_unit.dart';
 
+import 'ellipse.dart';
+
 void main() {
+  test('ellipse ad', () {
+    var startPoint = DPoint(0, 400);
+    var endPoint = DPoint(400, 0);
+    // var startPoint = DPoint(0, 400);
+    // var endPoint = DPoint(400, 400);
+    EllipseTest.calculateYAxisPoints(
+        startPoint, startPoint, startPoint, endPoint, endPoint, false);
+  });
   test('Unit Description', () {
     print(UnitDescriptionMap.getDesc(VidUsUnit.HR));
     print(UnitDescriptionMap.getDescByInt(60));