I get the following code, after running, we can see that the time is changing with the timeline, but how should this change of time be used?

I get the following code, after running, we can see that the time is changing with the timeline, but how should this change of time be used?For example, how do I take the hour h of a changing time in a module, which is still changing outside the module, and the formula h=h-8 is also changing along the timeline

  class MyShadowInfoObserver < Sketchup::ShadowInfoObserver
    def onShadowInfoChanged(shadow_info, type)
      # puts "onShadowInfoChanged: #{type}"
      Sketchup.active_model.active_view.invalidate
    end
  end

  class ShadowTool
    def initialize()
      # Attach the observer.
      Sketchup.active_model.select_tool(self)
    end
     
    def activate
      # puts 'activate'
      @observer =MyShadowInfoObserver.new
      Sketchup.active_model.shadow_info.add_observer(@observer)
      Sketchup.active_model.active_view.invalidate
    end

    def deactivate(view)
      # puts 'deactivate'
      Sketchup.active_model.shadow_info.remove_observer(@observer)
      view.invalidate
    end
    
    def draw(view)
      model = Sketchup.active_model
      shadowinfo = model.shadow_info 
      @text = shadowinfo["ShadowTime"].to_s
      view.draw_text([30, 30], @text, {size: 18, color: [80, 80, 80]})
    end
    
  end # tool
end

SW::ShadowTool.new
nil

I’m not sure I understand what you want to achieve? Perhaps you can try to explain in other words…
First of all, the first line of the above snippet is missing:

module SW

Here is the corrected and expanded version of the code snippet.
It writes the hours and minutes to the Ruby Console and the values calculated from these values too.

module SW
 class MyShadowInfoObserver < Sketchup::ShadowInfoObserver
    def onShadowInfoChanged(shadow_info, type)
      # puts "onShadowInfoChanged: #{type}"
      Sketchup.active_model.active_view.invalidate
    end
  end

  class ShadowTool
    def initialize()
      @model = Sketchup.active_model
      @shadowinfo = @model.shadow_info
      @model.select_tool(self)
    end
     
    def activate
      # puts 'activate'
      # Attach the observer.
      @observer = MyShadowInfoObserver.new
      @model.shadow_info.add_observer(@observer)
      @model.active_view.invalidate
    end

    def deactivate(view)
      # puts 'deactivate'
      # Remove the observer.
      @model.shadow_info.remove_observer(@observer)
      view.invalidate
    end
    
    def draw(view)
      @text = @shadowinfo["ShadowTime"].to_s
      view.draw_text([30, 30], @text, {size: 18, color: [80, 80, 80]})
      handle_shadowinfo_hour_min
    end
    
    def handle_shadowinfo_hour_min
      @shadowinfo_hour = @shadowinfo["ShadowTime"].hour
      puts "shadowinfo_hour: #{@shadowinfo_hour}"
      @calculated_hour = @shadowinfo_hour - 8
      puts "calculated_hour: #{@calculated_hour}"
      @shadowinfo_min = @shadowinfo["ShadowTime"].min
      puts "shadowinfo_min: #{@shadowinfo_min}"
      @calculated_min = @shadowinfo_min - 3
      puts "calculated_min: #{@calculated_min}"
      # etc. you can do somthing with the instace variables
    end
    
  end # tool
end

SW::ShadowTool.new
1 Like

In addition to dezmo’s excellent improvements:

(This is a software engineering principle that is valid for any programming API, not only SketchUp)

An API method like Sketchup.active_model means “of all the models, give me a reference to the one which is currently active”.
This sentence implies that when you call this method several times, there is no guarantee that every time the same is still the active model. The fact that you “see” that SketchUp has only one model (on Windows) is no proof that there cannot be more models, in fact the way that the API is designed, SketchUp developers could add support for multiple models at any time, and then suddenly such code breaks.

For this reason, whenever you want to use the “same object”, get an object reference once and save it in a variable (here @model). This principle can be applied to many other types of objects, like selected entities (a user can change selection and then the selected entities are not the same anymore), materials etc.


In other words: “Don’t repeat yourself
When two lines of code use a chain of same method calls:

Sketchup.active_model.shadow_info.add_observer(@observer)
Sketchup.active_model.active_view.invalidate

you can simplify it to:

model = Sketchup.active_model
model.shadow_info.add_observer(@observer)
model.active_view.invalidate
3 Likes

Also, add comments to your code explaining what is happening.

WE do not know what YOU want to do with the time data. As a programmer is is up to YOU to decide.

As I explained in your other topic thread

So you need to modify these lines of code …

      @text = shadowinfo["ShadowTime"].to_s
      view.draw_text([30, 30], @text, {size: 18, color: [80, 80, 80]})

… so that you have available a direct reference to the Time object.

Also, the time text is not used outside the draw() callback method, so it should be a local text reference and not an @text instance reference.

      time = shadowinfo["ShadowTime"]
      text = time.to_s
      view.draw_text([30, 30], text, {size: 18, color: [80, 80, 80]})

Now you can call the #hour, #day, (and other methods) on the time object.

What you do with the data from the time object is your decision.

1 Like

This is the code for plane rotation, and I would like to use the @Calculated_hour variable above to control plane rotation. How the two codes fit together (how to call the @Calculated_hour variable outside of the module).

  ent = mod.entities # All entities in model
  sel = mod.selection # Current selection
  def_list = mod.definitions
  path = Sketchup.find_support_file "16.skp","Components"
  comp_def = def_list.load path
  time0 = Time.utc(2020,1,1,9,0,0) 
  time1 = Time.utc(2020,1,1,@calculated_hour,0,0) 
    t=time1.hour-time0.hour
    ent.each do |entity|
      if entity.typename == "ComponentInstance"
       entity.erase!
      end
    end
    inst1 = ent.add_instance comp_def,[0,0,0]
    tr = Geom::Transformation.rotation [0,0,0],[1,0,0],5*t.degrees
    ent.transform_entities tr,inst1
    UI.messagebox("#{5*t}"+"度")

I’m still not sure what you want to achive… but I can also imagine something like this without using observer:

module SW
  class ShadowTool
  
    def initialize
      @model = Sketchup.active_model
      @shadowinfo = @model.shadow_info
      @instance_added = false
      @model.select_tool(self)
      @model.start_operation('Add & Rotate test')
    end
     
    def activate
      @model.active_view.invalidate
    end

    def deactivate(view)
      @model.commit_operation
      view.invalidate
    end
    
    def draw(view)
      time = @shadowinfo["ShadowTime"]
      text = time.to_s
      view.draw_text([30, 30], text, {size: 18, color: [80, 80, 80]})
      unless @shadowinfo_hour == @shadowinfo["ShadowTime"].hour
        handle_shadowinfo_hour
      end
      view.invalidate
    end
    
    def handle_shadowinfo_hour
      @shadowinfo_hour = @shadowinfo["ShadowTime"].hour
      @calculated_hour = @shadowinfo_hour - 8
      @calculated_hour += 24 if @calculated_hour < 0
      ent = @model.entities # All entities in model
      unless @instance_added 
        ent.each do |entity|
          # if entity.typename == "ComponentInstance"
          if entity.is_a?(Sketchup::ComponentInstance)
           entity.erase!
          end
        end
        def_list = @model.definitions
        path = Sketchup.find_support_file "16.skp","Components"
        comp_def = def_list.load path
        @inst1 = ent.add_instance comp_def,[0,0,0]
        @instance_added = true
      end
      time0 = Time.utc(2020,1,1,9,0,0) 
      time1 = Time.utc(2020,1,1,@calculated_hour,0,0) 
      t=time1.hour-time0.hour
      tr = Geom::Transformation.rotation [0,0,0],[1,0,0],5*t.degrees
      ent.transform_entities tr,@inst1
      puts "#{5*t} 度"
      # UI.messagebox("#{5*t} 度")
    end
    
  end # tool
end

SW::ShadowTool.new

test_rot_sw

Maybe you can explain what you decide to do in Chinese briefly?

Thank you. My purpose is to control the rotation of the plane on the time axis. Your solution has done it。But maybe my computer is so bad that I can’t close the program every time it’s finished. The whole program is stuck

I have changed to a better computer to run the code, but there is still a phenomenon that the code cannot be closed after running. Is there such a phenomenon on your computer?

No.
Most probably You need to optimize the code, it’s just a quick one…

Hello, I changed a few computers and the same thing happened again. I just clicked Close button directly. What code did you use to end the program? As for the optimization problem you mentioned, so far I have only thought of this one way, and I will finish it with your help. Do you have any new ideas about time axis control plane rotation?

As most of the tool, you have select an other tool to close… in this case hit the space bar or click - for example - on a Rectangle tool icon.
And yes, if I want to close SU during this code snippet is running, this will hang SU. I don’t know why.
I didn’t look deeper. I assumed you will have more time to do it…

You mean you will use a code written by sWilliams, asking someone to make improvement then asking someone to to help to optimize. Neat! :slight_smile:

This sentence cannot be interpreted for me.
I have no idea what does it mean at all.

I apologize for my lazy behavior and thank you for your help. I don’t want all the key work to be done by others. I have thought for a long time before asking you, but I have no clue. I don’t have any information about Ruby in Sketahup, I can go to the forum to ask for help when I have difficulty problem .I’ll continue to work hard, try to solve the problem by myself, thank you again for your patience solutions, thank each to help patient with my friends, thank you!(Translation software always ambiguities my words)

I found that when the time axis stops, the program is also running. It will keep taking the time of the slider, but because of the existence of these lines of code, there is no output result.

I also found that clicking the middle mouse button before closing the program can interrupt the program.
Compared to your final code, the code that initially only displays the time on the screen does not run when the timeline is stopped. I tried to combine the original code with the rotation function code, but I failed.
As an expert on Ruby language in Sketchup, how did you learn it in the first place? Can you give me some experience? Thank you!

The #suspend method is called by SketchUp when the tool temporarily becomes inactive because another tool has been activated. This typically happens when a viewing tool is activated, such as when orbit is active due to the middle mouse button.

This method is automatically called within your Tool. You can write your code “inside” this method to be able to react as you desired…
Even you can design what will happen if the orbit tool “handling back the execution” to your tool with the #resume method.
_


_

I’m very far from that. I’m just an amateur curious person trying to observe the mysteries of Ruby in his limited spare time. I’m probably more advanced in learning than you are, but that’s it. Programming is not my profession.
Unfortunately for me, there are no background studies. I don’t understand or know a lot of things. I’m just trying to understand, for example, from what others are asking and answering here on the forum.

I started dealing with Ruby about 10 years ago. First, I studied the Ruby API documentation in depth:
https://ruby.sketchup.com/index.html
I mean, you have to read each method back and forth several times in detail. Then again.
Honestly, this website should always be open when you write a program.

In addition, since the SU Ruby API only contains SU special procedures, you need to know the general Ruby. The current Ruby version in SU2021 is https://ruby-doc.org/core-2.7.1/index.html (If I remember right in SU2018 the Ruby version is 2.2.4 and in SU2019 is 2.5.1)

Then I studied a lot of plugins (extensions) that others wrote. For example, you can start here with the “official” example: https://github.com/SketchUp/sketchup-ruby-api-tutorials

But there are many good examples e.g. here: https://sketchucation.com/pluginstore and there: https://extensions.sketchup.com/

Dan wrote a very good summary here: https://forums.sketchup.com/t/ruby-learning-resources-wikilists/22861

2 Likes