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

    Fastest way to retrieve the corners that make up a face?

    Scheduled Pinned Locked Moved Developers' Forum
    9 Posts 4 Posters 223 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.
    • S Offline
      steve r
      last edited by

      I need to know the coordinates of the corners that make up selected faces. Right now I'm doing something like this:

      for face in selection
      corner.insert face.bounds.corner(0)
      corner.insert face.bounds.corner(1)
      corner.insert face.bounds.corner(6)
      corner.insert face.bounds.corner(7)
      end
      

      Where selection is all of the currently selected entities (which have been checked to only be faces) and corner is a previously empty Set. Obviously, using the BoundingBox only works if the faces are oriented exactly along the axes of the model. I know I can get the edges of each face, and then get the vertexes that make up the edges, then convert those to Point3d... but that seems really slow. Since I need to do this a lot (over 2,500 times in one example model) I'm looking for the fastest way to do this... any ideas?

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

        This will only work on rectangular faces ?
        face.vertices returns an array of each actual corner [vertex].
        vertex.position returns the point of a vertex.

        TIG

        1 Reply Last reply Reply Quote 0
        • S Offline
          steve r
          last edited by

          @tig said:

          This will only work on rectangular faces ?
          face.vertices returns an array of each actual corner [vertex].
          vertex.position returns the point of a vertex.

          Oh jeez, that seems pretty obvious now. Thanks!

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

            so take it to a 1 liner (where your Set is named corners, and need not really be empty):

            corners.insert( *face.vertices.map{|vertex| vertex.position } )

            NOTE: The API does not say so, but the insert() method can take multiple args separated by commas.
            The map method returns an array, so we can use the * expand/contract (I call it the "accordian",) operator, to convert the array to an argument list.

            I'm not here much anymore.

            1 Reply Last reply Reply Quote 0
            • thomthomT Offline
              thomthom
              last edited by

              @dan rathbun said:

              NOTE: The API does not say so, but the insert() method can take multiple args separated by commas.

              Doh!!! 😲

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

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

                @thomthom said:

                @dan rathbun said:

                NOTE: The API does not say so, but the insert() method can take multiple args separated by commas.

                Doh!!! 😲

                Which brings up a compatibility issue between Sketchup's Set and Ruby Set.

                The Ruby Set#add() method only takes 1 argument, so I cannot just alias add as insert in my set_fix.rb file.

                I'm not here much anymore.

                1 Reply Last reply Reply Quote 0
                • S Offline
                  steve r
                  last edited by

                  @dan rathbun said:

                  so take it to a 1 liner (where your Set is named corners, and need not really be empty):

                  corners.insert( *face.vertices.map{|vertex| vertex.position } )

                  NOTE: The API does not say so, but the insert() method can take multiple args separated by commas.
                  The map method returns an array, so we can use the * expand/contract (I call it the "accordian",) operator, to convert the array to an argument list.

                  Wow, well, that's a little over my head, I'm just learning Ruby, so I'll have to dissect that. Thanks!

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

                    Ok well assigning values to references may help you understand, but it will slow down the loop.
                    (Also it's confusing both to read, and slows down Ruby interpreter, when you use ref names that are the same as method names.)

                    So:

                    coord = Set.new()
                    for f in sel
                      verts = f.vertices
                      posary = verts.map {|v| v.position }
                      for p3d in posary
                        coord.insert( p3d )
                      end
                    end
                    

                    The only persistent reference you really need is coord.

                    Now simplify a bit:

                    coord = Set.new()
                    for f in sel
                      verts = f.vertices
                      posary = verts.map {|v| v.position }
                      coord.insert( *posary )
                    end
                    

                    The * operator will expand an array into an argument list, or (if used within method definition's parameters,) compress the remaining argument list into an array. We are using the former, in this example.

                    So, simplify a bit more:

                    coord = Set.new()
                    for f in sel
                      verts = f.vertices
                      coord.insert( *verts.map{|v| v.position } )
                    end
                    

                    And again:

                    coord = Set.new()
                    for f in sel
                      coord.insert( *f.vertices.map{|v| v.position } )
                    end
                    

                    And finally:

                    coord = Set.new()
                    sel.each{|f|coord.insert(*f.vertices.map{|v|v.position})}
                    
                    

                    ADD: For some reason, for .. in loops are faster than each block methods.

                    I'm not here much anymore.

                    1 Reply Last reply Reply Quote 0
                    • thomthomT Offline
                      thomthom
                      last edited by

                      @dan rathbun said:

                      ADD: For some reason, for .. in loops are faster than each block methods.

                      They may be faster - because they don't create a local variable scope - the scope is shared with it's parent scope. Creating variables in Ruby is an expensive operation, so if you create variables within an each loop it's created every time, within a for loop it's reused.

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

                      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