Does RRF support 3d arcs?

Let's get some cubic splines now!

@bot said in Does RRF support 3d arcs?:
Let's get some cubic splines now!
Does any slicer actually generate them?

@dc42 Not that I am aware of. Fusion 360 should be able to, but it does not afaik.
By the year 2030 at the latest, I plan to have PrusaSlicer slicing STEP files directly, and outputting fitted bezier curves for all perimeters (that are not perfectly straight nor simple arcs).
So, no rush.

From what I have understood, the tricky thing to get right when extruding along Bézier curves is the filament extrusion rate. The G5command, as it is defined in Marlin, gets the total amount of extrusion for the curve, but to calculate the extrusion rate you also need the length of the curve. The problem is that there, apparently, exists no closed formula for the curve length. The length can be estimated numerically by simulating the move, but this is hard to realize in real time; you can not start the move without knowing the entire curve length.
I have not looked into the Marlin source code recently, so I do not know how they solve this.

@örjane This, among other difficulties, is why the ETA has been pushed to 2030.
Also, offsetting bezier curves is nontrivial, e.g., for the inner perimeters (and the outer perimeter, too, because it must be offset in by half an extrusion width).
I spoke with merill of SuperSlicer once about it, and we agreed that forcing approximations of the correct bezier curve to fit highlydetailed faceted polylines would be the easy/perhaps best approach. Thus, we could steal the length from that prototype highresolution polyline.
Currently, the mesh limits the polyline resultion. If no mesh were limiting the resolution, then the douglaspeucker algorithm limits the polyline resolution.
We can generate an overlyhighresolution polyline to fit bezier curves to. Basically, the slicing would work as it does now, but using STEP files as input and discretizing the polylines to very high detail. The perimeters would be offset like normal. It is only after we have the properly offset segmented polylines for all perimeters that we then generate and force to fit approximations of the required bezier curve  they would technically not be the identical tothemicron bezier curve that the STEP model has on its outer surface, but it would be close.
The purpose of the bezier curves is not to get higher resolution curves: we can already max out the resolution of the mesh and get smoothassilk curves.
Instead, the point of bezier curves is to print those smooth curves fast, because hopefully the throughput of processing those splines would be faster than the many gcode moves required to define a high resolution sequence of G1 moves.

@bot I looked briefly into the Marlin source code for G5 and, as expected, they do not solve the problem with extrusion rate. They seem to use the tparameter (that runs from zero to one along a Bézier curve) to linearly control extrusion. That code is actually marked with a "FIXME" comment. For simple arclike curves, this may be good enough, but for wilder Bézier curves the extrusion rate will vary considerably along the curve.
Since the slicer does not have to work in real time, and, as you say, often already has the curve represented as line segments, it would be good if the slicer had some way of telling the firmware what the curve length is. One obvious solution would be to have the curve length as an extra parameter to G5.

That is interesting info thank you for looking at the marlin source.
One thing I forgot to mention: when merill and I were discussing it, we realized that the beziers would have to be chopped up arbitrarily. As in, there might be multiple fitted "close enough" bezier curves for what would ideally be a single curve. This is because the offset of a bezier curve can, I think, never (or maybe just not always) be represented by a slightly different single curve.
I forget the specifics, I may be misremembering, but the information seemed to be somewhat common knowledge when I was googling it a year or so ago.

@bot You might be interested spending 30 minutes watching this: https://youtu.be/aVwxzDHniEw . I enjoyed it a lot!

Well, that came out just great  smooth and all the detail showed up. Thanks. For scale the nearer lizard is about 1.5" long.

That looks awesome!

This post is deleted! 
@alankilian Thanks. The finish is really glossy so it shows the machining ripples well in this light and they're just spot on.

I wrote an experimental slicing script for doing parametric slicing. Computing the offset curves is too hard in my opinion. Instead you should only make the outer perimeter a parametric curve and discretize the inner extrusions as usual.
The framework i use for slicing will also output bezier curves (converted from bsplines) that are of degree 5 etc. As I see it Marlin/GCode Standard only supports degree 2/3 which is quadric/cubic. This means you would need support for higher degree curves as well.
So the best way I currently see is doing some sort of curve fitting inside the slicer or the Duet. Maybe even assisted based on a parametric slice. Modern CNCs can already do this kind of fitting. I think I read something about it on a Siemens control unit.

@seeul8er perhaps implementing bsplines in RRF would be a better way forward than implementing bezier curves?

@dc42 I'm not sure, but I do not think Bsplines would be easier to implement or use.
From what I understand, there are two problems with Bézier curves in this context:
 The length of the curve is unknown beforehand.
 Drawing with an offset from a Bézier curve is not itself following a Bézier curve.
The first causes problems to compute the extrusion rate if only the total extrusion is known. The second causes problems when drawing multiple walls or when the outside of an object should follow a Bézier curve.
Both these things can be avoided by defining the Gcode somewhat differently from how Marlin has done it. If the extrusion rate (mm filament per mm movement) is given as a parameter, instead of the extrusion length, this would solve the first issue. The second could be handled by an optional offset parameter to move the tool with an offset (along the normal) to the curve. Both these things would be fairly straightforward to implement (I think...), and potentially useful for a slicer.

@örjane I'm not sure I understand the difficulty in tracking the extrusion amount for the curve. If we specify that the curve have a constant height and width, and we follow the centerline, the extrusion should be a linear function of the length travelled, right?
Maybe I'm not thinking about it enough.
@seeul8er thank you very much for chiming in! It sounds like you have already done some interesting work. I had the same thought of only "curving" the external perimeter, but for a number of reasons I want at least two curved perimeters. I figured that, since we would already stumble on not having higherorder curves, we will be approximating the external perimeter anyway, so why not do the same for internal perimeters? Is it just that difficult to get an approximated offset, even if we output a different/larger number of curves for the inner perimeters? I thought that there should certainly be a (larger) number of closeenough curves that could fit into what would otherwise be the offset of a single ideal single bspline. I'm not an expert with this math or concept at all, so please ignore me if you wish.
If, however, we have to begin splitting the curves into a larger and larger number of curves to get the offset, then we run into the same problem as polylines: too many moves slowing things down.
I would want to at least get two perimeters in curves/splines. A single perimeter, in my experience, is not sufficient to hide the crimes of the perimeter immediately interior to it. Zigzag infill needs at least two perimeters to hide. So, the faceted inner segmentation would reveal itself at spots through a single curved perimeter.

@bot The problem with extrusion amount is that in the G5 command (as implemented in Marlin) it is specified as the total amount that should be extruded until you reach the end of the move. Since you do not know (and can't easily compute) the length of the curve, you do not know how fast you should extrude.
Regarding the need for curved perimeters, my wild idea was to let the firmware handle the offset. The slicer would then generate gcode commands for the same curve for each perimeter, but specify different offset for each perimeter. Then there would be no need to calculate any approximate curve(s) for the inner perimeters. Since the normal of a Bézier curve is simple to compute, it would not be hard for the firmware to move the tool along the offset path.

@örjane I understand now, thank you. I was forgetting that the firmware needs to calculate the move length itself to determine the extrusion rate. So, yes I think the responsible slicer will provide a length.
As for the normal of the bezier being used to automatically offset: that is a great idea. I don't see why that wouldn't work. I'm not sure how I got into thinking that the inner perimeters needed to be discrete curves.
I suppose the problem becomes selfintersection, and cases where the requested number of perimeters don't fit. It's worth experimenting with on (digital) pen and paper. I might play around with some CAD software and see how splines and curves behave more intimately.

@bot Many of the problems seem to come from how the interface between the slicer and the firmware is defined. The extrusion rate is known by the slicer but it is forced to communicate it to the firmware via the Eparameter which is the total extruded amount instead of the rate. When I think about it, this also applies to G1,2,3 moves; the slicer internally translates rate to amount and the firmware translates back to rate. I guess that for most prints, the extrusion rate stays constant over many (hundreds of) G1 moves, so there would be a potential for saving gcode file size here by only sending the rate number when it changes. Well, changing G1 would probably be too disruptive to be realistic.
To somewhat bring this back to the original topic of this thread, perhaps we should also consider Bézier curves in 3D, not only planar ones. The question about offset then becomes a bit more complicated, but not unsolvable (cross products come to mind).
As you point out, self intersections may occur if offsets are used in tight bends, but I would consider that to be the slicers responsibility to detect (when it matters). We should also note that movement along an offset curve will affect the speed and hence (again) the extrusion. Those things (acceleration, jerk, PA, input shaping) are all under the control of the firmware, so this would hopefully be handled by the existing machinery.

@örjane Very good thoughts, thank you. I can confidently say that you've progressed my understanding of the problem forward. Maybe we can move the ETA to 2029 from 2030! I'm still in no position to know where to start coding this, but PrusaSlicer already deals with beziers for SVG, though, so...

@bot I'm happy if these scattered ideas can be of some use; looking forward to 2029.
It is indeed a bit of a chickenandegg problem where to start coding; both firmware(s) and slicer(s) need to support this to be useful. One approach could be to have a converter inbetween, in the same spirit as ArcWelder, which can convert back and/or forth between polylines and Béziers.
I did not know that PrusaSlicer already supports Béziers in SVG. Interesting. Supporting Béziers in the input to the slicer is probably quite different, perhaps even independent, from using Béziers in the output (GCode). Circular holes where the axis is tilted from Z, for example, will become ellipses in the XY plane which are not well captured by circular arcs (G2/G3). I expect that Béziers could be well suited for such situations if the slicer would be able to detect them.

The thread is interesting, but I have some questions, maybe someone can answer them:
For the discussed use case here, are quadratic and cubic Bezier curves meant or are higher orders needed?
I wondered why discussion of extrusion length is important in the thread, because for CNC we don't need it.
Being able to print curves would be interesting for kinematics with rotational actuators, especially for 3D movements (helix milling).

@joergs5 I remember deciding, in the past, that cubic beziers were the right thing to use  but since then, the theory has fallen from my head and I don't remember all the details of the differences between the splines, curves etc.
So, at this stage, whatever works best is what we want. The goal is to replace a sequence of short G1 moves with more efficient definitions of smooth curves, to a closeenough tolerance that the joints of these segments do not produce undesirable motion profiles.
I could picture a series of fitted cubic curves. Complex shapes would require chains of these fitted curves. It's not exactly the intended use of beziers  I suppose you want as few curve/spline definitions as possible, ideally. However, ideally we wouldn't want a million G1 moves in quick succession, so here we are.
CNC might want to know information about the move length in order to dynamically ramp the spindle speed? I do not know exactly what tricks the CNC subtractive strategies employ, but I know there are some fun ones.
Yes, being able to do these moves in 3D would be very nice. I do not know if something about that makes it much more difficult. This is something to research, to see if we need to compromise in that regard.

@bot said in Does RRF support 3d arcs?:
goal is to replace a sequence of short G1 moves with more efficient definitions of smooth curves
Thank you explaining some details of the requirements.
In RRF, curves, but also straight lines, are divided into segments, short straight lines (if you like to say, short G1 moves). For some kinematics like scara, delta, polar, robot etc, the straight lines are not straight from the viewpoint of the steppers, because the steppers behave nonlinear. So from the view of such a kinematic, to segment a curve like Bezier, there is no difference to segmenting the curve into curved segments instead.
As I understood, the Bezier curves are often approximated anyway by the DeCasteljau algorithm, which is a recursive process and the same like a segmentation of a curve into smaller curves. So this recursion could fit nicely to a curvedlinessegmentation. The kinematics mentioned above can make curved movements, so curved milling or 3D printing will look better than short straight lines.
For the lengths of the curves, I wonder why it's a problem, because if one knows how to print a curve and know how the steppers behave, those rotational and prismatic movements can be calculated into cartesian xyz and rotation xyz changes by using jacobian matrix calculations like done by robots. Jacobian matrices contain xyz speeds and xyz angle speeds and allow calculation of cartesian speeds from stepper speeds, and other round by its inverse. The results are get by matrix multiplications of prismatic and rotational movements of the joints. Bezier offsets, if tool offsets or tool width are meant, can and should be included into the matrix calculations.
To make it short, I see a possibility to find mathematical solutions to this problem. I would even expand it into NURBS, as this summarizes Bezier and BSpline, if I understood it correctly.
The slicer could add up all the curved short segments lengths into a total length and communicate it to RRF in GCode. RRF then knows the total extrusion and if it calculates the short segments, it calculates the short segments lengths for himself (sum is same, if slicer and RRF use the same segmentation level). So the mathematical intense calculation is made by a PC and relieves the RRF processor.

So to sum this up a bit:
Curves: Bezier Curves only require the specification of control points
 BSplines will require an additional KnotVector
 NURBS Curves will require the additional KnotVector and a vector of point weights
Here is a super convenient way of understanding the differences with all the types of curves. Out of that fact, Bezier curves will require less information in the GCode file, making them smaller in size. From a computational point of view, I do think that all of the curves are fairly easy to compute and should not cause performance issues on 32bit hardware. While BSplines and NURBS sure are more complex and allow a more exact fitting of surface points with fewer curves, I think that Bezier curves will do just fine for a first implementation and looking beyond.
Slicing:
I always thought that there is an analytical solution for computing the intersection curve of a plane with a NURBS surface (pretty much all freeform CAD Data is based on NURBS Surfaces). But I am not aware of such an implementation or solution. I did some very basic research on some published papers and couldn't find any in that direction. Usually, they go and find a clever way of determining the area of the NURBS surface that intersects with the plane and then compute and sample intersection points. After that, you do curvefitting through those points and get the intersection curve as a Bezier, BSpline or NURBS. Maybe someone else got more info on that.
The script I wrote leaves all the intersection curve computational stuff to a CAD Kernel, so I have no real control over what kind of curve I will receive. That is why I was struggling when receiving bezier curves with an order of 5. If you would write a slicer from scratch you could fit multiple cubic bezier curves instead.Since the slicing described above is also just an (very accurate) approximation of the surface based on surface points, you could also slice a very detailed STL/3MF the traditional way and then postprocess the GCode in an ArcWelderLike fashion. That way you could use the robustness of the current slicers, and not have to deal with offsetting parametric curves. Something that I believe is not trivial to get right every time.
Interpreter (RRF):
As stated above: While it is pretty hard to compute the length of those curves analytically, there are numerical solutions that approximate the length. Since RRF needs to linearize (approximate the curve with tiny line segments of a defined length  Marlin uses 1mm by default I think) the curve anyways, one could use that to compute the length of the curve. In that case, you would need to precompute the entire move along the curve before actually moving the motors. I am not sure that fits into the current design of RRF.