using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
using System.Security.Permissions;
using System.ComponentModel;
namespace IStation.Model
{
///
/// 曲线表达式
///
[DataContract]
public class CurveExpress : ICloneable
{
#region 构造函数
public CurveExpress() { }
public CurveExpress(CurveExpress rhs)
{
this.FitPow = rhs.FitPow;
this.FitType = rhs.FitType;
this.Min = rhs.Min;
this.Max = rhs.Max;
this.Index0 = rhs.Index0;
this.Index1 = rhs.Index1;
this.Index2 = rhs.Index2;
this.Index3 = rhs.Index3;
this.DefinePoints = rhs.DefinePoints?.Select(x => new CurvePoint(x)).ToList();
this.IsNull = rhs.IsNull;
}
public CurveExpress(CurveExpress rhs, double ratio_y)
{
this.FitPow = rhs.FitPow;
this.FitType = rhs.FitType;
this.Min = rhs.Min;
this.Max = rhs.Max;
this.Index0 = rhs.Index0 * ratio_y;
this.Index1 = rhs.Index1 * ratio_y;
this.Index2 = rhs.Index2 * ratio_y;
this.Index3 = rhs.Index3 * ratio_y;
this.DefinePoints = rhs.DefinePoints?.Select(x => new CurvePoint(x.X, x.Y * ratio_y)).ToList();
this.IsNull = rhs.IsNull;
}
public CurveExpress(string strParas)
{
if (string.IsNullOrEmpty(strParas))
{
this.IsNull = true;
return;
}
var str_list = strParas.Split(new string[] { Separator }, StringSplitOptions.RemoveEmptyEntries);
var count = str_list.Count();
if (count < 8)
{
this.IsNull = true;
return;
}
this.IsNull = false ;
this.FitPow = Convert.ToInt32(str_list[0]);
this.FitType = (eCurveFitType)Convert.ToInt32(str_list[1]);
this.Min = Convert.ToDouble(str_list[2]);
this.Max = Convert.ToDouble(str_list[3]);
this.Index0 = Convert.ToDouble(str_list[4]);
this.Index1 = Convert.ToDouble(str_list[5]);
this.Index2 = Convert.ToDouble(str_list[6]);
this.Index3 = Convert.ToDouble(str_list[7]);
if (count > 8)
{
this.DefinePoints = CurvePoint.ToList(str_list[8]);
}
}
public CurveExpress(List points)
{
ResetCurve(points, eCurveFitType.CubicCurve, false);
}
public CurveExpress(List points, bool savePoints)
{
ResetCurve(points, eCurveFitType.CubicCurve, savePoints);
}
public CurveExpress(List points, eCurveFitType fitType)
{
ResetCurve(points, fitType,false);
}
public CurveExpress(List points, eCurveFitType fitType, bool savePoints)
{
ResetCurve(points, fitType, savePoints);
}
public CurveExpress(List points, int fitPow)
{
ResetCurve(points, fitPow,false);
}
public CurveExpress(List points, int fitPow, bool savePoints)
{
ResetCurve(points, fitPow, savePoints);
}
///
/// 重置曲线
///
public virtual void ResetCurve(CurveExpress rhs)
{
this.FitPow = rhs.FitPow;
this.FitType = rhs.FitType;
this.Min = rhs.Min;
this.Max = rhs.Max;
this.Index0 = rhs.Index0;
this.Index1 = rhs.Index1;
this.Index2 = rhs.Index2;
this.Index3 = rhs.Index3;
this.DefinePoints = rhs.DefinePoints?.Select(x => new CurvePoint(x)).ToList();
this.IsNull = rhs.IsNull;
}
///
/// 重置曲线
///
public virtual void ResetCurve(List points, eCurveFitType fitType, bool savePoints = false )
{
var express = FitCurveHelper.BuildCurveExpress(points, fitType);
if (express == null)
{
this.IsNull = true;
return;
}
if (express.IsNull)
{
this.IsNull = true;
return;
}
this.FitType = express.FitType;
this.FitPow = express.FitPow;
this.Min = express.Min;
this.Max = express.Max;
this.Index0 = express.Index0;
this.Index1 = express.Index1;
this.Index2 = express.Index2;
this.Index3 = express.Index3;
this.IsNull = express.IsNull;
if (savePoints)
{
this.DefinePoints = express.DefinePoints;
}
else if (fitType == eCurveFitType.ThroughPoint)
{
this.DefinePoints = express.DefinePoints;
}
}
///
/// 重置曲线
///
public virtual void ResetCurve(List points, int fitPow, bool savePoints = false )
{
var fitType = GetFitType(fitPow);
this.ResetCurve(points, fitType, savePoints);
}
#endregion
#region 静态值
public const string Separator = "#";
#endregion
#region 属性
///
/// 拟合次数
///
[DataMember]
public int FitPow
{
get { return fitPow; }
set { fitPow = value; }
}
protected int fitPow = 3;
///
/// 拟合类型
///
[DataMember]
public eCurveFitType FitType
{
get { return fitType; }
set { fitType = value; }
}
protected eCurveFitType fitType = eCurveFitType.CubicCurve;
///
/// 最大值
///
[DataMember]
public double Max
{
get { return max; }
set { max = value; }
}
protected double max;
///
/// 最小值
///
[DataMember]
public double Min
{
get { return min; }
set { min = value; }
}
protected double min;
///
/// 0次系数
///
[DataMember]
public double Index0
{
get { return index0; }
set { index0 = value; }
}
protected double index0;
///
/// 1次系数
///
[DataMember]
public double Index1
{
get { return index1; }
set { index1 = value; }
}
protected double index1;
///
/// 2次系数
///
[DataMember]
public double Index2
{
get { return index2; }
set { index2 = value; }
}
protected double index2;
///
/// 3次系数
///
[DataMember]
public double Index3
{
get { return index3; }
set { index3 = value; }
}
protected double index3;
///
/// 定义点
///
[DataMember]
public List DefinePoints
{
get { return definePoints; }
set { definePoints = value; }
}
protected List definePoints = null;
///
/// 是否为空
///
[DataMember]
public bool IsNull
{
get { return isNull; }
set { isNull = value; }
}
protected bool isNull;
#endregion
///
/// 转化为保存字符串
///
public string ToDsString()
{
var str_list = new List();
str_list.Add(this.FitPow.ToString());
str_list.Add(((int)this.FitType).ToString());
str_list.Add(this.Min.ToString());
str_list.Add(this.Max.ToString());
//str_list.Add(this.Index0.ToString());
//str_list.Add(this.Index1.ToString("0.00000"));
//str_list.Add(this.Index2.ToString("0.0000000000"));
//str_list.Add(this.Index3.ToString("0.00000000000000"));
//nsx
var dc = new DoubleConverter();
str_list.Add(dc.ConvertToString(this.Index0));
str_list.Add(dc.ConvertToString(this.Index1));
str_list.Add(dc.ConvertToString(this.Index2));
str_list.Add(dc.ConvertToString(this.Index3));
if (this.DefinePoints != null && this.DefinePoints.Count > 0)
{
str_list.Add(this.DefinePoints.ToDsString());
}
return string.Join(Separator, str_list);
}
object ICloneable.Clone()
{
return Clone();
}
public CurveExpress Clone()
{
return new CurveExpress(this);
}
///
/// 是否在内部
///
public bool IsInterior(double x)
{
if (x < Min)
return false;
if (x > Max)
return false;
return true;
}
///
/// 获取拟合次方
///
public static int GetFitPow(eCurveFitType fitType)
{
switch (fitType)
{
case eCurveFitType.CubicCurve: return 3;
case eCurveFitType.ConicCurve: return 2;
case eCurveFitType.ConicCurveB0: return 2;
case eCurveFitType.LinearCurve: return 1;
case eCurveFitType.ThroughPoint: return 0;
default: return 3;
}
}
///
/// 获取拟合类型
///
public static eCurveFitType GetFitType(int fitPow)
{
switch (fitPow)
{
case 3: return eCurveFitType.CubicCurve;
case 2: return eCurveFitType.ConicCurve;
case 1: return eCurveFitType.LinearCurve;
case 0: return eCurveFitType.ThroughPoint;
default: return eCurveFitType.CubicCurve;
}
}
///
/// 获取拟合点
///
public double GetFitPointY(double x)
{
return FitCurveHelper.GetFitPointY(this, x);
}
///
/// 获取拟合点
///
public List GetFitPoints(int pointNumber = 20)
{
if (this.IsNull)
return default;
return FitCurveHelper.GetFitPoints(this, pointNumber);
}
///
/// 通过区间内拟合点
///
public List GetFitPointsByRange(double minX, double maxX, int pointNumber = 20)
{
if (this.IsNull)
return default;
return FitCurveHelper.GetFitPointsByRange(this, minX, maxX, pointNumber);
}
///
/// 获取拟合点
///
public List GetFitPointsByExtend(double ratioExtend, int pointNumber = 20)
{
if (this.IsNull)
return default;
return GetFitPointsByRange(this.min, this.max * ratioExtend, pointNumber);
}
///
/// 获取第一个拟合点
///
public CurvePoint GetFirstFitPoint()
{
return new CurvePoint(this.Min, GetFitPointY(this.Min));
}
///
/// 获取最后一个拟合点
///
public CurvePoint GetLastFitPoint()
{
return new CurvePoint(this.Max, GetFitPointY(this.Max));
}
///
/// 获取零点的Y值
///
public double GetZeroFitPointY()
{
return this.Index0;
}
///
/// 转换为Model
///
public static CurveExpress ToModel(string strParas)
{
if (string.IsNullOrEmpty(strParas))
return default;
var express = new CurveExpress(strParas);
if (express == null)
return default;
return express;
}
///
/// 是否相等
///
public bool IsEquals(CurveExpress rhs)
{
if (rhs == null)
return false;
if (rhs.ToDsString().Equals(this.ToDsString()))
return true;
else
return false;
}
///
/// 是否为Zero表达式
///
public bool IsZeroExpress()
{
if (this.Index0 != 0)
return false;
if (this.Index1 != 0)
return false;
if (this.Index2 != 0)
return false;
if (this.Index3 != 0)
return false;
return true;
}
///
/// 通过 X转换
///
public CurveExpress TransferX(double ratioX)
{
var fitPoints = this.GetFitPoints();
fitPoints = fitPoints?.Select(x => new CurvePoint(x.X * ratioX, x.Y)).ToList();
if (fitPoints == null || fitPoints.Count < 1)
return default;
var exp = new CurveExpress(fitPoints, this.FitType);
var definePoints = this.DefinePoints?.Select(x => new CurvePoint(x.X * ratioX, x.Y)).ToList();
if (definePoints != null && definePoints.Count > 0)
exp.DefinePoints = definePoints;
return exp;
}
///
/// 相似换算(speed_ratio = 新的转速 除以 老的转速)
///
public CurveExpress SimuBySpeed(eFeatCurveType featType, double speed_ratio, int pointNumber = 20)
{
double space = (this.Max - this.Min) / (pointNumber - 1);
switch (featType)
{
case eFeatCurveType.QH:
{
List pointInfo60 = new List();
for (int i = 0; i < pointNumber; i++)
{
double q50 = space * i + this.Min;
double q60 = q50 * speed_ratio;
double Y50 = GetFitPointY(q50);
pointInfo60.Add(new CurvePoint() { X = q60, Y = Y50 * speed_ratio * speed_ratio });
}
var new_curve = new CurveExpress(pointInfo60, this.FitType);
new_curve.DefinePoints = this.DefinePoints?.Select(x => new CurvePoint() { X = x.X * speed_ratio, Y = x.Y * speed_ratio * speed_ratio }).ToList();
return new_curve;
}
case eFeatCurveType.QE:
{
List pointInfo60 = new List();
for (int i = 0; i < pointNumber; i++)
{
double q50 = space * i + this.Min;
double q60 = q50 * speed_ratio;
double Y50 = GetFitPointY(q50);
pointInfo60.Add(new CurvePoint() { X = q60, Y = Y50 });
}
var new_curve = new CurveExpress(pointInfo60, this.FitType);
return new_curve;
}
case eFeatCurveType.QP:
{
List pointInfo60 = new List();
for (int i = 0; i < pointNumber; i++)
{
double q50 = space * i + this.Min;
double q60 = q50 * speed_ratio;
double Y50 = GetFitPointY(q50);
pointInfo60.Add(new CurvePoint() { X = q60, Y = Y50 * speed_ratio * speed_ratio * speed_ratio });
}
var new_curve = new CurveExpress(pointInfo60);
new_curve.DefinePoints = this.DefinePoints?.Select(x => new CurvePoint() { X = x.X * speed_ratio, Y = x.Y * speed_ratio * speed_ratio * speed_ratio }).ToList();
return new_curve;
}
default:
{
List pointInfo60 = new List();
for (int i = 0; i < pointNumber; i++)
{
double q50 = space * i + this.Min;
double q60 = q50 * speed_ratio;
double Y50 = GetFitPointY(q50);
pointInfo60.Add(new CurvePoint() { X = q60, Y = Y50 });
}
var new_curve = new CurveExpress(pointInfo60);
new_curve.DefinePoints = this.DefinePoints?.Select(x => new CurvePoint() { X = x.X * speed_ratio, Y = x.Y }).ToList();
return new_curve;
}
}
}
///
/// 50 到 60
///
public CurveExpress SimuFrom50To60(eFeatCurveType featType, int pointNumber = 20)
{
return SimuBySpeed(featType, 1.2, pointNumber);
}
///
/// 曲线方程:用于显示
///
public string GetCurveFunction(string xName = "Q")
{
//double signValue = 0;
//int value = 0;
StringBuilder sb = new StringBuilder();
//sb.Append(this.index0.ToString("G"));
//sb.Append(this.index0.ToString("0.00E+000"));//ToString("G"));
sb.Append(Math.Abs(this.Index0).ToString("0.00"));//.ToString("G"));
if (this.Index1 > 0)
sb.Append(" + ");
else
sb.Append(" - ");
//GetFuncScientificValue(1,Math.Abs(index1),ref signValue,ref value);
//sb.AppendFormat("{0}E{1}",signValue,value);
sb.Append(Math.Abs(this.Index1).ToString("0.0000"));//.ToString("G"));
sb.Append(" * ");
sb.Append(xName);
if (this.Index2 > 0)
sb.Append(" + ");
else
sb.Append(" - ");
//GetFuncScientificValue(2,Math.Abs(index2),ref signValue,ref value);
//sb.AppendFormat("{0}E{1}",signValue,value);
//sb.Append(Math.Round(Math.Abs(this.index2),4).ToString("G"));//.ToString("G"));
sb.Append(Math.Abs(this.Index2).ToString("0.000000000"));//.ToString("G"));
sb.Append(" * ");
sb.Append(xName);
sb.Append("^2 ");
if (this.Index3 > 0)
sb.Append(" + ");
else
sb.Append(" - ");
//GetFuncScientificValue(3,Math.Abs(index3),ref signValue,ref value);
//sb.AppendFormat("{0}E{1}",signValue,value);
//sb.Append(Math.Abs(this.index3).ToString("G"));//.ToString("G"));
sb.Append(Math.Abs(this.Index3).ToString("0.000000000000"));//.ToString("G"));
sb.Append(" * ");
sb.Append(xName);
sb.Append("^3 ");
return sb.ToString();
}
private static void GetFuncScientificValue(int FunctionIndex,
double FunctionCoeff, ref double signValue, ref int indexValue)
{
string strList = "";
if (FunctionIndex == 0)
{
strList = FunctionCoeff.ToString("0.000e+000");
}
else if (FunctionIndex == 1)
{
strList = FunctionCoeff.ToString("0.000000e+000");
}
else if (FunctionIndex == 2)
{
strList = FunctionCoeff.ToString("#.#########e+000");
}
else if (FunctionIndex == 3)
{
strList = FunctionCoeff.ToString("#.############e+000");
}
string[] st1 = null;
st1 = strList.Split('e');
signValue = Convert.ToDouble(st1[0]);
indexValue = Convert.ToInt32(st1[1]);
}
}
}