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

    Turning a selection into a face?

    Scheduled Pinned Locked Moved Developers' Forum
    40 Posts 4 Posters 626 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.
    • Dan RathbunD Offline
      Dan Rathbun
      last edited by

      @tomot said:

      ... but thomthom is right, I'm looking for the statement that allows me to offset the face the offset.rb creates.

      OK... then first of all the Example 1 re-write of Rick's method mimics the native offset tool, and returns the newly created offset face.

      (Just ignore Examples 2 & 3, as I did not understand what was needed and may have misunderstood what Rick's code was doing.)

      If you wish to AGAIN apply an offset, pass the newly created face and a new offset distance (or whatever distance,) into the method a second time.

      If you wish to move it or something else ... do whatever by using the returned reference as needed.

      Here is test script wrapped as Tomot::Offset, that adds right-click mouse "Offset Face" commands to the popup menu, but differs in result from the native tool by setting the selection to the new face. (The native tool does not change the selection set.) It also uses an inputbox to get the distance, ... but in practice you would bypass that and your code would supply the needed distance value.

      module Tomot
        module Offset
          class << self
      
            def offset_a_face( face, dist )
      
              unless face.is_a?(Sketchup;;Face)
                fail(TypeError,"Sketchup;;Face instance expected for 1st argument",caller)
              end
      
              unless dist.is_a?(Numeric)
                fail(TypeError,"Numeric subclass expected for 2nd argument",caller)
              else
                if dist.zero?
                  unless $VERBOSE.nil?
                    puts("Tomot;;Offset;WARNING; offset_a_face(); Offset distance was zero.")
                  end
                  return nil
                end
              end
      
              new_face = nil # this method's return value
      
              pi = Math;;PI
              verts = face.outer_loop.vertices
              pts   = []
      
              # CREATE ARRAY pts OF OFFSET POINTS FROM FACE
      
              0.upto(verts.length-1) do |a|
                vec1 = (verts[a].position-verts[a-(verts.length-1)].position).normalize
                vec2 = (verts[a].position-verts[a-1].position).normalize
                vec3 = (vec1+vec2).normalize
                if vec3.valid?
                  ang = vec1.angle_between(vec2)/2
                  ang = pi/2 if vec1.parallel?(vec2)
                  vec3.length = dist/Math;;sin(ang)
                  t = Geom;;Transformation.new(vec3)
                  if pts.length > 0
                    vec4 = pts.last.vector_to(verts[a].position.transform(t))
                    if vec4.valid?
                      unless (vec2.parallel?(vec4))
                        t = Geom;;Transformation.new(vec3.reverse)
                      end
                    end
                  end
      
                  pts.push(verts[a].position.transform(t))
                end
              end
      
              # CHECK FOR DUPLICATE POINTS IN pts ARRAY
              #
              duplicates = []
              pts.each_index do |a|
                pts.each_index do |b|
                  next if b==a
                  duplicates<<b if pts[a]===pts[b]
                end
                break if a==pts.length-1
              end
              duplicates.reverse.each{|a| pts.delete(pts[a])}
      
              # CREATE FACE FROM POINTS IN pts ARRAY
              #
              if pts.length > 2
                begin
                  #
                  if Sketchup.version.to_i > 6
                    face.model.start_operation('Offset Face',true)
                  else
                    face.model.start_operation('Offset Face')
                  end
                    #
                    new_face = face.parent.entities.add_face(pts)
                    #
                  face.model.commit_operation()
                  #
                rescue
                  face.model.abort_operation()
                  raise() # to outer rescue clause
                end # begin
              end # if
      
            rescue TypeError
      
              raise() # just re-raise the Exception
      
            rescue => e # any other Exceptions;
      
              unless $VERBOSE.nil?
                puts("Tomot;;Offset;WARNING; offset_a_face(); #{face.inspect} did not offset; #{pts}")
                puts("Error; #<#{e.class.name}; #{e.message}>")
                puts(e.backtrace) if $VERBOSE
              end
              raise() # re-raise to any debugger in use
      
            else # when no errors;
      
              return new_face
      
            end # offset_a_face()
            
            #{ get_dist(face)
            #
            #  Prompts for a distance, then calls offset_a_face()
            #  If a new offset face is created, it will be set as
            #    a single object of the current model's selection.
            #
            def get_dist(face)
              result = UI.inputbox(['Offset distance ;   '],[0],'Offset a Face')
              if result
                ret = offset_a_face(face,result[0])
                if ret
                  sel = Sketchup.active_model.selection
                  sel.clear
                  sel.add(ret)
                else
                  return nil
                end
              else
                return nil
              end
            end #}
      
          end # proxy class
      
          unless file_loaded?(File.basename(__FILE__))
      
            UI.add_context_menu_handler {|popup|
              unless Sketchup.active_model.selection.empty?
                sel = Sketchup.active_model.selection
                if sel.single_object? && sel[0].is_a?(Sketchup;;Face)
                  face = sel[0]
                  popup.add_item('Offset Face',10) { get_dist(face) }
                else
                  face = sel.find {|o| o.is_a?(Sketchup;;Face) }
                  if face # (nil if no face was selected)
                    popup.add_item('Offset First Face',11) { get_dist(face) }
                  end
                end
              end
            }
      
            file_loaded(File.basename(__FILE__))
      
          end
      
        end # module Offset
      end # module Tomot
      

      Question to the room at large: Regarding line 137, which is faster for large selection sets ?
      face = sel.find {|o| o.is_a?(Sketchup::Face) }
      OR
      face = sel.grep(Sketchup::Face)[0]

      Keep in mind both need to be fololowed by a nil test conditional, viz:
      if face

      ❓

      I'm not here much anymore.

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

        Dan thanks for your code, however regarding your last piece of code.
        I'm unclear as to how to use it.

        If I save your code as as offset.rb and replace it with the original offset.rb then load it in the console, I get an error in the console when I right click on selected face.

        Is this the way you intended it to be used? Please explain further!
        and just to make sure, please see the attachment regarding the face in question.


        offset.png

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

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

          YES, make a selection, then right-click the selection (or a single face,) and an inputbox should pop up to enter a distance.

          IF you get an error, it would help if you paste the error message into a post.

          I'm not here much anymore.

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

            @dan rathbun said:

            IF you get an error, it would help if you paste the error message into a post.

            there is also no "offset" reference in the context menu


            offset1.png

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

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

              @Tomot ... you have no profile information showing.

              (1) What SketchUp version ?

              (2) What SketchUp edition (Free or Pro) ?

              (3) What Platform & Operating System ?

              Lastly... if you are using an old version that does not support the 2nd ordinal position argument for add_item(), then remove that argument, and the menu items will just be at the end of the popup menu.

              The popup menu items are really just for testing... you can directly call the methods just as the menu items do, and remove the popup menu code.

              The code is an example.

              I'm not here much anymore.

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

                @dan rathbun said:

                @Tomot ... you have no profile information showing.

                (2) What SketchUp edition (Free or Pro) ?

                Pro, My bad its working, after update!

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

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

                  @tomot said:

                  Pro, My bad its working, after update!

                  You may also be interested in this from TIG:

                  [Plugin] TIG-Smart_offset v2.1

                  I have not tried it, so I do not know if it sets the new offset face as the selection.

                  TIG ?

                  I'm not here much anymore.

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

                    @dan rathbun said:

                    @tomot said:

                    Pro, My bad its working, after update!

                    You may also be interested in this from TIG:

                    [Plugin] TIG-Smart_offset v2.1

                    I have not tried it, so I do not know if it sets the new offset face as the selection.

                    TIG ?
                    The originally selected face remains selected, but it should 'return' an array of the new face[s] formed when run via code...

                    TIG

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

                      I would like to take offset 1 step further: namely allowing the selection of more than one face.
                      I revised Dan's script and added a secondary Reveal offset to the menu. The Reveal menu item represents the depth of the reveal.

                      The reason behind my initial interest in RickW's offset.rb was to use it to provide reveals
                      of selected faces, using SketchUp, for proposed concrete faces, be they cast-in-place or precast.

                      Dan correctly identified users selecting more than 1 face, before the offset professing occurs.
                      I need a hint πŸŽ‰ so I can I change the code to allow selecting more than 1 face?
                      The attached pic shows my added revised code, the revised code is also attached.


                      offset1.jpg


                      offset.rb

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

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

                        You should not really have that method.
                        You should have written an additional method to do a multi-face offset.

                        What do you want the selection to hold at the end of the multi-face offset ?

                        (Also.. ALWAYS check if results from an inputbox, in case the user cancels the dialog.)

                        I'm not here much anymore.

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

                          @dan rathbun said:

                          You should not really have that method.
                          What do you want the selection to hold at the end of the multi-face offset ?

                          I wanted all selected faces to be offset and revealed
                          I was unaware that I would have to write a muiti-face offset routine 😞

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

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

                            TIG's ....TIG-Smart_offset.rb does a great job offsetting multiple faces. πŸŽ‰
                            I hope he does not mind me learning more about Ruby using his script.

                            I added the following highlighted code to his script incorporating a reveal option.
                            Unfortunately this added complexity causes faces which share a common edge not to work well, with the reveal option, when pushpull is used.


                            offset1.jpg

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

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

                              When you make a change like that.. you need to change the top level namespace from TIG to Tomot

                              .. also I do not understand your use of the word "reveal" (which means "to show" or "to make visible".)

                              Can you post an image from the model of the final result you wish to achieve ?

                              I'm not here much anymore.

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

                                @Tomot
                                Yes, please use your own Tomot namespace to avoid confusion with my TIG one...

                                @Dan
                                A 'reveal' [noun not a verb] is an architectural term for the 'sides' of the hole into which something like a window will be fitted... The window's 'reveals' are typically just the two vertical sides of its opening, which are arranged at [or near] right-angles to the main wall-face; the top 'side' is called the 'head' and the bottom one the 'sill': the use of 'reveal' for all four is correct, but somewhat unspecific and perhaps brings to mind a simple 'recess' in a wall with nothing inserted into it [e.g. 'the four reveals of that recess']. So I think Tomot is using the term 'reveal' to refer to all of the new face-parts that are created perpendicular to the main face: which will only be true 'reveals' if the pushpull were 'inwards', forming a 'recess' with 'reveals'; if it were 'outwards' the new form makes an upstanding 'plateau', and so it will technically not have 'reveals', but just 'sides' [cliffs!]... πŸ˜’

                                TIG

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

                                  @tig said:

                                  @Tomot
                                  Yes, please use your own Tomot namespace to avoid confusion with mt TIG one...

                                  TIG is right, If you were working in an architectural office and did not know what a reveal was, your peers would wonder how you got the job. 🀣


                                  box3.JPG

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

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

                                    @tig said:

                                    @Tomot
                                    Yes, please use your own Tomot namespace to avoid confusion with my TIG one...

                                    TIG, I'm simply looking a your script and adding additional functonality, naturally and without question this is your script. This might turnout to be a good architectural addition and I would hope you could add it to your list of accomplished rubies πŸ˜„

                                    However as I already stated, while the Offset portion of the script has no problems, because the offset faces does not interfere with any adjoining face. The added "Reveal option" does have problems, because it introduces the problem of how "pushpull" can't effectively deal with push pulling shared faces. I recall there had been discussion about shared faces and pushpull but I could not find any solutions. 😒

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

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

                                      @tomot said:

                                      TIG is right, If you were working in an architectural office and did not know what a reveal was, your peers would wonder how you got the job.

                                      Which, of course tells you correctly that I have not yet worked in architectural engineering. (Only mechanical, electrical, electronic and systems with a combination of those [ie, railway, vehicles, aircraft, and commercial broadcasting.])

                                      I'm not here much anymore.

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

                                        Referring to my previous code posting: HERE

                                        To get multiple faces rather than the first face (which is not may not work, as the selection's order may not be returned in the order the user picked,) ...

                                              UI.add_context_menu_handler {|popup|
                                                unless Sketchup.active_model.selection.empty?
                                                  sel = Sketchup.active_model.selection
                                                  if sel.single_object? && sel[0].is_a?(Sketchup;;Face)
                                                    face = sel[0]
                                                    popup.add_item('Offset Face',10) { get_dist(face) }
                                                  else
                                                    faces = sel.grep(Sketchup;;Face)
                                                    unless faces.empty? # (empty array if no face was selected)
                                                      popup.add_item('Offset Selected Faces',11) {
                                                        if get_values()
                                                          offset_multi_faces(faces)
                                                        end
                                                     }
                                                    end
                                                  end
                                                end
                                              }
                                        
                                        

                                        The get_values() dialog method would need changing (from get_dist,) to just set the variables (as you did,) and return true to continue the command, or false if the user canceled the dialog, meaning they wished to cancel the command.

                                        Then a new method offset_multi_faces(faces) would iterate the faces array, calling offset_a_face() for each face member in the array.

                                        I'm not here much anymore.

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

                                          My Smart_offset method should return an array of the face[s] made by the offset [excluding the original face], which in your example will be just the inner new rectangular face.
                                          So if you move the pushpull code into the block that is offsetting each face in turn to be something like:

                                          faces.each{|face|
                                            newfaces=TIG;;Smart_offset.new(face, @dist, tidy)
                                            newfaces.each{|newface|newface.pushpull(@reveal)}if newfaces
                                          }
                                          

                                          it might work ???

                                          TIG

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

                                            @dan rathbun said:

                                            selection's order may not be returned in the order the user picked,) ...

                                            That is an entire new can of worms!....I don't know how SU implements a user select all picking order. I also see different results each time I use select all If you copy and paste each of the 4 attached cubes and run the script on each of the 4 cubes separate, sometimes the script gets the reveal right, most of the time it does not.

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

                                            1 Reply Last reply Reply Quote 0
                                            • 1
                                            • 2
                                            • 2 / 2
                                            • First post
                                              Last post
                                            Buy SketchPlus
                                            Buy SUbD
                                            Buy WrapR
                                            Buy eBook
                                            Buy Modelur
                                            Buy Vertex Tools
                                            Buy SketchCuisine
                                            Buy FormFonts

                                            Advertisement