relative (within group) vs global x, y, z...

174 views
Skip to first unread message

John

unread,
Nov 4, 2008, 1:00:29 AM11/4/08
to Google SketchUp Help - Ruby API & SketchUp SDK
Hey! I'd appreciate any tips, clues, or links that would help me
understand the global and relative "position" of a component vs
components within groups, and how these can be manipulated with
ruby. I must have some wrong assumption that is getting in my way!
Below is a quick summary of the particular problem i'm trying to
solve. ah, it seemed to simple...

I put my house in sketchup. i have used components to indicate every
electrical outlet, switch, light, etc. With the help of ruby, i
wanted to build an electric map. (electric map = which outlets are
on which circuit)

This electrical map is really a chart. The way i wanted to build the
chart is to tell ruby to add symbols to my model for each kind of
electrical device. My symbol is basically a circle that lays on the
ground (or on some plane well below the model) in front of the
device. I figure i'll make a scene or version of model that is a
clean graphic of the floor plan with electrical device locations
clearly labeled.

i hacked some sample scripts (especially jf_ciid.rb (C) Copyright 2007
jim....@gmail.com) to iterate through model, identify electrical
device components, get the center of the bounding box of the
component, then add another component (the symbol) to the model in
position where it's legible.

When i tested the idea on a very simple model, it worked nicely. But
when I ran the ruby script on my real model, the locations of the new
components were getting jumbled. I think the reason is that when my
electrical component is within a group... or a group within a group
within a group, I am getting x, y, x coordinates relative to the
parent group (or so i think), but then i'm adding the new component at
the "global" x y x.

Is there a simple way to extract the "global" x y z of a component,
without regard to its parent group, so i can use those coordinates to
setup a new component that is not part of the same group?

again, appreciate any insights! thanks, john

ps. haven't other people done electrical maps with sketchup models of
house?







Thomas Bleicher

unread,
Nov 4, 2008, 5:27:41 AM11/4/08
to sketch...@googlegroups.com
John.

Unfortunately there is no 'simple' way to do what you want.
Basically you have to keep track of a group's or component's
transformation towards global space while you're descending
down a parent-child tree of groups.

One way is to keep a stack of transformations that's extended
and reduced with every nesting level. Here is an example that
might do that (untested):

##begin##

# first initialise the stack with a unity transformation
$transformationStack = [Geom::Transformation.new()]

def descend(entity):
## push new transformation matrix of entity onto stack
## entity.transformation is the transformation relative to parent
## newTrans is the transformation to global space
newTrans = $transformationStack[0] *= entity.transformation
$transformationStack.push(newTrans)
if entity.class == Sketchup::ComponentInstance
entities = entity.definition.entities
else
entities = entity.entities
end
entities.each { |e|
if e.class == Sketchup::ComponentInstance
doStuffWithComponent(e)
descend(e)
elsif e.class == Sketchup::Group
doStuffWithGroup(e)
descend(e)
else
doStuffWithFaceOrEdge(e)
end
}
## don't forget to pop() the transformation stack
## after you're done with 'entity'
$transformationStack.pop()
end

def doStuffWithComponent(e)
## for you to fill in
## you can access the transformation to global space via
toGlobal = $transformationStack[-1]
showTransformation(toGlobal)
end

def doStuffWithGroup(e)
## dito
end

def doStuffWithFaceOrEdge(e)
## for you to fill in
## here is some code that prints every vertex of a face
if e.class == Sketchup::Face
polymesh = e.mesh 7
polymesh.transform!($transformationStack[-1])
polymesh.points.each { |p|
printf "point: %s\n" % p
}
end
end

def showTransformation(trans)
## first row is x, second is y, third is z-axis
## origin (x,y,z) is last row, units is inches!
a = trans.to_a
printf " %5.2f %5.2f %5.2f %5.2f\n" % a[0..3]
printf " %5.2f %5.2f %5.2f %5.2f\n" % a[4..7]
printf " %5.2f %5.2f %5.2f %5.2f\n" % a[8..11]
printf " %5.2f %5.2f %5.2f %5.2f\n" % a[12..15]
end

##end##

Regards,
Thomas

John

unread,
Nov 4, 2008, 7:40:19 PM11/4/08
to Google SketchUp Help - Ruby API & SketchUp SDK
Thomas -- Thank you! This is *really* helpful. --- john
> > jim.fo...@gmail.com) to iterate through model, identify electrical

Rob Zinn

unread,
Jun 3, 2017, 3:56:07 PM6/3/17
to SketchUp Ruby API, johnz...@gmail.com
Hello John and Thomas,

Boy, I struggled and struggled with this!  I was trying to mine down to a specific group, no matter how far nested it was in a model - then copy it out to the top/model context.  Thomas's stack method seemed to be perfect but I was not getting the results I needed.  I think because I could not rely on $transformationStack[-1] to just give me the last transformation added to the stack.  Sometimes, I was going into a group that had multiple entities, none of which were or even contained the groups I was looking for and $transformationStack.pop() did not seem to maintain the stack as entities where descended or un-descended.

So anyway, hopefully this is helpful to someone. I'm sure this could be done more elegantly and brieflly!!!

The "OPENINGS_TEMP_PRIMATIVES" entity is the group I was copying everything out to and layer.name=="OPENING_PRIMATIVES" was the test I was using to find the target groups. Modify as needed.

Here is the modified code based on Thomas's routine - Thank you Thomas!!!!

class FindOpenings

# initialize objects
@@mod = Sketchup.active_model
@@ent = @@mod.entities
@@lay = @@mod.layers
@@sel = @@mod.selection
@@temp_opening_primitives = Sketchup.active_model.active_entities.add_group
@@temp_opening_primitives.name = "OPENINGS_TEMP_PRIMATIVES"

$context_stack = [Geom::Transformation.new()]
$trans_level = 0

def FindOpenings::descend(ent_in)
# handle ComponentInstance entities differently from others
if ent_in.class == Sketchup::ComponentInstance
e_ents = ent_in.definition.entities
else
e_ents = ent_in.entities
end

if((ent_in.parent.class == Sketchup::Model) && (ent_in.class == Sketchup::Group) && (ent_in.layer.name=="OPENING_PRIMATIVES"))

puts "TOP PRIMATIVE GROUP - ADDING GROUP USING THIS_TRANS:"
report_trans(ent_in)

@@temp_opening_primitives.entities.add_instance(e_ents.parent, ent_in.transformation)

else # everything else should be descended
if(ent_in.name != "OPENINGS_TEMP_PRIMATIVES")
if(ent_in.parent.class == Sketchup::Model)

newTrans = $context_stack[0] = ent_in.transformation
$context_stack.push(newTrans)

puts "TOP NON PRIMATIVE GROUP OR COMP - DESCENDING NATURALLY"
report_trans(ent_in)
$trans_level += 1

end
e_ents.each {|entity|
if(entity.class == Sketchup::ComponentInstance)

newTrans = $context_stack[0] *= entity.transformation
$context_stack.push(newTrans)

puts "COMPONENT INSTANCE - DESCENDING"
report_trans(entity)
$trans_level += 1

descend(entity)

elsif(entity.class == Sketchup::Group)
if(entity.layer.name=="OPENING_PRIMATIVES")

puts "PRIMATIVE GROUP - ADD USING THIS_TRANS * STACK AT THIS LEVEL"
report_trans(entity)
@@temp_opening_primitives.entities.add_instance(entity.entities.parent, $context_stack[$trans_level]*entity.transformation)

else

newTrans = $context_stack[0] = $context_stack[$trans_level]*entity.transformation
$context_stack.push(newTrans)

puts "NON PRIMATIVE GROUP - DESCENDING"
report_trans(entity)
$trans_level += 1

descend(entity)
end
end
}
$context_stack.pop()
$trans_level -= 1
end # end of OPENINGS_TEMP_PRIMATIVES skip
end # end of top level check
@@temp_opening_primitives.entities.each{|tg|
if tg.is_a? Sketchup::Group
tg.explode
end
}
end # end of def

def FindOpenings::report_trans(e_in)
puts "---------------------------#{e_in.name}------------------------------"
puts "THIS_TRANS:"
show_trans(e_in.transformation)
puts "CURRENT_STACK:"
$context_stack.each_with_index{|ts,index|
show_trans(ts,index)
}
puts "STACK AT LEVEL #{$trans_level}:"
show_trans($context_stack[$trans_level])
puts "THIS_TRANS * STACK AT THIS LEVEL:"
show_trans($context_stack[$trans_level]*e_in.transformation)
puts "-----------------------"
end #report_trans def

def FindOpenings::show_trans(trans,i=nil) # i is optional
#first 3 rows are scale (x,y,z) 4th row is origin (x,y,z)
a = trans.to_a
if i!=nil
printf("%d: " %i)
printf("%d,%d\n" %a[12..13])
# + %d,%d\n" %i %a[12] a[13]
else
printf "%d,%d\n" %a[12..14]
end
end # showTransformation def

# define cut_walls
def FindOpenings::cut_walls

SKETCHUP_CONSOLE.clear
@@ent.each{|ents|
descend(ents)
}
end # end cut_walls def

end # class FindOpenings
Reply all
Reply to author
Forward
0 new messages