algorithmic modeling for Rhino
yes, there was an inconsistency in the script library (RhinoPython, not the component GhPython). LineIsFartherThan called a naughty version of coercecurve, that made it accept only the Line type or Python tuples.
I've changed the coercecurve function in utility.py to also allows the input of LineCurves and Guids, so your script will work, provided that you choose RhinoScriptSyntax. Hopefully life will be better also for other users. :)
You can wait for next week's release of Rhino 5 for this to be fixed automatically, or follow the instructions in the attached file to change the file today.
I hope this is helpful,
Hi Benjamin, thank you for your explanation.
I am a beginner as well, through my previous learnings, I know that there are different ways to achieve same results in Ghpython, however, I do not understand, yet, the benefit of one over another. For example, are there situations where it's better to use rhinoscriptsyntax and other situations where it is better to use RhinoCommon? Would the answer be that of course when you need GUID it is better to use rs and when you don't, RhinoCommon is better? If there is are other reasons as well I would really appreciate it if you can help me gain a better understanding, thank you!
I'm not sure Benjamin is around much anymore. Anywho, I wrote a small blurb on this subject for a workshop once that might help you here:
"RhinoCommon is the Rhino SDK (Software development kit) which is used when developing Rhino plug-ins, Rhino commands, Grasshopper components etc. It is basically the core of Rhino upon which most things code-related is developed. This includes all geometry types (curves, surfaces, meshes, points etc.), layer management, viewports, input/outputs etc. RhinoCommon is designed as a .NET style SDK, meaning that it designed to work with C#/VB (and iron languages) and is organized in a certain way. Rhinoscriptsyntax is a Python module which was designed to make it easy for people who had been using the old RhinoScript language (a more or less defunct version of VBScript) to move over to Python scripting instead. The module basically mirrors the functions found in RhinoScript by wrapping RhinoCommon functionality in "easy-to-use" Python functions. You can check out the actual source code on your hard drive*. The primary difference between using rhinoscriptsyntax and RhinoCommon is that rhinoscriptsyntax targets the actual Rhino document. That is, it operates on what is known as GUIDs (Globally unique identifier) which refer to geometries, layers, cameras etc. RhinoCommon on the other hand operates on objects which purely exist in memory. Generally this means that procedures which operate on geometry etc. will typically compute faster. When you "coerce" geometry this refers to the process of getting the RhinoCommon geometry object from a GUID. This is likely one of the bottlenecks involved when using rhinoscriptsyntax in GHPython. Another difference is that rhinoscriptsyntax is designed to write very procedural code whereas RhinoCommon is designed around Object-Oriented Programming principles. In general I would recommend any geometry related GHPython scripting to be written using RhinoCommon. That said, rhinoscriptsyntax is still a useful module for those situations where you want do something with/in the Rhino document (i.e. get something from a layer, change the color of the background etc.).
Edit I: Take all this with a grain of salt, it is based on my personal findings and experience and may contain alternative facts.
Edit II: This blurb assumes that the reader is aware that Rhino/Grasshopper implements the IronPython version of Python, where the iron prefix refers to a version of a programming language which targets the .NET Framework.
I think this is a great explanation, thanks, Anders!
The only incorrect part, in my opinion, is the "bottleneck" that would be looking up a Guid in the document. To dispel that urban myth, we need to be a little technical. The lookup is implemented as a dictionary lookup, which definitely adds a millisecond-fractional overhead per call, but being in practice "very close to O(1)", it will not add time complexity and will generally not be the bottleneck of an algorithm.
When you have an actual problem, it's easier to start, as a programming beginner, in my opinion, in RhinoScript. If you want to delve into object-oriented programming, have time to look into thousands of class methods, etc, then RhinoCommon is certainly more comprehensive and more thorough. RhinoScript itself is implemented in RhinoCommon!
In my opinion the two are just two levels of programming, both very prolific.
My 2 cents.
Cheers Giulio, and I totally agree. This particular bottleneck concern is definitely what I would consider as being an alternative fact now, a few years after writing this ;)
Wow, thank you Anders and Giulio both for your wonderful insight.
Actually, maybe it still is an issue. Just ran a quick test (haven't used rhinoscriptsyntax in years now for geometry stuff). In this particular (and granted very basic) case I'm seeing a pretty consistent behaviour of rhinoscriptsyntax being substantially less performant than straight up RhinoCommon. Granted, this test has many calls, but my point is, that in real-life production situations with many functions, iterations or even dynamic/iterative solving, these small tolls quickly add up to what I would consider as being an unnecessary penalty (or a bottleneck):
Thanks for this input, Anders.
Well, this is really a worst-case for rhinoscriptsyntax and not by far a real-word algorithm. If you want the absolute performance for this example, it should be written in a C# component and in the Grasshopper SDK. Well, it turns out I wrote and it takes 1:25-1:100 of the time* of scripting components. So the 1:7 between rhinoscriptsyntax and RhinoCommon is not even comparable to doing things with the Grasshopper SDK. We are in Grasshopper after all. In turn, I assure you a C++ plug-in in Rhino will create these points even faster, probably under 1-2ms as a reference.
Should this worry us? In algorithm performance behavior analysis, it's not the absolute time that matters (here it's rather small and the sample does not do anything useful) but the asymptotic behavior: what happens if the algorithm is run with 100 inputs vs 1000 inputs, for example. rhinoscript runs linearly, so it does not add time complexity. With 1000 inputs, if the rest of the algorithm is also linear, it will take 10 times what it took with 100 inputs. This is what really matters!
Btw, it's been some time that I have been chatting with Steve about optimizing coerce3dpoint() and coerce3dvector() more. And I want to take a spin on the Grasshopper-SDK marshaller for RhinoScriptSyntax. They will never be as fast as pure C# in the Grasshopper SDK, but I think there's some space for improvement... stay tuned.
*it often takes less, and sometimes more; sometimes so little that Grasshopper does not even show it. You can see this better by turning off all other components: mostly it depends if a garbage collection happened while running a particular component.
PS: I attached all data for the samples, so you can test this on your system and see that I did not cheat :)
Hehe, thanks Giulio :)
This is (as always) a terrific breakdown and I absolutely appreciate your points and input. The only point I was trying to make above was that if you can achieve an non-trivial increase in performance* simply by implementing a RhinoCommon method instead of the equivalent RhinoScriptSyntax function, it seems a little bit silly not to do so, even if this increase wasn't in the 4X range. That said, at this point I think my appreciation of RhinoCommon has much more to with its completeness, design and structure, than the fact that it might be faster than RhinoScriptSyntax. But again, to each their own ;)
* In the specific context of geometry creation and manipulation using GHPython (i.e. not dropping to a lower level language for performance gains, which is of course always an option, but perhaps not always a very good one).
Just for the sake of completeness on the topic of performance in the strict context of GHPython, I would be remiss not to point out the old output bottleneck concern (that is also quite apparent in your test Giulio). I've found that this can be substantially reduced by wrapping the output data in either Grasshopper.Kernel.Types or, in cases where you don't need the data directly on the canvas, in a Python list or dictionary:
Hope this might be useful to all you Python-heads :)
Nice blurb :)