Set attribut date shadow dynamic component

Good evening the community!
I am new to the forum, although I have been using sketchup for many years.
I have not yet taken the time to train myself at Ruby.

I’m a landscape artist, and I draw my dynamic components of plants.
I would like to vary them according to the date of the sketchup shadows. Depending on the seasons, appear fruits, flowers, autumn foliage …

Sketchup does not propose to return this date information in the dynamic component functions!

This is only possible with a Ruby script.
I would like a code for:
Select all the dynamic components of the model and set them the “DateShadow” attribute that corresponds to the shadow date of the model.

I thank you for your time.

Best regards
Simon

Thanks Dan
Thanks for the responsiveness and quality of the response.
I will try with the help of another comrade on the Biblio3D forum to put this into practice.
I come back to you to tell you how progresses!

Our first step was to use elevation of the sun and angle
But the summer and spring seasons overlap with fall and winter.
It joins a celestial vault trigonometric located in Paris.
The zones are drawn according to the values ​​provided by the values ​​of the elevation of the sun and sketchup angles in the functions of the dynamic component.
thanks again
Best regards

Simon
Video Saison solaire sketchup sur youtube

Hello

I begin to understand your code, which proposes a change of state of a season attribute according to a list of 4 possible values.
With a return to the first value if one has reached the last one.

If I want more flexibility on the value of the non-season attribute but dateShadow.
For a flowering may last only a few weeks. And who are not the same as his neighbor. And yet both bloom in spring!

Without artificially varying season value. I prefer to retrieve in value the date of the shadows of the model.
This will allow me to vary it easily.

It lacks a right mouse click to “Update dateShadow attibut in dynamic component”

Thank you

Best regards
Simon

Thanks Dan
I will try to complete the code!
I come back for the correction.
Thanks again.
Simon

I did not try
I wanted to know if I was first on the right track!
Here is my first jet
Thank you for showing me my mistakes.

    # encoding: UTF-8

    require "sketchup.rb"

    module SimJoubert
      module SeasonalComponents

        extend self
        
        MENU_TEXT = "Update dateShadow DC attibuts"
        DICT = "dynamic_attributes"

        def command
          selset = Sketchup::active_model.selection
          if selset.empty?
            # update ALL seasonal components
            update_dc_date_attribut(Sketchup::active_model.definitions)
          else
            # update ONLY selected seasonal components
            update_dc_date_attribut(selset)
          end
        end

        def get_seasonal_dcs(collection)
          # Filter the referenced collection to
    		dlist = Sketchup::active_model.definitions
    		dcs = dlist.select {|d| d.attribute_dictionary(DICT,false) }
    		
          # select only seasonal dynamic components
    		seasonal = dcs.select {|d| d.get_attribute(DICT,"Season",false) }
          # as shown in previous posted example.
        end

        def update_dc_date_attribut(collection)
          seasonal = get_seasonal_dcs(collection)
          # 1. Retrieve data from shadowinfo into local variables,
    		model = Sketchup.active_model
    		shadowinfo = model.shadow_info
    		
          # 2. Iterate the seasonal component definitions
    		value = shadowinfo["DayOfYear"]
          #    writing the data into dictionary attributes.
    		seasonal.each {|d| d.set_attribute(dict,"Season",value) }
    	  
        end

        # other code / methods here

        unless file_loaded?(__FILE__)

          UI.add_context_menu_handler do |context_menu|
            context_menu.add_item(MENU_TEXT) { command() }
          end # context_menu_handler

        end

      end # plugin module
    end # outer namespace module

I don’t know how stylised the code in the message .

Thanks i have trouble in the second part !

# encoding: UTF-8

require "sketchup.rb"

module SimJoubert
  module SeasonalComponents

    extend self
    
    MENU_TEXT = "Update dateShadow DC attibuts"
    DICT = "dynamic_attributes"

    def command
      selset = Sketchup::active_model.selection
      if selset.empty?
        # update ALL seasonal components
        update_dc_date_attribut(Sketchup::active_model.definitions)
      else
        # update ONLY selected seasonal components
        update_dc_date_attribut(selset)
      end
    end

    def get_seasonal_dcs(collection=nil)
      # Filter the referenced collection
      if collection.nil?
        dlist = Sketchup::active_model.definitions
        dlist.reject! {|d| d.image? }
      elsif collection.all? {|o| o.is_a?(Sketchup::ComponentDefinition) }
        dlist = collection.reject {|d| d.image? }
      else
        insts = collection.grep(Sketchup::ComponentInstance)
        groups = collection.grep(Sketchup::Group)
        dlist = insts.map{|i| i.definition } + groups.map{|g| g.definition }
        dlist.uniq!
      end
      dcs = dlist.select {|d| d.attribute_dictionary(DICT,false) }
      # select only seasonal dynamic components
      seasonal = dcs.select {|d| d.get_attribute(DICT,"Season",false) }
    end


    def update_dc_date_attribut(collection)
      # seasonal = get_seasonal_dcs(collection)  **<----I TEST  To enable or not this line**
      # 1. Retrieve data from shadowinfo into local variables,
      model = Sketchup.active_model
      shadowinfo = model.shadow_info
      
      # 2. Iterate the seasonal component definitions
      value = shadowinfo["DayOfYear"]
      #    writing the data into dictionary attributes.
      seasonal.each {|d| d.set_attribute(dict,"Season",value) }

    end

    # other code / methods here

    unless file_loaded?(__FILE__)

      UI.add_context_menu_handler do |context_menu|
        context_menu.add_item(MENU_TEXT) { command() }
      end # context_menu_handler

    end

  end # plugin module
end # outer namespace module

It looks like you are using single quotes not backticks. The backtick is the character on the key at upper left of your keyboard, with tilde ~ as the shifted char.

1 Like

Hello

to return the date of the day according to the shadows i find in API sketchup

=model = Sketchup.active_model shadowinfo = model.shadow_info UI.messagebox ('the day is' shadowinfo ['DayOfYear'].to_s)

I have a ‘date’ attribute and I want ruby ​​to update my attibut date with the date generated by the shadows

For example if I take today’s date, ‘shadowinfo [’ DayOfYear ‘]’ returns me how to write a piece of code to update the value ‘shadowinfo [’ DayOfYear ‘]’ in the ‘date’ attribute of My dynamic component

I am french and very bad in english, sorry for my english translated by google :yum:

Thank you

Best regards
Jack

I tried without success!
I can not set the “Season” attribute with the value of the day variable.

    def update_dc_date_attribut(collection)
      # seasonal = get_seasonal_dcs(collection)
      # 1. Retrieve data from shadowinfo into local variables,
      model = Sketchup.active_model
      shadowinfo = model.shadow_info
      
      # 2. Iterate the seasonal component definitions
      day = shadowinfo["DayOfYear"]
	  UI.messagebox("le Jour de l'année est: " + day.to_s)
      #    writing the data into dictionary attributes.
      seasonal.each {|d| d.set_attribute(DICT,"Season",day) }

    end

By cons I managed to put style code on the forum

Thanks to explain me the mystake

Thanks
Simon

There were 3 errors in the code.

DC attribute keys must be all lowercase.
(We were referring to the attribute label, which can be title case.)

So we must reference it as “season” instead.

This uses a dict local variable, instead of the module constant DICT, in the update_dc_date_attribut() method. We also need to use the lowercase attribute key name “season” instead of the attribute text label.


There also was an error in the get_seasonal_dcs() method where it checked for seasonal attributes.
(Besides using the correct lowercase key name,) when the “season” attributes were unset, or nil, the test for the attribute returned nil, which caused the boolean test inside the select() method’s block to give false result even upon dictionaries with a “season” key. (In the Ruby language, nil and false evaluate as boolean FALSE, but all other objects evaluate as boolean TRUE.)

So this fails with brand new unset (empty) “season” attributes:

seasonal = dcs.select {|d| d.get_attribute(DICT,"season",false) }

Instead we need to just check for the existence of the “season” key, with no regard for it’s value:

seasonal = dcs.select {|d|
  d.attribute_dictionary(DICT,false).keys.include?("season")
}

So, I have posted the re-worked code with built-in debug switch in the next post.

I added a create command to make a non-seasonal component into a seasonal one.
Their are also now a debug switch. At the console switch on debugging:

SimJoubert::SeasonalComponents.debug= true

The name of the seasonal attribute key can be set at the top of the module via the constant: SEASON_ATTR


Here is the file to download …
seasonal_components.rb (3.6 KB)
… which looks like:

# encoding: UTF-8

require "sketchup.rb"
require "pp"

module SimJoubert
  module SeasonalComponents

    extend self
    
    @@context_menu_set ||= false
    @@debug ||= false
    
    MENU_TEXT = {
      :update => "Update season DC attibuts",
      :create => "Create season DC attibuts"
    }

    DICT = "dynamic_attributes"

    SEASON_ATTR = "season"

    def command_create(selset)
      return if selset.empty?
      # Make the definitions of selected components
      # or groups seasonal:
      create_dc_date_attribut(selset)
    end

    def command_update(selset)
      if selset.empty?
        # update ALL seasonal components
        update_dc_date_attribut(Sketchup::active_model.definitions)
      else
        # update ONLY selected seasonal components
        update_dc_date_attribut(selset)
      end
    end

    def debug
      @@debug
    end

    def debug=(arg)
      @@debug =( arg ? true : false )
    end

    def get_seasonal_dcs(collection=nil)
      # Filter the referenced collection
      if collection.nil?
        dlist = Sketchup::active_model.definitions
        dlist.reject! {|d| d.image? }
      elsif collection.all? {|o| o.is_a?(Sketchup::ComponentDefinition) }
        dlist = collection.reject {|d| d.image? }
      else
        insts = collection.grep(Sketchup::ComponentInstance)
        groups = collection.grep(Sketchup::Group)
        dlist = insts.map{|i| i.definition } + groups.map{|g| g.definition }
        dlist.uniq!
      end
      dcs = dlist.select {|d| d.attribute_dictionary(DICT,false) }
      # select only seasonal dynamic components
      seasonal = dcs.select {|d|
        d.attribute_dictionary(DICT,false).keys.include?(SEASON_ATTR)
      }
      if @@debug
        puts "#{Module::nesting[0].name}: debug is true."
        puts "The 'dlist' array:"
        pp dlist
        puts "The 'dcs' array:"
        pp dcs
        puts "The 'seasonal' array:"
        pp seasonal
      end
      return seasonal
    end


    def create_dc_date_attribut(selected)
      # 1. Retrieve data from shadowinfo into local variables,
      model = Sketchup.active_model
      shadowinfo = model.shadow_info     
      value = shadowinfo["DayOfYear"]
      if @@debug
        puts "The 'day of year' value:"
        pp value
        puts # blank line
      end
      # Writing the data into dictionary attributes.
      selected.each {|obj|
        next unless obj.respond_to?(:definition)
        obj.definition.set_attribute(DICT,SEASON_ATTR,value) 
      }
    end

    def update_dc_date_attribut(collection)
      seasonal = get_seasonal_dcs(collection)
      # 1. Retrieve data from shadowinfo into local variables,
      model = Sketchup.active_model
      shadowinfo = model.shadow_info
      
      # 2. Iterate the seasonal component definitions
      value = shadowinfo["DayOfYear"]
      if @@debug
        puts "The 'day of year' value:"
        pp value
        puts # blank line
      end
      #    writing the data into dictionary attributes.
      seasonal.each {|d| d.set_attribute(DICT,SEASON_ATTR,value) }
    end

    # other code / methods here

    unless file_loaded?(__FILE__) || @@context_menu_set

      UI.add_context_menu_handler do |context_menu|
        selset = Sketchup::active_model.selection
        context_menu.add_item(MENU_TEXT[:update]) { command_update(selset) }
        unless selset.empty?
          context_menu.add_item(MENU_TEXT[:create]) { command_create(selset) }
        end
      end # context_menu_handler

      @@context_menu_set = true

    end

  end # plugin module
end # outer namespace module

WOUHOU !!!:raised_hands::tada:

Thanks you very much ! It’s amazing !
I hope one day to be able to do the same

I have to spend time to understand all the line of this code.
Thanks DanRathbun.

The declaration of variable at the begin is very useful.!
I tangled the brush between the declaration of the selection and what is selected.

I don’t understand when you write

seasonal.each {|d| d.set_attribute(DICT,SEASON_ATTR,value)

what for : |d| ?

I’ll go to test it !

Thank you
Best regards

Simon

Yes it’s great !
Only a space error in line 63 64

 # select only seasonal dynamic components
      seasonal = dcs.select {|d|
        d.attribute_dictionary(DICT,false).keys.include?(SEASON_ATTR)
      }

it must be

 # select only seasonal dynamic components
      seasonal = dcs.select {|d| d.attribute_dictionary(DICT,false).keys.include?(SEASON_ATTR) }

Thank you
I have to learn and practice the code.

Simon

But the ruby consol no accept !

On the Ruby console you have to use ctrl+enter to continue on a new line. Otherwise enter causes the console to immediately evaluate whatever it has so far.

This is not true in a Ruby source file, it is peculiar to SketchUp’s Ruby console.

Btw on Mac you use alt+enter

Thanks for the subtility !
I test it it’s well
We must exit the dc to refresh the panel attribut
Can we add a refresh command?

On PC machines to refresh dialog windows, explorer, browsers, etc,
the operating system has already set the shortcut key F5.

F5

… but the window (to be refreshed) must have the UI focus.

Hello

A quick test
ok to update the season but I put a variable in the dynamic component to update the components

(I put the title of the plugin in French in the context menu )

https://www.youtube.com/embed/EYy0K38t6gA

This topic was automatically closed after 91 days. New replies are no longer allowed.