Exemplo n.º 1
0
        /// <summary>
        /// Break each arc into lots of short straight lines.
        /// If they’re short enough no one will be able to tell the difference.
        /// </summary>
        /// <param name="center">arc center position</param>
        /// <param name="endpoint">arc end position</param>
        /// <param name="clockwise">true if clockwise motion</param>
        /// <param name="startpoint">arc start position</param>
        /// <returns>the arc interpolated as a list of straight lines</returns>
        public List <LinePoints> RenderArc(Point3D center, Point3D endpoint, bool clockwise, ref Point3D startpoint)
        {
            // see also
            // https://www.marginallyclever.com/2014/03/how-to-improve-the-2-axis-cnc-gcode-interpreter-to-understand-arcs/

            // figure out our deltas
            var    current = new Point3D(startpoint.X, startpoint.Y, startpoint.Z);
            double aX      = current.X - center.X;
            double aY      = current.Y - center.Y;
            double bX      = endpoint.X - center.X;
            double bY      = endpoint.Y - center.Y;

            // angle variables.
            double angleA;
            double angleB;

            if (clockwise)
            {
                // Clockwise
                angleA = Math.Atan2(bY, bX);
                angleB = Math.Atan2(aY, aX);
            }
            else
            {
                // Counterclockwise
                angleA = Math.Atan2(aY, aX);
                angleB = Math.Atan2(bY, bX);
            }

            // Make sure angleB is always greater than angleA
            // and if not add 2PI so that it is (this also takes
            // care of the special case of angleA == angleB,
            // ie we want a complete circle)
            if (angleB <= angleA)
            {
                angleB += 2 * Math.PI;
            }

            double angle = angleB - angleA;

            // calculate a couple useful things.
            double radius = Math.Sqrt(aX * aX + aY * aY);

            // get length of arc
            // float circumference = PI*2.0*radius;
            // float length = angle*circumference/(PI*2.0);
            // simplifies to:
            double length = radius * angle;

            // Maximum of either 2.4 times the angle in radians
            // or the length of the curve divided by the curve section constant
            int steps = Transformation.CalculateStepsAsInt(angle, radius);

            // this is the real draw action.
            var newPoint  = new Point3D(current.X, current.Y, current.Z);
            var lastPoint = new Point3D(current.X, current.Y, current.Z);
            var output    = new List <LinePoints>();
            var p         = clockwise ? PenColorList.CWArc : PenColorList.CCWArc;

            int    step;
            double fraction;
            double angle3;

            for (int s = 1; s <= steps; s++)
            {
                // Forwards for CCW, backwards for CW
                if (!clockwise)
                {
                    step = s;
                }
                else
                {
                    step = steps - s;
                }

                // interpolate around the arc
                fraction = ((double)step / steps);
                angle3   = (angle * fraction) + angleA;

                // find the intermediate position
                newPoint.X = (float)(center.X + Math.Cos(angle3) * radius);
                newPoint.Y = (float)(center.Y + Math.Sin(angle3) * radius);

                // store max and min values
                maxX = Math.Max(maxX, newPoint.X);
                maxY = Math.Max(maxY, newPoint.Y);
                minX = Math.Min(minX, newPoint.X);
                minY = Math.Min(minY, newPoint.Y);

                // and add the new line
                output.Add(new LinePoints(startpoint, newPoint, p));

                // store the last position
                startpoint.X = newPoint.X;
                startpoint.Y = newPoint.Y;
            }
            return(output);
        }