top of page
Trimble_Logo.svg.png
SketchUp-Horizontal-RGB-120pxl_0.png

Lengths and Units in SketchUp

Chapters

This article will hopefully shed some light on the nuances of lengths and units in SketchUp, how to understand them, and how to create better extensions, with less work!

The Theory

In most 3D modelers, lengths are represented by abstract numbers and the unit that translates these numbers into a physical distance in space is stored as metadata. In SketchUp, lengths and units work a bit differently. Internally, SketchUp always uses inches. The unit setting of a model is used to translate between inches and the unit of the user's choice, in the display layer only.

 

For end users it may make little difference, but it can be useful to know as developers. Thinking in inches can be upsetting for people outside of the USA. Luckily, you don't actually need to think of inches. The SketchUp length class encapsulates this well, and SketchUp's internal unit can be thought of largely as an implementation detail.

In practice

In SketchUp extensions, prefer defining distances using the Length class, not as floats or integers. The length class has a bunch of nice behaviors we'll get into in this article. It also makes the intent of the code clearer when you spell out a distance - such as the thickness of your lumber - as 2 inches and not 2 abstract units.


The API offers several methods for converting Numerics to Lengths.

# Bad
length1 = 1
length2 = 0.2

# Good
length1 = 1.feet
length2 = 0.2.m

When showing the values to the user, rely on the `Length#to_s` method. This will automatically format the value according to the model's unit settings as well as the system's decimal separator.

# Bad
length = 200
length_string = length.to_s + " mm"

# Good
length = 200.mm
length_string = length.to_s

When parsing the user input, rely on `String#to_l`. This allows the user to enter values with any unit SketchUp supports, defaulting to the display unit of the model if the user doesn't specify one. It also honors the system's decimal separator.

 

You can try different input values such as `"50 mm"`, `"5cm"`, `"50.0mm"`, `2"`, or an implicit unit like `50` or `0.5`, and see how this code behaves.

# Bad
user_input = "50" # (Expecting mm)
length = user_input.to_f.mm

# Also bad
user_input = "50" # (Expecting mm)
length = user_input.to_f * 0.03937

# Good
user_input = "50" # (Honors model setting)
length = user_input.to_l

A little caveat is that you need to do some error handling if the user enters an invalid value that cannot be interpreted as a length. You can try with values such as "3.1 m" or "3,1 m". One of these should work and the other not, depending on what decimal separator your system uses.

begin
  length = user_input.to_l
rescue
  UI.messagebox("Invalid input").
end

Also, in most cases you probably want to do some input verification anyway, to make sure it's not 0 or negative.

Serializing

When saving a length for later use, e.g. holding on to a user input between SketchUp sessions or saving values to a config file, use Floats. The `Length` class only exists within SketchUp and cannot be directly serialized. The string representation is dependent on the system's current decimal separator, the model's display unit and rounded to the model's display precision. The string is great for communicating with humans but unstable for storing values.

# Bad
length = 4.cm
path = UI.savepanel("Config File")
File.write(path, length.to_s)

# Also bad
length = 4.cm
path = UI.savepanel("Config File")
File.write(path, length) # Implicitly converts to String

# Good
length = 4.cm
path = UI.savepanel("Config File")
File.write(path, length.to_f)

You can try different inputs with varying numbers of decimals, adjust the unit settings (Window > Model Info > Units) or your system decimal separator, and see how the length is read back.

serialized_length = File.read(path)
length = serialized_length.to_l
serialized_length.to_s

Calculations

Something to be aware of when doing mathematical operations is that the return value doesn't stick to the Length class. However, this can be easily fixed by calling `to_l` again.

# Bad
length = 2.m
double_length = length * 2
double_length.class => # Float
double_length.to_s => # "157.48031496062993"


# Good
length = 2.m
double_length = (length * 2).to_l
double_length.class => # Length
double_length.to_s => # "4000 mm"

While most of SketchUp's API can accept both Length objects and any Numeric object, it's good to consistently stick to Lengths. This avoids surprises when later formatting the value into a String and ensures any comparison is done with SketchUp's tolerance. Convert to String for the UI layer and to float for serializing the value, but use Length in the rest of your code.

Unit Aware Defaults

You may have noticed that the metric values in these examples look bad if you are using imperial units or vice versa.

# Metric definition
lumber_size = 50.mm

input = UI.inputbox(["Lumber Thickness"], [lumber_size])

# Metric users see 50 mm, 5 cm, 0.05 m etc :)

# Imperial users see ~ 2", ~ 1,97", ~ 1 15/16" etc :(

# Imperial definition
lumber_size = 2.inch

input = UI.inputbox(["Lumber Thickness"], [lumber_size])

# Imperial users see 2" :)
# Metric users see 50,8 mm ~ 51 mm, ~ 5.1 etc cm:(

Two whole inches translate to the awkward 50.8 mm, while a nice even 50 mm maps to 1.968503937007874 inches. A value such as 1.968503937007874 doesn't bring the user any joy or much confidence in your extension.

 

Instead of using the exact same measurement, it often makes sense to use whole numbers in the current measurement system. You can check what measurement system SketchUp uses and provide different default values for metric and imperial usage.

def metric?
  unit_options = Sketchup.active_model.options["UnitsOptions"]
  return false unless unit_options["LengthFormat"] == Length::Decimal
 
  [Length::Millimeter, Length::Centimeter,
  Length::Meter].include?(unit_options["LengthUnit"])
end

lumber_thickness = metric? ? 50.mm : 2.inch
door_height = metric? ? 2.1.m : 80.inch
road_width = metric? ? 10.m : 30.feet

input = UI.inputbox(
  ["Lumber Thickness", "Door Height", "Road Width"],
  [lumber_thickness, door_height, road_width]
)

On rare occasions you may want a measurement to default to 1 of whatever display unit SketchUp happens to be using, for instance to draw a unit sphere. However this is quite unusual and most extensions seem to be drawing concrete things with physical sizes like doors and roads. SketchUp is very much a practical design tool and not widely used for abstract geometry. Also, while measurements such as 1 yard, 1 meter or 1 inch are typically fine, drawing a 1 mm radius sphere clashes with SketchUp's internal tolerances and ability to form small faces. In addition mm is widely used in architecture in Europe. Just because the display unit is small doesn't necessarily mean the user is drawing small objects.

Unit Agnostic Extensions!

You may have noticed these preferred snippets work the same regardless of model display unit.

 

There's a tendency among new extension developers to hardcode extensions to the one unit of their choice. Without knowing of the Length class, it's easy to fall back on integers and floats and your own definition of in what unit they are. Unfortunately this makes the extension much less useful in industries and regions with other units.

 

Hardcoding a certain unit is also inconsistent to SketchUp and makes the extension feel less polished. Even if it's hardcoded to the same unit as the user's model, it would just look and feel different.

Bad:

2025-03-25_11h52_48.png

Good:

2025-03-25_11h53_28.png

Also, it doesn't really save any work to hardcode the unit. In the above examples, the snippets handling just one unit and those handling any unit are about as long. On the contrary, if you manually try to replicate the parsing and formatting already provided by SketchUp, you are increasing your workload. There are even cases when there's a metric and imperial version of the same extension, meaning any feature improvements or bugfixes have to be done twice.

SketchUp's Internal Unit

Note that the above code doesn't really care about what unit SketchUp uses internally.

SketchUp could hypothetically be working in meters, cm, inches, oranges or bananas, the above code would look the same. Usually we can think of SketchUp's internal unit as an implementation detail, at least when using the Length class properly instead of other Numeric classes. Metric developers, fear not!

 

But why does SketchUp at all have an internal unit? Why isn't everything defined in the same unit as it's displayed? One reason could be that SketchUp is primarily meant for designing physical things like houses, interiors and landscapes. When copying something between an architectural model - using inches or mm - and a landscaping model - using feet or meters - you normally want to retain its physical size, not the digits used to express that size.

 

Separating the presentation from the underlying value also helps with complex unit display. For instance SketchUp can combine units and format a distance as 6'8" (6 feet and 8 inches) instead of 80", or display fractions such as 1 1/8" (one and one eighth of an inch) instead of 1.125". This is a great example of SketchUp's early human centric design. Don't make humans adapt to computers; make computers adapt to humans!

Area and Volume

Areas and volumes are expressed internally in square and cubic inches. There is however no built-in Area or Volume class nicely encapsulating them like the Length class. Instead Floats are typically used.

 

There's no built-in support in the API but you can manually convert between units.

area = 5 / 0.0254**2 # Square m to square inches
volume = 10 / 2.54**3 # Cubic cm to cubic inches

It's however quite rare that you define areas and volumes directly. Usually you get areas from faces or volumes from solid (manifold) groups and components. You can also calculate them by multiplying perpendicular distances.

area = 5.m * 4.m
volume = 1.inch * 2.feet * 1.yard

The API provides methods for formatting the measurements for the user, honoring the active model's unit settings and the system's decimal separator.

Sketchup.format_area(area)
Sketchup.format_volume(volume)

There's no API method for parsing areas and volumes typed in by the user but Thomas Thomassen has made a little library that can help with this, among other things.

Angles

Like with most programming languages, Ruby's trigonometric methods use radians for angles. The display layer of SketchUp however uses degrees, like most humans. The conversion between display units and internal units is similar to that of other measurements.


Similar to Lengths, the Ruby API provides a method for converting from numerics, although there's no dedicated class to express angles. Similar to areas and volumes, there's a method to format as strings that honors the model's display precision and the system's decimal separator.

# Prefer radians internally
angle = 30.degrees

# Format as string for the display layer
display_angle = Sketchup.format_angle(angle)

The API has no method for parsing user angle input, but you can define one yourself, or use Thomassen's library.

def self.parse_angle(text)
  text.tr(Sketchup::RegionalSettings.decimal_separator, ".").to_f.degrees
end

In Summary
Separate internal values and the display layer. Use the power of the Lengths class for any values representing distances. Convert to Strings only in the display layer and only convert Lengths to Floats when you need to store the value.
 
This keeps your code cleaner and easier to work with, while also ensuring a consistent user experience to the rest of SketchUp.


Further Reading
Handling the ~ Mark
Dealing with Units in SketchUp - Thomas Thomasen 2012

bottom of page