using IStation.Epanet.Enums;
using System.Collections;
namespace IStation.Epanet.Network.Structures
{
///2D graph used to map volume, pump, efficiency and head loss curves.
public sealed class Curve : Element, IEnumerable
{
private readonly List _points = new List();
public Curve(string name) : base(name) { }
public override ElementType ElementType => ElementType.CURVE;
/// Computes intercept and slope of head v. flow curve at current flow.
///
/// Flow value.
/// Head at zero flow (y-intercept).
/// dHead/dFlow (slope).
public void GetCoeff(FieldsMap fMap, double q, out double h0, out double r)
{
q *= fMap.GetUnits(FieldType.FLOW);
int npts = _points.Count;
var k2 = 0;
while (k2 < npts && _points[k2].X < q) k2++;
if (k2 == 0) k2++;
else if (k2 == npts) k2--;
int k1 = k2 - 1;
r = (_points[k2].Y - _points[k1].Y) / (_points[k2].X - _points[k1].X);
h0 = _points[k1].Y - r * _points[k1].X;
h0 /= fMap.GetUnits(FieldType.HEAD);
r *= fMap.GetUnits(FieldType.FLOW) / fMap.GetUnits(FieldType.HEAD);
}
///Curve type.
public CurveType Type { get; set; } //TODO: parse it correctly
/// Compute the linear interpolation of a 2d cartesian graph.
/// The abscissa value.
/// The interpolated value.
public double Interpolate(double x)
{
var p = _points;
int m = _points.Count - 1;
if (x <= p[0].X) return p[0].Y;
for (int i = 1; i <= m; i++)
{
if (p[i].X >= x)
{
double dx = p[i].X - p[i - 1].X;
double dy = p[i].Y - p[i - 1].Y;
if (Math.Abs(dx) < Constants.TINY) return p[i].Y;
return p[i].Y - (p[i].X - x) * dy / dx;
}
}
return p[m].Y;
}
#region partial implementation of IList
public void Add(double x, double y) { _points.Add(new EnPoint(x, y)); }
IEnumerator IEnumerable.GetEnumerator() { return _points.GetEnumerator(); }
public IEnumerator GetEnumerator() { return _points.GetEnumerator(); }
public int Count => _points.Count;
public EnPoint this[int index] => _points[index];
#endregion
}
}