How access UserDictionary in Python?

python

#1

OK, I didn’t sleep last night because the following drives me nuts: How can I access the UserDictionary with PythonScript of :

  1. a Rhino object selected by the user,
  2. or a Brep, or Geometry in GH (what is the difference BTW?)

For the Rhino object I tried things the following for hours, but no matter what I try I get the error message “Message: 'builtin_function_or_method' object has no attribute 'UserDictionary'

obj = Rhino.Input.Custom.GetObject()
obj.SetCommandPrompt("Select objects")
... blah, blah

for i in range(obj.ObjectCount):
    # Nope:
    o = obj.Object(i)
    o.UserDictionary.Set("KEY", "VALUE")   <-- Nope, error
    # Nope:
    g = o.Geometry
    g.UserDictionary.Set("KEY", "VALUE")   <-- Nope, error
    # Sigh....

Nada. I picked a solid Box and a Sphere, but no UserDictionary.

Obviously I have no idea how the basic concept works. I’ve created zillions of getters and setters in my life, and key value pairs isn’t exactly rocket science, so that’s not the problem, but where is the friggin dictionary? (And yes, I see them in the documentation but nowhere to be found in the code… :slight_smile: )

And BTW, what is a ‘Geometry’ as opposed to an “Object” in Rhino (the difference)? And despite the difference, shouldn’t both have the UserDictionary?

OK, perhaps I need some sleep, but if anyone has a python code snippet to share, please. And explain the concept (which should be obvious, I mean, if you just find the dict… )

// Rolf


#2

Hi Rolf

hmmm …
in RhinoCommon both GeometryBase and ObjectAttributes have GetUserString() and SetUserString() methods.
Are you talking of something else ?


#3

… and UserDictionary. Are they the same thing? I find the form UserDictionary.Set("key", "value") in the documentation. When I try GetUserString() and SetUserString() in the code above I get the same message: “Message: 'builtin_function_or_method' object has no attribute 'GetUserString'

I’m entirely lost.

// Rolf


#4

I cannot really answer your question, but generally things work as you expect them to work. You just seem to look in the wrong place: UserDictionary.gh (5.0 KB)


#5

The Breps in GH is OK, but where I prove to be RILStupid™ is with the regular PythonScript. :slight_smile:

Now, what is a “Brep” as opposed to “Object” as opposed to “Geometry” in PythonScript… ? Can I cast from one to another, etc?

The secret enabling one to look in the right place is to have an overview of the general concepts I guess. I lack this overview.

UML?
If there where a UML diagram somewhere explaining the basic concepts, that would help a lot. The individual inheritance chains as presented in the documentation doesn’t explain much about how things relate to each other

// Rolf


#6

With a box selected running this prints the value:

import rhinoscriptsyntax as rs
object = rs.GetObject(message=None, filter=0, preselect=True, select=True, subobjects=True)
x = rs.coercebrep(object)
x.UserDictionary.Set("Rolf", "rendered by RILLife")  # <-- TM removed!
_, value = x.UserDictionary.TryGetValue('Rolf')
print(value)

For the most part I use Python only in GH, but you can read rhinoscript itself. I mean, the scripts. I think all coerceXXX() are in utility.py


#7

Ah, there we go! 10.000^10 thanks! You made my day.

RILThanks™!

// Rolf


#8

… look something like this :

Fig.1 Rhino.Geometry & Attributes & Brep (Updated). Now it looks messy with the UserData and UserDictionary classes… :

// Rolf


Looking for docs
#9

Glad to see that you already found the answer :slight_smile:

Anyway here is a very simple test script

import Rhino
import rhinoscriptsyntax as rs

def main():
  gob = Rhino.Input.Custom.GetObject()
  gob.SetCommandPrompt( 'Object ?' )
  gob.Get()
  key = rs.GetString( 'Key ?' )
  val = rs.GetString( 'Value [Enter to read] ?' )
  rob = gob.Object( 0 ).Object()
  if val:
    rob.Attributes.SetUserString( key, val )
    print( 'Written value ' + val )
  else:
    val = rob.Attributes.GetUserString( key )
    print( 'Read value ' + val )

main()

I agree that what is missing AFAIK is a general explanation of what does what.

References that I know of are the samples here:


… and the rhinoscriptsyntax source copied on our PCs along with Rhino (very useful IMO)

If you allow a few quick (and maybe confused) words from a non-expert …
Geometry is just that: theoretical geometrical objects
Object and ObjRef refer to what sits in Rhino’s data base, representing the geometrical objects we see on the screen
An Object contains a Geometry instance, but with RhinoCommon we can also work with Geometry instances (unlike rhinoscripsyntax, that can only reference Rhino Objects )

HTH

EDIT:
Rhino’s data base that I mentioned earlier is here:
http://developer.rhino3d.com/api/RhinoCommonWin/html/N_Rhino_DocObjects_Tables.htm
I think these tables, mostly object tables, layer tables, etc are a good start point to understand how Rhino works … for scripting purposes, I mean


#10

While there isn’t a UML diagram per say, you can look up the same data in the RhinoCommon SDK. See the Brep class here. You can inspect the inheritance tree, methods, properties etc there.


#11

Yup, that’s exactly what I’m doing, adding some info to the UML diagram.

// Rolf


#12

Then I’m a bit confused, is the Inheritance Hierarchy there not enough to answer your query? Edit: I see what you’re saying. Something that clarifies the relationships across classes. That would be cool, maybe you can automate this :wink:


#13

@emilio, I think I got a good start from the example. I will from now on draw UML diagrams of my reading in the RhinoCommon SDK documentation. It is easier to get an overview when drawing. I draw only the most important feateures to start with, and this links and attributes I happen to use myself. Gradually the model will be more complete. It’s a good way of learning the structure.

What I find a bit confusing is the different import names for VBScript/.NET & PyhonScript. The names (scriptsyntax, …context etc).

It would be very helpful with a short-list with “equivalents” between all approaches, which would help resolve confusion while being a RILNewbie™ like me.

@AndersDeleuran: A diagram gives overview,. For a newbie a zillion class & attribute and package names criss cross on different pages doesn’t give a good overview very quickly. Over time everything eventually sinks in but…

Edit 1:

Yup. The UML diagram above makes it much easier to get an overview.

Edit 2:

Yes please, give me the sources and I’ll reverse engineer the whole thing (into Enterprise Architect which I used here) in a few minutes… :slight_smile:

// Rolf


#14

Yes, these things aren’t so complex, just not easy to know for a newcomer.

scriptcontext is listed here:


And you can find it on your PC (just like rhinoscriptsyntax)

scriptcontext is often used in Python script to reach the RhinoDoc object that represents the Rhino document.
You obtain the RhinoDoc object by scriptcontext.doc
From this object you can get all Rhino tables: Objects, Layers, Views, etc.
that you use to interact with the Rhino document: geometric objects, layers etc.

I think .NET and IronPython both use RhinoCommon, classes and members should be the same

scriptcontext is just a Python module that mimics VBScript’s RhinoScript methods using RhinoCommon.

Thus in IronPython you can freely mix RhinoCommon and rhinoscriptsyntax, along with .NET classes (e.g. System.Drawing.Color) and Python modules available in IronPython.


#15

Yes, I think I got it sorted out now. I’ve been drawing some more on the structure, and it gradually becomes clearer. Doing UML is a bit like code refactoring, useful for learning the code. Here another “thin” model (intended for overview) with some glitches which gradually will be plugged as I dig deeper into RhinoCommon :

Fig.1. Another RILCheatSheet™ :

// Rolf


Looking for docs
#16

Nice work !
Thanks for sharing.
… trying to learn something about UML …


#17

The basics on UML diagrams should be covered in the following picture. Just differ classes from object instances (objects) like you differ a house drawing from an actual house (one drawing , many houses).

Inheritance uses fat arrowhead towards the parent. An arrow on other relations often mean “one way” (when the arrow is drawn). You seldom draw two-way arrows since it clutters the diagram without adding any essential info. The rolenames, like “Brep--------UserDictionary–>” should be read “seen from the source class”, from the Brep or the ObjectAttributes in this case, so (a Brep object).UserDictionary will return the (instantiated) UserDictionary. Links that holds multiple instances (lists) should use plural form in the role names (and any of the these multiplicity symbols * or n..* or 1..* if a least one instance must reside in the list, aso.

The names between “< < > >” are called < < stereotypes > > and may indicate different things (actually, whatever you designate, here I decided that the stereotypes display the Namespace)

[details=Plug :slight_smile: ]Plug: I made a system once drawn in UML with many hundred classes which generated both the database structure and the code stubs, AND instantiated and injected the very diagram itself into the executable so as to provide runtime info about the model (a higher form of “reflection” actually). The architecture is still around and provides an industrial strength Model Driven Arcitecture (MDA) which is very (very) robust, no glitches. Links and attributes could be derived with simple text OCL-expressions, automagic subscriptions laid on all relations, etc, etc.

An updated C# version of that same system is called MDriven (I used the original Win32 Bold Architecture version of this, called Delphi 7 Architect once upon the time). This is the ultimate MDA system which atomagically autogenerates a basic UI for any system drawn as a UML class diagram, inlcuding statemachine generation from state diagrams. http://www.new.capableobjects.com/products/eco-model-driven-framework/

[/details]

// Rolf


Looking for docs
#18

Thanks a lot,Rolf !


#19

My favorite example of interpreting UML class diagrams in the picture below.

All about Types
Notice that the diagram shows two (2) ways to define “type”. The traditional Object Oriented (OO) Inheritance way (Male and Female classes descending from “Human”) and the more flexible GenderType-link to a, well, a GenderType (more advanced both technically and conceptually because it also allows changing the gender, and to add any number of “genders”… :slight_smile: ).

Hierarchy
Anyway, since OOP involves “inheritance” I think that an example of Kind (Class Humans) as opposed to Generations (depicted by children & parents) helps the mind to find the best way to define different kinds of hierarchies.

Interface - The Interface type is not included here, only Classes, Attributes and Relations, but Interfaces are simply “injected” to classes with a pin symbol with a round pin head.

Ownership Links - Notice the difference between filled and unfilled diamond symbols for certain relations :

  • Filled diamonds (black) can be perceived as “owns” and code generators typically injects code to auto-create such related objects On Create of the owning class (and also destroyed together with the owning object)
  • Unfilled diamonds can be perceived as “has”. A “has”-relation can be dropped, or reconfigured to refer to some other object instance as opposed to “owns” which live and die with the owner object.

Configurable Type - The “advanced” GenderType kind of type-concept (shown far below in the picture) is often used in other contexts, so never mind the concept of gender, it just goes well together with human inheritance and relations etc.

Roles - Notice also the direction from which you read the link-roles (“wife” is technically an attribute of Male and “husband” is an attribute of “Female” etc).

There are a few more other UML notations not shown here, but this is the basic stuff that makes most sense for a start.

Edit: Notice also that using inheritance for defining Male & Female in software is not recommended (but for explaining the technical OO concept of inheritance it is useful). One reason for not using inheritance for gender is that the sequence of events for gaining the information may require that you create a “Person” or “Human” object first, and only after that you will learn about the gender, and so it’s more convenient to just create the Person class and assign the GenderType-link only when that info is known.

// Rolf


Looking for docs
#20

These diagrams are fantastic! If there is a way to have this as part of the documentation that would be awesome! :thumbsup:
as you say: [quote=“RIL, post:13, topic:42267”]
It’s a good way of learning the structure.
[/quote]
by the way It would be awesome if you could make the UML look like the grasshopper UI. Maybe @DavidRutten can help? :wink: