Component axis problem
-
It's been a while since I coded so bare with me...
I'm trying to create some geometry in a group that is converted into a component.
I then want to change the components axis so that it will align with the component.
Here is a snippet of code that I have problems with:#Snippet comp = group.to_component compdef = comp.definition compdef.name="MyComponent" v = Geom;;Vector3d.new 0,0,0 trans=Geom;;Transformation.translation(v) @@newAxis=comp.bounds.center comp.erase! #Why do I have to erase this to not end up with two components??? entities = Sketchup.active_model.entities entities.add_instance(compdef,trans) instance = (compdef.name = "MyComponent") #Need to get the instance to be able to move axis below. #Not correct but what should I do? #Can't use comp since that is erased. [color=#FF0000]#Moving the components axis to match comp position and rotation #This def is copied from the forum. def resetAxis(ent) cd=ent.definition realBounds= Geom;;BoundingBox.new cd.entities.each{|de| realBounds.add(de.bounds)} #Calculate the real bounding box of the entities in the component. center=@@newAxis #desired center. if(realBounds.center!=center) #if not already centered #transform all the entities to be around the new center cd.entities.transform_entities(Geom;;Transformation.new( center-realBounds.center), cd.entities.to_a) #move each instance of this component to account for the entities moving inside the component. cd.instances.each{|ci| newCenter=realBounds.center.transform(ci.transformation) ci.transform!(newCenter-ci.transformation.origin) } end end resetAxis(instance) #What should this be?
-
Does anyone know how to do this?
-
comp = group.to_component
↑ Here you take an existing group and turn it into a component,
mind you, it still is in the drawingentities.add_instance(compdef,trans)
↑ Here you add a second component based on the definition of the first one
If you only want one component you'll either have to delete the first one,
or don't create the second one and move the first one to the point where you want itinstance = (compdef.name = "MyComponent")
↑ Here you set instance to the string "MyComponent"
However you can't fetch a component like that by it's name, you need the link to the instance. You don't need this line.The moment you create the instance you get the link to the created instance, just catch it like that:
instance = entities.add_instance(compdef,trans)
Tip: You can try reading out what you got by putting "puts instance" afterwards, the result should look like this: #Sketchup::ComponentInstance:0xXXXXXXXX
-
You already have an instance of the component definition when you make the conversion of group to component.
Thecomp
refers to its instance.
Thecompdef
refers to its definition.If you want to rotate/move that component's axes do this...
If necessary...
Get the transformation of the current instance [tr
]. Usecompo.transform!(tr.inverse)
to relocate it at the origin.Make the transformation needed to make the change[s] to the axes [
tr2
].
Apply that transformation thus:compo.transform!(tr2)
Immediately apply that transformation to the definition thus:
compdef.entities.transform_entities(tr2.inverse, compdef.entities.to_a)
The instance should now appear as it was before, but the axes have changed...If approapriate...
Usecompo.transform!(tr)
to move the group back where it was when you started... -
Thanks for this both of you. I will try this as soon as I get a chance.
-
Not sure why I'm having such a hard time getting this right but following TIGs guide, the Components BoundingBox/selection box remains unrotated until I open the component to edit. After exiting out of the edit component mode, the selection box is properly rotated, even though I still have some work left to get the component axis where I want it... Coding can be sooo frustrating...
-
@pixero said:
Not sure why I'm having such a hard time getting this right but following TIGs guide, the Components BoundingBox/selection box remains unrotated until I open the component to edit. After exiting out of the edit component mode, the selection box is properly rotated, even though I still have some work left to get the component axis where I want it... Coding can be sooo frustrating...
That's what I thought during my first month or so, but eventually it gets a lot easier as you learn how Sketchup and Ruby work.
I don't know that phenomenon personally but I think it might be related to the component not being refreshed properly. You could try to redraw it:
dcs = $dc_observers.get_latest_class dcs.redraw(entity,progress_bar_visible=false,is_recursive_call=false)
-
Sorry, I rushed out the code snippets...
You also need to do acompdef.invalidate_bounds
after the changes, inside themodel.start_operation...commit block
, to make it change visually !
http://www.sketchup.com/intl/en/developer/docs/ourdoc/componentdefinition#invalidate_bounds -
Now I got the rotation of the boundingbox working as it should.
However the transformation of the components axis is still at origo.
Rotated correctly but not transformed.
I must still be missing something?tr = comp.transformation rotvector = pt1-pt0 originvector = Geom;;Vector3d.new(1,0,0) angle = rotvector.angle_between originvector wfc.transform!(tr.inverse) tr2 = Geom;;Transformation.rotation(ORIGIN, Z_AXIS, angle) comp.transform!(tr2) compdef.entities.transform_entities(tr2.inverse, compdef.entities.to_a) compdef.invalidate_bounds comp.transform!(tr)
-
@pixero said:
Now I got the rotation of the boundingbox working as it should.
However the transformation of the components axis is still at origo.
Rotated correctly but not transformed.
I must still be missing something?> tr = comp.transformation > rotvector = pt1-pt0 > originvector = Geom;;Vector3d.new(1,0,0) > angle = rotvector.angle_between originvector > wfc.transform!(tr.inverse) > > tr2 = Geom;;Transformation.rotation(ORIGIN, Z_AXIS, angle) > comp.transform!(tr2) > > compdef.entities.transform_entities(tr2.inverse, compdef.entities.to_a) > compdef.invalidate_bounds > comp.transform!(tr) >
Did you ever get this figured out?
Here is what I came up with.
mod = Sketchup.active_model ent = mod.active_entities sel = mod.selection grp = ent.first; #<--For test purposes cmp = grp.to_component cd = cmp.definition; cde = cd.entities; ct = cmp.transformation cmp.transform! ct.inverse org = cmp.bounds.corner(0) #rotvector = pt1-pt0 #originvector = Geom;;Vector3d.new(1,0,0) #angle = rotvector.angle_between originvector #angle = -angle * (rotvector.y<=>0) angle = -30.degrees #<--For test purposes tr0 = Geom;;Transformation.rotation(org,Z_AXIS,angle) cde.transform_entities(tr0,cde.to_a) bb = Geom;;BoundingBox.new() cde.each{|e| bb.add e.bounds} org = bb.center tr1 = Geom;;Transformation.new(org) cde.transform_entities(tr1.inverse,cde.to_a) cmp.transformation = cmp.transformation * tr1 cmp.transform! ct * tr0.inverse cd.invalidate_bounds
-
Yes I figured it out. Thanks anyway.
-
I have found a bug in my script that causes errors when drawn at certain angles.
When less than 90 degrees the angle needs to be negative and that works well with this fix but when it is 90 degrees or -90 degrees I cant seem to find a way of getting it correct without overwriting the values. Any clues how to do this?def set_origin(compdef, compinst, pt0, pt1, pt3) tr1 = compinst.transformation rotvector = pt1-pt0 originvector = Geom;;Vector3d.new(1,0,0) org = pt3 angle = rotvector.angle_between originvector if angle < 90.degrees angle2 = -angle elsif angle > 90.degrees angle2 = angle end #if # This part don't trigger when it's not exactly 90 degrees. # If its just below or above but not enought to be caught in the <90 or >90. # 90.00000000000007 doesn't trigger it. (1.570796326794898 in radians) if angle == 90.degrees angle2 = -90.degrees puts "I'm 90" elsif angle == -90.degrees angle2 = 90.degrees puts "I'm -90" end compinst.transform! tr1.inverse tr2 = Geom;;Transformation.rotation(org, Z_AXIS, angle2) tr3 = Geom;;Transformation.new(org) compdef.entities.transform_entities(tr2, compdef.entities.to_a) compdef.entities.transform_entities(tr3.inverse, compdef.entities.to_a) compinst.transformation = compinst.transformation * tr3 compinst.transform! tr1 * tr2.inverse compdef.invalidate_bounds end #def
-
Replace 90.degrees with Math::PI/2.
-
Thanks, I tried that but the result is the same.
Is there a way of clamping very small values since 90.00000000000003 degrees seem to be enough not to work?if angle == Math;;PI/2 angle2 = -90.degrees elsif angle == -(Math;;PI/2) angle2 = 90.degrees end
-
This issue is unavoidable with finite precision math on the computer. You have to choose a threshold of significance and then test for agreement within that tolerance, e.g.
if (angle.degrees - 90.0).abs < threshold
Of course, then you will become subject to all the same complaints as SketchUp gets for its internal 0.001 inch tolerance for consolidating Vertices - which is due to exactly the same situation!
-
I don't think the angle between vectors is ever going to be negative. Since you are measuring the angle from the x axis, you will need to use the y value of the rotvector to determine if the angle is negative or positive.
angle *= -(rotvector.y<=>0)
In a Sketchup rotation transformation, a positive angle is a counter clockwise rotation.
-
I think I finally solved it by checking which of the pt0.y and pt1.y is larger and treat it different accordingly. Seems to work now.
Thanks for you input. -
I just thought I'd post this snippet in case it will help someone with a similar problem.
def set_origin(compdef, compinst, pt0, pt1, pt3) tr1 = compinst.transformation rotvector = pt1-pt0 originvector = Geom;;Vector3d.new(1,0,0) org = pt3 angle = rotvector.angle_between originvector if angle < 90.degrees angle2 = -angle elsif angle > 90.degrees angle2 = angle end #if if angle == Math;;PI/2 angle2 = -90.degrees end if pt0.y > pt1.y && angle == Math;;PI/2 #Check if it's drawn at 90 degrees but in opposite direction angle2 = 90.degrees end compinst.transform! tr1.inverse tr2 = Geom;;Transformation.rotation(org, Z_AXIS, angle2) tr3 = Geom;;Transformation.new(org) compdef.entities.transform_entities(tr2, compdef.entities.to_a) compdef.entities.transform_entities(tr3.inverse, compdef.entities.to_a) compinst.transformation = compinst.transformation * tr3 compinst.transform! tr1 * tr2.inverse compdef.invalidate_bounds end #def
Advertisement