I ran out of numbers.

Ha, so I thought that a Polargraph could be as big as your piece of string, well, that’s true, but there’s a significant caveat.  Because the string lengths are represented by variables of type long, it can never be longer than 2,147,483,647 steps.  One more step, and it rolls over to -2,147,483,648.

Now that’s pretty long.  With a PolargraphSD machine, that’s 63,761,390 mm, or a 63 metres diagonal distance.   Plenty room for expansion there.

Well, not quite, because to deal with strings that long, and machines that size, we need to have some headroom.  One of the core calculations that happens in Polargraph is working out the cartesian coordinates given the native coordinates:

float getCartesianXFP(float aPos, float bPos)  {
      float calcX = (sq(pageWidth) - sq(bPos) + sq(aPos)) 
        / (pageWidth*2);
      return calcX; 
float getCartesianYFP(float cX, float aPos) {
      float calcY = sqrt(sq(aPos)-sq(cX));
      return calcY;

So squaring (with the sq(…) function) produces a much larger number than is input, and it produces a number that is larger than can actually be expressed with a long (32 bit) number. Disconcertingly, sq(2147483647L) evaluates to 1.  1! That’s not helpful.

This calculation (sq(pageWidth)) is used a lot during any vector moves, and will be wrong if pageWidth or the target move positions are any larger than the square root of 2,147,483,647.  It’s 46,340 btw, which in steps is actually about 1.3m, or very very much less than 63 metres.  I’m slightly amazed that nobody (myself included) has not come across this problem already.  I have chased this issue down after helping a customer debug their envelope-pushing setup, and I’m a bit embarrassed to be honest, all my bold chat about “it’s as big as a piece of string”, well.

So, the good news is there’s a simple solution: cast to floats during the calculation.  In principle I may lose accuracy, but in practice I don’t believe it’s in a place where it is likely to be significant.  If it comes down to it, I could cast to use a long long, which is a 64 bit int type I only just discovered existed, but in a method that takes floats as parameters, and returns floats, I think it makes sense to treat the other numbers as floats too.

The fixed method looks like this:

float getCartesianXFP(float aPos, float bPos)  {
      float calcX = (sq((float)pageWidth) - sq(bPos) + sq(aPos)) 
        / ((float)pageWidth*2.0);
      return calcX; 

Note the casting to floats when referring to the variables that are actually longs.

The fixes (firmware 1.66) are in the usual places:

Though be aware that you only need bother update, if your machine is wider than 1.3m – there aren’t any other fixes in there.

– EDIT I introduced a new issue with 1.65.  1.66 (just now) should fix it.

Webcam removed from controller

The webcam view was too unreliable, and crippled the controller app for those people who didn’t have compatible machines / cameras.  I’ve taken it out.  It will be back in future, in a safer form, but in the meantime, it caused too much havoc.

So I’ve just uploaded a new package, containing unchanged firmwares (1.63 for _a1, and 1.62 for _polarshield and _mega versions), and an updated controller (1.6) that uses the loaded image instead of the live webcam view:

Thanks for being patient!