Array of unique points?
-
When you have an array of arbitrary
points
- and you want to ensure that array only contains unique points, how do you filter them out?points.uniq!
doesn't seem to work.Example:
` point1 = Geom::Point3d.new 1,1,1
Point3d(1, 1, 1)
point2 = Geom::Point3d.new 10,10,10
Point3d(10, 10, 10)
point3 = Geom::Point3d.new 10,10,10
Point3d(10, 10, 10)
a = [point1, point2, point3]
[Point3d(1, 1, 1), Point3d(10, 10, 10), Point3d(10, 10, 10)]
a.uniq
[Point3d(1, 1, 1), Point3d(10, 10, 10), Point3d(10, 10, 10)]` -
Any chance you are getting the points from an array of vertices? Vertices will respond to the uniq(!) methods. I can't think of any time that I actually sorted by Point3d objects. And I tihnk it was because I found it easier to use vertices, which has always worked out ok for what I was writing.
Chris
-
No, not vertices. computed intersections.
-
atm I got this code:
def self.uniq_points(points) old_points = points.clone new_points = [] until old_points.empty? point = old_points.shift point_exists = false new_points.each { |p| if p == point point_exists = true break end } new_points << point unless point_exists end return new_points end
but I was wondering if there was a better method....
-
Yeah, as I was thinking - each Point3d object is its own object, and therefore different, even though they might share the same coordinates in space.
You need to compare them as strings I suppose, since I see no quicker comparison method(?). Try this line:
` a = [point1.inspect, point2.inspect, point3.inspect]
a.uniq`
That should work, I don't know how slow it will be if its over zillions of points though,
Chris
-
no, not string. you can compare two points -
point1 == point2
if return true if they are the same point, withing some tolerance SU has set. But it seems thatarray.uniq
doesn't do this type of comparison... -
Point3d's will be uniq!'d if they have the same ID BUT NOT if they have just the same XYZ values [they aren't really equal are they?], but we can write a simple def to sort it out...
def unique(pointsIN = []) return pointsIN if pointsIN.to_a[0].class != Geom;;Point3d # we'll only process an array of Point3d's ? points_a = []; pointsIN.to_a.compact.each{|p| points_a << p.to_a}; pointsa.uniq! # we compact to remove any 'nil' entries ? pointsOUT = []; points_a.each{|p| pointsOUT << Geom.Point3d.new(p.x, p.y, p.z)} return pointsOUT end#def # Assuming a list [array] of Point3d's that might contain duplicates called 'points' then... points = unique points # will give us a list [array] of unique Point3d's called 'points'...
-
Alternatively, following TT's point1 == point2 idea
def unique(pointsIN = []) pointsOUT=[] pointsIN.to_a.each{|p| duplicated = false pointsOUT.each{|po| if po == p duplicated = true break end#if } pointsOUT << p if not duplicated } return pointsOUT end#def points = points unique
Which keeps the Point3d's IDs unchanged...
-
@thomthom said:
But it seems that
array.uniq
doesn't do this type of comparison...Have you tried just adding them to a set?
-
I was pretty sure I'd tried that!
But clearly I haven't!
` point1 = Geom::Point3d.new 1,1,1
Point3d(1, 1, 1)
point2 = Geom::Point3d.new 10,10,10
Point3d(10, 10, 10)
point3 = Geom::Point3d.new 10,10,10
Point3d(10, 10, 10)
s = Set.new
#Set:0xbd7da68
s.insert(point1)
#Set:0xbd7da68
s.insert(point2)
#Set:0xbd7da68
s.insert(point3)
#Set:0xbd7da68
s.to_a
[Point3d(1, 1, 1), Point3d(10, 10, 10)]`Very interesting that it evaluates differently. It compares the values, not the objects.
Exactly the kind of solution I was hoping for.
Advertisement