A CURTA model II mechanical calculator is simulated in its visible operations. In the drawings below you see the machine in a front view at the left and a top view at the top right. For ease of understanding a synoptic view of the registers is added at the bottom right.
Click the "Show Legends" button to show the names of the parts and the points where you can click to operate the machine (input register sliders have to be dragged).
Like most mechanical calculators the CURTA has an input register where the user selects the digits of a number, a result register where the result of arithmetic operations are shown, and a counter register that counts the number of times the crank has been turned.
A CURTA model II is used for this simulator: it has 11 input digits, 15 result digits, 8 counter digits and 8 shift positions.
No images are used: all you see is made with vector graphics.
The simulator only shows how to operate the machine. It does not show how the carry mechanism is implemented, how the clearing of registers works internally, how the ten's complement is computed. I.e. the simulator lets you operate the machine but it does not tell you how it actually works.
Parts shown are:
There is no attempt at 3D visuals even though SVG allows some. The front view is "flattened" on purpose because the number of input digits on the model II is too high for them all to be visible at once from the front. The impact of this flattening on operation is unimportant. The most significant deviations from a real view are:
Though the resulting image looks "flat" it still has the same silhouette as the real machine. Using very dark colours, turning the crank in front view did not give any impression of it passing in front first and then in the back before returning to its resting position. Therefore I opted for a much lighter colour for the thin vertical side of the crank and the handle bearing under the crank.
The top view displays the machine as accurately as I could make it.
The commas/thousands separators are not shown. On the real machine there are three in the bottom groove and six in the top cover groove. Their presence is not necessary for understanding how to operate the machine. I may add them later.
When the crank is turned slowly on the real machine, it is obvious that the carry mechanism is not simple at all. I don't quite understand it…
Thus, for the cap:
To work with whole numbers, the dimensions of the actual machine are expressed in tenths of a mm, thus what in reality would be 3.4mm would here be expressed as 34. Angles are in degrees and to avoid dealing with negative angles they may be greater than 360.
Objects are generated around 0,0 as their object centre, then transformed as needed.
There are 15+8+11 = 34 digit wheels. Each digit wheel on the cap is represented as a black background rectangle with a white digit. Since the digits need to change, each digit is a clone of one of ten digit glyphs.
The digit glyphs were designed by hand in SVG, trying to match the real digit font as close as possible. Their form may still be tweaked in the future. Because of pixel-size differences some digits may not look perfect in all postions in all registers. However, there are really only 10 separate designs.
Top circle: (in 0.1mm)
inner diameter: 510
digit width: 25, inter-digit space: 42, inter register space: 72
angle between digits: 15º
15x(14+7)=315, leaves 360-315=45, or 22.5º on each side between the registers.
In the figure at the right, let 0º pass through the centre of the result register's first digit. Let angles increase clockwise (they do so in SVG anyway). Then:
This helps in deciding when to set a digit to 0 as the reset handle passes over it.
In the real machine there is something sophisticated going on: when the clearing handle turns clockwise, digits are cleared slightly ahead of the handle, if it turns counterclockwise they are cleard slightly after the handle passes over them. But this happens only at the start of the clearing operation, towards the end (before the handle reaches its resting position) digits closer to the handle and finally under the handle are cleared. This is very difficult to simulate, I decided to clear a digit only under the handle so that we don't even have to simulate the rotation of the digit wheels.
The handle has two resting positions: one in each of the centres of the register separation spaces (which themselves are -22.5/2 = -11.25º away from a digit's centre). These positions are at 337.5º (resting position 1) and 232.5º (resting position 2). However:
The problem with clearing the result could also be solved by using two different values for resting position 1: 337.5 for the counter and -11.5 for the result. This solution is effectively used by comparing with cRegisterDivide1-360 in the result procedures.
To make it easier to decide when to clear a digit as the clearing handle passes over it, we move the clearing handle in increments of 5º, but because it starts at either -11.25º or 221.25º we begin by putting it at a whole multiple of 5º: -10 or 220º . Then, as its angle modulo 15 is zero, we clear the digit corresponding to its position.
Both resting positions are taken to be at positive angles. After clearing the handle has to be in the other resting position. This makes a more general mechanism so difficult that it is easier to use four unfortunately very similar routines rather than trying to fold them up into one.
All graphics are fairly simple SVG objects. There are no images, only vector graphics.
Trick for those who want to play with the code: option-clicking (alt key) on the Show Legends button displays a grid of 100x100 units and a circle around the path of the clear handle. This aids in positioning elements.
Using stroke-dashoffset to simulate rotating the cap in front view works well but is of course a trick. It avoids having to clip.
All graphic objects that are referred to by id have their handle stored during the setup phase, so there should not be uses of document.getElementById after setup. During setup (i.e. inside the Setup() function) there are a few local references, used only to position graphic elements.
A few numbers remain in the code: they are small offsets to make things look slightly prettier and it was deemed not worth the trouble to define them as parameters: they would have needed very long names and are used only once and only during setup. An example is the distance from the top cover of the CURTA name. These numbers are marked in the code with the word tweak.
To handle the illusion that in the front view the crank passes in front of the axle there is a small section of a slightly lighter colour which is painted "in front" or "behind". Its shape is calculated at each angle, but is geometrically different in certain sectors of the total crank revolution. Since the crank angle increases uniformly, it is easy to know in which sector we are by looking at which crucial angles have already been passed. This is quicker and simpler to program than testing against a set of upper and lower limits.
Handle animation requests by queueing them and finishing one before starting the next.
Animation procedures all use setTimeout to call themselves until a condition is met.
To recognise them easily their names start with "Do". They are:
None of them uses parameters (those are set up in global variables beforehand). They cannot be called directly, the procedures that need them must push a request onto the queue.
We assume that moving the cursors of the input register and switching the counter do not use any time (i.e. will always be terminated before the user has time to start another interaction).
The animation requests are pushed onto an array gAnimation. The function Animate checks the queue at reasonable intervals (say every 100ms) to see if anything is on it, locks a semaphore (gDone) and waits until that is unlocked by the animating procedure before starting the next animation on the queue.
The real machine has mechanical interlocks: a new operation can only start when the previous one is finished. E.g. it is not possible to lift the cap while the crank is not in its rest position. Queueing the requests simulates this well enough.
At first the digits were taken from Helvetica, no font was found to be closer to the Curta's digits. A possible solution would be to use a path for each digit instead of a font glyph, and this was ultimately adopted. There is no noticeable increase of processing time.
An attempt was made to use SVG filters to show some 3D and lighting effects. These do introduce a noticeable delay when clearing registers because the clearing handle has to be redrawn with a different lighting at each position, and furthermore the two little buttons have to be separate with a separate filter. Finally, the filters turn with the objects, it is impossible to fix them to a different frame, they do not work in Firefox and there is no way to modify their attributes satisfactorily. In the end I abandoned them infavour of simple flat fills. It does not look too bad.
The real machine in front (side) view is a cylinder. On the model II not all input digits are then visible and also the counter inversion switch is most of the time out of view. At first I rolled the cylinder out flat, but then the cap's 15 digit positions become very wide and the counter switch is far away to the right. To cope with that I took a few liberties: move the sliders closer together, only show 11 positions of the cap at a time and put the counter switch adjacent to the first input slider.
Making the interslot step 1.8mm instead of 4.8mm makes the flat front image look much better and the sliders then all fit into a space that corresponds to the width of the actual machine when seen from the front. I decided to leave it flat, despite the relative ease of introducing a round look to some parts.
Making the cap and bottom grips "rounded" looks worse because of lack of perspective up-down.
On my machine the crank is the only element made from plastic. There is a triangle on top of its axle centre, it points to the counter digit that is currently incremented or decremented. The paint of this arrow is yellowish, probably because of age (I bought my Curta in 1969). I used plain white in the SVG.
Most of the machine is black. To distinguish parts better, levels of grey are used as fill colours:
Symmetric paths have their origin in the centre. Rectangles have their origin at top left; Digits (unfortunately?) have their origin at bottom left instead of centre.
The real machine can only add.
When the cap is in position 1, there are four result digits to the left of the leftmost input digit. Those digits must also increment in case there are carries, and therefore inside the machine there are vertical axles for that purpose. They are identical to the axles for the input digits but their engaging sprockets are fixed at position zero (at the top).
These outlines show the SVG design elements. The small red circles show the outline's origin (coordinate 0,0 for its path).