item_feature.dart 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. import 'package:fis_common/logger/logger.dart';
  2. import 'package:fis_measure/interfaces/date_types/point.dart';
  3. import 'package:fis_measure/interfaces/process/calculators/values.dart';
  4. import 'package:fis_measure/interfaces/process/items/item.dart';
  5. import 'package:fis_measure/interfaces/process/items/item_feature.dart';
  6. import 'package:fis_measure/interfaces/process/items/item_metas.dart';
  7. import 'package:fis_measure/interfaces/process/visuals/visual_area.dart';
  8. import 'package:fis_measure/process/workspace/measure_data_controller.dart';
  9. import 'package:fis_measure/utils/canvas.dart';
  10. import 'package:fis_measure/values/colors.dart';
  11. import 'package:flutter/widgets.dart';
  12. import 'package:get/get.dart';
  13. import 'package:vid/us/vid_us_unit.dart';
  14. import 'item.dart';
  15. abstract class MeasureItemFeature implements IMeasureItemFeature {
  16. late IMeasureItem _refItem;
  17. late List<DPoint> _innerPoints;
  18. late FeatureStyle _featureStyle;
  19. late String _measureModeName;
  20. IVisualArea? _hostVisualArea;
  21. bool _isActive = true;
  22. int _id = 0;
  23. List<ValueBase> _values = [];
  24. late final measureData = Get.find<MeasureDataController>();
  25. int _activeIndex = -1;
  26. Rect? zoomRect; // 当前缩放区域的归一化坐标
  27. bool? isURMDualImages; // 是否是URM 双幅图
  28. @override
  29. int? frameIndex;
  30. @override
  31. int? imageBelongSign;
  32. Paint get paintPan => measureData.paintPen;
  33. Paint get paintLinePan => measureData.paintLinePan;
  34. Paint get paintPointPan => measureData.paintPointPan;
  35. double get annotationFontSize =>
  36. measureData.measureSystemSetting.annotationFontSize.toDouble();
  37. MeasureItemFeature(IMeasureItem refItem) {
  38. _refItem = refItem;
  39. if (refItem.parent != null) {
  40. _id = refItem.parent!.feature?.id ?? 0;
  41. } else {
  42. _id = refItem.assignId();
  43. }
  44. _innerPoints = [];
  45. _measureModeName = "";
  46. _recordHistory();
  47. try {
  48. final measureData = Get.find<MeasureDataController>();
  49. _featureStyle = FeatureStyle(
  50. showBriefAnnotation:
  51. measureData.measureSystemSetting.showBriefAnnotation);
  52. } catch (e) {
  53. logger.e("Init meature item's feature style failed: $e");
  54. }
  55. }
  56. int get activeIndex => _activeIndex;
  57. set activeIndex(int val) {
  58. if (val != _activeIndex) {
  59. _activeIndex = val;
  60. }
  61. }
  62. @override
  63. FeatureStyle get featureStyle => _featureStyle;
  64. @override
  65. List<DPoint> get innerPoints => _innerPoints;
  66. @override
  67. MeasureItem get refItem => _refItem as MeasureItem;
  68. @override
  69. String get measureModeName => _measureModeName;
  70. /// 所在区域
  71. IVisualArea? get hostVisualArea => _hostVisualArea;
  72. set hostVisualArea(IVisualArea? value) {
  73. if (value != _hostVisualArea) {
  74. _hostVisualArea = value;
  75. }
  76. }
  77. @override
  78. bool get isActive => _isActive;
  79. set isActive(bool value) {
  80. if (value != _isActive) {
  81. _isActive = value;
  82. }
  83. }
  84. @override
  85. int get id => _id;
  86. /// 获取画布轨迹起点的角标文案,如果测量结果显示简洁注释,则会在轨迹起点显示简洁注释
  87. String get idText => _getIdText();
  88. String _getIdText() {
  89. if (featureStyle.showBriefAnnotation) {
  90. if (refItem.briefAnnotation.isNotEmpty) {
  91. return '$id.${refItem.briefAnnotation}';
  92. }
  93. }
  94. return '$id';
  95. }
  96. /// 顶点尺寸
  97. double get vertexSize =>
  98. measureData.measureSystemSetting.shapeCursorSize * refItem.scaleRatio;
  99. @override
  100. List<ValueBase> get values => _values;
  101. @override
  102. ValueBase? get value => _values.isNotEmpty ? _values.first : null;
  103. /// 更新浮点型结果值
  104. FloatValue? updateFloatValue(
  105. ItemOutputMeta outputMeta,
  106. double value,
  107. VidUsUnit unit,
  108. ) {
  109. int index = values.indexWhere((e) => e.meta.name == outputMeta.name);
  110. if (index < 0) {
  111. final floatValue = FloatValue(outputMeta, value, unit);
  112. values.add(floatValue);
  113. return floatValue;
  114. } else {
  115. ValueBase valueBase = values[index];
  116. if (valueBase is FloatValue) {
  117. final floatValue = valueBase;
  118. floatValue.value = value;
  119. return floatValue;
  120. } else {
  121. final newValue = FloatValue(outputMeta, value, unit);
  122. values[index] = newValue;
  123. return newValue;
  124. }
  125. }
  126. }
  127. void initValues() {
  128. _values = [];
  129. }
  130. /// 更新字符串结果值
  131. StringValue updateStringValue(
  132. ItemOutputMeta outputMeta,
  133. String value, [
  134. VidUsUnit unit = VidUsUnit.None,
  135. ]) {
  136. int index = values.indexWhere((e) => e.meta.name == outputMeta.name);
  137. if (index < 0) {
  138. final stringValue = StringValue(outputMeta, value, unit);
  139. values.add(stringValue);
  140. return stringValue;
  141. } else {
  142. ValueBase valueBase = values[index];
  143. if (valueBase is StringValue) {
  144. final floatValue = valueBase;
  145. floatValue.value = value;
  146. return floatValue;
  147. } else {
  148. final newValue = StringValue(outputMeta, value, unit);
  149. values[index] = newValue;
  150. return newValue;
  151. }
  152. }
  153. }
  154. @protected
  155. DPoint convert2ViewPoint(Size size, DPoint logicPoint) {
  156. if (zoomRect != null) {
  157. DPoint zoomedLogicPoint = getZoomedPoint(zoomRect!, logicPoint);
  158. final x = size.width * zoomedLogicPoint.x;
  159. final y = size.height * zoomedLogicPoint.y;
  160. return DPoint(x, y);
  161. }
  162. final x = size.width * logicPoint.x;
  163. final y = size.height * logicPoint.y;
  164. return DPoint(x, y);
  165. }
  166. // 获取点 p 在 Rect r 中的归一化坐标
  167. DPoint getZoomedPoint(Rect r, DPoint p) {
  168. double xPctInR = (p.x - r.left) / r.width;
  169. double yPctInR = (p.y - r.top) / r.height;
  170. return DPoint(xPctInR, yPctInR);
  171. }
  172. @override
  173. void setZoomRect(Rect? rect) {
  174. zoomRect = rect;
  175. }
  176. @override
  177. void setURMDualImages(bool? isURMDual) {
  178. isURMDualImages = isURMDual;
  179. }
  180. @override
  181. void paintPerfusion(
  182. Canvas canvas,
  183. Size size,
  184. ) {}
  185. /// 画序号
  186. ///
  187. /// [text] 自定义序号内容
  188. @protected
  189. void drawId(Canvas canvas, Size size, [String? text]) {
  190. final String displayText;
  191. if (refItem.parent == null) {
  192. displayText = text ?? id.toString();
  193. } else {
  194. displayText = '$id.${refItem.description}';
  195. }
  196. final point = innerPoints[0];
  197. var offset = convert2ViewPoint(size, point).toOffset();
  198. return drawCustomId(canvas, size, offset, displayText);
  199. }
  200. /// 画自定义位置的序号
  201. /// [offset] 位置
  202. /// [text] 自定义序号内容
  203. @protected
  204. void drawCustomId(Canvas canvas, Size size, Offset offset, [String? text]) {
  205. final displayText = text ?? id.toString();
  206. final fontSize = annotationFontSize * refItem.scaleRatio;
  207. final fontOffsetY = 4.0 * refItem.scaleRatio;
  208. final letterSpacing = 0.0 * refItem.scaleRatio;
  209. final style = TextStyle(
  210. fontSize: fontSize,
  211. color: MeasureColors.Primary,
  212. // fontWeight: FontWeight.bold,
  213. letterSpacing: letterSpacing,
  214. );
  215. final fontPlace = boundingTextSize(displayText, style);
  216. double transY = 0;
  217. double transX = 0;
  218. final vertexOffsetW = vertexSize / 2;
  219. if (offset.dx < fontPlace.width) {
  220. transX = fontSize + vertexOffsetW;
  221. } else {
  222. transX = -fontPlace.width - vertexOffsetW;
  223. }
  224. if (offset.dy < fontPlace.height + fontOffsetY) {
  225. transY = fontOffsetY;
  226. } else {
  227. transY = -fontPlace.height - fontOffsetY;
  228. }
  229. offset = offset.translate(transX, transY);
  230. canvas.drawText(
  231. displayText,
  232. offset,
  233. style: style,
  234. );
  235. }
  236. /// 画顶点
  237. void drawVertex(Canvas canvas, Offset offset, [bool active = false]) {
  238. canvas.drawVertex(offset, vertexSize, active: active);
  239. }
  240. /// 画小顶点(1/2 大小)由 measureData.measureSystemSetting.minCursorDistance 来控制是否触发
  241. void drawMiniVertex(Canvas canvas, Offset offset, [bool active = false]) {
  242. canvas.drawVertex(offset, vertexSize / 2, active: active);
  243. }
  244. /// 画顶点
  245. void drawCrossVertex(Canvas canvas, Offset offset, [bool active = false]) {
  246. canvas.drawCrossVertex(offset, vertexSize, active: active);
  247. }
  248. /// 画短横标记
  249. void drawMark(Canvas canvas, Offset offset,
  250. [bool active = false, bool ifHorizontal = true]) {
  251. canvas.drawMark(offset, vertexSize,
  252. active: active, ifHorizontal: ifHorizontal);
  253. }
  254. /// 计算文本长度
  255. static Size boundingTextSize(
  256. String text,
  257. TextStyle style, {
  258. int maxLines = 2 ^ 31,
  259. double maxWidth = double.infinity,
  260. }) {
  261. // if (Get.context == null) return Size.zero;
  262. if (text.isEmpty) return Size.zero;
  263. final TextPainter textPainter = TextPainter(
  264. textDirection: TextDirection.ltr,
  265. // locale: Localizations.localeOf(Get.context!),
  266. text: TextSpan(text: text, style: style),
  267. maxLines: maxLines,
  268. )..layout(maxWidth: maxWidth);
  269. return textPainter.size;
  270. }
  271. void _recordHistory() {
  272. if (refItem.parent == null) {
  273. final recorder = refItem.application.recorder;
  274. recorder.recordMeasureItem(refItem.meta.name);
  275. _measureModeName = refItem.application.currentMode.modeType.name;
  276. }
  277. }
  278. @override
  279. bool checkCanPaint() {
  280. if (refItem is ITopMeasureItem) {
  281. return true;
  282. }
  283. bool result = true;
  284. final app = refItem.application;
  285. if (app.crossFrameContext != null && !app.crossFrameContext!.isOver) {
  286. final imgSign = app.crossFrameContext!.currentUrl.hashCode;
  287. final frameIndex = app.frameData!.index;
  288. result = result && checkFeatureCanPaintInCrossFrame(imgSign, frameIndex);
  289. }
  290. return result;
  291. }
  292. /// 判断跨帧状态中Future是否可绘制
  293. bool checkFeatureCanPaintInCrossFrame(
  294. int imgSign,
  295. int index,
  296. ) {
  297. if (imageBelongSign != null && imageBelongSign != imgSign) {
  298. return false;
  299. }
  300. if (frameIndex != null && frameIndex != index) {
  301. return false;
  302. }
  303. return true;
  304. }
  305. }