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.
    • D Offline
      driven
      last edited by

      is this what you mean?

      draw a cube, select any face, run this code...

        
            mod  = Sketchup.active_model
            ents = mod.active_entities
            sel  = mod.selection
            face = sel.grep(Sketchup;;Face)[0]
            cent = face.bounds.center
            norm = face.normal
            dia  = 10
            segs = 24
           
            
            ents.add_circle(cent, norm, dia, segs)
            
            sel.clear
            sel.add(ents.to_a.last)
            sel[0].erase!
      

      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

        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