Multiple attribute dictionaries created
-
Hi,
I am working on a plugin that adds a standard set of attributes (representing building element properties) to selected entities in the model. I want to be able to save this meta-data with the model, so attributes would seem to be the correct way to go.When I add an attribute dictionary to a number of different entities, using
entity.set_attribute(dictName, attrName, attrValue)
a different AttributeDictionary object is created for each entity (eg#<Sketchup::AttributeDictionary:0x11f60408>, #<Sketchup::AttributeDictionary:0x11fb7488>
), even though I am using the same dictionary name every time.
I am planning to cascade these attributes to all entities with groups etc, which could amount to a considerable number of entities. Is there any concern with the amount of memory taken up by all these separate AttributeDictionary objects in terms of performance and if so is there any way around it? Can I create a global attribute dictionary that applies to the whole model or would there be no benefit doing that? - it just seems it would be a neater solution.many thanks
Dave -
If you have data that applies only to a definition, instance or group then you must add the attribute dictionary to that 'by name'. OK. there are then separate dictionaries using the same name attached to different objects... but you know which one belongs to which object. That data is remembered across sessions. If the object is deleted the data/dictionary goes too.
You can add an attribute dictionary to the model itself.
This is useful for remembering data specific to the model, again it's retained across sessions.
If you were to save objects' data into a central attribute dictionary if would get unwieldy.
An object's 'id' varies session per session, so you'd need to rely on its name etc to find it, or attach a 'tid' [(1000*Time.now.to_f).to_i] attributes to each object which rather goes against the centralization concept !
The centralized dictionary entries could be in the form of an array of objects with sub-arrays of name and other data relating to that name - attribute data can only be string, integer, float, boolean or array [including point3d and vector3d objects which are specialized arrays] - you can remember transient Sketchup class/reference objects etc.
You might also find it easier to use a hash to remember values... but you'll need to 'deconstruct' a hash into an array [array=hash.to_a
] so that you can 'set' it as an attribute, and later then when you 'get' that array attribute back you'll need to convert it into a hashh={};array.each{|a|h[a[0]]=a[1]}
?
You model's attributes can also get out of step with the model's contents as the user could well delete objects that the model's dictionary still contains...
There might also be size limits on individual attribute dictionaries or their keys/values.
I'd stick with attaching attributes to 'container' objects that need them, it's less convoluted...
Although individual entities like faces can have attributes the face might easily be erased by the user and recreated [even perhaps by an undo] and the attributes might be lost. If a 'container' is deleted the loss of its attributes is of no concern as these relate specifically to it anyway... -
Hi TIG,
Thanks for your reply.
I agree, creating a centralised dictionary with hashes and arrays does sound rather convoluted.The way I am using the attributes is similar to instance variables and methods for a class; creating a standard set of attributes for a building element such as, say a wall, so in addition to the
face.area
,face.normal
methods etc I can store other properties about the geometry and construction. Since I was thinking along these lines, I was expecting the attribute dictionaries to behave in a similar way to creating instance variables; creating a standard dictionary for an object type such as walls, with a number of pre-defined attribute names, so they are standard across all instances of walls.
The way attributes are implemented does seem a bit inefficient because if I want to add or change the names of attributes in future, I will have to audit every entity (that has attributes) in old models to make them compliant with the latest attribute scheme, rather than being able to modify those attributes (but not their instance values) in one place. Looks like I will have to learn to live with this though - it would be a relatively simple script, so just something I need to be aware of.I hadn't appreciated that attributes applied to a face would be lost if it is deleted and restored by undo, so thanks for bringing that to my attention! I can see there would be a benefit to only attaching attributes to container objects, but there will be cases where this is not practicable without making the model more complicated by adding extra levels of containers.
cheers
Dave -
When you do an 'undo' the object is replaced by a new 'matching' instance [new 'id'], this new object matches the previous one in respects of material, layer etc, it also transfers attributes... but with something like a face you need to use an undo and not remake the face, e.g. by drawing over a line - because this new face will loose the previous material, layer, attributes etc...
-
You should prefix your Dictionary names with something unique to YOUR company and plugin:
ie: "
ACME_BIMinator
"Using a plain common name like "
Properties
" is likely to conflict with someone else's plugin. -
@archidave said:
... Since I was thinking along these lines, I was expecting the attribute dictionaries to behave in a similar way to creating instance variables; ...
Nothing is stopping you from doing so.
You can create a custom class (within your plugin namespace module,) for a Wall, that has instance variables, that are loaded from an entity's attribute dictionary.
If you just save the values as an array, into a single attribute, you can use Ruby's iterator loops or methods, to load the values into instance variables.
So the names of instance variables, are defined by a literal array inside your class, an the initialize method iterates this array, matching it's indexes, with the indexed values in the dictionary array.
module ACME module BIMinator DictName = 'ACME_BIMinator' class Wall Atts = [;area,;thickness,;paint] attr_accessor( *Atts ) # expand array Atts to parameter list def initialize(entity) @prop = entity.get_attribute(ACME;;BIMinator;;DictName, 'properties') Atts.each_with_index {|att,i| method("#{att.to_s}=").call(@prop[i]) } end end # class end # BIMinator end
SO.. the actual attribute names are defined in ONE place, your custom class.
Advertisement