using System;
using System.Collections.Generic;
using UnityEngine;
namespace Framework.Geometry.Lines.Fitting {
/// Fits 2D line segments to geometric data
public static class Segment2Fitter {
/// Fits a line segment to an arbitrary set of points
/// Points to which a line segment will be fitted
/// The line segment fitted to the points
public static Segment2 Fit(IList points) {
// Special logic for point sets with no or just a single point
int pointCount = points.Count;
switch (pointCount) {
case 0: { return new Segment2(); }
case 1: { return new Segment2(points[0], points[0]); }
}
// Fit an infinite line to the point set
Line2 fittedLine = Line2Fitter.Fit(points);
// Now look for the points furthest to the negative direction of the line and
// to the positive direction of the line, also sum the intervals so the direction
// of the line segment can be matched to the direction of the point set.
float minInterval, maxInterval, intervalSum;
{
float lastInterval = Vector2.Dot(points[0] - fittedLine.Offset, fittedLine.Direction);
intervalSum = 0.0f;
minInterval = lastInterval;
maxInterval = lastInterval;
for (int index = 1; index < pointCount; ++index) {
float interval = Vector2.Dot(points[index] - fittedLine.Offset, fittedLine.Direction);
if (interval < minInterval) {
minInterval = interval;
}
if (interval > maxInterval) {
maxInterval = interval;
}
intervalSum += (interval - lastInterval);
lastInterval = interval;
}
}
// If the interval sum was negative, the points are sorted in reverse to
// the positive direction of the line, so flip it around
if(intervalSum >= 0) {
return new Segment2(
fittedLine.Offset + (minInterval * fittedLine.Direction),
fittedLine.Offset + (maxInterval * fittedLine.Direction)
);
} else {
return new Segment2(
fittedLine.Offset + (maxInterval * fittedLine.Direction),
fittedLine.Offset + (minInterval * fittedLine.Direction)
);
}
}
}
} // namespace Framework.Geometry.Lines.Fitting