Uniquifying arrays of Geom::Point3d
or Geom::Vector3d
objects
In Ruby each Geom::Point3d
or Geom::Vector3d
instance object created has it’s own signature and is distinct, even if it’s coordinates match another instance.
But, in many coding scenarios it is desirable or necessary to uniquify arrays of Geom::Point3d
or Geom::Vector3d
objects … before passing them to geometry creation methods. (Uniquifying means that the duplicates that have matching coordinates need to be pared down to a single item in the array.)
Ruby’s Array
class has the #uniq
and #uniq!
methods. But beware!
These methods use Object#hash
and Object#eql?
for comparison.
However, the SketchUp Ruby API has not overridden these methods for the Geom::Point3d
or Geom::Vector3d
classes. So they will return differing values and will not help to find instance objects that have the same coordinates.
What we need is to compare point or vector objects within SketchUp’s merging tolerance (~ 0.001").
Fortunately the API’s Length
class does this in comparisons, and the Geom::Point3d#to_a
and Geom::Vector3d#to_a
methods return an array of [Length, Length, Length]
. (How convenient!)
So for example, to leverage Ruby’s uniq’ing methods on an array of points, use …
pt_ary.uniq!(&:to_a)
… which will remove any duplicates based upon comparing the point’s x,y,z Length
arrays.
The shorthand above is the same as:
pt_ary.uniq! { |pt| pt.to_a }
Note that this will not convert the members of pt_ary
to Length
arrays. It only uses them for comparison.
Also, the first duplicate(s) found are kept, the others discarded.
If we want a new uniq’ed array, then we would not use the bang form of the method, instead:
uniq_ary = pt_ary.uniq(&:to_a)
The same applies to arrays of 3D vector objects.
In summation, if a point array is to be passed into a face creation method, it can be uniquified as:
model.entities.add_face(pts.uniq(&:to_a))
Or …
model.entities.build { |builder|
builder.add_face(pts.uniq(&:to_a))
}