Interaction with objects for simulation
-
Good evening,
I'm new to plugin programming, though I've been using Sketchup for several years on an occasional basis and have programming experience in other languages - as an engineer, not a dedicated programmer. I am trying to write a simulation for bicycling, but can't see how to make it respond to controls like Sketchy Physics does. Can anyone give me ideas on how to go about it. I've tried the animation command in the API, and just drawing/redrawing the model after calculating each frame and neither does what I want. The model will have to respond to changes in hill slope, rider power, winds and braking. The reason I prefer not to use SP is that I want it to run fast enough to have smooth movement (I'm on an XP machine). Any help would be appreciated.
Thank you and Happy Holidays,
Nick -
Anybody? I'm kind of anxious to find a solution.
Thanks.
Nick -
SketchUp has NO understanding of physics built into its core. You will have to program that yourself, or use an existing physics library and then tie it into SketchUp - which is what Sketchyphysics does. It uses an existing C or C# (or something) physics library.
So you have to write the physics yourself, or borrow them. Not for the faint of heart in my opinion.
-
@chris fullmer said:
SketchUp has NO understanding of physics built into its core. You will have to program that yourself, or use an existing physics library and then tie it into SketchUp - which is what Sketchyphysics does. It uses an existing C or C# (or something) physics library.
So you have to write the physics yourself, or borrow them. Not for the faint of heart in my opinion.
Chris,
Thanks for the reply. The physics part is easy for me, I've been doing that professionally for 30-some years and I'm making a simplified model of the physics. What I don't get is how to animate Sketchup interactively (like SketchyPhysics does). I've only seen examples of scripted or key-frame animations, what I want to do is have the animation respond to changes that occur in each frame. Looked at the ruby source for Sketchy Physics and couldn't see how they do it there. Was wondering if anyone else has done this and can explain it or point me to a good example.
Thanks.
Nick -
Haven't done anything like that, but have you looked at the
Animation
class? http://code.google.com/apis/sketchup/docs/ourdoc/animation.htmlAnd
Group.move!
&ComponentInstance.move!
- moves a group/component instnace without adding the event to the undo stack. -
@thomthom said:
Haven't done anything like that, but have you looked at the
Animation
class? http://code.google.com/apis/sketchup/docs/ourdoc/animation.htmlAnd
Group.move!
&ComponentInstance.move!
- moves a group/component instnace without adding the event to the undo stack.Thanks for the response thomthom, that's actually where I started with guidance from Martin Rhinehart's excellent tutorial series. However, as he explains, you can't use that for interactive animation because Sketchup computes the numerical stuff and graphic stuff in separate threads. Don't want to get too deep in the explanation here, but the end result is that the image skips from the start of the animation to the end without showing any of the scenes in between. Martin doesn't know any way around that, I'm trying to find one. Chris Phillips must have found a way because Sketchy Physics does it, not sure if anyone else has.
Thanks again,
Nick -
@nickinwv said:
Don't want to get too deep in the explanation here, but the end result is that the image skips from the start of the animation to the end without showing any of the scenes in between.
It does? That's very odd. I thought that was the very purpose of that class to avoid that...
It's the kind of behaviour I'd expect from a loop - perhaps a timer loop.
You hadn't wrapped things up in a
start_operation
, did you?So what about a timer loop?
Or... call
view.refresh
- which should force a refresh. -
I'm pretty sure its the animation class. That lets you animate things - objects in the model - while the model is still active. Its how Dynamic components do it as well I think.
-
Nick, do you have a bare bones example of an Animation where only the start and end displays in the viewport? Maybe we can spot anything that's blocking the middle bit?
-
If you wish to do things when the frame changes I think you'll need to use "the little-known" FrameChangeObserver
Google posted a full length example in the official Sketchup Blog (last year or more.)
Todd Burch, of Smustard, cleaned up the code, and posted the "cleaner" version at Smustard.com.
see this post for more links: http://forums.sketchucation.com/viewtopic.php?f=180&t=29163&p=254729&hilit=framechangeobserver#p254729
-
Good evening,
Thank you for your replies, sorry I'm so late in responding - I've been preoccupied with other things for a month.-
Dan, I wasn't able to comprehend the frameobserver that you referred to. Would it be possible to post a simple example?
-
Here's a simple example of what I've tried with the "animation" command that doesn't work. It uses Martin Rhinehart's TransformableCI. My example is just the last few lines....
/r/anim1.rb - sample Animation
require 'sketchup'
transformable_ci.rb - a ComponentInstance with easy, transform!-based transformations
from Edges to Rubies - The Complete SketchUp Tutorial
Copyright 2010, Martin Rinehart
require 'sketchup'
$radians_per_degree = Math::PI/180.0
class TransformableCI
=begin
A TransformableCI can do move, rotate and scale transformations. The
developer creates a TransformableCI from a ComponentInstance and then
applies move(), rotate() and/or scale() methods directly, without needing
Transformation objects or methods.Internally, the transformations are performed with the
ComponentInstance.transform!() method, recording changes on the undo stack
and redrawing immediately. (Use a MovableCI if you do not want to record
undo changes and view changes immediately .)This is documented in the tutorial's Chapter 16.
=endattr_reader :inst, :trans def initialize( inst ) @inst = inst @trans = inst.transformation.to_a() end # of initialize def move( *args ) # Point3d or Vector3d or [r,g,b] arg = args[0] if args.length == 3 vec = Geom::Vector3d.new( args[0], args[1], args[2] ) xform = Geom::Transformation.new( vec ) @inst.transform!( xform ) elsif arg.is_a?( Array ) vec = Geom::Vector3d.new( args[0] ) xform = Geom::Transformation.new( vec ) @inst.transform!( xform ) elsif arg.is_a?( Geom::Vector3d ) xform = Geom::Transformation.new( args[0] ) @inst.transform!( xform ) elsif arg.is_a?( Geom::Point3d ) xform = inst.transformation().to_a() xform[12] = arg[0]; xform[13] = arg[1]; xform[14] = arg[2] @inst.transformation= xform else raise "move cannot handle " + args[0].to_s() end end # of move() def rotate( point, plane_or_axis, degrees ) axis = make_axis(plane_or_axis) degrees *= $radians_per_degree xform = Geom::Transformation.rotation( point, axis, degrees ) @inst.transform!( xform ) end # of rotate() def scale( *args ) case args.length when 1 then xform = Geom::Transformation.scaling( args[0] ) when 2 then xform = Geom::Transformation.scaling( args[0], args[1] ) when 3 then xform = Geom::Transformation.scaling( args[0], args[1], args[2] ) when 4 then xform = Geom::Transformation.scaling( args[0], args[1], args[2], args[3] ) end @inst.transform!( xform ) end # of scale()
support functions
def make_axis( plane_or_axis ) if plane_or_axis.is_a?( String ) case plane_or_axis when 'rg' then axis = [0,0,1] when 'rb' then axis = [0,1,0] when 'gb' then axis = [1,0,0] else raise "Plane must be 'rg', 'rb', 'gb' or an axis." end else axis = plane_or_axis end return axis end # of make_axis() def inspect() return '#<Transformable' + @inst.to_s() + '>' end # of inspect()
end # of class MovableCI
#================= Beginning of test code ===================
$mvbl = TransformableCI.new( Sketchup.active_model().selection()[0] )for $i in [1..10] do
$mvbl.move( Geom::Vector3d.new(1, 0, 0) )
Sketchup.active_model().active_view().invalidate()
end
#================= endf test code =========================== -
-
1) Please enclose all code within [ code ] ... [ /code ] bbCode tags. You can edit your message... highlite all the code and click the
[**Code**]
button, on the edit post toolbar. (Those buttons are there to help you be a better poster!)2) It is not necessary to repost Martin's code unless you modified it in some way (and you should have renamed it, and wrapped it within your own toplevel namespace, if you did.) Martin ALSO should have done this (and I "bitched" at him many times, but he decided to use the global ObjectSpace as his own, anyway)
3) The simple example is posted in the Google Sketchup API Blog:
http://sketchupapi.blogspot.com/2009/07/dynamic-components-that-react-to-scene.html4) It is not formmatted correctly (if you cut and paste it from the webpage,) so Todd Burch reformatted it, and posted it here:
http://www.smustard.com/forum/viewtopic.php?f=9&t=25IF you use it, RENAME the class "FrameChangeObserver" to something else, WITHIN your own toplevel namespace.
Ex:module WVnick # <<-- unique toplevel namespace module AnimTest class FrameSpy # modified callback methods # from the Google example end # your AnimTest code that uses # an instance of your FrameSpy class # other methods, etc. end # module end # module
-
It does not work because (likely,) when the code loads, the part at the bottom runs (or is evaluated,) and there is probably no selection, so nothing happens.
You need to write event driven method code, that happens when the user chooses a menu item, or using a SelectionObserver subclass (beware of bugs in this class,) when the user changes the selection, or when the user presses a toolbar button, or using some other observer subclass, when something else happens.
You should be defining your code within your namespace. (And separating your various projects with sub-namespaces.)
When you do, you do NOT use global variables. (They are not needed and clutter up everyone's else global environment.)
Use local constants, module/class @@varnames, instance @varnames, or local varnames, WITHIN your namespaces (modules and classes.)Please read some other free books (besides just Martin's tutorial. His work is heavily influenced by Java, and IMHO is not the Ruby way.)
The link in my signature line will lead to a bunch of info (dowmloadable books, etc.) I highly recommend read the old 'Pick-Axe' "Programming Ruby" even though it was written circa v1.6.x, it's still valid (except for the object reference.)
-
Dan,
Thanks for the quick, instructive and helpful reply. I have no formal training in any computer language and thus have been struggling with Ruby. Just when I'm thinking I've learned enough to get by I come across something that I need to know and that may take some time to understand. Given that this is strictly a hobby project right now that time is limited. I've got some questions - would it be better to correspond with you privately?Main question is "Do I need SU Pro to use dynamic components?" I don't currently have it, or money to buy it.
I'm trying the FrameChangeObserver to see if that works any better.
btw The code i posted ran without errors, it just didn't do what I wanted it to. It moved the box 1 step and not 100.
-
@nickinwv said:
btw The code i posted ran without errors, it just didn't do what I wanted it to. It moved the box 1 step and not 100.
It ran only once, because there is only ONE object in the Array as you wrote it:
for i in *Array_Literal_with_1_element* do
...
end
It happens that the single element is a
Range
object, but it does not matter what kind of object the elements are.To USE the Range as the loop control, you need to use:
for i in 1..10
...
end
or
steps = Array.new(10)
[nil, nil, nil, nil, nil, nil, nil, nil, nil, nil]
then
for i in steps
...
end
or simplier:
10.times do |i|
...
end
NOTE: Be careful with the
do
keyword ! It is required if the loop statement is all on a single line. But if your iteration is a block over multiple lines, you must omit it, or the interpreter will not parse it correctly and give you and "unexpected end" or an "end expected" error. (Basically it cannot match up the "end
"s with the correct blocks.)The times iterator method needs either a
do
..end
, or{
...}
.There is also the
upto
iterator method:
start = 1 stop = 10 start.upto(stop) do |i|
...
end
also can use literals:
1.upto(10) do |i|
...
end
-
@nickinwv said:
"Do I need SU Pro to use dynamic components?"
Not to use.
You can can insert them (from say the 3D Warehouse, or the samples installed with Sketchup.)
You can copy them, scale them, move them, etc.You can change their options.
You can interact with them, via the Click Interact tool. (You'd need to turn on the DC toolbar.)
Pro is only required if you wish to create or edit DCs via the app's GUI.
Setting their options is somewhat involved (and there's a whole separate forum here for discussing DCs.)Advice...
- Learn Standard Ruby first. (The Sketchup API is just 3 modules, with encapsulated classes, that extends Ruby.)
- Then start with simple plugins and macros first. (Learn to crawl, before you try to walk, and before attempting to run.)
- Study what others have done first. (Stand on the shoulders of giants. Pay attention to the work of the most prolific coders in the Code Snippets index, and the Plugins Index (Plugins Forum).)
Animation is an advanced catagory. Make sure you visit the Code Snippets index. (Jim Foltz posted an animation example I believe.)
Advertisement