Accuracy and return values from inputbox when default value is a length

So, in my mind, the user is really only interested in using / seeing values as set in the Units panel. So I would present them with values in their selected (expected) precision:

model = Sketchup.active_model
units = model.options["UnitsOptions"]

#<Sketchup::OptionsProvider:0x0000000dca6db0>

units.keys

["LengthPrecision", "LengthFormat", "LengthUnit", "LengthSnapEnabled",
"LengthSnapLength", "AnglePrecision", "AngleSnapEnabled",
"SnapAngle", "SuppressUnitsDisplay", "ForceInchDisplay"]

units["LengthPrecision"]

3

:warning: The above are not constants. The user can change them at any time. But coders can use an observer to watch these options collections.

1 Like

If I understand what you are saying then I must proceed as follows.
I postfix values in inputbox with value.to_l so they are presented in the unit and precision format of the user. If I want to compare the return value with a comparison variable I must reformat the comparison variable to the users precision because inputbox will have truncated the return value. inputbox cannot return the original value because it converts it to a string to show in the dialog box and thereby losses the original precision. If you convert the return value to a float then you get a number with invalid numbers in the out of precision end of the number, which looks precise but is wrong.

The code snippet below works on my 64bit HP PC. I would point out that it is necessary to temporarily increase the precision to get an accurate comparison if the units are metres and the precision is 2 or less. I increased it to 4 then reset it when the comparison was done in this snippet.

original = 123456789.125456789
shown = original.to_l

options_manager = Sketchup.active_model.options
unitsOptions = options_manager["UnitsOptions"]
lengthPrecision = unitsOptions["LengthPrecision"]

comparison = original.to_l.round(lengthPrecision)

unitsOptions["LengthPrecision"] = 4

puts"original is #{original}. comparison is #{comparison}. shown is #{shown}"

input=UI.inputbox(["Float", "Text"], [shown, "Jim"], "Basic Data")
returned_value = input[0].to_f.round(lengthPrecision)
puts"returned_value is #{returned_value}"
unitsOptions["LengthPrecision"] = lengthPrecision

if comparison== returned_value
then puts("comparison and returned value are effectively equal")
else puts("comparison and returned value are unequal")
end

Just as a prerequsite, go to the “Ideas” group from the pinned wikilist for Ruby Learning Resources, and read and study Thomas’ tutorial on units and the UI::inputbox() method.


And FYI, (besides Length#to_s(),) there are additional module methods in the API, to create unit formatted strings:

(Unless otherwise noted, methods available since v 6.0)

Re your example.

a. It is not nice to change the user’s precision setting without restoring it when done.

b. If I were doing this I think I’d leverage the Length class’ ==() method which does comparisons using SketchUp’s internal tolerance. Because basically that is what really matters. (You’re using Ruby Float class’ comparison method, which brings in the floating point madness into the picture.)

Thank you for your helpful links and advice. I found the articles by Thomas interesting.
a/ I reset the precision with the line quoted below from my example.

Or is there something not right about resetting it in this way?

b/ I tried that but the comparison doesn’t work unless I convert it to a string and back into a length. Below is the code I tried first, which doesn’t work.

original = 123456789.125456789
shown = original.to_l
comparison = original.to_l
puts"original is #{original}. shown is #{shown}. comparison is #{comparison}."
input=UI.inputbox(["Float", "Text"], [shown, "Jim"], "Basic Data")
returned_value = input[0].to_l
puts"returned_value is #{returned_value}"
if comparison == returned_value
then puts("comparison and returned value are effectively equal")
else puts("comparison and returned value are unequal")
end

Below is the code where the variable comparison is first converted to length, then to string and finally back to length. This comparison seems to work, even if it is a bit of a palaver!

original = 123456789.125456789
shown = original.to_l
comparison = original.to_l.to_s.to_l
puts"original is #{original}. shown is #{shown}. comparison is #{comparison}."
input=UI.inputbox(["Float", "Text"], [shown, "Jim"], "Basic Data")
returned_value = input[0].to_l
puts"returned_value is #{returned_value}"
if comparison == returned_value
then puts("comparison and returned value are effectively equal")
else puts("comparison and returned value are unequal")
end

Thank you again everyone for your help.

1 Like