sketchucation logo sketchucation
    • Login
    🤑 SketchPlus 1.3 | 44 Tools for $15 until June 20th Buy Now

    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

      How to create a hole in a surface?

      1. Ruby script: tells user to select a surface area by rectangle (pink)
      2. Ruby script: then creates a circle at the center of the selected surface
      group = entities.add_group
      entities = group.entities
      circle = entities.add_circle(@pt15, @vec3, @Ldia, 24)
      base = entities.add_face(circle)
      

      What code do I need to add to the script, that recognizes the selected surface, so I can have the circle cut a hole out of the selected surface?


      2016-12-01_12-00-30.png

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

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

        Entities#add_face() is bugged with an edge array as argument. That is what is returned from the Entities#add_circle() method, not the curve object itself.

        So try:

        base = entities.add_face(circle[0].curve)

        or:
        faces = entities.grep(Sketchup::Face) num_added = circle[0].find_faces() found = entities.grep(Sketchup::Face) - faces base = found.empty? ? nil : found.first

        I'm not here much anymore.

        1 Reply Last reply Reply Quote 0
        • 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