This is your lucky day. Not only do I work with plotters every hour at work, I’ve actually solved (almost) this exact problem.
(Some of this will be plotter information that is known to you, but I’m including it for everyone else)
Fundamentally, your plotter is capable of movement in the X and Y axis, in a series of discrete movements controlled by stepper motors which can move the plot head in multiples of their minimal distance. This means that the plotter head is capable of being placed anywhere on a large grid of points, a lot like a graphical display is broken up into pixels, and it can be moved in between these points, but it cannot be stopped in between two adjacent points.
Your plotter also has a Z axis - the ability to lift the plot tool off the plot area - but this is not relevant to our discussion.
Drawing a line aligned with either axis is simple. Maneuver the head to the beginning of the line; tell the appropriate stepper motor to execute a number of steps, which will be (length of line along axis) / (distance of each step).
However, when a line is not aligned with an axis - i.e., it has a slope or a curve - the solution is quite different. Here are the two cases to consider.
Straight line between two points
The solution to this depends on the capabilities of your plotter’s controller. If your plotter can correctly handle a command like “move 100 X steps and 71 Y steps”, then the case is solved. Problems may arise if the plotter’s internal calculations are not implemented in a way that correctly spreads any division/rounding errors across the entire length of the line, or discards them, both of which will cause inaccurate lines.
If the plotter produces errors, you’ll need to decompose your straight line down into line segments that the plotter can produce correctly, in a way that accounts for division and rounding. You will need to determine how small your lines must be - this will depend on the plotter’s controller. Generally speaking, you would recursively bisect your line, creating new line segments, until the line segments fall at or below the accuracy threshold of your plotter. Instead of “move 100 X steps and 71 Y steps”, you’ll have a very long list of commands that look more like “move 2 X steps and 1 Y step”, “move 3 X steps and 2 Y steps”, etc.
Cubic Bezier curves
SVG uses cubic Bezier curves to define all of its paths where the line connecting any two points is not straight. Although the math behind Bezier curves is complex, it isn’t hard to implement and should be approachable for most developers.
Essentially, Bezier curves are described by parametric equations that defines a point on the curve at a percentage of its total length - T - where T ranges from 0 to 1. If you run the equations from 0 to 1 in .1 increments, you will produce 11 sets of (X, Y) coordinates and can draw a straight line between them to approximate the curve. This is a process called “flattening” - you are converting your curve into straight line segments.
However, using .1 is not a solution that will work in every circumstance. For example, the curve may have some wild loops and turns, and using .1 will produce a very jagged curve because the resulting line segments are too long. A smaller value will produce shorter lines and will approximate the curve more accurately.
The accuracy - or inaccuracy - of your flattening algorithm is thus controlled by the T increment (.1 in our example) and is referred to as “flatness”. Choosing the right flatness value is, again, related to the accuracy of your plotter, because it defines how small the resulting line segments are.
It is also acceptable to use variable T increments over different parts of the curve, depending on how “curvy” they are; some areas of the curve can be described using large T increments, while others require a smaller value.
For your situation, there are two approaches:
-
For each curve you encounter, use a T parameter to generate straight line segments. If any of the line segments is too large for the plotter to accurately render, re-do the flattening using a smaller T parameter until all the line segments are acceptable to the plotter.
-
Recursively bisect your Bezier curve until you produce a series of sub-curves where the starting and end points of each curve describe a straight line that can be accurately rendered by the plotter.
Approach 1 is probably the eaiser approach, but can produce too much accuracy in some areas of the curve, which may results in slow or odd output on the plotter. Approach 2 will produce ideal accuracy across the entire length of the curve but will be more complex to implement.
Caveats
The approaches outlines above for line and curves work for statically defined objects in an SVG file. However, SVG includes commands to transform vectors - for example, reflect, rotate, skew. These are beyond the scope of this discussion but must be taken into account if you expect to correctly render any SVG that follows the format spec. Again, the math surrounding these transformations is complex but not too difficult to implement. That said, getting your implementation right will be challenging; I would suggest you look into libraries that would distill a SVG file down to just straight lines and Bezier curves. This would hopefully also help your code deal with text.