123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293 |
- import 'dart:math';
- import 'dart:ui';
- import 'package:vector_math/vector_math.dart';
- 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_metas.dart';
- import 'package:fis_measure/interfaces/process/items/item.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/calculator.dart';
- import 'package:fis_measure/process/items/item.dart';
- import 'package:fis_measure/process/items/item_feature.dart';
- /// 独立的两个线段确定一个角度
- class TwolineAngle extends MeasureItem<TwolineAngleFeature> {
- TwolineAngle(ItemMeta meta, IMeasureItem? parent) : super(meta, parent);
- static TwolineAngle createTwolineAngle(ItemMeta meta,
- [IMeasureItem? parent]) {
- TwolineAngle polygon = TwolineAngle(meta, parent);
- polygon.calculator = _AngleCalc(polygon);
- return polygon;
- }
- @override
- bool onExecuteMouse(PointInfo args) {
- 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 (feature == null) return false;
- if (args.pointType == PointInfoType.mouseUp) return false;
- final f = feature!;
- if (args.pointType == PointInfoType.mouseDown) {
- f.innerPoints.add(args);
- if (f.innerPoints.length == 5) {
- f.innerPoints.removeLast();
- doFeatureFinish();
- }
- } else {
- f.innerPoints.last = args;
- }
- doCalculate();
- }
- return true;
- }
- DPoint lastStartPoint = DPoint(0, 0); // 上一个起点
- bool isFirstPointNeedOffset = false; // 第一个点是否需要施加偏移
- DPoint splineTouchStartPoint = DPoint(0, 0); // 轨迹触摸起始点
- bool isOtherPointNeedOffset = false; // 其他点是否需要施加偏移
- @override
- bool onExecuteTouch(PointInfo args) {
- if (state == ItemStates.finished) {
- if (args.pointType == PointInfoType.touchDown) {
- state = ItemStates.waiting;
- }
- }
- if (state == ItemStates.waiting) {
- if (isFirstPointNeedOffset) args.addOffset(0, -0.2);
- switch (args.pointType) {
- case PointInfoType.touchDown:
- handleTouchDownWhileWaiting(args);
- isFirstPointNeedOffset = false;
- break;
- case PointInfoType.touchUp:
- lastStartPoint = args; // 设置线段起点
- state = ItemStates.running;
- feature?.innerPoints.first = args;
- break; // 按下立即抬起无事发生
- case PointInfoType.touchMove:
- if (isMoveTargetOutOfRange(args)) return true;
- isFirstPointNeedOffset = true;
- feature?.innerPoints.first = args;
- break;
- default:
- break;
- }
- } else if (state == ItemStates.running) {
- final f = feature!;
- if (isOtherPointNeedOffset && f.innerPoints.length == 3) {
- args.addOffset(0, -0.2);
- }
- if (feature == null) return false;
- PointInfo newPoint = PointInfo.fromOffset(
- lastStartPoint
- .clone()
- .addVector(args - splineTouchStartPoint)
- .toOffset(),
- args.pointType);
- newPoint.hostVisualArea = args.hostVisualArea;
- if (args.pointType == PointInfoType.touchUp) {
- if (!isOtherPointNeedOffset) {
- f.innerPoints.last = args;
- lastStartPoint = args;
- doCalculate();
- } else {
- lastStartPoint = newPoint;
- }
- if (f.innerPoints.length == 4) {
- doFeatureFinish();
- }
- }
- if (args.pointType == PointInfoType.touchDown) {
- isOtherPointNeedOffset = false;
- splineTouchStartPoint = args;
- f.innerPoints.add(lastStartPoint);
- if (f.innerPoints.length == 3) {
- lastStartPoint = args;
- }
- }
- if (args.pointType == PointInfoType.touchMove) {
- if (isMoveTargetOutOfRange(newPoint)) return true;
- isOtherPointNeedOffset = true;
- f.innerPoints.last = newPoint;
- }
- doCalculate();
- }
- return true;
- }
- void handleMouseDownWhileWaiting(PointInfo args) {
- // TODO: 判断是否当前area
- // 转换为Area逻辑位置
- final point = args.toAreaLogicPoint();
- feature = TwolineAngleFeature(this, point);
- if (args.hostVisualArea != null) {
- feature!.hostVisualArea = args.hostVisualArea;
- }
- state = ItemStates.running;
- }
- void handleTouchDownWhileWaiting(PointInfo args) {
- // TODO: 判断是否当前area
- // 转换为Area逻辑位置
- final point = args.toAreaLogicPoint();
- feature = TwolineAngleFeature.withOneStartPoint(this, point);
- if (args.hostVisualArea != null) {
- feature!.hostVisualArea = args.hostVisualArea;
- }
- }
- }
- class TwolineAngleFeature extends MeasureItemFeature {
- TwolineAngleFeature(IMeasureItem refItem, DPoint point) : super(refItem) {
- innerPoints.add(point.clone());
- innerPoints.add(point.clone());
- }
- TwolineAngleFeature.withOneStartPoint(IMeasureItem refItem, DPoint point)
- : super(refItem) {
- innerPoints.add(point.clone());
- }
- @override
- void paint(Canvas canvas, Size size) {
- if (innerPoints.isEmpty) return;
- drawId(canvas, size);
- final innerOffsets =
- innerPoints.map((e) => convert2ViewPoint(size, e).toOffset()).toList();
- final len = innerOffsets.length;
- if (len == 1) {
- drawVertex(canvas, innerOffsets[0]);
- } else if (len == 2) {
- final a = innerOffsets[0];
- final b = innerOffsets[1];
- canvas.drawLine(a, b, paintLinePan);
- } else if (len == 3) {
- final a = innerOffsets[0];
- final b = innerOffsets[1];
- canvas.drawLine(a, b, paintLinePan);
- drawVertex(canvas, innerOffsets[2]);
- } else if (len == 4) {
- final a = innerOffsets[0];
- final b = innerOffsets[1];
- final c = innerOffsets[2];
- final d = innerOffsets[3];
- canvas.drawLine(a, b, paintLinePan);
- canvas.drawLine(c, d, paintLinePan);
- //向量 A、B
- final vecA = Vector2(b.dx - a.dx, b.dy - a.dy);
- final vecB = Vector2(d.dx - c.dx, d.dy - c.dy);
- //计算向量夹角
- final angle = vecA.angleToSigned(vecB);
- //计算射线cd的角度
- final vecBAngle = vecB.angleToSigned(Vector2(1, 0));
- // 计算射线ab与射线cd的交点
- final Offset? p = _getIntersection(a, b, c, d);
- if (p != null) {
- // 绘制角度
- canvas.drawArc(Rect.fromCircle(center: p, radius: 30), -vecBAngle,
- -angle, false, paintLinePan);
- //如果交点在线段外,线段要延长至交点
- Offset? p1 = _getIntersection(a, b, p, Offset(0, p.dy));
- if (p1 != null) {
- final vecA1 = Vector2(p1.dx - a.dx, p1.dy - a.dy).normalized() * 50;
- p1 += Offset(vecA1.x, vecA1.y);
- canvas.drawLine(a, p1, paintLinePan);
- }
- Offset? p2 = _getIntersection(c, d, p, Offset(0, p.dy));
- if (p2 != null) {
- final vecB1 = Vector2(p2.dx - c.dx, p2.dy - c.dy).normalized() * 50;
- p2 += Offset(vecB1.x, vecB1.y);
- canvas.drawLine(c, p2, paintLinePan);
- }
- }
- }
- }
- /// 计算射线ab与射线cd的交点
- Offset? _getIntersection(Offset a, Offset b, Offset c, Offset d) {
- final x1 = a.dx;
- final y1 = a.dy;
- final x2 = b.dx;
- final y2 = b.dy;
- final x3 = c.dx;
- final y3 = c.dy;
- final x4 = d.dx;
- final y4 = d.dy;
- final denominator = ((x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4));
- // 检查分母是否为零,即两条射线是否平行
- if (denominator == 0) {
- return null; // 无交点
- }
- final x =
- ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) /
- denominator;
- final y =
- ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) /
- denominator;
- return Offset(x, y);
- }
- }
- class _AngleCalc extends Calculator<TwolineAngle, double> {
- _AngleCalc(TwolineAngle ref) : super(ref);
- @override
- void calculate() {
- if (ref.feature == null) return;
- final feature = ref.feature!;
- final viewport = feature.hostVisualArea!.viewport!;
- final points = feature.innerPoints.map((e) => viewport.convert(e)).toList();
- feature.values.clear();
- double angle;
- if (points.length != 4) {
- angle = 0;
- } else {
- angle = calcAngle(points[0], points[1], points[2], points[3]);
- }
- for (var output in ref.meta.outputs) {
- if (output.name == MeasureTypes.Angle) {
- var value = roundDouble(angle, output.fractionalDigits);
- feature.updateFloatValue(output, value, output.unit);
- }
- }
- }
- static double calcAngle(
- DPoint pointsA, DPoint pointsB, DPoint pointsC, DPoint pointsD) {
- double finalAngleDegree = 0;
- //向量 A、B
- final vecA = Vector2(pointsB.x - pointsA.x, pointsB.y - pointsA.y);
- final vecB = Vector2(pointsD.x - pointsC.x, pointsD.y - pointsC.y);
- //计算向量夹角
- final angle = vecA.angleToSigned(vecB);
- //转换为角度
- finalAngleDegree = angle * 180 / pi;
- if (finalAngleDegree < 0) {
- finalAngleDegree = -finalAngleDegree;
- }
- return finalAngleDegree;
- }
- }
|