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.
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.