123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277 |
- import 'package:fis_measure/interfaces/date_types/point.dart';
- class SplineUtils {
- static List<DPoint> create(
- List<DPoint>? sourcePoints, {
- double tension = 0.5,
- List<double>? tensions,
- bool isClosed = false,
- double tolerance = 1.0,
- bool closeByStraightLine = false,
- List<DPoint> samplePoints = const [],
- bool isSimpsonSpline = false,
- }) {
- List<DPoint> splinePoints = [];
- double length = 0;
- if (sourcePoints == null || sourcePoints.isEmpty) {
- return splinePoints;
- }
- splinePoints.add(sourcePoints[0]);
- if (sourcePoints.length == 1) {
- generateSamplePointsFromTraceLine(
- sourcePoints[0], sourcePoints[0], samplePoints);
- return splinePoints;
- }
- var pts = List<DPoint>.from(sourcePoints);
- if (pts.length > 2 &&
- (pts[pts.length - 1] - pts[pts.length - 2]).length < tolerance) {
- pts.removeAt(pts.length - 1);
- }
- _ModifiableInt segmentStart = _ModifiableInt(-1);
- if (pts.length == 2) {
- if (!isClosed) {
- length += _segment(splinePoints, pts[0], pts[0], pts[1], pts[1],
- tension, tension, tolerance, segmentStart);
- } else {
- length += _segment(splinePoints, pts[1], pts[0], pts[1], pts[0],
- tension, tension, tolerance, segmentStart);
- length += _segment(splinePoints, pts[0], pts[1], pts[0], pts[1],
- tension, tension, tolerance, segmentStart);
- }
- generateSamplePointsFromTraceLine(pts[0], pts[1], samplePoints);
- } else {
- // var startEndTension = ResourceManager.GetValue("Measurement", "Tension", 0.1);
- var startEndTension = 0.1; // TODO
- List<int> pointSegments = [];
- var useTensionCollection = tensions != null && tensions.isNotEmpty;
- for (var i = 0; i < pts.length; i++) {
- var t1 = useTensionCollection ? tensions[i % tensions.length] : tension;
- var t2 = useTensionCollection
- ? tensions[(i + 1) % tensions.length]
- : tension;
- if (isSimpsonSpline &&
- (i == 0 || i == pts.length - 2 || i == pts.length - 1)) {
- t1 = t2 = startEndTension;
- }
- if (i == 0) {
- length += _segment(
- splinePoints,
- isClosed ? pts[pts.length - 1] : pts[0],
- pts[0],
- pts[1],
- pts[2],
- t1,
- t2,
- tolerance,
- segmentStart,
- );
- if (segmentStart.value != -1) {
- pointSegments.add(segmentStart.value);
- }
- } else if (i == pts.length - 2) {
- length += _segment(
- splinePoints,
- pts[i - 1],
- pts[i],
- pts[i + 1],
- isClosed ? pts[0] : pts[i + 1],
- t1,
- t2,
- tolerance,
- segmentStart,
- );
- if (segmentStart.value != -1) {
- pointSegments.add(segmentStart.value);
- }
- } else if (i == pts.length - 1) {
- if (isClosed) {
- if (closeByStraightLine) {
- length += (pts[i] - pts[0]).length;
- } else {
- length += _segment(splinePoints, pts[i - 1], pts[i], pts[0],
- pts[1], t1, t2, tolerance, segmentStart);
- if (segmentStart.value != -1) {
- pointSegments.add(segmentStart.value);
- }
- }
- }
- } else {
- length += _segment(splinePoints, pts[i - 1], pts[i], pts[i + 1],
- pts[i + 2], t1, t2, tolerance, segmentStart);
- if (segmentStart.value != -1) {
- pointSegments.add(segmentStart.value);
- }
- }
- }
- if (samplePoints.isNotEmpty) {
- if (pointSegments.length <= samplePoints.length) {
- int samples = 0;
- int totalPoints = splinePoints.length;
- for (int i = 0; i < pointSegments.length; i++) {
- var nextStart = i == pointSegments.length - 1
- ? splinePoints.length
- : pointSegments[i + 1];
- var startIndex = pointSegments[i];
- var segCount = nextStart - startIndex;
- var totalSamples = samplePoints.length - samples;
- var interval = totalPoints / totalSamples;
- if (interval >= 1) {
- int count = (segCount / interval).round();
- if (count <= 1) {
- samplePoints[samples++] =
- splinePoints[startIndex + segCount - 1];
- if (samples == samplePoints.length) {
- return splinePoints;
- }
- } else {
- var step = segCount ~/ count;
- var seek = (segCount % count + step - 1).toInt();
- for (int index = seek; index < segCount; index += step) {
- samplePoints[samples++] = splinePoints[startIndex + index];
- if (samples == samplePoints.length) {
- return splinePoints;
- }
- }
- }
- } else {
- for (int index = 0; index < segCount; index++) {
- samplePoints[samples++] = splinePoints[startIndex + index];
- if (samples == samplePoints.length) {
- return splinePoints;
- }
- }
- }
- totalPoints -= segCount;
- }
- if (samples > 1 && samples < samplePoints.length) {
- List<DPoint> temp = samplePoints.take(samples).toList();
- int insertIndex = temp.length - 1;
- while (temp.length < samplePoints.length) {
- var vector = (temp[insertIndex] - temp[insertIndex - 1]) / 2;
- var point = temp[insertIndex - 1].addVector(vector);
- temp.insert(insertIndex, point);
- insertIndex--;
- if (insertIndex == 0) {
- insertIndex = temp.length - 1;
- }
- }
- for (int i = 0; i < samplePoints.length; i++) {
- samplePoints[i] = temp[i];
- }
- }
- } else {
- throw ArgumentError("Too many trace point segments.");
- }
- }
- }
- return splinePoints;
- }
- static void generateSamplePointsFromTraceLine(
- DPoint start,
- DPoint end,
- List<DPoint> samplePoints,
- ) {
- if (samplePoints.length > 1) {
- if (start.x == end.x && start.y == end.y) {
- for (int i = 0; i < samplePoints.length; i++) {
- samplePoints[i] = start;
- }
- } else {
- DPoint step = DPoint((end.x - start.x) / (samplePoints.length - 1),
- (end.y - start.y) / (samplePoints.length - 1));
- for (int i = 0; i < samplePoints.length; i++) {
- samplePoints[i] = DPoint(start.x + step.x * i, start.y + step.y * i);
- }
- }
- }
- }
- static double _segment(
- List<DPoint> points,
- DPoint pt0,
- DPoint pt1,
- DPoint pt2,
- DPoint pt3,
- double t1,
- double t2,
- double tolerance,
- _ModifiableInt segmentStart,
- ) {
- segmentStart.value = -1;
- double length = (pt1 - pt2).length;
- double sx1 = t1 * (pt2.x - pt0.x);
- double sy1 = t1 * (pt2.y - pt0.y);
- double sx2 = t2 * (pt3.x - pt1.x);
- double sy2 = t2 * (pt3.y - pt1.y);
- double ax = sx1 + sx2 + 2 * pt1.x - 2 * pt2.x;
- double ay = sy1 + sy2 + 2 * pt1.y - 2 * pt2.y;
- double bx = -2 * sx1 - sx2 - 3 * pt1.x + 3 * pt2.x;
- double by = -2 * sy1 - sy2 - 3 * pt1.y + 3 * pt2.y;
- double cx = sx1;
- double cy = sy1;
- double dx = pt1.x;
- double dy = pt1.y;
- int num = ((pt1.x - pt2.x).abs() + (pt1.y - pt2.y).abs()) ~/ tolerance;
- for (int i = 1; i < num; i++) {
- double t = i / (num - 1);
- DPoint pt = DPoint(
- ax * t * t * t + bx * t * t + cx * t + dx,
- ay * t * t * t + by * t * t + cy * t + dy,
- );
- if (i == 1) {
- length += (pt - pt1).length;
- } else {
- length += (pt - points[points.length - 1]).length;
- }
- if (segmentStart.value == -1) {
- segmentStart.value = points.length;
- }
- points.add(pt);
- }
- return length;
- }
- }
- class _ModifiableInt extends _ModifiableValue<int> {
- _ModifiableInt(super.value);
- _ModifiableInt operator +(int other) {
- value += other;
- return this;
- }
- _ModifiableInt operator -(int other) {
- value -= other;
- return this;
- }
- }
- class _ModifiableValue<T> {
- T value;
- _ModifiableValue(
- this.value,
- );
- }
|