sketchucation logo sketchucation
    • 登入
    Oops, your profile's looking a bit empty! To help us tailor your experience, please fill in key details like your SketchUp version, skill level, operating system, and more. Update and save your info on your profile page today!
    ⚠️ Important | Libfredo 15.6b introduces important bugfixes for Fredo's Extensions Update

    Turning a selection into a face?

    已排程 已置頂 已鎖定 已移動 Developers' Forum
    40 貼文 4 Posters 1.3k 瀏覽 4 Watching
    正在載入更多貼文
    • 從舊到新
    • 從新到舊
    • 最多點贊
    回覆
    • 在新貼文中回覆
    登入後回覆
    此主題已被刪除。只有擁有主題管理權限的使用者可以查看。
    • T 離線
      tomot
      最後由 編輯

      the code snippet below asks the user to make a selection

      model=Sketchup.active_model
      	ents=model.active_entities
      	sel=model.selection
          
          if sel.empty? 
            UI.messagebox("No selection !")
            return nil
          end
      

      what code do I require to turn that selection into a face?

      _____________ == Sketchup::Face

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

      1 條回覆 最後回覆 回覆 引用 0
      • TIGT 離線
        TIG Moderator
        最後由 編輯

        There are many ways, e.g.
        sel.grep(Sketchup::Edge).each{|e|e.find_faces}
        adds all possible faces edges in the selection...

        TIG

        1 條回覆 最後回覆 回覆 引用 0
        • T 離線
          tomot
          最後由 編輯

          @tig said:

          There are many ways, e.g.
          sel.grep(Sketchup::Edge).each{|e|e.find_faces}
          adds all possible faces edges in the selection...

          If I use the following statement:
          $newface1=sel.grep(Sketchup::Edge).each{|e|e.find_faces}
          the ruby console respond is:
          %(#FF0000)[$newface1
          []]
          I was expecting something like:
          #Sketchup::Face:0xb3cb350

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

          1 條回覆 最後回覆 回覆 引用 0
          • TIGT 離線
            TIG Moderator
            最後由 編輯

            That method doesn't return faces, it just makes them !
            To find them try...
            ` edges=sel.grep(Sketchup::Edge)
            ofaces=[]
            edges.each{|e|ofaces << e.faces}
            ofaces.flatten!
            ofaces.uniq!

            edges.each{|e|e.find_faces}
            nfaces=[]
            edges.each{|e|nfaces << e.faces}
            nfaces.flatten!
            nfaces.uniq!The array 'nfaces' is all of the faces that are now attached to the edges - old and new. To find just the new faces try... faces=nfaces-ofaces`
            Where 'faces' is the array of those...

            TIG

            1 條回覆 最後回覆 回覆 引用 0
            • T 離線
              tomot
              最後由 編輯

              I did not know that this is a 2 stage process, 1: find & 2: return

              $newface1=sel.grep(Sketchup;;Face) #finds face only!
              $newface1.pushpull $inset
              

              So How do I implement a pushpull of $newface1?

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

              1 條回覆 最後回覆 回覆 引用 0
              • TIGT 離線
                TIG Moderator
                最後由 編輯

                First off...
                Don't use $ variables !
                If the vars are spread across different methods in the same class/module use @.
                Otherwise why use them at all...
                Try
                newface1.pushpull(inset)
                or
                @newface1.pushpull(@inset)
                Depending on the +/-ve value of the face it dictates the extrusion relative to the face.normal.
                Note that the face.normal can be determined prior to the pushpull and then face.reverse! if it's the 'wrong orientation', for example you want the face to be 'down' so a +ve inset moves the pushpull down too then test face.normal.z<0, and if not you can use face.reverse! before the pushpull is done...

                TIG

                1 條回覆 最後回覆 回覆 引用 0
                • thomthomT 離線
                  thomthom
                  最後由 編輯

                  @tomot said:

                  I did not know that this is a 2 stage process, 1: find & 2: return

                  $newface1=sel.grep(Sketchup;;Face) #finds face only!
                  > $newface1.pushpull $inset
                  

                  So How do I implement a pushpull of $newface1?

                  sel.grep(Sketchup::Face)
                  This returns an array of all faces in the colletion (in this case selection)

                  <span class="syntaxdefault"><br />faces&nbsp;</span><span class="syntaxkeyword">=&nbsp;</span><span class="syntaxdefault">sel</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">grep</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">Sketchup</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">Face</span><span class="syntaxkeyword">)&nbsp;}<br /></span><span class="syntaxcomment">#&nbsp;Push/pull&nbsp;all&nbsp;faces<br /></span><span class="syntaxdefault">faces</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">each&nbsp;</span><span class="syntaxkeyword">{&nbsp;|</span><span class="syntaxdefault">face</span><span class="syntaxkeyword">|&nbsp;</span><span class="syntaxdefault">face</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">pushpull</span><span class="syntaxkeyword">(&nbsp;</span><span class="syntaxdefault">distance&nbsp;</span><span class="syntaxkeyword">)&nbsp;}<br />&nbsp;</span><span class="syntaxdefault"></span>
                  

                  If you want only one entity, use find():

                  <span class="syntaxdefault"><br />face&nbsp;</span><span class="syntaxkeyword">=&nbsp;</span><span class="syntaxdefault">sel</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">find&nbsp;</span><span class="syntaxkeyword">{&nbsp;|</span><span class="syntaxdefault">e</span><span class="syntaxkeyword">|&nbsp;</span><span class="syntaxdefault">e</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">is_a</span><span class="syntaxkeyword">?(</span><span class="syntaxdefault">Sketchup</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">Face</span><span class="syntaxkeyword">)&nbsp;}<br /></span><span class="syntaxdefault">face</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">pushpull</span><span class="syntaxkeyword">(&nbsp;</span><span class="syntaxdefault">distance&nbsp;</span><span class="syntaxkeyword">)<br />&nbsp;</span><span class="syntaxdefault"></span>
                  

                  Thomas Thomassen — SketchUp Monkey & Coding addict
                  List of my plugins and link to the CookieWare fund

                  1 條回覆 最後回覆 回覆 引用 0
                  • T 離線
                    tomot
                    最後由 編輯

                    @tig said:

                    First off...
                    Don't use $ variables !
                    snip

                    I was using $ variables only to check what my face code was actually being selecting in the Ruby Console. I still trying to resolved this issue. 😢

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

                    1 條回覆 最後回覆 回覆 引用 0
                    • T 離線
                      tomot
                      最後由 編輯

                      @thomthom said:

                      sel.grep(Sketchup::Face)
                      This returns an array of all faces in the colletion (in this case selection)

                      <span class="syntaxdefault"><br />faces </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> sel</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">grep</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">Sketchup</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">Face</span><span class="syntaxkeyword">)</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">}<br /></span><span class="syntaxcomment"># Push/pull all faces<br /></span><span class="syntaxdefault">faces</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">each </span><span class="syntaxkeyword">{</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">|</span><span class="syntaxdefault">face</span><span class="syntaxkeyword">|</span><span class="syntaxdefault"> face</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">pushpull</span><span class="syntaxkeyword">(</span><span class="syntaxdefault"> distance </span><span class="syntaxkeyword">)</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">}<br /></span><span class="syntaxdefault"></span>
                      

                      If you want only one entity, use find():

                      <span class="syntaxdefault"><br />face </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> sel</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">find </span><span class="syntaxkeyword">{</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">|</span><span class="syntaxdefault">e</span><span class="syntaxkeyword">|</span><span class="syntaxdefault"> e</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">is_a</span><span class="syntaxkeyword">?(</span><span class="syntaxdefault">Sketchup</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">Face</span><span class="syntaxkeyword">)</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">}<br /></span><span class="syntaxdefault">face</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">pushpull</span><span class="syntaxkeyword">(</span><span class="syntaxdefault"> distance </span><span class="syntaxkeyword">)<br /></span><span class="syntaxdefault"></span>
                      

                      That's precisely my problem in a larger nutshell 😄 , I'm trying to use RickW's offset.rb which draws a 2nd offset on the initial "sel" selected face. Since there now 2 faces I'm having difficulty selecting the offset face for pushpull that the offset.rb created, and NOT the initial "sel" selected face for pushpull. (I can post a pic if my description falls short)

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

                      1 條回覆 最後回覆 回覆 引用 0
                      • Dan RathbunD 離線
                        Dan Rathbun
                        最後由 編輯

                        @tomot said:

                        I'm trying to use RickW's offset.rb which draws a 2nd offset on the initial "sel" selected face.

                        Please do not use that script AS IS. We need to put it on the Quarantine List.

                        It overrides the API Array#offset method, and adds methods to both API and Ruby Core base classes.

                        You can use ideas from the methods that do not change base classes (by re-writing them and putting them inside your own namespace.)

                        So... anyway Rick's offset method should have returned a reference to the added face, because it uses Entities#add_face()

                        To use that method inside youir OWN namespace, you need to pass a reference to the original face into the method, and replace all self references within the method to the reference name of the passed face argument.

                        Example 1 (The internals have not been changed much, but an undo operation has been added):

                        module Tomot
                          module SomePlugin
                            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;;SomePlugin;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;;SomePlugin;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()
                        
                            end # proxy class
                          end # module SomePlugin
                        end # module Tomot
                        

                        💭

                        I'm not here much anymore.

                        1 條回覆 最後回覆 回覆 引用 0
                        • Dan RathbunD 離線
                          Dan Rathbun
                          最後由 編輯

                          Example 2 : Here is a shorter edition that uses a vector or an array as the 2nd argument, and leverages the API's built-in Geom::Point3d#offset! method.

                          You can create a vector to pass as the 2nd argument, or call the method with an array literal, to say, offset the face by 10 units in the positive Z direction:
                          offset_a_face( @face, [0,0,10.0] )

                          module Tomot
                            module SomePlugin
                              class << self
                          
                                def offset_a_face( face, vect )
                          
                                  unless face.is_a?(Sketchup;;Face)
                                    fail(TypeError,"Sketchup;;Face instance expected for 1st argument",caller)
                                  end
                           
                                  unless vect.is_a?(Geom;;Vector3d) || vect.is_a?(Array)
                                    fail(TypeError,"Geom;;Vector3d or Array expected for 2nd argument",caller)
                                  else
                                    vect = Geom;;Vector3d.new(*vect) if vect.is_a?(Array)
                                    if vect.length.zero?
                                      unless $VERBOSE.nil?
                                        puts("Tomot;;SomePlugin;WARNING; offset_a_face(); Offset vector length was zero.")
                                      end
                                      return nil
                                    end
                                  end
                          
                                  new_face = nil # this method's return value
                          
                                  verts = face.vertices
                          
                                  # CREATE ARRAY pts OF OFFSET POINTS FROM FACE
                                  pts = verts.map {|v| v.position.offset!(vect) }
                          
                                  # 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;;SomePlugin;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()
                          
                              end # proxy class
                            end # module SomePlugin
                          end # module Tomot
                          

                          💭

                          I'm not here much anymore.

                          1 條回覆 最後回覆 回覆 引用 0
                          • Dan RathbunD 離線
                            Dan Rathbun
                            最後由 編輯

                            Example 3 : a one-liner (with no error trapping, etc.)

                            Assume @vect is either an Array or a Geom::Vector3d instance:

                            @nface = @oface.parent.entities.add_face(@oface.vertices.map {|v| v.position.offset!(@vect) })
                            

                            I'm not here much anymore.

                            1 條回覆 最後回覆 回覆 引用 0
                            • thomthomT 離線
                              thomthom
                              最後由 編輯

                              @tomot said:

                              That's precisely my problem in a larger nutshell 😄 , I'm trying to use RickW's offset.rb which draws a 2nd offset on the initial "sel" selected face. Since there now 2 faces I'm having difficulty selecting the offset face for pushpull that the offset.rb created, and NOT the initial "sel" selected face for pushpull. (I can post a pic if my description falls short)

                              <span class="syntaxdefault"><br />model&nbsp;</span><span class="syntaxkeyword">=&nbsp;</span><span class="syntaxdefault">Sketchup</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">active_model<br />entities&nbsp;</span><span class="syntaxkeyword">=&nbsp;</span><span class="syntaxdefault">model</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">active_entities<br />sel&nbsp;</span><span class="syntaxkeyword">=&nbsp;</span><span class="syntaxdefault">model</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">selection<br /><br /></span><span class="syntaxcomment">#&nbsp;Grab&nbsp;a&nbsp;list&nbsp;of&nbsp;existing&nbsp;faces<br /></span><span class="syntaxdefault">original_faces&nbsp;</span><span class="syntaxkeyword">=&nbsp;</span><span class="syntaxdefault">entities</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">grep</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">Sketchup</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">Face</span><span class="syntaxkeyword">)<br /><br /></span><span class="syntaxcomment">#&nbsp;First&nbsp;offset&nbsp;face<br /></span><span class="syntaxdefault">face&nbsp;</span><span class="syntaxkeyword">=&nbsp;</span><span class="syntaxdefault">sel</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">find&nbsp;</span><span class="syntaxkeyword">{&nbsp;|</span><span class="syntaxdefault">e</span><span class="syntaxkeyword">|&nbsp;</span><span class="syntaxdefault">e</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">is_a</span><span class="syntaxkeyword">?(</span><span class="syntaxdefault">Sketchup</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">Face</span><span class="syntaxkeyword">)&nbsp;}<br /></span><span class="syntaxdefault">offset</span><span class="syntaxkeyword">(&nbsp;</span><span class="syntaxdefault">face</span><span class="syntaxkeyword">,&nbsp;</span><span class="syntaxdefault">20.mm&nbsp;</span><span class="syntaxkeyword">)&nbsp;</span><span class="syntaxcomment">#&nbsp;I&nbsp;don't&nbsp;know&nbsp;what&nbsp;the&nbsp;real&nbsp;method&nbsp;is&nbsp;there.<br /><br />#&nbsp;Then&nbsp;Push-pull&nbsp;inner&nbsp;face<br /></span><span class="syntaxdefault">faces&nbsp;</span><span class="syntaxkeyword">=&nbsp;</span><span class="syntaxdefault">entities</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">grep</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">Sketchup</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">Face</span><span class="syntaxkeyword">)&nbsp;-&nbsp;</span><span class="syntaxdefault">original_faces<br />inner_face_from_offset&nbsp;</span><span class="syntaxkeyword">=&nbsp;</span><span class="syntaxdefault">faces</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">first&nbsp;</span><span class="syntaxcomment">#&nbsp;*should*&nbsp;be&nbsp;just&nbsp;one&nbsp;face<br /></span><span class="syntaxdefault">inner_face_from_offset</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">pushpull</span><span class="syntaxkeyword">(&nbsp;</span><span class="syntaxdefault">500.mm&nbsp;</span><span class="syntaxkeyword">)<br />&nbsp;</span><span class="syntaxdefault"></span>
                              

                              Untested

                              Thomas Thomassen — SketchUp Monkey & Coding addict
                              List of my plugins and link to the CookieWare fund

                              1 條回覆 最後回覆 回覆 引用 0
                              • Dan RathbunD 離線
                                Dan Rathbun
                                最後由 編輯

                                @thomthom said:

                                I don't know what the real method is there.

                                It was my Example 1 (above) but Rick's edition was an instance method added to the Sketchup::Face class. (I re-wrote it to pass the face instance into the method.)

                                As shown in my one-liner (Example 3) a method is not really even needed.
                                @oface is the old face in the selection.
                                The new face will be @nface, and then just do the push-pull on it.

                                I'm not here much anymore.

                                1 條回覆 最後回覆 回覆 引用 0
                                • thomthomT 離線
                                  thomthom
                                  最後由 編輯

                                  @dan rathbun said:

                                  Example 3 : a one-liner (with no error trapping, etc.)

                                  Assume @vect is either an Array or a Geom::Vector3d instance:

                                  @nface = @oface.parent.entities.add_face(@oface.vertices.map {|v| v.position.offset!(@vect) })
                                  

                                  That just offsets in an direction - we're talking about offsetting in terms of what the Offset tool does.

                                  Thomas Thomassen — SketchUp Monkey & Coding addict
                                  List of my plugins and link to the CookieWare fund

                                  1 條回覆 最後回覆 回覆 引用 0
                                  • T 離線
                                    tomot
                                    最後由 編輯

                                    Tig, thomthom and Dan, thanks for your input it will take me a few days to digest your input, and try putting your input into use.
                                    but thomthom is right, I'm looking for the statement that allows me to offset the face the offset.rb creates.

                                    I was hoping a simple Boolean expression in the API would have served a very useful purpose, in this particular instance. 😢

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

                                    1 條回覆 最後回覆 回覆 引用 0
                                    • Dan RathbunD 離線
                                      Dan Rathbun
                                      最後由 編輯

                                      @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 條回覆 最後回覆 回覆 引用 0
                                      • T 離線
                                        tomot
                                        最後由 編輯

                                        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 條回覆 最後回覆 回覆 引用 0
                                        • Dan RathbunD 離線
                                          Dan Rathbun
                                          最後由 編輯

                                          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 條回覆 最後回覆 回覆 引用 0
                                          • T 離線
                                            tomot
                                            最後由 編輯

                                            @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 條回覆 最後回覆 回覆 引用 0
                                            • 1
                                            • 2
                                            • 1 / 2
                                            • 第一個貼文
                                              最後的貼文
                                            Buy SketchPlus
                                            Buy SUbD
                                            Buy WrapR
                                            Buy eBook
                                            Buy Modelur
                                            Buy Vertex Tools
                                            Buy SketchCuisine
                                            Buy FormFonts

                                            Advertisement