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

    Array.uniq! for a 3d-point array ???

    Scheduled Pinned Locked Moved Developers' Forum
    6 Posts 4 Posters 1.1k 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.
    • artmusicstudioA Offline
      artmusicstudio
      last edited by

      hi,
      i cannot find the syntax for

      arry.uniq!,

      where the array contains some 3d-points and i have to delete the identical 3d-point from it.

      the array in the ruby-console:

      show array:

      
      roof.each { |e|
      puts e
      	}
      
      

      result:


      (-503,8105m, 0m, 8,999982m)
      (-503,8105m, -57,150823m, 8,999982m)
      (-583,560407m, -92,554593m, 8,999982m)
      (-583,560407m, -92,554593m, 8,999982m)
      (-583,560407m, -59,804506m, 8,999982m)
      (-503,8105m, 0m, 8,999982m)


      roof.uniq!

      does not work.

      zhanx for tips!
      stan

      1 Reply Last reply Reply Quote 0
      • A Offline
        Aerilius
        last edited by

        Point3ds are "real" objects and have an identity (two objects with same properties are not the same object). Things that we can compare have a method == that checks whether two objects are "equal" (trivial for numbers and strings). SketchUp's Geom::Point3d.== method checks for example if all coordinates (x, y, z) are equal, and then says two points are equal.

        uniq appears to check for identity and not for equality. So we need to do it on our own, with checking for equality:

        roof = roof.inject([]){ |array, point| array.any?{ |p| p == point } ? array ; array << point }
        

        It does the same as:

        
        roof2 = []
        roof.each{ |point|
          # Check if we have already added any points to 'roof2' that are equal with 'point'.
          any = false
          roof2.each{ |p|
            break any = true if p == point
          }
          # If 'roof2' does not contain an equal point, we can add it.
          roof2.push(point) if not any
        }
        roof = roof2
        
        
        1 Reply Last reply Reply Quote 0
        • TIGT Offline
          TIG Moderator
          last edited by

          A Point3d is pretty much an Array, at least for many aspects of most methods, and a three item Array can usually be treated as a Point3d too.
          But as has been said unless your array-of-points [which you want to use .uniq on] is an array of Array objects and not Point3d objects it will not work, since each Point3d has a unique reference already.
          So make an array of points-made-into-arrays [using point.to_a etc] and then use .uniq! on that. Any duplicates that match will be removed - but be aware that if the ordering is important the missing duplicate-point-as-array might make difficulties for you 'down the line'...

          Alternatively, iterate each point and compare it with every other point in the array, using point==point_i - this includes SketchUp's tolerance, so two ALMOST each points are considered equal, but the equivalent array might no be !

          Why do you want to do this?
          There may be alternative ways of approaching the challenge ??

          TIG

          1 Reply Last reply Reply Quote 0
          • artmusicstudioA Offline
            artmusicstudio
            last edited by

            hi tig,
            your last question was the solution. i needed an hour and two coffies....

            instead of duplicating all startpoints of face edges in a certain height and then creating new edges between them (which caused the problem, when more lines met in one point >> doubled startpoints)

            i just draw the bottom line and its pendant in height "x" directly in the method and place them into another group.

            but anyway: your line for clearing the array is fantastic, although i had the problem, that there was no controll over which of the identical point is deleted and so the result face sometimes was missing a point. but i will study this later.

            so thanx for helping and the advice ! the OTHER WAY seems to work.

            stan

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

              I seem to remember injectrunning slowly in Ruby 1.8.x

              @aerilius said:

              It does the same as:

              
              > roof2 = []
              > roof.each{ |point|
              >   # Check if we have already added any points to 'roof2' that are equal with 'point'.
              >   any = false
              >   roof2.each{ |p|
              >     break any = true if p == point
              >   }
              >   # If 'roof2' does not contain an equal point, we can add it.
              >   roof2.push(point) if not any
              > }
              > roof = roof2
              > 
              

              My condensed edition would be:

              pts = []
              roof.each {|point|
                next unless point.is_a?(Geom;;Point3d)
                pts << point unless pts.any? {|p| p == point }
              }
              
              

              I'm not here much anymore.

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

                @aerilius said:

                Geom::Point3d.== method checks for example if all coordinates (x, y, z) are equal, and then says two points are equal.

                uniq appears to check for identity and not for equality.

                In Ruby 2.x (SketchUp 2014+,) where we now have a block form of the uniq method, that we can tailor to override C internals of the uniq! method, and tell it what and how to do the comparison.
                Ex:
                pts = roof.uniq {|a,b| a.==(b) }
                or:
                pts = roof.uniq {|pt| pt.to_a }

                In the future, perhaps, custom uniq methods could be added to a new PointArray subclass of Array., for the API.
                Of course any author could create such a custom class within their own namespace(s).

                ALSO.. the many od the API classes should have had their eql?() method aliased as the overridden ==() method.
                The uniq methods want to call eql?() instead of ==().

                I'm not here much anymore.

                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