• Login
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 1 Dec 2016, 21:09

    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
    • D Offline
      Dan Rathbun
      last edited by 2 Dec 2016, 11:32

      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 2 Dec 2016, 13:22

        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 2 Dec 2016, 19:19

          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
          • S Offline
            sdmitch
            last edited by 2 Dec 2016, 22:06

            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
            • D Offline
              Dan Rathbun
              last edited by 3 Dec 2016, 16:37

              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 3 Dec 2016, 17:15

                @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 3 Dec 2016, 21:06

                  @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 3 Dec 2016, 21:18

                    @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
                    • D Offline
                      Dan Rathbun
                      last edited by 3 Dec 2016, 23:47

                      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 6 Dec 2016, 17:58

                        @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
                        • S Offline
                          sdmitch
                          last edited by 6 Dec 2016, 19:50

                          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 11 Dec 2016, 21:40

                            @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
                            1 / 1
                            • First post
                              1/13
                              Last post
                            Buy SketchPlus
                            Buy SUbD
                            Buy WrapR
                            Buy eBook
                            Buy Modelur
                            Buy Vertex Tools
                            Buy SketchCuisine
                            Buy FormFonts

                            Advertisement