poyline.dart 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. import 'dart:ui';
  2. import 'package:fis_measure/interfaces/date_types/point.dart';
  3. import 'package:fis_measure/interfaces/enums/items.dart';
  4. import 'package:fis_measure/interfaces/process/items/item.dart';
  5. import 'package:fis_measure/interfaces/process/workspace/point_info.dart';
  6. import 'package:fis_measure/utils/canvas.dart';
  7. import 'package:path_drawing/path_drawing.dart';
  8. import '../calcuators/area.dart';
  9. import '../calcuators/perimeter.dart';
  10. import '../items/item.dart';
  11. import '../items/item_feature.dart';
  12. class PolyLine extends MeasureItem<PolyLineFeature> {
  13. final bool _initialClosed = false;
  14. PointInfo? _firstPoint;
  15. PolyLine(ItemMeta meta, IMeasureItem? parent) : super(meta, parent);
  16. @override
  17. bool onExecuteMouse(PointInfo args) {
  18. if (state == ItemStates.finished) {
  19. if (args.pointType == PointInfoType.mouseDown) {
  20. state = ItemStates.waiting;
  21. }
  22. }
  23. if (state == ItemStates.waiting) {
  24. if (args.pointType == PointInfoType.mouseDown) {
  25. handleMouseDownWhileWaiting(args);
  26. }
  27. } else if (state == ItemStates.running) {
  28. if (args.pointType == PointInfoType.mouseUp) return false;
  29. feature?.adopt(args);
  30. doCalculate();
  31. if (args.pointType == PointInfoType.mouseDown) {
  32. doFeatureFinish();
  33. } else {
  34. _checkAutoFinish(args);
  35. }
  36. }
  37. return true;
  38. }
  39. void _doFinish() {
  40. doFeatureFinish();
  41. _firstPoint = null;
  42. }
  43. void _checkAutoFinish(PointInfo current) {
  44. if (feature == null || feature!.innerPoints.length < 3) return;
  45. double autoSnapDistance = 0.01; //TODO: from config
  46. double autoSnapThreshold = 0.05;
  47. bool isAutoSnap = true; //TODO: from config
  48. if (isAutoSnap == false) return;
  49. // final viewport = feature!.hostVisualArea!.viewport!;
  50. var length = (feature!.firstPoint - current).length;
  51. if (length > autoSnapThreshold * 2.0 && !feature!.isSmartMove) {
  52. feature!.isSmartMove = true;
  53. }
  54. if (length < autoSnapThreshold && feature!.isSmartMove) {
  55. _doFinish();
  56. }
  57. // final logicStart = feature!.innerPoints.first;
  58. // final logicEnd = feature!.innerPoints.last;
  59. // // isSmartMove
  60. // if (logicEnd.almostEquals(logicStart, 0.01)) {
  61. // feature!.innerPoints.add(feature!.innerPoints.first); // 强制闭合
  62. // doFeatureFinish();
  63. // }
  64. }
  65. void handleMouseDownWhileWaiting(PointInfo args) {
  66. // TODO: 判断是否当前area
  67. // 转换为Area逻辑位置
  68. feature = PolyLineFeature(this);
  69. feature!.isClosed = _initialClosed;
  70. if (args.hostVisualArea != null) {
  71. feature!.hostVisualArea = args.hostVisualArea;
  72. }
  73. final point = args.toAreaLogicPoint();
  74. feature!.adopt(point);
  75. _firstPoint = args;
  76. state = ItemStates.running;
  77. }
  78. @override
  79. bool onExecuteTouch(PointInfo args) {
  80. return true;
  81. }
  82. /// 创建面积测量
  83. static PolyLine createArea(
  84. ItemMeta meta, [
  85. IMeasureItem? parent,
  86. ]) {
  87. PolyLine poyline = PolyLine(meta, parent);
  88. poyline.calculator = PolyLineAreaCal(poyline);
  89. return poyline;
  90. }
  91. /// 创建周长测量
  92. static PolyLine createPerimeter(
  93. ItemMeta meta, [
  94. IMeasureItem? parent,
  95. ]) {
  96. PolyLine poyline = PolyLine(meta, parent);
  97. poyline.calculator = PolyLinePerimeterCal(poyline);
  98. return poyline;
  99. }
  100. }
  101. class PolyLineFeature extends MeasureItemFeature {
  102. bool _isClosed = false;
  103. bool _isSmartMove = false;
  104. PolyLineFeature(IMeasureItem refItem) : super(refItem);
  105. /// 是否闭合?抄自超声机
  106. bool get isClosed => _isClosed;
  107. set isClosed(bool value) {
  108. if (value != _isClosed) {
  109. _isClosed = value;
  110. }
  111. }
  112. /// 是否启动智能定位
  113. bool get isSmartMove => _isSmartMove;
  114. set isSmartMove(bool value) {
  115. if (value != _isSmartMove) {
  116. _isSmartMove = value;
  117. }
  118. }
  119. /// 首节点
  120. DPoint get firstPoint => innerPoints.first;
  121. /// 接收新坐标
  122. void adopt(DPoint point) {
  123. innerPoints.add(point);
  124. }
  125. @override
  126. void paint(Canvas canvas, Size size) {
  127. if (innerPoints.isEmpty) return;
  128. // TODO: from style config
  129. const double vertexSize = 10;
  130. final points = innerPoints.map((e) => convert2ViewPoint(size, e)).toList();
  131. final startPoint = points.first;
  132. canvas.drawVertex(
  133. startPoint.toOffset(),
  134. vertexSize,
  135. active: points.length == 1,
  136. );
  137. if (points.length > 1) {
  138. final Path path = Path();
  139. path.moveTo(startPoint.x, startPoint.y);
  140. for (var i = 1; i < points.length; i++) {
  141. final point = points[i];
  142. path.lineTo(point.x, point.y);
  143. }
  144. path.lineTo(startPoint.x, startPoint.y);
  145. canvas.drawPath(
  146. dashPath(path, dashArray: CircularIntervalList([2.0, 10.0])),
  147. paintPan,
  148. );
  149. }
  150. canvas.drawVertex(points.last.toOffset(), vertexSize, active: isActive);
  151. }
  152. }