Init
This commit is contained in:
139
MarketDataLib/Numerics/BetaGenerator.cs
Normal file
139
MarketDataLib/Numerics/BetaGenerator.cs
Normal file
@@ -0,0 +1,139 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
//using MarketData.DataAccess;
|
||||
using MarketData.MarketDataModel;
|
||||
using MarketData.Utils;
|
||||
|
||||
// This Beta calculator is modelled after Yahoo Finance Beta calculator. It calculates Beta using 36 monthly prices start at beginning of previous month and going back 36 months
|
||||
// While the calculator does not match exactly to Yahoo Finance I will use this as an alternative in the event that Yahoo Finance Beta is no longer available.
|
||||
namespace MarketData.Numerical
|
||||
{
|
||||
public class BetaPrices : List<BetaPrice>
|
||||
{
|
||||
public BetaPrices()
|
||||
{
|
||||
}
|
||||
// assuming that the list is in descending date order
|
||||
public double[] ReturnsBenchmark()
|
||||
{
|
||||
double[] returns=new double[Count-1];
|
||||
for(int index=Count-2;index>=0;index--)
|
||||
{
|
||||
if(this[index+1].PriceBenchmark.Close==0.00)returns[index]=0.00;
|
||||
else returns[index]=(this[index].PriceBenchmark.Close-this[index+1].PriceBenchmark.Close)/this[index+1].PriceBenchmark.Close;
|
||||
}
|
||||
return returns;
|
||||
}
|
||||
public double[] ReturnsSymbol()
|
||||
{
|
||||
double[] returns=new double[Count-1];
|
||||
for(int index=Count-2;index>=0;index--)
|
||||
{
|
||||
if(this[index+1].PriceSymbol.Close==0.00)returns[index]=0.00;
|
||||
else returns[index]=(this[index].PriceSymbol.Close-this[index+1].PriceSymbol.Close)/this[index+1].PriceSymbol.Close;
|
||||
}
|
||||
return returns;
|
||||
}
|
||||
}
|
||||
public class BetaPrice
|
||||
{
|
||||
public BetaPrice(String symbol,String benchmark,Price symbolPrice,Price benchmarkPrice,DateTime pricingDate)
|
||||
{
|
||||
Symbol=symbol;
|
||||
Benchmark=benchmark;
|
||||
PricingDate=pricingDate;
|
||||
PriceSymbol=symbolPrice;
|
||||
PriceBenchmark=benchmarkPrice;
|
||||
}
|
||||
public DateTime PricingDate{get;set;}
|
||||
public String Symbol{get;set;}
|
||||
public String Benchmark{get;set;}
|
||||
public Price PriceSymbol{get;set;}
|
||||
public Price PriceBenchmark{get;set;}
|
||||
}
|
||||
|
||||
public class BetaGenerator
|
||||
{
|
||||
private BetaGenerator()
|
||||
{
|
||||
}
|
||||
//public static double Beta(String symbol,int months = 36)
|
||||
//{
|
||||
// return Beta(symbol, PricingDA.GetLatestDate(symbol), months);
|
||||
//}
|
||||
//public static double Beta(String symbol,DateTime asof,int months=36)
|
||||
//{
|
||||
// try
|
||||
// {
|
||||
// String benchmark = "SPY";
|
||||
// DateGenerator dateGenerator = new DateGenerator();
|
||||
|
||||
// BetaPrices betaPrices = new BetaPrices();
|
||||
// DateTime startDate = dateGenerator.GetPrevMonthStart(asof);
|
||||
// DateTime minPricingDate = PricingDA.GetEarliestDate(symbol);
|
||||
// Dictionary<DateTime, Price> symbolPricesByDate = new Dictionary<DateTime, Price>();
|
||||
// Dictionary<DateTime, Price> benchmarkPricesByDate = new Dictionary<DateTime, Price>();
|
||||
// List<DateTime> historicalDates = new List<DateTime>();
|
||||
// while (historicalDates.Count < (months + 1))
|
||||
// {
|
||||
// historicalDates.Add(startDate);
|
||||
// startDate = dateGenerator.GetPrevMonthStart(startDate);
|
||||
// }
|
||||
// Prices symbolPrices = PricingDA.GetPrices(symbol, asof, historicalDates[historicalDates.Count - 1]);
|
||||
// Prices benchmarkPrices = PricingDA.GetPrices(benchmark, asof, historicalDates[historicalDates.Count - 1]);
|
||||
// foreach (Price price in symbolPrices) symbolPricesByDate.Add(price.Date, price);
|
||||
// foreach (Price price in benchmarkPrices) benchmarkPricesByDate.Add(price.Date, price);
|
||||
// startDate = dateGenerator.GetPrevMonthStart(asof);
|
||||
// while (betaPrices.Count < (months + 1))
|
||||
// {
|
||||
// BetaPrice betaPrice = GetPrice(symbol, benchmark, startDate, symbolPricesByDate, benchmarkPricesByDate);
|
||||
// if (null == betaPrice)
|
||||
// {
|
||||
// return double.NaN;
|
||||
// }
|
||||
// betaPrices.Add(betaPrice);
|
||||
// startDate = dateGenerator.GetPrevMonthStart(startDate);
|
||||
// if (startDate < minPricingDate) break;
|
||||
// }
|
||||
// double[] returnsSymbol = betaPrices.ReturnsSymbol();
|
||||
// double[] returnsBenchmark = betaPrices.ReturnsBenchmark();
|
||||
// double beta = Numerics.Beta(ref returnsSymbol, ref returnsBenchmark);
|
||||
// return beta;
|
||||
// }
|
||||
// catch (Exception exception)
|
||||
// {
|
||||
// MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Exception:{0}",exception.ToString()));
|
||||
// return double.NaN;
|
||||
// }
|
||||
//}
|
||||
private static BetaPrice GetPrice(String symbol, String benchmark, DateTime requestedDate, Dictionary<DateTime, Price> symbolPricesByDate, Dictionary<DateTime, Price> benchmarkPricesByDate)
|
||||
{
|
||||
try
|
||||
{
|
||||
int maxAdvanceDays = 10;
|
||||
Price symbolPrice = null;
|
||||
Price benchmarkPrice = null;
|
||||
for (int advanceDays = 0; advanceDays < maxAdvanceDays; advanceDays++)
|
||||
{
|
||||
if (!symbolPricesByDate.ContainsKey(requestedDate)) { requestedDate = requestedDate.AddDays(1); continue; }
|
||||
symbolPrice = symbolPricesByDate[requestedDate];
|
||||
if (!benchmarkPricesByDate.ContainsKey(requestedDate)) { requestedDate = requestedDate.AddDays(1); continue; }
|
||||
benchmarkPrice = benchmarkPricesByDate[requestedDate];
|
||||
}
|
||||
if (null == symbolPrice || null == benchmarkPrice) return null;
|
||||
symbolPrice.Date = requestedDate.Date;
|
||||
benchmarkPrice.Date = requestedDate.Date;
|
||||
return new BetaPrice(symbol, benchmark, symbolPrice, benchmarkPrice, requestedDate);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
MDTrace.WriteLine(LogLevel.DEBUG, String.Format("Exception:{0}", exception.ToString()));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
66
MarketDataLib/Numerics/Bin.cs
Normal file
66
MarketDataLib/Numerics/Bin.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MarketData.Numerical
|
||||
{
|
||||
public interface IBinValueExtractor
|
||||
{
|
||||
double BinValue();
|
||||
}
|
||||
public class BinCollection<T> : List<BinItems<T>>
|
||||
{
|
||||
}
|
||||
public class BinItems<T> : List<T>
|
||||
{
|
||||
public BinItems()
|
||||
{
|
||||
}
|
||||
public BinItems(List<T> list)
|
||||
{
|
||||
foreach(T item in list)Add(item);
|
||||
}
|
||||
}
|
||||
public class BinHelper<T> where T : IBinValueExtractor
|
||||
{
|
||||
public static BinCollection<T> CreateBins(BinItems<T> items,int bins)
|
||||
{
|
||||
BinCollection<T> binCollection=new BinCollection<T>();
|
||||
if(null==items||0==items.Count)
|
||||
{
|
||||
for(int index=0;index<bins;index++)binCollection.Add(new BinItems<T>());
|
||||
return binCollection;
|
||||
}
|
||||
items.Sort();
|
||||
T minItem=items[0];
|
||||
T maxItem=items[items.Count-1];
|
||||
double midPoint=(maxItem.BinValue()-minItem.BinValue())/(double)bins;
|
||||
List<double> borderValues=new List<double>();
|
||||
for(int index=0;index<bins+1;index++)
|
||||
{
|
||||
if(0==index){borderValues.Add(minItem.BinValue());continue;}
|
||||
else if(index==bins)borderValues.Add(borderValues[index-1]+midPoint+1);
|
||||
else borderValues.Add(borderValues[index-1]+midPoint);
|
||||
}
|
||||
binCollection.Add(new BinItems<T>());
|
||||
for(int index=0;index<borderValues.Count;index++)
|
||||
{
|
||||
double lowerBound;
|
||||
double upperBound;
|
||||
BinItems<T> binItems=binCollection[binCollection.Count-1];
|
||||
lowerBound=borderValues[index];
|
||||
if(index==borderValues.Count-1)upperBound=maxItem.BinValue();
|
||||
else upperBound=borderValues[index+1];
|
||||
for(int itemIndex=0;itemIndex<items.Count;itemIndex++)
|
||||
{
|
||||
T item=items[itemIndex];
|
||||
if(item.BinValue()>=lowerBound&&item.BinValue()<upperBound)binItems.Add(item);
|
||||
}
|
||||
if(index<borderValues.Count-2)binCollection.Add(new BinItems<T>());
|
||||
}
|
||||
return binCollection;
|
||||
}
|
||||
}
|
||||
}
|
||||
73
MarketDataLib/Numerics/BlackScholes.cs
Normal file
73
MarketDataLib/Numerics/BlackScholes.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MarketData.MarketDataModel;
|
||||
|
||||
namespace MarketData.Numerical
|
||||
{
|
||||
/// <summary>
|
||||
/// Black Sholes Option Pricing Model for simplest scenario
|
||||
/// </summary>
|
||||
public class BlackScholesOptionPricingModel
|
||||
{
|
||||
private BlackScholesOptionPricingModel()
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// Get Option price by applying BlackScholesOptionPricingModel
|
||||
/// </summary>
|
||||
/// <param name="optionType">Enum to indicate whether Call or Put</param>
|
||||
/// <param name="S">Price of underlying</param>
|
||||
/// <param name="X">Strike price</param>
|
||||
/// <param name="T">Time to expiration in years</param>
|
||||
/// <param name="r">Risk free interest rate</param>
|
||||
/// <param name="v">Volatility</param>
|
||||
/// <returns></returns>
|
||||
//public static double GetPrice(OptionTypeEnum optionType, double S, double X, double T, double r, double v)
|
||||
//{
|
||||
// double d1 = 0.0;
|
||||
// double d2 = 0.0;
|
||||
// double optionValue = 0.0;
|
||||
|
||||
// d1 = (Math.Log(S / X) + (r + v * v / 2.0) * T) / (v * Math.Sqrt(T));
|
||||
// d2 = d1 - v * Math.Sqrt(T);
|
||||
// if (optionType == OptionTypeEnum.CallOption)
|
||||
// {
|
||||
// optionValue = S * CumulativeNormalDistributionFun(d1) - X * Math.Exp(-r * T) * CumulativeNormalDistributionFun(d2);
|
||||
// }
|
||||
// else if (optionType == OptionTypeEnum.PutOption)
|
||||
// {
|
||||
// optionValue = X * Math.Exp(-r * T) * CumulativeNormalDistributionFun(-d2) - S * CumulativeNormalDistributionFun(-d1);
|
||||
// }
|
||||
// return optionValue;
|
||||
//}
|
||||
/// <summary>
|
||||
/// Cumulative normal distribution function
|
||||
/// </summary>
|
||||
/// <param name="d"></param>
|
||||
/// <returns></returns>
|
||||
private static double CumulativeNormalDistributionFun(double d)
|
||||
{
|
||||
double L = 0.0;
|
||||
double K = 0.0;
|
||||
double dCND = 0.0;
|
||||
const double a1 = 0.31938153;
|
||||
const double a2 = -0.356563782;
|
||||
const double a3 = 1.781477937;
|
||||
const double a4 = -1.821255978;
|
||||
const double a5 = 1.330274429;
|
||||
L = Math.Abs(d);
|
||||
K = 1.0 / (1.0 + 0.2316419 * L);
|
||||
|
||||
dCND = 1.0 - 1.0 / Math.Sqrt(2 * Convert.ToDouble(Math.PI)) * Math.Exp(-L * L / 2.0) * (a1 * K + a2 * K * K + a3 * Math.Pow(K, 3.0) + a4 * Math.Pow(K, 4.0) + a5 * Math.Pow(K, 5.0));
|
||||
|
||||
if (d < 0)
|
||||
{
|
||||
return 1.0 - dCND;
|
||||
}
|
||||
else
|
||||
{
|
||||
return dCND;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
52
MarketDataLib/Numerics/KStest.cs
Normal file
52
MarketDataLib/Numerics/KStest.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
//using System.Data.SqlClient;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
// Filename: KSTest.cs
|
||||
// Author:Yan Kvitko
|
||||
// Date:01/2005
|
||||
|
||||
namespace MarketData.Numerical
|
||||
{
|
||||
[Serializable]
|
||||
public class KSTest
|
||||
{
|
||||
private int h;
|
||||
private double pValue;
|
||||
private double ksStat;
|
||||
private double criticalValue;
|
||||
|
||||
public KSTest()
|
||||
{
|
||||
}
|
||||
public KSTest(int h, double pValue, double ksStat, double criticalValue)
|
||||
{
|
||||
this.h=h;
|
||||
this.pValue=pValue;
|
||||
this.ksStat=ksStat;
|
||||
this.criticalValue=criticalValue;
|
||||
}
|
||||
public int H
|
||||
{
|
||||
get{return h;}
|
||||
set{h=value;}
|
||||
}
|
||||
public double PValue
|
||||
{
|
||||
get{return pValue;}
|
||||
set{pValue=value;}
|
||||
}
|
||||
public double KSStat
|
||||
{
|
||||
get{return ksStat;}
|
||||
set{ksStat=value;}
|
||||
}
|
||||
public double CriticalValue
|
||||
{
|
||||
get{return criticalValue;}
|
||||
set{criticalValue=value;}
|
||||
}
|
||||
}
|
||||
}
|
||||
134
MarketDataLib/Numerics/LeastSquares.cs
Normal file
134
MarketDataLib/Numerics/LeastSquares.cs
Normal file
@@ -0,0 +1,134 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MarketData.Utils;
|
||||
|
||||
namespace MarketData.Numerical
|
||||
{
|
||||
public class LeastSquaresResult
|
||||
{
|
||||
public double[] LeastSquares { get; set; }
|
||||
public double YIntercept { get; set; }
|
||||
public double XIntercept { get; set; }
|
||||
public double Slope { get; set; }
|
||||
public void Extend(int itemCount, double slope) // extend the result set by itemCount by applying the slope to subsequent values
|
||||
{
|
||||
if (null == LeastSquares || 0 == LeastSquares.Length) return;
|
||||
double[] extendedItems = new double[itemCount + LeastSquares.Length];
|
||||
Array.Copy(LeastSquares, 0, extendedItems, itemCount, LeastSquares.Length);
|
||||
for (int index = itemCount - 1; index >= 0; index--)
|
||||
{
|
||||
extendedItems[index] = extendedItems[index + 1] + slope;
|
||||
}
|
||||
LeastSquares = extendedItems;
|
||||
}
|
||||
}
|
||||
public class LeastSquaresResultWithR2 : LeastSquaresResult
|
||||
{
|
||||
public double RSquared { get; set; }
|
||||
}
|
||||
// **********************************************************************************************************************************************
|
||||
public class LeastSquaresHelper
|
||||
{
|
||||
private LeastSquaresHelper()
|
||||
{
|
||||
}
|
||||
// This version reverses the slope because the input data is in reverse order
|
||||
// The input data should be in the following manner observations[count-1]=earliest data point, observations[0]=most recent data point
|
||||
// This version should be retained as-is because it is being referenced in models etc.,
|
||||
public static LeastSquaresResult CalculateLeastSquares(double[] observations)
|
||||
{
|
||||
try
|
||||
{
|
||||
LeastSquaresResult leastSquaresResult = new LeastSquaresResult();
|
||||
double[] xSeries = new double[observations.Length];
|
||||
double[] xMinusXMean = new double[observations.Length];
|
||||
double[] yMinusYMean = new double[observations.Length];
|
||||
double[] meanProduct = new double[observations.Length];
|
||||
double[] xMinusXMeanSquared = new double[observations.Length];
|
||||
double[] leastSquares = new double[observations.Length];
|
||||
double xMean = double.NaN;
|
||||
double yMean = double.NaN;
|
||||
double slope = double.NaN;
|
||||
double yIntercept = double.NaN;
|
||||
for (int index = 0; index < xSeries.Length; index++) xSeries[index] = index + 1;
|
||||
xMean = Numerics.Mean(ref xSeries);
|
||||
yMean = Numerics.Mean(ref observations);
|
||||
for (int index = 0; index < observations.Length; index++)
|
||||
{
|
||||
xMinusXMean[index] = xSeries[index] - xMean;
|
||||
yMinusYMean[index] = observations[index] - yMean;
|
||||
meanProduct[index] = xMinusXMean[index] * yMinusYMean[index];
|
||||
xMinusXMeanSquared[index] = xMinusXMean[index] * xMinusXMean[index];
|
||||
}
|
||||
slope = Numerics.Sum(ref meanProduct) / Numerics.Sum(ref xMinusXMeanSquared);
|
||||
yIntercept = Numerics.YIntercept(xMean, yMean, slope);
|
||||
for (int index = 0; index < leastSquares.Length; index++) leastSquares[index] = slope * xSeries[index] + yIntercept;
|
||||
leastSquaresResult.LeastSquares = leastSquares;
|
||||
leastSquaresResult.YIntercept = yIntercept;
|
||||
leastSquaresResult.XIntercept = xMean;
|
||||
leastSquaresResult.Slope = slope * -1.00;
|
||||
return leastSquaresResult;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
MDTrace.WriteLine(LogLevel.DEBUG, exception.ToString());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// This version uses the true slope whereas the version above reverses the slope due to the arrangement of the input data
|
||||
// The input data should be in the following manner observations[0]=earliest data point, observations[count-1]=most recent data point
|
||||
public static LeastSquaresResultWithR2 CalculateLeastSquaresWithR2(double[] observations)
|
||||
{
|
||||
try
|
||||
{
|
||||
LeastSquaresResultWithR2 leastSquaresResultWithR2 = new LeastSquaresResultWithR2();
|
||||
double[] xSeries = new double[observations.Length];
|
||||
double[] xMinusXMean = new double[observations.Length];
|
||||
double[] yMinusYMean = new double[observations.Length];
|
||||
double[] meanProduct = new double[observations.Length];
|
||||
double[] xMinusXMeanSquared = new double[observations.Length];
|
||||
double[] leastSquares = new double[observations.Length];
|
||||
double xMean = double.NaN;
|
||||
double yMean = double.NaN;
|
||||
double slope = double.NaN;
|
||||
double yIntercept = double.NaN;
|
||||
for (int index = 0; index < xSeries.Length; index++) xSeries[index] = index + 1;
|
||||
xMean = Numerics.Mean(ref xSeries);
|
||||
yMean = Numerics.Mean(ref observations);
|
||||
for (int index = 0; index < observations.Length; index++)
|
||||
{
|
||||
xMinusXMean[index] = xSeries[index] - xMean;
|
||||
yMinusYMean[index] = observations[index] - yMean;
|
||||
meanProduct[index] = xMinusXMean[index] * yMinusYMean[index];
|
||||
xMinusXMeanSquared[index] = xMinusXMean[index] * xMinusXMean[index];
|
||||
}
|
||||
slope = Numerics.Sum(ref meanProduct) / Numerics.Sum(ref xMinusXMeanSquared);
|
||||
yIntercept = Numerics.YIntercept(xMean, yMean, slope);
|
||||
for (int index = 0; index < leastSquares.Length; index++) leastSquares[index] = slope * xSeries[index] + yIntercept;
|
||||
leastSquaresResultWithR2.LeastSquares = leastSquares;
|
||||
leastSquaresResultWithR2.YIntercept = yIntercept;
|
||||
leastSquaresResultWithR2.XIntercept = xMean;
|
||||
leastSquaresResultWithR2.Slope = slope;
|
||||
// calculate the R2
|
||||
double[] estimated = new double[observations.Length];
|
||||
double[] estimatedLessMeanSquared = new double[observations.Length];
|
||||
double sumOfEstimatedLessMeanSquared = 0.00;
|
||||
double sumofsquares = 0.00;
|
||||
foreach (double observation in observations) sumofsquares += Math.Pow(observation - yMean, 2);
|
||||
for (int index = 0; index < observations.Length; index++) estimated[index] = yIntercept + (slope * (index + 1));
|
||||
for (int index = 0; index < observations.Length; index++) estimatedLessMeanSquared[index] = Math.Pow(estimated[index] - yMean, 2);
|
||||
foreach (double value in estimatedLessMeanSquared) sumOfEstimatedLessMeanSquared += value;
|
||||
leastSquaresResultWithR2.RSquared = sumOfEstimatedLessMeanSquared / sumofsquares;
|
||||
return leastSquaresResultWithR2;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
MDTrace.WriteLine(LogLevel.DEBUG, exception.ToString());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1497
MarketDataLib/Numerics/Numerics.cs
Normal file
1497
MarketDataLib/Numerics/Numerics.cs
Normal file
File diff suppressed because it is too large
Load Diff
114
MarketDataLib/Numerics/Spline.cs
Normal file
114
MarketDataLib/Numerics/Spline.cs
Normal file
@@ -0,0 +1,114 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace MarketData.Numerical
|
||||
{
|
||||
// The column is the key, the row is the value.
|
||||
// For Time series elements put the date in the column and the value in the row
|
||||
public class Element
|
||||
{
|
||||
private double row;
|
||||
private double column;
|
||||
|
||||
public Element()
|
||||
{
|
||||
}
|
||||
public Element(double column, double row)
|
||||
{
|
||||
this.column = column;
|
||||
this.row = row;
|
||||
}
|
||||
public double Row
|
||||
{
|
||||
get { return row; }
|
||||
set { row = value; }
|
||||
}
|
||||
public double Column
|
||||
{
|
||||
get { return column; }
|
||||
set { column = value; }
|
||||
}
|
||||
}
|
||||
public class CatmullRom
|
||||
{
|
||||
private CatmullRom()
|
||||
{
|
||||
}
|
||||
public static bool PerformSpline(Element[] sourcePairs, Element[] destPairs)
|
||||
{
|
||||
double a0, a1, a2, a3;
|
||||
double dx, dx1, dx2;
|
||||
double dy, dy1, dy2;
|
||||
double endPointOne;
|
||||
double endPointTwo;
|
||||
double resamplingPos;
|
||||
double xPoint;
|
||||
int clampOne, clampTwo;
|
||||
int direction;
|
||||
int destSize = destPairs.Length;
|
||||
int sourceSize = sourcePairs.Length;
|
||||
int inputIndex, index;
|
||||
|
||||
a0 = a1 = a2 = a3 = endPointOne = 0;
|
||||
if (sourceSize < 2 || destSize < 1) return false;
|
||||
if (((Element)sourcePairs[0]).Column < ((Element)sourcePairs[1]).Column)
|
||||
{
|
||||
if (((Element)destPairs[0]).Column < ((Element)sourcePairs[0]).Column ||
|
||||
((Element)destPairs[destSize - 1]).Column > ((Element)sourcePairs[sourceSize - 1]).Column)
|
||||
direction = 0;
|
||||
else direction = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (((Element)destPairs[0]).Column > ((Element)sourcePairs[0]).Column ||
|
||||
((Element)destPairs[destSize - 1]).Column < ((Element)sourcePairs[sourceSize - 1]).Column)
|
||||
direction = 0;
|
||||
else direction = -1;
|
||||
}
|
||||
if (0 == direction) return false;
|
||||
if (1 == direction) endPointTwo = ((Element)destPairs[0]).Column - 1;
|
||||
else endPointTwo = ((Element)destPairs[0]).Column + 1;
|
||||
for (index = 0; index < destSize; index++)
|
||||
{
|
||||
resamplingPos = ((Element)destPairs[index]).Column;
|
||||
if ((1 == direction && resamplingPos > endPointTwo) ||
|
||||
(-1 == direction && resamplingPos < endPointTwo))
|
||||
{
|
||||
for (inputIndex = 0; inputIndex < sourceSize && resamplingPos > ((Element)sourcePairs[inputIndex]).Column; inputIndex++) ;
|
||||
if (resamplingPos < ((Element)sourcePairs[inputIndex]).Column) inputIndex--;
|
||||
if (inputIndex < 0) inputIndex = 0;
|
||||
else if (inputIndex == sourceSize-1) inputIndex--;
|
||||
endPointOne = ((Element)sourcePairs[inputIndex]).Column;
|
||||
endPointTwo = ((Element)sourcePairs[inputIndex + 1]).Column;
|
||||
clampOne = Math.Max(inputIndex - 1, 0);
|
||||
clampTwo = Math.Min(inputIndex + 2, sourceSize - 1);
|
||||
double clampOneValue = ((Element)sourcePairs[clampOne]).Column;
|
||||
double clampTwoValue = ((Element)sourcePairs[clampTwo]).Column;
|
||||
dx = 1.0 / ((endPointTwo - endPointOne)==0?1:(endPointTwo-endPointOne));
|
||||
dx1 = 1.0 / ((endPointTwo - clampOneValue) == 0 ? 1 : (endPointTwo - clampOneValue));
|
||||
dx2 = 1.0 / (clampTwoValue-endPointOne == 0 ? 1 : (clampTwoValue - endPointOne));
|
||||
dy = (((Element)sourcePairs[inputIndex + 1]).Row - ((Element)sourcePairs[inputIndex]).Row) * dx;
|
||||
dy1 = (((Element)sourcePairs[inputIndex + 1]).Row - ((Element)sourcePairs[clampOne]).Row) * dx1;
|
||||
dy2 = (((Element)sourcePairs[clampTwo]).Row - ((Element)sourcePairs[inputIndex]).Row) * dx2;
|
||||
a0 = ((Element)sourcePairs[inputIndex]).Row;
|
||||
a1 = dy1;
|
||||
a2 = dx * (3 * dy - 2 * dy1 - dy2);
|
||||
a3 = dx * dx * (-2 * dy + dy1 + dy2);
|
||||
}
|
||||
xPoint = resamplingPos - endPointOne;
|
||||
((Element)destPairs[index]).Row = ((a3 * xPoint + a2) * xPoint + a1) * xPoint + a0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public static Element[] CreateSplineSourceElements(double[] columns, double[] rows)
|
||||
{
|
||||
Element[] elements = new Element[columns.Length];
|
||||
if (columns.Length != rows.Length) return null;
|
||||
for (int index = 0; index < columns.Length; index++)
|
||||
{
|
||||
elements[index] = new Element(columns[index], rows[index]);
|
||||
}
|
||||
return elements;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
Reference in New Issue
Block a user