Entering components
-
Hi, This seems really simple, so hopefully it is!
I want to loop through all the instances of a component in a model, then loop through it's entities and find a face that has a special material (lets say kryptonite).
From looking at the API it seems that Groups have a .entities, but ComponentInstances don't.
Any hints on how is it done?
Back story *(ignore this if you aren't too bothered about the application of this)*I'm analysing an appartment block. There are 8 or so appartment types, each is placed and named according to it's position, so one might be 'floor 5 appt 7'. There is a critical window that I need to test using the method outlined in the Taking pictures with cameras thread.
My plan so far is to take a copy of each face and put it onto a layer, run the test for each window, and then delete them all. Essentially leaving the model untouched.
-
I've actually cracked this. I found an old thread that explained it. I'll post it up in a bit when I finish it
-
@ben.doherty said:
From looking at the API it seems that Groups have a .entities, but ComponentInstances don't.
Any hints on how is it done?
With
ComponentInstances
you need to access itsComponentDefinition
- that has.entities
.Btw, Groups and Images also have definitions, you iterate them when you iterate
model.definitions
. Which is whyComponentDefinition
has.group?
and.Image?
-
So here's the solution I came to. I'm sure that there are better ways to do this, but this was quick, and it worked. I suppose in the future adding a method to the vector class instead of making an instance method would be neater etc.
[as I see it] Feature instances can't be entered, but their definitions can be. That means that you can find the face that you need to access, but it'll be at the origin. the Instance does have a transform, so if you apply that transform to the new object then you can make it be in the same place as the instance.
But wait! you can't transform a face, but you can transform a group, so just throw the face into a group and transform that.Any raises on that? it doesn't seem too elegant, but it does the job.
#module Voyeur #module FaceMaker if( not file_loaded?("makeTheFaces.rb") ) # This will add a separator to the menu, but only once add_separator_to_menu("Voyeur") plugins_menu = UI.menu("Plugins") voyeur_menu = plugins_menu.add_submenu("Voyeur") voyeur_menu.add_item("make analysis faces") { makeAnalysisFaces } end def toP3d(vec) return Geom;;Point3d.new(vec.x,vec.y,vec.z) end def vertToVec(aVertex) unless aVertex == nil pos = aVertex.position theVec = Geom;;Vector3d.new(pos.x,pos.y,pos.z) return theVec end end def scaleVec(vec,scalar) return Geom;;Vector3d.new(vec.x * scalar, vec.y * scalar, vec.z * scalar) end def makeAnalysisFaces mod = Sketchup.active_model ent = mod.entities sel = mod.selection analysisLayer = mod.layers.add 'analysis' ent.each{ |e| if e.is_a? Sketchup;;ComponentInstance e.definition.entities.each { |newE| if ((newE.is_a? Sketchup;;Face) and (newE.material != nil)) #puts newE.material.name verts = newE.vertices normal = Geom;;Vector3d.new(newE.normal).normalize offsetFactor = 3000.mm offset = scaleVec(normal, offsetFactor) newPoints = [] for i in (0...verts.length) pvec = vertToVec(verts[i]) newPoints[i] = toP3d(pvec + offset) #ent.add_cpoint newPoints[i] end tempGroup = ent.add_group face = tempGroup.entities.add_face newPoints #puts "#{e.name}'s transform matrix" #puts e.transformation.to_a tempGroup.transformation = e.transformation tempGroup.set_attribute "analysisInfo", "apptType", e.definition.name tempGroup.set_attribute "analysisInfo", "apptNumber", e.name tempGroup.layer = analysisLayer end #if newE.is_a? Sketchup;;Face } #e.definition.entities.each end #if e.is_a } #ent.each end #makeAnalysisFaces #end #end
I am having lots of trouble with modules though, if I ask the ruby console for
Voyeur::FaceMaker::instance_methods
it gives me back a list of the methods as I'd expect, but if I sayVoyeur::FaceMaker.makeAnalysisFaces
it throws a#<NoMethodError....
any idea how to fix that? Currently I've just taken the module stuff out, which seems like bad karma. -
I also think you missed the Geom::Point3d.offset method
for i in (0...verts.length) pvec = vertToVec(verts[i]) newPoints[i] = toP3d(pvec + offset) #ent.add_cpoint newPoints[i] end
can become:
for i in (0...verts.length) newPoints[i] = verts[i].position.offset( scaleVec ) #ent.add_cpoint newPoints[i] end
-
@ben.doherty said:
I suppose in the future adding a method to the vector class instead of making an instance method would be neater etc.
> def toP3d(vec) > return Geom;;Point3d.new(vec.x,vec.y,vec.z) > end >
Done already (in a way.)
See the API method: Geom::Vector3d#to_aAlso do not overlook (it's easy; the online API is not organized at that well,) that the API extended the Ruby baseclass Array to be compatible with both Geom::Vector3d and Geom::Point3d classes.
See, (API left nav) Base Classes: ArrayWhat the API does NOT explain well (and you won't know unless you read the API topic thread,) is:
Geom::Point3d.new( *args )
*args can accept an Array argument or literal as the 1st arg (the rest are then ignored.)
Ex:
Geom::Point3d.new( [1,2,3 )]
Geom::Point3d.new( vec.to_a )Geom::Vector3d.new( *args )
*args can accept an Array argument or literal as the 1st arg (the rest are then ignored.)
Ex:
Geom::Vector3d.new( [1,2,3 )]
Geom::Vector3d.new( pt.to_a )Neither class can directly accept each other as arguments; you must use the .to_a method on the argument.
So to convert Vertex to Vector3d, is simply:
Geom::Vector3d.new( vertex.position.to_a )
In addition to scale a vector, you can use:
vector.length=vector.length*scaler
or use the vector.transform! method:
vector.transform! Geom::Transformation.scaling(scalar)For a new scaled vector:
vector2=vector1.clone
vector2.length=vector1.length*scaler
or use the vector.transform method:
vector2=vector1.transform Geom::Transformation.scaling(scalar) -
@ben.doherty said:
I am having lots of trouble with modules though, if I ask the ruby console for
Voyeur::FaceMaker::instance_methods
it gives me back a list of the methods as I'd expect, but if I sayVoyeur::FaceMaker.makeAnalysisFaces
it throws a#<NoMethodError....
any idea how to fix that?moved to it's OWN topic thread, so folks can find it easier:
Advertisement