Checkpoints feature (to restore a state when printing fails)

Hi

I recently added a feature we called "Checkpoints", that consists in keeping in memory some state information in order to be able to restore previous states if something goes wrong. I think it might be useful for you.
A typical use case would be: you start printing something big, you go to sleep, and the next day you realize that you run out of plastic or something went wrong and left the model partially printed, this feature allows you to go back and generate a new code to continue from any of the checkpoints kept in memory (in a similar way to postponed jobs, but without storing that information in a file).

The way to use it is:
Start printing as usual.
Once you detect something went wrong, Kill the job (it works also if printing ended obviously). Checkpoint information is kept in memory until you start a new job.
Open checkpoints dialog. This dialog allows you to walk the checkpoints going back and forward, in order to select the right checkpoint. Once you found the right one, you select the continue button, and it generates a new gcode with the code to continue this job. The code is generated in a similar way it's done with postponed jobs (actually, it's the same code).
When open, this dialog will display a 3d view of what would be printed until the current checkpoint if option "Preview checkpoint" is enabled.
In order to find the right checkpoint, you have the following tools (which will be explained later):
- Next/previous checkpoint
- FF/Rew (the same as next/previous but faster)
- Go to next/previous layer
- Go to first/last checkpoint
- Lock Z
- Go to checkpoint in current layer
- Go to checkpoint nearest to current position
And two options:
- Show checkpoint position in 3d view
- Move nozzle to checkpoint position
- Preview checkpoint.

If "Preview checkpoint" is enabled, the 3d view will display a view of current checkpoint. This will show what was printed up to that checkpoint.
Option "Show checkpoint position in 3d view" is useful to move among checkpoints. If enabled, each time you move, it will update the 3d view, which is useful to discover which is the right checkpoint. This is useful, but if you need to move fast, refreshing makes this process slow, so, you can disable this refresh.

When printing fails, it usually ends up printed up to a layer, which might also be partially printed.
In order to find where to continue, you should use the printer manual control to move the nozzle to the nearest point to where printing ended. Then you use "Go to checkpoint nearest to current position", or "Go to checkpoint in current layer", to move the memory cursor up to that point.
"Go to checkpoint in current layer" moves to the first checkpoint in a given layer. "Go to checkpoint nearest to current position", instead, searchs among the checkpoints in the same layer the one nearest to current position.
If you enable "Move nozzle to Checkpoint position", each time you move the cursor in memory, the nozzle moves up to that position. This option is disabled by default, because it can be dangerous (for example, if you go to the first checkpoint, the nozzle will probably collide with the model!!!!!). If this option is enabled when you use "Go to checkpoint nearest to current position" or "Go to checkpoint in current layer", it will move the nozzle to the checkpoint position.

In order to reduce the risk of colliding the extuder with the model, once you found the right layer, you can lock the z position using "lock z". This only locks the z position when moving among checkpoints. This disables some of the options because they might move to different layers.


The way it works
When printing, I added some event listeners when position changes to capture some state information. When it changes the z position, it stores a checkpoint (this behaviour can be disabled). When it moves, it counts how many movements were made, and if it reaches a number of movements (which can be configured). I set 10 steps as default. 100 is good enough in many cases and needs less memory. Storing a checkpoint every 1 movement usually makes no sense at all. It doesn't provide a real advantage and it makes really hard to navigate checkpoints.
In order to be sure job data doesn't change, I keep a copy in memory.
I tested how much extra memory this feature needs. With a 31mb model using the virtual printer. Without the checkpoints feature, it used 551Mb. With checkpoints every 100 movements and every layer, it used 594Mb. With checkpoints every 10 movements and every layer, it used 608Mb. With checkpoints every 1 movement and every layer, it used 745Mb.
These values varies among different tests.


How to configure it
I added a couple of options to Repetier General Settings:
- Create Checkpoint on new layer (to create checkpoints when z changes)
- Create Checkpoint on number of movements (to create checkpoints every N movement)
- A textbox to set the number of movements.

Additional comments
- The code is prepared for cases when you print objects using slic3r sequential printing, but it was mostly tested with only one printing. In order to handle cases like that, I detect when the nozzle goes down, and consider it like "another stack". This modifies a bit the way the user uses this feature, because when I move up and down among layers, I try to keep in a stack, as different stacks could differ their distance from bed.
- The FF and Rew speed is prepared to be configured if desired using the registry ("ffAndRewSpeed", default 20), but I didn't add this configuration to avoid making the configuration screen bigger with parameters that really aren't that important. Maybe you have other params like these. If so, you might want to add it.
There's another "indexingMaxLayerHeight", which is the vertical distance it will go at most when searching for the current layer. That is, when you ask Repetier to locate the checkpoint at a specified layer, it's very difficult to set the right vertical position, so, if the nearest layer found is no further than that distance, it considers that's the layer you are searching. The default value i set is 1.0 (1 millimeter).
- Default configuration for checkpoints is "enabled" both for z and N movements (with N=10). I did that because you "don't expect to need checkpoints". However, if you think it's better to have it disabled, feel free to change it.

Code status compared to the trunk
The code is merged up to the latest commit from the repetier trunk.


known bugs / things to improve:
- If for any reason you disconnect the printer while having checkpoints, when restoring the state it won't know where the home is, so, it might end up moving out of the valid area.
- Large files make checkpoints drawing slow obviously, and make it hard to navigate (this is why i added the checkbox to disable refreshing for each movement).
- I keep a copy of the gcode in memory. This might not be necessary, but I didn't feel confident enough using the same list. Probably some lists copying are unnecessary.
- if you try to view checkpoints from a postponed job, you will notice it will have a couple of initial steps, which are when the nozzle moves to go to the initial position to continue printing. These extra movements, may bother a bit because they are at a different distance from the bed compared to the rest of the model, which sometimes make it harder to navigate.
- It would be useful to add checkpoint per distance instead of number of movements. For example, if you have a square and a circle, steps in the square move much further than steps in the circle.

Additionally, I added some missing spanish translations.

Feel free to ask me any questions if you need to eai@eoconsulting.com.ar