All Grasshopper users know the pain that comes with accidentally setting off an enormous calculation, and realising we’ve done something wrong and need to cancel it.
Since Grasshopper is tied on to the Rhino process in Windows, and the whole thing is single threaded, it is very difficult programatically to allow users to cancel a calculation part-way through. Part of the reason is that the UI and the calculations share that same thread. When heavy calculations are running, there are basically no cycles spare to handle a ‘cancel’ button.
Rutten has implemented a workaround, however. By button-mashing the Esc key during calculations, some components can listen for this key and issue an ‘abort request’. This system isn’t perfect, but it has on numerous occasions saved me from needing me to completely kill and restart Rhino.
This functionality doesn’t happen automatically. The Esc key check only happens when specified within your code, so if you never check if the Esc key is down, it is impossible for the user to abort the solution whilst Grasshopper is churning through your component. We need to implement this functionality manually.
For many lightweight components, this isn’t critical. But if your component takes a long time to calculate, it’s more likely that the user will want to abort the solution while Grasshopper is calculating yours – since Grasshopper processes each component during calculation one at a time.
How to implement Esc behaviour
Grasshopper includes some useful methods to provide the behaviour we need. How it works is that, every once in a while, we check if the escape key is down as part of our calculations. If it is down, the user wants to cancel calculations. So we submit a cancel request to Grasshopper. It is then up to Grasshopper to act upon this request.
For a compiled component, we can implement the code within SolveInstance(), or within another calculation-heavy part of your code.
The following code is in C#:
if (GH_Document.IsEscapeKeyDown())
{
GH_Document GHDocument = OnPingDocument();
GHDocument.RequestAbortSolution();
}
A good place to put this code is within a loop within your component. Don’t call IsEscapeKeyDown() too often though, as it requires processing power to handle this method, which will slow down your component.
Since the GH_Document is likely constant for the life of the component instance, you could pull this out and calculate it in the constructor* at the top of your SolveInstance() – since it’s a useful variable elsewhere anyway.
References
http://www.grasshopper3d.com/forum/topics/acknowledging-abort-request
And for a rather interesting comment thread… http://www.grasshopper3d.com/forum/topics/emergency-top-for-solution-calculation
Why do you assign the GH_Document to be its own variable? If the example here, where the if statement is relatively small, it’s not too much of a problem, but if that was a larger statement (with more things being done when the esc key is pressed), then I’d recommend doing
OnPingDocument().RequestAbortSolution();
Saves extra memory waiting to go out of scope.
Also, what happens to data that has been calculated prior to the abort being called? Presumably this just gets destroyed and isn’t available? Is there an argument for threading this to give greater control over what happens when the calculations stop? I’ve found that threading it makes the whole thing slightly quicker (marginally on small components granted) but the extra control is definitely a worthwhile benefit I think.
Entirely for readability in this case. Once you understand what’s happening, there’s nothing stopping you from using the one line alternative.
Usually, and in accordance with the Grasshopper paradigm, if we are aborting a solution then we are also not interested in the data that has been calculated so far. Threading is suitable in the rare cases where this isn’t so, but given that most GH developers are learning to program as they go, the principle of Keep It Simple, Stupid definitely applies here.