This is a strange one… So strange that my code needs to be tweaked for SU2017 on Windows only… But let me provide the following snippet first:
p1 = Geom::Point3d.new(1.0, 2.0, 3.0)
p2 = Geom::Point3d.new(4.0, 5.0, 6.0)
h = Hash.new
h[[1.0, 2.0, 3.0, 4.0, 5.0, 6.0]] = 7.0
k1 = [*p1, *p2]
k2 = [p1.x, p1.y, p1.z, p2.x, p2.y, p2.z]
puts k1 == k2 # Prints true
puts h[k1] # Prints 7.0, as expected
puts h[k2] # Prints nothing :(
What is going on here? In my actual code I’m setting up a similar hash and then I query it later on. I was using the asterisks approach to unpack the values and it worked just fine in SU2022 on macOS, but when testing on Windows with SU2017 I needed the opposite approach… Then I’ve tested SU2017-macOS and SU2023-Windows and the asterisks worked there too.
I am completely baffled.
Never mind, I’ve fixed the problem in my extension code (turns out that I needed to explicitly call .to_f
on each .x
, .y
and .z
when adding items to my hash). I’m still puzzled about the snipped above, though.
EDIT. Let me add another k3
key:
k3 = [p1.x.to_f, p1.y.to_f, p1.z.to_f, p2.x.to_f, p2.y.to_f, p2.z.to_f]
puts h[k3] # Prints 7.0 again!
Be aware that the API docs are incorrect, in that the .x
, .y
and .z
methods of the Geom::Point3d
class return Length
not Float
nor generic Numeric
.
This means that comparisons will use the API Length#==
method to find matches within SketchUp’s tolerance of 0.001 inch.
This may not be true for Float
which is subject to floating point errors and could cause you grief.
1 Like
Yeah, it was a Float
vs Length
issue… This can be seen by calling .class
on the key elements, e.g.
k1[0].class # Returns Float
k2[0].class # Returns Length
It’s funny that k1.hash == k2.hash
is true
, so I thought the dictionary lookup would succeed anyway. Seems like the Ruby hash takes into account the class
attribute as well.
The Ruby docs for Hash#==
say …
Equality—Two hashes are equal if they each contain the same number of keys and if each key-value pair is equal to (according to Object#==
) the corresponding elements in the other hash.
So, you have both key match comparisons and value comparisons. The value comparisons will use the overridden #==
method for their class, but if not overridden then Ruby will search up the inheritance (ancestry) chain for the first #==
method it finds to use for the comparison.
For Length
it’s #==
method has been overridden to test within SketchUp’s tolerance.
For Float
it has also an overridden #==
method that can compare objects of different Numeric
subclasses. Make sure you read this about the Float
comparisons and how it’s #==
method can mislead you.
I would strongly suggest you should use arrays and hash values converted to Length
objects.
1 Like