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

    [Code] AnimateSelection Example v1.0.1

    Scheduled Pinned Locked Moved Developers' Forum
    12 Posts 4 Posters 1.4k 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.
    • renderizaR Offline
      renderiza
      last edited by

      Thank you

      I will study this code very carefully so I can learn how to make changes if needed to accomplish what I want.

      [url=https://www.sketchupcode.com/:z3kqsidd]My Extensions ...[/url:z3kqsidd]

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

        Notice how:

        • No $ global variables are used:

        • Instead @@ module variables are used.

        • All code is executing (defined and evaluated,) within the Author's namespace.

        • (With the exception of the require('sketchup.rb') statement at the top. It also could have been put within the Author's namespace, but serves to provide an exit if the file is loaded into standard Ruby outside SketchUp.)

        I'm not here much anymore.

        1 Reply Last reply Reply Quote 0
        • T Offline
          todd burch
          last edited by

          #  AnimateSelection Example
          #
          #  Contributors;
          #  Martin Rinehart, Chris Fullmer, Dan Rathbun
          #
          #  Version ; 1.0.0
          #
          #  Bug Fixes / Enhancements;
          #  Version 1.0.1  October 23, 2012  Todd Burch 
          #                 1. @elapsed not being calculated properly 
          #                 2. Group entire selection to perform just 1 transformation per 
          #                     frame, and surround all that within a commit scope.  
          #
          
          require('sketchup.rb')
          
          module Author  # <-- replace with the name of YOUR toplevel namespace module
          
            module AnimateSelection
            
              VERSION ||= '1.0.1'
            
              @@menu_loaded ||= false
              
              @@delay ||= 0.5
              @@duration ||= 15
              
              @@vlength ||= 1.to_l
          
              class Animate
              
          	def initialize( objs, trans, delay = 0.5, duration = 15 )
                  @delay = delay.to_f 
                  @t = trans
                  @objs = objs
                  @start = Time.now.to_i 
                  @duration = duration
                  @elapsed = 0
                end
          
          	def nextFrame( view )
          		model = view.model									# new code V1.0.1 
          		model.start_operation("Animation Move")				# new code V1.0.1
          		group = model.active_entities.add_group(@objs) ;	# new code V1.0.1     
          		group.transform!( @t )								# new code V1.0.1
          		group.explode										# new code V1.0.1
          		model.commit_operation								# new code V1.0.1 
          		@elapsed = Time.now.to_i - @start					# new code V1.0.1
          		if @elapsed < @duration
          			view.show_frame( @delay )
          		else
          			return false # stops the animation
          		end
          	end
                
                def pause()
                  @start = 0
                end
          
                def resume()
                  @start = Time.now.to_i
                end
          
                def stop()
                  puts("Animation Complete (#{@elapsed} secs)")
                end
          
              end # class Animate
          
              class << self # Proxy class of AnimateSelection module
              
                def animate(objs,vec,view=Sketchup.active_model.active_view)
                  #
                  t = Geom;;Transformation.new(vec)
                  #
                  view.animation = Animate.new(objs,t,@@delay,@@duration)
                  #
                end
                
                def delay_input(title='Enter Delay')
                  #
                  prompt = 'Frame Delay (secs); '
                  default = @@delay
                  num = UI.inputbox( [prompt], [default], title ) 
                  #
                  if num
                    @@delay = set_delay(num[0])
                  end
                  #
                end
              
                def set_delay(num=0.5)
                  @@delay = num.to_f rescue 0.5
                end
              
                def duration_input(title='Enter Duration')
                  #
                  prompt = 'Animate Duration (secs); '
                  default = @@duration
                  num = UI.inputbox( [prompt], [default], title ) 
                  #
                  if num
                    @@duration = set_duration(num[0])
                  end
                  #
                end
              
                def set_duration(num=15)
                  @@duration = num.to_i rescue 15
                end
              
                def vector_input(title='Enter Vector Length')
                  #
                  prompt = 'Vector length; '
                  default = @@vlength # Length class instance
                  vec = UI.inputbox( [prompt], [default], title ) 
                  #
                  if vec
                    @@vlength = vec[0] if @@vlength != vec[0] 
                    return vec[0]
                  else
                    return false
                  end
                  #
                end
              
              end # proxy class
              
              unless @@menu_loaded
          
                # Build Popup Context Menu;
                UI.add_context_menu_handler {|popup|
                  sel = Sketchup.active_model.selection
                  unless sel.empty? # show the submenu;
                    objs = sel.to_a
                    view = sel.model.active_view
                    animenu = popup.add_submenu('Animate Selection')
                    #
                    animenu.add_item('Vector Animate X') {
                      vecX = vector_input('Vector X Length')
                      vec  = Geom;;Vector3d.new(vecX,0,0)
                      animate(objs,vec,view)
                    }
                    animenu.add_item('Vector Animate Y') {
                      vecY = vector_input('Vector Y Length')
                      vec  = Geom;;Vector3d.new(0,vecY,0)
                      animate(objs,vec,view)
                    }
                    animenu.add_item('Vector Animate Z') {
                      vecZ = vector_input('Vector Z Length')
                      vec  = Geom;;Vector3d.new(0,0,vecZ)
                      animate(objs,vec,view)
                    }
                    animenu.add_separator
                    animenu.add_item('Set Duration ...') {
                      duration_input()
                    }
                    animenu.add_item('Set Frame Delay ...') {
                      delay_input()
                    }
                    #
                  end
                }
          
                # Mark file as loaded once;
                @@menu_loaded = true
                file_loaded("AnimateSelection;#{File.basename(__FILE__)}")
          
              end
          
            end # module AnimateSelection
          
          end # Author's toplevel namespace module
          
          
          1 Reply Last reply Reply Quote 0
          • Dan RathbunD Offline
            Dan Rathbun
            last edited by

            Good Job Todd. πŸ‘

            Add your name to the contributors.

            I'm not here much anymore.

            1 Reply Last reply Reply Quote 0
            • thomthomT Offline
              thomthom
              last edited by

              Why make a group to do a bulk transformation? Why not just apply the transformation to all entities with .transform_entities ? Should be even less overhead with out group and explode. Explode can even mess about with geometry as it triggers merge and intersection.

              ent.parent.entities.transform_entities(@t,@objs)

              ❓

              Thomas Thomassen β€” SketchUp Monkey & Coding addict
              List of my plugins and link to the CookieWare fund

              1 Reply Last reply Reply Quote 0
              • T Offline
                todd burch
                last edited by

                I made a group because as the model was being twisted and torqued out of shape due to moving one entity at a time, SU was also leaving some bits un-transformed (obviously a bug) and that caused the model to be incorrect at the end of the animation.

                Your solutions works fine too, removing

                
                group = model.active_entities.add_group(@objs) ;	
                group.transform!( @t )
                group.explode
                

                and replacing it with

                
                @objs[0].parent.entities.transform_entities(@t,@objs)
                
                1 Reply Last reply Reply Quote 0
                • Dan RathbunD Offline
                  Dan Rathbun
                  last edited by

                  OK I see that @elapsed is still not correct.

                  The intention is that when the animation is paused, the "clock stops running", and starts again when it resumes.

                  What was the error you were seeing Todd?

                  I'm not here much anymore.

                  1 Reply Last reply Reply Quote 0
                  • T Offline
                    todd burch
                    last edited by

                    Ha! No such thing as not working correct when there are no statements or comments about what it should be doing! BTW, there is no mechanism to pause this, so how was that supposed to work? V2?

                    As I said, the model is moved one entity at a time. First, an edge, then a face, then a group, etc...

                    Here are two pictures that show 2 bugs in the original code. There is a face and then 2 connected lines outside the face (7 entities total). You can see the starting position (Before) and the ending position (After) when the animation is complete.

                    Before After

                    bug1: The angle of the two connected lines is now turned inside out.

                    bug2: Because of the user-chosen duration and frame delay, the square, at the end of the animation, is now a skewed polygon, since the animation ended before the square could be transformed into square again (since it is being moved a piece at a time).

                    EDIT: FYI: for my example, the square is 30" each side, the delay is 1 second and the duration is 15 seconds.

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

                      @unknownuser said:

                      Ha! No such thing as not working correct when there are no statements or comments about what it should be doing! BTW, there is no mechanism to pause this, so how was that supposed to work? V2?

                      Yep.. ya' got me there. I did not read the API Dictionary well, and assumed the stop and start buttons work for custom Animations (which the docs say does not yet work. But implies perhaps they will in the future.)

                      So the pause() and resume() methods either need to come out, or... create our own animation control toolbar.

                      One thing I did not have time to do was "steal" code from the "linetool.rb" and add a "Draw Move Vector" option.

                      I'm not here much anymore.

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

                        @unknownuser said:

                        As I said, the model is moved one entity at a time. First, an edge, then a face, then a group, etc...

                        Ok I get it now. I did not notice because the OP in the original thread that instigated this was moving groups. And I tested it moving a grouped manifold cube.

                        The OP (I think,) never had the else clause that moved individual entities. I believe that it was I that added that in as a "bonus" (which it now turns out to be a headache.)

                        Undo ops: It was discussed in the other thread, that using move!() might be better so that the undo stack is not cluttered.

                        I did not make that change because of course it only works on groups and instances, not primitives. (And I don't remember whether I thought of grouping primitives like you did or not. Simply, it was aimed at the request of the Op in the companion thread, which has a link to this one, in order to show how to use the animation class in the manner he wanted. I had to get it posted that day, and then I moved on to other projects.)

                        So.. again good debugging job. I also agree this example needs to be made more general. But bear in mind it's really a teaching example, and not meant to be a plugin, really.

                        How about a "Undoable" menu option (checked/unchecked) ?
                        If checked an undo operation is created (but I would propose it wrap the entire animation, if possible,) and the code uses transform!(); if unchecked the code uses move!()


                        Just thinking out loud... Examples should clear and as simple as possible. It we get too fancy the answer to the original question becomes obscured. The question was:
                        "How do I use the API's Animation class to move a group in a certain direction."

                        Ordinarily the coder will hard code the duration, delay and the vector will come from some other part of his code. I added in the popup menu, and input boxes for delay and duration, only for development purposes. Ie, the coder would play with the settings, until they liked what happened then use those values to assign to the instance variables.

                        Here, I am thinking I may have confused things a bit by adding in these UI features. (It makes the example look like a plugin, although it is not intended to be. I thought it would be nice to be able to fire the animation via the menu, rather than force the "learner" to type a method name at the Ruby Console.)

                        I'm not here much anymore.

                        1 Reply Last reply Reply Quote 0
                        • T Offline
                          todd burch
                          last edited by

                          I understood it was an example, but the logic of the code told me it accepted primitives, and primitives didn't work like they should have, nor did the duration work as expected.

                          As an example, for its intent, it's fine and I would not bother (other than adding comments for the learner) with any additional enhancements.

                          Todd

                          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