|
@@ -1,11 +1,14 @@
|
|
|
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';
|
|
|
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/items/types.dart';
|
|
|
import 'package:fis_measure/interfaces/process/workspace/point_info.dart';
|
|
|
+import 'package:fis_measure/process/calcuators/curve.dart';
|
|
|
import 'package:fis_measure/process/calcuators/formulas/general.dart';
|
|
|
import 'package:fis_measure/process/items/item.dart';
|
|
|
import 'package:fis_measure/process/items/item_feature.dart';
|
|
@@ -14,8 +17,13 @@ import 'package:fis_measure/process/primitives/area_abstract.dart';
|
|
|
import 'package:fis_measure/process/primitives/utils/auto_snap.dart';
|
|
|
import 'package:fis_measure/utils/canvas.dart';
|
|
|
import 'package:flutter/foundation.dart';
|
|
|
+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,
|
|
|
splineBeginEdit,
|
|
@@ -26,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);
|
|
|
|
|
@@ -65,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 {
|
|
@@ -153,23 +161,34 @@ class SimpsonPath extends AreaItemAbstract with AutoSnapMixin {
|
|
|
}
|
|
|
|
|
|
class SimpsonPathFeature extends AreaItemFeatureAbstract {
|
|
|
- Map<int, double> horizontalSplitterLegths = {};
|
|
|
+ static const autoGetApexPoint = false; // TODO
|
|
|
+
|
|
|
+ late Map<int, double> horizontalSplitterLegths;
|
|
|
+ late DPoint moveBasedPoint;
|
|
|
+
|
|
|
IPathGeometry? _pathGeometry;
|
|
|
List<DPoint>? _splinePoints;
|
|
|
IPathGeometry? _spline;
|
|
|
late DPoint _centerLineFixedPoint;
|
|
|
late DPoint _centerLineMovablePoint;
|
|
|
+
|
|
|
+ late MovablePointsInfo _movablePtsInfo;
|
|
|
late DPoint _leftPoint;
|
|
|
late DPoint _rightPoint;
|
|
|
late DPoint _apexPoint;
|
|
|
|
|
|
SimpsonPathFeature(AreaItemAbstract refItem) : super(refItem) {
|
|
|
- // _splinePoints = [];
|
|
|
+ _splinePoints = [];
|
|
|
_centerLineFixedPoint = DPointExt.empty;
|
|
|
_centerLineMovablePoint = DPointExt.empty;
|
|
|
+
|
|
|
+ _movablePtsInfo = MovablePointsInfo.empty();
|
|
|
_leftPoint = DPointExt.empty;
|
|
|
_rightPoint = DPointExt.empty;
|
|
|
_apexPoint = DPointExt.empty;
|
|
|
+
|
|
|
+ moveBasedPoint = DPointExt.empty;
|
|
|
+ horizontalSplitterLegths = {};
|
|
|
}
|
|
|
|
|
|
@override
|
|
@@ -181,10 +200,61 @@ class SimpsonPathFeature extends AreaItemFeatureAbstract {
|
|
|
_centerLineMovablePoint = val;
|
|
|
|
|
|
updateSplitters();
|
|
|
- // OnVertexPointChanged();
|
|
|
+ _onVertexPointChanged();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ DPoint get centerLineFixedPoint => _centerLineFixedPoint;
|
|
|
+
|
|
|
+ MovablePointsInfo get movablePtsInfo => _movablePtsInfo;
|
|
|
+ set movablePtsInfo(MovablePointsInfo val) {
|
|
|
+ if (val != _movablePtsInfo) {
|
|
|
+ _movablePtsInfo = val;
|
|
|
+ _onSplineMovablePointsInfoChanged();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ DPoint get leftPoint => _leftPoint;
|
|
|
+ set leftPoint(DPoint val) {
|
|
|
+ if (val != _leftPoint) {
|
|
|
+ _leftPoint = val;
|
|
|
+ _onVertexPointChanged();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ DPoint get rightPoint => _rightPoint;
|
|
|
+ set rightPoint(DPoint val) {
|
|
|
+ if (val != _rightPoint) {
|
|
|
+ _rightPoint = val;
|
|
|
+ _onVertexPointChanged();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ DPoint get apexPoint => _apexPoint;
|
|
|
+ set apexPoint(DPoint val) {
|
|
|
+ if (val != _apexPoint) {
|
|
|
+ _apexPoint = val;
|
|
|
+ _onVertexPointChanged();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ double get centerLineLength {
|
|
|
+ final viewport = hostVisualArea!.viewport!;
|
|
|
+ final p1 = viewport.convert(_centerLineFixedPoint);
|
|
|
+ final p2 = viewport.convert(_centerLineMovablePoint);
|
|
|
+ final value = (p2 - p1).length.abs();
|
|
|
+ return value;
|
|
|
+ }
|
|
|
+
|
|
|
+ double get area {
|
|
|
+ final viewport = hostVisualArea!.viewport!;
|
|
|
+ final points = innerPoints.map((e) => viewport.convert(e)).toList();
|
|
|
+ final value = AreaPerimeterCal.calcArea(points);
|
|
|
+ return value;
|
|
|
+ }
|
|
|
+
|
|
|
+ bool isClosed = false; // TODO
|
|
|
+
|
|
|
@override
|
|
|
void paint(Canvas canvas, Size size) {
|
|
|
if (innerPoints.isEmpty) return;
|
|
@@ -210,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);
|
|
|
}
|
|
@@ -222,73 +315,70 @@ class SimpsonPathFeature extends AreaItemFeatureAbstract {
|
|
|
|
|
|
void updateActivePoint(DPoint point) {
|
|
|
if (activeIndex > 0 && activeIndex <= innerPoints.length) {
|
|
|
- // ActivePoint = point;
|
|
|
+ activePoint = point;
|
|
|
recreateSpline(false);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ DPoint get activePoint {
|
|
|
+ if (activeIndex < 0 || activeIndex >= innerPoints.length) {
|
|
|
+ throw IndexError.withLength(activeIndex, innerPoints.length);
|
|
|
+ }
|
|
|
+ return innerPoints[activeIndex];
|
|
|
+ }
|
|
|
+
|
|
|
+ set activePoint(DPoint val) {
|
|
|
+ if (activeIndex < 0 || activeIndex >= innerPoints.length) {
|
|
|
+ throw IndexError.withLength(activeIndex, innerPoints.length);
|
|
|
+ }
|
|
|
+ innerPoints[activeIndex] = val;
|
|
|
+ }
|
|
|
+
|
|
|
void fixedSpline() {
|
|
|
- return;
|
|
|
if (innerPoints.isEmpty) {
|
|
|
return;
|
|
|
}
|
|
|
- // _centerLineFixedPoint =
|
|
|
- DPoint((innerPoints.last.x + innerPoints.first.x) * 0.5,
|
|
|
- (innerPoints.last.y + innerPoints.first.y) * 0.5);
|
|
|
+ _centerLineFixedPoint = DPoint(
|
|
|
+ (innerPoints.last.x + innerPoints.first.x) * 0.5,
|
|
|
+ (innerPoints.last.y + innerPoints.first.y) * 0.5,
|
|
|
+ );
|
|
|
|
|
|
var movablePoint = DPoint(0, double.infinity);
|
|
|
|
|
|
- // if (BaseType == MeasureTypes.SimpsonAutoTrace)
|
|
|
- // {
|
|
|
- // movablePoint = InnerPoints[InnerPoints.Count >> 1];
|
|
|
- // }
|
|
|
- // else
|
|
|
- // {
|
|
|
- // var isFindMin = innerPoints[innerPoints.length >> 1].y - innerPoints[0].y < 0;
|
|
|
- // if (AutoGetApexPoint)
|
|
|
- // {
|
|
|
- // movablePoint = isFindMin ? movablePoint : DPoint(0, double.negativeInfinity);
|
|
|
- // }
|
|
|
+ var isFindMin =
|
|
|
+ innerPoints[innerPoints.length >> 1].y - innerPoints[0].y < 0;
|
|
|
+ if (autoGetApexPoint) {
|
|
|
+ movablePoint =
|
|
|
+ isFindMin ? movablePoint : DPoint(0, double.negativeInfinity);
|
|
|
+ }
|
|
|
|
|
|
- // foreach (DPoint point in InnerPoints)
|
|
|
- // {
|
|
|
- // if (AutoGetApexPoint && innerPoints.Count > 0)
|
|
|
- // {
|
|
|
- // if (isFindMin)
|
|
|
- // {
|
|
|
- // if (point.Y < movablePoint.Y)
|
|
|
- // {
|
|
|
- // movablePoint = point;
|
|
|
- // }
|
|
|
- // }
|
|
|
- // else
|
|
|
- // {
|
|
|
- // if (point.Y > movablePoint.Y)
|
|
|
- // {
|
|
|
- // movablePoint = point;
|
|
|
- // }
|
|
|
- // }
|
|
|
- // }
|
|
|
- // else
|
|
|
- // {
|
|
|
- // if (point.Y < movablePoint.Y)
|
|
|
- // {
|
|
|
- // movablePoint = point;
|
|
|
- // }
|
|
|
- // }
|
|
|
- // }
|
|
|
- // }
|
|
|
+ for (DPoint point in innerPoints) {
|
|
|
+ if (autoGetApexPoint && innerPoints.isNotEmpty) {
|
|
|
+ if (isFindMin) {
|
|
|
+ if (point.y < movablePoint.y) {
|
|
|
+ movablePoint = point;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (point.y > movablePoint.y) {
|
|
|
+ movablePoint = point;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (point.y < movablePoint.y) {
|
|
|
+ movablePoint = point;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- // if (_centerLineMovablePoint != movablePoint)
|
|
|
- // {
|
|
|
- // _centerLineMovablePoint = movablePoint;
|
|
|
- // if (!DPointExtension.IsEmpty(_centerLineMovablePoint) && (BaseType != MeasureTypes.SimpsonAutoTrace))
|
|
|
- // {
|
|
|
- // _centerLineMovablePoint.SynchToMainMonitorScreen(HostArea);
|
|
|
- // }
|
|
|
- // }
|
|
|
- // UpdateSplitters();
|
|
|
- // OnVertexPointChanged();
|
|
|
+ if (_centerLineMovablePoint != movablePoint) {
|
|
|
+ _centerLineMovablePoint = movablePoint;
|
|
|
+ if (!_centerLineMovablePoint.isEmpty) {
|
|
|
+ // TODO 重设光标位置,暂不支持
|
|
|
+ // _centerLineMovablePoint.SynchToMainMonitorScreen(HostArea);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ updateSplitters();
|
|
|
+ _onVertexPointChanged();
|
|
|
}
|
|
|
|
|
|
void adjustEndPoint(DPoint point) {
|
|
@@ -360,6 +450,9 @@ class SimpsonPathFeature extends AreaItemFeatureAbstract {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ void _onVertexPointChanged() {}
|
|
|
+ void _onSplineMovablePointsInfoChanged() {}
|
|
|
}
|
|
|
|
|
|
class SimpsonGeometryGenerator {
|
|
@@ -372,7 +465,96 @@ class SimpsonGeometryGenerator {
|
|
|
DPoint centerLineMovablePoint,
|
|
|
Map<int, double> horizontalSplitterLegths,
|
|
|
) {
|
|
|
- // TODO: 辛普森绘制核心
|
|
|
+ if (centerLineFixedPoint.isEmpty || centerLineMovablePoint.isEmpty) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Center line
|
|
|
+ DVector centerLine = centerLineMovablePoint - centerLineFixedPoint;
|
|
|
+ var horizontalStart = DPoint(-50, 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;
|
|
|
+
|
|
|
+ //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);
|
|
|
+
|
|
|
+ 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(
|
|
@@ -390,26 +572,66 @@ 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;
|
|
|
|
|
|
PathGeometryContainer(Path geometry) {
|
|
@@ -418,26 +640,77 @@ class PathGeometryContainer implements IPathGeometry {
|
|
|
|
|
|
@override
|
|
|
void addGeometry(IPathGeometry geometry) {
|
|
|
- // TODO:
|
|
|
- // pathList.addAll(geometry.pathList);
|
|
|
- }
|
|
|
-
|
|
|
- void addPath(Path path) {
|
|
|
- pathList.add(path);
|
|
|
+ geometries.add(geometry);
|
|
|
}
|
|
|
|
|
|
@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;
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -455,3 +728,15 @@ extension DPointExt on DPoint {
|
|
|
return this == empty;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+class MovablePointsInfo {
|
|
|
+ int index;
|
|
|
+ int start;
|
|
|
+ int end;
|
|
|
+
|
|
|
+ MovablePointsInfo(this.index, this.start, this.end);
|
|
|
+
|
|
|
+ factory MovablePointsInfo.empty() {
|
|
|
+ return MovablePointsInfo(-1, -1, -1);
|
|
|
+ }
|
|
|
+}
|