|
@@ -1,4 +1,5 @@
|
|
|
import 'dart:ui';
|
|
|
+import 'dart:math' as math;
|
|
|
|
|
|
import 'package:fis_measure/interfaces/date_types/point.dart';
|
|
|
import 'package:fis_measure/interfaces/date_types/vector.dart';
|
|
@@ -20,6 +21,8 @@ import 'package:flutter/rendering.dart';
|
|
|
import 'package:path_drawing/path_drawing.dart';
|
|
|
|
|
|
import 'spline.dart';
|
|
|
+import 'utils/line.dart';
|
|
|
+import 'utils/spline.dart';
|
|
|
|
|
|
enum LvSimpsonStep {
|
|
|
none,
|
|
@@ -31,8 +34,8 @@ enum LvSimpsonStep {
|
|
|
}
|
|
|
|
|
|
class SimpsonPath extends AreaItemAbstract with AutoSnapMixin {
|
|
|
- static const int SplitterCount = 20;
|
|
|
- static const double MaxPointsCount = 10000;
|
|
|
+ static const int splitterCount = 20;
|
|
|
+ static const double maxPointsCount = 10000;
|
|
|
|
|
|
SimpsonPath(ItemMeta meta, IMeasureItem? parent) : super(meta, parent);
|
|
|
|
|
@@ -70,7 +73,7 @@ class SimpsonPath extends AreaItemAbstract with AutoSnapMixin {
|
|
|
final lineLen = (args - firstPoint!).length;
|
|
|
if ((feature!.innerPoints.length > 3 &&
|
|
|
GeneralFormulas.doubleAlmostEquals(lineLen, 0)) ||
|
|
|
- feature!.innerPoints.length >= MaxPointsCount) {
|
|
|
+ feature!.innerPoints.length >= maxPointsCount) {
|
|
|
lvSimpsonStep = LvSimpsonStep.splineCompleted;
|
|
|
feature!.fixedSpline();
|
|
|
} else {
|
|
@@ -277,6 +280,29 @@ class SimpsonPathFeature extends AreaItemFeatureAbstract {
|
|
|
// paintLinePan,
|
|
|
// );
|
|
|
// }
|
|
|
+ if (_pathGeometry != null) {
|
|
|
+ final geometry = _pathGeometry as PathGeometryContainer;
|
|
|
+ for (var fragment in geometry.geometries) {
|
|
|
+ final path = Path();
|
|
|
+ if (fragment is PathGeometry) {
|
|
|
+ for (var i = 0; i < fragment.points.length; i++) {
|
|
|
+ final point = convert2ViewPoint(size, fragment.points[i]);
|
|
|
+ if (i == 0) {
|
|
|
+ path.moveTo(point.x, point.y);
|
|
|
+ } else {
|
|
|
+ path.lineTo(point.x, point.y);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else if (fragment is LineGeometry) {
|
|
|
+ DPoint point;
|
|
|
+ point = convert2ViewPoint(size, fragment.start);
|
|
|
+ path.moveTo(point.x, point.y);
|
|
|
+ point = convert2ViewPoint(size, fragment.end);
|
|
|
+ path.lineTo(point.x, point.y);
|
|
|
+ }
|
|
|
+ canvas.drawPath(path, paintLinePan);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
drawVertex(canvas, points.last.toOffset(), isActive);
|
|
|
}
|
|
@@ -443,8 +469,6 @@ class SimpsonGeometryGenerator {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- // TODO: 辛普森绘制核心
|
|
|
-
|
|
|
// Center line
|
|
|
DVector centerLine = centerLineMovablePoint - centerLineFixedPoint;
|
|
|
var horizontalStart = DPoint(-50, centerLineFixedPoint.y);
|
|
@@ -462,26 +486,75 @@ class SimpsonGeometryGenerator {
|
|
|
double midPointY =
|
|
|
centerLineFixedPoint.y - cellHeight * (i - 1) - cellHeight / 2;
|
|
|
//horizontal splitter line
|
|
|
- final tempLinePath = Path();
|
|
|
- tempLinePath.moveTo(-50, midPointY);
|
|
|
- tempLinePath.lineTo(50, midPointY);
|
|
|
-
|
|
|
- var matrix = Matrix4.identity();
|
|
|
- matrix.rotateZ(angleToVertical * 0.0174533); // Convert degrees to radians
|
|
|
- // matrix.translate(centerLineFixedPoint.dx, centerLineFixedPoint.dy);
|
|
|
- matrix.scale(1, 1, 1); // Adjust scale if needed
|
|
|
- matrix.translate(
|
|
|
- -50, -midPointY); // Adjust translation to center the line
|
|
|
- // tempLinePath.transform(matrix)
|
|
|
- // LineGeometry templineGeometry =
|
|
|
- // new LineGeometry(Point(-50, midPointY), Point(50, midPointY));
|
|
|
- // templineGeometry.Transform = new RotateTransform(
|
|
|
- // -angleToVertical, centerLineFixedPoint.x, centerLineFixedPoint.y);
|
|
|
- // temSplittersGeometry.addGeometry(templineGeometry);
|
|
|
+ DPoint p1 = DPoint(-50, midPointY);
|
|
|
+ DPoint p2 = DPoint(50, midPointY);
|
|
|
+
|
|
|
+ final lineGeometry = LineGeometry(p1, p2);
|
|
|
+ lineGeometry.rotateTransform(
|
|
|
+ angle,
|
|
|
+ centerLineFixedPoint.x,
|
|
|
+ centerLineFixedPoint.y,
|
|
|
+ );
|
|
|
+
|
|
|
+ temSplittersGeometry.addGeometry(lineGeometry);
|
|
|
}
|
|
|
|
|
|
+ //Get intersection points
|
|
|
+ List<DPoint> points = getIntersectionPoints(temSplittersGeometry, spline);
|
|
|
List<DPoint> leftPoints = [];
|
|
|
List<DPoint> rightPoints = [];
|
|
|
+ //Split point by center line
|
|
|
+ const double constMagnify = 1000.0;
|
|
|
+ for (DPoint point in points) {
|
|
|
+ var magnifyPoint = point;
|
|
|
+ magnifyPoint.x *= constMagnify;
|
|
|
+ magnifyPoint.y *= constMagnify;
|
|
|
+
|
|
|
+ DVector line = magnifyPoint -
|
|
|
+ DPoint(
|
|
|
+ (centerLineFixedPoint.x + centerLineMovablePoint.x) /
|
|
|
+ 2.0 *
|
|
|
+ constMagnify,
|
|
|
+ (centerLineFixedPoint.y + centerLineMovablePoint.y) /
|
|
|
+ 2.0 *
|
|
|
+ constMagnify,
|
|
|
+ );
|
|
|
+
|
|
|
+ double angleToCenter = DVector.angleBetween(line, centerLine);
|
|
|
+
|
|
|
+ if (angleToCenter >= 0.0) {
|
|
|
+ leftPoints.add(point);
|
|
|
+ } else {
|
|
|
+ rightPoints.add(point);
|
|
|
+ }
|
|
|
+ //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);
|
|
|
+ return vA.compareTo(vB);
|
|
|
+ });
|
|
|
+ rightPoints.sort((a, b) {
|
|
|
+ final vA = orderByCalc(a);
|
|
|
+ final vB = orderByCalc(b);
|
|
|
+ return vA.compareTo(vB);
|
|
|
+ });
|
|
|
+ var finalLeftPoint = leftPoints;
|
|
|
+ var finalRightPoint = rightPoints;
|
|
|
+
|
|
|
+ if (finalLeftPoint.length == finalRightPoint.length &&
|
|
|
+ finalLeftPoint.length == splitterCount) {
|
|
|
+ for (int i = 0; i < splitterCount; i++) {
|
|
|
+ horizontalSplitterLegths[i + 1] =
|
|
|
+ (finalLeftPoint[i] - finalRightPoint[i]).length;
|
|
|
+ pathGeometry.addLineGeometry(finalLeftPoint[i], finalRightPoint[i]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
IPathGeometry? createSpline(
|
|
@@ -499,26 +572,65 @@ class SimpsonGeometryGenerator {
|
|
|
return null;
|
|
|
}
|
|
|
List<DPoint> samplePoints = [];
|
|
|
- // var points = Spline.create(sourcePoints, tension, tensions, isClosed, tolerance, true, out length, samplePoints,true);
|
|
|
- var points = <DPoint>[];
|
|
|
+ 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);
|
|
|
- var pathGeometry = Path();
|
|
|
// pathGeometry.Figures.Add(pathFigure);
|
|
|
|
|
|
splinePoints = points;
|
|
|
- return PathGeometryContainer(pathGeometry);
|
|
|
+
|
|
|
+ final pathGeometry = PathGeometry(points);
|
|
|
+ final continer = PathGeometryContainer(Path());
|
|
|
+ continer.addGeometry(pathGeometry);
|
|
|
+ return continer;
|
|
|
}
|
|
|
|
|
|
IPathGeometry createPathGeometry() {
|
|
|
return PathGeometryContainer(Path());
|
|
|
}
|
|
|
+
|
|
|
+ static double rotaeY(DPoint point, DPoint cenPoint, double theta) {
|
|
|
+ return math.sin(theta) * (point.x - cenPoint.x) +
|
|
|
+ math.cos(theta) * (point.y - cenPoint.y) +
|
|
|
+ cenPoint.y;
|
|
|
+ }
|
|
|
+
|
|
|
+ List<DPoint> getIntersectionPoints(IPathGeometry g1, IPathGeometry g2) {
|
|
|
+ final result = <DPoint>[];
|
|
|
+ final splittersGeometry = g1 as PathGeometryContainer;
|
|
|
+ final splineGeometry = g2 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);
|
|
|
+ }
|
|
|
+ if (i != endLimit) {
|
|
|
+ lastPoint = point;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
class PathGeometryContainer implements IPathGeometry {
|
|
|
- final pathList = <Path>[];
|
|
|
final geometries = <IPathGeometry>[];
|
|
|
late final Path control;
|
|
|
|
|
@@ -531,22 +643,74 @@ class PathGeometryContainer implements IPathGeometry {
|
|
|
geometries.add(geometry);
|
|
|
}
|
|
|
|
|
|
- void addPath(Path path) {
|
|
|
- pathList.add(path);
|
|
|
- }
|
|
|
-
|
|
|
@override
|
|
|
void clear() {
|
|
|
- pathList.clear();
|
|
|
+ geometries.clear();
|
|
|
}
|
|
|
|
|
|
@override
|
|
|
void addLineGeometry(
|
|
|
DPoint centerLineFixedPoint, DPoint centerLineMovablePoint) {
|
|
|
- final linePath = Path()
|
|
|
- ..moveTo(centerLineFixedPoint.x, centerLineFixedPoint.y)
|
|
|
- ..lineTo(centerLineMovablePoint.x, centerLineMovablePoint.y);
|
|
|
- addPath(linePath);
|
|
|
+ // final linePath = Path()
|
|
|
+ // ..moveTo(centerLineFixedPoint.x, centerLineFixedPoint.y)
|
|
|
+ // ..lineTo(centerLineMovablePoint.x, centerLineMovablePoint.y);
|
|
|
+ addGeometry(LineGeometry(centerLineFixedPoint, centerLineMovablePoint));
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+class PathGeometry implements IPathGeometry {
|
|
|
+ final List<DPoint> points;
|
|
|
+
|
|
|
+ PathGeometry(this.points);
|
|
|
+
|
|
|
+ @override
|
|
|
+ void addGeometry(IPathGeometry spline) {}
|
|
|
+
|
|
|
+ @override
|
|
|
+ void addLineGeometry(
|
|
|
+ DPoint centerLineFixedPoint, DPoint centerLineMovablePoint) {}
|
|
|
+
|
|
|
+ @override
|
|
|
+ void clear() {}
|
|
|
+}
|
|
|
+
|
|
|
+class LineGeometry implements IPathGeometry {
|
|
|
+ final DPoint start;
|
|
|
+ final DPoint end;
|
|
|
+
|
|
|
+ LineGeometry(this.start, this.end);
|
|
|
+
|
|
|
+ @override
|
|
|
+ void addGeometry(IPathGeometry spline) {}
|
|
|
+
|
|
|
+ @override
|
|
|
+ void addLineGeometry(
|
|
|
+ DPoint centerLineFixedPoint, DPoint centerLineMovablePoint) {}
|
|
|
+
|
|
|
+ @override
|
|
|
+ void clear() {}
|
|
|
+
|
|
|
+ void rotateTransform(double angle, double centerX, double centerY) {
|
|
|
+ rotatePoint(start, centerX, centerY, angle);
|
|
|
+ rotatePoint(end, centerX, centerY, angle);
|
|
|
+ }
|
|
|
+
|
|
|
+ static void rotatePoint(
|
|
|
+ DPoint point,
|
|
|
+ double centerX,
|
|
|
+ double centerY,
|
|
|
+ double angle,
|
|
|
+ ) {
|
|
|
+ double radians = angle * math.pi / 180;
|
|
|
+ double cosTheta = math.cos(radians);
|
|
|
+ double sinTheta = math.sin(radians);
|
|
|
+
|
|
|
+ point.x = centerX +
|
|
|
+ (point.x - centerX) * cosTheta -
|
|
|
+ (point.y - centerY) * sinTheta;
|
|
|
+ point.y = centerY +
|
|
|
+ (point.x - centerX) * sinTheta +
|
|
|
+ (point.y - centerY) * cosTheta;
|
|
|
}
|
|
|
}
|
|
|
|