private bool DefineSagitalPlane(Common.Vbo handle, ref Common.Plane plane, int selectedIndex, Common.Plane occlusalPlane) { if (occlusalPlane == null || !occlusalPlane.valid) { MessageBox.Show("Occlusal Plane should be defined prior to defining Sagital Plane.", "No Occlusal Plane"); return(false); } List <uint> sel; Vector3[] verts; sel = handle.selectedVertices; verts = handle.verticesData.vertices; if (sel.Count != 2) { MessageBox.Show("To define a Sagital Plane, first define the Occlusal Plane, then Select 2 points on the midline.", "Wrong number of selected points"); return(false); } plane = new Common.Plane(verts[sel[0]], verts[sel[1]], occlusalPlane.GetNormal()) { valid = true }; return(true); }
private Vector3[] ProjectToothOnAxisPlane(Common.Vbo handle, Common.Plane axisP, Common.Plane occlusalP) { const float dist2CenterTh = 5; const float dist2PlaneTh = 0.2f; List <Vector3> projectedPoints = new List <Vector3>(); double distanceToLowest = occlusalP.Distance2Point(axisP.lowestPoint); double distanceToHighest = occlusalP.Distance2Point(axisP.highestPoint); //int sideLowest = occlusalP.PointSide for (int i = 0; i < handle.verticesData.vertices.Length; i++) { if (axisP.Distance2Point(handle.verticesData.vertices[i]) < dist2PlaneTh && (handle.verticesData.vertices[i] - axisP.center).Length <dist2CenterTh && //occlusalP.Distance2Point(handle.verticesData.vertices[i]) < distanceToLowest && //occlusalP.Distance2Point(handle.verticesData.vertices[i]) > distanceToHighest handle.verticesData.vertices[i].Z> axisP.lowestPoint.Z && // ASSUMING CAST IS FACED UPWARD = Z handle.verticesData.vertices[i].Z < axisP.highestPoint.Z //ASSUMING CAST IS FACED UPWARD = Z ) { projectedPoints.Add(axisP.ProjectPointOnPlane(handle.verticesData.vertices[i])); } } return(projectedPoints.ToArray());//projectedPointsOnAxisPlane[selectedToothIndex].ToArray(); ; }
private Plane NormalPlane(DenseMatrix pointsMat) { int num = pointsMat.RowCount; var centroid = pointsMat.ColumnSums() / num; for (int i = 0; i < num; i++) { pointsMat[i, 0] -= centroid[0]; pointsMat[i, 1] -= centroid[1]; pointsMat[i, 2] -= centroid[2]; } var svd = pointsMat.Transpose().Svd(true); var singularValues = svd.S; var normalVec = new MathNet.Numerics.LinearAlgebra.Double.DenseVector(3); svd.U.Column(2, normalVec); Vector3 normalVec3 = new Vector3((float)normalVec[0], (float)normalVec[1], (float)normalVec[2]); Vector3 centroid3 = new Vector3((float)centroid[0], (float)centroid[1], (float)centroid[2]); Common.Plane p = new Common.Plane(normalVec3, centroid3); return(p); }
private bool DefineTeethPlaneAndTangentLine(Common.Vbo handle, ref Common.Plane toothAxisPlane, int selectedToothIndex, Common.Plane[] Planes) { try { List <uint> sel; Vector3[] verts; sel = handle.selectedVertices; verts = handle.verticesData.vertices; if (sel.Count != 3) { MessageBox.Show("Exactly 3 points must be selected to define the tooth axis", "Wrong number of points"); return(false); } if (Planes[OCCLUSALPLANE_INDEX] == null || !Planes[OCCLUSALPLANE_INDEX].valid) { MessageBox.Show("Occlusal Plane should be defined prior to calculatin tooth Inclination.", "No Occlusal Plane"); return(false); } Vector3 point1 = verts[sel[0]]; Vector3 point2 = verts[sel[1]]; Vector3 point3 = verts[sel[2]]; //making sure points are in correct order--> lowest:point1, middle: point2, top: point3 //cause occulsal plane sometimes goes lower than the upper and even middle point, //couldn't find a solution at the moment and decided to go with this: //the operator should Select the points in the correct order: lowest=first, highest=last //Sort3PointsBasedOnDistanceToOcclusalPlane(ref point1, ref point2, ref point3, Planes[OCCLUSALPLANE_INDEX]); toothAxisPlane = DefineAxisPlane(point1, point2, point3, Planes[OCCLUSALPLANE_INDEX]); Vector3[] projectedPoints = ProjectToothOnAxisPlane(handle, toothAxisPlane, Planes[OCCLUSALPLANE_INDEX]); Vector3[] projectedPointsOnBuccal = FindAndSortPointsOnBuccalSide(projectedPoints, toothAxisPlane, Planes[OCCLUSALPLANE_INDEX]); Vector3 BBPUser = point2; Vector3 projectedBBPUser = toothAxisPlane.ProjectPointOnPlane(point2); toothAxisPlane.projectedPointsOnAxisPlane = projectedPointsOnBuccal; toothAxisPlane.tangentPoints = CalculateTangentLine(projectedPointsOnBuccal, toothAxisPlane, projectedBBPUser); Vector3 tangentVector = toothAxisPlane.tangentPoints[1] - toothAxisPlane.tangentPoints[0]; toothAxisPlane.Inclination = Planes[OCCLUSALPLANE_INDEX].Angle2Vector(tangentVector); //radian toothAxisPlane.Inclination = (toothAxisPlane.Inclination / (float)Math.PI) * 180; toothAxisPlane.Inclination = CorrectInclination_BiggerORSmallerThan90(toothAxisPlane, point1, Planes[OCCLUSALPLANE_INDEX]); toothAxisPlane.validInclination = true; return(true); } catch (Exception e) { Common.Logger.Log("MainForm", "TeethComputations", "DefineTeethPlaneAndTangentLine", e.Message, true); return(false); } }
private Common.Plane DefineAxisPlane(Vector3 point1, Vector3 point2, Vector3 point3, Common.Plane occlusalPlane) { Vector3 normalToOcclucal = occlusalPlane.GetNormal(); Vector3 toothAxis = point1 - point3; //Common.Plane axisPlane = new Common.Plane(point1, point2, point3, toothAxis, normalToOcclucal, // "Axial "+SelectedIndex.ToString(), PLANE_DRAW_RADIUS_TOOTH); Common.Plane axisPlane2 = new Common.Plane(point1, point2, point3, "Axial " + SelectedIndex.ToString(), PLANE_DRAW_RADIUS_TOOTH); return(axisPlane2); }
private void DrawPlane(Common.Plane p, Color c) { GL.Enable(EnableCap.Blend); //GL.BlendFunc(BlendingFactorSrc.OneMinusConstantColor, BlendingFactorDest.OneMinusConstantColor); GL.Color3(c); GL.Disable(EnableCap.CullFace); GL.Begin(BeginMode.Polygon); for (int i = 0; i < p.pointsForDraw.Length; ++i) { GL.Vertex3(p.pointsForDraw[i]); } GL.End(); GL.Enable(EnableCap.CullFace); GL.Color3(Color.White); GL.Disable(EnableCap.Blend); }
private float CorrectInclination_BiggerORSmallerThan90(Common.Plane toothAxisPlane, Vector3 lowestPoint, Common.Plane occlusalPlane) { Vector3 upperP, lowerP; int lowestSide = occlusalPlane.PointSide(lowestPoint); if (occlusalPlane.PointSide(toothAxisPlane.tangentPoints[0]) == lowestSide && occlusalPlane.PointSide(toothAxisPlane.tangentPoints[1]) != lowestSide) { upperP = toothAxisPlane.tangentPoints[1]; lowerP = toothAxisPlane.tangentPoints[0]; } else if (occlusalPlane.PointSide(toothAxisPlane.tangentPoints[0]) != lowestSide && occlusalPlane.PointSide(toothAxisPlane.tangentPoints[1]) == lowestSide) { upperP = toothAxisPlane.tangentPoints[0]; lowerP = toothAxisPlane.tangentPoints[1]; } else //error { upperP = toothAxisPlane.tangentPoints[1]; lowerP = toothAxisPlane.tangentPoints[0]; Common.Logger.Log("MainForm", "TeethComputations", "CorrectInclination_BiggerORSmallerThan90", "Logical Error: both points of toothAxisPlane.tangentPoints were located on the same of the plane", true); } Vector3 upperPProj = occlusalPlane.ProjectPointOnPlane(upperP); Vector3 lowerPProj = occlusalPlane.ProjectPointOnPlane(lowerP); float distUpperPProj2Center = (upperPProj - occlusalPlane.centerForDraw).LengthSquared; float distLowerPProj2Center = (lowerPProj - occlusalPlane.centerForDraw).LengthSquared; if (distUpperPProj2Center < distLowerPProj2Center) { return(toothAxisPlane.Inclination - 90); } else { return(90 - toothAxisPlane.Inclination); } }
private Vector3[] FindAndSortPointsOnBuccalSide(Vector3[] projectedPoints, Common.Plane AxisPlane, Common.Plane OcclusalPlane) { Vector3 center = AxisPlane.center; Vector3 highest = AxisPlane.highestPoint; Vector3 lowest = AxisPlane.lowestPoint; //projectedPoints.sor tempOcclusalPlaneForPointCompareSort = OcclusalPlane; System.Comparison <Vector3> comp = new Comparison <Vector3>(PointCompareOnDistanceToOcclusalPlane); Array.Sort <Vector3>(projectedPoints, comp); //plane which cut the tooth in half in vertical (medio-lateral) Vector3 point3 = new Vector3(highest); point3 += AxisPlane.GetNormal(); Common.Plane halfPlaneOfTooth = new Common.Plane(highest, lowest, point3, "halfPlane", PLANE_DRAW_RADIUS_TOOTH); //Testing the halfPlane //Planes[SAGITALPLANE_INDEX] = halfPlaneOfTooth; //Planes[SAGITALPLANE_INDEX].valid = true; //tcb[SAGITALPLANE_INDEX].Enabled = true; //tcb[SAGITALPLANE_INDEX].Checked = true; int centerSide = halfPlaneOfTooth.PointSide(center); List <Vector3> newPoints = new List <Vector3>(); for (int i = 0; i < projectedPoints.Length; i++) { //if ((center - highest).Length > (center - projectedPoints[i]).Length) //meaning point is on buccal! if (halfPlaneOfTooth.PointSide(projectedPoints[i]) == centerSide) { newPoints.Add(projectedPoints[i]); } } //this.Text = newPoints.Count.ToString(); return(newPoints.ToArray()); }
bool DefineOcclusalPlane(Common.Vbo handle, ref Common.Plane plane, int planeNumber) { List <uint> sel; Vector3[] verts; sel = handle.selectedVertices; verts = handle.verticesData.vertices; if (sel.Count != 3) { MessageBox.Show("Exactly 3 points must be selected to define the Occlusal Plane", "Wrong number of points"); return(false); } plane = new Common.Plane(verts[sel[0]], verts[sel[1]], verts[sel[2]], "occlusal " + planeNumber.ToString(), PLANE_DRAW_RADIUS_OTHER) { valid = true }; return(true); }
private Vector3[] CalculateTangentLine(Vector3[] projectedPointsOnBuccal, Common.Plane axisPlane, Vector3 BBPSelectedByUser) { Vector3 rotationAxis_Horizontal; float rotationDegree; axisPlane.RotationAxisAndDegreeToMakePlaneHorizontal(out rotationAxis_Horizontal, out rotationDegree); Vector3[] rotatedPoints = Common.Plane.RotatePointsAroundAxis(projectedPointsOnBuccal.ToArray(), rotationAxis_Horizontal, rotationDegree); Vector3[] points = rotatedPoints; //Testing rotation: //Vector3[] oldpoints = Common.Plane.RotatePointsAroundAxis(rotatedPoints, rotationAxis_Horizontal, -rotationDegree); //projected user BBP Vector3 rotatedBBPUser = Common.Plane.RotatePointsAroundAxis(new Vector3[] { BBPSelectedByUser }, rotationAxis_Horizontal, rotationDegree)[0]; #region commented and moved to new function //int numPoints = points.Length; //Vector2 first = points[0].Xy; //Vector2 last = points[points.Length - 1].Xy; //Vector2 midOfFirstLast = (first + last) / 2; //Common.Line FLLine = new Common.Line(first, last); //Common.Line midPerpLine = new Common.Line(midOfFirstLast, FLLine.PerpendicularMu()); ////int minDistToMidPerpLineIndex = -1; ////float minDistToMidPerpLine = float.MaxValue; ////for (int i = 0; i < points.Length; i++) ////{ //// if (midPerpLine.DistanceToPoint(points[i].Xy) < minDistToMidPerpLine) //// { //// minDistToMidPerpLine= midPerpLine.DistanceToPoint(points[i].Xy); //// minDistToMidPerpLineIndex = i; //// } ////} ////float[] x = new float[points.Length]; ////float[] y = new float[points.Length]; //double[] xd = new double[points.Length]; //double[] yd = new double[points.Length]; ////checking if the points are actualy spread over X-axis. ////other wise I swap the X-Y axises to make te polyfit function of matlab work. //bool invereseXY = false; //if (Math.Abs(first.X - last.X) < Math.Abs(first.Y - last.Y)) // invereseXY = true; //if (!invereseXY) // for (int i = 0; i < points.Length; i++) // { // //x[i] = points[i].X; // //y[i] = points[i].Y; // xd[i] = points[i].X; // yd[i] = points[i].Y; // } //else // for (int i = 0; i < points.Length; i++) // { // //y[i] = points[i].X; // //x[i] = points[i].Y; // xd[i] = points[i].Y; // yd[i] = points[i].X; // } ////Vector3 midPoint = points[minDistToMidPerpLineIndex];//points[numPoints / 2]; //Vector2d midPoint = new Vector2d(xd[minDistToMidPerpLineIndex], yd[minDistToMidPerpLineIndex]); #endregion //float mu = PolynomialRegressionAndDerivative_MATLAB(x, y, midPoint); Vector2 midpoint = rotatedBBPUser.Xy; float mu = (float)PolynomialRegressionAndDerivativeAtMidPoint_MathNet(points, ref midpoint); Vector3[] tangentLinePoints = new Vector3[2]; tangentLinePoints[0] = new Vector3() { X = midpoint.X + TANGENT_VECTOR_LENGTH / 2, Y = TANGENT_VECTOR_LENGTH / 2 * mu + midpoint.Y, Z = points[0].Z }; tangentLinePoints[1] = new Vector3() { X = midpoint.X - TANGENT_VECTOR_LENGTH / 2, Y = midpoint.Y - TANGENT_VECTOR_LENGTH / 2 * mu, Z = points[0].Z, }; Vector3[] tangentLinePoints3D = Common.Plane.RotatePointsAroundAxis(tangentLinePoints, rotationAxis_Horizontal, -rotationDegree); //fixing the length Vector3 mid3D = (tangentLinePoints3D[0] + tangentLinePoints3D[1]) / 2; Vector3 lengthVector = (tangentLinePoints3D[0] - mid3D); lengthVector.Normalize(); tangentLinePoints3D[0] = mid3D + lengthVector * TANGENT_LINE_LENGTH; tangentLinePoints3D[1] = mid3D - lengthVector * TANGENT_LINE_LENGTH; return(tangentLinePoints3D); }
private void Sort3PointsBasedOnDistanceToOcclusalPlane(ref Vector3 point1, ref Vector3 point2, ref Vector3 point3, Common.Plane occlusalP) { double dist1 = occlusalP.Distance2Point(point1); double dist2 = occlusalP.Distance2Point(point2); double dist3 = occlusalP.Distance2Point(point3); if (dist1 > dist2 && dist2 > dist3) { //points are in correct order } else { if (dist1 < dist2) { Vector3 t = point1; point1 = point2; point2 = t; double d = dist1; dist1 = dist2; dist2 = d; } if (dist2 < dist3) { Vector3 t = point3; point3 = point2; point2 = t; double d = dist3; dist3 = dist2; dist2 = d; } if (dist1 < dist2) { Vector3 t = point1; point1 = point2; point2 = t; double d = dist1; dist1 = dist2; dist2 = d; } } }
private void ReadCalculationResults_txt(string fileAddress) //out of use { // This function was not a good idea and I will stop supporting it. StreamReader sr = new StreamReader(fileAddress); try { Common.Plane[] P; if (GetSelectedVbOIndex() == 1) { P = Planes[0]; } else { P = Planes[1]; } string[] header1 = sr.ReadLine().Split(','); if (header1[0] != "OrthoAid - TXT Calculation File") { throw new Exception("txt calculation file was not in the correct format"); } else { if (header1.Length > 1) { Vector3 centerDraw = new Vector3(float.Parse(header1[1]), float.Parse(header1[2]), float.Parse(header1[3])); Vector3 normal = new Vector3(float.Parse(header1[4]), float.Parse(header1[5]), float.Parse(header1[6])); P[OCCLUSALPLANE_INDEX] = new Common.Plane(normal, centerDraw); } } string header2 = sr.ReadLine(); if (header2 != "ToothNo,Inclination") { throw new Exception("txt calculation file was not in the correct format"); } string[] tokens; while (true) { tokens = sr.ReadLine().Split(','); if (tokens.Length < 2) { break; } int toothNo = int.Parse(tokens[0]); float inclination = float.Parse(tokens[1]); P[toothNo] = new Common.Plane() { Inclination = inclination, validInclination = true }; } string header3 = sr.ReadLine(); if (header3 != "ToothNo,Inclination") { throw new Exception("txt calculation file was not in the correct format"); } while (true) { tokens = sr.ReadLine().Split(','); if (tokens.Length < 2) { break; } int toothNo = int.Parse(tokens[0]); float inclination = float.Parse(tokens[1]); Planes[2][toothNo] = new Common.Plane() { Inclination = inclination, validInclination = true }; } string header4 = sr.ReadLine(); if (header4 != "ToothNo,Dislocation_X,Dislocation_Y,Dislocation_Z,Dislocation_Total") { throw new Exception("txt calculation file was not in the correct format"); } while (!sr.EndOfStream) { tokens = sr.ReadLine().Split(','); int toothNo = int.Parse(tokens[0]); Dislocations[toothNo].dislocation = new Vector3(float.Parse(tokens[1]), float.Parse(tokens[2]), float.Parse(tokens[3])); Dislocations[toothNo].length = float.Parse(tokens[4]); Dislocations[toothNo].valid = true; } sr.Close(); DisableAllCheckBoxes(); UpdateTeethAndPlanesUI(); } catch (Exception err) { sr.Close(); throw err; } }
void CalculateCurveFit(Common.Vbo handle) { int num = handle.selectedVertices.Count; var pointsMat = new MathNet.Numerics.LinearAlgebra.Double.DenseMatrix(num, 3); var points = new Vector3[num]; //get selected points for (int i = 0; i < num; i++) { pointsMat[i, 0] = handle.verticesData.vertices[handle.selectedVertices[i]].X; pointsMat[i, 1] = handle.verticesData.vertices[handle.selectedVertices[i]].Y; pointsMat[i, 2] = handle.verticesData.vertices[handle.selectedVertices[i]].Z; points[i] = handle.verticesData.vertices[handle.selectedVertices[i]]; } //find the plane which holds the least distance to all ponits using SVD Common.Plane curve_plane = NormalPlane(pointsMat); curve_plane.valid = true; Planes[GetSelectedVbOIndex() - 1][CURVEPLANE_INDEX] = curve_plane; if (Planes[GetSelectedVbOIndex() - 1][OCCLUSALPLANE_INDEX] != null && Planes[GetSelectedVbOIndex() - 1][OCCLUSALPLANE_INDEX].valid) { double angle = Planes[GetSelectedVbOIndex() - 1][CURVEPLANE_INDEX].Angle2Plane(Planes[0][OCCLUSALPLANE_INDEX]); lb_curve2occlusalPlane.Text = "Angle to Occlusal Plane: " + angle.ToString("F2"); } //calculate sum of distances to this plane double sumOfSquaredDistances = 0; double[] z_distances = new double[num]; for (int i = 0; i < num; ++i) { double d = curve_plane.Distance2Point(points[i]); z_distances[i] = d; sumOfSquaredDistances += Math.Pow(d, 2); } double rmse_z = Math.Sqrt(sumOfSquaredDistances / num); // find the x and y direction on the plane var p0 = new Vector3(curve_plane.ProjectPointOnPlane(new Vector3(0, 0, 0))); var px = new Vector3(curve_plane.ProjectPointOnPlane(points[num - 1] - points[0])); //new Vector3(1, 0, 0))); var py = new Vector3(curve_plane.ProjectPointOnPlane(Vector3.Cross(curve_plane.GetNormal(), px))); //new Vector3(0, 1, 0))); var pvx = (px - p0); var pvy = (py - p0); pvx.Normalize(); pvy.Normalize(); //project 3D points on the plane and create a 2D point set var points2DX = new double[num]; var points2DY = new double[num]; for (int i = 0; i < num; ++i) { points2DX[i] = Vector3.Dot(pvx, points[i] - p0); points2DY[i] = Vector3.Dot(pvy, points[i] - p0); } //check and fix inverse y mode if (points2DY[0] < points2DY[points2DY.Length / 2]) { points2DY = points2DY.Select(el => - el).ToArray(); } //move points to fit on the screen var xMin = points2DX.Min(); var yMin = points2DY.Min(); for (int i = 0; i < num; ++i) { points2DX[i] -= xMin; points2DY[i] -= yMin; points2DX[i] += 10; points2DY[i] += 10; } //drawing projected points var graphics = pl_curveFit.CreateGraphics(); graphics.Clear(Color.White); for (int i = 0; i < num; ++i) { DrawPoint2DOnControl(graphics, new PointF((float)points2DX[i], (float)points2DY[i]), Color.Black, 4); } //DrawPoint2DOnControl(graphics, new PointF((float)10, (float)20), Color.Red, 10); //change of parameter var diffx = Diff(points2DX); var diffy = Diff(points2DY); diffx = diffx.Select(el => el * el).ToArray(); diffy = diffy.Select(el => el * el).ToArray(); double[] t = new double[num]; for (int i = 0; i < num; ++i) { if (i > 0) { t[i] = Math.Sqrt(diffx[i] + diffy[i]) + t[i - 1]; } else { t[i] = Math.Sqrt(diffx[i] + diffy[i]); } } //fit curve params int deg = (int)nUpDown_order.Value; FitFunction fitFunction = config.fitFunction; //fit x and y to t DenseVector Wx; DenseVector Wy; try { //f = Fit.Polynomial(xdata, ydata, order); Wx = FitLeastSquaresBasis(t, points2DX, fitFunction, deg); Wy = FitLeastSquaresBasis(t, points2DY, fitFunction, deg); } catch (Exception e) { Common.Logger.Log("MainForm", "curveFit.cs", "CalculateCurveFit", e.Message); MessageBox.Show("The order of polynomial is too high and " + "results are unstable. Please use a lower " + "degree polynomial.", "Error in Curve Fitting"); return; } // create polynomial curve struct (for later to match to the wire brackets) CurveFit[GetSelectedVbOIndex() - 1].CoeffsX = Wx; CurveFit[GetSelectedVbOIndex() - 1].CoeffsY = Wy; CurveFit[GetSelectedVbOIndex() - 1].degree = deg; CurveFit[GetSelectedVbOIndex() - 1].minT = t.Min() - 5; CurveFit[GetSelectedVbOIndex() - 1].maxT = t.Max() + 5; CurveFit[GetSelectedVbOIndex() - 1].fitFunction = fitFunction; //calculate xx and yy //const double stepSize = 0.01; //double mint = t.Min(); //double maxt = t.Max(); //int numCurve = (int)((maxt - mint) / stepSize); //double[] tt = new double[numCurve]; //for (int i = 0; i < numCurve; i++) //{ // tt[i] = mint + stepSize * i; //} //var TT = MakeBasis(tt, fitFunction, deg); //var XX = TT * Wx; //var YY = TT * Wy; Tuple <DenseVector, DenseVector> tempTuple = ParametricPolynomial_to_2DPoints(CurveFit[GetSelectedVbOIndex() - 1]); DenseVector XX = tempTuple.Item1; DenseVector YY = tempTuple.Item2; DrawCurve(graphics, XX, YY, Color.Blue); //least squares //DenseVector W; //try //{ // //f = Fit.Polynomial(xdata, ydata, order); // W = FitLeastSquaresBasis(xdata, ydata, fitFunction, deg); //} //catch (Exception e) //{ // MessageBox.Show("The order of polynomial is too high and results are unstable. Please use a lower degree polynomial.", "Error in Curve Fitting"); // return; //} //draw the blue curve //DrawCurve(graphics, W, xdata.Min()-4, xdata.Max()+4, fitFunction, deg); //calculate Error //var rmse_xy = CalculatePerpendicularDistancePointToCurve(xdata, ydata, W, fitFunction, deg, graphics); double[] xy_distances; int[] closestPointsIndexOnCurve; var rmse_xy = CalculatePerpendicularDistancePointToCurve(points2DX, points2DY, XX, YY, graphics, out xy_distances, out closestPointsIndexOnCurve); //fill the list view with point distances lv_pointDistance.Clear(); lv_pointDistance.Columns.Add("Pt", 20, HorizontalAlignment.Center); lv_pointDistance.Columns.Add("off", 40, HorizontalAlignment.Center); lv_pointDistance.Columns.Add("intra", 40, HorizontalAlignment.Center); for (int i = 0; i < num; ++i) { lv_pointDistance.Items.Add(new ListViewItem(new string[] { i.ToString(), z_distances[i].ToString("F2"), xy_distances[i].ToString("F2") })); } if (lv_pointDistance.Items.Count > 0) { lv_pointDistance.Items[0].Selected = true; } lb_curvefit_rmse_xy.Text = "in-plane RMS Error: " + rmse_xy.ToString("F2"); lb_curvefit_rmse_z.Text = "off-plane RMS Error: " + rmse_z.ToString("F2"); // write results to disk string resultsDir = "Results"; if (!System.IO.Directory.Exists(resultsDir)) { System.IO.Directory.CreateDirectory(resultsDir); } string save_path = System.IO.Path.Combine( resultsDir, "CurveFitResults_" + GetSelectedVbOIndex().ToString() + ".csv"); var writer = new StreamWriter(save_path); writer.WriteLine("Point Number,X,Y,Z,Projected on WirePlane (X),Projected on WirePlane (Y)," + "Nearest Point on 2D Wire (projected wire) (X),Nearest Point on 2D Wire(projected wire)(Y)," + "InPlane Distance,OffPlane Distance"); for (int i = 0; i < num; ++i) { writer.Write(i.ToString() + ","); writer.Write(points[i].X.ToString() + ","); writer.Write(points[i].Y.ToString() + ","); writer.Write(points[i].Z.ToString() + ","); writer.Write(points2DX[i].ToString() + ","); writer.Write(points2DY[i].ToString() + ","); writer.Write(XX[closestPointsIndexOnCurve[i]].ToString() + ","); writer.Write(YY[closestPointsIndexOnCurve[i]].ToString() + ","); writer.Write(xy_distances[i].ToString() + ","); writer.Write(z_distances[i].ToString()); writer.WriteLine(""); } writer.Close(); status.Text = "Results of curve fitting are saved in: " + save_path; }