import 'dart:ui'; import 'dart:math' as math; import 'package:fis_measure/interfaces/date_types/point.dart'; import 'package:fis_measure/interfaces/date_types/rect_region.dart'; import 'package:fis_measure/interfaces/enums/items.dart'; import 'package:fis_measure/interfaces/process/items/item.dart'; import 'package:fis_measure/interfaces/process/items/item_metas.dart'; import 'package:fis_measure/interfaces/process/workspace/application.dart'; import 'package:fis_measure/interfaces/process/workspace/point_info.dart'; import 'package:fis_measure/process/calcuators/velocity.dart'; import 'package:fis_measure/process/visual/tissue_area.dart'; import 'package:fis_measure/utils/canvas.dart'; import 'package:get/get.dart'; import 'package:vid/us/vid_us_mode.dart'; import '../calcuators/depth.dart'; import '../items/item.dart'; import '../items/item_feature.dart'; import '../physical_coordinates/convex_tissue.dart'; class Location extends MeasureItem { Location(ItemMeta meta, IMeasureItem? parent) : super(meta, parent); @override bool get finishAfterUnactive => false; @override bool onExecuteMouse(PointInfo args) { if (state == ItemStates.finished || state == ItemStates.waiting) { if (args.pointType == PointInfoType.mouseMove) { handleMouseMoveWhileFinish(args); } } if (state == ItemStates.running) { if (args.pointType == PointInfoType.mouseUp) return false; feature?.point = args; doCalculate(); if (args.pointType == PointInfoType.mouseDown) { doFeatureFinish(); } } return true; } @override bool onExecuteTouch(PointInfo args) { if (state == ItemStates.finished || state == ItemStates.waiting) { if (args.pointType == PointInfoType.touchDown) { handleMouseMoveWhileFinish(args); } } if (state == ItemStates.running) { if (args.pointType == PointInfoType.touchDown) { feature?.point = args; doCalculate(); } if (args.pointType == PointInfoType.touchMove) { args.addOffset(0, -0.2); if (isMoveTargetOutOfRange(args)) return true; feature?.point = args; doCalculate(); } if (args.pointType == PointInfoType.touchUp) { doFeatureFinish(); } } return true; } void handleMouseMoveWhileFinish(PointInfo args) { // TODO: 判断是否当前 area // 转换为 Area 逻辑位置 final point = args.toAreaLogicPoint(); handleTissue(args, point); handleTissueTM(args.hostVisualArea!.mode.modeType, point); if (args.hostVisualArea != null) { feature!.hostVisualArea = args.hostVisualArea; } state = ItemStates.running; } void handleTissueTM(VidUsModeType mode, DPoint point) { if (mode == VidUsModeType.TissueTM || mode == VidUsModeType.Doppler) { feature = LocationFeature(this, point); } } void handleTissue(PointInfo args, DPoint point) { final mode = args.hostVisualArea!.mode.modeType; if (mode == VidUsModeType.Tissue || mode == VidUsModeType.Flow) { final isProbeConvex = (args.hostVisualArea! as TissueArea).isConvex; if (isProbeConvex) { feature = TissueConvexLocationFeature(this, point); } else { feature = LocationFeature(this, point); } } } static Location createTissueConvexDepth( ItemMeta meta, [ IMeasureItem? parent, ]) { Location location = Location(meta, parent); location.calculator = TissueConvexDepthCal(location); return location; } static Location createTissueDepth( ItemMeta meta, [ IMeasureItem? parent, ]) { final area = Get.find().currentVisualArea; final isProbeConvex = (area as TissueArea).isConvex; final fn = isProbeConvex ? createTissueConvexDepth : createTissueNormalDepth; return fn(meta, parent); } static Location createTissueNormalDepth( ItemMeta meta, [ IMeasureItem? parent, ]) { Location location = Location(meta, parent); location.calculator = TissueDepthCal(location); return location; } static Location createTissueTMDepth( ItemMeta meta, [ IMeasureItem? parent, ]) { Location location = Location(meta, parent); location.calculator = MDepthCal(location); return location; } static Location createVelocity( ItemMeta meta, [ IMeasureItem? parent, ]) { Location location = Location(meta, parent); location.calculator = VelocityCal(location); return location; } } class TissueConvexLocationFeature extends LocationFeature { TissueConvexLocationFeature(IMeasureItem refItem, DPoint point) : super(refItem, point); @override void paint(Canvas canvas, Size size) { super.paint(canvas, size); if (!measureData.measureSystemSetting.showDepthGuideline) return; final point = this.point.clone(); final layout = hostVisualArea!.displayRegion; point.addOffset(-layout.left, -layout.top); // TODO : fix bug final viewport = hostVisualArea!.viewport!; final physical = (viewport.physical! as ConvexTissuePhysicalCoordinate); final region = viewport.region; final physicalZeroPoint = DPoint(region.width / 2, physical.zeroY); // 真实尺寸圆心 final physicalPoint = viewport.convert(point); final physicalStartPoint = _findCrossPointOnInnerDiameter( physicalZeroPoint, physicalPoint, physical.zeroRadius, viewport.region, ); // 在内圈内,不处理 if (physicalStartPoint == null) return; final logicStartPoint = viewport.convertBack(physicalStartPoint); logicStartPoint.addOffset(layout.left, layout.top); point.addOffset(layout.left, layout.top); Offset viewStartPoint = convert2ViewPoint(size, logicStartPoint).toOffset(); Offset viewPoint = convert2ViewPoint(size, point).toOffset(); if (viewStartPoint.dy < 0) { // TODO: 处理起点在画布区间外的情况,区间外不绘制 return; } canvas.drawDashLine(viewStartPoint, viewPoint, 1, 10, paintLinePan); } /// 找到直线(圆心到当前点)和扇形内圈的交叉点 DPoint? _findCrossPointOnInnerDiameter( DPoint zero, DPoint point, double zeroRadius, RectRegion region, ) { final centerOfX = region.width / 2; final pointWidthOnX = centerOfX - point.x; final pointHeightOnY = point.y - zero.y; final pointRadius = math.sqrt(math.pow(pointWidthOnX, 2) + math.pow(pointHeightOnY, 2)); final ratio = zeroRadius / pointRadius; if (ratio > 1) return null; double width = pointWidthOnX * ratio; double height = pointHeightOnY * ratio; double x = centerOfX - width; double y = height + zero.y; return DPoint(x, y); } } class LocationFeature extends MeasureItemFeature { LocationFeature(IMeasureItem refItem, DPoint point) : super(refItem) { innerPoints.add(point); } DPoint get point => innerPoints[0]; set point(DPoint value) => innerPoints[0] = value; @override void paint(Canvas canvas, Size size) { drawId(canvas, size); final viewPoint = convert2ViewPoint(size, point).toOffset(); drawVertex(canvas, viewPoint, isActive); } }