twoline_angle.dart 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. import 'dart:math';
  2. import 'dart:ui';
  3. import 'package:vector_math/vector_math.dart';
  4. import 'package:fis_measure/interfaces/date_types/point.dart';
  5. import 'package:fis_measure/interfaces/enums/items.dart';
  6. import 'package:fis_measure/interfaces/process/items/item_metas.dart';
  7. import 'package:fis_measure/interfaces/process/items/item.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/calculator.dart';
  11. import 'package:fis_measure/process/items/item.dart';
  12. import 'package:fis_measure/process/items/item_feature.dart';
  13. import 'package:fis_measure/utils/canvas.dart';
  14. /// 独立的两个线段确定一个角度
  15. class TwolineAngle extends MeasureItem<TwolineAngleFeature> {
  16. TwolineAngle(ItemMeta meta, IMeasureItem? parent) : super(meta, parent);
  17. static TwolineAngle createTwolineAngle(ItemMeta meta,
  18. [IMeasureItem? parent]) {
  19. TwolineAngle polygon = TwolineAngle(meta, parent);
  20. polygon.calculator = _AngleCalc(polygon);
  21. return polygon;
  22. }
  23. @override
  24. bool onExecuteMouse(PointInfo args) {
  25. if (state == ItemStates.finished) {
  26. if (args.pointType == PointInfoType.mouseDown) {
  27. state = ItemStates.waiting;
  28. }
  29. }
  30. if (state == ItemStates.waiting) {
  31. if (args.pointType == PointInfoType.mouseDown) {
  32. handleMouseDownWhileWaiting(args);
  33. }
  34. } else if (state == ItemStates.running) {
  35. if (feature == null) return false;
  36. if (args.pointType == PointInfoType.mouseUp) return false;
  37. final f = feature!;
  38. if (args.pointType == PointInfoType.mouseDown) {
  39. f.innerPoints.add(args);
  40. if (f.innerPoints.length == 5) {
  41. f.innerPoints.removeLast();
  42. doFeatureFinish();
  43. }
  44. } else {
  45. f.innerPoints.last = args;
  46. }
  47. doCalculate();
  48. }
  49. return true;
  50. }
  51. @override
  52. bool onExecuteTouch(PointInfo args) {
  53. // TODO: implement onExecuteTouch
  54. throw UnimplementedError();
  55. }
  56. void handleMouseDownWhileWaiting(PointInfo args) {
  57. // TODO: 判断是否当前area
  58. // 转换为Area逻辑位置
  59. final point = args.toAreaLogicPoint();
  60. feature = TwolineAngleFeature(this, point);
  61. if (args.hostVisualArea != null) {
  62. feature!.hostVisualArea = args.hostVisualArea;
  63. }
  64. state = ItemStates.running;
  65. }
  66. }
  67. class TwolineAngleFeature extends MeasureItemFeature {
  68. TwolineAngleFeature(IMeasureItem refItem, DPoint point) : super(refItem) {
  69. innerPoints.add(point.clone());
  70. innerPoints.add(point.clone());
  71. }
  72. @override
  73. void paint(Canvas canvas, Size size) {
  74. if (innerPoints.isEmpty) return;
  75. drawId(canvas, size);
  76. final innerOffsets =
  77. innerPoints.map((e) => convert2ViewPoint(size, e).toOffset()).toList();
  78. final len = innerOffsets.length;
  79. if (len == 2 || len == 3) {
  80. final a = innerOffsets[0];
  81. final b = innerOffsets[1];
  82. canvas.drawLine(a, b, paintLinePan);
  83. } else if (len >= 4) {
  84. final a = innerOffsets[0];
  85. final b = innerOffsets[1];
  86. final c = innerOffsets[2];
  87. final d = innerOffsets[3];
  88. canvas.drawLine(a, b, paintLinePan);
  89. canvas.drawLine(c, d, paintLinePan);
  90. //向量 A、B
  91. final vecA = Vector2(b.dx - a.dx, b.dy - a.dy);
  92. final vecB = Vector2(d.dx - c.dx, d.dy - c.dy);
  93. //计算向量夹角
  94. final angle = vecA.angleToSigned(vecB);
  95. //计算射线cd的角度
  96. final vecBAngle = vecB.angleToSigned(Vector2(1, 0));
  97. // 计算射线ab与射线cd的交点
  98. final p = _getIntersection(a, b, c, d);
  99. // 绘制角度
  100. canvas.drawArc(Rect.fromCircle(center: p, radius: 30), -vecBAngle, -angle,
  101. false, paintLinePan);
  102. //如果交点在线段外,线段要延长至交点
  103. Offset p1 = _getIntersection(a, b, p, Offset(0, p.dy));
  104. final vecA1 = Vector2(p1.dx - a.dx, p1.dy - a.dy).normalized() * 50;
  105. p1 += Offset(vecA1.x, vecA1.y);
  106. Offset p2 = _getIntersection(c, d, p, Offset(0, p.dy));
  107. final vecB1 = Vector2(p2.dx - c.dx, p2.dy - c.dy).normalized() * 50;
  108. p2 += Offset(vecB1.x, vecB1.y);
  109. canvas.drawLine(a, p1, paintLinePan);
  110. canvas.drawLine(c, p2, paintLinePan);
  111. }
  112. }
  113. /// 计算射线ab与射线cd的交点
  114. Offset _getIntersection(Offset a, Offset b, Offset c, Offset d) {
  115. final x1 = a.dx;
  116. final y1 = a.dy;
  117. final x2 = b.dx;
  118. final y2 = b.dy;
  119. final x3 = c.dx;
  120. final y3 = c.dy;
  121. final x4 = d.dx;
  122. final y4 = d.dy;
  123. final x =
  124. ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) /
  125. ((x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4));
  126. final y =
  127. ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) /
  128. ((x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4));
  129. return Offset(x, y);
  130. }
  131. }
  132. class _AngleCalc extends Calculator<TwolineAngle, double> {
  133. _AngleCalc(TwolineAngle ref) : super(ref);
  134. @override
  135. void calculate() {
  136. if (ref.feature == null) return;
  137. final feature = ref.feature!;
  138. final viewport = feature.hostVisualArea!.viewport!;
  139. final points = feature.innerPoints.map((e) => viewport.convert(e)).toList();
  140. feature.values.clear();
  141. double angle;
  142. if (points.length != 4) {
  143. angle = 0;
  144. } else {
  145. angle = calcAngle(points[0], points[1], points[2], points[3]);
  146. }
  147. for (var output in ref.meta.outputs) {
  148. if (output.name == MeasureTypes.Angle) {
  149. var value = roundDouble(angle, output.fractionalDigits);
  150. feature.updateFloatValue(output, value, output.unit);
  151. }
  152. }
  153. }
  154. static double calcAngle(
  155. DPoint pointsA, DPoint pointsB, DPoint pointsC, DPoint pointsD) {
  156. double finalAngleDegree = 0;
  157. //向量 A、B
  158. final vecA = Vector2(pointsB.x - pointsA.x, pointsB.y - pointsA.y);
  159. final vecB = Vector2(pointsD.x - pointsC.x, pointsD.y - pointsC.y);
  160. //计算向量夹角
  161. final angle = vecA.angleToSigned(vecB);
  162. //转换为角度
  163. finalAngleDegree = angle * 180 / pi;
  164. if (finalAngleDegree < 0) {
  165. finalAngleDegree = -finalAngleDegree;
  166. }
  167. return finalAngleDegree;
  168. }
  169. }