tag:blogger.com,1999:blog-63136321189770555542023-10-24T15:58:50.755-07:00Google SketchUp API BlogThe latest news from the SketchUp API team.Unknownnoreply@blogger.comBlogger28125tag:blogger.com,1999:blog-6313632118977055554.post-74529415827010625452012-04-26T06:21:00.000-07:002012-04-26T06:21:02.348-07:00A new home for SketchUp<span class="byline-author">Posted by Scott Lininger, SketchUp API Team</span><br />
<br />
As has been <a href="http://sketchupdate.blogspot.com/2012/04/new-home-for-sketchup.html">announced on the official SketchUp blog</a>, SketchUp is moving to a new home: Trimble.<br />
<br />
I'm here to assure you that Trimble is committed to preserving the vitality of SketchUp’s developer community. You guys have made SketchUp great, and we have every expectation that opportunities will grow for you as we continue to develop SketchUp at Trimble.<br />
<br />
It's often said that people building plugins have more to do with SketchUp's success than anyone else, and I couldn't agree more. In the years I've been at Google, the most rewarding part of my job has been interacting with all of you and seeing the amazing features you've created.<br />
<br />
In the short term, this change will have zero impact on your plugins and businesses. Everything will work exactly as it does today. In the longer term, I expect it to improve the state of our APIs and developer resources. Trimble wants to invest strongly in SketchUp as a platform, and advance its mission of "3D for Everyone."<br />
<br />
I'm very excited to be joining in this next stage of SketchUp's journey. See you all on the other side!Unknownnoreply@blogger.com7tag:blogger.com,1999:blog-6313632118977055554.post-17780083579546507102011-12-01T17:16:00.000-08:002011-12-01T17:16:22.218-08:00RBZs in SketchUp 8M2: Distribute Your Plugin as One File!Posted by Scott Lininger, SketchUp Engineer<br />
<br />
In the latest and greatest SketchUp 8 maintenance release, M2, we added an easier way for users to install your Ruby scripts. In the past, folks had to manually copy your .rb files into their Plugins folder, or you would have to write a custom installer to do it for them.<br />
<br />
Now there's a button in SketchUp that'll make this easier. It's found under Preferences > Extensions > Install Extension. Clicking this button will bring up a file browser window where your users can select any .RBZ file from their harddrive, and SketchUp will put them in the right spot plus load them up. No more fumbling around looking for the Plugins folder. No need to restart SketchUp to see your shiny plugin.<br />
<br />
<b>But what is an RBZ file?<br />
<br />
And how do I make one?</b><br />
<br />
It's simple. RBZ files are nothing more than ZIP files. You can use your favorite ZIP tool (I like 7-zip on Windows) to create the archive, then rename it to have a .RBZ extension. Anything you put inside of this RBZ file, including files and subfolders, will be unpacked into the user's Plugins folder. That's it!<br />
<br />
So let's say you had a plugin with the following files in it:<br />
<br />
<ul><li>SketchUp 8/Plugins/helloworld.rb<br />
<li>SketchUp 8/Plugins/helloworld_files/hello.html<br />
<li>SketchUp 8/Plugins/helloworld_files/smiley.png</ul>You would create a ZIP file containing the above files. With my ZIP tool, I simply select the helloworld.rb and helloworld_files folder, right click on them, and select "Create ZIP". The resulting file is called helloworld.zip. Right click > rename to helloworld.rbz, and you're golden. HOWEVER, before I do this, it would be even better to change my simple ruby script into a <a href="http://code.google.com/apis/sketchup/docs/ourdoc/sketchupextension.html">SketchupExtension</a>. That way my users will see your Extension added to the Extensions panel when they do the install, and in the future it's easy for them to turn it off.<br />
<br />
Happy distributing!Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-6313632118977055554.post-79389954654431026462011-08-11T09:42:00.000-07:002011-08-11T10:21:11.559-07:00Hidden Corners of SketchUp's Ruby API: Transforming Vertices<span class="byline-author">Posted by Scott Lininger, SketchUp team<div>
<br /></div><div>There are many capabilities of the SketchUp Ruby API that aren't easy to discover. With over 1000 methods, it's not surprising! In this semi-regular blog series, I'll be pointing out my favorites.</div><div>
<br /></div><div>Here's one: <b>transforming individual vertices</b>.</div><div>
<br /></div><div>Let's say I've drawn a 2x2 grid of squares on the ground...</div><div>
<br /></div><code>ents = Sketchup.active_model.entities
<br />square1 = ents.add_face [0,0,0], [10,0,0], [10,10,0], [0,10,0]
<br />square2 = ents.add_face [10,0,0], [20,0,0], [20,10,0], [10,10,0]
<br />square3 = ents.add_face [0,10,0], [10,10,0], [10,20,0], [0,20,0]
<br />square4 = ents.add_face [10,10,0], [20,10,0], [20,20,0], [10,20,0]
<br />center_vertex = square1.vertices[3]
<br /></code><div>
<br /></div><div>Easy. Now, this also gives me a 3x3 grid of <i>vertices</i>. Let's say I want to move that center_vertex 10" into the sky without moving the others. Can it be done?</div><div>
<br /></div><div>If you go to the <a href="http://code.google.com/apis/sketchup/docs/ourdoc/vertex.html">Vertex class documentation</a>, there isn't a simple transform() method. There's a <a href="http://code.google.com/apis/sketchup/docs/ourdoc/vertex.html#position">Vertex.position</a> method... but alas, it's read only.</div><div>
<br /></div><div>But wait! What about the parent class? A Vertex is an Entity, and so I can call any Entity method, too. Maybe there's a transform() method on the <a href="http://code.google.com/apis/sketchup/docs/ourdoc/entity.html">Entity class</a>...</div><div>
<br /></div><div>Nope.</div><div>
<br /></div><div>At this point, you might have given up. (I know I did the first time I tried this...) But don't! The secret is that <a href="http://code.google.com/apis/sketchup/docs/ourdoc/entities.html#transform_entities">Entities.transform_entities</a> can accept naked vertices as well as edges and faces. This wasn't obvious to me because if you <a href="http://code.google.com/apis/sketchup/docs/ourdoc/entities.html#each">iterate over the Entities collection</a>, it doesn't contain vertices! So I just assumed that the transform_entities method wouldn't work on vertices. I was wrong, though. It'll accept any Entity, just like the documentation says. Check this out...</div><div>
<br /></div><code>ents = Sketchup.active_model.entities
<br />square1 = ents.add_face [0,0,0], [10,0,0], [10,10,0], [0,10,0]
<br />square2 = ents.add_face [10,0,0], [20,0,0], [20,10,0], [10,10,0]
<br />square3 = ents.add_face [0,10,0], [10,10,0], [10,20,0], [0,20,0]
<br />square4 = ents.add_face [10,10,0], [20,10,0], [20,20,0], [10,20,0]
<br />center_vertex = square1.vertices[3]
<br />
<br />move_up = Geom::Transformation.new([0, 0, 10])
<br />ents.transform_entities move_up, [center_vertex]
<br /></code><div>
<br /></div><div>Hopefully that will help you out in some future plugin coding adventure.</div><div>
<br /></div><div>What are your favorite "secrets" of the API? Share 'em in the comments.</div><div>
<br /></div><div>
<br /></div>Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-6313632118977055554.post-76214799765103118152011-08-03T10:12:00.000-07:002011-08-03T10:53:00.222-07:00Being a Good SketchUp Ruby Citizen<span class="byline-author">Posted by Scott Lininger, SketchUp Team</span><br /><br /><div>In the world of Ruby scripts, keep in mind that users who will install your SketchUp plugin probably have installed <i>other </i>SketchUp plugins, too. Since Ruby is a wide-open language that lets you override and inspect just about anything, this can lead to bugs where your plugin conflicts with someone else's.</div><div><br /></div><div>So before you distribute your hot new plugin, don't forget to follow these important steps:</div><div><div><ol><b><li>Try to know what others are doing/have done.</b> This isn't always easy, but some research and questions go a long way in avoiding conflicting class/method names. It can also prevent you from duplicating someone else's effort - why re-create method x when it's already been written? Just tap into it and go (with permission, of course). Look for public scripts that are doing similar things to what you're acconplishing, and consider working with that author to cross-promote your tools. Sometimes, the already-written code won't do exactly what you want. In that case, you can either subclass yours and modify the methods (for classes, obviously), or write your own using a different class/method name.<br/><br/></li><b><li>Try to use unique names rather than common ones.</b> For example, if you write a "ProgressBar" class, you will cause conflicts with any other "ProgressBar" class. That will make for unhappy users, as they try to get tech support for something the author says works just fine on his machine, but clearly won't work on their machine; and will make for unhappy fellow developers, who have to hunt down the conflicting script, locate the author, and try to work out a solution. Better to do something like "mskp_ProgressBar" which is unlikely to collide.<br/><br/></li><b><li>Encapsulate methods in a Module or a Class.</b> Within a class, you don't have to worry about method naming conflicts, and within a module, you can be less careful about both class and method names.<br/><br/></li><b><li>Test your work against as many other works as possible, and test them against yours.</b> Unfortunately, the burden of compatibility will more than likely fall to the second developer. However, if you send your script to other developers asking them to test for compatibility with their works, they'll most likely be happy to oblige (subject to their own time constraints, naturally). This will help keep the user experience (and your reputation) positive.<br/><br/></li><b><li>Be respectful of the Plugins directory structure.</b> If your plugins has a lot of support files (piles of .rb files, html file, image files, etc.), group them together into a subdirectory under the Plugins folder. This will make it easy for users to identify (and potentially uninstall) your script. It will also make it less likely that your "cursor.png" will by overwritten by someone else's "cursor.png".<br/><br/></li><b><li>Document your code and include contact information.</b> Write generous comments and include a header block at the top of your scripts that tells people what is included with your Plugin, what it does, and how to contact you in case of upgrades or bug reports.<br/><br/></li></ol></div><div>Thanks for Rick Wilson for the original post that I took these tips from. Code on!</div></div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6313632118977055554.post-86254639374100022002011-07-21T13:35:00.000-07:002011-07-21T14:27:10.379-07:00Turn Your Plugin Into An Extension<span class="byline-author">Posted by Scott Lininger, SketchUp Team</span><br /><br /><p>Around the office here we're always amazed at the awesome Ruby scripts you developers create. They make SketchUp more productive, smarter, and downright snazzy. So it's no surprise when we hear from users who have a <i>lot</i> of plugins installed.<br /><br /><p>Plugin management can get really difficult, though. If two scripts conflict with each other somehow, SketchUp can go haywire, and figuring out which scripts are the culprits can require a lot of detective work. If only all of the ruby programmers out there used SketchupExtensions... ahh, the world would be so much nicer.<br /><br /><p><a href="http://code.google.com/apis/sketchup/docs/ourdoc/sketchupextension.html">SketchupExtensions</a> are a handy-dandy way for you to package your plugin that is easier for users to toggle on and off. You can see the extensions you already have under Window > Preferences > Extensions. With a quick click, you can learn about who authored each of them and can even turn 'em on and off. It's dandy!</p><br /><br /><p>And the cool thing is that an extension is nothing but a normal Ruby plugin wrapped in a little bit of extra code. Making one of your own is easy and well worth your time. Here are several advantages:<br /><br /><p><ul><li>Makes it easier for your users to turn off your script if they don't need it at the moment</li><li>Makes customer support easier for <i>you</i>, because you can track plugin versions</li><li>Gives you a handy promotional space to put contact info, website details, etc.</li><li>Keeps everyone's scripts better isolated so there are fewer cross-script conflicts</li></ul><br /><br /><p>Let's walk through an example. Say you have a script called drawboat.rb. It already works. Now you just want to make it an extension. Here are the steps.<br /><br /><p><ol><li>Copy <span class="Apple-style-span">plugins/drawboat.rb</span> into a new subfolder and rename it, <span class="Apple-style-span">plugins/drawboat/drawboat_loader.rb</span></li><li>Create a new, empty file called <span class="Apple-style-span" style="font-family: 'courier new'; ">plugins/drawboat.rb</span></li><li>Put the following code into <span class="Apple-style-span" style="font-family: 'courier new'; ">plugins/drawboat.rb</span></li></ol><pre> # Load the normal support files.<br /> require 'sketchup.rb'<br /> require 'extensions.rb'<br /> <br /> <br /> # Create the extension.<br /> ext = SketchupExtension.new 'BoatCreator Beta',<br /> 'drawboat/drawboat_loader.rb'<br /><br /> # Attach some nice info.<br /> ext.creator = 'DrawingBoats, Inc.'<br /> ext.version = '1.0.0'<br /> ext.copyright = '2011, DrawingBoats, Inc.'<br /> ext.description = 'Draw boats! Visit drawboats.com for support.'<br /><br /> # Register and load the extension on startup.<br /> Sketchup.register_extension ext, true<br /></pre><br /><br /><p>That's all there is to it. When you restart SketchUp your plugin will load as before, but now people can control it in the Preferences panel. We highly recommend that you do this with all of your plugins that extend SketchUp's UI with buttons or menu items.Unknownnoreply@blogger.com8tag:blogger.com,1999:blog-6313632118977055554.post-56030038773931961552011-07-07T14:08:00.000-07:002011-07-14T14:35:31.949-07:00The go_faster Parameter<span class="byline-author"><i>Posted by Scott Lininger, SketchUp Team</i></span><br /><br /><div>So I've been sitting in on a lot of product demos recently from some great Ruby API developers, and in a couple of cases they did not know about the "go_faster" parameter.</div><div><br /></div><div>The "go_faster" parameter, you say. What's that?!</div><div><br /></div><div>Let's look at two pieces of code. First without it:</div><br /><br /><pre>start_time = Time.new<br />Sketchup.active_model.start_operation("Draw a grid")<br />for x in 0..50<br /> for y in 0..50<br /> p1 = [x, y]<br /> p2 = [x+1, y]<br /> p3 = [x+1, y+1]<br /> p4 = [x, y+1]<br /> Sketchup.active_model.entities.add_face(p1, p2, p3, p4);<br /> end<br />end<br />Sketchup.active_model.commit_operation<br />end_time = Time.new<br />total_time = end_time - start_time<br />puts total_time.to_s + " seconds to run"<br /></pre><br /><br /><div>On my IBM Thinkpad this executes in 5.9 seconds. Now let's add the parameter...</div><br /><br /><pre>start_time = Time.new<br />Sketchup.active_model.start_operation("Draw a grid", <b style="background-color:#00FF00">true</b>)<br />for x in 0..50<br /> for y in 0..50<br /> p1 = [x, y]<br /> p2 = [x+1, y]<br /> p3 = [x+1, y+1]<br /> p4 = [x, y+1]<br /> Sketchup.active_model.entities.add_face(p1, p2, p3, p4);<br /> end<br />end<br />Sketchup.active_model.commit_operation<br />end_time = Time.new<br />total_time = end_time - start_time<br />puts total_time.to_s + " seconds to run"<br /></pre><br /><br /><div>Whoohoo! One little flag and now it runs in 4.7 seconds. That's a 25% increase in performance for typing six keys on my keyboard.</div><div><br /></div><div>If you're already using <a href="http://code.google.com/apis/sketchup/docs/ourdoc/model.html#start_operation">Model.start_operation</a> in your plugins, this is a change worth making. If you're not, you should be. In addition to this performance increase, start_operation groups all of your model changes into a single "undo," which makes your plugin easier on your users.</div><div><br /></div><div>What Ruby performance secrets do <i>you </i>know? Let's hear 'em in the comments!</div>Unknownnoreply@blogger.com4tag:blogger.com,1999:blog-6313632118977055554.post-4378729712054919062010-09-02T11:25:00.000-07:002010-09-02T12:27:06.830-07:00SketchUp Ruby API documentation for SketchUp8 is live<meta equiv="content-type" content="text/html; charset=utf-8"><span class="Apple-style-span" style="border-collapse: separate; color: rgb(0, 0, 0); font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;font-family:'Times New Roman';font-size:medium;" ><div color="transparent" style="margin: 0px;"><meta equiv="content-type" content="text/html; charset=utf-8"><span id="internal-source-marker_0.2238406331744045" style="font-size: 13pt; font-family: 'Trebuchet MS'; color: rgb(51, 51, 51); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">As many of you already know, we released SketchUp 8 yesterday. Check it out: http://sketchup.google.com/</span>
<br /><span class="Apple-style-span" style="border-collapse: separate; color: rgb(0, 0, 0); font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium;"><div style="margin: 0px; background-color: transparent;"><span style="font-size: 13pt; font-family: 'Trebuchet MS'; color: rgb(51, 51, 51); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span>
<br /><span style="font-size: 13pt; font-family: 'Trebuchet MS'; color: rgb(51, 51, 51); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">We have updated the documentation for the Ruby API and you can find the Ruby API release notes at: http://code.google.com/apis/sketchup/docs/releases.html</span>
<br /><span style="font-size: 13pt; font-family: 'Trebuchet MS'; color: rgb(51, 51, 51); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span>
<br /><span style="font-size: 13pt; font-family: 'Trebuchet MS'; color: rgb(51, 51, 51); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Enjoy!</span>
<br /><span style="font-size: 13pt; font-family: 'Trebuchet MS'; color: rgb(51, 51, 51); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span>
<br /><span style="font-size: 13pt; font-family: 'Trebuchet MS'; color: rgb(51, 51, 51); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Posted by Simone Nicolo, Google SketchUp team.</span><span style="font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;font-family:'Trebuchet MS';font-size:13pt;color:transparent;" ></span></div></span></div></span>Simone (snicolo)http://www.blogger.com/profile/15177631670413453224noreply@blogger.com0tag:blogger.com,1999:blog-6313632118977055554.post-69848596704306990522010-03-10T09:56:00.001-08:002010-03-17T10:34:24.560-07:00New User's Comments Feature on the Google SketchUp Ruby API documentation site<div id="internal-source-marker_0.4658320294631547" class="kix-clipboard-outer"><div class="kix-clipboard" contenteditable="true"><span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); font-weight: bold; font-style: normal; text-decoration: none; vertical-align: baseline;" id="internal-source-marker_0.4658320294631547">New User's Comments Feature on the Google SketchUp Ruby API documentation site</span><span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline;"></span><br /><span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline;"></span><br /><span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline;">Google Code is running a pilot on user-contributed notes to the API documentation. This feature is currently enabled for the documentation of a handful of products, including the </span><a href="http://code.google.com/apis/sketchup/docs/index.html"><span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 153); font-weight: normal; font-style: normal; text-decoration: underline; vertical-align: baseline;">Google SketchUp Ruby API</span></a><span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline;">! The ultimate goal of this feature is to provide a richer documentation experience for our developers, similar to that offered in open source projects such as </span><a href="http://www.google.com/url?q=http%3A%2F%2Fphp.net%2F&sa=D&sntz=1&usg=AFrqEzcx3lM22s0FAdH64FiwEThPsHFQXg"><span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 153); font-weight: bold; font-style: normal; text-decoration: underline; vertical-align: baseline;">php.net</span></a><span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline;">.</span><br /><span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline;"></span><br /><span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline;">We invite you to participate by adding notes, insights, or code examples to a particular doc. Your note may take up to 24 hours to appear after you submit it. All notes will be moderated to ensure they provide a useful contribution to the topic to which they are attached. Requests for help with the API should not be submitted as notes, but should continue to be posted to the </span><a href="http://groups.google.com/group/google-sketchup-developers"><span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 153); font-weight: normal; font-style: normal; text-decoration: underline; vertical-align: baseline;">Google SketchUp Developers</span></a><span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline;"> Google Group.</span><br /><span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline;"></span><br /><span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline;">Posted by Simone Nicolo, Google Sketchup Team</span></div></div>Simone (snicolo)http://www.blogger.com/profile/15177631670413453224noreply@blogger.com3tag:blogger.com,1999:blog-6313632118977055554.post-88183157228068710142010-02-08T15:41:00.000-08:002010-02-09T13:49:27.794-08:00SketchUp 7.1 SDK UpdateLast month we released a 2nd update for SketchUp 7.1. This release includes a few bug fixes as well as fixes for two reported security issues. Were happy to announce that we have also updated the SDK package with the same security fixes. Please note that the file format for the 7.1 M2 has not changed but we do recommend that folks upgrade to the latest version. It can be downloaded from the <a href="http://code.google.com/apis/sketchup/docs/downloadsdksubmit.html" id="cwjt" title="API Site">SDK page</a> on our code site. If you'd like more info on this update please see our <a href="http://sketchupdate.blogspot.com/2010/01/new-year-new-sketchup-build.html" id="y8gp" title="original blog post">original blog post</a> for the release.<br /><br />Happy SketchUp Developing!<br />Bryce Stout<br />Product Manager.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6313632118977055554.post-74972359104746650652009-11-02T10:45:00.000-08:002009-11-02T10:52:58.347-08:00SketchUp Ruby API site updated for SketchUp 7.1<span style=";font-family:georgia;font-size:130%;" >SketchUp 7.1 launched back in September. Last week, we updated the </span><span style="font-size:130%;"><a style="font-family: georgia;" title="SketchUp ruby API Site" target="_blank" href="http://code.google.com/apis/sketchup/" id="afld">SketchUp ruby API Site</a></span><span style=";font-family:georgia;font-size:130%;" > with all the changes that have been made since the release of Sketchup 7.0 (Nov 2008). This includes documentation fixes and updates for several new methods. For all the details check out the </span><span style="font-size:130%;"><a style="font-family: georgia;" title="API release notes" target="_blank" href="http://code.google.com/apis/sketchup/docs/releases.html" id="p6-q">API release notes</a></span><span style=";font-family:georgia;font-size:130%;" >. </span><span style="font-size:130%;"><br /><br /></span><span style=";font-family:georgia;font-size:130%;" >We would also like to say "Thanks!!" to the </span><span style="font-size:130%;"><a style="font-family: georgia;" target="_blank" title="SketchUcation community" href="http://forums.sketchucation.com/" id="n4oj">SketchUcation community</a></span><span style=";font-family:georgia;font-size:130%;" > and the guys over at </span><span style="font-size:130%;"><a style="font-family: georgia;" title="Smustard.com" target="_blank" href="http://www.smustard.com/" id="a1.:">Smustard.com</a></span><span style=";font-family:georgia;font-size:130%;" > for sending us Ruby documentation fixes. SketchUp's amazing developer community continues to be one of the best "features" of the Ruby API.</span><span style="font-size:130%;"><br /><br /></span><span style=";font-family:georgia;font-size:130%;" >~Bryce Stout </span><span style="font-size:130%;"><br /></span><span style=";font-family:georgia;font-size:130%;" >Product Manager</span>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6313632118977055554.post-16222327439528453262009-07-23T16:18:00.000-07:002009-07-27T16:32:10.728-07:00Dynamic Components that react to scene (aka page) changes<span class="byline-author"></span><meta equiv="Content-Type" content="text/html; charset=utf-8"><meta name="ProgId" content="Word.Document"><meta name="Generator" content="Microsoft Word 11"><meta name="Originator" content="Microsoft Word 11"><link rel="File-List" href="file:///C:%5CDOCUME%7E1%5Csnicolo%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_filelist.xml"><!--[if gte mso 9]><xml> <w:worddocument> <w:view>Normal</w:View> <w:zoom>0</w:Zoom> <w:punctuationkerning/> <w:validateagainstschemas/> <w:saveifxmlinvalid>false</w:SaveIfXMLInvalid> <w:ignoremixedcontent>false</w:IgnoreMixedContent> <w:alwaysshowplaceholdertext>false</w:AlwaysShowPlaceholderText> <w:compatibility> <w:breakwrappedtables/> <w:snaptogridincell/> <w:wraptextwithpunct/> <w:useasianbreakrules/> <w:dontgrowautofit/> <w:usefelayout/> </w:Compatibility> <w:browserlevel>MicrosoftInternetExplorer4</w:BrowserLevel> </w:WordDocument> </xml><![endif]--><!--[if gte mso 9]><xml> <w:latentstyles deflockedstate="false" latentstylecount="156"> </w:LatentStyles> </xml><![endif]--><style> <!-- /* Font Definitions */ @font-face {font-family:PMingLiU; panose-1:2 2 3 0 0 0 0 0 0 0; mso-font-alt:新細明體; mso-font-charset:136; mso-generic-font-family:roman; mso-font-pitch:variable; mso-font-signature:3 137232384 22 0 1048577 0;} @font-face {font-family:"\@PMingLiU"; panose-1:2 2 3 0 0 0 0 0 0 0; mso-font-charset:136; mso-generic-font-family:roman; mso-font-pitch:variable; mso-font-signature:3 137232384 22 0 1048577 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-parent:""; margin:0in; margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:12.0pt; font-family:"Times New Roman"; mso-fareast-font-family:PMingLiU;} @page Section1 {size:8.5in 11.0in; margin:1.0in 1.25in 1.0in 1.25in; mso-header-margin:.5in; mso-footer-margin:.5in; mso-paper-source:0;} div.Section1 {page:Section1;} --> </style><!--[if gte mso 10]> <style> /* Style Definitions */ table.MsoNormalTable {mso-style-name:"Table Normal"; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-parent:""; mso-padding-alt:0in 5.4pt 0in 5.4pt; mso-para-margin:0in; mso-para-margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:10.0pt; font-family:"Times New Roman"; mso-fareast-font-family:"Times New Roman"; mso-ansi-language:#0400; mso-fareast-language:#0400; mso-bidi-language:#0400;} </style> <![endif]--> <p class="MsoNormal">Have you ever wanted to have a Dynamic Component that reacts to Scene changes?</p>
<br /><p class="MsoNormal">
<br /></p> <p class="MsoNormal"><o:p> </o:p></p> <p class="MsoNormal">Well, this blogpost tells you how to write one (thanks to John Clemens for the idea).</p><p class="MsoNormal">
<br />
<br /></p> <p class="MsoNormal"><o:p> </o:p></p> <p class="MsoNormal">First of all, you need a mechanism to detect a scene change. After some struggles with using the PagesObserver, I decided to use the FrameChangeObserver.</p>
<br /><p class="MsoNormal"><o:p> </o:p></p> <p class="MsoNormal">
<br /></p><p class="MsoNormal">The add_frame_change_observer method is used to add a new FrameChangeObserver that is called with each frame of an animation. This means the end user has clicked on a Scene tab (aka Page) inside SketchUp and the camera is animating to that scene. Moreover, it provides you with a percent_done variable and fromPage and toPage variables which allow you to have finer feedback over the state of the animation.</p> <p class="MsoNormal"><o:p> </o:p></p> <p class="MsoNormal">
<br />
<br /></p><p class="MsoNormal">The other challenge is that we need to find the DC that will react to the scene change. This can be accomplished by traversing the model entities and examining all the component instances that have a “dynamic_attributes” dictionary attached to them; those are the dynamic components in the model. Once we have a way to find all the dynamic components, it is just a matter of detecting which ones we want to influence on a scene change. For that, we add a SCENE_CHANGE Boolean (true or false values only) attribute to the top level attributes of our DC to indicate whether or not we want that DC to change. Then, we add a SCENE_TRIGGER attribute that contains an index that is affected by each scene change and that changes between 1 and 4 (this can be customized to be anything you want). This can then can be used to drive changes in the DC.</p>
<br /><p class="MsoNormal"><o:p> </o:p></p> <p class="MsoNormal">
<br /></p><p class="MsoNormal">To see this in action, put the attached script in the Tools or Plugins folder of SketchUp, open the attached model, change the scene, and ta-dah the magic begins. You will notice that one of the two components does not change, the reason being that the attribute SCENE_CHANGE for that component is set to 'false'. Change it to 'true' and you will see it changing.</p>
<br /><p class="MsoNormal"><o:p> </o:p></p> <p class="MsoNormal">
<br /></p><p class="MsoNormal">It is important to notice that there are several observers available from Ruby (e.g ToolsObserver, SelectionObserver, etc.) and any of them can be used to trigger changes in dynamic components using the same strategy I used in the attached script. DC can be made to change according to which tool is currently active, or depending on the currently selected material.</p><p class="MsoNormal">
<br /></p><p class="MsoNormal">Download the example model <a href="http://sketchup.google.com/3dwarehouse/details?mid=1f2c6afc778c660a8bbad0f4df6effc0">here</a>.</p>
<br /><p class="MsoNormal">
<br /></p><p class="MsoNormal">Code snippet below
<br /></p><p class="MsoNormal">----------------------------------------------------------------</p><p class="MsoNormal"># Copyright 2005-2008, Google, Inc.
<br />
<br /># Permission to use, copy, modify, and distribute this software for
<br /># any purpose and without fee is hereby granted, provided that the above
<br /># copyright notice appear in all copies.
<br />
<br /># THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
<br /># IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
<br /># WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
<br />#
<br />
<br /># This code snippets allows you to have Dynamic Components
<br /># that modify themselves based on a Scene Change
<br />#
<br /># They need to have at the top level the following attributes
<br /># "scene_change" a boolean value that if true force the DC to react to scene changes
<br /># and if false has the DC ignore the scene change
<br /># and
<br /># "scene_trigger" which is the index that is incremented every time there is a scene change and
<br /># it is used to change attributes for the DC.
<br />#
<br />#
<br /># Author: Simone Nicolo
<br />
<br />require 'sketchup.rb'
<br />
<br />
<br /># Define the Frame Change Observer which is documented in the Pages class.
<br />class FrameChangeObserver
<br />
<br />def initialize
<br /># @current page is used to make sure that the observer is only triggered by page changes
<br /># This is to workaround the PC bug that does not correctly populate the fromPage variable in the
<br /># callback to frameChange.
<br />@current_page = Sketchup.active_model.pages.selected_page
<br />end
<br />
<br /># Callback triggered by the Frame change observer.
<br /># fromPage is populated with the page we were coming from, toPage is
<br /># populated with the page we were transitioning to
<br /># and percent done contains the percentage of the transition that
<br /># has completed.
<br />def frameChange(fromPage, toPage, percent_done)
<br /># If there has been a page change and it has completed
<br />if (not toPage.nil? and percent_done == 1) then
<br /> if @current_page != toPage then
<br /> #update the current page
<br /> @current_page = toPage
<br /> #find the DCs that need redrawing, and redraw them.
<br /> find_dc_for_redraw
<br /> end
<br />end
<br />end
<br />
<br /># This function finds all the DC's that need to be redrawn based on a scene transition and
<br /># on the boolean scene_change attribute if scene_change is true, change and redraw
<br /># the DC on a scene transition, if it is false do not change or redraw the DC.
<br />def find_dc_for_redraw
<br />entities_list = Sketchup.active_model.entities
<br />if entities_list != []
<br /> # For all the entities in the model
<br /> entities_list.each do |item|
<br /> type = item.typename
<br /> case type
<br /> # Find the Dynamic Component instances
<br /> when "ComponentInstance"
<br /> if not item.attribute_dictionaries.nil?
<br /> attributes = item.attribute_dictionaries[DICTIONARY_NAME]
<br /> # If they have a scene_change attribute that contains true
<br /> if (not attributes.nil? and attributes[SCENE_CHANGE] == 1.to_s)
<br /> # Increment the scene_trigger attribute.
<br /> # Here we are allowing the scene trigger attributes to only have the values
<br /> # 1, 2, 3, and 4.
<br /> attributes[SCENE_TRIGGER] = (((attributes[SCENE_TRIGGER].to_i+1)%5)).to_s
<br /> if attributes[SCENE_TRIGGER] == "0" then
<br /> attributes[SCENE_TRIGGER] = 1.to_s
<br /> end
<br /> # Redraw the DC using the $dc_observers global variable.
<br /> $dc_observers.get_latest_class.redraw_with_undo(item)
<br /> end
<br /> end
<br /> end
<br /> end
<br />else
<br /> UI.messagebox("There are no entities in this model!")
<br />end
<br />end
<br />
<br />end
<br />
<br />if not file_loaded? 'scenes.rb'
<br /># Useful constants
<br /># Dynamic Components dictionary name
<br />DICTIONARY_NAME = "dynamic_attributes"
<br /># Boolean attribute that turns on and off the reaction to a scene change for the DC
<br />SCENE_CHANGE = "scene_change"
<br /># Index attribute for the DC that is used to drive changes in the DC.
<br />SCENE_TRIGGER = "scene_trigger"
<br /># Attach the frame chage observer to the global Pages object.
<br />id = Sketchup::Pages.add_frame_change_observer(FrameChangeObserver.new)
<br />file_loaded 'scenes.rb'
<br />end
<br /></p><p class="MsoNormal">
<br /></p> Simone (snicolo)http://www.blogger.com/profile/15177631670413453224noreply@blogger.com1tag:blogger.com,1999:blog-6313632118977055554.post-77783047697375052252009-05-07T08:22:00.001-07:002009-05-08T07:31:32.828-07:00Champion the 3D Web using COLLADA ContestOur friends over at the Khronos group are holding a <a href="http://www.colladacontest.com/" id="u.30" target="_blank" title="Champion the 3D Web using COLLADA Contest">Champion the 3D Web using COLLADA Contest</a>. They're looking for the best 3D models, avatars, worlds, or simulations created using COLLADA. Prizes include cash awards and opportunities at a future Immersive Education Initiative in-world (virtual) events. The contest will run through July 15, 2009. Winners will be announced at <a href="http://www.siggraph.org/s2009/" id="glxz" target="_blank" title="Siggraph">Siggraph</a> this year in New Orleans. The contest is sponsored by the <a href="http://www.khronos.org/" target="_blank" title="contest site">Khronos Group</a> and the <a href="http://immersiveeducation.org/" target="_blank" title="contest site">Media Grid Immersive Education Initiative</a>. Please check out the <a href="http://www.colladacontest.com/" id="ikpi" target="_blank" title="contest site">contest site</a> for full details.<br /><b><br />Using SketchUp to enter the contest</b><br />SketchUp can be used to create models for this contest. SketchUp Pro and the Pro Evaluation both export COLLADA (DAE) files directly. The free version of SketchUp can export Google Earth (KMZ) files which contain a COLLADA model. To extract a COLLADA model from a KMZ file follow these steps:<br /><br /><ol><li> Export your SketchUp model to KMZ. </li><li> Change the file extension from ".kmz" to ".zip".</li><li>Double-click on the ZIP file.</li><li>Double-click on the "models" folder. </li><li>Locate the DAE file. Copy and paste this file to your Desktop.</li><li> Check your file's appearance in a COLLADA viewer like <a title="Swirl X3D Viewer©" target="_blank" href="http://www.pinecoast.com/swview.htm" id="ey6p">Swirl X3D Viewer©</a> </li><li> Submit your model to the contest. </li></ol><br />Good Luck!<br />Bryce Stout<br />Product Manager<br />GoogleUnknownnoreply@blogger.com0tag:blogger.com,1999:blog-6313632118977055554.post-83266394996191259982009-04-17T09:15:00.000-07:002009-04-21T14:33:11.884-07:00Ruby API Objects diagram<font class="byline-author">Posted by Simone Nicolo, Google SketchUp team.<br /><br /></font>Have you ever wondered how the various classes are organized in the ruby API?<br />Well, I <font style="background-color: rgb(255, 255, 102);"></font>recently created a diagram to show the objects hierarchy for the SketchUp Ruby API.<br /><br />It can be found <a title="SU Objects diagram" href="http://code.google.com/apis/sketchup/docs/diagram.html" target="_blank">here</a> and it provides an easy way to visualize relationships between SU API's various objects.<br /><br />Below are some examples of ways in which the diagram can be used:<br /><br />Example 1<br />In the diagram, it is evident that the Entity class has several subclasses which all inherit the Entity class methods. For example, the Face class can add an EntityObserver to its instances just by taking advantage of the inherited methods from the Entity class.<br /><br />Example 2<br />It is also visually clear that I can get handles to different entities using Ruby. For example, if I want to obtain a handle to my current model, I can do so using <font style="font-style: italic;">Sketchup.active_model </font>or <font style="font-style: italic;">Entity.model</font>. The Entity.model method will work on any class that inherits from Entity.<br /><br />Example 3<br />I can clearly visualize which classes have observers and which do not. For example, I can easily see that the View class has its own observer, while the camera class does not.<br /><br />To keep it as simple as possible, some classes were not included in the diagram.<br /><br />Hopefully this will help you better visualize the organization of the Ruby API elements.<br /><br />Simone.<br /><font class="byline-author"><br /></font>Simone (snicolo)http://www.blogger.com/profile/15177631670413453224noreply@blogger.com0tag:blogger.com,1999:blog-6313632118977055554.post-76823409100805771742009-04-01T09:33:00.001-07:002009-04-01T14:20:48.161-07:00SketchUp API Updates<b>Updated </b><b>Ruby API Documentation</b><br /><br />The guys over at the <a title="SketchUcation Community Forums" href="http://www.sketchucation.com/forums/scf/" id="cavz">SketchUcation Community Forums</a> have been submitting documentation corrections to us and we just pushed a bunch of updates to our <a title="Ruby API Site" href="http://code.google.com/apis/sketchup/docs/index.html" id="ow6k">Ruby API Site</a> . Thanks to everyone who's been helping us improve our docs! If you find other typos or problems please join the <a title="thread on SketchUcation" href="http://www.sketchucation.com/forums/scf/viewtopic.php?f=180&t=17047" id="skcq">thread on SketchUcation</a> or post to our ruby group.<br /><br /><b>New Ruby Tutorial</b><br /><br />Check out our new tutorial on <a title="Attribute Reporting" href="http://code.google.com/apis/sketchup/docs/tutorial_attrreporting.html" id="qqau">Attribute Reporting</a> to learn how to read attribute data from entities in your models.<br /><br /><b>New SDK Package</b><br /><br />We recently repackaged the SDK to make it a bit easier to use. Improvements include:<br /><br />- Reorganized folders to make them more understandable<br />- New GettingStarted.html intro to help get folks headed down the right path<br />- Updated SkpReader and SkpWriter documentation<br />- Updated SkpToXml example to compile on the PC<br /><br />We also removed Client Warehouse SDK from the package. If you need support on this please post your contact info to the SDK support group.<br /><br />There were no changes to the headers or binaries so there are no code fixes with this release. Please download the latest package at - <a href="http://code.google.com/apis/sketchup/docs/downloadsdksubmit.html">http://code.google.com/apis/sketchup/docs/downloadsdksubmit.html</a><br /><br />Bryce Stout<br />Product Manager<br />GoogleUnknownnoreply@blogger.com3tag:blogger.com,1999:blog-6313632118977055554.post-81535897430066117682009-03-12T10:19:00.000-07:002009-03-17T09:56:53.825-07:00Deleting Unnecessary Edges<p><span class="byline-author">Posted by Sandra Winstead, SketchUp Team</span><br /><br />Have you ever opened a SketchUp file that you didn’t create, or imported a model from another application, and found that it has hundreds of needless hidden or softened lines separating coplanar faces? Wish you could get rid of them with a simple ruby script? Now you can!<br /><br />First, set up a few variables:<br /><span style="font-family: courier new;font-size:100%;"><pre>def variables<br /> @group_list = []<br /> @component_list = []<br /> @delete_these = []<br /> @model_list = Sketchup.active_model.entities<br />end<br /></pre></span><br />Then write a method that determines if an edge is 1) hidden or softened, and 2) bordered by two co-planar faces. If the edge meets each of those requirements, it is added to @delete_these list.<br /><br /><span style="font-family: courier new;font-size:100%;"><pre>def delete_soft_lines(e)<br /><font color="green"> # Determine if the edge is soft or hidden, and if it is bordered by <br /> # two faces.</font><br /> if ((e.soft? and e.faces.size == 2) or (e.hidden? and e.faces.size == 2))<br /><font color="green"> # Determine if the two bordering faces are coplanar.<br /> # Note: This will only catch cases where the front faces are pointing <br /> # in the same direction.</font><br /> if (e.faces[0].normal.dot(e.faces[1].normal) > 0.999999999)<br /><font color="green"> # Add the edge to the list of entities that will be deleted.</font><br /> @delete_these.push(e)<br /> end<br /> end<br />end<br /></pre></span><br />Now create a method to find all the edges in the model, including edges that are embedded in groups and components:<br /><br /><span style="font-family: courier new;font-size:100%;"><pre>def traverse_model_entities<br /><font color="green"> # @model_list will not be empty until all of the groups, components <br /> # and edges have been traversed.</font><br /> while @model_list != []<br /> @model_list.each do |item|<br /><font color="green"> # Determine if the entity is an edge, group, or component.</font><br /> type = item.typename<br /> case type<br /> when "Edge"<br /><font color="green"> # Determine if the edge should be deleted, and add it to the <br /> # @delete_these list.</font><br /> delete_soft_lines(item)<br /> when "Group"<br /><font color="green"> # Add each of the entities in the group into the group_list<br /> # array.</font><br /> item.entities.each do |entity|<br /> @group_list.push entity<br /> end<br /> when "ComponentInstance"<br /><font color="green"> # .entities can be called on a Component Definition, but not on<br /> # a Component Instance.<br /> # Use the .definition method to access the Component Definition<br /> # that the instance belongs to.</font><br /> item.definition.entities.each do |entity|<br /><font color="green"> # Add each of the entities in the component into the<br /> # component_list array.</font><br /> @component_list.push entity<br /> end<br /> end<br /> end<br /><font color="green"> # Update the @model_list so it contains only the entities that were <br /> # embedded in groups or components. These entities haven't been<br /> # counted yet.</font><br /> @model_list = @group_list + @component_list<br /><font color="green"> # Clear out the group and component lists so they're ready for the<br /> # next level of sub-groups/components.</font><br /> @group_list = []<br /> @component_list =[]<br /> end<br /><font color="green"> # The edges that need to be deleted have all been added to the<br /> # @delete_these list, so erase those entities from the <br /> # active SketchUp model.</font><br /> Sketchup.active_model.entities.erase_entities(@delete_these)<br />end<br /><br /></pre></span><br />Finally, add a “Delete unnecessary edges” item to Tools menu, and pop a dialog letting you know the edges were deleted:<br /><span style="font-family: courier new;font-size:100%;"><pre>def delete_edges<br /> variables<br /> traverse_model_entities<br /> UI.messagebox("Edges deleted.")<br />end<br /><br />UI.menu("Tools").add_item("Delete unnecessary edges") {delete_edges}<br /></pre></span></p>Unknownnoreply@blogger.com4tag:blogger.com,1999:blog-6313632118977055554.post-49496694936044189412009-03-06T13:01:00.000-08:002009-03-06T13:04:05.417-08:00Google I/O 2009<img style="width: 345px; height: 64px;" src="https://docs.google.com/a/google.com/File?id=csj37xb_4gzsmjgcd_b" /><br /><div id="x5ja" style="padding: 1em 0pt; text-align: left;"><br /><span style="font-weight: normal;">The </span><a style="font-weight: normal;" href="http://code.google.com/events/io/" id="af4_" title="Google I/O conference">Google I/O Developer Conference</a><span style="font-weight: normal;"> is May 28th and 27th in San Francisco, CA. Members of the SketchUp team will be presenting in the </span><a style="font-weight: normal;" href="http://code.google.com/events/io/sessions.html" id="m9.y" title="What you don't know about Geo APIs can't hurt you">What you don't know about Geo APIs can't hurt you</a><span style="font-weight: normal;"> session and will also be available during </span><a style="font-weight: normal;" href="http://code.google.com/events/io/about.html" id="b9:b" title="Office Hours">Office Hours</a><span style="font-weight: normal;">. Hope to see you there! </span><br /><br /><br /><span style="font-weight: normal;"> Posted by Bryce Stout, Product Manager</span><br /></div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6313632118977055554.post-79820637294744512622009-02-23T17:01:00.000-08:002009-02-27T07:42:11.316-08:00SketchUp Importers<span class="byline-author">Posted by Sang Ahn, SketchUp Team</span><br /><br />There's a lot of 3D content out there, and we understand that a lot of it is not in the SketchUp file format. But, if you can read the content, you can use the Ruby Importer plugin API to import it into SketchUp.<div><br /><div>It's easy to write and use your own Ruby importers in SketchUp. Just follow these steps:<br /><br />1. Define a class with the plugin API methods.<br />2. Register an object of the class with SketchUp.<br />3. Recover from Mardi Gras festivities (may not be applicable).<br /></div><br /><div>An importer class must have the following methods:</div><div><br /><code>def description<br /> # Returns a brief description of your importer plugin.<br />end</code><br /><code>def file_extension<br /> # Returns the file extension of the file format your<br /> # importer can read (e.g. fbx, dae, etc.)<br />end</code><br /><code>def supports_options?<br /> # Returns true if your plugin supports import options.<br />end</code><br /><code>def do_options<br /> # Presents the import options dialog panel to the user.<br />end</code><br /><code>def id<br /> # Returns the id string of your importer.<br />end</code><br /><code>def load_file(file_name, show_summary)<br /> # Reads the contents of location on disk specified<br /> # by file_name.<br /> # Shows the summary dialog panel if show_summary is true.<br /> # Returns 0 on success, returns 1 on failure.<br /> 0<br />end</code></div><div><br /></div><div>Once you have defined your importer class, register your importer with SketchUp:<br /><code><br />Sketchup.register_importer MyImporter.new<br /></code></div><br /><div>Now your importer plugin will be available when you select the Import item under the File menu of SketchUp. The Ruby Importer capability is available in both SketchUp Free and Pro. Now go forth and import.</div></div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6313632118977055554.post-61841972157677837112009-01-21T09:51:00.000-08:002009-01-21T13:03:53.062-08:00The SketchUp 7 SDK is now available<font class="byline-author">Posted by Bryce Stout, SketchUp Team</font><br /><br />We have recently updated the SketchUp SDK for folks who need read and/or write SketchUp 7 files. It is available on <a href="http://code.google.com/apis/sketchup/docs/downloadsdksubmit.html">http://code.google.com/apis/sketchup/docs/downloadsdksubmit.html</a>. If you have feedback or questions, please post your questions or suggestions to the <a href="http://groups.google.com/group/su-sdk-fileshare/topics">SketchUp SDK Group</a>. If you would like to be notified about future SDK updates and news, please subscribe to this blog, if you haven't already.<br /><br />Happy SketchUp Developing!<br />Bryce Stout<br />Product ManagerUnknownnoreply@blogger.com3tag:blogger.com,1999:blog-6313632118977055554.post-22715063856314176412009-01-07T16:02:00.000-08:002009-01-09T15:53:22.058-08:00Playing Sounds in SketchUp<span class="byline-author">Posted by Scott Lininger, SketchUp Team</span><br /><br />This week I'd like to talk about a much-maligned feature of the SketchUp Ruby API... <b>UI.play_sound</b>. Why would you <span style="font-style: italic;">ever</span> want to play sound via the Ruby API? Glad you asked!<br /><br />Besides the <span style="font-style: italic;">obvious</span> desire to listen to <a href="http://en.wikipedia.org/wiki/Marvin_Gaye" target="_blank">Marvin Gaye</a> while drawing your <a href="http://sketchup.google.com/3dwarehouse/cldetails?mid=7bf295d83bf0b273bdde1f81a135a9ac&prevstart=0" target="_blank">skatepark</a>, you could enhance a scene tour with sound effects that match the location where your camera is located. It puts the multi in multimedia. Sounds fun, right? Let's try it.<br /><br /><span style="font-size:130%;">Step 1: Get a Zoo With some Scenes</span><br /><br />For this exercise, we're going to need a model with some Scene tabs. Luckily I have just the zoo. Click here to <a href="http://groups.google.com/group/sketchup-Pro-Groups/web/RubyBlog_Zoo.zip" target="_blank">download a ZIP file</a> with everything you need to follow this example. <br /><br />Once you get it, unzip everything to your <a href="http://code.google.com/apis/sketchup/docs/gsrubyfaq.html" target="_blank">SketchUp/Plugins/</a> directory. It contains four files:<ul><br /><li>zoo.skp - a model of the world's lamest zoo<br /><li>zoo.rb - the code that we're about to talk about<br /><li>zoo_lion.wav - what the lion says<br /><li>zoo_elephant.wav - what the elephant says<br /><li>zoo_sang.wav - what Sang says<br /></ul><br /><span style="font-size:130%;">Step 2: Don't Feed the Animals</span><br /><br />Once everything is in your /Plugins/ directory, open the zoo.skp file<br />and click the Scene tabs. Turn up the volume. You should hear a sound<br />effect that the Ruby API plays at each scene stop.<br /><br /><span style="font-size:130%;">Step 3: Explore the Code</span><br /><br />Here's the entire script. It shows using a Page Observer to capture<br />each frame of our scene animations. It watches the callback parameter<br />percent_done to figure out when the animation is complete, and then<br />it plays the sound.<br /><span style="font-family: courier new;font-size:100%;"><pre># Create a class that will "observe" frame changes.<br />class ZooFrameObserver < Sketchup::ViewObserver<br /><br /> def frameChange(from_page, to_page, percent_done)<br /> if percent_done == 1.0<br /> if to_page == Sketchup.active_model.pages[0]<br /> UI.play_sound("Plugins/zoo_lion.wav")<br /> elsif to_page == Sketchup.active_model.pages[1]<br /> UI.play_sound("Plugins/zoo_elephant.wav")<br /> elsif to_page == Sketchup.active_model.pages[2]<br /> UI.play_sound("Plugins/zoo_sang.wav")<br /> end<br /> end<br /> end<br /><br />end<br /><br /># Attach our observer.<br />Sketchup::Pages.add_frame_change_observer(ZooFrameObserver.new)</pre></span><br />I look forward to the day when every ruby script will play sounds with each interaction. I also like the <blink>blink</blink> tag. Huzzah!Unknownnoreply@blogger.com3tag:blogger.com,1999:blog-6313632118977055554.post-8790031798683699082008-11-13T13:33:00.000-08:002008-11-24T11:37:16.165-08:00What's New in SketchUp 7<span class="byline-author">Posted by Scott Lininger, SketchUp Team</span><br /><br />SketchUp 7 contains several improvements to the Ruby API. Here's a quick tour of the best changes.<br /><ul><li><span style="font-weight: bold;">Improve your script's performance!</span><br />Ability to perform faster inside start_operation transactions.<br /><span style="font-family:courier new;"><span style="color: rgb(0, 102, 0);">go_faster = true</span></span><br /><span style="font-family:courier new;"><span style="color: rgb(0, 102, 0);">model.start_operation operation_name, go_faster</span></span><br /><br />Results from some real world tests, once the go_faster boolean was added:<br /><br /><a href="http://www.smustard.com/script/IntersectOverlaps">Intersect overlaps</a> with 500 overlapping squares<br />28.4 seconds vs. 26.3 (~92% as long)<br /><br /><a href="http://www.smustard.com/script/MakeFaces">Make faces</a> with 500 faceless cubes<br />21.7 seconds vs. 14.5 (~66% as long)<br /><a href="http://members.cox.net/rick.wilson/"><br />Windowizer 3.0</a> with Four 20'x20' windows, 12x12<br />16.1 seconds vs. 7.0 seconds (~43% as as long)<br /><br /><a href="http://www.smustard.com/script/Windowizer4">Windowizer 4.0</a> with Ten 5'x5' windows, 6x6<br />22.6 seconds vs 8.7 seconds (~38% as long)<br /><br /></li><li><span style="font-weight: bold;">Leverage improved Web Dialogs</span><br />Addition of min/max widths.<br /><span style="font-family:courier new;"> <span style="color: rgb(0, 102, 0);">WebDialog.min_width=</span></span><span style="color: rgb(0, 102, 0);font-family:courier new;" >100<br />WebDialog.max_width=300</span><br /><span style="color: rgb(0, 102, 0);font-family:courier new;" > WebDialog.min_height=</span><span style="color: rgb(0, 102, 0);font-family:courier new;" >500<br />WebDialog.max_height=600</span><br /><br />Fixed Mac support for WebDialogs execute_script<br /><span style="color: rgb(0, 102, 0);font-family:courier new;" >WebDialog.execute_script('alert("Bug is Fixed!")');</span><br /><br />New full_security mode for webdialogs (disables plugins and remote links)<br /><span style="color: rgb(0, 102, 0);font-family:courier new;" >WebDialog.set_full_security</span><br /><br />Ability to hide home/next/back navigation icons on the Mac<br /><span style="color: rgb(0, 102, 0);font-family:courier new;" >WebDialog.navigation_buttons_enabled=true</span><br /><br />Cleaner, hash-based syntax for initializing<br /><span style="color: rgb(0, 102, 0);font-family:courier new;" >my_dialog = WebDialog.new(my_settings_hash)</span><br /><br /></li><li><span style="font-weight: bold;">Control Scale Tool handles on your components</span><br />Your script can now control which scale tool handles appear<br /><span style="color: rgb(0, 102, 0);font-family:courier new;" ># Disable the green and red-axes handles<br /># by setting bits 1 and 2 to 1.<br />behavior = my_component_definition.behavior<br />behavior.no_scale_mask = (1 </span><span style="color: rgb(0, 102, 0);font-family:courier new;" ><< 1) + (1 <<</span><span style="color: rgb(0, 102, 0);font-family:courier new;" > 2) <br /><br /></span></li><li><span style="font-weight: bold;">Load Definitions from the Web, or save to disk</span><br />Ability to download a definition from URL<span style="color: rgb(0, 102, 0);font-family:courier new;" ><br />model.definitions.load_from_url(url, download_handler</span>)<br /><br />Ability to Save components to disk from the API<br /><span style="color: rgb(0, 102, 0);font-family:courier new;" >my_definition.save_as(path)</span><br /><br /></li><li><span style="font-weight: bold;">Know more about what your users are doing</span><br />New methods for detecting "Component Edit" mode<br /><span style="color: rgb(0, 102, 0);font-family:courier new;" >users_current_edit = model.active_path<br />edit_mode_transform = model.edit_transform<br /><br /></span>Easily determine if they're running in licensed Pro<br /><span style="color: rgb(0, 102, 0);font-family:courier new;" >is_licensed_pro = Sketchup.is_pro?</span><br /><br />New "model level" callbacks in ModelObserver<br /><span style="color: rgb(0, 102, 0);font-family:courier new;" >def onActivePathChanged(model) { # Detect edit mode }<br /></span> <span style="color: rgb(0, 102, 0);font-family:courier new;" >def onPlaceComponent(instance) { # Detect placements }</span><span style="color: rgb(0, 102, 0);font-family:courier new;" ><br /></span><span style="color: rgb(0, 102, 0);font-family:courier new;" >def onExplode(model) { # Detect group/component explode }<br /></span><span style="color: rgb(0, 102, 0);font-family:courier new;" >def onBeforeComponentSaveAs(instance) { # Add data on save as }</span><br /><span style="color: rgb(0, 102, 0);font-family:courier new;" >def onAfterComponentSaveAs(instance) { # Then clean up }</span><br /><br />Detect if they've turned off your extension via the AppObserver<br /><span style="color: rgb(0, 102, 0);font-family:courier new;" >def onUnloadExtension(extension_name)</span><br /><br /></li><li><span style="font-weight: bold;">Delete your scenes via the API</span><br /><span style="color: rgb(0, 102, 0);font-family:courier new;" >my_page.erase</span><br /><br /></li><li><span style="font-weight: bold;">Keep SketchUp in Synch</span><br /><span style="color: rgb(0, 102, 0);font-family:courier new;" >UI.refresh_inspectors # force complete UI update</span><br /><span style="color: rgb(0, 102, 0);font-family:courier new;" >my_definition.refresh_thumbnail # force thumb update<br /></span><span style="color: rgb(0, 102, 0);font-family:courier new;" >my_definition.invalidate_bounds # force bb update</span><br /><br /></li><li><span style="font-weight: bold;">Measure your groups regardless of their transform</span><br /><span style="color: rgb(0, 102, 0);font-family:courier new;" >untransformed_bb = my_group.local_bounds</span><br /><br /></li><li><span style="font-weight: bold;">Use middle mouse button in your custom tools</span><br /><span style="color: rgb(0, 102, 0);font-family:courier new;" >def onMButtonDown(flags, x, y, view) { # now works! }<br /></span><span style="color: rgb(0, 102, 0);font-family:courier new;" >def onMButtonUp(flags, x, y, view) { # now works! }</span><br /><br /></li><li><span style="font-weight: bold;">Send ruby console output to the standard out</span><br />If you start up SketchUp from the command line, you can pipe to standard error and see ruby puts statements appear for you.<br /><span style="color: rgb(0, 153, 0);font-family:courier new;" >Sketchup.exe > myRubyLog.txt</span><br /><br /></li><li><span style="font-weight: bold;">and your users will benefit from numerous stability fixes</span>!<br /><br /><div style="text-align: left;">Detailed documentation is coming soon... stay tuned!</div></li></ul>Unknownnoreply@blogger.com10tag:blogger.com,1999:blog-6313632118977055554.post-84653669600848049632008-11-05T09:38:00.000-08:002008-11-05T12:59:56.476-08:00Storing and Retrieving with AttributeDictionary<span class="byline-author" style="font-size:100%;">Posted by Mason Thrall, 3D Data Specialist</span><span style="font-size:100%;"><span style="color: rgb(0, 0, 0);font-family:Arial;"><br /><br />The AttributeDictionary class allows you to store information into a SketchUp Entity. A good way to demonstrate this is to store camera settings into an object in an AttributeDictionary, then activate a context menu on the Entity to get these camera parameters and return to the same camera. This is also a great way to visualize important views in 3D space.<br /><br />Our first method definition will create the camera geometry and put it into a group Entity. Then we will create an AttributeDictionary in the group and store the camera settings into the </span></span><span style="font-size:100%;"><span style="font-family:Arial;">AttributeDictionary.</span><br /></span><span style="font-size:100%;"><span style="font-family:Arial;"><br />We will start by getting the current camera parameters and storing them into variables:</span><br /><br /></span><span style="color: rgb(102, 102, 102);font-family:Courier New;font-size:85%;" >def reveal_view</span><span style="font-size:85%;"><br /></span><div style="text-align: justify;"> <span style="color: rgb(102, 102, 102);font-family:Courier New;font-size:85%;" > m=Sketchup.active_model</span><span style="font-size:85%;"><br /></span><span style="color: rgb(102, 102, 102);font-family:Courier New;font-size:85%;" > m.start_operation("reveal view")</span><span style="font-size:85%;"><br /></span><span style="color: rgb(102, 102, 102);font-family:Courier New;font-size:85%;" > ents=m.entities</span><span style="font-size:85%;"><br /></span><span style="color: rgb(102, 102, 102);font-family:Courier New;font-size:85%;" > view=m.active_view</span><span style="font-size:85%;"><br /></span><span style="color: rgb(102, 102, 102);font-family:Courier New;font-size:85%;" > cam=view.camera</span><span style="font-size:85%;"><br /></span><span style="color: rgb(102, 102, 102);font-family:Courier New;font-size:85%;" > up=cam.up</span><span style="font-size:85%;"><br /></span><span style="color: rgb(102, 102, 102);font-family:Courier New;font-size:85%;" > target=cam.target</span><span style="font-size:85%;"><br /></span><span style="color: rgb(102, 102, 102);font-family:Courier New;font-size:85%;" > persp=cam.perspective?</span><span style="font-size:85%;"><br /></span><span style="color: rgb(102, 102, 102);font-family:Courier New;font-size:85%;" > fov=cam.fov</span><span style="font-size:85%;"><br /></span><span style="color: rgb(102, 102, 102);font-family:Courier New;font-size:85%;" > eye=cam.eye</span><span style="font-size:85%;"><br /></span><span style="color: rgb(102, 102, 102);font-family:Courier New;font-size:85%;" > focus_ray=Geom::Vector3d.new(eye,target)</span><span style="font-size:85%;"><br /></span><span style="color: rgb(102, 102, 102);font-family:Courier New;font-size:85%;" > eye_axes=focus_ray.axes</span><br /></div><span style="color: rgb(102, 102, 102);font-family:Courier New;font-size:100%;" ><br /></span><span style="font-size:100%;"><span style="color: rgb(0, 0, 0);font-family:Arial;">Next, we'll make a simple representation of the camera, using the stored camera settings to determine the geometry,<br /><br /><span style="font-family:Courier New;"> </span></span></span><span style="color: rgb(102, 102, 102);font-family:Courier New;font-size:100%;" > </span><span style="font-size:85%;"><span style="font-family:Arial;"><span style="font-family:Courier New;"><span style="color: rgb(102, 102, 102);"> target_pointer = </span></span><span style="color: rgb(102, 102, 102);font-family:Courier New;" >ents.add_cline(eye,target)<br /></span></span></span><span style="color: rgb(102, 102, 102);font-family:Courier New;font-size:85%;" > </span><span style="font-size:85%;"><span style="font-family:Arial;"><span style="color: rgb(102, 102, 102);font-family:Courier New;" > eye_point = ents.</span></span></span><span style="font-size:85%;"><span style="font-family:Arial;"><span style="color: rgb(102, 102, 102);font-family:Courier New;" >add_cpoint(eye)</span></span><br /></span><span style="color: rgb(102, 102, 102);font-family:Courier New;font-size:85%;" > </span><span style="font-size:85%;"><span style="font-family:Arial;"><span style="color: rgb(102, 102, 102);font-family:Courier New;" > target_point = ents.add_cpoint(target)<br /></span></span></span><span style="color: rgb(102, 102, 102);font-family:Courier New;font-size:85%;" > </span><span style="font-size:100%;"><span style="font-family:Arial;"><span style="color: rgb(102, 102, 102);font-family:Courier New;" ><span style="font-size:85%;"> circle = ents.add_circle(eye, focus_ray, 20, 8)</span><br /><br /><span style="color: rgb(0, 0, 0);font-family:Arial;" >and store them into a group. For better organization, create a "cameras" layer and put the group into this layer. Also, be sure to lock the group, so the camera geometry can't move.<br /><span style="font-size:85%;"><br /></span><span style="color: rgb(102, 102, 102);font-family:Courier New;font-size:85%;" > camera_geom = []<br /> camera_geom.push(target_pointer,eye_point,target_point,circle)<br /> camera_geom.flatten!<br /> cam_group=ents.add_group(camera_geom)<br /> cam_group.name="camera"<br /> cam_layer=m.layers.add("cameras")<br /> cam_group.layer=cam_layer<br /> cam_group.locked=true</span><br /><br />We will then be storing the camera settings into the AttributeDictionary called "is_a_camera".<br />Create the AttributeDictionary in the cam_group Entity:<br /><br /><span style="color: rgb(102, 102, 102);font-size:85%;" ><span style="font-family:Courier New;"> is_camera=cam_group.attribute_dictionary("is_a_camera", true)</span></span><br /><br />The "true" indicates that the AttributeDictionary doesn't yet exist and needs to be created. AttributeDictionary objects store arbitrary amounts of key/value pairs. Add key/value pairs to AttributeDictionary for the camera settings,<br /><span style="font-size:85%;"><br /></span><span style="color: rgb(102, 102, 102);font-size:85%;" ><span style="font-family:Courier New;"> is_camera["cam"]=cam</span><br /><span style="font-family:Courier New;"> is_camera["up"]=up</span><br /><span style="font-family:Courier New;"> is_camera["target"]=target<br /></span></span></span></span></span></span><span style="font-size:85%;"><span style="font-family:Arial;"><span style="color: rgb(102, 102, 102);font-family:Courier New;" ><span style="color: rgb(0, 0, 0);font-family:Arial;" ><span style="color: rgb(102, 102, 102);"><span style="font-family:Courier New;"> is_camera["persp"]=persp</span></span></span></span></span><br /></span><span style="font-family:Courier New;font-size:85%;"> is_camera["fov"]=fov</span><br /><span style="font-family:Courier New;font-size:85%;"> is_camera["eye"]=eye</span><br /><span style="font-family:Courier New;font-size:85%;"> is_camera["focus_ray"]=focus_ray</span><br /><span style="font-family:Courier New;font-size:85%;"> is_camera["eye_axes"]=eye_axes</span></span><br /><br />and commit the undo operation.<br /><br /><span style="font-family:Courier New;"><span style="color: rgb(102, 102, 102);font-size:85%;" > m.commit_operation</span><span style="font-size:85%;"><br /></span><span style="color: rgb(102, 102, 102);"><span style="font-size:85%;">end<br /><br />UI.menu("Plugins").add_item("reveal view"){reveal_view}</span><br /><br /></span></span></span></span></span></span><span style="font-size:100%;"><span style="font-family:Arial;"><span style="color: rgb(102, 102, 102);font-family:Courier New;" ><span style="color: rgb(0, 0, 0);font-family:Arial;" >Finally, we add a context menu option to call a method only on objects which contain the </span></span></span></span><span style="font-size:100%;"><span style="font-family:Arial;"><span style="color: rgb(102, 102, 102);font-family:Courier New;" ><span style="color: rgb(0, 0, 0);font-family:Arial;" >AttributeDictionary </span></span></span></span><span style="font-size:100%;"><span style="font-family:Arial;"><span style="color: rgb(102, 102, 102);font-family:Courier New;" ><span style="color: rgb(0, 0, 0);font-family:Arial;" >"is_a_camera". If the </span></span></span></span><span style="font-size:100%;"><span style="font-family:Arial;"><span style="color: rgb(102, 102, 102);font-family:Courier New;" ><span style="color: rgb(0, 0, 0);font-family:Arial;" >AttributeDictionary exists,<span style="font-family:Arial;"> then the option "go to view" is added to the context menu.</span></span></span></span><br /></span><span style="font-size:100%;"><span style="font-family:Arial;"><span style="color: rgb(102, 102, 102);font-family:Courier New;" ><span style="color: rgb(0, 0, 0);font-family:Arial;" ><span style="color: rgb(102, 102, 102);font-family:Courier New;" ><br /><blockquote></blockquote><span style="font-size:85%;">UI.add_context_menu_handler do |menu|<br /> select_one=Sketchup.active_model.selection[0]<br /> if select_one.class==Sketchup::Group<br /> if select_one.attribute_dictionary("is_a_camera",false)!=nil<br /> menu.add_item("go to view"){go_to_view(select_one)}<br /> end<br /> end<br />end</span><br /><br /></span></span></span></span></span><span style="font-size:100%;"><span style="font-family:Arial;"><span style="color: rgb(102, 102, 102);font-family:Courier New;" ><span style="color: rgb(0, 0, 0);font-family:Arial;" ><span style="font-family:Arial;">When this is clicked, it calls the go_to_view() method. </span></span></span></span></span><span style="font-size:100%;"><span style="font-family:Arial;"><span style="color: rgb(102, 102, 102);font-family:Courier New;" ><span style="color: rgb(0, 0, 0);font-family:Arial;" >Our second method, </span></span></span></span><span style="font-size:100%;"><span style="font-family:Arial;"><span style="color: rgb(102, 102, 102);font-family:Courier New;" ><span style="color: rgb(0, 0, 0);font-family:Arial;" ><span style="font-family:Arial;">go_to_view(),</span></span></span></span></span><span style="font-size:100%;"><span style="font-family:Arial;"><span style="color: rgb(102, 102, 102);font-family:Courier New;" ><span style="color: rgb(0, 0, 0);font-family:Arial;" > will take a selected Entity and recall the values stored in the </span></span></span></span><span style="font-size:100%;"><span style="font-family:Arial;"><span style="color: rgb(102, 102, 102);font-family:Courier New;" ><span style="color: rgb(0, 0, 0);font-family:Arial;" >AttributeDictionary </span></span></span></span><span style="font-size:100%;"><span style="font-family:Arial;"><span style="color: rgb(102, 102, 102);font-family:Courier New;" ><span style="color: rgb(0, 0, 0);font-family:Arial;" >"is_a_camera". It then uses these values to return to the stored camera position and settings.</span></span></span><br /></span><span style="font-size:100%;"><span style="font-family:Arial;"><span style="color: rgb(102, 102, 102);font-family:Courier New;" ><span style="color: rgb(0, 0, 0);font-family:Arial;" ><span style="font-family:Courier New;"><span style="color: rgb(102, 102, 102);"><br /><span style="font-size:85%;">def go_to_view(sel)<br /> info=sel.attribute_dictionary("is_a_camera")<br /> m=Sketchup.active_model<br /> view=m.active_view<br /> view.camera=Sketchup::Camera.new(info["eye"],info["target"],<br /> info["up"],info["persp"],info["fov"])<br />end</span></span></span></span></span></span></span>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6313632118977055554.post-69607333383224488152008-10-23T14:48:00.000-07:002008-10-23T15:34:14.818-07:00wxSU and You<span class="byline-author">Posted by Sang Ahn, SketchUp Software Engineer</span><br /><br />A lot of you are already using the <a href="http://code.google.com/apis/sketchup/docs/developers_guide/classes/UI/WebDialog.html" id="iban" title="WebDialog">WebDialog</a> of the <a href="http://code.google.com/apis/sketchup/" id="r9bq" title="SketchUp Ruby API">SketchUp Ruby API</a> to extend the user interface of SketchUp. Let's say you want something with a more native-application feel to it. Thanks to Peter Ellis of <a href="http://apps1.eere.energy.gov/buildings/energyplus/energy_design_plugin.cfm" id="ev4h" title="NREL">NREL</a>, there's a neat plugin out there that allows you to do this. It comes with useful GUI elements that you can use in your own plugins such as a file-open dialog box, progress bar, etc.<div><br /><table style="width: auto;"><tbody><tr><td><img src="http://lh3.ggpht.com/sanga20254/SQDyTM_eXHI/AAAAAAAAABU/bQH3K3fU_P4/s400/Picture%202.png" /></td></tr><tr><td style="font-family: arial,sans-serif; font-size: 11px; text-align: center;"><br /></td></tr></tbody></table><br /><div><div><div><div>It's built on top of <a href="http://wxruby.rubyforge.org/" id="xgq8" title="wxRuby">wxRuby</a>, so your UI implementation is cross-platform and you won't have to do any extra work. Best of all, it's <a href="http://sourceforge.net/projects/wxsu/" id="wj4g" title="FREE">FREE</a>! Hats off to Peter.<br /></div></div></div></div></div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6313632118977055554.post-10202869519990380292008-10-21T09:42:00.000-07:002008-10-23T15:55:27.664-07:00Animate Yo' Cheese<span class="byline-author">Posted by Scott Lininger, SketchUp Engineer<br /><br />Drawing <a id="yzsf" title="food" href="http://sketchup.google.com/3dwarehouse/cldetails?mid=1057282acb5f8292dfbd9fb701f55f19&prevstart=0&scoring=p">foodstuffs</a> in SketchUp is fantastically cool, but at the end of the day you wind up with a meal that is, sigh, static. You can push your food about <a id="jh08" title="manually" href="http://sketchup.google.com/support/bin/answer.py?answer=94859">manually</a>, of course, or you can hide or change its appearance by using <a id="j.b0" title="scenes" href="http://sketchup.google.com/support/bin/answer.py?hl=en&answer=39656">scenes</a>, but wouldn't it be fun if there were a way to make it animate on its own?<br /><br />There are many plugins out there to help you create certain kinds of animations (<a id="lwjp" title="Sketchy Physics" href="http://code.google.com/p/sketchyphysics/">Sketchy Physics</a> and <a id="is0k" title="Podium" href="http://www.suplugins.com/index.php?p=product&id=15&parent=0">Podium</a> are a couple that come to mind), but what if you're a gastric megalomaniac? What if you want to animate food using Ruby and thus have TOTAL CONTROL?<br /><br />Glad you asked. Let's sling some code (and some <a id="fgxo" title="gouda" href="http://sketchup.google.com/3dwarehouse/details?mid=40f2597ec07a8750a8aae67c3e4a4955&prevstart=0">gouda</a>).<br /><br /><span style=""><strong>Our Example: Black hole ate my cheese</strong></span><br /><br />We're going to write a ruby script that allows you to right-click on any component and suck it magically to the model origin. (The origin is where the red, green, and blue axes of your model intersect.) It will work on any component, but especially well on cheese, 'cause it's <a id="f0b0" title="delicious" href="http://uk.youtube.com/watch?v=ogjfxhDiSEg&feature=related">delicious</a>.<br /><br /><span style=""><strong>Step 1: Create our "move" method</strong><br /><br />The first thing we need to realize our dream of ballistic curds is code that moves a component one step at a time toward a target. There are lots of ways to create these kinds of <a id="o-ye" title="tweening animations" href="http://en.wikipedia.org/wiki/Tweening">tweening animations</a>. We're going to use a simple averaging method, where the object moves halfway toward the destination with each call...<br /><br />blackhole.rb<br /><span style=";font-family:courier new;font-size:85%;" ><br /># Define our method that does the transform.<br />def move_halfway_toward(entity, target_pt)<br /> current_pt = entity.transformation.origin<br /> halfway = Geom::Point3d.linear_combination(0.5, current_pt, 0.5,<br /> target_pt)<br /><br /> # Undo our current transform with inverse,<br /> # then move to the halfway point.<br /> entity.transform! entity.transformation.inverse<br /> entity.transform! Geom::Transformation.new halfway<br /><br /> # Invalidate our view to force SU to refresh the screen. <br /> Sketchup.active_model.active_view.invalidate<br /><br />end <br /><br /># Create a rightclick handler that'll activate it.<br />UI.add_context_menu_handler do |context_menu|<br /> context_menu.add_item('Move halfway to origin') {<br /> entity = Sketchup.active_model.selection[0]<br /> origin_pt = Geom::Point3d.new 0, 0, 0<br /> move_halfway_toward(entity, origin_pt)<br /> }<br />end<br /></span><br /><br />Create this new file called blackhole.rb, and save it in your <a id="i1h." title="SketchUp/Plugins directory" href="http://code.google.com/apis/sketchup/docs/gsrubyfaq.html">SketchUp/Plugins directory</a>. When you restart SketchUp, you can now right click on Bryce (or any other component), and activate our new command. Do it over and over again and you can start to visualize a wheel of cheddar blazing through space. (Insert evil laugh here)<br /><br /><strong><span style="">Step 2: use UI.start_timer to provide a timeline</strong><br /><br />Now we add a bit more to make the method fire again and again and again, auto-magically. The secret is SketchUp's <a id="ma_-" title="UI.start_timer" href="http://download.sketchup.com/OnlineDoc/gsu6_ruby/Docs/ruby-ui.html#start_timer">UI.start_timer</a> method, which instructs the API to call a snippet of code on a regular basis.<br /><br />blackhole.rb (add these to the bottom of the existing file)<br /><span style=";font-family:courier new;font-size:85%;" ><br /># Define our method that starts an animation.<br />def start_animation(entity, target_pt)<br /><br /> # This calls our code snippet once every 10th of a second... <br /> frames_per_second = 10.0<br /> pause_length = 1.0 / frames_per_second<br /><br /> timer_id = UI.start_timer(pause_length, true) {<br /> move_halfway_toward(entity, target_pt)<br /> # If we're within an inch of the origin, turn off the timer.<br /> new_location = entity.transformation.origin<br /> distance_from_target = new_location.distance target_pt<br /> if distance_from_target < 1.0<br /> UI.stop_timer timer_id<br /> end<br /> }<br />end<br /><br /># Create a rightclick handler that'll activate it.<br />UI.add_context_menu_handler do |context_menu|<br /> context_menu.add_item('Animate to origin') {<br /> entity = Sketchup.active_model.selection[0]<br /> origin_pt = Geom::Point3d.new 0, 0, 0<br /> start_animation(entity, origin_pt)<br /> }<br />end<br /></span><br /><br /><span style="">Restart SU, <a id="a1mc" title="download some cheese" href="http://sketchup.google.com/3dwarehouse/search?q=cheese&btnG=Search&styp=m&reps=1"><span style="">download some cheese</a><span style="">, and get to animating! If you're motivated, you could try these fun, extra credit assignments:<br /><ul><li><span style="">Experiment with the frames_per_second to change the speed. (easy)</li><br /><li><span style="">Use <a id="gr.x" title="UI.inputbox" href="http://download.sketchup.com/OnlineDoc/gsu6_ruby/Docs/ruby-ui.html#inputbox"><span style="">UI.inputbox</a><span style=""> to ask for an X, Y, Z location to animate to. (medium) </li><br /><li><span style="">Send a <a id="w:zk" title="raytest" href="http://download.sketchup.com/OnlineDoc/gsu6_ruby/Docs/ruby-model.html#raytest"><span style="">raytest</a><span style=""> from the base of your cheese downward, to determine the nearest "ground" geometry, and have the cheese animate to land right on it! (tough) </li><br /><li><span style="">Use a <a id="s3kk" title="custom tool" href="http://download.sketchup.com/OnlineDoc/gsu6_ruby/Docs/ruby-tool.html"><span style="">custom tool</a><span style=""> to activate animations with a single click! (semi-soft, with a salty rind) </li></ul><br /><div></div>Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-6313632118977055554.post-9164675640391018782008-09-29T16:16:00.000-07:002008-09-29T16:47:55.874-07:00Reading Textures from a SketchUp Model Using the Reader SDK<span class="byline-author">Posted by Sang Ahn, SketchUp Software Engineer</span><br /><br /><div>In case you haven't looked yet, we have an <a id="h96l" href="http://code.google.com/apis/sketchup/docs/downloadsdksubmit.html" title="SDK">SDK</a> that allows you to read SketchUp files using a C++ interface. This allows you to write your own exporter for Google SketchUp or an importer for another <a id="q9v." href="http://www.luxology.com/whatismodo/plugins/plugin_sketchup_importer.aspx" title="application">application</a> to read SketchUp files. Oftentimes you want all the polygons on your exported model to be triangles. Since most faces in a SketchUp model are quadrilateral polygons, you will need to triangulate the faces. Also, if a face has a texture you will want the uvq coordinates of the triangulated faces as well. Besides the face and the mesh that represents the face after it is triangulated, there are several other objects in the SketchUp Reader SDK that are used to read the uvq texture coordinates of a face. For example, there is the texture writer object. This is the object used to write out the face textures to disk. In order to retrieve the uvq texture coordinates of the mesh you also need a UV helper object and also a perspective object.<br />First, using the SkechUp document object, create the texture writer object:</div><br /><code><br />ISkpApplication* sketchup_application = NULL;<br />sketchup_document->get_Application(&sketchup_application);<br />ISkpTextureWriter* texture_writer = NULL;<br />sketchup_application->CreateTextureWriter(&texture_writer);<br /></code><br /><div>Next, retrieve the ISkpCorrectPerspective interface of the texture writer:</div><br /><code><br /><div>ISkpCorrectPerspective* perspective = NULL;<br />texture_writer->QueryInterface(IID_ISkpCorrectivePerspective,<br />                               &perspective);<br /></div><br /></code><br /><div>For each face retrieve its UV helper object using the perspective object:</div><br /><code><br /><div>ISkpUVHelper* uv_helper = NULL;<br />face->GetUVHelper(face,<br />                  true, // front face<br />                  perspective,<br />                  &uv_helper);<br /></div><br /></code><br /><div>Finally, create the triangulated mesh:</div><br /><code><br /><div>ISkpPolygonMesh* mesh = NULL;<br />face->CreateMesh(<br />     PolygonMeshPoints |<br />     PolygonMeshUVQFront |<br />     PolygonMeshUVQBack,<br />     perspective, &mesh);<br /></div><br /></code><br /><div>Index through the vertices of the mesh and retrieve the position value of each vertex. If the face object belongs to a group or a component instance, the position needs to be transformed. The homogeneous transformation used to transform the position is the aggregate of the transformation of the parent group or component instance. If the parent is nested in other group(s) or component instance(s) then you the need to aggregate all the transformations.</div><br /><code><br /><div>double position[] = {0, 0, 0};<br />mesh->_GetPoint(index, position);<br /></div><br /></code><br /><div>Finally, retrieve the uvq value that corresponds to the vertex position. The uvq value does not need to be transformed like the position value:</div><br /><code><br /><div>double uvq[] = {0, 0, 0};<br />uv_helper->GetFrontUVQ(<br />     position[0],<br />     position[1],<br />     position[2],<br />     &uvq[0],<br />     &uvq[1],<br />     &uvq[1]);<br /></div><br /></code><br /><div style="text-align: auto;">Stay tuned for further tips and tricks.</div><br /><br>Unknownnoreply@blogger.com16tag:blogger.com,1999:blog-6313632118977055554.post-61837930724246886812008-03-21T15:47:00.000-07:002008-03-21T15:49:39.167-07:00Inserting an External SketchUp Component (of some Pants)Posted by Scott Lininger, SketchUp Software Engineer<br /><br />You've just SketchUped an <i id="c-ny">amazing</i> <a title="Robot Monkey" href="http://sketchup.google.com/3dwarehouse/details?mid=64e8de6ff3a7f4bd4a61afe7d0ea14a6&prevstart=0" id="e_jw">Robot Monkey</a>, and you're ready to include him in your company brochure. Excitedly, you email the <a title="3D PDF" href="http://wiki.renderplus.com/index.php?title=RPS_3D_PDF" id="mr6y">3D PDF</a> over to the legal department for approval, and you're faced with the biggest letdown of the whole project. They love it, they say, but due to new sensitivity around artificial animal companion rights, all Robot Monkeys must be modestly clothed before being released to the public.<br /><br />Fortunately, you anticipated this problem and have a very nice model of some <a title="Monkey Pants" href="http://sketchup.google.com/3dwarehouse/details?mid=3a527cc9f19c7c4bce48c8156131b77c&prevstart=0" id="lrrk">respectable trousers</a>. Now you just need to insert them into your model, preferably by using the Ruby API.<br /><br />If you know the exact file path to the SKP file that you'd like to insert, your job is simple. Just type these lines into the Ruby console (replace the "C:\pants.skp" with the absolute path to your component.)<br /><br /><span id="gvhv" style="font-family:Courier New;font-size:85%;">pants_def = Sketchup.active_model.definitions.load("C:\pants.skp")</span><span style="font-size:85%;"><br /></span><span id="jndq" style="font-family:Courier New;font-size:85%;">Sketchup.active_model.place_component(pants_def)</span><br /><br />If everything typed out okay, then you should be inserting some snazzy pants using the standard "place component" tool. Hooray!<br /><br />"But that's not very useful," you say, "It's easier to use the Component Browser to do <i id="x08_">that</i>! What if I don't know the path to my pants? What if you want to place my pants in a particular spot?"<br /><br />Okay, okay. Here's a more complete snippet that keeps the power in the control of the Ruby.<br /><br /><span id="f_i1" style="color: rgb(61, 133, 198);font-size:85%;" ><span id="que0" style="font-family:Courier New;"># First, load our pants (heh). This time we'll search for<br /># the file inside our Components directory.</span></span><span style="font-size:85%;"><br /></span><span id="z5-x" style="font-family:Courier New;font-size:85%;">pants_path = Sketchup.find_support_file "pants.skp" ,"Components"</span><span style="font-size:85%;"><br /></span><span id="db:8" style="font-family:Courier New;font-size:85%;">pants_def = model.definitions.load pants_path</span><span style="font-size:85%;"><br /></span><span id="a89k" style="color: rgb(56, 118, 29);font-size:85%;" ><br /></span><span id="gfi7" style="color: rgb(61, 133, 198);font-size:85%;" ><span id="f2tt" style="font-family:Courier New;"># Then define a location, and place our pants there.</span></span><span style="font-size:85%;"><br /></span><span id="lq6:" style="font-family:Courier New;font-size:85%;">pants_location = Geom::Point3d.new 100,200,0</span><span style="font-size:85%;"><br /></span><span id="tnaa" style="font-family:Courier New;font-size:85%;"> transform = Geom::Transformation.new </span><span id="dl_a" style="font-family:Courier New;font-size:85%;">pants_location</span><span style="font-size:85%;"><br /></span><span id="f2z3" style="font-family:Courier New;font-size:85%;">entities = Sketchup.active_model.active_entities</span><span style="font-size:85%;"><br /></span><span id="i3ww" style="font-family:Courier New;font-size:85%;">instance = entities.add_instance pants_def, transform</span><span style="font-size:85%;"><br /></span><br />And at long last, your Monkey has Pants, and you're the new company hero!Unknownnoreply@blogger.com8