Beware… Your title asks about points. Although the API allows 3 element arrays to be used as point coordinate data in many of it’s method arguments, they are not actually points objects.
a =[
[0.0, 0.0, 97.125], [0.0, 0.0, 97.125], [0.0, 5.5, 97.125], [0.0, 5.5, 97.125]
]
Plain Ruby will see the first two members as the same because Array#uniq
uses #eql? to compare members which for Array#eql?
sees two arrays as equivalent if they contain the same exact core numeric data (ie, Float or Integer values.)
a == a.uniq
#=> false
a[0] == a[1]
#=> true
However, when the members are actual point objects the result is different …
a.map!{|e| Geom::Point3d.new(e) }
#=> [
# Point3d(0, 0, 97.125), Point3d(0, 0, 97.125),
# Point3d(0, 5.5, 97.125), Point3d(0, 5.5, 97.125)
# ]
a[0] == a[1]
#=> true, because the API overrode Geom::Point3d#==
a[0].eql?(a[1])
#=> false, because the API did not override Geom::Point3d#eql?
a == a.uniq
#=> true, because again Array#uniq is using Object#eql?
# ... which the API did not override for the Geom::Point3d class.
So, it might be best if you use a custom method to uniquify a list of points …
def unique_point_array(*args)
if args.size == 1 && args[0].is_a?(Array) &&
args[0].all? {|arg| !arg.is_a?(Numeric) }
args.flatten!
end
# Create a copy of the array mapped to points:
ary = args.map do |obj|
next obj if obj.is_a?(Geom::Point3d)
next nil unless obj.respond_to?(:to_a)
Geom::Point3d.new(obj.to_a[0..2]) # Array | Geom::Vector3d
end
ary.compact! # removes nil references
ary.delete_if do |pt|
# Compare pt against the remainder of the array, removing
# the pt immediately each iteration if block returns true:
ary[ary.index(pt)+1..-1].any? { |other|
# Use API's Geom::Point3d#== to compare within tolerance:
pt == other
}
end
end
Now you still need to be sure that you pass a minimum of three points or an array of 3 points to the #add_face
method.
ents = group.entities
Now, assume you have an array of mixed objects (numeric arrays, points or vectors):
ents.add_face(unique_point_array(array))
Or, if the objects were not in an array, you can pass as a list …
ents.add_face(
unique_point_array(pt1,[0.0, 0.0, 97.125],vec2,pt3,[0.0, 5.5, 97.125])
)
AND … if you wish to pare it down more … and not allow a list of parameters, …
ie, require 1 array argument of arrays, points or vectors …
# Takes only 1 Array argument of (arrays, points or vectors)
def unique_point_array(args)
# Create a copy of the array mapped to points:
ary = args.select {|arg| arg.respond_to?(:to_a) }.map do |arg|
Geom::Point3d.new(arg.to_a[0..2]) # Array | Point3d | Vector3d
end
ary.delete_if do |pt|
ary[ary.index(pt)+1..-1].any? { |other| pt == other }
end
end