Iterate Over Existing Dimensions

Hello,

Great resources on this forum, and I want to thank everyone in advance, and apologize as I’m coming from python and thus learning Ruby and the SKUP API all at once.

My goal is to open a Layout document, get all the existing Dimension, and set their Layout::Style to Metric.

UPDATE:
So I’ve got this far in editing dimension style. Now I’m just looking for help turning this into a for loop and iterating over the dimensions.

    doc = Layout::Document.open(“/FILEPATH/Test.layout”)
    page = doc.pages.first
    entity = page.entities.first
    style = entity.style
    style.set_dimension_units(Layout::Style::DECIMAL_MILLIMETERS, 1)
    entity.style = style
    doc.save

This just gets the first page and the first entity on that page. I’m guessing I need to get all pages as an [array] and loop over each page, with a nested for loop getting all entities.

Will it throw an error if I don’t specify Dimensions?

Thanks again

Please delimit code blocks correctly for the forum …

Major difference is Ruby uses 2 space indents and has an end statement to close blocks (of all kinds. It does not have specific end keywords for each type of block like Pascal has for example.)

Second, major difference is that modules and class definitions are not tied to any specific file nor filename. (Ie, the name of a file has no bearing upon what the identifier names are of module or class definitions within the file.)
Ruby is a dynamic language and so any (unfrozen) class or module can be reopened for changes during runtime, by any number of files. When you use the interpreter syntax of a line beginning with module, the interpreter will call the Module class constructor if it hasn’t yet been defined, or it it has, then the interpreter will call the #module_eval upon the module object passing in the code block.

This all means you’ll be modifying your toplevel namespace module each time you load one of your plugins. Each extension / plugin should be wrapped in a submodule of your namespace module, so it will not clash with your other plugins, and the namespace module protects it from other coder’s code (as well as the Ruby core classes and modules.) The opposite is also true.

This also means that your plugin submodule can span any number of .rb files. This can make it much easier to write and maintain if you use a code editor that has tabbed mutil-doc interface and more so if it supports side by side or one above another editing panes.


Take advantage of the wiki lists I’ve compiled here …

… and especially the Python migration primer listed on …

It will (raise an NoMethodError) if you call a method that the iterator entity does not respond to.

The most beneficial thing new SketchUp Ruby API coders need to learn is that most SketchUp API collection classes mixin in the Ruby Core Enumerable module. From this module we get the very fast #grep method. Ie …

module Sertfas
  module MyThang
  
    extend self

    def set_dim_units_mm(doc)
      doc.pages.each do |page|
        dims = page.entities.grep(Layout::LinearDimension)
        dims.each do |dim|
          style = dim.style
          style.set_dimension_units(Layout::Style::DECIMAL_MILLIMETERS, 1)
          dim.style= style
        end
      end
    end

    def do_my_thang()
      filepath = UI.openpanel(
        'Choose filepath', File.expand_path('~'), 'Test.layout'
      )
      return false unless filepath
      begin
        doc = Layout::Document.open(filepath)
      rescue => err
        puts err.inspect
        return false
      else
        set_dim_units_mm(doc)
        doc.save
      end
    end

    if !@loaded
      UI.menu('Extensions').add_item('Do My Thang...') { do_my_thang() }
      @loaded = true
    end

  end
end

EDIT: Fixed the method set_dim_units_mm that was setting the units upon the dimension’s text object instead of the dimension itself. (See @sertfas’ post below.)


Notice at the top of the Layout::Entities class documentation page, it lists the Enumerable module as included.

See Module#include for more explanation.

Wow, thank you very much for the clear and thorough explanation. Really grateful for you to take the time. It would’ve taken me a loooong time to get to this point.

For the benefit of posterity, please note commented lines below. While I’m sure Dan’s code works as intended on his machine, I had to change the following lines to achieve the desired result.

    module Sertfas
      module MyThang
      
        extend self

        def set_dim_units_mm(doc)
          doc.pages.each do |page|
            dims = page.entities.grep(Layout::LinearDimension)
            dims.each do |dim|
              style = dim.style    #Replaced dim.text.style with dim.style
              style.set_dimension_units(Layout::Style::DECIMAL_MILLIMETERS, 1)
              dim.style = style  #Replaced dim.text.style with dim.style
            end
          end
        end

        def do_my_thang()
          filepath = UI.openpanel(
            'Choose filepath', File.expand_path('~'), 'Test.layout'
          )
          return false unless filepath
          begin
            doc = Layout::Document.open(filepath)
          rescue => err
            puts err.inspect
            return false
          else
            set_dim_units_mm(doc)
            doc.save
          end
        end

        if !@loaded
          UI.menu('Extensions').add_item('Do My Thang...') { do_my_thang() }
          @loaded = true
        end

      end
    end

Thank you again Dan, hope this little script can help someone else’s workflow.

1 Like

:laughing: I actually didn’t test it. Just whacked it out.

I looked for the #style getter method under the Layout::LinearDimension class, didn’t see it, and saw the #text getter, and looked that up and saw it did have a #style getter. I made an assumption. :blush:

The Layout::LinearDimension class actually inherits it’s #style getter and #style= setter methods from it’s superclass Layout::Entity.

I’ll fix the example so readers are not misled.