• Login
sketchucation logo sketchucation
  • Login
ℹ️ Licensed Extensions | FredoBatch, ElevationProfile, FredoSketch, LayOps, MatSim and Pic2Shape will require license from Sept 1st More Info

Component axis problem

Scheduled Pinned Locked Moved Developers' Forum
18 Posts 5 Posters 1.2k Views 5 Watching
Loading More Posts
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • P Offline
    Pixero
    last edited by 5 Jan 2015, 16:41

    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?
    
    
    1 Reply Last reply Reply Quote 0
    • P Offline
      Pixero
      last edited by 6 Jan 2015, 14:43

      Does anyone know how to do this?

      1 Reply Last reply Reply Quote 0
      • X Offline
        XorUnison
        last edited by 7 Jan 2015, 08:58

           comp = group.to_component
        

        ↑ Here you take an existing group and turn it into a component,
        mind you, it still is in the drawing

           entities.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 it

        instance = (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

        1 Reply Last reply Reply Quote 0
        • T Offline
          TIG Moderator
          last edited by 7 Jan 2015, 10:41

          You already have an instance of the component definition when you make the conversion of group to component.
          The comp refers to its instance.
          The compdef 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]. Use compo.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...
          Use compo.transform!(tr) to move the group back where it was when you started...

          TIG

          1 Reply Last reply Reply Quote 0
          • P Offline
            Pixero
            last edited by 7 Jan 2015, 10:48

            Thanks for this both of you. I will try this as soon as I get a chance.

            1 Reply Last reply Reply Quote 0
            • P Offline
              Pixero
              last edited by 9 Jan 2015, 11:49

              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...

              1 Reply Last reply Reply Quote 0
              • X Offline
                XorUnison
                last edited by 9 Jan 2015, 12:30

                @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)
                
                1 Reply Last reply Reply Quote 0
                • T Offline
                  TIG Moderator
                  last edited by 9 Jan 2015, 13:08

                  Sorry, I rushed out the code snippets...
                  You also need to do a compdef.invalidate_bounds
                  after the changes, inside the model.start_operation...commit block, to make it change visually !
                  http://www.sketchup.com/intl/en/developer/docs/ourdoc/componentdefinition#invalidate_bounds

                  TIG

                  1 Reply Last reply Reply Quote 0
                  • P Offline
                    Pixero
                    last edited by 9 Jan 2015, 18:34

                    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)	
                    
                    
                    1 Reply Last reply Reply Quote 0
                    • sdmitchS Offline
                      sdmitch
                      last edited by 17 Jan 2015, 15:46

                      @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
                      
                      

                      Nothing is worthless, it can always be used as a bad example.

                      http://sdmitch.blogspot.com/

                      1 Reply Last reply Reply Quote 0
                      • P Offline
                        Pixero
                        last edited by 17 Jan 2015, 19:10

                        Yes I figured it out. Thanks anyway.

                        1 Reply Last reply Reply Quote 0
                        • P Offline
                          Pixero
                          last edited by 24 Jan 2015, 12:16

                          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
                          
                          1 Reply Last reply Reply Quote 0
                          • sdmitchS Offline
                            sdmitch
                            last edited by 24 Jan 2015, 15:47

                            Replace 90.degrees with Math::PI/2.

                            Nothing is worthless, it can always be used as a bad example.

                            http://sdmitch.blogspot.com/

                            1 Reply Last reply Reply Quote 0
                            • P Offline
                              Pixero
                              last edited by 24 Jan 2015, 17:07

                              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
                              
                              1 Reply Last reply Reply Quote 0
                              • S Offline
                                slbaumgartner
                                last edited by 24 Jan 2015, 17:48

                                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!

                                1 Reply Last reply Reply Quote 0
                                • sdmitchS Offline
                                  sdmitch
                                  last edited by 24 Jan 2015, 18:39

                                  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.

                                  Nothing is worthless, it can always be used as a bad example.

                                  http://sdmitch.blogspot.com/

                                  1 Reply Last reply Reply Quote 0
                                  • P Offline
                                    Pixero
                                    last edited by 25 Jan 2015, 16:00

                                    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.

                                    1 Reply Last reply Reply Quote 0
                                    • P Offline
                                      Pixero
                                      last edited by 25 Jan 2015, 17:39

                                      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
                                      
                                      1 Reply Last reply Reply Quote 0
                                      • 1 / 1
                                      • First post
                                        Last post
                                      Buy SketchPlus
                                      Buy SUbD
                                      Buy WrapR
                                      Buy eBook
                                      Buy Modelur
                                      Buy Vertex Tools
                                      Buy SketchCuisine
                                      Buy FormFonts

                                      Advertisement