|
@@ -0,0 +1,204 @@
|
|
|
+import 'dart: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_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';
|
|
|
+import 'package:fis_measure/utils/canvas.dart';
|
|
|
+
|
|
|
+class Polyline extends MeasureItem<PolylineFeature> {
|
|
|
+ Polyline(ItemMeta meta, IMeasureItem? parent) : super(meta, parent);
|
|
|
+
|
|
|
+ static Polyline createAreaPerimeter(ItemMeta meta, [IMeasureItem? parent]) {
|
|
|
+ Polyline polygon = Polyline(meta, parent);
|
|
|
+ polygon.calculator = _AreaPerimeterCalc(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);
|
|
|
+ } else {
|
|
|
+ f.innerPoints.last = args;
|
|
|
+ }
|
|
|
+ doCalculate();
|
|
|
+
|
|
|
+ if (false) {
|
|
|
+ doFeatureFinish();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ @override
|
|
|
+ bool onExecuteTouch(PointInfo args) {
|
|
|
+ // TODO: implement onExecuteTouch
|
|
|
+ throw UnimplementedError();
|
|
|
+ }
|
|
|
+
|
|
|
+ void handleMouseDownWhileWaiting(PointInfo args) {
|
|
|
+ // TODO: 判断是否当前area
|
|
|
+ // 转换为Area逻辑位置
|
|
|
+ final point = args.toAreaLogicPoint();
|
|
|
+ feature = PolylineFeature(this, point);
|
|
|
+ if (args.hostVisualArea != null) {
|
|
|
+ feature!.hostVisualArea = args.hostVisualArea;
|
|
|
+ }
|
|
|
+ state = ItemStates.running;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+class PolylineFeature extends MeasureItemFeature {
|
|
|
+ bool _isClosed = false;
|
|
|
+ double _splineTension = 0.0;
|
|
|
+ PolylineFeature(IMeasureItem refItem, DPoint point) : super(refItem) {
|
|
|
+ innerPoints.add(point);
|
|
|
+ }
|
|
|
+
|
|
|
+ DPoint get startPoint => innerPoints.first;
|
|
|
+ DPoint get endPoint => innerPoints.last;
|
|
|
+
|
|
|
+ bool get isClosed => _isClosed;
|
|
|
+ set isClosed(bool val) {
|
|
|
+ if (val != _isClosed) {
|
|
|
+ _isClosed = val;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ double get splineTension => _splineTension;
|
|
|
+ set splineTension(double val) {
|
|
|
+ if (val != _splineTension) {
|
|
|
+ _splineTension = val;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @override
|
|
|
+ void paint(Canvas canvas, Size size) {
|
|
|
+ if (innerPoints.isEmpty) return;
|
|
|
+
|
|
|
+ drawId(canvas, size);
|
|
|
+
|
|
|
+ final startOffset = convert2ViewPoint(size, startPoint).toOffset();
|
|
|
+
|
|
|
+ if (innerPoints.length == 1) {
|
|
|
+ drawVertex(canvas, startOffset, true);
|
|
|
+ return;
|
|
|
+ } else {
|
|
|
+ drawVertex(canvas, startOffset);
|
|
|
+ }
|
|
|
+
|
|
|
+ final len = innerPoints.length;
|
|
|
+ for (var i = 1; i < len; i++) {
|
|
|
+ final a = innerPoints[i - 1];
|
|
|
+ final b = innerPoints[i];
|
|
|
+ final offsetA = convert2ViewPoint(size, a).toOffset();
|
|
|
+ final offsetB = convert2ViewPoint(size, b).toOffset();
|
|
|
+ canvas.drawDashLine(offsetA, offsetB, 1, 10, paintPan);
|
|
|
+ final isLast = len - i == 1;
|
|
|
+ drawVertex(canvas, offsetB, isLast);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+class _AreaPerimeterCalc extends Calculator<Polyline, double> {
|
|
|
+ _AreaPerimeterCalc(Polyline 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 area;
|
|
|
+ double perimeter;
|
|
|
+ if ((feature.splineTension - 0).abs() > 0) {
|
|
|
+ // TODO: CreateSpline - Polyline.cs 850
|
|
|
+ perimeter = 0;
|
|
|
+ area = 0;
|
|
|
+ } else {
|
|
|
+ double threshold = 0.0;
|
|
|
+ area = calcArea(points);
|
|
|
+ perimeter = calcPerimeter(points, feature.isClosed, threshold);
|
|
|
+ }
|
|
|
+ for (var output in ref.meta.outputs) {
|
|
|
+ if (output.name == MeasureTypes.Perimeter) {
|
|
|
+ var value = roundDouble(perimeter, output.fractionalDigits);
|
|
|
+ feature.updateFloatValue(output, value, output.unit);
|
|
|
+ } else if (output.name == MeasureTypes.Area) {
|
|
|
+ var value = roundDouble(area, output.fractionalDigits);
|
|
|
+ feature.updateFloatValue(output, value, output.unit);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ static double calcArea(List<DPoint> points) {
|
|
|
+ if (points.isEmpty) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ double sum = 0;
|
|
|
+ var ax = points[0].x;
|
|
|
+ var ay = points[0].y;
|
|
|
+ for (var i = 1; i < points.length - 1; i++) {
|
|
|
+ var bx = points[i].x;
|
|
|
+ var by = points[i].y;
|
|
|
+ var cx = points[i + 1].x;
|
|
|
+ var cy = points[i + 1].y;
|
|
|
+ sum += ax * by - ay * bx + ay * cx - ax * cy + bx * cy - cx * by;
|
|
|
+ }
|
|
|
+ return (-sum / 2).abs();
|
|
|
+ }
|
|
|
+
|
|
|
+ static double calcPerimeter(
|
|
|
+ List<DPoint> points,
|
|
|
+ bool isClosed,
|
|
|
+ double threshold,
|
|
|
+ ) {
|
|
|
+ final len = points.length;
|
|
|
+ if (points.length < 2) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ double sum = 0;
|
|
|
+ for (int i = 1, j = 0; j < len && i < len; i++) {
|
|
|
+ var length = (points[i] - points[j]).length;
|
|
|
+ if ((length).abs() > threshold) {
|
|
|
+ sum += length;
|
|
|
+ j = i;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (isClosed) {
|
|
|
+ sum += (points[len - 1] - points[0]).length;
|
|
|
+ }
|
|
|
+
|
|
|
+ return sum;
|
|
|
+ }
|
|
|
+}
|