Using an observer to delete a screen note
-
Yes, I think so. When SU renders it animations (either a video format like .avi or as jpg stills), it does not run your observer like I think you were hoping it would do. So in my mind there are a few ways to tackle this, but all essentially do the same thing. Add a note for each scene.
If I were to write it, I think I would try to set it up so that the user only had to set up their desired scenes. Then I would write a custom animation jpg exporter. It would work so that it reads how many seconds per scene the user has set up. Then it would ask how many frames per second the user wants. It would then setup a camera for the first frame, and it would have to change the shadow info from frame to frame also, and then it would add the note. Then once it has the view set, the shadows set and the note added, it would move on to the next frame. And start over setting all that info again.
Setting the camera for each frame is actually easy. The API lets you get that info already. You already know how to add and remove and update the screen text. so that would be easy enough. the hardest part would be figuring out the shadow info from frame to frame. That would require getting the starting scene's shadow info and the next scene's shadow info, then divide the time transition up over how many frames there between the scenes, then change the model shadow info to amtch what you have calculated. Its not impossible at all, but it would make my head hurt I'm sure.
Then its just a matter of exporting the images, which is fairly straightfoward.
That is how (I think) I would tackle it if I really wanted to do a thorough job.
Chris
-
Hmm. As always, thanks for the detailed thoughts.
I think I'll attack this from the angle of putting a screen note on each scene. I think this will be the cleanest approach for my application, as I have not been using transition times or scene delays. This will, I think, eliminate the issue of needing to retrieve the next scenes shadow info during the rendering process.
I do like the little snippet we've developed here. And, if I may say so, I think it's a cleaner approach than the [TBD] Time plugin on smustard (no offense to the author; I've appreciated and studied the plugin). The reason I like this approach more is that is updates instantaneously instead of at one second intervals. It also doesn't update until there is actually a change in the shadow info. If I add a on/off switch, and a few options to choose the format of the note, it will be a fully functioning utility.
I am running into a problem with this script, though. When I start SketchUp from scratch, in the first model I work on, the script works great. However, if I open an existing model, or create a new model while SketchUp is running, the script does not work in either case. Is there any obvious reason why this would be the case?
-
The ShadowInfo is part of the model, so when you open an existing model or start a new model, you need to attach your observer to the new ShadowInfo.
You can automate this by using an AppObserver to notify the script when a model is opened or created, and attach the ShadowInfoObserver at that time.
Note on Macs, you can have more than a single Model open. Not so on Windows where there is always only a single Model available.
-
Wouldn't this be a perfect job for the FrameChangeObserver ??
-
I don't think the FrameChangeObserver works either when exporting an animation.
-
That's interesting. I've never noticed that observer (I tend to stay away form them after hearing all of Thom's problems with them). That seems like it would be a great one to use here if only it worked during animation export.
Chris
-
Hello,
it's a pity that I read this post just now, when I finished my little plugin using the shadowinfo_observer to achieve exactly what danbig described. Display the Shadowtime for different shading situations.
My Plugin works perfectly. I was proud of it until I tried an animation export
Is this problem solved by now?
It seems not very sophisticated to me, to write notes on every page which are hidden when another page is displayed...
is there no other way ?Matthias
-
@chris fullmer said:
That's interesting. I've never noticed that [FrameChangeObserver observer] ...
Yes that is because is one of the API missing class boo-boos. It IS mentioned within the API, in passing.
Pages.add_frame_change_observer
Pages.remove_frame_change_observerIt was featured (documented) in the Sketchup API BlogSpot:
Dynamic Components that react to scene (aka page) changes('scenes.rb') Code properly formatted (by Todd Burch) at:
http://www.smustard.com/forum/viewtopic.php?f=9&t=25It basically only has one event callback:
frameChange( fromPage, toPage, percent_done ),
the intialize method, plus any custom method(s) you need inside to keep your code readable and organized.@chris fullmer said:
That seems like it would be a great one to use here if only it worked during animation export.
I guess the animation export is a manual 'built-in' C++ side plugin? And as such all Ruby processing stops? (..similar to what happens when the App Modal 'Preferences' dialog opens.)
.. or is it a special way of running an Animation object? -
I, for one, have decided that I have a knack for attempting the most complicated tasks as my "test project" in a new area.
Matthias: I'm sorry that you got so far before realizing the issue with the shadowinfo_observer. This is a lesson that I've learned too many times: test code at the smallest possible snippets, and verify it's functionality individually before putting it all together into a larger code block.
-
@danbig said:
I, for one, have decided that I have a knack for attempting the most complicated tasks as my "test project" in a new area.
danbig,
It's dawning on me that this might be true for me tooI try the approach with one note per page. Hopefully this will be more successful
Matthias
-
It really is not all that difficult to make your script export a series of jpgs that can then turned into a movie (its more dificult for the user though ). But if you feel that is an option, you could try writing your own export method and then you can update the screen text for each frame easily that way.
Chris
-
@chris fullmer said:
It really is not all that difficult to make your script export a series of jpgs
ChrisChris,
can I also export directly into an avi file somehow ?
To make it a bit easier for the user ...Matthias
-
@chris fullmer said:
It really is not all that difficult to make your script export a series of jpgs that can then turned into a movie (its more dificult for the user though ). But if you feel that is an option, you could try writing your own export method and then you can update the screen text for each frame easily that way.
Chris
"Difficult" being a relative term here.
-
Oh I agree. But really exporting an image is not that hard. For me, the hardest part BY FAR was getting it recognize the location I was trying to save it. I really struggle with ruby and files/paths. Its is remarkably painful. But you might be able to use the save dialog box and let the user supply the path easier than hard coding like I think I did.
Chris
-
@pvbuero said:
@chris fullmer said:
It really is not all that difficult to make your script export a series of jpgs
can I also export directly into an avi file somehow ?
To make it a bit easier for the userA thot...
.. I wonder if MS MediaPlayer or MovieMaker or PhotoStory could be run in batch mode, to stitch a collection of image files (in a folder,) into a AVI, by calling the exe with command line parameters.
Many of the old SlideShow executables would do similar for a slideshow. (Which is now built into XP.)
If not, perhaps out there somewhere, is a command line "AVI maker" executable that would do the job.
-
Call me unambitious, but I'm back to the strategy of placing the screen note on each scene, and hiding it on all the others. It would work for my workflow, and it seems digestible for me.
I could then use the standard "export to animation" function to either jpg or avi, and (I think) it would come out as expected.
-
I really don't blame you, that is a sensible way to do it I think.
@Dan R., there is a free command line encoder called mencoder that will take a series of still images and turn it into any video format. It is Win, Mac, Linus capable too. I have thought to write a ruby to test out its capabilities half a dozeon times, and jhust never fully sat down and done it. If anyone ever does look at it, it would be awesomw if they posted their code snippet that interacts with that command line encoder.
Chris
-
@danbig said:
Call me unambitious, but I'm back to the strategy of placing the screen note on each scene, and hiding it on all the others. It would work for my workflow, and it seems digestible for me.
I could then use the standard "export to animation" function to either jpg or avi, and (I think) it would come out as expected.I made it that way and it works:
shadowtime_on_screen = [sunrise..sunset] for hour in sunrise..sunset time = Time.gm(2010,month,day,hour,minute,00) shadowinfo["ShadowTime"]= time shadowinfo["DisplayShadows"]= true shadowtime_on_screen[hour] = Sketchup.active_model.add_note (shadInf.shadowtimetxt,0.1,0.2) shadowtime_on_screen[hour].hidden = true end for hour in sunrise..sunset time = Time.gm(2010,month,day,hour,minute,00) shadowinfo["ShadowTime"]= time shadowtime_on_screen[hour].hidden = false page = Sketchup.active_model.pages.add time.strftime("%d %b %H;%M Uhr") shadowtime_on_screen[hour].hidden = true page.delay_time= 0 page.transition_time= 3 end
First I create all the notes on the screen and hide them, then I unhide one by one and create the corresponding pages.
My next step will be to allow steps which are different from one hour... and as I learnd here I have to deal with jquery (sigh) to enter the start and the end time...
Matthias
-
@unknownuser said:
I made it that way and it works:
shadowtime_on_screen = [sunrise..sunset] for hour in sunrise..sunset time = Time.gm(2010,month,day,hour,minute,00) shadowinfo["ShadowTime"]= time shadowinfo["DisplayShadows"]= true shadowtime_on_screen[hour] = Sketchup.active_model.add_note (shadInf.shadowtimetxt,0.1,0.2) shadowtime_on_screen[hour].hidden = true end for hour in sunrise..sunset time = Time.gm(2010,month,day,hour,minute,00) shadowinfo["ShadowTime"]= time shadowtime_on_screen[hour].hidden = false page = Sketchup.active_model.pages.add time.strftime("%d %b %H;%M Uhr") shadowtime_on_screen[hour].hidden = true page.delay_time= 0 page.transition_time= 3 end
Is this code ready to execute through the console or webconsole? I get an "undefined local variable" error for sunrise when I evaluate it.
What I'd like to do is merge your code, above, with this script (Chris essentially wrote this, and I have simply tweeked it to suit my needs):
I'm not as concerned with sunrise and sunset, if those values are used in your script. I prefer to set the start and stop times myself, and create the screen notes associated with the times and intervals I have chosen.model = Sketchup.active_model si = model.shadow_info ps = model.pages si["DisplayShadows"]= true #set the year, month, day, and time of first shading scene as follows; (year,month,day,hour,min,sec) t = Time.gm(2010,"dec",1,9,0,0).to_i #set number of days to repeat 31.times do |day| si["ShadowTime_time_t"]=t page = ps.add #set scenes to save camera position (true or false) status = page.use_camera=false #set scene transition time to 0 from PM of previous day to AM of next day page.transition_time = 0.0 #set hours from first scene for day until second scene for the same day (sec*min*hours) t= t+(60 * 60 * 6) si["ShadowTime_time_t"]=t page = ps.add status = page.use_camera=false page.transition_time = -1 #set hours from second scene for day, until first scene of next day (sec*min*hours) t= t+(60 * 60 * 18) end
-
@danbig said:
Is this code ready to execute through the console or webconsole?
NO.. because it is NOT wrapped in a module. When you run code like this in the console (or webconsole,) it runs INSIDE class Object. EVERYTHING in Ruby is a subclass of class Object, and inherits all of it's methods, constants and most important, it's local variables. (Say "Reference clashes, boys and girls!")
When you declare a sunrise var (or any other var using a common word like start and stop,) in the console (ie, in Object,) you run the risk of clashing (overwriting,) a var of the same name, by another script (if it is also not module wrapped.)@danbig said:
I get an "undefined local variable" error for sunrise when I evaluate it.
You'd get the same forsunset
.
It's obviously a snippet from a larger script, where these local vars are predefined, most likely grabbing them from the model'sShadowInfo
settings.Stay within YOUR namespace, YOUR namespace is your friend. It protects your code from the rest of the world, and visa versa.
Don't have a namespace?
Let's invent one, how about Danbig ?? (..you can chose another, but for example's sake..)In EACH and EVERYONE of your Ruby script files, all your code will be wrapped inside a Danbig module block, like:
` module Danbigcode goes here.
end # Danbig`
Then for each separate plugin, you create a submodule inside YOUR Danbig namespace, so that YOUR plugins do not clash with each other. Like:module Danbig module ShadowAnim # # code goes here. # end # ShadowAnim end # Danbig
The beauty is that module and class definitions can span across multiple files (but method defs cannot, a method def will totally redefine any method that is already defined***.)
*** This is why you should NOT define methods in the console (inside Object,) as they will often end up redefining someone else's method, or worse (and it's happened,) one of the important Ruby methods of Object or Kernel [which is mixed-into Object,] causing problems for EVERYONE.)
Anyhow.. you'd refer to your animation start method as:
Danbig::ShadowAnim.start
using the**::**
scope operator.Now you don't need $global vars to share settings or info among your plugins. Just create either CONSTANTS, @@class vars or @attributes inside the Danbig module.
Constants can be refered to (in individual plugin submodules,) asDanbig::CONSTANTNAME
For @@ or @ vars you'd make getter and setter methods inside Danbig. It's easy to make @vars with the attr_accessor method.
` module Danbigsetup common @vars for ALL my plugins
attr_accessor(:time,:starttime,:endtime,:danbigmenu) #etc.
endcreates attribute vars:
@time @starttime @endtime @danbigmenuand methods:
Danbig.time Danbig.starttime Danbig.endtime Danbig.danbigmenu Danbig.time= Danbig.starttime= Danbig.endtime= Danbig.danbigmenu=After
attr_accessorthe @vars will all be
nil, but you can (below that in code,) set them to an initial value inside the
DanbigOh! There I go again.. ranting on Namespaces. For more info from some of my other rants...
http://forums.sketchucation.com/viewtopic.php?f=180&t=24356&p=255792#p254458
and beginning post 4 at:
http://groups.google.com/group/sketchupruby/browse_frm/thread/4f22a3ac2c3a8603/4d538051fc7cbf75?lnk=gst&q=File+spanning#4d538051fc7cbf75
Advertisement