Array.uniq! for a 3d-point array ???
-
hi,
i cannot find the syntax forarry.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 -
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'sGeom::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
-
A
Point3d
is pretty much anArray
, at least for many aspects of most methods, and a three itemArray
can usually be treated as aPoint3d
too.
But as has been said unless your array-of-points [which you want to use.uniq
on] is an array ofArray
objects and notPoint3d
objects it will not work, since eachPoint3d
has a unique reference already.
So make an array of points-made-into-arrays [usingpoint.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 ?? -
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
-
I seem to remember
inject
running 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 } }
-
@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 theuniq!
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 newPointArray
subclass ofArray
., 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.
Theuniq
methods want to calleql?()
instead of==()
.
Advertisement