Browse Source

implement simpson path feature

Melon 10 months ago
parent
commit
4f9410e44f

+ 73 - 74
lib/process/primitives/simpson_path.dart

@@ -278,8 +278,6 @@ class SimpsonPathFeature extends AreaItemFeatureAbstract {
     final startPoint = points.first;
     drawVertex(canvas, startPoint.toOffset(), points.length == 1);
 
-    // if(refItem.lvSimpsonStep==)
-
     if (points.length > 1) {
       final Path path = Path();
       path.moveTo(startPoint.x, startPoint.y);
@@ -300,21 +298,21 @@ class SimpsonPathFeature extends AreaItemFeatureAbstract {
       _drawGeometry(canvas, size, _pathGeometry!);
     }
 
-    canvas.drawCircle(
-      convert2ViewPoint(size, centerLineFixedPoint).toOffset(),
-      10,
-      Paint()
-        ..color = Colors.blue
-        ..style = PaintingStyle.fill,
-    );
-
-    canvas.drawCircle(
-      convert2ViewPoint(size, centerLineMovablePoint).toOffset(),
-      10,
-      Paint()
-        ..color = Colors.red
-        ..style = PaintingStyle.fill,
-    );
+    // 此处仅供调试绘制参考点
+    // canvas.drawCircle(
+    //   convert2ViewPoint(size, centerLineFixedPoint).toOffset(),
+    //   10,
+    //   Paint()
+    //     ..color = Colors.blue
+    //     ..style = PaintingStyle.fill,
+    // );
+    // canvas.drawCircle(
+    //   convert2ViewPoint(size, centerLineMovablePoint).toOffset(),
+    //   10,
+    //   Paint()
+    //     ..color = Colors.red
+    //     ..style = PaintingStyle.fill,
+    // );
 
     drawVertex(canvas, points.last.toOffset(), isActive);
   }
@@ -429,8 +427,19 @@ class SimpsonPathFeature extends AreaItemFeatureAbstract {
     }
     var endPoint = point;
     double minDistance = double.infinity;
-    if (_splinePoints != null) {
-      for (DPoint splinePoint in _splinePoints!) {
+    // if (_splinePoints != null && _splinePoints!.isNotEmpty) {
+    //   for (DPoint splinePoint in _splinePoints!) {
+    //     double distance = (point - splinePoint).length;
+    //     if (distance < minDistance) {
+    //       minDistance = distance;
+    //       endPoint = splinePoint;
+    //     }
+    //   }
+    // }
+    // TODO: _splinePoints填充和此处时序有问题,先用innerPoints代替,有性能问题,后续解决
+    if (innerPoints.isNotEmpty) {
+      final splinePoints = innerPoints.take(innerPoints.length - 1);
+      for (DPoint splinePoint in splinePoints) {
         double distance = (point - splinePoint).length;
         if (distance < minDistance) {
           minDistance = distance;
@@ -438,7 +447,6 @@ class SimpsonPathFeature extends AreaItemFeatureAbstract {
         }
       }
     }
-
     centerLineMovablePoint = endPoint;
   }
 
@@ -513,48 +521,32 @@ class SimpsonGeometryGenerator {
 
     // Center line
     DVector centerLine = centerLineMovablePoint - centerLineFixedPoint;
-    // var horizontalStart = DPoint(-50, centerLineFixedPoint.y);
-    var horizontalStart = DPoint(-0.5, centerLineFixedPoint.y);
-    // horizonta line
-    DVector horizontalLine = horizontalStart - centerLineFixedPoint;
-    // Get angle between horizontal and center line
-    double angle = DVector.angleBetween(horizontalLine, centerLine);
-    double angleToVertical = 90.0 - angle;
 
-    double cellHeight = centerLine.length / splitterCount;
+    DVector centerPerLine = centerLine / 20;
+    final verticalVector = DVector(-centerLine.y, centerLine.x) * 50;
 
     //Create a 20 splitters path geometry
     PathGeometryContainer temSplittersGeometry = PathGeometryContainer(Path());
-    for (int i = 1; i <= splitterCount; i++) {
-      double midPointY =
-          centerLineFixedPoint.y - cellHeight * (i - 1) - cellHeight / 2;
-      //horizontal splitter line
-      // DPoint p1 = DPoint(-50, midPointY);
-      // DPoint p2 = DPoint(50, midPointY);
-      // DPoint p1 = DPoint(-0.5, midPointY);
-      // DPoint p2 = DPoint(0.5, midPointY);
-      DPoint p1 = DPoint(0, midPointY);
-      DPoint p2 = DPoint(1, midPointY);
-
+    for (var i = 0; i < splitterCount; i++) {
+      final center = centerLineFixedPoint
+          .clone()
+          .addVector(centerPerLine * i.toDouble())
+          .addVector(centerPerLine / 2);
+      DPoint p1 = center.clone().addVector(verticalVector);
+      DPoint p2 = center.clone().subtractVector(verticalVector);
       final lineGeometry = LineGeometry(p1, p2);
-      lineGeometry.rotateTransform(
-        -angleToVertical,
-        centerLineFixedPoint.x,
-        centerLineFixedPoint.y,
-      );
-
       temSplittersGeometry.addGeometry(lineGeometry);
-      pathGeometry.addGeometry(lineGeometry); // TODO remove
     }
 
     //Get intersection points
     List<DPoint> points = getIntersectionPoints(temSplittersGeometry, spline);
+
     List<DPoint> leftPoints = [];
     List<DPoint> rightPoints = [];
     //Split point by center line
     const double constMagnify = 1.0;
     for (DPoint point in points) {
-      var magnifyPoint = point;
+      var magnifyPoint = point.clone();
       magnifyPoint.x *= constMagnify;
       magnifyPoint.y *= constMagnify;
 
@@ -576,12 +568,17 @@ class SimpsonGeometryGenerator {
         rightPoints.add(point);
       }
     }
+
+    double angleToVertical =
+        DVector.angleBetween(verticalVector, DVector(1, 0));
+
     //order point by vertical axis value
     orderByCalc(DPoint point) => rotaeY(
           point,
           centerLineFixedPoint,
           angleToVertical * math.pi / 180.0,
         );
+
     leftPoints.sort((a, b) {
       final vA = orderByCalc(a);
       final vB = orderByCalc(b);
@@ -592,6 +589,7 @@ class SimpsonGeometryGenerator {
       final vB = orderByCalc(b);
       return vA.compareTo(vB);
     });
+
     var finalLeftPoint = leftPoints;
     var finalRightPoint = rightPoints;
 
@@ -619,23 +617,18 @@ class SimpsonGeometryGenerator {
     if (sourcePoints.isEmpty) {
       return null;
     }
-    List<DPoint> samplePoints = [];
-    var points = SplineUtils.create(
-      sourcePoints,
-      tension: tension,
-      tensions: tensions,
-      isClosed: isClosed,
-      tolerance: tolerance,
-      closeByStraightLine: true,
-      samplePoints: samplePoints,
-      isSimpsonSpline: true,
-    );
-    // var myPoints = GeomTools.ToWindowPoints(points.ToArray());
-    // var polyLineSegment = new PolyLineSegment { Points = new PointCollection(myPoints) };
-    // var pathFigure = new PathFigure { IsClosed = isClosed, IsFilled = true, StartPoint = sourcePoints[0].ToWindowPoint() };
-    // pathFigure.Segments.Add(polyLineSegment);
-    // pathGeometry.Figures.Add(pathFigure);
-
+    // List<DPoint> samplePoints = [];
+    // var points = SplineUtils.create(
+    //   sourcePoints,
+    //   tension: tension,
+    //   tensions: tensions,
+    //   isClosed: isClosed,
+    //   tolerance: tolerance,
+    //   closeByStraightLine: true,
+    //   samplePoints: samplePoints,
+    //   isSimpsonSpline: true,
+    // );
+    final points = sourcePoints; // TODO: !!!!!!! 创建收缩Spline有问题,先不计算了,有性能问题再优化
     splinePoints = points;
 
     final pathGeometry = PathGeometry(points);
@@ -659,19 +652,26 @@ class SimpsonGeometryGenerator {
     final splittersGeometry = g1 as PathGeometryContainer;
     final splineGeometry =
         (g2 as PathGeometryContainer).geometries.first as PathGeometry;
+
     for (var splitter in splittersGeometry.geometries) {
       splitter as LineGeometry;
       DPoint lastPoint = splineGeometry.points.first;
       final endLimit = splineGeometry.points.length - 1;
       for (var i = 1; i < splineGeometry.points.length; i++) {
-        final point = splineGeometry.points[i];
-        final intersection = LineUtils.calculateIntersection(
-            splitter.start, splitter.end, lastPoint, point);
-        if (intersection != null) {
-          result.add(intersection);
+        final currPoint = splineGeometry.points[i];
+        final crossPoint = LineUtils.calculateIntersection(
+          splitter.start,
+          splitter.end,
+          lastPoint,
+          currPoint,
+        );
+        if (crossPoint != null) {
+          if (LineUtils.isPointOnLine(lastPoint, currPoint, crossPoint)) {
+            result.add(crossPoint);
+          }
         }
         if (i != endLimit) {
-          lastPoint = point;
+          lastPoint = currPoint;
         }
       }
     }
@@ -699,10 +699,9 @@ class PathGeometryContainer implements IPathGeometry {
 
   @override
   void addLineGeometry(
-      DPoint centerLineFixedPoint, DPoint centerLineMovablePoint) {
-    // final linePath = Path()
-    //   ..moveTo(centerLineFixedPoint.x, centerLineFixedPoint.y)
-    //   ..lineTo(centerLineMovablePoint.x, centerLineMovablePoint.y);
+    DPoint centerLineFixedPoint,
+    DPoint centerLineMovablePoint,
+  ) {
     addGeometry(LineGeometry(centerLineFixedPoint, centerLineMovablePoint));
   }
 }

+ 56 - 24
lib/process/primitives/utils/line.dart

@@ -1,4 +1,5 @@
 import 'package:fis_measure/interfaces/date_types/point.dart';
+import 'package:fis_measure/interfaces/date_types/vector.dart';
 
 class LineUtils {
   // 计算两条直线是否有交点
@@ -8,30 +9,61 @@ class LineUtils {
     DPoint startB,
     DPoint endB,
   ) {
-    final lineA = _IntersectionTempLine.fromPoints(startA, endA);
-    final lineB = _IntersectionTempLine.fromPoints(startB, endB);
-
-    if (lineA.isVertical && lineB.isVertical) {
-      // 两条直线都是垂直线,没有交点
-      return null;
-    } else if (lineA.isVertical) {
-      // 第一条直线是垂直线,交点的x坐标是第一条直线的x坐标
-      return DPoint(
-          lineA.intercept, lineB.slope * lineA.intercept + lineB.intercept);
-    } else if (lineB.isVertical) {
-      // 第二条直线是垂直线,交点的x坐标是第二条直线的x坐标
-      return DPoint(
-          lineB.intercept, lineA.slope * lineB.intercept + lineA.intercept);
-    } else if (lineA.slope == lineB.slope) {
-      // 斜率相同,直线平行或重合,没有交点
-      return null;
-    } else {
-      // 斜率不同,计算交点
-      double x =
-          (lineB.intercept - lineA.intercept) / (lineA.slope - lineB.slope);
-      double y = lineA.slope * x + lineA.intercept;
-      return DPoint(x, y);
-    }
+    return _getIntersectionPointCloneCSharp(startA, endA, startB, endB);
+    // final lineA = _IntersectionTempLine.fromPoints(startA, endA);
+    // final lineB = _IntersectionTempLine.fromPoints(startB, endB);
+
+    // if (lineA.isVertical && lineB.isVertical) {
+    //   // 两条直线都是垂直线,没有交点
+    //   return null;
+    // } else if (lineA.isVertical) {
+    //   // 第一条直线是垂直线,交点的x坐标是第一条直线的x坐标
+    //   return DPoint(
+    //       lineA.intercept, lineB.slope * lineA.intercept + lineB.intercept);
+    // } else if (lineB.isVertical) {
+    //   // 第二条直线是垂直线,交点的x坐标是第二条直线的x坐标
+    //   return DPoint(
+    //       lineB.intercept, lineA.slope * lineB.intercept + lineA.intercept);
+    // } else if (lineA.slope == lineB.slope) {
+    //   // 斜率相同,直线平行或重合,没有交点
+    //   return null;
+    // } else {
+    //   // 斜率不同,计算交点
+    //   double x =
+    //       (lineB.intercept - lineA.intercept) / (lineA.slope - lineB.slope);
+    //   double y = lineA.slope * x + lineA.intercept;
+    //   return DPoint(x, y);
+    // }
+  }
+
+  static bool isPointOnLine(DPoint p1, DPoint p2, DPoint point) {
+    // 计算向量v和w
+    DVector v = p2 - p1;
+    DVector w = point - p1;
+
+    // 计算叉积和点积
+    double crossProduct = v.x * w.y - v.y * w.x;
+    double dotProduct = _dotVector(v, w);
+
+    // 判断点是否在线上
+    // 叉积接近0表示点在与线垂直的线上,点积在0到v的模的平方之间表示点在p1和p2之间
+    return crossProduct.abs() < 1e-10 &&
+        dotProduct >= 0 &&
+        dotProduct <= _dotVector(v, v);
+  }
+
+  static double _dotVector(DVector a, DVector b) {
+    return a.x * b.x + a.y * b.y;
+  }
+
+  static DPoint? _getIntersectionPointCloneCSharp(
+      DPoint p1, DPoint p2, DPoint p3, DPoint p4) {
+    double denom =
+        (p4.x - p3.x) * (p2.y - p1.y) - (p2.x - p1.x) * (p4.y - p3.y);
+    if (denom == 0) return null;
+    double t1 =
+        ((p3.x - p1.x) * (p3.y - p4.y) - (p3.y - p1.y) * (p3.x - p4.x)) / denom;
+    return DPoint(p1.x + t1 * (p2.x - p1.x), p1.y + t1 * (p2.y - p1.y));
   }
 }
 

+ 2 - 3
lib/process/primitives/utils/spline.dart

@@ -46,7 +46,7 @@ class SplineUtils {
       generateSamplePointsFromTraceLine(pts[0], pts[1], samplePoints);
     } else {
       // var startEndTension = ResourceManager.GetValue("Measurement", "Tension", 0.1);
-      var startEndTension = 0.1 / 100; // TODO
+      var startEndTension = 0.1; // TODO
 
       List<int> pointSegments = [];
       var useTensionCollection = tensions != null && tensions.isNotEmpty;
@@ -234,8 +234,7 @@ class SplineUtils {
     double dx = pt1.x;
     double dy = pt1.y;
 
-    int num =
-        ((pt1.x - pt2.x).abs() + (pt1.y - pt2.y).abs() ~/ tolerance).toInt();
+    int num = ((pt1.x - pt2.x).abs() + (pt1.y - pt2.y).abs()) ~/ tolerance;
 
     for (int i = 1; i < num; i++) {
       double t = i / (num - 1);