algorithmic modeling for Rhino
Hi, I'm trying out a method to automate slider behavior using a GHPython component inside Grasshopper. I have taken some inspiration from this post dating already 3 years ago:
http://www.grasshopper3d.com/forum/topics/use-pythoneditor-to-run?c...
For now I am considering a simple test case in which a set of sliders are added together into a GH_number component called "output":
I am finding that from the Rhino Python Editor it is definitely possible to change the slider values and retrieve results in a loop. Below I copied the code that runs from the Rhino Python Editor, where I simply change the slider value of the slider with Nickname "Number Slider1" from 0 to 2. (note that grasshopper and the testfile are already open in this example)
This script prints out the following results as expected:
Slider value: 0.0
Result value: 1.154
Slider value: 1.0
Result value: 2.154
Slider value: 2.0
Result value: 3.154
However using the exact same code in a GHPython component within Grasshopper the Grasshopper Python Script Editor's console reads:
Slider value: 2.0
Result value: 3.154
Slider value: 2.0
Result value: 3.154
Slider value: 2.0
Result value: 3.154
It seems that the solver doesn't recompute during each iteration but just retrieves the final state of my script.
So basically I have been trying to trigger a 'runsolver' command inside my loop. I tried using the methods available trough the RhinoScript interface, as David describes here.
http://www.grasshopper3d.com/forum/topics/open-a-gh-automatically
I could create a loop looking like this:
But running this in the Grasshopper Component crashes Rhino. I have also tried this by Disabling the solver first using the DisableSolver() method. This does disable the solver but still Rhino crashes. Also I used the ExpireSolution(True) method on the slider object like:
However in this case I don't get any different results.
So I guess my question is simple:
Is there a way to recompute the solver after a slider change inside a GHPython script component during a loop?
Any suggestions, or references would be greatly appreciated!
(FYI: I am using Rhino5x64 and Grasshopper Version 0.9.0014, attached is the script I used both in the Rhino Python Editor and the GHPython component and the grasshopper file)
Tags:
Update:
To anyone listening in; I suspect the problem with this method is that only at the end of a grasshopper solution the sliders will actually be set, (and results can be collected) since the ghPython component is part of a single Grasshopper solution it cannot initiate new ones during the run.
So I have been looking at alternatives of controlling the solutions with more external sources. Options could be:
- an external application trough COM
- a static class that is accessible for custom plugin components that controls solution flow by making use of solution event handlers and scheduling of new solutions (to create loops)
I have been mostly successful in the later option;
In a nutshell this (static) class controls document related methods such as reading job data from external files (jobs) / setting slider values / and writing results. These methods are linked to event handlers triggered at solution start and solution end. A new solution is initialized using schedule solution immediately after the previous solution is finished.
Unless anyone has any brilliant solutions to make this thing work I will close this discussing soon.
cheers dion
Hi Dion, though I'm not sure I understand what you are doing (bit to exotic for me to grasp), I have a feeling my method for animating might spark ideas. Hope I sort of understood correctly~ if not, nevermind:)
Hi Pieter, thanks for the reply, I have taken a look at Galgo, it looks very interesting, I am impressed you managed to do all that with just using User Objects!
In any case the thing is that making animation curves (as you use them) for animating (or in my case sampling) trough slider values seems a bit tricky in my case, since I have no preset data on the behavior of such curves (each subsequent slider 'state' is likely to be unrelated to its predecessor.
In this way states are generated either by some program outside grasshopper that just provides a bunch of predefined samples, or an optimization algorithm is basing new states on the results from previous ones.
This plugin is supposed to turn Grasshopper into a sort of worker than can run in parallel on a server with other workers. They will poll to some database for jobs (containing slider values and their corresponding nicknames). Once jobs are placed into this database, the workers will run. And fill some other database with results. I hope in this way to achieve high performance for heavy analysis tasks, for for instance structural optimization. So in a way there is no need for user interaction during these runs in Grasshopper. And visualization is something I will deal with after all the results are collected.
I hope this makes it a bit clearer.
Still thank you Pieter for the suggestion, I will definitely take a closer look into your tool.
Dion
This is interesting!
I will take a look at it a soon as I find some spare time.
Just one question D. Have you tried the same routine within a VB or C# component?
Best,
M.
C#, the methods are mostly handled by event handlers that are registered in my plugin but outside of any physical component contained in the plugin. The event handlers will be registered once you start to use the components.
If you are interested take a look at my other discussion (that has been resolved I guess) where I explain the construct:
http://www.grasshopper3d.com/forum/topics/creating-background-recor...
Anyway for finding a component in the canvas per nickname or guid goes something like this:
public IGH_DocumentObject FindComponent(GH_Document ghDocument, string name = null, string guid = null)
{
/// Method to find a object in the canvas returns IGH_DocumentObject (Cast to proper component format to use)
/// Iterate over all objects inside the document.
for (int i = 0; i < ghDocument.ObjectCount; i++)
{
IGH_DocumentObject obj = ghDocument.Objects[i];if (name != null)
{
// Test the NickName of the object against the search name.
if (obj.NickName.Equals(name, StringComparison.Ordinal))
{
if (obj != null) { return obj; }
}
}
if (guid != null)
{
// Check for component based on component Guid
if (obj.ComponentGuid.Equals(guid))
{
if (obj != null) { return obj; }
}
}
}
return null;
}
Then once you have a list containing the nicknames and their corresponding values you can set them like:
for (int i = 0; i < nicknames.Count; i++)
{
try
{
GH_NumberSlider slider = (GH_NumberSlider)FindComponent(document, nicknames[i], null);
slider.Slider.Value = (decimal)values[i];
}
catch (Exception e)
{
throw new ArgumentException(e.Message);
}
}
Again I am only doing this once per every solution(run), since changing the slider trough this method does NOT invoke a new solution to start (as it would when you change a slider manually). Therefore you set it / obtain results / schedule a new run and repeat. At least that is the only way I could come up with. Hope this helps!
Dion
In a few custom components I use I have made sure that when a new slider for example is connected to the input of the component, it will get a specific predefined range.
I am sometimes experiencing a few problems with naming this specific slider, but when a second slider is connected thus a new solution is invoked the name changes as well.
I haven't spent proper time looking this out , so this might be a good chance to get into it.
Again to schedule a new (dummy) run as you say might not be the best practice, it sure though is the logical one.
Hopefully i will have something to add .
Best,
M.
Nice Cool!
I had also thought it every day.. cause slow GH.!
adding...
each Evaluation place division.
but GH is Greatest Ultra Fantastic Tool in Universe~~.
:)
Welcome to
Grasshopper
Added by Parametric House 0 Comments 0 Likes
Added by Parametric House 0 Comments 0 Likes
Added by Parametric House 0 Comments 0 Likes
Added by Parametric House 0 Comments 0 Likes
© 2024 Created by Scott Davidson. Powered by