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

    [SOLVED]Reloading Component via DefinitionsList.load Problem

    Scheduled Pinned Locked Moved Developers' Forum
    14 Posts 5 Posters 7.9k 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.
    • TommyKT Offline
      TommyK
      last edited by

      @tig said:

      How about this alternative...
      definition1.name >>> 'A' definition1.name = definitions.unique_name(definition1.name) ### e.g. A#1

      Now RE-load the component SKP ['A.skp'] and there is nothing in its way.
      Let's assume it's referenced as ' defintion2'.
      It should arrive named 'A'.

      Unfortunately, the component doesn't arrive named 'A'. definitions.load path returns the existing definition if the path is identical.

      I have tried this:

      ` model = Sketchup.active_model

      We have a single component in the model

      old_definition = model.entities[0].definition
      puts old_definition.path #=> '/HD/Users/User/cylinder.skp'

      Rename the component

      old_definition.name = model.definitions.unique_name(old_definition.name)

      Attempt to reload the component

      new_definition = model.definitions.load '/HD/Users/User/cylinder.skp'

      if new_definition == old_definition
      puts "The definitions are the same! This shouldn't happen, no?" #=> ...but it does
      end`

      It appears that the problem is not the clash of definition names when a definition is loaded, but the clash of paths between the new and old components. And you just can't change a definition path other than by loading it! Quite an omission in the API methinks.

      In the meantime, my only other option is to temporarily rename the skp file from which the component is loaded using File.rename. It's messy, but it should work ok.

      BTW - I am on Mac, Sketchup Pro 2015, and I experience this issue. I would be interested if this is the case on other platforms.

      1 Reply Last reply Reply Quote 0
      • J Offline
        Jim
        last edited by

        Which is worse: CPU time or Disk I/O time?

        You will need to do your own testing, but here's another possible work-around..

        in Windows, save the definition as "nul" (or "\\Device\\Null"), and Mac as "/dev/null/"

        These are special files that will not actually write to disk, but just throw away the data. But the definition path will be changed.

        It's not exactly what you are asking for, but maybe better than creating double files on disk.

        Hi

        1 Reply Last reply Reply Quote 0
        • TommyKT Offline
          TommyK
          last edited by

          @jim said:

          Which is worse: CPU time or Disk I/O time?

          You will need to do your own testing, but here's another possible work-around..

          in Windows, save the definition as "nul" (or "\\Device\\Null"), and Mac as "/dev/null/"

          These are special files that will not actually write to disk, but just throw away the data. But the definition path will be changed.

          It's not exactly what you are asking for, but maybe better than creating double files on disk.

          Thank you for your suggestion, Jim. I have made the test as you suggested:

          definition = Sketchup.active_model.entities[0].definition
          
          n = 50
          Benchmark.bm do |x|
            x.report("save to nul ") { for i in 1..n; definition.save_as("/dev/null"); end }
            x.report("save to desk") { for i in 1..n; definition.save_as("/Volumes/.../Desktop/cubes.skp"); end }
          end
          
                              user     system      total        real
          save to /dev/null   7.770000   0.440000   8.210000 (  8.380249)
          save to desktop     8.180000   0.630000   8.810000 ( 10.576788)
          

          There is a marginal improvement. I imagine it would be a greater improvement if the save_as path was a network drive, so well worth noting.

          Another lesson I learned in the process was understanding how fast the save_as method was. The component in the benchmark above was 3MB when saved. This works out at 0.055 seconds/MB on my Mac Pro (2008).

          This contrasts markedly from the Definitions.load method, which guzzles a lot of CPU (it takes 6 times longer):

          model = Sketchup.active_model
          
          n = 50
          Benchmark.bm do |x|
            x.report("load/save") {
              for i in 1..n
                definition = model.definitions.load("/Volumes/Storage/Users/Tommy/Desktop/Component.skp")
                definition.save_as("/dev/null")
              end
            }
            x.report("save to null ") { for i in 1..n; Sketchup.active_model.entities[0].definition.save_as("/dev/null"); end }
          end
                         user     system      total        real
          load/save      59.010000   2.180000  61.190000 ( 61.211738)
          save to null   8.720000   0.440000   9.160000 (  9.310672)
          

          So the way ahead is clear. Save to change the path, then load only once.

          1 Reply Last reply Reply Quote 0
          • tt_suT Offline
            tt_su
            last edited by

            Have you tried to "touch" the old definition first by making a small change like entities.add_cpoint(ORIGIN) then trying to load the new?

            1 Reply Last reply Reply Quote 0
            • J Offline
              Jim
              last edited by

              Hmm, if you add an empty Group instead of a CPoint it also works; and then you may need to worry less about cleaning up since the empty group will get swept away.

              Hi

              1 Reply Last reply Reply Quote 0
              • TommyKT Offline
                TommyK
                last edited by

                @tt_su said:

                Have you tried to "touch" the old definition first by making a small change like entities.add_cpoint(ORIGIN) then trying to load the new?

                Yes, I did! And it works. Happy camper.

                1 Reply Last reply Reply Quote 0
                • tt_suT Offline
                  tt_su
                  last edited by

                  @jim said:

                  Hmm, if you add an empty Group instead of a CPoint it also works; and then you may need to worry less about cleaning up since the empty group will get swept away.

                  Good point. (No pun intended)

                  I'll file up the issue internally so we'll look into it.

                  1 Reply Last reply Reply Quote 0
                  • M Offline
                    masp
                    last edited by

                    This is a very useful thread: I'm trying to apply this workaround (add_cpoint) but I'm still getting an identical GUID. Would you mind posting the actual solution, so there's an explicit example I can refer to? For what it's worth, this is my attempt (I'm trying to automate re-loading certain components from their .skp files):

                    
                        model = Sketchup.active_model
                        selection_set = model.selection
                        selection = selection_set[0]
                        definition = selection.definition
                        definition.entities.add_cpoint(ORIGIN)   # not sure if I'm applying this to the correct entity
                        new_definition = model.definitions.load(definition.path)
                        puts "Old GUID; " + definition.guid
                        puts "New GUID; " + new_definition.guid
                    
                    

                    I'm not sure if I'm applying add_cpoint() to the right entity; also I'm not sure whether creating an empty group is a better workaround as suggested in the thread, or how to do that!).

                    Finally, this is how I hope to replace the instances (based on someone else's example):

                    
                          definition.instances.each { |instance|
                            instance.parent.entities.add_instance(new_definition, instance.transformation)
                            instance.erase!
                          }
                    
                    

                    Many thanks, and hugely appreciated!

                    Mike

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

                      Your first block of code changes the selected instance's definition's entities, by adding the cpoint.
                      At that point I'd also rename it e.g. definition.name=definition.name+rnd.to_s

                      This should then mean that a re-load of the original definition from the external SKP makes a new definition, auto-reusing its earlier name.

                      Next you need to swap out any existing instances of the original definition, to use the new definition...
                      definition.instances.each{|i|i.definition=new_definition}

                      Finally you can clear the entities of the original definition to remove it from the model's definitions list.
                      definition.entities.clear!
                      Note that you need to have all of this code inside a model.start_...commit_operation block for it to take immediate effect...

                      TIG

                      1 Reply Last reply Reply Quote 0
                      • M Offline
                        masp
                        last edited by

                        Thanks for the quick reply! I think I've done everything right, but I only get a new definition (loaded) when I use the write-to-dev-null trick (but it's painfully slow!). When I use the add_cpoint() or add_group() trick my SKP file is ignored and I get the same GUID back. Here's my full script, if you don't mind taking a look:

                        
                        require "sketchup.rb"
                        
                        module RefreshComponent
                          def self.force_reload_component_definition!(model, definition)
                            definition_path = definition.path
                            definition_name = definition.name
                            definition.name = definition.name + rand.to_s
                        ##    definition.entities.add_cpoint(ORIGIN)     ## <== this causes GUIDs to match (fail)
                            definition.save_as("/dev/null")              ## <== this causes new definition load (success)
                            reloaded_definition = model.definitions.load(definition_path)
                            puts "Old GUID; " + definition.guid
                            puts "New GUID; " + reloaded_definition.guid
                            reloaded_definition
                          end
                        
                          def self.reconnect_component_instances!(model, old_definition, new_definition)
                            model.start_operation("Remap instances")
                            old_definition.instances.each { |instance| instance.definition = new_definition }
                            model.commit_operation
                          end
                        
                          def self.delete_component_definition!(model, definition)
                            model.start_operation("Delete Definition")
                            definition.entities.erase_entities(definition.entities.to_a)
                            model.commit_operation
                          end
                        
                          def self.refresh_component(model, definition)
                            model.start_operation("Reload current component definition", true)
                            reloaded_definition = force_reload_component_definition!(model, definition)
                            reconnect_component_instances!(model, definition, reloaded_definition)
                            delete_component_definition!(model, definition)
                            model.commit_operation
                          end
                        
                          def self.start
                            model = Sketchup.active_model
                            model.start_operation("Reload component definitions from file", true)
                            model
                              .selection
                              .select { |entity| entity.is_a?(Sketchup;;ComponentInstance) }
                              .map { |instance| instance.definition }
                              .uniq
                              .each { |definition| refresh_component(model, definition) }
                            model.commit_operation
                          end
                        end 
                        
                        unless file_loaded?("refresh_component.rb")
                            UI.add_context_menu_handler do |context_menu|
                              context_menu.add_item("Reload Current Component Definition") {
                                RefreshComponent.start
                              }
                            end
                           file_loaded("refresh_component.rb")
                        end
                        
                        
                        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