private Dictionary <string, object> GetWebData(int objectID, FaultRateInfo.ObjectType objectType, int months, Dictionary <int, int> eqptContractCount, Dictionary <int, int> repairCount) { months = months > 120 ? 120 - 1 : months - 1; Dictionary <string, object> result = new Dictionary <string, object>(); List <FaultRateInfo> ForecastRateList = new List <FaultRateInfo>(); double slope = 0, intercept = 0, slope1 = 0, intercept1 = 0; List <FaultRateInfo> RateList = new List <FaultRateInfo>(); List <FaultRateInfo> RateList1 = new List <FaultRateInfo>(); GetRateList(objectID, objectType, eqptContractCount, repairCount, months, out RateList, out RateList1); if (RateList.Count >= 2) { Tuple <double, double> solpAndIntercept1 = SimpleRegression.Fit(RateList.Select(item => SQLUtil.ConvertDouble((item.Year - 1) * 12 + (int)item.Month)).ToArray(), RateList.Select(item => item.Rate).ToArray()); slope = solpAndIntercept1.Item1; intercept = solpAndIntercept1.Item2; } if (RateList1.Count >= 2) { Tuple <double, double> solpAndIntercept2 = SimpleRegression.Fit(RateList1.Select(item => SQLUtil.ConvertDouble((item.Year - 1) * 12 + (int)item.Month)).ToArray(), RateList1.Select(item => item.Rate).ToArray()); slope1 = solpAndIntercept2.Item1; intercept1 = solpAndIntercept2.Item2; } ForecastRateList = GetForecastRate(objectID, objectType, slope, intercept, slope1, intercept1, months); result.Add("RateList", RateList); result.Add("RateList1", RateList1); result.Add("ForecastRateList", ForecastRateList); result.Add("WebData", ForecastRateList.Concat(RateList).Concat(RateList1)); return(result); }
private Tuple <double, double> AllCases(double hr50, double hr85) { var validReadings = dataResult.Where(el => el <hr85 && el> hr50); var underReadings = dataResult.Where(el => el < hr85); var aboveReadings = dataResult.Where(el => el > hr50); if (underReadings.Count() == 0 || aboveReadings.Count() == 0 || validReadings.Count() < 2) { MessageBox.Show("All readings are invalid, we cannot determine your Aerobic Capacity"); return(null); } var xdata = new List <double>(); var ydata = new List <double>(); for (int i = 0; i < dataResult.Count; i++) { if (dataResult[i] < hr50 || dataResult[i] > hr85) { continue; } ydata.Add(dataResult[i]); xdata.Add((double)Tools.StepToAerobic(i, stepHeight)); } return(SimpleRegression.Fit(xdata.ToArray(), ydata.ToArray())); }
/// <summary> /// Gets the specified user identifier. /// </summary> /// <param name="userId">The user identifier.</param> /// <returns></returns> public IActionResult Get([FromQuery] Guid userId, [FromQuery] Guid procedureId, [FromQuery] Guid scenarioId) { try { IQueryable <TrialAnalysis> query = this._repository.GetTrialAnalysis(); if (userId != Guid.Empty) { query = query.Where(a => a.UserId == userId); } if (procedureId != Guid.Empty) { query = query.Where(a => a.ProcedureId == procedureId); } if (scenarioId != Guid.Empty) { query = query.Where(a => a.ScenarioId == scenarioId); } List <TrialAnalysis> result = query.ToList(); double[] y = result.Select(t => (double)t.Milliseconds / 1000).ToArray(); double[] x = result.Select(t => Math.Log((2.0 * t.Distance) / t.Width, 2)).ToArray(); Tuple <double, double> fit = SimpleRegression.Fit(x, y); return(Ok(new { A = fit.Item1, B = fit.Item2 })); } catch (Exception ex) { this._logger.LogError(0, ex, ex.Message); throw; } }
public static Line FitLine2D(List <double> xs, List <double> ys) { var yDeviation = ys.StandardDeviation(); var xDeviation = xs.StandardDeviation(); var isVertical = yDeviation > xDeviation; if (isVertical) { Swap(ref xs, ref ys); } var biasAndWeight = SimpleRegression.Fit(xs.ToArray(), ys.ToArray()); var bias = biasAndWeight.Item1; var weight = biasAndWeight.Item2; var xStart = xs.Min(); var xEnd = xs.Max(); var yStart = xStart * weight + bias; var yEnd = xEnd * weight + bias; return(new Line(isVertical?yStart: xStart, isVertical ?xStart: yStart, isVertical ? yEnd: xEnd, isVertical ? xEnd: yEnd)); }
/// <summary> /// Least-Squares fitting the points (x,y) to a line y : x -> a+b*x, /// returning a function y' for the best fitting line. /// </summary> public static Func <double, double> LineFunc(double[] x, double[] y) { var parameters = SimpleRegression.Fit(x, y); double intercept = parameters.Item1, slope = parameters.Item2; return(z => intercept + slope * z); }
public double GetR2(List <EDFSample> samples) { if (samples.Count <= 1) { return(0); } double[] Time = new double[samples.Count]; double[] Amount = new double[samples.Count]; int counter = 0; foreach (EDFSample item in samples) { Time[counter] = int.Parse(item.DATE); Amount[counter] = double.Parse(item.RESULT); counter++; } Tuple <double, double> t = SimpleRegression.Fit(Time, Amount); double a = t.Item2; double b = t.Item1; double[] model = new double[Time.Length]; for (int x = 0; x < Time.Count(); x++) { model[x] = (Time[x] * a) + b; } return(GoodnessOfFit.RSquared(model, Amount)); }
private void FitLineRegression(double[] xs, double[] ys, out HTuple lineX1, out HTuple lineY1, out HTuple lineX2, out HTuple lineY2) { var lineResult = SimpleRegression.Fit(xs, ys); var bias = lineResult.Item1; var weight = lineResult.Item2; HalconScripts.ImageLineIntersections(weight, bias, _width, _height, out lineX1, out lineY1, out lineX2, out lineY2); }
/*------------ STATIC METHODS ------------------*/ public static double MeasureSlope(PartLocation[] list) { // Fit to linear regression // y:x->a+b*x Double[] Xs = list.Select(xx => xx.X).ToArray(); Double[] Ys = list.Select(xx => xx.Y).ToArray(); Tuple <double, double> result = SimpleRegression.Fit(Xs, Ys); //x.a = result.Item1; //this should be as close to zero as possible if things worked correctly return(result.Item2); //this represents the slope of the tape }
public BETA(kdata data, kdata index) { var q = from i in index join s in data on i.date equals s.date select new { stock = s.close, index = i.close }; var ret = SimpleRegression.Fit( pct(q.Select(p => p.index).ToArray()), pct(q.Select(p => p.stock).ToArray())); alpha = ret.Item1; beta = ret.Item2; }
public static double Slope(double[] values, int startIndex, int length) { var x = new double[length]; var y = new double[length]; for (var i = 0; i < length; i++) { x[i] = startIndex + i; y[i] = values[startIndex + i]; } var(a, b) = SimpleRegression.Fit(x, y); return(-b); }
public double Correlation(double[] xArray, double[] yArray) { SimpleRegression regression = new SimpleRegression(); if (xArray.Length != yArray.Length) { //TODO throw new DimensionMismatchException(xArray.length, yArray.length); } if (xArray.Length < 2) { //TODO throw new MathIllegalArgumentException(LocalizedFormats.INSUFFICIENT_DIMENSION, new Object[] { Integer.valueOf(xArray.length), Integer.valueOf(2) }); } for (int i = 0; i < xArray.Length; i++) { regression.AddData(xArray[i], yArray[i]); } return(regression.GetR()); }
static double kRatio(StatisticsCollector collector) { var pnl = collector.pnl(); if (all(pnl, p => p == 0)) { return(0); } var equity = cumulativeSum(pnl); var regression = new SimpleRegression(); eachIt(equity, (i, p) => regression.addData(i + 1, p)); var b1 = regression.getSlope(); var stdError = regression.getSlopeStdErr(); return(b1 / (stdError * Math.Sqrt(pnl.Count))); }
private double FixationSlope(List <Fixation> fixations) { List <Tuple <double, double> > samples = new List <Tuple <double, double> >(); foreach (var fixation in fixations) { Tuple <double, double> sample = new Tuple <double, double>(fixation.x, fixation.y); samples.Add(sample); } if (samples.Count >= 2) { Tuple <double, double> result = SimpleRegression.Fit(samples); return(result.Item2); } else { return(0); } }
public void FitsToBestLineThroughOrigin() { // Mathematica: Fit[{{1,4.986},{2,2.347},{3,2.061},{4,-2.995},{5,-2.352},{6,-5.782}}, {x}, x] // -> -0.467791 x var x = Enumerable.Range(1, 6).Select(Convert.ToDouble).ToArray(); var y = new[] { 4.986, 2.347, 2.061, -2.995, -2.352, -5.782 }; var resp = Fit.LineThroughOrigin(x, y); Assert.AreEqual(-0.467791, resp, 1e-4); var resf = Fit.LineThroughOriginFunc(x, y); foreach (var z in Enumerable.Range(-3, 10)) { Assert.AreEqual(-0.467791 * z, resf(z), 1e-4); } var respSeq = SimpleRegression.FitThroughOrigin(Generate.Map2(x, y, Tuple.Create)); Assert.AreEqual(-0.467791, respSeq, 1e-4); }
public double GetTrend(List <EDFSample> samples) { double[] Time = new double[samples.Count]; double[] Amount = new double[samples.Count]; int counter = 0; foreach (EDFSample item in samples) { Time[counter] = int.Parse(item.DATE); Amount[counter] = double.Parse(item.RESULT); counter++; } if (Time.Length > 1) { double result = SimpleRegression.Fit(Time, Amount).Item2; return(result); } else { return(0); } }
/// <summary> /// 计算策略的各项性能指标,目前胜率等和交易次数相关的指标只针对非仓位管理型的策略 /// 该性能统计默认为是对日频采样的统计,若为其他频率需调整barsOfYear /// 所有指标保留四位小数 /// 若未穿入benchmark /// </summary> /// <param name="accountHistory"></param> /// <param name="positions"></param> /// <param name="benchmark"></param> /// <param name="riskFreeRate"></param> /// <returns></returns> public static PerformanceStatisics compute(List <BasicAccount> accountHistory, SortedDictionary <DateTime, Dictionary <string, PositionsWithDetail> > positions, double[] benchmark = null, double riskFreeRate = 0.00) { //若没有输入benchmark,构建默认的benchmark(全为1)3 int sign0 = 0; if (benchmark == null) { benchmark = new double[accountHistory.Count]; for (; sign0 < accountHistory.Count; sign0++) { benchmark[sign0] = 1; } } //benchmark与净值数据不匹配时跳出 if (benchmark.Length != accountHistory.Count) { Console.WriteLine("The length of benchmark is not consistent with accountHistory!"); return(null); } PerformanceStatisics performanceStats = new PerformanceStatisics(); //无风险收益率(年化) double barsOfYear = 252; //account长度,account记录周期数 int lengthOfAccount = accountHistory.Count; //初始资产 double intialAssets = accountHistory[0].totalAssets; //净值 double[] netWorth = accountHistory.Select(a => a.totalAssets / intialAssets).ToArray(); //收益率与超额收益率,比净值数少一 double[] returnArray = new double[netWorth.Length - 1]; //收益率 double[] returnArrayOfBenchmark = new double[netWorth.Length - 1]; //基准收益率 double[] benchmarkExcessReturn = new double[returnArray.Length]; //基准收益率 - 无风险收益率 double[] excessReturnToBenchmark = new double[returnArray.Length]; //收益率 - 基准收益率 double[] excessReturnToRf = new double[returnArray.Length]; //收益率 - 无风险收益率 double[] timeIndexList = new double[netWorth.Length]; //时间标签tick for (int i = 0; i < returnArray.Length; i++) { returnArray[i] = (netWorth[i + 1] - netWorth[i]) / netWorth[i]; returnArrayOfBenchmark[i] = (benchmark[i + 1] - benchmark[i]) / benchmark[i]; excessReturnToRf[i] = returnArray[i] - riskFreeRate / barsOfYear; benchmarkExcessReturn[i] = returnArrayOfBenchmark[i] - riskFreeRate / barsOfYear; excessReturnToBenchmark[i] = returnArray[i] - returnArrayOfBenchmark[i]; timeIndexList[i] = i; } timeIndexList[timeIndexList.Length - 1] = timeIndexList.Length - 1; //交易次数 double numOfTrades = 0; //成功交易次数 double numOfSuccess = 0; //失败交易次数 double numOfFailure = 0; //累计盈利 double cumProfit = 0; //累计亏损 double cumLoss = 0; //交易统计 foreach (var date in positions.Keys) { foreach (var variety in positions[date].Keys) { //交易笔数累计(一组相邻的反向交易为一笔交易) numOfTrades += positions[date][variety].record.Count / 2; //成功交易笔数累计 // List<TransactionRecord> lastestRecord = new List<TransactionRecord>(positions[date][variety].record[positions[date][variety].record.Count -1]) for (int rec = 1; rec < positions[date][variety].record.Count; rec += 2) { var nowRec = positions[date][variety].record[rec]; var lastRec = positions[date][variety].record[rec - 1]; //若当前为平多,则平多价格大于开多价格,成功数+1; //若当前为平空,则平空价格小于于开空价格,成功数+1 if ((nowRec.volume < 0 && nowRec.price > lastRec.price) || (nowRec.volume > 0 && nowRec.price < lastRec.price)) { //成功计数 numOfSuccess++; //收益累加 cumProfit += nowRec.volume < 0 ? (nowRec.price - lastRec.price) * Math.Abs(nowRec.volume) : (-nowRec.price + lastRec.price) * Math.Abs(nowRec.volume); } else { //亏损累加 cumLoss += nowRec.volume < 0 ? (nowRec.price - lastRec.price) * Math.Abs(nowRec.volume) : (-nowRec.price + lastRec.price) * Math.Abs(nowRec.volume); } } } } numOfFailure = numOfTrades - numOfSuccess; // netProfit performanceStats.netProfit = Math.Round((accountHistory[lengthOfAccount - 1].totalAssets - intialAssets), 4); //perNetProfit performanceStats.perNetProfit = Math.Round((performanceStats.netProfit / numOfTrades), 4); //totalReturn performanceStats.totalReturn = Math.Round((performanceStats.netProfit / intialAssets), 4); //anualReturn double daysOfBackTesting = accountHistory.Count; performanceStats.anualReturn = Math.Round((performanceStats.totalReturn / (daysOfBackTesting / barsOfYear)), 4); //anualSharpe performanceStats.anualSharpe = Math.Round(((returnArray.Average() - riskFreeRate / barsOfYear) / Statistics.StandardDeviation(returnArray) * Math.Sqrt(252)), 4); //winningRate performanceStats.winningRate = Math.Round((numOfSuccess / numOfTrades), 4); //PnLRatio performanceStats.PnLRatio = Math.Round((cumProfit / Math.Abs(cumLoss)), 4); //maxDrawDown performanceStats.maxDrawDown = Math.Round(computeMaxDrawDown(netWorth.ToList()), 4); //maxProfitRate performanceStats.maxProfitRatio = Math.Round(computeMaxProfitRate(netWorth.ToList()), 4); //profitMDDRatio performanceStats.profitMDDRatio = Math.Round((performanceStats.totalReturn / performanceStats.maxDrawDown), 4); //informationRatio performanceStats.informationRatio = Math.Round((excessReturnToBenchmark.Average() / Statistics.StandardDeviation(excessReturnToBenchmark) * Math.Sqrt(barsOfYear)), 4); //alpha var regstats = SimpleRegression.Fit(benchmarkExcessReturn, excessReturnToRf); performanceStats.alpha = Math.Round(regstats.Item1, 4); //beta performanceStats.beta = Math.Round(regstats.Item2, 4); //rSquare performanceStats.rSquare = Math.Round(Math.Pow(Correlation.Pearson(timeIndexList, netWorth), 2), 4); //averageHoldingRate double barsOfHolding = 0; double[] positionRate = new double[accountHistory.Count]; int sign = 0; foreach (var accout in accountHistory) { if (accout.positionValue != 0) { barsOfHolding++; } positionRate[sign] = accout.positionValue / accout.totalAssets; sign++; } performanceStats.averageHoldingRate = Math.Round((barsOfHolding / accountHistory.Count), 4); //averagePositionRate performanceStats.averagePositionRate = Math.Round(positionRate.Average(), 4); return(performanceStats); }
/// <summary> /// Least-Squares fitting the points (x,y) to a line y : x -> a+b*x, /// returning a function y' for the best fitting line. /// </summary> public static Func <double, double> LineFunc(double[] x, double[] y) { (double intercept, double slope) = SimpleRegression.Fit(x, y); return(z => intercept + slope * z); }
/// <summary> /// Least-Squares fitting the points (x,y) to a line through origin y : x -> b*x, /// returning a function y' for the best fitting line. /// </summary> public static Func <double, double> LineThroughOriginFunc(double[] x, double[] y) { double slope = SimpleRegression.FitThroughOrigin(x, y); return(z => slope * z); }
/// <summary> /// Least-Squares fitting the points (x,y) to a line through origin y : x -> b*x, /// returning its best fitting parameter b, /// where the intercept is zero and b the slope. /// </summary> public static double LineThroughOrigin(double[] x, double[] y) { return(SimpleRegression.FitThroughOrigin(x, y)); }
/// <summary> /// Least-Squares fitting the points (x,y) to a line y : x -> a+b*x, /// returning its best fitting parameters as [a, b] array, /// where a is the intercept and b the slope. /// </summary> public static Tuple <double, double> Line(double[] x, double[] y) { return(SimpleRegression.Fit(x, y)); }
private static PartLocation DoCameraCalibration(VideoProcessing vp, PartLocation movement) { var cnc = Global.Instance.cnc; var distance = new List <PartLocation>(); var pixels = new List <PartLocation>(); // turn on slack compensation var savedSlackCompensation = cnc.SlackCompensation; cnc.SlackCompensation = true; var startingPos = cnc.XYLocation; startingPos.A = 0; vp.MarkA.Clear(); for (int i = -4; i < 5; i++) { //move var newLocation = startingPos + (i * movement); if (!cnc.CNC_XYA(newLocation)) { return(null); } //try 5 times to find a circle List <Shapes.Circle> circles = new List <Shapes.Circle>(); for (int tries = 5; tries > 0 && circles.Count == 0; tries--) { circles = VideoDetection.FindCircles(vp); } if (circles.Count == 0) { continue; //not found, move and try again } //find largest circle of the bunch var circle = circles.Aggregate((c, d) => c.Radius > d.Radius ? c : d); //find largest circle if we have multiple // var circlePL = (1 / zoom) * circle.ToPartLocation(); //compensate for zoom circle.ToScreenUnzoomedResolution(); distance.Add(newLocation); pixels.Add(circle.ToPartLocation()); vp.MarkA.Add(circle.Clone().ToScreenResolution().ToPartLocation().ToPointF()); //DisplayText(String.Format("Actual Loc = {0}\t Measured Loc = {1}", newLocation, UpCamera.PixelsToActualLocation(circlePL)), Color.Blue); } double XmmPerPixel = 0, YmmPerPixel = 0; if (pixels.Count < 2) { Global.Instance.mainForm.ShowMessageBox("Unable To Detect Circles", "Try to adjust upcamera processing to see circles, and ensure upcamera needle position is correctly configured", MessageBoxButtons.OK); } else { // Do regression on X and Y var Xs = pixels.Select(xx => xx.X).ToArray(); var Ys = distance.Select(xx => xx.X).ToArray(); var result = SimpleRegression.Fit(Xs, Ys); XmmPerPixel = result.Item2; Xs = pixels.Select(xx => xx.Y).ToArray(); Ys = distance.Select(xx => xx.Y).ToArray(); result = SimpleRegression.Fit(Xs, Ys); YmmPerPixel = result.Item2; Global.Instance.DisplayText(String.Format("{0} Xmm/pixel {1} Ymm/pixel", XmmPerPixel, YmmPerPixel), Color.Purple); // Now move to the center /* need to get gotolocation upcamera working still * double X, Y; //error offset * GotoUpCamPosition_button_Click(null, null); * for (int tries = 5; tries > 0; tries--) { * if (GoToLocation_m(UpCamera, Shapes.ShapeTypes.Circle, 1.8, 0.5, out X, out Y)) { * Properties.Settings.Default.UpCam_PositionX = Cnc.CurrentX + X; * Properties.Settings.Default.UpCam_PositionY = Cnc.CurrentY - Y; * UpcamPositionX_textBox.Text = Properties.Settings.Default.UpCam_PositionX.ToString("0.00", CultureInfo.InvariantCulture); * UpcamPositionY_textBox.Text = Properties.Settings.Default.UpCam_PositionY.ToString("0.00", CultureInfo.InvariantCulture); * * } * } */ } //restore settings cnc.SlackCompensation = savedSlackCompensation; vp.MarkA.Clear(); //return value return((pixels.Count < 2) ? null : new PartLocation(Math.Abs(XmmPerPixel), Math.Abs(YmmPerPixel))); }
public bool CalibrateTape(TapeObj x) { // Setup Camera if (x.FirstHole == null && x.FirstPart == null) { x.FirstHole = Cnc.XYLocation; //defaults to hole based calibration } if (x.FirstHole != null) { SetCurrentTapeMeasurement(x.TapeType); } List <PartLocation> holes = new List <PartLocation>(); List <int> holeIndex = new List <int>(); if (x.FirstHole != null) { //1 - ensure first hole is correct MainForm.DisplayText("Moving to first hole @ " + x.FirstHole, Color.Purple); if (!MainForm.Cnc.CNC_XY(x.FirstHole)) { return(false); } var holepos = MainForm.FindPositionAndMoveToClosest(Shapes.ShapeTypes.Circle, 1.8, 0.1); //find this hole with high precision if (holepos == null) { return(false); } x.FirstHole = holepos; MainForm.DisplayText("Found new hole locaiton @ " + x.FirstHole, Color.Purple); // move to first hole for shits & giggles if (!MainForm.Cnc.CNC_XY(x.FirstHole)) { return(false); } holes.Add(x.FirstHole); holeIndex.Add(0); } //2 - Look for for a few more holes // XXX-should be adjsuted to acocomodate smaller strips if (x.FirstHole != null) { for (int i = 2; i < 8; i += 2) { /* - hole based detection - */ /****************************/ if (!MainForm.Cnc.CNC_XY(x.GetHoleLocation(i))) { break; } Thread.Sleep(500); var loc = MainForm.FindPositionAndMoveToClosest(Shapes.ShapeTypes.Circle, 1.8, 0.2); if (loc == null) { break; } holes.Add(loc); holeIndex.Add(i); } } else { for (int i = 0; i < 8; i += 1) { /* - part based detection - */ /****************************/ if (x.FirstPart != null) { if (!MainForm.Cnc.CNC_XY(x.GetPartBasedLocation(i))) { break; } Thread.Sleep(500); var loc = MainForm.FindPositionAndMoveToClosest(Shapes.ShapeTypes.Fiducial, 1.8, 0.2, x.TemplateFilename, .8); if (loc == null) { break; } holes.Add(loc); holeIndex.Add(i); } } } if (holes.Count < 2) { return(false); // didn't get enough points to calibrate this one } //3 - Do Linear Regression on data if we have 2+ points // Fit circle to linear regression // y:x->a+b*x Double[] Xs = holes.Select(xx => xx.X - ((x.FirstHole != null) ? x.FirstHole.X : x.FirstPart.X)).ToArray(); Double[] Ys = holes.Select(xx => xx.Y - ((x.FirstHole != null) ? x.FirstHole.Y : x.FirstPart.Y)).ToArray(); Tuple <double, double> result = SimpleRegression.Fit(Xs, Ys); x.a = result.Item1; //this should be as close to zero as possible if things worked correctly x.Slope = result.Item2; //this represents the slope of the tape MainForm.DisplayText(String.Format("Linear Regression: {0} + (0,{1})+(0,{2})x", x.FirstHole, x.a, x.Slope), Color.Brown); //4 - Determine Avg Hole Spacing double spacing = 0; for (int i = 0; i < holes.Count - 1; i++) { spacing += holes[i].DistanceTo(holes[i + 1]) / 2; //distance one hole to the next - /2 because we skip every other hole (step 2) } if (x.FirstHole != null) { x.HolePitch = spacing / (holes.Count - 1); //compute average for holes } else { x.PartPitch = 2 * spacing / (holes.Count - 1); } //5 - Done, specify that this is fully calibrated x.IsFullyCalibrated = true; MainForm.DisplayText("Tape " + x.ID + " Calibrated", Color.Brown); //MainForm.DisplayText(String.Format("\tEquation = {3} + (0,{0}) + {1} * ({2} * holeNumber)", x.a, x.b, x.HolePitch), System.Drawing.Color.Brown); MainForm.cameraView.DownCameraReset(); if (!MainForm.Cnc.CNC_XY(x.FirstHole ?? x.FirstPart)) { return(false); } return(true); }
public static List <Vector2Int> ComputeLSF( Color32 colId, float[] pixelsXF, float[] pixelsYF, float2 minXY, float2 maxXY, Texture2D provinceTex, out float[] midPointDistances, out bool isIdeal, int sampleResolution = 20, float minimumDistanceAlwaysHorizontal = 450f) { isIdeal = true; double[] xDouble = new double[pixelsXF.Length]; double[] yDouble = new double[pixelsYF.Length]; for (int i = 0; i < pixelsXF.Length; i++) { xDouble[i] = pixelsXF[i]; yDouble[i] = pixelsYF[i]; } System.Tuple <double, double> resH = SimpleRegression.Fit(xDouble, yDouble); int interceptH = Mathf.RoundToInt((float)resH.Item1 * provinceTex.width); System.Tuple <double, double> resV = SimpleRegression.Fit(yDouble, xDouble); int interceptV = Mathf.RoundToInt((float)resV.Item1 * provinceTex.height); float xRange = maxXY.x - minXY.x; float yRange = maxXY.y - minXY.y; int xRangeInt = Mathf.RoundToInt(xRange * provinceTex.width); int yRangeInt = Mathf.RoundToInt(yRange * provinceTex.height); int minX = Mathf.RoundToInt(minXY.x * provinceTex.width); int minY = Mathf.RoundToInt(minXY.y * provinceTex.height); //Sample the two lines we found using linear regression. Vector2Int[] horizontalLineSamples = GetLineSamples( false, sampleResolution, minX, minY, xRangeInt, yRangeInt, (float)resH.Item2, interceptH, 0); Vector2Int[] verticalLineSamples = GetLineSamples( true, sampleResolution, minX, minY, xRangeInt, yRangeInt, (float)resV.Item2, interceptV, 0); //Get the distance for which the line is inside of the province. float distanceH = GetLineThroughProvinceColorDistance( sampleResolution, provinceTex, horizontalLineSamples, colId); float distanceV = GetLineThroughProvinceColorDistance( sampleResolution, provinceTex, verticalLineSamples, colId); //see which line is longer float slope; int intercept; float originalDistance; bool vertical; if (distanceH >= distanceV || distanceH >= minimumDistanceAlwaysHorizontal) { slope = (float)resH.Item2; intercept = interceptH; vertical = false; originalDistance = distanceH; } else { slope = (float)resV.Item2; intercept = interceptV; vertical = true; originalDistance = distanceV; } //Create some lines parallel to the original line and compare distances int numParallelLines = 2; //every couple of lines are equally offset but on opposite sides float[] lineDistances = new float[1 + numParallelLines]; lineDistances[0] = originalDistance; LineData[] lines = new LineData[1 + numParallelLines]; //add original line lines[0] = new LineData( sampleResolution, minX, minY, xRangeInt, yRangeInt, slope, intercept, 0); float offsetAmount = 0f; for (int i = 1; i <= numParallelLines; i++) { //LINE int sign = i % 2 == 0 ? -1 : 1; offsetAmount = i % 2 == 0 ? offsetAmount : offsetAmount + 0.1f; int offset = Mathf.RoundToInt(i * offsetAmount * xRangeInt) * sign; verticalLineSamples = GetLineSamples( vertical, sampleResolution, minX, minY, xRangeInt, yRangeInt, slope, intercept, offset); lines[i] = new LineData( sampleResolution, minX, minY, xRangeInt, yRangeInt, slope, intercept, offset); //Put the distances of each line in an array. lineDistances[i] = GetLineThroughProvinceColorDistance( sampleResolution, provinceTex, verticalLineSamples, colId); } //find the max distance line float maxDistance = 0f; int longestLineIndex = 0; for (int i = 0; i < lineDistances.Length; i++) { if (lineDistances[i] > maxDistance) { maxDistance = lineDistances[i]; longestLineIndex = i; } } //along the longest line, create some offsets and sample lines perpendicular to those offsets LineData[] offsetLines = new LineData[3]; Vector2Int[][] offsetLineSamples = new Vector2Int[3][]; Vector2Int[] offsetPointOnLineArray = new Vector2Int[3]; for (int i = 1; i <= 3; i++) { offsetLineSamples[i - 1] = new Vector2Int[sampleResolution]; Vector2Int a = GetPointOnLine(lines[longestLineIndex], ((float)i / ((float)3 + 1)), vertical); offsetPointOnLineArray[i - 1] = a; /*GameObject go = GameObject.CreatePrimitive(PrimitiveType.Sphere); * go.transform.localScale /= 3f; * go.transform.position = new Vector3(a.x * (100f / 8192f), 0f, a.y * (100f / 8192f));*/ float perpSlope = -1 * lines[longestLineIndex].slope; int offsetIntercept = GetInterceptThroughPoint(perpSlope, a, !vertical); offsetLines[i - 1] = new LineData( sampleResolution, minX, minY, xRangeInt, yRangeInt, perpSlope, offsetIntercept, 0); offsetLineSamples[i - 1] = GetLineSamples( !vertical, sampleResolution, minX, minY, xRangeInt, yRangeInt, perpSlope, offsetIntercept, 0); } //get the midpoint of each perpendicular offset line List <Vector2Int> offsetMidpoints = new List <Vector2Int>(); float[] offSetLineDistances = new float[3]; for (int i = 0; i < 3; i++) { if (TryGetLineMidpointOverProvince(sampleResolution, offsetLineSamples[i], provinceTex, colId, out offSetLineDistances[i], out Vector2Int o)) { offsetMidpoints.Add(o); } } //relax the midpoints a bit if (offsetMidpoints.Count == 3) { offsetMidpoints = RelaxMidpointSpline(lines[longestLineIndex], offsetMidpoints, 0.5f); } else if (offsetMidpoints.Count == 0 || offsetMidpoints.Count == 2) { isIdeal = false; int count = offsetMidpoints.Count; offsetMidpoints.Clear(); float dist = Vector2.Distance(offsetPointOnLineArray[0], offsetPointOnLineArray[1]); for (int i = 0; i < offsetPointOnLineArray.Length; i++) { offsetMidpoints.Add(offsetPointOnLineArray[i]); offSetLineDistances[i] = dist; } ImproveCenteringOfTwoPointCase(offsetPointOnLineArray[0], offsetPointOnLineArray[2], provinceTex, colId, out offsetMidpoints, 40); } midPointDistances = offSetLineDistances; return(offsetMidpoints); }
/// <summary> /// Least-Squares fitting the points (x,y) to a line y : x -> a+b*x, /// returning its best fitting parameters as [a, b] array, /// where a is the intercept and b the slope. /// </summary> public static (double A, double B) Line(double[] x, double[] y) { return(SimpleRegression.Fit(x, y)); }