import 'package:fis_measure/interfaces/date_types/point.dart'; import 'package:fis_measure/interfaces/process/calculators/values.dart'; import 'package:fis_measure/interfaces/process/items/item.dart'; import 'package:fis_measure/interfaces/process/items/item_feature.dart'; import 'package:fis_measure/interfaces/process/items/item_metas.dart'; import 'package:fis_measure/interfaces/process/visuals/visual_area.dart'; import 'package:fis_measure/utils/canvas.dart'; import 'package:fis_measure/values/colors.dart'; import 'package:flutter/widgets.dart'; import 'package:get/get.dart'; import 'package:vid/us/vid_us_unit.dart'; import 'item.dart'; abstract class MeasureItemFeature implements IMeasureItemFeature { late IMeasureItem _refItem; late List _innerPoints; IVisualArea? _hostVisualArea; bool _isActive = true; int _id = 0; final List _values = []; int _activeIndex = -1; @protected final paintPan = Paint() ..color = const Color.fromARGB(255, 255, 255, 0) ..isAntiAlias = true ..strokeWidth = 2 ..style = PaintingStyle.stroke; MeasureItemFeature(IMeasureItem refItem) { _refItem = refItem; if (refItem.parent != null) { _id = refItem.parent!.feature?.id ?? 0; } else { _id = refItem.assignId(); } _innerPoints = []; _recordHistory(); } int get activeIndex => _activeIndex; set activeIndex(int val) { if (val != _activeIndex) { _activeIndex = val; } } @override List get innerPoints => _innerPoints; @override MeasureItem get refItem => _refItem as MeasureItem; /// 所在区域 IVisualArea? get hostVisualArea => _hostVisualArea; set hostVisualArea(IVisualArea? value) { if (value != _hostVisualArea) { _hostVisualArea = value; } } @override bool get isActive => _isActive; set isActive(bool value) { if (value != _isActive) { _isActive = value; } } @override int get id => _id; /// 顶点尺寸 double get vertexSize => 10.0 * refItem.scaleRatio; @override List get values => _values; @override ValueBase? get value => _values.isNotEmpty ? _values.first : null; /// 更新浮点型结果值 FloatValue? updateFloatValue( ItemOutputMeta outputMeta, double value, VidUsUnit unit, ) { final valueBase = values.firstWhereOrNull((e) => e.meta.name == outputMeta.name); if (valueBase == null) { final floatValue = FloatValue(outputMeta, value, unit); values.add(floatValue); return floatValue; } else { final floatValue = valueBase as FloatValue; floatValue.value = value; floatValue.unit = unit; return floatValue; } } /// 更新字符串结果值 StringValue updateStringValue( ItemOutputMeta outputMeta, String value, [ VidUsUnit unit = VidUsUnit.None, ]) { final valueBase = values.firstWhereOrNull((e) => e.name == outputMeta.name); if (valueBase == null) { final stringValue = StringValue(outputMeta, value, unit); values.add(stringValue); return stringValue; } else { final stringValue = valueBase as StringValue; stringValue.value = value; stringValue.unit = unit; return stringValue; } } @protected DPoint convert2ViewPoint(Size size, DPoint logicPoint) { final x = size.width * logicPoint.x; final y = size.height * logicPoint.y; return DPoint(x, y); } /// 画序号 /// /// [text] 自定义序号内容 @protected void drawId(Canvas canvas, Size size, [String? text]) { final String displayText; if (refItem.parent == null) { displayText = text ?? id.toString(); } else { displayText = '$id.${refItem.description}'; } final point = innerPoints[0]; var offset = convert2ViewPoint(size, point).toOffset(); return drawCustomId(canvas, size, offset, displayText); } /// 画自定义位置的序号 /// [offset] 位置 /// [text] 自定义序号内容 @protected void drawCustomId(Canvas canvas, Size size, Offset offset, [String? text]) { final displayText = text ?? id.toString(); final fontSize = 14.0 * refItem.scaleRatio; // TODO: from config final fontOffsetY = 4.0 * refItem.scaleRatio; final letterSpacing = 0.0 * refItem.scaleRatio; final style = TextStyle( fontSize: fontSize, color: MeasureColors.Primary, // fontWeight: FontWeight.bold, letterSpacing: letterSpacing, ); final fontPlace = boundingTextSize(displayText, style); double transY = 0; double transX = 0; final vertexOffsetW = vertexSize / 2; if (offset.dx < fontPlace.width) { transX = fontSize + vertexOffsetW; } else { transX = -fontPlace.width - vertexOffsetW; } if (offset.dy < fontPlace.height + fontOffsetY) { transY = fontOffsetY; } else { transY = -fontPlace.height - fontOffsetY; } offset = offset.translate(transX, transY); canvas.drawText( displayText, offset, style: style, ); } /// 画顶点 void drawVertex(Canvas canvas, Offset offset, [bool active = false]) { canvas.drawVertex(offset, vertexSize, active: active); } /// 画短横标记 void drawMark(Canvas canvas, Offset offset, [bool active = false, bool ifHorizontal = true]) { canvas.drawMark(offset, vertexSize, active: active, ifHorizontal: ifHorizontal); } /// 计算文本长度 static Size boundingTextSize( String text, TextStyle style, { int maxLines = 2 ^ 31, double maxWidth = double.infinity, }) { // if (Get.context == null) return Size.zero; if (text.isEmpty) return Size.zero; final TextPainter textPainter = TextPainter( textDirection: TextDirection.ltr, // locale: Localizations.localeOf(Get.context!), text: TextSpan(text: text, style: style), maxLines: maxLines, )..layout(maxWidth: maxWidth); return textPainter.size; } void _recordHistory() { if (refItem.parent == null) { final recorder = refItem.application.recorder; recorder.recordMeasureItem(refItem.meta.name); } } }