Get Entity from string
-
I'm making a plugin where I send a JSON hash to a webdialog. The JSON contains references to SketchUp entities, received in the form of Entity.to_s (Example: "#Sketchup::Face:0xfb042f0").
What I'd like to do next is send that reference back to SU and be able to deal with it as an object.
So my question is: how do you convert a string into an SU object? Or is there a better way to pass entity references between webdialogs and SU?
-
Hi Thomas,
I don't know. My first thought was to use the entity's .entityID, and pass that back and forth instead. You would then need to search the model for that entityID, or you could keep a hash of entities for performance.
-
Yea, I was hoping to avoid searching the model each time. I do have an identical hash in the Ruby code, so I suppose I could search that instead. Just hoped there was a neater way.
Here's an example of one JSON hash:
{ "#<Sketchup;;Model;0xfb04a40>"; { "#<Sketchup;;Face;0xfb03df8>"; "6200.0124000248", "#<Sketchup;;Group;0xfb04968>"; { }, "#<Sketchup;;Group;0xfb04770>"; { "#<Sketchup;;ComponentInstance;0xfb04530>"; { "#<Sketchup;;Face;0xfb042f0>"; "6200.0124000248" }, "#<Sketchup;;Group;0xfb04338>"; { "#<Sketchup;;Face;0xfb04008>"; "578.476293446544", "#<Sketchup;;Face;0xfb03e28>"; "578.476293446544", "#<Sketchup;;Face;0xfb04140>"; "578.476293446544", "#<Sketchup;;Face;0xfb04068>"; "1156.95258689309", "#<Sketchup;;Face;0xfb03ea0>"; "578.476293446544" } }, "#<Sketchup;;ComponentInstance;0xfb04788>"; { "#<Sketchup;;Face;0xfb042f0>"; "6200.0124000248" }, "#<Sketchup;;Face;0xfb047a0>"; "6200.0124000248", "#<Sketchup;;Group;0xfb046c8>"; { "#<Sketchup;;Face;0xfb04470>"; "6200.0124000248", "#<Sketchup;;Face;0xfb04518>"; "6200.0124000248" }, "#<Sketchup;;Face;0xfb042c0>"; "2155.33980480896", "#<Sketchup;;Face;0xfb041e8>"; "3423.10763458592", "#<Sketchup;;Group;0xfb04938>"; { "#<Sketchup;;Face;0xfb046e0>"; "6200.0124000248" } } }
I could use the .entityID instead of the .to_s value...
I just found it a bit odd that I could not find a method or function to pass SU data between webdialogs and Ruby. (All though, I've overlooked stuff from the APi manual before) I thought that eval() might work, but no go there either. -
The hex string is the pointer address of the ruby object. The problem is, a given object (entity, face, edge, anything), doesn't always have the same pointer address. If the object is unused in ruby (differing from being "used" in SU; SU doesn't store it's objects permanently in ruby), it may get discarded during garbage collection. The next time you ask for the entity, it will be the same entity, but it won't necessarily have the same address. A lesson I learned the hard way making a C ruby extension.
entityID is, to my knowledge, the only way to safely retrieve an entity.
-
Ok. .entityID it is then. And there isn't any function to locate the SU object from a given ID? I need to do this myself?
-
Not that I know of. You have to recurse through every group, component, etc (which can be a bit time consuming). A suggestion is that you create a table where you store the entity and your own key (just an incremental index probably), then you pass that key back and forth. I don't know how you plan on using it but if it's just a way to retrieve an entity it may work for you. As long as you keep an active instance of the entity, like in a table, I'm pretty sure ruby won't trash it out from under you and you can use that key to retrieve it at any time.
-
In your Ruby code, just build a Hash table of the entity indexed by their object address, so that it will be easy and fast to retrieve the entity. Just store them, without even bothering for the hierarchy
hsh_entities [entity.to_s] = entity
If you don't modify the model during your dialog session, it should work fine.
Fredo
-
I already have a hashtable in my script, which is what the JSON comes from.
The script loops through all model entities, looking for faces with materials applied and builds a hash from that. That's being sent to a webdialog which builds a table displaying the total area the material has been applied to as well as letting the user break it down to the individual faces.
All I need to do is make the .to_json method I made use the .entitiyID instead of .to_s and have the webdialog send the ID back whenever it needs to interact with the ruby.
I'm thinking I just crawl my existing hash, all though it's nested. If it should turn out that it's too slow I build another un-nested hash for quick reference lookup.
Thanks for your feedback guys.
-
@thomthom said:
I'm thinking I just crawl my existing hash, all though it's nested. If it should turn out that it's too slow I build another un-nested hash for quick reference lookup.
That's what I do with DCs. Just build a hash of entities where the key is the id... then you get fast lookup later on, and you can use the valid? method to determine if something has been deleted since you added it to the hash. You can periodically clean it out to prevent it from growing too large.
I wish there were a generic way to grab things in Ruby, but I don't know of one.
Sounds like a very cool script, by the way!
-
Thanks Scott.
I think I'll put forward a request for a built-in lookup method in SU. So that each ruby doesn't have to build their own hash every time.
Advertisement