import 'dart:ui' as ui; import 'package:fis_measure/interfaces/date_types/point.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/items/types.dart'; import 'package:fis_measure/interfaces/process/workspace/point_info.dart'; import 'package:fis_measure/process/calcuators/urm_calcuators/urm_shell_den_measure.dart'; import 'package:fis_measure/process/calcuators/urm_calcuators/urm_shell_den_vel_measure.dart'; import 'package:fis_measure/process/calcuators/urm_calcuators/urm_shell_density_measure.dart'; import 'package:fis_measure/process/calcuators/urm_calcuators/urm_shell_fractal_dim_measure.dart'; import 'package:fis_measure/process/calcuators/urm_calcuators/urm_shell_hist_measure.dart'; import 'package:fis_measure/process/calcuators/urm_calcuators/urm_shell_perfusion_measure.dart'; import 'package:fis_measure/process/calcuators/urm_calcuators/urm_shell_vel_measure.dart'; import 'package:fis_measure/process/primitives/area_abstract.dart'; import 'package:fis_measure/process/primitives/trace.dart'; import 'package:fis_measure/process/primitives/utils/urm_sharp_copy.dart'; import 'package:fis_measure/utils/canvas.dart'; import 'package:fis_measure/utils/prompt_box.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; class URMShellMeasure extends Trace { URMShellMeasure(super.meta, super.parent); static URMShellMeasure createURMShellDenMeasure(ItemMeta meta, [IMeasureItem? parent]) { URMShellMeasure measureShellDen = URMShellMeasure(meta, parent); measureShellDen.calculator = URMShellDenMeasureCal( measureShellDen, ); return measureShellDen; } static URMShellMeasure createURMShellVelMeasure(ItemMeta meta, [IMeasureItem? parent]) { URMShellMeasure measureShellVel = URMShellMeasure(meta, parent); measureShellVel.calculator = URMShellVelMeasureCal( measureShellVel, ); return measureShellVel; } static URMShellMeasure createURMShellDensityMeasure(ItemMeta meta, [IMeasureItem? parent]) { URMShellMeasure measureShellDensity = URMShellMeasure(meta, parent); measureShellDensity.calculator = URMShellDensityMeasureCal( measureShellDensity, ); return measureShellDensity; } static URMShellMeasure createURMShellFractalDimMeasure(ItemMeta meta, [IMeasureItem? parent]) { URMShellMeasure measureShellFractalDim = URMShellMeasure(meta, parent); measureShellFractalDim.calculator = URMShellFractalDimMeasureCal( measureShellFractalDim, ); return measureShellFractalDim; } static URMShellMeasure createURMShellPerfusionMeasure(ItemMeta meta, [IMeasureItem? parent]) { URMShellMeasure measureShellPerfusion = URMShellMeasure(meta, parent); measureShellPerfusion.calculator = URMShellPerfusionMeasureCal( measureShellPerfusion, ); return measureShellPerfusion; } static URMShellMeasure createURMShellHistMeasure(ItemMeta meta, [IMeasureItem? parent]) { URMShellMeasure measureShellHist = URMShellMeasure(meta, parent); measureShellHist.calculator = URMShellHistMeasureCal( measureShellHist, ); return measureShellHist; } static URMShellMeasure createURMShellDenVelMeasure(ItemMeta meta, [IMeasureItem? parent]) { URMShellMeasure measureShellDenVel = URMShellMeasure(meta, parent); measureShellDenVel.calculator = URMShellDenVelMeasureCal( measureShellDenVel, ); return measureShellDenVel; } @override bool onExecuteMouse(PointInfo args) { if (waitingResult) return false; if (state == ItemStates.finished) { if (args.pointType == PointInfoType.mouseDown) { state = ItemStates.waiting; } } if (state == ItemStates.waiting) { if (args.pointType == PointInfoType.mouseDown) { handleMouseDownWhileWaiting(args); } } else if (state == ItemStates.running) { if (args.pointType == PointInfoType.mouseUp) return false; feature?.adopt(args); if (args.pointType == PointInfoType.mouseDown) { handleFinish(); } else { checkAutoSnap(args); } } return true; } @override void handleMouseDownWhileWaiting(PointInfo args) { if (meta.measureType == MeasureTypes.URMShellPerfusionMeasure) { feature = ShellPerfusionImageFeature(this); } else { feature = ShellImageFeature(this); // if (args.hostVisualArea != null) { // feature!.hostVisualArea = args.hostVisualArea; // } // final point = args.toAreaLogicPoint(); // feature!.adopt(point); } state = ItemStates.running; } bool waitingResult = false; void handleFinish({bool recordSharp = true}) async { if (recordSharp) { _recordSharp(); } feature!.isActive = false; waitingResult = true; await doCalculateAsync(); doFeatureFinish(); doFeatureUpdate(); // 若不执行,子测量将无法自动切换 PromptBox.dismiss(); waitingResult = false; } void _recordSharp() { UrmSharpCopyBoard.recordSharp( UrmSharpCopyDataType.rim, feature!.innerPoints, ); } /// 自动结束检测 @override bool checkAutoSnap(PointInfo current, [bool autoFinishFeature = true]) { if (feature == null || feature!.innerPoints.length < 3) { isSmartMove = false; return _syncState(false); } // final viewport = feature!.hostVisualArea!.viewport!; if (isAutoSnap == false) return false; final pixelSize = application.displaySize; final p1 = feature!.innerPoints.first.scale2Size(pixelSize); final p2 = current.scale2Size(pixelSize); final length = (p1 - p2).length; if (length > snapThreshold * 2.0 && !isSmartMove) { isSmartMove = true; } if (length < snapThreshold && isSmartMove) { feature!.innerPoints.last = feature!.innerPoints.first.clone(); /// 此处的最后一个点,方便计算,但是绘制时要剔除 // feature!.innerPoints.removeLast(); HapticFeedback.heavyImpact(); if (autoFinishFeature) { handleFinish(); } isSmartMove = false; return _syncState(true); } else { return _syncState(false); } } bool _syncState(bool isSnap) { snapState = isSnap; return snapState; } } class ShellImageFeature extends TraceFeature { ShellImageFeature(AreaItemAbstract refItem) : super(refItem); List outerExterPoints = []; List interExterPoints = []; bool isNeedPaintColors = false; /// 绘制rim 外环 @override void paint(Canvas canvas, Size size) { super.paint(canvas, size); if (outerExterPoints.isEmpty) { return; } final pixelPoints = outerExterPoints.map((e) { return convert2ViewPoint(size, e).toOffset(); }).toList(); canvas.drawDashPointsLine(pixelPoints, 1, 10, paintLinePan, close: true); if (isNeedPaintColors) { final inPixelPoints = interExterPoints .map((e) => convert2ViewPoint(size, e).toOffset()) .toList(); // 创建一个蓝色带透明度的Paint对象,用于填充区域 Paint outPaint = Paint() ..color = const Color(0xFF2897ea).withOpacity(0.5) ..style = PaintingStyle.fill; // 创建一个蓝色带透明度的Paint对象,用于填充区域 Paint innerPaint = Paint() ..color = const Color(0xFF57ED26).withOpacity(0.5) ..style = PaintingStyle.fill; // 创建Path并连接点 Path path = Path(); Path pathb = Path(); if (pixelPoints.isNotEmpty) { path.moveTo(pixelPoints[0].dx, pixelPoints[0].dy); for (var point in pixelPoints) { path.lineTo(point.dx, point.dy); } path.close(); // 闭合路径 } if (inPixelPoints.isNotEmpty) { pathb.moveTo(inPixelPoints[0].dx, inPixelPoints[0].dy); for (var point in inPixelPoints) { pathb.lineTo(point.dx, point.dy); } pathb.close(); // 闭合路径 } // 绘制路径 canvas.drawPath(path, outPaint); // 绘制路径 canvas.drawPath(pathb, innerPaint); } } } class ShellPerfusionImageFeature extends TraceFeature { ShellPerfusionImageFeature(AreaItemAbstract refItem) : super(refItem); ui.Image? perfusionImg; DPoint? leftTopPoint; DPoint? rightBottomPoint; List outerExterPoints = []; /// 绘制灌注图 @override void paintPerfusion(Canvas canvas, Size size) { if (perfusionImg != null) { Paint paint = Paint(); Rect src = Rect.fromLTWH( 0, 0, perfusionImg!.width.toDouble(), perfusionImg!.height.toDouble(), ); if (leftTopPoint == null || rightBottomPoint == null) { return; } DPoint leftTop = convert2ViewPoint(size, leftTopPoint!); DPoint rightBottom = convert2ViewPoint(size, rightBottomPoint!); convert2ViewPoint(size, rightBottomPoint!); Rect dst = Rect.fromPoints( Offset(leftTop.x, leftTop.y), Offset(rightBottom.x, rightBottom.y)); canvas.drawImageRect(perfusionImg!, src, dst, paint); final pixelPoints = outerExterPoints.map((e) { return convert2ViewPoint(size, e).toOffset(); }).toList(); canvas.drawDashPointsLine(pixelPoints, 1, 10, paintLinePan, close: true); } } }