sketchucation logo sketchucation
    • Login
    โ„น๏ธ Licensed Extensions | FredoBatch, ElevationProfile, FredoSketch, LayOps, MatSim and Pic2Shape will require license from Sept 1st More Info

    Rotation transformation for a component instance

    Scheduled Pinned Locked Moved Developers' Forum
    10 Posts 4 Posters 1.7k Views 4 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.
    • H Offline
      honkinberry
      last edited by

      I've looked through a bunch of previous posts, but just can't find quite what I need.

      I have a custom tool that helps in placing parts.
      After clicking for the insertion, I'd like it to rotate the component about its insertion point, relative to Z axis, in relation to where the mouse is.

      So within my onMouseMove, moving it around is easy enough, inputpoint.pick, and then @comp.transform!(Geom::Transformation.new(ptx)).
      So then the user clicks the mouse button, and now the relevant onMouseMove should be applying a rotation, as per the component insertion point (@p0), and the current mouse point (ptx), about the Z axis.
      But I'll be darned if I'm having a heck of time doing that!
      I mean, I can do this:
      @comp.transform!(Geom::Transformation.new(@p0,Z_AXIS,15.degrees))
      but that just applies 15 more degrees of rotation to the component, so no matter where you have the mouse, just as you move it, the table just keeps slowly rotating.
      So I'm struggling with creating a vector to the new point, ptx, yes? And then I should be able to determine the angle of that vector? And then, its transformation= instead of transform! ?

      Hoping that is clear enough? I can clean up the code and post if you need.

      Thanks, as always, you guys keep saving my rear!

      --J

      1 Reply Last reply Reply Quote 0
      • Chris FullmerC Offline
        Chris Fullmer
        last edited by

        I think it sounds like you need to add more logic to watching the cursor location. You appear to have it set so that as the mouse moves a certain amount, it applies a transformation to the component. I think that's good. You just need to decide if you apply a positive or negative 15 degrees I think.

        I think what you want to do is watch the screen position of the cursor.
        If the x position increases, then:
        @comp.transform!(Geom::Transformation.new(@p0,Z_AXIS,15.degrees))

        if the x position decreases then:
        @comp.transform!(Geom::Transformation.new(@p0,Z_AXIS,-15.degrees))

        maybe it looks something like this:

        def onMouseMove(flags, x, y, view)
          if x > @x_old
            @comp.transform!(Geom;;Transformation.new(@p0,Z_AXIS,15.degrees))
          elsif x < @x_old
        	@comp.transform!(Geom;;Transformation.new(@p0,Z_AXIS,-15.degrees))
          end
          @x_old=x
        end
        

        Lately you've been tan, suspicious for the winter.
        All my Plugins I've written

        1 Reply Last reply Reply Quote 0
        • TIGT Offline
          TIG Moderator
          last edited by

          xax=object.transformation.xaxis
          will give a vector, initially it's ==X_AXIS, but once it has been rotated you'll need to get 'xax' again.
          Then you need to find the flat-angle between that and the cursor-point - let's call that p0 - and the object's insertion point [.origin]...
          org=object.transformation.origin p00=p0.clone p00.z=org.z vec=org.vector_to(p00) fangle=xax.angle_between(vec)
          Then you have a flat-angle to use in your rotation transformation [perhaps using -ve, I've not tested this!***]
          ***Also you'll need to use vec.cross(xax) to determine the flat-angle's 'direction' from the returned cross's z-axis 'sign'... because remember that picking a point 15 degrees away from the 'xax' could be on either side of the object and would return 15 as the answer both times, so the 'cross' cab tell you which side, so you can adjust the fangle +/- ?

          TIG

          1 Reply Last reply Reply Quote 0
          • H Offline
            honkinberry
            last edited by

            Ugh, still no luck.
            Among my issues -- I added a test of creating an edge, just to see what my "target" point was.
            By still keeping the .pick method in there, it just keeps "vibrating", jumping around like mad -- I'm not clear on what to test for, whether the ip.pick is too far away -- maybe if the angle calculated is more than, say, 45 degrees from what it is currently?
            But then going off of just the x,y from the mousemove, that seems off too, not sure what's wrong with that.
            And then the other problem is that the angle_between is always less than 180 degrees, so I guess I do need to use .cross or something, but at a loss for how.
            So here's what I have so far, absolutely grateful for any assistance!

            
            class PlaceandRotate
            
            	def initialize
            		@model = Sketchup.active_model
            		@p0 = nil # point about which we rotate site
            		@rotate = nil # if we are rotating site
            		@compdef = @model.definitions[0] # component to be placed
            		@comp = nil # our guy we will be placing
            		@ip = nil # input point
            	end # intialize
            
            	# activate event fires upon tool usage
            	# load component at 0,0, prep data input points
            	def activate
            		pt0 = Geom;;Point3d.new([0,0,0])
            		@comp = @model.entities.add_instance(@compdef,pt0)
            		@ip = Sketchup;;InputPoint.new
            	end # activate
            
            	# as user moves mouse, we apply a transformation to the component.
            	def onMouseMove(flags, x, y, view)
            		if ( @rotate ) # then we are just rotating site about @p0
            
            			myx = @comp.transformation.xaxis # current xaxis
            			myz = @comp.transformation.zaxis
            
            # this is not working, yet i don't want to have to do an ip.pick here, as it picks up too much clutter
            # but going off of just x,y is off, not sure how i need to apply view vector or what
            			p00 = [x,y,@p0.z] # mouse position, at same Z as component origin
            			vector = @p0.vector_to(p00) # vector from origin to mouse position on same Z
            
            # draw a test edge to confirm our p00 is good
            @model.entities.add_edges [@p0,p00] # test edge to see if it is
            # at least all the test edges are correctly on the Z plane!
            
            			fangle = myx.angle_between(vector) # but only goes up to 180.
            # need to use V.cross to determine true angle?
            
            			@comp.transformation = Geom;;Transformation.new(@p0) # reapply our point
            			@comp.transform! Geom;;Transformation.new(@p0,myz,fangle) # rotation
            # if we instead just do .transformation = .new(@p0,myz,fangle), it goes to 0,0
            
            		else # placing
            			# turn off our guy so we don't confuse him with .pick
            			@comp.visible = false
            
            			# infer our mouse point
            			@ip.pick(view, x, y)
            			ptx = Geom;;Point3d.new(@ip.position)
            
            			# after picking a clean point without component in the way, turn him back on
            			@comp.visible = true
            
            			@comp.transformation = Geom;;Transformation.new(ptx)
            
            			@p0 = ptx # save last point for when rotating
            		end # if
            	end # onMouseMove
            
            
            	# L button click, switch to rotating, or place and loop
            	def onLButtonUp(flags, x, y, view)
            		if (!@rotate) # switch to rotating
            			@rotate = true
            		else # then we are placing again!
            			@model.select_tool PlaceandRotate.new
            		end # if
            	end # onLbuttonup
            
            	# user pressed Esc, erase current plant and exit
            	def onCancel(reason, view)
            		# erase component
            		@model.entities.erase_entities @comp
            		@model.select_tool nil
            	end # onCancel
            
            end # PlaceandRotate class
            
            def pandr
            	Sketchup.active_model.select_tool PlaceandRotate.new
            end # def
            
            
            1 Reply Last reply Reply Quote 0
            • H Offline
              honkinberry
              last edited by

              Ah! I'm getting there!
              So now I just need to convert angle_between to true angle. Would that be un-normalizing it? Do something with the vectors and compare their reverses or something... hmm...

              Improved mousemove:

              
              	def onMouseMove(flags, x, y, view)
              
              		# we toggle visibility while picking the point, so it doesn't interfere
              		@comp.visible = false
              		@ip.pick(view, x, y)
              		@comp.visible = true
              		ptx = Geom;;Point3d.new(@ip.position)
              
              		if ( @rotate ) # then we are just rotating about @p0
              
              			myz = @comp.transformation.zaxis # axis we are rotating about
              
              			ptx = Geom;;Point3d.new([ptx.x,ptx.y,@p0.z]) keep at same Z
              
              			vector = @p0.vector_to(ptx) # vector from component insertion to mousepoint at same Z
              
              			fangle = X_AXIS.angle_between(vector) # angle (but only up to 180!)
              # but how do I determine if it is that, or -1 * that?
              
              			@comp.transformation = Geom;;Transformation.new(@p0) # if i don't do this first, it goes to 0,0
              			@comp.transform! Geom;;Transformation.rotation(@p0,myz,fangle)
              
              		else # placing
              			@comp.transformation = Geom;;Transformation.scaling(@scalex,@scalex,@scalex)
              			@comp.transform! Geom;;Transformation.new(ptx)
              
              			@p0 = ptx # save last point
              		end # if
              	end # onMouseMove
              
              
              1 Reply Last reply Reply Quote 0
              • H Offline
                honkinberry
                last edited by

                Ah, I see what you were saying TIG.
                Like this:

                
                			crossvector = vector.cross(X_AXIS)
                			multiplier = crossvector[2]
                			if (multiplier < 0)
                				multiplier = 1
                			else
                				multiplier = -1
                			end # if
                
                			# so now our angle is
                			fangle = X_AXIS.angle_between(vector)
                			fangle = fangle * multiplier
                
                

                No understanding of why that works, but if you say so, then it's the way to do it!

                Thanks for help, you rock!

                --J

                1 Reply Last reply Reply Quote 0
                • Chris FullmerC Offline
                  Chris Fullmer
                  last edited by

                  Did I misunderstand what you wanted? My code worked well for what I thought you were asking for. Here is your code, with mine added in. I deleted everything you had in the if ( @rotate ) portion of the onmousemove and replaced it with my snippet from above. Those went in as lines 25-30. I also initialized on line 10 the @x_old variable I introduced.

                  Test this out and see if it does what you had in mind. If not, then I totally misunderstood what you were trying to achieve ๐Ÿ’š That wouldn't entirely surprise me!

                  class PlaceandRotate
                  
                     def initialize
                        @model = Sketchup.active_model
                        @p0 = nil # point about which we rotate site
                        @rotate = nil # if we are rotating site
                        @compdef = @model.definitions[0] # component to be placed
                        @comp = nil # our guy we will be placing
                        @ip = nil # input point
                  	  @x_old = 0
                     end # intialize
                  
                     # activate event fires upon tool usage
                     # load component at 0,0, prep data input points
                     def activate
                        pt0 = Geom;;Point3d.new([0,0,0])
                        @comp = @model.entities.add_instance(@compdef,pt0)
                        @ip = Sketchup;;InputPoint.new
                     end # activate
                  
                     # as user moves mouse, we apply a transformation to the component.
                     def onMouseMove(flags, x, y, view)
                        if ( @rotate ) # then we are just rotating site about @p0
                  
                  		if x > @x_old
                  			@comp.transform!(Geom;;Transformation.new(@p0,Z_AXIS,15.degrees))
                  		elsif x < @x_old
                  			@comp.transform!(Geom;;Transformation.new(@p0,Z_AXIS,-15.degrees))
                  		end	
                  		@x_old=x
                  
                        else # placing
                           # turn off our guy so we don't confuse him with .pick
                           @comp.visible = false
                  
                           # infer our mouse point
                           @ip.pick(view, x, y)
                           ptx = Geom;;Point3d.new(@ip.position)
                  
                           # after picking a clean point without component in the way, turn him back on
                           @comp.visible = true
                  
                           @comp.transformation = Geom;;Transformation.new(ptx)
                  
                           @p0 = ptx # save last point for when rotating
                        end # if
                     end # onMouseMove
                  
                  
                     # L button click, switch to rotating, or place and loop
                     def onLButtonUp(flags, x, y, view)
                        if (!@rotate) # switch to rotating
                           @rotate = true
                        else # then we are placing again!
                           @model.select_tool PlaceandRotate.new
                        end # if
                     end # onLbuttonup
                  
                     # user pressed Esc, erase current plant and exit
                     def onCancel(reason, view)
                        # erase component
                        @model.entities.erase_entities @comp
                        @model.select_tool nil
                     end # onCancel
                  
                  end # PlaceandRotate class
                  
                  def pandr
                     Sketchup.active_model.select_tool PlaceandRotate.new
                  end # def
                  

                  Chris

                  Lately you've been tan, suspicious for the winter.
                  All my Plugins I've written

                  1 Reply Last reply Reply Quote 0
                  • H Offline
                    honkinberry
                    last edited by

                    Just a slight misunderstanding, but I wasn't totally clear.
                    I want to be able to place a component like a bench, and then immediately rotate it about the Z axis.
                    So both the placement and the rotation should be linked very smoothly to accurate cursor position.
                    My use of the 15.degrees was just a placeholder, that was actually what I wanted to derive, the angle from the component's insertion point, to the current cursor position.
                    So I was after a sort of rubber-band style rotation, basically like the Rotate tool. Yours is more of a wheel style, bumping it 15 degrees each time you nudge the mouse. That has its value too, so it's nice to have in the tool basket.
                    Thanks for the help!

                    --J

                    1 Reply Last reply Reply Quote 0
                    • Chris FullmerC Offline
                      Chris Fullmer
                      last edited by

                      Ah, got it!

                      Did you get it worked out now with TIG's code then? Or are you still trying to tidy up some loose end?

                      Chris

                      Lately you've been tan, suspicious for the winter.
                      All my Plugins I've written

                      1 Reply Last reply Reply Quote 0
                      • Dan RathbunD Offline
                        Dan Rathbun
                        last edited by

                        @honkinberry said:

                        I want to be able to place a component like a bench, and then immediately rotate it about the Z axis.
                        So both the placement and the rotation should be linked very smoothly to accurate cursor position.

                        OH.. well that is extremely EASY.

                        Because that functionality is built-into the native component placement tool, which is accessible from the Ruby API.

                        So.. for example the bench's name is "Bench Wood HighBack"

                        def place_bench()
                          mdl = Sketchup.active_model
                          compdef = mdl.definitions["Bench Wood HighBack"]
                          if compdef
                            mdl.place_component(compdef,false)
                            return true
                          else
                            return false
                          end
                        end
                        

                        The trick is the 2nd argument to Model#place_component() must be false, so that you can use the rotate handles (they appear as little red crosses,) just after you choose the insert point.

                        Insert the bench.. then move the cursor to the top of the comp's boundingbox, and you should see 4 red crosses appear. Hover over one of the cross handles, and the cursor will change to a rotate cursor. Hold & Drag (or Click Move Click,) to rotate about the Z axis.

                        ๐Ÿ’ญ

                        I'm not here much anymore.

                        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