simpson_path.dart 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742
  1. import 'dart:ui';
  2. import 'dart:math' as math;
  3. import 'package:fis_measure/interfaces/date_types/point.dart';
  4. import 'package:fis_measure/interfaces/date_types/vector.dart';
  5. import 'package:fis_measure/interfaces/enums/items.dart';
  6. import 'package:fis_measure/interfaces/process/items/item.dart';
  7. import 'package:fis_measure/interfaces/process/items/item_metas.dart';
  8. import 'package:fis_measure/interfaces/process/items/types.dart';
  9. import 'package:fis_measure/interfaces/process/workspace/point_info.dart';
  10. import 'package:fis_measure/process/calcuators/curve.dart';
  11. import 'package:fis_measure/process/calcuators/formulas/general.dart';
  12. import 'package:fis_measure/process/items/item.dart';
  13. import 'package:fis_measure/process/items/item_feature.dart';
  14. import 'package:fis_measure/process/primitives/polyline.dart';
  15. import 'package:fis_measure/process/primitives/area_abstract.dart';
  16. import 'package:fis_measure/process/primitives/utils/auto_snap.dart';
  17. import 'package:fis_measure/utils/canvas.dart';
  18. import 'package:flutter/foundation.dart';
  19. import 'package:flutter/rendering.dart';
  20. import 'package:path_drawing/path_drawing.dart';
  21. import 'spline.dart';
  22. import 'utils/line.dart';
  23. import 'utils/spline.dart';
  24. enum LvSimpsonStep {
  25. none,
  26. splineBeginEdit,
  27. splineEditing,
  28. splineEndEdit,
  29. splineCompleted,
  30. done,
  31. }
  32. class SimpsonPath extends AreaItemAbstract with AutoSnapMixin {
  33. static const int splitterCount = 20;
  34. static const double maxPointsCount = 10000;
  35. SimpsonPath(ItemMeta meta, IMeasureItem? parent) : super(meta, parent);
  36. PointInfo? firstPoint;
  37. @protected
  38. LvSimpsonStep lvSimpsonStep = LvSimpsonStep.none;
  39. @override
  40. SimpsonPathFeature? get feature => super.feature as SimpsonPathFeature;
  41. @override
  42. bool onExecuteMouse(PointInfo args) {
  43. if (state == ItemStates.finished) {
  44. if (args.pointType == PointInfoType.mouseDown) {
  45. state = ItemStates.waiting;
  46. lvSimpsonStep = LvSimpsonStep.none;
  47. }
  48. }
  49. if (state == ItemStates.waiting) {
  50. if (args.pointType == PointInfoType.mouseDown) {
  51. handleMouseDownWhileWaiting(args);
  52. }
  53. } else if (state == ItemStates.running) {
  54. switch (args.pointType) {
  55. case PointInfoType.mouseUp:
  56. return false;
  57. case PointInfoType.mouseDown:
  58. if (lvSimpsonStep == LvSimpsonStep.splineCompleted) {
  59. feature!.adjustEndPoint(args.toAreaLogicPoint());
  60. lvSimpsonStep = LvSimpsonStep.done;
  61. // CaliperExtension.ShowCaliper();
  62. } else {
  63. final lineLen = (args - firstPoint!).length;
  64. if ((feature!.innerPoints.length > 3 &&
  65. GeneralFormulas.doubleAlmostEquals(lineLen, 0)) ||
  66. feature!.innerPoints.length >= maxPointsCount) {
  67. lvSimpsonStep = LvSimpsonStep.splineCompleted;
  68. feature!.fixedSpline();
  69. } else {
  70. feature!.adopt(args.toAreaLogicPoint());
  71. }
  72. }
  73. break;
  74. case PointInfoType.mouseMove:
  75. if (lvSimpsonStep == LvSimpsonStep.splineCompleted) {
  76. feature!.adjustEndPoint(args.toAreaLogicPoint());
  77. } else {
  78. if (!snapState) {
  79. checkAutoSnap(args, false);
  80. }
  81. if (!snapState) {
  82. feature!.updateActivePoint(args.toAreaLogicPoint());
  83. }
  84. }
  85. break;
  86. default:
  87. break;
  88. }
  89. }
  90. doCalculate();
  91. if (args.pointType == PointInfoType.mouseDown) {
  92. // doFeatureFinish();
  93. if (state == ItemStates.waiting || state == ItemStates.finished) {
  94. state = ItemStates.running;
  95. }
  96. if (state == ItemStates.running) {
  97. updateStatus();
  98. }
  99. }
  100. if (args.pointType == PointInfoType.mouseMove) {
  101. updateStatus();
  102. }
  103. return true;
  104. }
  105. @override
  106. bool onExecuteTouch(PointInfo args) {
  107. // TODO: implement onExecuteTouch
  108. throw UnimplementedError();
  109. }
  110. void handleMouseDownWhileWaiting(PointInfo args) {
  111. // TODO: 判断是否当前area
  112. // 转换为Area逻辑位置
  113. feature = SimpsonPathFeature(this);
  114. if (args.hostVisualArea != null) {
  115. feature!.hostVisualArea = args.hostVisualArea;
  116. }
  117. final point = args.toAreaLogicPoint();
  118. feature!.adopt(point);
  119. feature!.adopt(point);
  120. state = ItemStates.running;
  121. firstPoint = args;
  122. }
  123. void updateStatus() {
  124. switch (lvSimpsonStep) {
  125. case LvSimpsonStep.splineCompleted:
  126. firstPoint = null;
  127. if (feature != null) {
  128. feature!.activeIndex = feature!.innerPoints.length;
  129. }
  130. break;
  131. case LvSimpsonStep.done:
  132. state = ItemStates.finished;
  133. if (feature != null) {
  134. feature!.activeIndex = -1;
  135. }
  136. break;
  137. default:
  138. break;
  139. }
  140. }
  141. static SimpsonPath create(ItemMeta meta, [IMeasureItem? parent]) {
  142. final path = SimpsonPath(meta, parent);
  143. return path;
  144. }
  145. }
  146. class SimpsonPathFeature extends AreaItemFeatureAbstract {
  147. static const autoGetApexPoint = false; // TODO
  148. late Map<int, double> horizontalSplitterLegths;
  149. late DPoint moveBasedPoint;
  150. IPathGeometry? _pathGeometry;
  151. List<DPoint>? _splinePoints;
  152. IPathGeometry? _spline;
  153. late DPoint _centerLineFixedPoint;
  154. late DPoint _centerLineMovablePoint;
  155. late MovablePointsInfo _movablePtsInfo;
  156. late DPoint _leftPoint;
  157. late DPoint _rightPoint;
  158. late DPoint _apexPoint;
  159. SimpsonPathFeature(AreaItemAbstract refItem) : super(refItem) {
  160. _splinePoints = [];
  161. _centerLineFixedPoint = DPointExt.empty;
  162. _centerLineMovablePoint = DPointExt.empty;
  163. _movablePtsInfo = MovablePointsInfo.empty();
  164. _leftPoint = DPointExt.empty;
  165. _rightPoint = DPointExt.empty;
  166. _apexPoint = DPointExt.empty;
  167. moveBasedPoint = DPointExt.empty;
  168. horizontalSplitterLegths = {};
  169. }
  170. @override
  171. SimpsonPath get refItem => super.refItem as SimpsonPath;
  172. DPoint get centerLineMovablePoint => _centerLineMovablePoint;
  173. set centerLineMovablePoint(DPoint val) {
  174. if (val != _centerLineMovablePoint) {
  175. _centerLineMovablePoint = val;
  176. updateSplitters();
  177. _onVertexPointChanged();
  178. }
  179. }
  180. DPoint get centerLineFixedPoint => _centerLineFixedPoint;
  181. MovablePointsInfo get movablePtsInfo => _movablePtsInfo;
  182. set movablePtsInfo(MovablePointsInfo val) {
  183. if (val != _movablePtsInfo) {
  184. _movablePtsInfo = val;
  185. _onSplineMovablePointsInfoChanged();
  186. }
  187. }
  188. DPoint get leftPoint => _leftPoint;
  189. set leftPoint(DPoint val) {
  190. if (val != _leftPoint) {
  191. _leftPoint = val;
  192. _onVertexPointChanged();
  193. }
  194. }
  195. DPoint get rightPoint => _rightPoint;
  196. set rightPoint(DPoint val) {
  197. if (val != _rightPoint) {
  198. _rightPoint = val;
  199. _onVertexPointChanged();
  200. }
  201. }
  202. DPoint get apexPoint => _apexPoint;
  203. set apexPoint(DPoint val) {
  204. if (val != _apexPoint) {
  205. _apexPoint = val;
  206. _onVertexPointChanged();
  207. }
  208. }
  209. double get centerLineLength {
  210. final viewport = hostVisualArea!.viewport!;
  211. final p1 = viewport.convert(_centerLineFixedPoint);
  212. final p2 = viewport.convert(_centerLineMovablePoint);
  213. final value = (p2 - p1).length.abs();
  214. return value;
  215. }
  216. double get area {
  217. final viewport = hostVisualArea!.viewport!;
  218. final points = innerPoints.map((e) => viewport.convert(e)).toList();
  219. final value = AreaPerimeterCal.calcArea(points);
  220. return value;
  221. }
  222. bool isClosed = false; // TODO
  223. @override
  224. void paint(Canvas canvas, Size size) {
  225. if (innerPoints.isEmpty) return;
  226. drawId(canvas, size);
  227. final points = innerPoints.map((e) => convert2ViewPoint(size, e)).toList();
  228. final startPoint = points.first;
  229. drawVertex(canvas, startPoint.toOffset(), points.length == 1);
  230. // if (points.length > 1) {
  231. // final Path path = Path();
  232. // path.moveTo(startPoint.x, startPoint.y);
  233. // for (var i = 1; i < points.length; i++) {
  234. // final point = points[i];
  235. // path.lineTo(point.x, point.y);
  236. // }
  237. // if (isClosed) {
  238. // path.lineTo(startPoint.x, startPoint.y);
  239. // }
  240. // canvas.drawPath(
  241. // path,
  242. // paintLinePan,
  243. // );
  244. // }
  245. if (_pathGeometry != null) {
  246. final geometry = _pathGeometry as PathGeometryContainer;
  247. for (var fragment in geometry.geometries) {
  248. final path = Path();
  249. if (fragment is PathGeometry) {
  250. for (var i = 0; i < fragment.points.length; i++) {
  251. final point = convert2ViewPoint(size, fragment.points[i]);
  252. if (i == 0) {
  253. path.moveTo(point.x, point.y);
  254. } else {
  255. path.lineTo(point.x, point.y);
  256. }
  257. }
  258. } else if (fragment is LineGeometry) {
  259. DPoint point;
  260. point = convert2ViewPoint(size, fragment.start);
  261. path.moveTo(point.x, point.y);
  262. point = convert2ViewPoint(size, fragment.end);
  263. path.lineTo(point.x, point.y);
  264. }
  265. canvas.drawPath(path, paintLinePan);
  266. }
  267. }
  268. drawVertex(canvas, points.last.toOffset(), isActive);
  269. }
  270. @override
  271. void adopt(DPoint point) {
  272. super.adopt(point);
  273. recreateSpline(false);
  274. }
  275. void updateActivePoint(DPoint point) {
  276. if (activeIndex > 0 && activeIndex <= innerPoints.length) {
  277. activePoint = point;
  278. recreateSpline(false);
  279. }
  280. }
  281. DPoint get activePoint {
  282. if (activeIndex < 0 || activeIndex >= innerPoints.length) {
  283. throw IndexError.withLength(activeIndex, innerPoints.length);
  284. }
  285. return innerPoints[activeIndex];
  286. }
  287. set activePoint(DPoint val) {
  288. if (activeIndex < 0 || activeIndex >= innerPoints.length) {
  289. throw IndexError.withLength(activeIndex, innerPoints.length);
  290. }
  291. innerPoints[activeIndex] = val;
  292. }
  293. void fixedSpline() {
  294. if (innerPoints.isEmpty) {
  295. return;
  296. }
  297. _centerLineFixedPoint = DPoint(
  298. (innerPoints.last.x + innerPoints.first.x) * 0.5,
  299. (innerPoints.last.y + innerPoints.first.y) * 0.5,
  300. );
  301. var movablePoint = DPoint(0, double.infinity);
  302. var isFindMin =
  303. innerPoints[innerPoints.length >> 1].y - innerPoints[0].y < 0;
  304. if (autoGetApexPoint) {
  305. movablePoint =
  306. isFindMin ? movablePoint : DPoint(0, double.negativeInfinity);
  307. }
  308. for (DPoint point in innerPoints) {
  309. if (autoGetApexPoint && innerPoints.isNotEmpty) {
  310. if (isFindMin) {
  311. if (point.y < movablePoint.y) {
  312. movablePoint = point;
  313. }
  314. } else {
  315. if (point.y > movablePoint.y) {
  316. movablePoint = point;
  317. }
  318. }
  319. } else {
  320. if (point.y < movablePoint.y) {
  321. movablePoint = point;
  322. }
  323. }
  324. }
  325. if (_centerLineMovablePoint != movablePoint) {
  326. _centerLineMovablePoint = movablePoint;
  327. if (!_centerLineMovablePoint.isEmpty) {
  328. // TODO 重设光标位置,暂不支持
  329. // _centerLineMovablePoint.SynchToMainMonitorScreen(HostArea);
  330. }
  331. }
  332. updateSplitters();
  333. _onVertexPointChanged();
  334. }
  335. void adjustEndPoint(DPoint point) {
  336. if (innerPoints.isEmpty) {
  337. return;
  338. }
  339. var endPoint = point;
  340. double minDistance = double.infinity;
  341. if (_splinePoints != null) {
  342. for (DPoint splinePoint in _splinePoints!) {
  343. double distance = (point - splinePoint).length;
  344. if (distance < minDistance) {
  345. minDistance = distance;
  346. endPoint = splinePoint;
  347. }
  348. }
  349. }
  350. centerLineMovablePoint = endPoint;
  351. }
  352. void recreateSpline(bool isClosed) {
  353. // if (_breaker.Paused) {
  354. // return;
  355. // }
  356. final generator = SimpsonGeometryGenerator();
  357. _pathGeometry ??= generator.createPathGeometry();
  358. double tempCircumference = 0;
  359. _spline = generator.createSpline(
  360. innerPoints,
  361. 0.5,
  362. null,
  363. isClosed,
  364. false,
  365. 0.005,
  366. tempCircumference,
  367. _splinePoints,
  368. );
  369. if (_spline != null && _splinePoints != null) {
  370. _pathGeometry!.addGeometry(_spline!);
  371. }
  372. }
  373. void updateSplitters() {
  374. recreateSpline(true);
  375. if (_spline != null && !_centerLineMovablePoint.isEmpty) {
  376. var generator = SimpsonGeometryGenerator();
  377. _pathGeometry!.clear();
  378. if (innerPoints.isNotEmpty) {
  379. _pathGeometry!.addGeometry(_spline!);
  380. horizontalSplitterLegths = {};
  381. generator.createSplitters(
  382. _pathGeometry!,
  383. _spline!,
  384. _centerLineFixedPoint,
  385. _centerLineMovablePoint,
  386. horizontalSplitterLegths,
  387. );
  388. _pathGeometry!.addLineGeometry(
  389. _centerLineFixedPoint,
  390. _centerLineMovablePoint,
  391. );
  392. }
  393. }
  394. }
  395. void _onVertexPointChanged() {}
  396. void _onSplineMovablePointsInfoChanged() {}
  397. }
  398. class SimpsonGeometryGenerator {
  399. static const int splitterCount = 20;
  400. void createSplitters(
  401. IPathGeometry pathGeometry,
  402. IPathGeometry spline,
  403. DPoint centerLineFixedPoint,
  404. DPoint centerLineMovablePoint,
  405. Map<int, double> horizontalSplitterLegths,
  406. ) {
  407. if (centerLineFixedPoint.isEmpty || centerLineMovablePoint.isEmpty) {
  408. return;
  409. }
  410. // Center line
  411. DVector centerLine = centerLineMovablePoint - centerLineFixedPoint;
  412. var horizontalStart = DPoint(-50, centerLineFixedPoint.y);
  413. // horizonta line
  414. DVector horizontalLine = horizontalStart - centerLineFixedPoint;
  415. // Get angle between horizontal and center line
  416. double angle = DVector.angleBetween(horizontalLine, centerLine);
  417. double angleToVertical = 90.0 - angle;
  418. double cellHeight = centerLine.length / splitterCount;
  419. //Create a 20 splitters path geometry
  420. PathGeometryContainer temSplittersGeometry = PathGeometryContainer(Path());
  421. for (int i = 1; i <= splitterCount; i++) {
  422. double midPointY =
  423. centerLineFixedPoint.y - cellHeight * (i - 1) - cellHeight / 2;
  424. //horizontal splitter line
  425. DPoint p1 = DPoint(-50, midPointY);
  426. DPoint p2 = DPoint(50, midPointY);
  427. final lineGeometry = LineGeometry(p1, p2);
  428. lineGeometry.rotateTransform(
  429. angle,
  430. centerLineFixedPoint.x,
  431. centerLineFixedPoint.y,
  432. );
  433. temSplittersGeometry.addGeometry(lineGeometry);
  434. }
  435. //Get intersection points
  436. List<DPoint> points = getIntersectionPoints(temSplittersGeometry, spline);
  437. List<DPoint> leftPoints = [];
  438. List<DPoint> rightPoints = [];
  439. //Split point by center line
  440. const double constMagnify = 1000.0;
  441. for (DPoint point in points) {
  442. var magnifyPoint = point;
  443. magnifyPoint.x *= constMagnify;
  444. magnifyPoint.y *= constMagnify;
  445. DVector line = magnifyPoint -
  446. DPoint(
  447. (centerLineFixedPoint.x + centerLineMovablePoint.x) /
  448. 2.0 *
  449. constMagnify,
  450. (centerLineFixedPoint.y + centerLineMovablePoint.y) /
  451. 2.0 *
  452. constMagnify,
  453. );
  454. double angleToCenter = DVector.angleBetween(line, centerLine);
  455. if (angleToCenter >= 0.0) {
  456. leftPoints.add(point);
  457. } else {
  458. rightPoints.add(point);
  459. }
  460. //order point by vertical axis value
  461. orderByCalc(DPoint point) => rotaeY(
  462. point,
  463. centerLineFixedPoint,
  464. angleToVertical * math.pi / 180.0,
  465. );
  466. leftPoints.sort((a, b) {
  467. final vA = orderByCalc(a);
  468. final vB = orderByCalc(b);
  469. return vA.compareTo(vB);
  470. });
  471. rightPoints.sort((a, b) {
  472. final vA = orderByCalc(a);
  473. final vB = orderByCalc(b);
  474. return vA.compareTo(vB);
  475. });
  476. var finalLeftPoint = leftPoints;
  477. var finalRightPoint = rightPoints;
  478. if (finalLeftPoint.length == finalRightPoint.length &&
  479. finalLeftPoint.length == splitterCount) {
  480. for (int i = 0; i < splitterCount; i++) {
  481. horizontalSplitterLegths[i + 1] =
  482. (finalLeftPoint[i] - finalRightPoint[i]).length;
  483. pathGeometry.addLineGeometry(finalLeftPoint[i], finalRightPoint[i]);
  484. }
  485. }
  486. }
  487. }
  488. IPathGeometry? createSpline(
  489. List<DPoint> sourcePoints,
  490. double tension,
  491. List<double>? tensions,
  492. bool isClosed,
  493. bool isFilled,
  494. double tolerance,
  495. double length,
  496. List<DPoint>? splinePoints,
  497. ) {
  498. length = 0;
  499. if (sourcePoints.isEmpty) {
  500. return null;
  501. }
  502. List<DPoint> samplePoints = [];
  503. var points = SplineUtils.create(
  504. sourcePoints,
  505. tension: tension,
  506. tensions: tensions,
  507. isClosed: isClosed,
  508. tolerance: tolerance,
  509. closeByStraightLine: true,
  510. samplePoints: samplePoints,
  511. isSimpsonSpline: true,
  512. );
  513. // var myPoints = GeomTools.ToWindowPoints(points.ToArray());
  514. // var polyLineSegment = new PolyLineSegment { Points = new PointCollection(myPoints) };
  515. // var pathFigure = new PathFigure { IsClosed = isClosed, IsFilled = true, StartPoint = sourcePoints[0].ToWindowPoint() };
  516. // pathFigure.Segments.Add(polyLineSegment);
  517. // pathGeometry.Figures.Add(pathFigure);
  518. splinePoints = points;
  519. final pathGeometry = PathGeometry(points);
  520. final continer = PathGeometryContainer(Path());
  521. continer.addGeometry(pathGeometry);
  522. return continer;
  523. }
  524. IPathGeometry createPathGeometry() {
  525. return PathGeometryContainer(Path());
  526. }
  527. static double rotaeY(DPoint point, DPoint cenPoint, double theta) {
  528. return math.sin(theta) * (point.x - cenPoint.x) +
  529. math.cos(theta) * (point.y - cenPoint.y) +
  530. cenPoint.y;
  531. }
  532. List<DPoint> getIntersectionPoints(IPathGeometry g1, IPathGeometry g2) {
  533. final result = <DPoint>[];
  534. final splittersGeometry = g1 as PathGeometryContainer;
  535. final splineGeometry = g2 as PathGeometry;
  536. for (var splitter in splittersGeometry.geometries) {
  537. splitter as LineGeometry;
  538. DPoint lastPoint = splineGeometry.points.first;
  539. final endLimit = splineGeometry.points.length - 1;
  540. for (var i = 1; i < splineGeometry.points.length; i++) {
  541. final point = splineGeometry.points[i];
  542. final intersection = LineUtils.calculateIntersection(
  543. splitter.start, splitter.end, lastPoint, point);
  544. if (intersection != null) {
  545. result.add(intersection);
  546. }
  547. if (i != endLimit) {
  548. lastPoint = point;
  549. }
  550. }
  551. }
  552. return result;
  553. }
  554. }
  555. class PathGeometryContainer implements IPathGeometry {
  556. final geometries = <IPathGeometry>[];
  557. late final Path control;
  558. PathGeometryContainer(Path geometry) {
  559. control = geometry;
  560. }
  561. @override
  562. void addGeometry(IPathGeometry geometry) {
  563. geometries.add(geometry);
  564. }
  565. @override
  566. void clear() {
  567. geometries.clear();
  568. }
  569. @override
  570. void addLineGeometry(
  571. DPoint centerLineFixedPoint, DPoint centerLineMovablePoint) {
  572. // final linePath = Path()
  573. // ..moveTo(centerLineFixedPoint.x, centerLineFixedPoint.y)
  574. // ..lineTo(centerLineMovablePoint.x, centerLineMovablePoint.y);
  575. addGeometry(LineGeometry(centerLineFixedPoint, centerLineMovablePoint));
  576. }
  577. }
  578. class PathGeometry implements IPathGeometry {
  579. final List<DPoint> points;
  580. PathGeometry(this.points);
  581. @override
  582. void addGeometry(IPathGeometry spline) {}
  583. @override
  584. void addLineGeometry(
  585. DPoint centerLineFixedPoint, DPoint centerLineMovablePoint) {}
  586. @override
  587. void clear() {}
  588. }
  589. class LineGeometry implements IPathGeometry {
  590. final DPoint start;
  591. final DPoint end;
  592. LineGeometry(this.start, this.end);
  593. @override
  594. void addGeometry(IPathGeometry spline) {}
  595. @override
  596. void addLineGeometry(
  597. DPoint centerLineFixedPoint, DPoint centerLineMovablePoint) {}
  598. @override
  599. void clear() {}
  600. void rotateTransform(double angle, double centerX, double centerY) {
  601. rotatePoint(start, centerX, centerY, angle);
  602. rotatePoint(end, centerX, centerY, angle);
  603. }
  604. static void rotatePoint(
  605. DPoint point,
  606. double centerX,
  607. double centerY,
  608. double angle,
  609. ) {
  610. double radians = angle * math.pi / 180;
  611. double cosTheta = math.cos(radians);
  612. double sinTheta = math.sin(radians);
  613. point.x = centerX +
  614. (point.x - centerX) * cosTheta -
  615. (point.y - centerY) * sinTheta;
  616. point.y = centerY +
  617. (point.x - centerX) * sinTheta +
  618. (point.y - centerY) * cosTheta;
  619. }
  620. }
  621. abstract class IPathGeometry {
  622. void clear();
  623. void addGeometry(IPathGeometry spline);
  624. void addLineGeometry(
  625. DPoint centerLineFixedPoint, DPoint centerLineMovablePoint);
  626. }
  627. extension DPointExt on DPoint {
  628. static final empty = DPoint(double.minPositive, double.minPositive);
  629. bool get isEmpty {
  630. return this == empty;
  631. }
  632. }
  633. class MovablePointsInfo {
  634. int index;
  635. int start;
  636. int end;
  637. MovablePointsInfo(this.index, this.start, this.end);
  638. factory MovablePointsInfo.empty() {
  639. return MovablePointsInfo(-1, -1, -1);
  640. }
  641. }