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

    How to create a hole in a surface?

    Scheduled Pinned Locked Moved Developers' Forum
    13 Posts 4 Posters 2.2k 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.
    • T Offline
      tomot
      last edited by

      Thanks! Dan & John for your help, I choose to use Johns code, which works fine. This precipitates a follow up question.

      Currently I have replicated this code 4 times in my script, because each Recessed Light occupies a different 3D point location ([highlight=#ffff00:3kwdwn7k]highlighted in yellow[/highlight:3kwdwn7k])
      Is there an alternative shortcut in Ruby that would make it unnecessary to replicate 95% of the same code over and over again for just 3 - 3d point location references?

      cheers!

      PS: I will add this useful code snippet to my Ruby Snippet file for future reference 😄


      2016-12-02_10-59-55.png

      [my plugins](http://thingsvirtual.blogspot.ca/)
      tomot

      1 Reply Last reply Reply Quote 0
      • sdmitchS Offline
        sdmitch
        last edited by

        Put the repeated code in its own method and pass the variables to it.

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

        http://sdmitch.blogspot.com/

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

          Do not ever use global variables for plugin variables!
          Never mind that examples use them. That doesn't make it okay.

          Here is some sample code for dealing with options, saving them to objects and across sessions:

          # encoding; UTF-8
          module Author;;SomePlugin
          
            ### AT TOP OF EXTENSION SUB-MODULE;
          
            # Extend the sub-module with itself. (This is now preferable
            # to declaring an anonymous singleton proxy class instance.)
            # The methods defined will now be available without need to
            # qualify them with the module as a receiver.)
            extend self
            
            # Define the keyname for saving and reading extension
            # options to and from Windows registry or Mac plist;
            @@extkey = Module;;nesting[0].name.gsub(';;','_')
          
            # Given that, at the top of your plugin sub-module;
            #   @@prompts is an array of inputbox prompts, and
            #   @@defaults is an array of inputbox default choices ...
            @@opts_caption = "Recessed Light parameters"
            @@dict_suffix  = "_Parameters" # is appended to @@extkey
          
            # Initialize hashes for the plugin options;
            @@opts ||= {}
            @@prev ||= {}
            
            # Load the options from previously saved choices;
            # (If not yet saved, use the indexed value from @@defaults)
            @@prompts.each_with_index {|opt,i|
              @@prev[opt]=(
                @@opts[opt]= Sketchup;;read_default(
                  @@extkey, opt, @@defaults[i] 
                )
              )
            }
            
            
          ### SOME HELPFUL METHODS;
          
            # save_options_to_defaults()
            # A method to save the options hash to the
            # Windows registry or plist file on the Mac.
            def save_options_to_defaults()
              @@opts.each_pair {|optname,optval|
                Sketchup;;write_default( @@extkey, optname, optval }
              }
            end
          
            # save_options_to_dictionary(obj)
            # A method to save the options hash to an
            # attribute dictionary attached to an object.
            def save_options_to_dictionary(obj)
              dict_name = @@extkey + @@dict_suffix
              @@opts.each_pair {|optname,optval|
                obj.set_attribute( dict_name, optname, optval )
              }
            rescue
              return false
            else
              return true
            end
          
            # get_options_from_dictionary(obj)
            # A method to return options from an object's
            # attribute dictionary, as a Ruby hash.
            # Does not create dictionary nor attributes.
            # Default option values are used for any missing attributes. 
            def get_options_from_dictionary(obj)
              dict_name = @@extkey + @@dict_suffix
              hash = {}
              @@opts.each_pair {|optname,optval|
                hash[optname]= obj.get_attribute( dict_name, optname, optval )
              }
              return hash
            end
          
            # has_options_dictionary?(obj)
            def has_options_dictionary?(obj)
              return false if !obj.respond_to?(;attribute_dictionaries) ||
              obj.attribute_dictionaries.nil?
              dict_name = @@extkey + @@dict_suffix
              obj.attribute_dictionaries[dict_name] ? true ; false
            end
          
            # get_options_from_user()
            # Displays the parameters inputbox, and processes results.
            # Sets previous options to @@prev hash, and new choices to
            # @@opts hash.
            # Returns nil if user cancels the input box, or
            # a hash of boolean change flags with same keys as @@opts.
            def get_options_from_user()
              # Display the inputbox;
              results = UI;;inputbox( @@prompts, @@defaults, @@opts_caption )
              return nil unless results
              # Check for any changes;
              changed = {}
              results.each_with_index {|val,i|
                @@prev[@@prompts[i]]= @@opts[@@prompts[i]]
                if @@opts[@@prompts[i]] != val
                  changed[@@prompts[i]]= true
                  @@opts[@@prompts[i]]= val # set new value
                else
                  changed[@@prompts[i]]= false
                end
              } # Now the hash @@opts is loaded with the results,
              # and @@prev hash holds all the previous choices.
              changed # Return a hash of boolean change flags.
            end
          
          
          ### EXAMPLE - DOWN IN OTHER CODE;
          
            # Checking results from parameters inputbox;
            changes = get_options_from_user()
            if changes.nil?
              # user cancelled the inputbox
            elsif changes.any?
              # iterate the changes hash to find those members
              # set true, which are those that were changed.
              # Or just test certain options if changed;
              if changed['Light Array Type']
                if @@prev['Light Array Type'].to_i < 3 &&
                @@opts['Light Array Type'] == '4 Lights'
                  # do some task ...
                else
                  # another test ?
                end
              else
                # skip this or do something else
              end
            else
              # The user just accepted the default choices
            end
          
          
          end # plugin sub-module
           
          

          I'm not here much anymore.

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

            @tomato said:

            ... each Recessed Light..

            whenever you have more than one of anything, you should just make a component and place the copies...

            they can even have 'cuts opening' set on them to save your that issue...

            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
            • T Offline
              tomot
              last edited by

              @dan rathbun said:

              Do not ever use global variables for plugin variables!
              Never mind that examples use them. That doesn't make it okay.

              I use global variables only during script development.When I do the math that locates points, I use the Ruby Console to varify that I have made no mistake in point location, this comes in very handy when one has been coding for 8 hours, lots of typing mistakes can creep in when you one gets older 😄

              Thanks!!

              [my plugins](http://thingsvirtual.blogspot.ca/)
              tomot

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

                @sdmitch said:

                Put the repeated code in its own method and pass the variables to it.

                Thanks! I'm aware of "making my own method" and it has not escaped me from looking at your scripts, regardless I have never been able to get any of my attempts to work ... hence I gave up! What would be really great if some You tube videos existed that use the Ruby Sketchup API, demonstrating the process and pitfalls .....just thinking out loud! 😄

                [my plugins](http://thingsvirtual.blogspot.ca/)
                tomot

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

                  Agian, there is no good reason to ever be using globals.
                  Not ever. They are not needed, ever! Zilch! Nada!

                  @tomot said:

                  @sdmitch said:

                  Put the repeated code in its own method and pass the variables to it.

                  I'm aware of "making my own method" ..., regardless I have never been able to get any of my attempts to work... hence I gave up!

                  I just gave you a proper example of how to use methods, and how to use module variables instead of globals.

                  Don't just "give up", ask specific questions about specific "attempts".
                  (Ie, your statement is a bit vague.)

                  What is it that you are having trouble understanding about using methods ?

                  I'm not here much anymore.

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

                    @unknownuser said:

                    The last pic I posted above shows the code snippet

                    1. Cuts a single hole for a recessed light
                    2. Draws the recessed light
                    3. At 3d point location @ptw1616

                    The other 3 recessed lights require either the same repeating code with a different 3d point location, Or as sdmitch suggested a method that passes the variables to it. It appears to me that there is only 1-3d point variable that needs to be passed on to this new method? I don't know now what if any of the code I currently have, will still be relevant, or how and where this new method will fit into the remainder to my script.

                    I hope this is somewhat less vague!

                    # Draw Circle on selected ceiling geometry - Cut Hole 
                    > 				mod  = Sketchup.active_model
                    > 				ents = mod.active_entities
                    > 				sel  = mod.selection
                    > 				face = sel.grep(Sketchup;;Face)[0]
                    > 				ents.add_circle(@ptw1616, @vec3, @Ldia, 24)
                    > 				sel.clear
                    > 				sel.add(ents.to_a.last)
                    > 				sel[0].erase!
                    > 				
                    > 				# Draw Recessed Light
                    > 				tube = entities.add_group
                    > 				tube_inner = tube.entities.add_circle(@ptw1616, @vec3, @Ldia-@Lthick , 24)
                    > 				tube_outer = tube.entities.add_circle(@ptw1616, @vec3, @Ldia , 24)
                    > 				cross_section_face = tube.entities.add_face tube_outer
                    > 				inner_face = tube.entities.add_face tube_inner
                    > 				tube.entities.erase_entities inner_face
                    > 				cross_section_face.pushpull -@Ldepth, false	
                    

                    Draw Circle on selected ceiling geometry - Cut Hole

                    			mod  = Sketchup.active_model
                    			ents = mod.active_entities
                    			sel  = mod.selection
                    			face = sel.grep(Sketchup;;Face)[0]
                    			ents.add_circle(@ptw1616, @vec3, @Ldia, 24)
                    			sel.clear
                    			sel.add(ents.to_a.last)
                    			sel[0].erase!
                    			
                    			# Draw Recessed Light
                    			tube = entities.add_group
                    			tube_inner = tube.entities.add_circle(@ptw1616, @vec3, @Ldia-@Lthick , 24)
                    			tube_outer = tube.entities.add_circle(@ptw1616, @vec3, @Ldia , 24)
                    			cross_section_face = tube.entities.add_face tube_outer
                    			inner_face = tube.entities.add_face tube_inner
                    			tube.entities.erase_entities inner_face
                    			cross_section_face.pushpull -@Ldepth, false	[/code:35jvptxs]
                    

                    [my plugins](http://thingsvirtual.blogspot.ca/)
                    tomot

                    1 Reply Last reply Reply Quote 0
                    • sdmitchS Offline
                      sdmitch
                      last edited by

                      I have no idea how you determine what @ptw1616 is but another option might be creating an array of the locations like this

                      # Draw Circle on selected ceiling geometry - Cut Hole
                      mod  = Sketchup.active_model
                      ents = mod.active_entities
                      sel  = mod.selection
                      face = sel.grep(Sketchup;;Face)[0]
                      @vec3 = face.normal; @Ldia=1.5; @Lthick=0.25; @Ldepth=0.25
                      locations=[[1,2,0],[3,2,0],[1,4,0],[3,4,0]]
                      locations.each{|loc| @ptw1616=loc
                        ents.add_circle(@ptw1616, @vec3, @Ldia/2, 24)
                        ents.to_a.last.erase!
                        # Draw Recessed Light
                        tube = ents.add_group
                        tube_inner = tube.entities.add_circle(@ptw1616, @vec3, @Ldia/2-@Lthick , 24)
                        tube_outer = tube.entities.add_circle(@ptw1616, @vec3, @Ldia/2 , 24)
                        cross_section_face = tube.entities.add_face tube_outer
                        inner_face = tube.entities.add_face tube_inner
                        tube.entities.erase_entities inner_face
                        cross_section_face.pushpull -@Ldepth, false
                      }
                      
                      

                      tomat.gif

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

                      http://sdmitch.blogspot.com/

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

                        @unknownuser said:

                        I have no idea how you determine what @ptw1616 is but another option might be creating an array of the locations like this

                        All the points are per-determined in my script. They relate to the user selected area.
                        Various combination of points make a pattern of lights the user can choose from in the Light Array Type Dialog Box.
                        Your understanding of Ruby has helped me tremendously. Furthermore I did not realize the importance of the last "}" .....which I originally thought might have been a typo........ Yikes!!!

                        [my plugins](http://thingsvirtual.blogspot.ca/)
                        tomot

                        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