/// <summary>
        /// Calculates the midpoint of all CircularArcs relative to the Arcs start position and
        /// clockwise direction. These points are used to help calculate the parts material size.
        /// </summary>
        /// <param name="points"></param>
        /// <param name="ObjProfile"></param>
        private static void getMidPointOfAllArcs(List<PointF> points, ObjectProfile ObjProfile)
        {
            // ... loop through each edge and scan for CircularArc's
            for (int i = 0; i < ObjProfile.Edges.Count; i++)
            {
                // ... get this Edge Type
                string str = ObjProfile.Edges[i].edgedata.Type;

                // ... we are only interested in Arcs at this point
                if (str.CompareTo("CircularArc") == 0)
                {
                    // ... get the X and Y vertices using the pointer for the start position
                    List<double> positionStart = getCoordinatesAt(ObjProfile, ObjProfile.Edges[i].edgedata.Start);

                    // ... get the X and Y vertices using the pointer for the end position
                    List<double> positionEnd = getCoordinatesAt(ObjProfile, ObjProfile.Edges[i].edgedata.End);

                    // ... the Arc may not always be 180 degrees, so calculate the arc length
                    double[] Vec1 = new double[3] { (positionEnd[0] - ObjProfile.Edges[i].edgedata.CenterX),
                        (positionEnd[1] - ObjProfile.Edges[i].edgedata.CenterY), 0.0 };

                    double[] Vec2 = new double[3] { (positionStart[0] - ObjProfile.Edges[i].edgedata.CenterX),
                        (positionStart[1] - ObjProfile.Edges[i].edgedata.CenterY), 0.0 };

                    // ... normilize the vectors
                    Vec1 = Normalize(Vec1);  Vec2 = Normalize(Vec2);

                    // ... calculate the angle between the vectors (in radians)
                    double angle = Math.Acos(DotProduct(Vec1, Vec2) / (getVectorLength(Vec1) * getVectorLength(Vec2)));

                    // ... get the point we want to rotate
                    List<double> clockWiseFrom = getCoordinatesAt(ObjProfile, ObjProfile.Edges[i].edgedata.ClockWiseFrom);

                    // ... convert the clockWiseFrom
                    double[] p = new double[3] { clockWiseFrom[0], clockWiseFrom[1], 0.0 };

                    // ... center point to rotate about
                    double[] p2 = new double[3] { ObjProfile.Edges[i].edgedata.CenterX, ObjProfile.Edges[i].edgedata.CenterY, 0.0 };

                    // ... rotate point p about the Z-Axis relative to the midpoint of the arc
                    double[] rotationPoint = rotateAboutZ_Axis(p, (angle * 0.5), p2);

                    // ... convert to the PointF type
                    PointF pt = new PointF((float)rotationPoint[0], (float)rotationPoint[1]);

                    // ... save it to the list
                    points.Add(pt);
                }
            }
        }
        /// <summary>
        /// Calculates the material size for costing
        /// </summary>
        /// <param name="ObjProfile"></param>
        /// <returns></returns>
        private static double[] getMaterialSize(ObjectProfile ObjProfile)
        {
            // ... container to hole the object x and y dimensions
            double[] size = new double[2];

            // ... container to hold all points for this profile
            List<PointF> points = new List<PointF>();

            // ... first store all vertices in the points collection
            for (int i = 0; i < ObjProfile.Vertices.Count; i++)
            {
                // ... get the point at this location
                PointF pt = new PointF((float)ObjProfile.Vertices[i].X, (float)ObjProfile.Vertices[i].Y);

                // ... save it to the points list
                points.Add(pt);
            }

            // ... calculate the midpoint of all Arcs
            getMidPointOfAllArcs(points, ObjProfile);

            // ... we now have enough points to calculate the bounding box of this part
            size = calculateBoundingBox(points);

            // ... return the values
            return size;
        }
        /// <summary>
        /// Returns the coordinates in the ObjectProfile pointed to by ptr
        /// </summary>
        /// <param name="profile"></param>
        /// <param name="ptr"></param>
        /// <returns></returns>
        private static List<double> getCoordinatesAt(ObjectProfile profile, int ptr)
        {
            // ... container to hold both x and y coordinates
            List<double> pos = new List<double>();

            // ... find the vertex we are after
            for (int i = 0; i < profile.Vertices.Count; i++)
            {
                // ... does the Id match ptr
                if (profile.Vertices[i].Id == ptr)
                {
                    // ... save the coordinates, x then y
                    pos.Add(profile.Vertices[i].X);
                    pos.Add(profile.Vertices[i].Y);

                    // ... we have the values, break the loop
                    break;
                }
            }

            // ... return the result
            return pos;
        }
        /// <summary>
        /// Calculates the Machine cost for cutting the parts straight (LineSegment) edges
        /// </summary>
        /// <param name="ObjProfile"></param>
        /// <returns></returns>
        public double getStraightEdgeCuttingCost(ObjectProfile ObjProfile)
        {
            // ... the total perimeter length of the profile
            double lengthCuttingCost = 0.0;

            // ... loop through all edges and calculate cutting cost for the LineSegment edge type
            for (int i = 0; i < ObjProfile.Edges.Count; i++)
            {
                // ... get this Edge Type
                string str = ObjProfile.Edges[i].edgedata.Type;

                if (str.CompareTo("LineSegment") == 0)
                {
                    // ... get the X and Y vertices using the pointer for the start position
                    List<double> positionStart = getCoordinatesAt(ObjProfile, ObjProfile.Edges[i].edgedata.Start);

                    // ... get the X and Y vertices using the pointer for the end position
                    List<double> positionEnd = getCoordinatesAt(ObjProfile, ObjProfile.Edges[i].edgedata.End);

                    // ... get the length of this edge (simple Pythagorean Theorem)
                    double A = positionEnd[0] - positionStart[0];
                    double B = positionEnd[1] - positionStart[1];
                    double length = Math.Sqrt((A * A) + (B * B));

                    // ... claculate the cost for this edge
                    lengthCuttingCost += (length / v_max) * MachineTimeCost;
                }
            }
            return lengthCuttingCost;
        }
        /// <summary>
        /// Calculates the material cost for this part
        /// </summary>
        /// <param name="ObjProfile"></param>
        /// <returns></returns>
        public double getMaterialCost(ObjectProfile ObjProfile)
        {
            // ... the size of the profile to be cut (x and y dimensions)
            double[] size = new double[2];

            // ... determine material size
            size = getMaterialSize(ObjProfile);

            // ... add padding to the size for the kerf offset
            size[0] += Padding;
            size[1] += Padding;

            // ... return the calculate the cost
            return ((size[0] * size[1]) * MaterialCost);
        }
        /// <summary>
        /// Calculate the cutting cost for all CircularArc's in this profile
        /// </summary>
        /// <param name="ObjProfile"></param>
        /// <returns></returns>
        public double getArcCuttingCost(ObjectProfile ObjProfile)
        {
            // ... the total perimeter length of the profile
            double ArcCuttingCost = 0.0;

            for (int i = 0; i < ObjProfile.Edges.Count; i++)
            {
                // ... get this Edge Type
                string str = ObjProfile.Edges[i].edgedata.Type;

                // ... we are only interested in Arcs at this point
                if (str.CompareTo("CircularArc") == 0)
                {
                    // ... get the X and Y vertices using the pointer for the start position
                    List<double> positionStart = getCoordinatesAt(ObjProfile, ObjProfile.Edges[i].edgedata.Start);

                    // ... get the X and Y vertices using the pointer for the end position
                    List<double> positionEnd = getCoordinatesAt(ObjProfile, ObjProfile.Edges[i].edgedata.End);

                    // ... the Arc may not always be 180 degrees, so calculate the arc length
                    double[] Vec1 = new double[3] { (positionEnd[0] - ObjProfile.Edges[i].edgedata.CenterX),
                        (positionEnd[1] - ObjProfile.Edges[i].edgedata.CenterY), 0.0 };

                    double[] Vec2 = new double[3] { (positionStart[0] - ObjProfile.Edges[i].edgedata.CenterX),
                        (positionStart[1] - ObjProfile.Edges[i].edgedata.CenterY), 0.0};

                    // ... get the radius from this vector (before its normalize)
                    double Radius = getVectorLength(Vec1);

                    // ... normilize the vectors
                    Vec1 = Normalize(Vec1);  Vec2 = Normalize(Vec2);

                    // ... calculate the angle between the vectors (in radians)
                    double angle = Math.Acos(DotProduct(Vec1, Vec2) / (getVectorLength(Vec1) * getVectorLength(Vec2)));

                    // ... calculate the arc cutting cost = $((ArcLength / (v_max * exp(-1/R))) * Machine Time Cost)
                    ArcCuttingCost += ((angle * Radius) / (v_max * Math.Exp(-1 / Radius))) * MachineTimeCost;
                }
            }
            return ArcCuttingCost;
        }