|
@@ -1,9 +1,13 @@
|
|
|
import 'dart:ui';
|
|
|
+import 'package:fis_measure/interfaces/date_types/matrix.dart';
|
|
|
import 'package:fis_measure/interfaces/date_types/point.dart';
|
|
|
+import 'package:fis_measure/interfaces/date_types/rect.dart';
|
|
|
+import 'package:fis_measure/interfaces/date_types/vector.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/point_info.dart';
|
|
|
+import 'package:fis_measure/process/calcuators/formulas/general.dart';
|
|
|
import 'package:fis_measure/process/calcuators/perimeter.dart';
|
|
|
import 'package:fis_measure/process/calcuators/volume.dart';
|
|
|
import 'package:fis_measure/utils/canvas.dart';
|
|
@@ -28,22 +32,35 @@ class Ellipse extends MeasureItem<EllipseFeature> {
|
|
|
}
|
|
|
} else if (state == ItemStates.running) {
|
|
|
if (feature == null) return false;
|
|
|
- if (args.pointType == PointInfoType.mouseUp) return false;
|
|
|
+ final f = feature!;
|
|
|
+ final activeIndex = f.activeIndex;
|
|
|
|
|
|
- final points = feature!.innerPoints;
|
|
|
- if (points.length < 2) {
|
|
|
- points.add(args);
|
|
|
- } else if (points.length < 3) {
|
|
|
- points[1] = args;
|
|
|
- } else {
|
|
|
- points[2] = args;
|
|
|
+ switch (args.pointType) {
|
|
|
+ case PointInfoType.mouseMove:
|
|
|
+ f.innerPoints[activeIndex] = args;
|
|
|
+ f.adjustPoints(args);
|
|
|
+ break;
|
|
|
+ case PointInfoType.mouseDown:
|
|
|
+ if (activeIndex == 1) {
|
|
|
+ if (f.xAxisEnd == f.xAxisStart) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ f.activeIndex = 2;
|
|
|
+ f.innerPoints[activeIndex] = args;
|
|
|
+ f.adjustPoints(args);
|
|
|
+ } else if (activeIndex == 2) {
|
|
|
+ doFeatureFinish();
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return false;
|
|
|
}
|
|
|
+
|
|
|
doCalculate();
|
|
|
- if (points.length == 3 && args.pointType == PointInfoType.mouseDown) {
|
|
|
- doFeatureFinish();
|
|
|
- }
|
|
|
+
|
|
|
+ return true;
|
|
|
}
|
|
|
- return true;
|
|
|
+ return false;
|
|
|
}
|
|
|
|
|
|
@override
|
|
@@ -59,6 +76,7 @@ class Ellipse extends MeasureItem<EllipseFeature> {
|
|
|
if (args.hostVisualArea != null) {
|
|
|
feature!.hostVisualArea = args.hostVisualArea;
|
|
|
}
|
|
|
+ feature!.activeIndex = 1;
|
|
|
state = ItemStates.running;
|
|
|
}
|
|
|
|
|
@@ -77,16 +95,24 @@ class Ellipse extends MeasureItem<EllipseFeature> {
|
|
|
|
|
|
class EllipseFeature extends MeasureItemFeature {
|
|
|
EllipseFeature(IMeasureItem refItem, DPoint point) : super(refItem) {
|
|
|
- innerPoints.add(point);
|
|
|
+ innerPoints.add(point.clone());
|
|
|
+ innerPoints.add(point.clone());
|
|
|
+ innerPoints.add(point.clone());
|
|
|
+ innerPoints.add(point.clone());
|
|
|
}
|
|
|
|
|
|
/// 质心
|
|
|
DPoint get centroid {
|
|
|
- final x = (innerPoints[1].x + innerPoints[0].x) * 0.5;
|
|
|
- final y = (innerPoints[1].y + innerPoints[0].y) * 0.5;
|
|
|
+ final x = (xAxisStart.x + xAxisEnd.x) * 0.5;
|
|
|
+ final y = (xAxisStart.y + xAxisEnd.y) * 0.5;
|
|
|
return DPoint(x, y);
|
|
|
}
|
|
|
|
|
|
+ DPoint get xAxisStart => innerPoints[0];
|
|
|
+ DPoint get xAxisEnd => innerPoints[1];
|
|
|
+ DPoint get yAxisStart => innerPoints[2];
|
|
|
+ DPoint get yAxisEnd => innerPoints[2];
|
|
|
+
|
|
|
@override
|
|
|
void paint(Canvas canvas, Size size) {
|
|
|
if (innerPoints.isEmpty) return;
|
|
@@ -94,33 +120,214 @@ class EllipseFeature extends MeasureItemFeature {
|
|
|
var idText = '$id.${refItem.briefAnnotation}';
|
|
|
drawId(canvas, size, idText);
|
|
|
|
|
|
- final startOffset = convert2ViewPoint(size, innerPoints.first).toOffset();
|
|
|
+ final xStartOffset = convert2ViewPoint(size, xAxisStart).toOffset();
|
|
|
|
|
|
- if (innerPoints.length < 2) {
|
|
|
- drawVertex(canvas, startOffset, true);
|
|
|
+ if (activeIndex < 1) {
|
|
|
+ drawVertex(canvas, xStartOffset, true);
|
|
|
return;
|
|
|
}
|
|
|
- drawVertex(canvas, startOffset);
|
|
|
+ drawVertex(canvas, xStartOffset);
|
|
|
|
|
|
- final secondOffset = convert2ViewPoint(size, innerPoints[1]).toOffset();
|
|
|
- canvas.drawDashLine(startOffset, secondOffset, 1, 10, paintPan);
|
|
|
+ final xEndOffset = convert2ViewPoint(size, xAxisEnd).toOffset();
|
|
|
+ canvas.drawDashLine(xStartOffset, xEndOffset, 1, 10, paintPan);
|
|
|
|
|
|
- final radius = (secondOffset - startOffset).distance.abs() / 2;
|
|
|
+ final yStartOffset = convert2ViewPoint(size, yAxisStart).toOffset();
|
|
|
+ final yEndOffset = convert2ViewPoint(size, yAxisEnd).toOffset();
|
|
|
final centroidOffset = convert2ViewPoint(size, centroid).toOffset();
|
|
|
- canvas.drawCircle(centroidOffset, radius, paintPan);
|
|
|
- // canvas.drawOval(rect, paint)
|
|
|
- // final path = Path();
|
|
|
- // path.moveTo(centroidOffset.dx, centroidOffset.dy);
|
|
|
- // path.conicTo(x1, y1, x2, y2, w)
|
|
|
- // canvas.drawPath(
|
|
|
- // dashPath(path, dashArray: CircularIntervalList([2.0, 10.0])),
|
|
|
- // paintPan,
|
|
|
- // );
|
|
|
+ canvas.drawDashLine(yStartOffset, centroidOffset, 1, 10, paintPan);
|
|
|
+
|
|
|
+ final radiusX = getRadiusX(size);
|
|
|
+ final radiusY = getRadiusY(size);
|
|
|
+
|
|
|
+ final path = Path();
|
|
|
+ path.moveTo(xStartOffset.dx, xStartOffset.dy);
|
|
|
+ path.arcToPoint(
|
|
|
+ xEndOffset,
|
|
|
+ radius: Radius.elliptical(radiusX, radiusY),
|
|
|
+ );
|
|
|
+ path.arcToPoint(
|
|
|
+ xStartOffset,
|
|
|
+ radius: Radius.elliptical(radiusX, -radiusY),
|
|
|
+ );
|
|
|
+ canvas.drawPath(
|
|
|
+ dashPath(
|
|
|
+ path,
|
|
|
+ dashArray: CircularIntervalList<double>(<double>[2.0, 10.0]),
|
|
|
+ ),
|
|
|
+ paintPan,
|
|
|
+ );
|
|
|
|
|
|
if (innerPoints.length < 3) {
|
|
|
- drawVertex(canvas, secondOffset, true);
|
|
|
+ drawVertex(canvas, xEndOffset, true);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ drawVertex(canvas, xEndOffset);
|
|
|
+ }
|
|
|
+
|
|
|
+ /// X轴半径
|
|
|
+ double getRadiusX([Size? fitSize]) {
|
|
|
+ if (innerPoints.length < 2) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ var p1 = xAxisStart;
|
|
|
+ var p2 = xAxisEnd;
|
|
|
+ if (fitSize != null) {
|
|
|
+ p1 = p1.scale2Size(fitSize);
|
|
|
+ p2 = p2.scale2Size(fitSize);
|
|
|
+ }
|
|
|
+ return (p2 - p1).length / 2;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Y轴半径
|
|
|
+ double getRadiusY([Size? fitSize]) {
|
|
|
+ if (innerPoints.length == 4) {
|
|
|
+ var p = yAxisStart;
|
|
|
+ var c = centroid;
|
|
|
+ if (fitSize != null) {
|
|
|
+ p = p.scale2Size(fitSize);
|
|
|
+ c = c.scale2Size(fitSize);
|
|
|
+ }
|
|
|
+ return (p - c).length;
|
|
|
+ } else {
|
|
|
+ return getRadiusX(fitSize);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ void adjustPoints(DPoint point) {
|
|
|
+ final List<DPoint> crossPoints;
|
|
|
+ if (activeIndex == 2) {
|
|
|
+ final radius = GeneralFormulas.distance2Line(xAxisStart, xAxisEnd, point);
|
|
|
+ crossPoints = _findCrossPoints(xAxisStart, xAxisEnd, radius);
|
|
|
+ } else {
|
|
|
+ crossPoints = _findCrossPoints(xAxisStart, xAxisEnd);
|
|
|
+ }
|
|
|
+ final p3Index = _findNearest(point, crossPoints);
|
|
|
+ innerPoints[2] = crossPoints.removeAt(p3Index);
|
|
|
+ innerPoints[3] = crossPoints.first;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// 计算Y轴坐标点
|
|
|
+ void adjustPoints2(DPoint adjustPoint, bool keepYAxisLength) {
|
|
|
+ if (innerPoints.length != 4) {
|
|
|
return;
|
|
|
}
|
|
|
- drawVertex(canvas, secondOffset);
|
|
|
+ var p3 = innerPoints[2];
|
|
|
+ var p4 = innerPoints[3];
|
|
|
+
|
|
|
+ if (activeIndex == 0 || activeIndex == 1) {
|
|
|
+ _calculateYAxisPoints(
|
|
|
+ p3,
|
|
|
+ p4,
|
|
|
+ innerPoints[1 - activeIndex],
|
|
|
+ adjustPoint,
|
|
|
+ adjustPoint,
|
|
|
+ keepYAxisLength,
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ print(DateTime.now());
|
|
|
+ print(p3);
|
|
|
+ print(p4);
|
|
|
+ _calculateYAxisPoints(
|
|
|
+ p3,
|
|
|
+ p4,
|
|
|
+ xAxisStart,
|
|
|
+ xAxisEnd,
|
|
|
+ adjustPoint,
|
|
|
+ false,
|
|
|
+ );
|
|
|
+ print(p3);
|
|
|
+ print(p4);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ static void _calculateYAxisPoints(
|
|
|
+ DPoint yAxisStart,
|
|
|
+ DPoint yAxisEnd,
|
|
|
+ DPoint xAxisStart,
|
|
|
+ DPoint xAxisEnd,
|
|
|
+ DPoint adjustYAxisPoint,
|
|
|
+ bool keepYAxisLength,
|
|
|
+ ) {
|
|
|
+ var reverseMatrix = DMatrix();
|
|
|
+
|
|
|
+ var vertical = DVector(1, 0);
|
|
|
+ var angleBetweenVertical = _calculateAngel(xAxisEnd, xAxisStart, vertical);
|
|
|
+
|
|
|
+ var centroidX = (xAxisStart.x + xAxisEnd.x) * 0.5;
|
|
|
+ var centroidY = (xAxisStart.y + xAxisEnd.y) * 0.5;
|
|
|
+ var centroid = DPoint(centroidX, centroidY);
|
|
|
+
|
|
|
+ reverseMatrix.rotateAt(angleBetweenVertical, centroid.x, centroid.y);
|
|
|
+
|
|
|
+ var convertMatrix = reverseMatrix..invert();
|
|
|
+
|
|
|
+ double length;
|
|
|
+ if (adjustYAxisPoint == xAxisEnd) {
|
|
|
+ if (keepYAxisLength) {
|
|
|
+ length = (yAxisStart - yAxisEnd).length / 2;
|
|
|
+ } else {
|
|
|
+ length = (xAxisEnd - xAxisStart).length / 2;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ length =
|
|
|
+ GeneralFormulas.distance2Line(xAxisStart, xAxisEnd, adjustYAxisPoint);
|
|
|
+ }
|
|
|
+
|
|
|
+ var pt3 = DPoint(centroid.x, centroid.y + length);
|
|
|
+ var pt4 = DPoint(centroid.x, centroid.y - length);
|
|
|
+
|
|
|
+ var yAxisStartTrans = convertMatrix.transformWidthPoint(pt3);
|
|
|
+ var yAxisEndTrans = convertMatrix.transformWidthPoint(pt4);
|
|
|
+ yAxisStart.update(yAxisStartTrans);
|
|
|
+ yAxisEnd.update(yAxisEndTrans);
|
|
|
+ }
|
|
|
+
|
|
|
+ static double _calculateAngel(DPoint pt1, DPoint pt2, DVector axis) {
|
|
|
+ DVector xAxis = pt2 - pt1;
|
|
|
+ var angle = DVector.angleBetween(xAxis, axis);
|
|
|
+ return angle;
|
|
|
+ }
|
|
|
+
|
|
|
+ static List<DPoint> _findCrossPoints(DPoint a, DPoint b, [double? radius]) {
|
|
|
+ var centroidX = (a.x + b.x) * 0.5;
|
|
|
+ var centroidY = (a.y + b.y) * 0.5;
|
|
|
+ var centroid = Offset(centroidX, centroidY);
|
|
|
+
|
|
|
+ final dx = b.x - a.x;
|
|
|
+ final dy = b.y - a.y;
|
|
|
+
|
|
|
+ final len = (b - a).length;
|
|
|
+
|
|
|
+ /// 单位长度轴上距离增加量
|
|
|
+ final udx = dx / len;
|
|
|
+ final udy = dy / len;
|
|
|
+
|
|
|
+ final px = -udy;
|
|
|
+ final py = udx;
|
|
|
+
|
|
|
+ final distance = radius ?? len / 2;
|
|
|
+
|
|
|
+ final x1 = centroid.dx + px * distance;
|
|
|
+ final y1 = centroid.dy + py * distance;
|
|
|
+ final out1 = DPoint(x1, y1);
|
|
|
+
|
|
|
+ final x2 = centroid.dx - px * distance;
|
|
|
+ final y2 = centroid.dy - py * distance;
|
|
|
+ final out2 = DPoint(x2, y2);
|
|
|
+
|
|
|
+ return [out1, out2];
|
|
|
+ }
|
|
|
+
|
|
|
+ static int _findNearest(DPoint p, List<DPoint> source) {
|
|
|
+ int rst = 0;
|
|
|
+ double minLen = (source[0] - p).length;
|
|
|
+ for (var i = 1; i < source.length; i++) {
|
|
|
+ final len = (source[i] - p).length;
|
|
|
+ if (len < minLen) {
|
|
|
+ minLen = len;
|
|
|
+ rst = i;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return rst;
|
|
|
}
|
|
|
}
|