Exemplo n.º 1
0
        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);
        }
Exemplo n.º 2
0
        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(); ;
        }
Exemplo n.º 3
0
        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);
        }
Exemplo n.º 4
0
        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);
            }
        }
Exemplo n.º 5
0
        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);
        }
Exemplo n.º 6
0
        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);
        }
Exemplo n.º 7
0
        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);
            }
        }
Exemplo n.º 8
0
        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());
        }
Exemplo n.º 9
0
        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);
        }
Exemplo n.º 10
0
        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);
        }
Exemplo n.º 11
0
        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;
                }
            }
        }
Exemplo n.º 12
0
        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;
            }
        }
Exemplo n.º 13
0
        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;
        }