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

    New to Ruby - I want to write a script to...

    Scheduled Pinned Locked Moved Developers' Forum
    26 Posts 5 Posters 924 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.
    • K Offline
      keithswd
      last edited by

      Dan - thanks for the response but I don't see how it would help me. I have a large number of components (actually a purchased library of entourage images as .skp files) which are not set up to Face-Me. Each time I insert one for the first time I have to set these two properties. I then save the component back to the file so I don't need to do it for that file again, but there are a hell of a lot yet to be updated...

      I hadn't expected any issues with T&C though!

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

        Oh and BTW... batch mode processing is easier on Windows as the same document window is reused, so that their is only ever ONE model file open, at a time.

        Mac SketchUp will open a new document window for EVERY file in the folder, because there is no way via the API to close model windows.

        The API does NOT have a built-in interface to simulate user keystrokes (in order to dismiss modal dialogs, etc.)

        You would have to use a 3rd-party utility. Some use Applescript on Mac.

        I'm not here much anymore.

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

          @driven said:

          @dan rathbun said:

          (2) Read the Terms of Use regarding using (or forbidding use of,) SketchUp in an "automated manner".

          my take on this is as long as your 'offline' you are not overburdening, Trimble's services in any way, in which case you can use 'Automator.app' to sequentially open and perform actions on your files.

          Yes that also makes sense to me.. but I have also had to deal with lawyers in the past, and they come from a galaxy far far away... and do not think like us mere mortals.

          YES I DO know how to do it. BUT I am wary of distributing such a utility (which I have already written to about 90% done.)

          I'm not here much anymore.

          1 Reply Last reply Reply Quote 0
          • K Offline
            keithswd
            last edited by

            I could do it Windows (via Parallels). Or perhaps process the components within a single model:
            Load component from file
            Set attributes
            Save component back to file
            Delete component instance
            Purge component
            Next

            I'll get reading the Newbie guides... Thanks again.

            1 Reply Last reply Reply Quote 0
            • D Offline
              driven
              last edited by

              hi Keith,
              the first bits relatively easy. if you paste this into 'Ruby Console' and hit 'return' it will open and mod all the .skp's found. Personally I find 'shadows_face_sun' a bit odd looking...

              # add your folder your path replaces this
              loadFolder =  "/your/path" 
              
              skpFiles = Dir[File.join( loadFolder, "*.skp" )]
              
              #open the files
              skpFiles.each {|f| 
              Sketchup.open_file f;
              # do your ruby actions
              Sketchup.active_model.selection.to_a.find_all{|e|e.class==Sketchup;;ComponentInstance}.map{|i|i.definition}.each{|d|d.behavior.always_face_camera=true; d.behavior.shadows_face_sun = true}
              }
              

              once there all done, you can either use Cmd "S" to save them, and if in the correct format Cmd "W" to close...

              alternatively, you could run this Applescript which will do the save and click any drop-downs that appear.
              for some reason it stalls on some windows, but if you click the error box and then 'Run' again it carries on.
              Run in Applescript Editor after all the skps are open...

              activate application "SketchUp"
              tell application "System Events"
              	tell process "SketchUp"
              		set winCount to count of every window
              		repeat with n from 1 to winCount
              			if description of window n is "standard window" then
              			set thisWindow to window n
              				try
              					if exists (click menu item "Save" of menu "File" of menu bar 1) then
              					end if
              				end try
              				delay 0.5
              				try
              					if exists (click button "Save" of sheet 1 of thisWindow) then
              					end if
              				end try
              				delay 0.5
              				try
              					if exists (click button "Replace" of sheet 1 of sheet 1 of thisWindow) then
              					end if
              				end try
              				delay 0.5
              				try
              					if exists (click menu item "Close" of menu "File" of menu bar 1) then
              					end if
              				end try
              			end if
              		end repeat
              	end tell
              end tell
              

              learn from the mistakes of others, you may not live long enough to make them all yourself...

              1 Reply Last reply Reply Quote 0
              • K Offline
                keithswd
                last edited by

                Driven - Thanks so much for taking the time to write that up for me.

                Unfortunately I don't think this approach will work as it seems that it opens all the files in the folder in one go? I have hundreds of files to process (although I could put them into a working folder in batches I suppose). I am going to try modifying your code to get the array of *.skp files in the folder, then sequentially load each one as a component, modify it, save it back to the folder, delete and purge the instance, and move on to the next file. It seems like that will avoid the issue of not being able to close the current model via Ruby, and will only open one component at a time.

                cheers Keith

                1 Reply Last reply Reply Quote 0
                • K Offline
                  keithswd
                  last edited by

                  This code appears to work on a test folder of 10 .skp files. Haven't let it loose on the main folder of 500!

                  model = Sketchup.active_model
                  
                  # set folder and get array of filenames
                  loadFolder = "/Users/Keith/Illustration Library/Testfolder"
                  skpFiles = Dir[File.join(loadFolder, "*.skp")]
                  
                  
                  # Returns a DefinitionList
                  definitions = model.definitions
                  
                  # iterate through files
                  
                  skpFiles.each do |compFile|
                  	compDefinition = definitions.load compFile
                  	behavior = compDefinition.behavior
                  	behavior.always_face_camera = true
                  	behavior.shadows_face_sun = true
                  	compDefinition.save_as compFile
                  	definitions.purge_unused
                  	end
                  

                  no error handling of course so it's a bit 'quick and dirty'.

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

                    @unknownuser said:

                    This code appears to work on a test folder of 10 .skp files. Haven't let it loose on the main folder of 500!

                    no error handling of course so it's a bit 'quick and dirty'.

                    Yes make backups first.

                    And when it comes to file work trapping errors is best.

                    I would think that the user would be prompted to overwrite the old skp file.

                    You don't see a confirm MB on the Mac ?

                    I'm not here much anymore.

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

                      If you make a subfolder then you can save the reformatted SKPs into there and leave the original SKPs alone...
                      That way you never change the original SKPs' data and don't need prompts etc... 😕

                      TIG

                      1 Reply Last reply Reply Quote 0
                      • K Offline
                        keithswd
                        last edited by

                        As the code stands it runs without any prompts at all. It processed 10 files in the folder in an instant. For my purposes I'd rather manually copy files to be processed into the folder and run the script unattended, knowing I had my own backups. It's only for me to use so I c an leave it rough and ready... Might be nice to select the folder via the file open dialog, other than that I think it serves my needs

                        Thanks to all for the help and encouragement.

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

                          @unknownuser said:

                          Might be nice to select the folder via the file open dialog, ...

                          folder = UI.openpanel("Choose a skp file to set folder","*.skp")
                          if folder && folder = File.dirname(folder)
                            # do your stuff
                          end
                          

                          I'm not here much anymore.

                          1 Reply Last reply Reply Quote 0
                          • D Offline
                            driven
                            last edited by

                            @unknownuser said:

                            Thanks to all for the help and encouragement.

                            no problem Keith,
                            we need to encourage mac users who are prepared to dip into coding, we're in a minority,
                            if nothing else, there are always PC authored scripts that need a bit of ironing before they're fully mac compatible.

                            @dan wrote a good 'chunking' script for me to process a 3D text sampler that may be useful/adaptable for handling a 500 file array. I'll see if I can find the link.
                            FOUND: http://sketchucation.com/forums/viewtopic.php?f=180&t=48761&p=444342&hilit=3d+text+chunk#p444342
                            john

                            PS, are you in London UK, or one of the impostors, I'm in East Dulwich?

                            learn from the mistakes of others, you may not live long enough to make them all yourself...

                            1 Reply Last reply Reply Quote 0
                            • K Offline
                              keithswd
                              last edited by

                              Ah - I was wondering what might happen if I loaded a really huge folder - actually I have a couple of thousand file to process. Not all at once though... I will check out that link when I have more time, at first glance looks a bit scary for a novice!

                              Yes, I really am in London UK (live in W14, work SE11)!

                              1 Reply Last reply Reply Quote 0
                              • K Offline
                                keithswd
                                last edited by

                                Thanks Dan for the pointer to UI.openpanel, that all works fine.

                                Not sure if it is because I need to learn about chunking my array, but my routine stops every time after processing 33 or 34 files (it is always after 33 or 34 files) and then SU8 crashes. Given that such a small number of files are processed before the hang/crash, I am not sure the array size is the problem? When the script stops running, I am left with the last loaded component in the component list. If I try and and check its 'Face-Me' status, SU crashes.

                                def setcompfm
                                
                                model = Sketchup.active_model
                                # set folder and get array of filenames
                                folder = UI.openpanel("Choose a skp file to set folder","*.skp")
                                
                                if folder && folder = File.dirname(folder)
                                	skpFiles = Dir[File.join(folder, "*.skp")]
                                end
                                
                                length = skpFiles.length
                                
                                result = UI.messagebox "Process " + length.to_s + " files?", MB_YESNO
                                
                                if result == 6 # Yes
                                
                                # Returns a DefinitionList
                                definitions = model.definitions
                                
                                # iterate through files
                                begin
                                
                                	skpFiles.each do |compFile|
                                
                                		compDefinition = definitions.load compFile
                                		behavior = compDefinition.behavior
                                		behavior.always_face_camera = true
                                		behavior.shadows_face_sun = true
                                		compDefinition.save_as compFile
                                		definitions.purge_unused
                                
                                	end #end do
                                
                                rescue
                                	puts compFile
                                
                                end #end begin
                                
                                end #end if
                                
                                end #end def
                                
                                1 Reply Last reply Reply Quote 0
                                • Dan RathbunD Offline
                                  Dan Rathbun
                                  last edited by

                                  The folder check was meant to enclose everything... but I see you have a empty folder check (which probably cannot happen because an actual file must be selected. BUT...

                                  change line 7 to:
                                  return unless folder && folder = File.dirname(folder)

                                  REMOVE the end (line 9)

                                  If you cancel the open panel, NOW your method exits (because the result of UI.openpanel will eval falsely.)

                                  I'm not here much anymore.

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

                                    change the name of THAT 33rd or 34th file to ".OFF" or whatever.

                                    Then try again. Just eliminate the bad file scenario.

                                    I'm not here much anymore.

                                    1 Reply Last reply Reply Quote 0
                                    • K Offline
                                      keithswd
                                      last edited by

                                      Thanks for the correction - I see my mistake now. However, the corrected syntax doesn't fix the crash. The folder selection works as it did before and populates the array with all the .skp files in the folder (about 200 for testing purposes), and my message box pops up and correctly reports the number to be processed.

                                      However it stops on the 33rd or 34th file no matter what that file is. Each time I run the script, I move the 33/34 successfully modified files out of the folder, so I am never processing the same files twice. I don't know what might be special about the 33/34 mark, but it bails at that point.

                                      Some kind of limit appears to be reached? Memory? I've no clue!

                                      1 Reply Last reply Reply Quote 0
                                      • D Offline
                                        driven
                                        last edited by

                                        not sure how to do it in ruby but in the osascript/applescript/bash I tend to use, if you don't add a distinct delay point, the process reaches some limit and errors. [That's what happening with the one I posted earlier]

                                        maybe adding a puts "done" after definitions.purge_unused will allow a break before opening the next?

                                        total stab in the dark
                                        john

                                        learn from the mistakes of others, you may not live long enough to make them all yourself...

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

                                          (1) The iterator block.. use curly braces instead of do ... end
                                          So the block can have access to external references, such as definitions

                                          (2) Make sure the loading is done before proceeding.

                                          (3) perhaps use undo operations ?

                                          Try an iterator like:

                                            i = 0
                                            puts()
                                            #
                                            skpFiles.each { |compFile|
                                              ###
                                              model.operation( "Update '#{File.basename(compFile)}'", true )
                                              ###
                                              compDefinition = definitions.load compFile
                                              begin
                                                if compDefinition.internal?
                                                  behavior = compDefinition.behavior
                                                  behavior.always_face_camera = true
                                                  behavior.shadows_face_sun = true
                                                  compDefinition.save_as compFile
                                                else
                                                  putc(46) # period char
                                                  redo
                                                end
                                              rescue => e
                                                ###
                                                model.abort_operation()
                                                ###
                                                puts()
                                                puts "ERROR saving component file;"
                                                puts "  #{compFile}\n"
                                                puts e.message
                                                puts e.backtrace if $VERBOSE
                                                puts()
                                              else
                                                i += 1
                                                if i >= 10
                                                  definitions.purge_unused
                                                  i = 0
                                                end
                                                ###
                                                model.commit_operation()
                                                ###
                                              end
                                              # each skp file
                                            }
                                            definitions.purge_unused if definitions.length > 0
                                          
                                          

                                          I'm not here much anymore.

                                          1 Reply Last reply Reply Quote 0
                                          • K Offline
                                            keithswd
                                            last edited by

                                            Thanks again for your help and suggested code. As it stands it does not modify any components. I discovered this is because it seems that even when the component file is loaded successfully, compDefinition.internal? returns false. I can only imagine that this is actually testing whether the component was created within the model or loaded from a file - in which case we are getting the expected result. I commented it out and it runs but... sadly it still bombs out at around 33 components.

                                            I really don't want to take up any more of anyone's time - this was just a little project for me to play with but it seems rather trickier than I could have forseen. But I thought you might like an update!

                                            def setcompfm
                                            
                                            model = Sketchup.active_model
                                            # set folder and get array of filenames
                                            folder = UI.openpanel("Choose a skp file to set folder","*.skp")
                                            
                                            return unless folder && folder = File.dirname(folder)
                                            
                                            skpFiles = Dir[File.join(folder, "*.skp")]
                                            
                                            length = skpFiles.length
                                            
                                            result = UI.messagebox "Process " + length.to_s + " files?", MB_YESNO
                                            
                                            return unless result == 6 # Yes
                                            
                                            # Returns a DefinitionList
                                            definitions = model.definitions
                                            
                                            # iterate through files
                                            i = 0
                                              puts()
                                              #
                                              skpFiles.each { |compFile|
                                                ###
                                                model.start_operation( "Update '#{File.basename(compFile)}'", true )
                                                ###
                                                compDefinition = definitions.load compFile
                                                begin
                                                  #if compDefinition.internal?
                                                    behavior = compDefinition.behavior
                                                    behavior.always_face_camera = true
                                                    behavior.shadows_face_sun = true
                                                    compDefinition.save_as compFile
                                                  #else
                                                  #  putc(46) # period char
                                                  #  redo
                                                  #end
                                                rescue => e
                                                  ###
                                                  model.abort_operation()
                                                  ###
                                                  puts()
                                                  puts "ERROR saving component file;"
                                                  puts "  #{compFile}\n"
                                                  puts e.message
                                                  puts e.backtrace if $VERBOSE
                                                  puts()
                                                else
                                                  i += 1
                                                  if i >= 10
                                                    definitions.purge_unused
                                                    i = 0
                                                  end
                                                  ###
                                                  model.commit_operation()
                                                  ###
                                                end
                                                # each skp file
                                              }
                                              definitions.purge_unused if definitions.length > 0
                                            
                                            
                                            end #end def
                                            
                                            1 Reply Last reply Reply Quote 0
                                            • 1
                                            • 2
                                            • 2 / 2
                                            • First post
                                              Last post
                                            Buy SketchPlus
                                            Buy SUbD
                                            Buy WrapR
                                            Buy eBook
                                            Buy Modelur
                                            Buy Vertex Tools
                                            Buy SketchCuisine
                                            Buy FormFonts

                                            Advertisement