curveToolsLengthDecimalBEZIER.zip (2.5 KB)
Hi,
I’ve updated the code (see attachment) to use Decimals instead of floats, which should in theory allow for as high a precision as one would like (default is 24, which should be more than enough). I started out by just ‘decimalising’ the curve parameter, but that didn’t really work out that well, so I decided to decimalise the whole thing.
In order to test the accuracy of the calculation, we need some curves whose lengths can be analytically calculated (to any desired precision). I’ve been testing this on 2 such curves (both with 1 segment): a straight line and a parabola. Here are the control points (in the xy-plane; from left to right; with x in [0 to 3]):
- line: (0, 0), (1, 0), (2, 0), (3, 0)
- parabola: (0, 0), (1, 0), (2, 3), (3, 9)
The length of the line is obviously 3, and the length of the parabola is (possibly a bit less obviously) about 9.747. You can call the static method CalcLengthParabola39() to get this length to any given precision. Also note that these control points really do result in a 1st and 2nd degree polynomial, respectively, and not in some ‘degenerate’ case of a 3rd degree polynomial.
Of course, these control points are vectors which are input through the GUI, and whose components are probably floats. If these are ‘floats’ in the pure python sense, I think they should actually be doubles (in the C sense), and should (at least in my case, on a 64-bit system) give a resolution of 128 bits, which would give an accuracy of about 33 decimal digits (http://en.wikipedia.org/wiki/Quadruple-precision_floating-point_format). Somebody please correct me if this is wrong. This seems worth mentioning, since we probably can’t do better than the resolution of our inputs.
Now it gets a bit weird. As can be seen from the control points above, our test curves are both defined by (small) integer coordinates (0, 1, 2, 3 and 9). One would assume these have an exact representation when they are converted into floats. This indeed seems to be the case; there are some global functions in the script that allow you to check this (near the bottom; TestPrecisionIntegerFloats*()). One might therefore think that, for these specific curves, since the inputs have an infinite precision, one could derive the length of the curve to any desired precision. That, however, is apparently not true.
The DecimalCubicBezierCurve class contains some logging capabilities. Especially the inputs are interesting (method LogBezierControlPoints()). For the line, everything works as expected. For the parabola, however, we immediately drop to an accuracy of about 7 decimal places for some of the coordinates (1 and 2), even though those coordinates have the same precision (whatever it may be) and are input in the same way (through the GUI). I really don’t understand what is going on there. Btw, please note that I’ve left out the world transformations for now, in order to narrow it down.
Anyway, for good measure, I should probably mention that I already have a good enough accuracy for my intended purposes. So it’s not that I expect to have a decimal precision of 24 digits always and everywhere, because that usually doesn’t make any sense. So you might want to look at this as a rather theoretical exercise. Actually, what worried me in the beginning of this pursuit, was that, by increasing the precision/nrSamples parameter, you could get a much more inaccurate result. I wasn’t quite expecting that, certainly not for the (rather small) precision range I was interested in.