<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;CEUDRno5eyp7ImA9WxNbEk8.&quot;"><id>tag:blogger.com,1999:blog-6313632118977055554</id><updated>2009-11-14T10:11:17.423-08:00</updated><title type="text">Google SketchUp API Blog</title><subtitle type="html">The latest news from the SketchUp API team.</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://sketchupapi.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://sketchupapi.blogspot.com/" /><link rel="hub" href="http://pubsubhubbub.appspot.com/" /><author><name>A Googler</name><email>noreply@blogger.com</email></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>19</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><link rel="self" href="http://feeds.feedburner.com/GoogleSketchupApiBlog" type="application/atom+xml" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><entry gd:etag="W/&quot;DU4DSX0_fyp7ImA9WxNUEUU.&quot;"><id>tag:blogger.com,1999:blog-6313632118977055554.post-7497235910474665065</id><published>2009-11-02T10:45:00.000-08:00</published><updated>2009-11-02T10:52:58.347-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-11-02T10:52:58.347-08:00</app:edited><title>SketchUp Ruby API site updated for SketchUp 7.1</title><content type="html">&lt;span style=";font-family:georgia;font-size:130%;"  &gt;SketchUp 7.1 launched back in September.  Last week, we updated the &lt;/span&gt;&lt;span style="font-size:130%;"&gt;&lt;a style="font-family: georgia;" title="SketchUp ruby API Site" target="_blank" href="http://code.google.com/apis/sketchup/" id="afld"&gt;SketchUp ruby API Site&lt;/a&gt;&lt;/span&gt;&lt;span style=";font-family:georgia;font-size:130%;"  &gt; 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 &lt;/span&gt;&lt;span style="font-size:130%;"&gt;&lt;a style="font-family: georgia;" title="API release notes" target="_blank" href="http://code.google.com/apis/sketchup/docs/releases.html" id="p6-q"&gt;API release notes&lt;/a&gt;&lt;/span&gt;&lt;span style=";font-family:georgia;font-size:130%;"  &gt;.   &lt;/span&gt;&lt;span style="font-size:130%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=";font-family:georgia;font-size:130%;"  &gt;We would also like to say "Thanks!!" to the &lt;/span&gt;&lt;span style="font-size:130%;"&gt;&lt;a style="font-family: georgia;" target="_blank" title="SketchUcation community" href="http://forums.sketchucation.com/" id="n4oj"&gt;SketchUcation community&lt;/a&gt;&lt;/span&gt;&lt;span style=";font-family:georgia;font-size:130%;"  &gt; and the guys over at &lt;/span&gt;&lt;span style="font-size:130%;"&gt;&lt;a style="font-family: georgia;" title="Smustard.com" target="_blank" href="http://www.smustard.com/" id="a1.:"&gt;Smustard.com&lt;/a&gt;&lt;/span&gt;&lt;span style=";font-family:georgia;font-size:130%;"  &gt; for sending us Ruby documentation fixes.   SketchUp's amazing developer community continues to be one of the best "features" of the Ruby API.&lt;/span&gt;&lt;span style="font-size:130%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=";font-family:georgia;font-size:130%;"  &gt;~Bryce Stout &lt;/span&gt;&lt;span style="font-size:130%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=";font-family:georgia;font-size:130%;"  &gt;Product Manager&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6313632118977055554-7497235910474665065?l=sketchupapi.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleSketchupApiBlog/~4/OSru09oh31I" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://sketchupapi.blogspot.com/feeds/7497235910474665065/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6313632118977055554&amp;postID=7497235910474665065" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6313632118977055554/posts/default/7497235910474665065?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6313632118977055554/posts/default/7497235910474665065?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleSketchupApiBlog/~3/OSru09oh31I/sketchup-ruby-api-site-updated-for.html" title="SketchUp Ruby API site updated for SketchUp 7.1" /><author><name>Sketchup Guide Bryce</name><uri>http://www.blogger.com/profile/05828718671079688877</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="05576126011266499069" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://sketchupapi.blogspot.com/2009/11/sketchup-ruby-api-site-updated-for.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUIHQXk5cCp7ImA9WxJbF04.&quot;"><id>tag:blogger.com,1999:blog-6313632118977055554.post-1622232743952845326</id><published>2009-07-23T16:18:00.000-07:00</published><updated>2009-07-27T16:32:10.728-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-07-27T16:32:10.728-07:00</app:edited><title>Dynamic Components that react to scene (aka page) changes</title><content type="html">&lt;span class="byline-author"&gt;&lt;/span&gt;&lt;meta equiv="Content-Type" content="text/html; charset=utf-8"&gt;&lt;meta name="ProgId" content="Word.Document"&gt;&lt;meta name="Generator" content="Microsoft Word 11"&gt;&lt;meta name="Originator" content="Microsoft Word 11"&gt;&lt;link rel="File-List" href="file:///C:%5CDOCUME%7E1%5Csnicolo%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_filelist.xml"&gt;&lt;!--[if gte mso 9]&gt;&lt;xml&gt;  &lt;w:worddocument&gt;   &lt;w:view&gt;Normal&lt;/w:View&gt;   &lt;w:zoom&gt;0&lt;/w:Zoom&gt;   &lt;w:punctuationkerning/&gt;   &lt;w:validateagainstschemas/&gt;   &lt;w:saveifxmlinvalid&gt;false&lt;/w:SaveIfXMLInvalid&gt;   &lt;w:ignoremixedcontent&gt;false&lt;/w:IgnoreMixedContent&gt;   &lt;w:alwaysshowplaceholdertext&gt;false&lt;/w:AlwaysShowPlaceholderText&gt;   &lt;w:compatibility&gt;    &lt;w:breakwrappedtables/&gt;    &lt;w:snaptogridincell/&gt;    &lt;w:wraptextwithpunct/&gt;    &lt;w:useasianbreakrules/&gt;    &lt;w:dontgrowautofit/&gt;    &lt;w:usefelayout/&gt;   &lt;/w:Compatibility&gt;   &lt;w:browserlevel&gt;MicrosoftInternetExplorer4&lt;/w:BrowserLevel&gt;  &lt;/w:WordDocument&gt; &lt;/xml&gt;&lt;![endif]--&gt;&lt;!--[if gte mso 9]&gt;&lt;xml&gt;  &lt;w:latentstyles deflockedstate="false" latentstylecount="156"&gt;  &lt;/w:LatentStyles&gt; &lt;/xml&gt;&lt;![endif]--&gt;&lt;style&gt; &lt;!--  /* 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;} --&gt; &lt;/style&gt;&lt;!--[if gte mso 10]&gt; &lt;style&gt;  /* 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;} &lt;/style&gt; &lt;![endif]--&gt;  &lt;p class="MsoNormal"&gt;Have you ever wanted to have a Dynamic Component that reacts to Scene changes?&lt;/p&gt;
&lt;br /&gt;&lt;p class="MsoNormal"&gt;
&lt;br /&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;Well, this blogpost tells you how to write one (thanks to John Clemens for the idea).&lt;/p&gt;&lt;p class="MsoNormal"&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;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.&lt;/p&gt;
&lt;br /&gt;&lt;p class="MsoNormal"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;
&lt;br /&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;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.&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;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.&lt;/p&gt;
&lt;br /&gt;&lt;p class="MsoNormal"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;
&lt;br /&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;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.&lt;/p&gt;
&lt;br /&gt;&lt;p class="MsoNormal"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;
&lt;br /&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;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.&lt;/p&gt;&lt;p class="MsoNormal"&gt;
&lt;br /&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;Download the example model &lt;a href="http://sketchup.google.com/3dwarehouse/details?mid=1f2c6afc778c660a8bbad0f4df6effc0"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;br /&gt;&lt;p class="MsoNormal"&gt;
&lt;br /&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;Code snippet below
&lt;br /&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;----------------------------------------------------------------&lt;/p&gt;&lt;p class="MsoNormal"&gt;# Copyright 2005-2008, Google, Inc.
&lt;br /&gt;
&lt;br /&gt;# Permission to use, copy, modify, and distribute this software for
&lt;br /&gt;# any purpose and without fee is hereby granted, provided that the above
&lt;br /&gt;# copyright notice appear in all copies.
&lt;br /&gt;
&lt;br /&gt;# THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
&lt;br /&gt;# IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
&lt;br /&gt;# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
&lt;br /&gt;#
&lt;br /&gt;
&lt;br /&gt;# This code snippets allows you to have Dynamic Components
&lt;br /&gt;# that modify themselves based on a Scene Change
&lt;br /&gt;#
&lt;br /&gt;# They need to have at the top level the following attributes
&lt;br /&gt;# "scene_change" a boolean value that if true force the DC to react to scene changes
&lt;br /&gt;# and if false has the DC ignore the scene change
&lt;br /&gt;# and
&lt;br /&gt;# "scene_trigger" which is the index that is incremented every time there is a scene change and
&lt;br /&gt;# it is used to change attributes for the DC.
&lt;br /&gt;#
&lt;br /&gt;#
&lt;br /&gt;# Author: Simone Nicolo
&lt;br /&gt;
&lt;br /&gt;require 'sketchup.rb'
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;# Define the Frame Change Observer which is documented in the Pages class.
&lt;br /&gt;class FrameChangeObserver
&lt;br /&gt;
&lt;br /&gt;def initialize
&lt;br /&gt;# @current page is used to make sure that the observer is only triggered by page changes
&lt;br /&gt;# This is to workaround the PC bug that does not correctly populate the fromPage variable in the
&lt;br /&gt;# callback to frameChange.
&lt;br /&gt;@current_page = Sketchup.active_model.pages.selected_page
&lt;br /&gt;end
&lt;br /&gt;
&lt;br /&gt;# Callback triggered by the Frame change observer.
&lt;br /&gt;# fromPage is populated with the page we were coming from, toPage is
&lt;br /&gt;# populated with the page we were transitioning to
&lt;br /&gt;# and percent done contains the percentage of the transition that
&lt;br /&gt;# has completed.
&lt;br /&gt;def frameChange(fromPage, toPage, percent_done)
&lt;br /&gt;# If there has been a page change and it has completed
&lt;br /&gt;if (not toPage.nil? and percent_done == 1) then
&lt;br /&gt;  if @current_page != toPage then
&lt;br /&gt;      #update the current page
&lt;br /&gt;      @current_page = toPage
&lt;br /&gt;      #find the DCs that need redrawing, and redraw them.
&lt;br /&gt;      find_dc_for_redraw 
&lt;br /&gt;  end
&lt;br /&gt;end
&lt;br /&gt;end
&lt;br /&gt;
&lt;br /&gt;# This function finds all the DC's that need to be redrawn based on a scene transition and
&lt;br /&gt;# on the boolean scene_change attribute if scene_change is true, change and redraw
&lt;br /&gt;# the DC on a scene transition, if it is false do not change or redraw the DC.
&lt;br /&gt;def find_dc_for_redraw
&lt;br /&gt;entities_list = Sketchup.active_model.entities
&lt;br /&gt;if entities_list != []
&lt;br /&gt;  # For all the entities in the model
&lt;br /&gt;  entities_list.each do |item|
&lt;br /&gt;    type = item.typename
&lt;br /&gt;      case type
&lt;br /&gt;      # Find the Dynamic Component instances
&lt;br /&gt;      when "ComponentInstance"
&lt;br /&gt;        if not item.attribute_dictionaries.nil?
&lt;br /&gt;          attributes = item.attribute_dictionaries[DICTIONARY_NAME]
&lt;br /&gt;          # If they have a scene_change attribute that contains true
&lt;br /&gt;          if (not attributes.nil? and attributes[SCENE_CHANGE] == 1.to_s)
&lt;br /&gt;            # Increment the scene_trigger attribute.
&lt;br /&gt;            # Here we are allowing the scene trigger attributes to only have the values
&lt;br /&gt;            # 1, 2, 3, and 4.
&lt;br /&gt;            attributes[SCENE_TRIGGER] = (((attributes[SCENE_TRIGGER].to_i+1)%5)).to_s
&lt;br /&gt;            if attributes[SCENE_TRIGGER] == "0" then
&lt;br /&gt;              attributes[SCENE_TRIGGER] = 1.to_s
&lt;br /&gt;            end
&lt;br /&gt;            # Redraw the DC using the $dc_observers global variable.
&lt;br /&gt;            $dc_observers.get_latest_class.redraw_with_undo(item)
&lt;br /&gt;          end
&lt;br /&gt;        end
&lt;br /&gt;    end
&lt;br /&gt;  end
&lt;br /&gt;else
&lt;br /&gt;  UI.messagebox("There are no entities in this model!")
&lt;br /&gt;end
&lt;br /&gt;end
&lt;br /&gt;
&lt;br /&gt;end
&lt;br /&gt;
&lt;br /&gt;if not file_loaded? 'scenes.rb'
&lt;br /&gt;# Useful constants
&lt;br /&gt;# Dynamic Components dictionary name
&lt;br /&gt;DICTIONARY_NAME = "dynamic_attributes"
&lt;br /&gt;# Boolean attribute that turns on and off the reaction to a scene change for the DC
&lt;br /&gt;SCENE_CHANGE = "scene_change"
&lt;br /&gt;# Index attribute for the DC that is used to drive changes in the DC.
&lt;br /&gt;SCENE_TRIGGER = "scene_trigger"
&lt;br /&gt;# Attach the frame chage observer to the global Pages object.
&lt;br /&gt;id = Sketchup::Pages.add_frame_change_observer(FrameChangeObserver.new)
&lt;br /&gt;file_loaded 'scenes.rb'
&lt;br /&gt;end
&lt;br /&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;
&lt;br /&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6313632118977055554-1622232743952845326?l=sketchupapi.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleSketchupApiBlog/~4/z7LNN-JeVq0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://sketchupapi.blogspot.com/feeds/1622232743952845326/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6313632118977055554&amp;postID=1622232743952845326" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6313632118977055554/posts/default/1622232743952845326?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6313632118977055554/posts/default/1622232743952845326?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleSketchupApiBlog/~3/z7LNN-JeVq0/dynamic-components-that-react-to-scene.html" title="Dynamic Components that react to scene (aka page) changes" /><author><name>Simone (snicolo)</name><uri>http://www.blogger.com/profile/15177631670413453224</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10534953208891399375" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://sketchupapi.blogspot.com/2009/07/dynamic-components-that-react-to-scene.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUcNQ3Y5cCp7ImA9WxJSF0Q.&quot;"><id>tag:blogger.com,1999:blog-6313632118977055554.post-7778304769737505225</id><published>2009-05-07T08:22:00.001-07:00</published><updated>2009-05-08T07:31:32.828-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-05-08T07:31:32.828-07:00</app:edited><title>Champion the 3D Web using COLLADA Contest</title><content type="html">Our friends over at the Khronos group are holding a &lt;a href="http://www.colladacontest.com/" id="u.30" target="_blank" title="Champion the 3D Web using COLLADA Contest"&gt;Champion the 3D Web using COLLADA Contest&lt;/a&gt;.  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 &lt;a href="http://www.siggraph.org/s2009/" id="glxz" target="_blank" title="Siggraph"&gt;Siggraph&lt;/a&gt; this year in New Orleans.  The contest is sponsored by the &lt;a href="http://www.khronos.org/" target="_blank" title="contest site"&gt;Khronos Group&lt;/a&gt; and the &lt;a href="http://immersiveeducation.org/" target="_blank" title="contest site"&gt;Media Grid Immersive Education Initiative&lt;/a&gt;. Please check out the &lt;a href="http://www.colladacontest.com/" id="ikpi" target="_blank" title="contest site"&gt;contest site&lt;/a&gt; for full details.&lt;br /&gt;&lt;b&gt;&lt;br /&gt;Using SketchUp to enter the contest&lt;/b&gt;&lt;br /&gt;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:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;  Export your SketchUp model to KMZ.  &lt;/li&gt;&lt;li&gt;  Change the file extension from ".kmz" to ".zip".&lt;/li&gt;&lt;li&gt;Double-click on the ZIP file.&lt;/li&gt;&lt;li&gt;Double-click on the "models" folder.  &lt;/li&gt;&lt;li&gt;Locate the DAE file. Copy and paste this file to your Desktop.&lt;/li&gt;&lt;li&gt;  Check your file's appearance in a COLLADA viewer like &lt;a title="Swirl X3D Viewer©" target="_blank" href="http://www.pinecoast.com/swview.htm" id="ey6p"&gt;Swirl X3D Viewer©&lt;/a&gt;   &lt;/li&gt;&lt;li&gt;  Submit your model to the contest.  &lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;Good Luck!&lt;br /&gt;Bryce Stout&lt;br /&gt;Product Manager&lt;br /&gt;Google&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6313632118977055554-7778304769737505225?l=sketchupapi.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleSketchupApiBlog/~4/_eUYLXyVcJ4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://sketchupapi.blogspot.com/feeds/7778304769737505225/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6313632118977055554&amp;postID=7778304769737505225" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6313632118977055554/posts/default/7778304769737505225?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6313632118977055554/posts/default/7778304769737505225?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleSketchupApiBlog/~3/_eUYLXyVcJ4/champion-3d-web-using-collada-contest.html" title="Champion the 3D Web using COLLADA Contest" /><author><name>Sketchup Guide Bryce</name><uri>http://www.blogger.com/profile/05828718671079688877</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="05576126011266499069" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://sketchupapi.blogspot.com/2009/05/champion-3d-web-using-collada-contest.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0INQHYzfCp7ImA9WxJTE0k.&quot;"><id>tag:blogger.com,1999:blog-6313632118977055554.post-8326639499619125998</id><published>2009-04-17T09:15:00.000-07:00</published><updated>2009-04-21T14:33:11.884-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-21T14:33:11.884-07:00</app:edited><title>Ruby API Objects diagram</title><content type="html">&lt;font class="byline-author"&gt;Posted by Simone Nicolo, Google SketchUp team.&lt;br /&gt;&lt;br /&gt;&lt;/font&gt;Have you ever wondered how the various classes are organized in the ruby API?&lt;br /&gt;Well, I &lt;font style="background-color: rgb(255, 255, 102);"&gt;&lt;/font&gt;recently created a diagram to show the objects hierarchy for the SketchUp Ruby API.&lt;br /&gt;&lt;br /&gt;It can be found &lt;a title="SU Objects diagram" href="http://code.google.com/apis/sketchup/docs/diagram.html" target="_blank"&gt;here&lt;/a&gt;  and it provides an easy way to visualize relationships between SU API's various objects.&lt;br /&gt;&lt;br /&gt;Below are some examples of ways in which the diagram can be used:&lt;br /&gt;&lt;br /&gt;Example 1&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;Example 2&lt;br /&gt;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 &lt;font style="font-style: italic;"&gt;Sketchup.active_model &lt;/font&gt;or &lt;font style="font-style: italic;"&gt;Entity.model&lt;/font&gt;. The Entity.model method will work on any class that inherits from Entity.&lt;br /&gt;&lt;br /&gt;Example 3&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;To keep it as simple as possible, some classes were not included in the diagram.&lt;br /&gt;&lt;br /&gt;Hopefully this will help you better visualize the organization of the Ruby API elements.&lt;br /&gt;&lt;br /&gt;Simone.&lt;br /&gt;&lt;font class="byline-author"&gt;&lt;br /&gt;&lt;/font&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6313632118977055554-8326639499619125998?l=sketchupapi.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleSketchupApiBlog/~4/7fbt0f2CtLg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://sketchupapi.blogspot.com/feeds/8326639499619125998/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6313632118977055554&amp;postID=8326639499619125998" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6313632118977055554/posts/default/8326639499619125998?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6313632118977055554/posts/default/8326639499619125998?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleSketchupApiBlog/~3/7fbt0f2CtLg/ruby-api-objects-diagram.html" title="Ruby API Objects diagram" /><author><name>Simone (snicolo)</name><uri>http://www.blogger.com/profile/15177631670413453224</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10534953208891399375" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://sketchupapi.blogspot.com/2009/04/ruby-api-objects-diagram.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ck8ASX89eSp7ImA9WxVbFk8.&quot;"><id>tag:blogger.com,1999:blog-6313632118977055554.post-7682340910080577174</id><published>2009-04-01T09:33:00.001-07:00</published><updated>2009-04-01T14:20:48.161-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-01T14:20:48.161-07:00</app:edited><title>SketchUp API Updates</title><content type="html">&lt;b&gt;Updated &lt;/b&gt;&lt;b&gt;Ruby API Documentation&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;The guys over at the &lt;a title="SketchUcation Community Forums" href="http://www.sketchucation.com/forums/scf/" id="cavz"&gt;SketchUcation Community Forums&lt;/a&gt; have been submitting documentation corrections to us and we just pushed a bunch of updates to our &lt;a title="Ruby API Site" href="http://code.google.com/apis/sketchup/docs/index.html" id="ow6k"&gt;Ruby API Site&lt;/a&gt; .  Thanks to everyone who's been helping us improve our docs!  If you find other typos or problems please join the &lt;a title="thread on SketchUcation" href="http://www.sketchucation.com/forums/scf/viewtopic.php?f=180&amp;amp;t=17047" id="skcq"&gt;thread on SketchUcation&lt;/a&gt; or post to our ruby group.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;New Ruby Tutorial&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Check out our new tutorial on &lt;a title="Attribute Reporting" href="http://code.google.com/apis/sketchup/docs/tutorial_attrreporting.html" id="qqau"&gt;Attribute Reporting&lt;/a&gt; to learn how to read attribute data from entities in your models.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;New SDK Package&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;We recently repackaged the SDK to make it a bit easier to use.  Improvements include:&lt;br /&gt;&lt;br /&gt;-  Reorganized folders to make them more understandable&lt;br /&gt;- New GettingStarted.html intro to help get folks headed down the right path&lt;br /&gt;-  Updated SkpReader and SkpWriter documentation&lt;br /&gt;-  Updated SkpToXml example to compile on the PC&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;There were no changes to the headers or binaries so there are no code fixes with this release.  Please download the latest package at - &lt;a href="http://code.google.com/apis/sketchup/docs/downloadsdksubmit.html"&gt;http://code.google.com/apis/sketchup/docs/downloadsdksubmit.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Bryce Stout&lt;br /&gt;Product Manager&lt;br /&gt;Google&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6313632118977055554-7682340910080577174?l=sketchupapi.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleSketchupApiBlog/~4/B2AKCNcX1dA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://sketchupapi.blogspot.com/feeds/7682340910080577174/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6313632118977055554&amp;postID=7682340910080577174" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6313632118977055554/posts/default/7682340910080577174?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6313632118977055554/posts/default/7682340910080577174?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleSketchupApiBlog/~3/B2AKCNcX1dA/sketchup-api-updates.html" title="SketchUp API Updates" /><author><name>Sketchup Guide Bryce</name><uri>http://www.blogger.com/profile/05828718671079688877</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="05576126011266499069" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">3</thr:total><feedburner:origLink>http://sketchupapi.blogspot.com/2009/04/sketchup-api-updates.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0cFQnY5fSp7ImA9WxVUE00.&quot;"><id>tag:blogger.com,1999:blog-6313632118977055554.post-8153589743006611768</id><published>2009-03-12T10:19:00.000-07:00</published><updated>2009-03-17T09:56:53.825-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-17T09:56:53.825-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Ruby" /><title>Deleting Unnecessary Edges</title><content type="html">&lt;p&gt;&lt;span class="byline-author"&gt;Posted by Sandra Winstead, SketchUp Team&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;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!&lt;br /&gt;&lt;br /&gt;First, set up a few variables:&lt;br /&gt;&lt;span style="font-family: courier new;font-size:100%;"&gt;&lt;pre&gt;def variables&lt;br /&gt;  @group_list = []&lt;br /&gt;  @component_list = []&lt;br /&gt;  @delete_these = []&lt;br /&gt;  @model_list = Sketchup.active_model.entities&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;/span&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;font-size:100%;"&gt;&lt;pre&gt;def delete_soft_lines(e)&lt;br /&gt;&lt;font color="green"&gt;  # Determine if the edge is soft or hidden, and if it is bordered by &lt;br /&gt;  # two faces.&lt;/font&gt;&lt;br /&gt;  if ((e.soft? and e.faces.size == 2) or (e.hidden? and e.faces.size == 2))&lt;br /&gt;&lt;font color="green"&gt;    # Determine if the two bordering faces are coplanar.&lt;br /&gt;    # Note: This will only catch cases where the front faces are pointing &lt;br /&gt;    # in the same direction.&lt;/font&gt;&lt;br /&gt;    if (e.faces[0].normal.dot(e.faces[1].normal) &gt; 0.999999999)&lt;br /&gt;&lt;font color="green"&gt;      # Add the edge to the list of entities that will be deleted.&lt;/font&gt;&lt;br /&gt;      @delete_these.push(e)&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;/span&gt;&lt;br /&gt;Now create a method to find all the edges in the model, including edges that are embedded in groups and components:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;font-size:100%;"&gt;&lt;pre&gt;def traverse_model_entities&lt;br /&gt;&lt;font color="green"&gt;  # @model_list will not be empty until all of the groups, components &lt;br /&gt;  # and edges have been traversed.&lt;/font&gt;&lt;br /&gt;  while @model_list != []&lt;br /&gt;    @model_list.each do |item|&lt;br /&gt;&lt;font color="green"&gt;      # Determine if the entity is an edge, group, or component.&lt;/font&gt;&lt;br /&gt;      type = item.typename&lt;br /&gt;      case type&lt;br /&gt;        when "Edge"&lt;br /&gt;&lt;font color="green"&gt;          # Determine if the edge should be deleted, and add it to the &lt;br /&gt;          # @delete_these list.&lt;/font&gt;&lt;br /&gt;          delete_soft_lines(item)&lt;br /&gt;        when "Group"&lt;br /&gt;&lt;font color="green"&gt;          # Add each of the entities in the group into the group_list&lt;br /&gt;          # array.&lt;/font&gt;&lt;br /&gt;          item.entities.each do |entity|&lt;br /&gt;            @group_list.push entity&lt;br /&gt;          end&lt;br /&gt;        when "ComponentInstance"&lt;br /&gt;&lt;font color="green"&gt;          # .entities can be called on a Component Definition, but not on&lt;br /&gt;          # a Component Instance.&lt;br /&gt;          # Use the .definition method to access the Component Definition&lt;br /&gt;          # that the instance belongs to.&lt;/font&gt;&lt;br /&gt;          item.definition.entities.each do |entity|&lt;br /&gt;&lt;font color="green"&gt;            # Add each of the entities in the component into the&lt;br /&gt;            # component_list array.&lt;/font&gt;&lt;br /&gt;            @component_list.push entity&lt;br /&gt;          end&lt;br /&gt;      end&lt;br /&gt;    end&lt;br /&gt;&lt;font color="green"&gt;    # Update the @model_list so it contains only the entities that were &lt;br /&gt;    # embedded in groups or components. These entities haven't been&lt;br /&gt;    # counted yet.&lt;/font&gt;&lt;br /&gt;    @model_list = @group_list + @component_list&lt;br /&gt;&lt;font color="green"&gt;    # Clear out the group and component lists so they're ready for the&lt;br /&gt;    # next level of sub-groups/components.&lt;/font&gt;&lt;br /&gt;    @group_list = []&lt;br /&gt;    @component_list =[]&lt;br /&gt;  end&lt;br /&gt;&lt;font color="green"&gt;  # The edges that need to be deleted have all been added to the&lt;br /&gt;  # @delete_these list, so erase those entities from the &lt;br /&gt;  # active SketchUp model.&lt;/font&gt;&lt;br /&gt;  Sketchup.active_model.entities.erase_entities(@delete_these)&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/span&gt;&lt;br /&gt;Finally, add a “Delete unnecessary edges” item to Tools menu, and pop a dialog letting you know the edges were deleted:&lt;br /&gt;&lt;span style="font-family: courier new;font-size:100%;"&gt;&lt;pre&gt;def delete_edges&lt;br /&gt;  variables&lt;br /&gt;  traverse_model_entities&lt;br /&gt;  UI.messagebox("Edges deleted.")&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;UI.menu("Tools").add_item("Delete unnecessary edges") {delete_edges}&lt;br /&gt;&lt;/pre&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6313632118977055554-8153589743006611768?l=sketchupapi.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleSketchupApiBlog/~4/Pdbc3MpSAm0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://sketchupapi.blogspot.com/feeds/8153589743006611768/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6313632118977055554&amp;postID=8153589743006611768" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6313632118977055554/posts/default/8153589743006611768?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6313632118977055554/posts/default/8153589743006611768?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleSketchupApiBlog/~3/Pdbc3MpSAm0/deleting-unnecessary-edges.html" title="Deleting Unnecessary Edges" /><author><name>Sandra Winstead</name><uri>http://www.blogger.com/profile/02397119399136808749</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="17327289224358684228" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">4</thr:total><feedburner:origLink>http://sketchupapi.blogspot.com/2009/03/deleting-unnecessary-edges.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUMARHo6fyp7ImA9WxVVE0o.&quot;"><id>tag:blogger.com,1999:blog-6313632118977055554.post-4949669493604418941</id><published>2009-03-06T13:01:00.000-08:00</published><updated>2009-03-06T13:04:05.417-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-06T13:04:05.417-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="google I/O" /><title>Google I/O 2009</title><content type="html">&lt;img style="width: 345px; height: 64px;" src="https://docs.google.com/a/google.com/File?id=csj37xb_4gzsmjgcd_b" /&gt;&lt;br /&gt;&lt;div id="x5ja" style="padding: 1em 0pt; text-align: left;"&gt;&lt;br /&gt;&lt;span style="font-weight: normal;"&gt;The &lt;/span&gt;&lt;a style="font-weight: normal;" href="http://code.google.com/events/io/" id="af4_" title="Google I/O conference"&gt;Google I/O Developer Conference&lt;/a&gt;&lt;span style="font-weight: normal;"&gt; is May 28th and 27th in San Francisco, CA.  Members of the SketchUp team will be presenting in the &lt;/span&gt;&lt;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"&gt;What you don't know about Geo APIs can't hurt you&lt;/a&gt;&lt;span style="font-weight: normal;"&gt; session and will also be available during &lt;/span&gt;&lt;a style="font-weight: normal;" href="http://code.google.com/events/io/about.html" id="b9:b" title="Office Hours"&gt;Office Hours&lt;/a&gt;&lt;span style="font-weight: normal;"&gt;.  Hope to see you there! &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: normal;"&gt;  Posted by Bryce Stout, Product Manager&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6313632118977055554-4949669493604418941?l=sketchupapi.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleSketchupApiBlog/~4/6B5a04hH6fc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://sketchupapi.blogspot.com/feeds/4949669493604418941/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6313632118977055554&amp;postID=4949669493604418941" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6313632118977055554/posts/default/4949669493604418941?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6313632118977055554/posts/default/4949669493604418941?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleSketchupApiBlog/~3/6B5a04hH6fc/google-io-2009.html" title="Google I/O 2009" /><author><name>Sketchup Guide Bryce</name><uri>http://www.blogger.com/profile/05828718671079688877</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="05576126011266499069" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://sketchupapi.blogspot.com/2009/03/google-io-2009.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0QHQH06fip7ImA9WxVWF0k.&quot;"><id>tag:blogger.com,1999:blog-6313632118977055554.post-7982063729474451262</id><published>2009-02-23T17:01:00.000-08:00</published><updated>2009-02-27T07:42:11.316-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-02-27T07:42:11.316-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="importers" /><title>SketchUp Importers</title><content type="html">&lt;span class="byline-author"&gt;Posted by Sang Ahn, SketchUp Team&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;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.&lt;div&gt;&lt;br /&gt;&lt;div&gt;It's easy to write and use your own Ruby importers in SketchUp.  Just follow these steps:&lt;br /&gt;&lt;br /&gt;1. Define a class with the plugin API methods.&lt;br /&gt;2. Register an object of the class with SketchUp.&lt;br /&gt;3. Recover from Mardi Gras festivities (may not be applicable).&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;An importer class must have the following methods:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;code&gt;def description&lt;br /&gt;&amp;nbsp;&amp;nbsp;# Returns a brief description of your importer plugin.&lt;br /&gt;end&lt;/code&gt;&lt;br /&gt;&lt;code&gt;def file_extension&lt;br /&gt;&amp;nbsp;&amp;nbsp;# Returns the file extension of the file format your&lt;br /&gt;&amp;nbsp;&amp;nbsp;# importer can read (e.g. fbx, dae, etc.)&lt;br /&gt;end&lt;/code&gt;&lt;br /&gt;&lt;code&gt;def supports_options?&lt;br /&gt;&amp;nbsp;&amp;nbsp;# Returns true if your plugin supports import options.&lt;br /&gt;end&lt;/code&gt;&lt;br /&gt;&lt;code&gt;def do_options&lt;br /&gt;&amp;nbsp;&amp;nbsp;# Presents the import options dialog panel to the user.&lt;br /&gt;end&lt;/code&gt;&lt;br /&gt;&lt;code&gt;def id&lt;br /&gt;&amp;nbsp;&amp;nbsp;# Returns the id string of your importer.&lt;br /&gt;end&lt;/code&gt;&lt;br /&gt;&lt;code&gt;def load_file(file_name, show_summary)&lt;br /&gt;&amp;nbsp;&amp;nbsp;# Reads the contents of location on disk specified&lt;br /&gt;&amp;nbsp;&amp;nbsp;# by file_name.&lt;br /&gt;&amp;nbsp;&amp;nbsp;# Shows the summary dialog panel if show_summary is true.&lt;br /&gt;&amp;nbsp;&amp;nbsp;# Returns 0 on success, returns 1 on failure.&lt;br /&gt;&amp;nbsp;&amp;nbsp;0&lt;br /&gt;end&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Once you have defined your importer class, register your importer with SketchUp:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;Sketchup.register_importer MyImporter.new&lt;br /&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;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.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6313632118977055554-7982063729474451262?l=sketchupapi.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleSketchupApiBlog/~4/Jc7e0bAmDkI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://sketchupapi.blogspot.com/feeds/7982063729474451262/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6313632118977055554&amp;postID=7982063729474451262" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6313632118977055554/posts/default/7982063729474451262?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6313632118977055554/posts/default/7982063729474451262?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleSketchupApiBlog/~3/Jc7e0bAmDkI/sketchup-importers.html" title="SketchUp Importers" /><author><name>Sang Ahn</name><uri>http://www.blogger.com/profile/15950646401058474337</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="02517248003770367906" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://sketchupapi.blogspot.com/2009/02/sketchup-importers.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C08HQn49eip7ImA9WxVRFUo.&quot;"><id>tag:blogger.com,1999:blog-6313632118977055554.post-6184197215767783711</id><published>2009-01-21T09:51:00.000-08:00</published><updated>2009-01-21T13:03:53.062-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-01-21T13:03:53.062-08:00</app:edited><title>The SketchUp 7 SDK is now available</title><content type="html">&lt;font class="byline-author"&gt;Posted by Bryce Stout, SketchUp Team&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;We have recently updated the SketchUp SDK for folks who need read and/or write SketchUp 7 files.  It is available on &lt;a href="http://code.google.com/apis/sketchup/docs/downloadsdksubmit.html"&gt;http://code.google.com/apis/sketchup/docs/downloadsdksubmit.html&lt;/a&gt;.   If you have feedback or questions, please post your questions or suggestions to the &lt;a href="http://groups.google.com/group/su-sdk-fileshare/topics"&gt;SketchUp SDK Group&lt;/a&gt;.  If you would like to be notified about future SDK updates and news, please subscribe to this blog, if you haven't already.&lt;br /&gt;&lt;br /&gt;Happy SketchUp Developing!&lt;br /&gt;Bryce Stout&lt;br /&gt;Product Manager&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6313632118977055554-6184197215767783711?l=sketchupapi.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleSketchupApiBlog/~4/tqXPnFjMKeE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://sketchupapi.blogspot.com/feeds/6184197215767783711/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6313632118977055554&amp;postID=6184197215767783711" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6313632118977055554/posts/default/6184197215767783711?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6313632118977055554/posts/default/6184197215767783711?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleSketchupApiBlog/~3/tqXPnFjMKeE/sketchup-7-sdk-is-now-available.html" title="The SketchUp 7 SDK is now available" /><author><name>Scott Lininger</name><uri>http://www.blogger.com/profile/05141972816510160560</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="17366763003152500127" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">3</thr:total><feedburner:origLink>http://sketchupapi.blogspot.com/2009/01/sketchup-7-sdk-is-now-available.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0UEQ34-cCp7ImA9WxVSFUk.&quot;"><id>tag:blogger.com,1999:blog-6313632118977055554.post-2271506385631417641</id><published>2009-01-07T16:02:00.000-08:00</published><updated>2009-01-09T15:53:22.058-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-01-09T15:53:22.058-08:00</app:edited><title>Playing Sounds in SketchUp</title><content type="html">&lt;span class="byline-author"&gt;Posted by Scott Lininger, SketchUp Team&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This week I'd like to talk about a much-maligned feature of the SketchUp Ruby API... &lt;b&gt;UI.play_sound&lt;/b&gt;. Why would you &lt;span style="font-style: italic;"&gt;ever&lt;/span&gt; want to play sound via the Ruby API? Glad you asked!&lt;br /&gt;&lt;br /&gt;Besides the &lt;span style="font-style: italic;"&gt;obvious&lt;/span&gt; desire to listen to &lt;a href="http://en.wikipedia.org/wiki/Marvin_Gaye" target="_blank"&gt;Marvin Gaye&lt;/a&gt; while drawing your &lt;a href="http://sketchup.google.com/3dwarehouse/cldetails?mid=7bf295d83bf0b273bdde1f81a135a9ac&amp;prevstart=0" target="_blank"&gt;skatepark&lt;/a&gt;, 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.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Step 1: Get a Zoo With some Scenes&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;For this exercise, we're going to need a model with some Scene tabs. Luckily I have just the zoo. Click here to &lt;a href="http://groups.google.com/group/sketchup-Pro-Groups/web/RubyBlog_Zoo.zip" target="_blank"&gt;download a ZIP file&lt;/a&gt; with everything you need to follow this example. &lt;br /&gt;&lt;br /&gt;Once you get it, unzip everything to your &lt;a href="http://code.google.com/apis/sketchup/docs/gsrubyfaq.html" target="_blank"&gt;SketchUp/Plugins/&lt;/a&gt; directory. It contains four files:&lt;ul&gt;&lt;br /&gt;&lt;li&gt;zoo.skp - a model of the world's lamest zoo&lt;br /&gt;&lt;li&gt;zoo.rb - the code that we're about to talk about&lt;br /&gt;&lt;li&gt;zoo_lion.wav - what the lion says&lt;br /&gt;&lt;li&gt;zoo_elephant.wav - what the elephant says&lt;br /&gt;&lt;li&gt;zoo_sang.wav - what Sang says&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Step 2: Don't Feed the Animals&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Once everything is in your /Plugins/ directory, open the zoo.skp file&lt;br /&gt;and click the Scene tabs. Turn up the volume. You should hear a sound&lt;br /&gt;effect that the Ruby API plays at each scene stop.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Step 3: Explore the Code&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Here's the entire script. It shows using a Page Observer to capture&lt;br /&gt;each frame of our scene animations. It watches the callback parameter&lt;br /&gt;percent_done to figure out when the animation is complete, and then&lt;br /&gt;it plays the sound.&lt;br /&gt;&lt;span style="font-family: courier new;font-size:100%;"&gt;&lt;pre&gt;# Create a class that will "observe" frame changes.&lt;br /&gt;class ZooFrameObserver &lt;  Sketchup::ViewObserver&lt;br /&gt;&lt;br /&gt;  def frameChange(from_page, to_page, percent_done)&lt;br /&gt;    if percent_done == 1.0&lt;br /&gt;      if to_page == Sketchup.active_model.pages[0]&lt;br /&gt;        UI.play_sound("Plugins/zoo_lion.wav")&lt;br /&gt;      elsif to_page == Sketchup.active_model.pages[1]&lt;br /&gt;        UI.play_sound("Plugins/zoo_elephant.wav")&lt;br /&gt;      elsif to_page == Sketchup.active_model.pages[2]&lt;br /&gt;        UI.play_sound("Plugins/zoo_sang.wav")&lt;br /&gt;      end&lt;br /&gt;     end&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# Attach our observer.&lt;br /&gt;Sketchup::Pages.add_frame_change_observer(ZooFrameObserver.new)&lt;/pre&gt;&lt;/span&gt;&lt;br /&gt;I look forward to the day when every ruby script will play sounds with each interaction. I also like the &lt;blink&gt;blink&lt;/blink&gt; tag. Huzzah!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6313632118977055554-2271506385631417641?l=sketchupapi.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleSketchupApiBlog/~4/gvFtin3LSs4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://sketchupapi.blogspot.com/feeds/2271506385631417641/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6313632118977055554&amp;postID=2271506385631417641" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6313632118977055554/posts/default/2271506385631417641?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6313632118977055554/posts/default/2271506385631417641?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleSketchupApiBlog/~3/gvFtin3LSs4/playing-sounds-in-sketchup.html" title="Playing Sounds in SketchUp" /><author><name>Scott Lininger</name><uri>http://www.blogger.com/profile/05141972816510160560</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="17366763003152500127" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">3</thr:total><feedburner:origLink>http://sketchupapi.blogspot.com/2009/01/playing-sounds-in-sketchup.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0MHR389fSp7ImA9WxRUFUg.&quot;"><id>tag:blogger.com,1999:blog-6313632118977055554.post-879003179868369908</id><published>2008-11-13T13:33:00.000-08:00</published><updated>2008-11-24T11:37:16.165-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-11-24T11:37:16.165-08:00</app:edited><title>What's New in SketchUp 7</title><content type="html">&lt;span class="byline-author"&gt;Posted by Scott Lininger, SketchUp Team&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;SketchUp 7 contains several improvements to the Ruby API. Here's a quick tour of the best changes.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Improve your script's performance!&lt;/span&gt;&lt;br /&gt;Ability to perform faster inside start_operation transactions.&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;go_faster = true&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;model.start_operation operation_name, go_faster&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Results from some real world tests, once the go_faster boolean was added:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.smustard.com/script/IntersectOverlaps"&gt;Intersect overlaps&lt;/a&gt; with 500 overlapping squares&lt;br /&gt;28.4 seconds vs. 26.3 (~92% as long)&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.smustard.com/script/MakeFaces"&gt;Make faces&lt;/a&gt; with 500 faceless cubes&lt;br /&gt;21.7 seconds vs. 14.5 (~66% as long)&lt;br /&gt;&lt;a href="http://members.cox.net/rick.wilson/"&gt;&lt;br /&gt;Windowizer 3.0&lt;/a&gt; with Four 20'x20' windows, 12x12&lt;br /&gt;16.1 seconds vs. 7.0 seconds (~43% as as long)&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.smustard.com/script/Windowizer4"&gt;Windowizer 4.0&lt;/a&gt; with Ten 5'x5' windows, 6x6&lt;br /&gt;22.6 seconds vs 8.7 seconds (~38% as long)&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Leverage improved Web Dialogs&lt;/span&gt;&lt;br /&gt;Addition of min/max widths.&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  &lt;span style="color: rgb(0, 102, 0);"&gt;WebDialog.min_width=&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);font-family:courier new;" &gt;100&lt;br /&gt;WebDialog.max_width=300&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);font-family:courier new;" &gt;  WebDialog.min_height=&lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);font-family:courier new;" &gt;500&lt;br /&gt;WebDialog.max_height=600&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Fixed Mac support for WebDialogs execute_script&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);font-family:courier new;" &gt;WebDialog.execute_script('alert("Bug is Fixed!")');&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;New full_security mode for webdialogs (disables plugins and remote links)&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);font-family:courier new;" &gt;WebDialog.set_full_security&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Ability to hide home/next/back navigation icons on the Mac&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);font-family:courier new;" &gt;WebDialog.navigation_buttons_enabled=true&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Cleaner, hash-based syntax for initializing&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);font-family:courier new;" &gt;my_dialog = WebDialog.new(my_settings_hash)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Control Scale Tool handles on your components&lt;/span&gt;&lt;br /&gt;Your script can now control which scale tool handles appear&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);font-family:courier new;" &gt;# Disable the green and red-axes handles&lt;br /&gt;# by setting bits 1 and 2 to 1.&lt;br /&gt;behavior = my_component_definition.behavior&lt;br /&gt;behavior.no_scale_mask = (1 &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);font-family:courier new;" &gt;&amp;lt;&amp;lt; 1) + (1 &amp;lt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);font-family:courier new;" &gt; 2) &lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Load Definitions from the Web, or save to disk&lt;/span&gt;&lt;br /&gt;Ability to download a definition from URL&lt;span style="color: rgb(0, 102, 0);font-family:courier new;" &gt;&lt;br /&gt;model.definitions.load_from_url(url, download_handler&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;Ability to Save components to disk from the API&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);font-family:courier new;" &gt;my_definition.save_as(path)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Know more about what your users are doing&lt;/span&gt;&lt;br /&gt;New methods for detecting "Component Edit" mode&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);font-family:courier new;" &gt;users_current_edit = model.active_path&lt;br /&gt;edit_mode_transform = model.edit_transform&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;Easily determine if they're running in licensed Pro&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);font-family:courier new;" &gt;is_licensed_pro = Sketchup.is_pro?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;New "model level" callbacks in ModelObserver&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);font-family:courier new;" &gt;def onActivePathChanged(model) { # Detect edit mode }&lt;br /&gt;&lt;/span&gt; &lt;span style="color: rgb(0, 102, 0);font-family:courier new;" &gt;def onPlaceComponent(instance) { # Detect placements }&lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);font-family:courier new;" &gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);font-family:courier new;" &gt;def onExplode(model) { # Detect group/component explode }&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);font-family:courier new;" &gt;def onBeforeComponentSaveAs(instance) { # Add data on save as }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);font-family:courier new;" &gt;def onAfterComponentSaveAs(instance) { # Then clean up }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Detect if they've turned off your extension via the AppObserver&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);font-family:courier new;" &gt;def onUnloadExtension(extension_name)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Delete your scenes via the API&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);font-family:courier new;" &gt;my_page.erase&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Keep SketchUp in Synch&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);font-family:courier new;" &gt;UI.refresh_inspectors # force complete UI update&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);font-family:courier new;" &gt;my_definition.refresh_thumbnail # force thumb update&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);font-family:courier new;" &gt;my_definition.invalidate_bounds # force bb update&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Measure your groups regardless of their transform&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);font-family:courier new;" &gt;untransformed_bb = my_group.local_bounds&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Use middle mouse button in your custom tools&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);font-family:courier new;" &gt;def onMButtonDown(flags, x, y, view) { # now works! }&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);font-family:courier new;" &gt;def onMButtonUp(flags, x, y, view) { # now works! }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Send ruby console output to the standard out&lt;/span&gt;&lt;br /&gt;If you start up SketchUp from the command line, you can pipe to standard error and see ruby puts statements appear for you.&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);font-family:courier new;" &gt;Sketchup.exe &gt; myRubyLog.txt&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;and your users will benefit from numerous stability fixes&lt;/span&gt;!&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;Detailed documentation is coming soon... stay tuned!&lt;/div&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6313632118977055554-879003179868369908?l=sketchupapi.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleSketchupApiBlog/~4/sdFkminfjXI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://sketchupapi.blogspot.com/feeds/879003179868369908/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6313632118977055554&amp;postID=879003179868369908" title="11 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6313632118977055554/posts/default/879003179868369908?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6313632118977055554/posts/default/879003179868369908?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleSketchupApiBlog/~3/sdFkminfjXI/whats-new-in-sketchup-7.html" title="What's New in SketchUp 7" /><author><name>Scott Lininger</name><uri>http://www.blogger.com/profile/05141972816510160560</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="17366763003152500127" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">11</thr:total><feedburner:origLink>http://sketchupapi.blogspot.com/2008/11/whats-new-in-sketchup-7.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkANR3o8fip7ImA9WxRWGUw.&quot;"><id>tag:blogger.com,1999:blog-6313632118977055554.post-8465366960084804963</id><published>2008-11-05T09:38:00.000-08:00</published><updated>2008-11-05T12:59:56.476-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-11-05T12:59:56.476-08:00</app:edited><title>Storing and Retrieving with AttributeDictionary</title><content type="html">&lt;span class="byline-author"  style="font-size:100%;"&gt;Posted by Mason Thrall, 3D Data Specialist&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="color: rgb(0, 0, 0);font-family:Arial;"&gt;&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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 &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:Arial;"&gt;AttributeDictionary.&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:Arial;"&gt;&lt;br /&gt;We will start by getting the current camera parameters and storing them into variables:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);font-family:Courier New;font-size:85%;"  &gt;def reveal_view&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;div style="text-align: justify;"&gt;  &lt;span style="color: rgb(102, 102, 102);font-family:Courier New;font-size:85%;"  &gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;m=Sketchup.active_model&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);font-family:Courier New;font-size:85%;"  &gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;m.start_operation("reveal view")&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);font-family:Courier New;font-size:85%;"  &gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;ents=m.entities&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);font-family:Courier New;font-size:85%;"  &gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;view=m.active_view&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);font-family:Courier New;font-size:85%;"  &gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;cam=view.camera&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);font-family:Courier New;font-size:85%;"  &gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;up=cam.up&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);font-family:Courier New;font-size:85%;"  &gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;target=cam.target&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);font-family:Courier New;font-size:85%;"  &gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;persp=cam.perspective?&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);font-family:Courier New;font-size:85%;"  &gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;fov=cam.fov&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);font-family:Courier New;font-size:85%;"  &gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;eye=cam.eye&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);font-family:Courier New;font-size:85%;"  &gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;focus_ray=Geom::Vector3d.new(eye,target)&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);font-family:Courier New;font-size:85%;"  &gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;eye_axes=focus_ray.axes&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;span style="color: rgb(102, 102, 102);font-family:Courier New;font-size:100%;"  &gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="color: rgb(0, 0, 0);font-family:Arial;"&gt;Next, we'll make a simple representation of the camera, using the stored camera settings to determine the geometry,&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:Courier New;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);font-family:Courier New;font-size:100%;"  &gt;  &lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:Arial;"&gt;&lt;span style="font-family:Courier New;"&gt;&lt;span style="color: rgb(102, 102, 102);"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;target_pointer = &lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);font-family:Courier New;" &gt;ents.add_cline(eye,target)&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);font-family:Courier New;font-size:85%;"  &gt;  &lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:Arial;"&gt;&lt;span style="color: rgb(102, 102, 102);font-family:Courier New;" &gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;eye_point = ents.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:Arial;"&gt;&lt;span style="color: rgb(102, 102, 102);font-family:Courier New;" &gt;add_cpoint(eye)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);font-family:Courier New;font-size:85%;"  &gt;  &lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:Arial;"&gt;&lt;span style="color: rgb(102, 102, 102);font-family:Courier New;" &gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;target_point = ents.add_cpoint(target)&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);font-family:Courier New;font-size:85%;"  &gt;  &lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:Arial;"&gt;&lt;span style="color: rgb(102, 102, 102);font-family:Courier New;" &gt;&lt;span style="font-size:85%;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;circle = ents.add_circle(eye, focus_ray, 20, 8)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);font-family:Arial;" &gt;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.&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);font-family:Courier New;font-size:85%;"  &gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;camera_geom = []&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;camera_geom.push(target_pointer,eye_point,target_point,circle)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;camera_geom.flatten!&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;cam_group=ents.add_group(camera_geom)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;cam_group.name="camera"&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;cam_layer=m.layers.add("cameras")&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;cam_group.layer=cam_layer&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;cam_group.locked=true&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;We will then be storing the camera settings into the AttributeDictionary called "is_a_camera".&lt;br /&gt;Create the AttributeDictionary in the cam_group Entity:&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(102, 102, 102);font-size:85%;" &gt;&lt;span style="font-family:Courier New;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;is_camera=cam_group.attribute_dictionary("is_a_camera", true)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;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,&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);font-size:85%;" &gt;&lt;span style="font-family:Courier New;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;is_camera["cam"]=cam&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:Courier New;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;is_camera["up"]=up&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:Courier New;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;is_camera["target"]=target&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:Arial;"&gt;&lt;span style="color: rgb(102, 102, 102);font-family:Courier New;" &gt;&lt;span style="color: rgb(0, 0, 0);font-family:Arial;" &gt;&lt;span style="color: rgb(102, 102, 102);"&gt;&lt;span style="font-family:Courier New;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;is_camera["persp"]=persp&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;is_camera["fov"]=fov&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;is_camera["eye"]=eye&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;is_camera["focus_ray"]=focus_ray&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;is_camera["eye_axes"]=eye_axes&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;and commit the undo operation.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:Courier New;"&gt;&lt;span style="color: rgb(102, 102, 102);font-size:85%;" &gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;m.commit_operation&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(102, 102, 102);"&gt;&lt;span style="font-size:85%;"&gt;end&lt;br /&gt;&lt;br /&gt;UI.menu("Plugins").add_item("reveal view"){reveal_view}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:Arial;"&gt;&lt;span style="color: rgb(102, 102, 102);font-family:Courier New;" &gt;&lt;span style="color: rgb(0, 0, 0);font-family:Arial;" &gt;Finally, we add a context menu option to call a method only on objects which contain the &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:Arial;"&gt;&lt;span style="color: rgb(102, 102, 102);font-family:Courier New;" &gt;&lt;span style="color: rgb(0, 0, 0);font-family:Arial;" &gt;AttributeDictionary &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:Arial;"&gt;&lt;span style="color: rgb(102, 102, 102);font-family:Courier New;" &gt;&lt;span style="color: rgb(0, 0, 0);font-family:Arial;" &gt;"is_a_camera". If the &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:Arial;"&gt;&lt;span style="color: rgb(102, 102, 102);font-family:Courier New;" &gt;&lt;span style="color: rgb(0, 0, 0);font-family:Arial;" &gt;AttributeDictionary exists,&lt;span style="font-family:Arial;"&gt; then the option "go to view" is added to the context menu.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:Arial;"&gt;&lt;span style="color: rgb(102, 102, 102);font-family:Courier New;" &gt;&lt;span style="color: rgb(0, 0, 0);font-family:Arial;" &gt;&lt;span style="color: rgb(102, 102, 102);font-family:Courier New;" &gt;&lt;br /&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&lt;span style="font-size:85%;"&gt;UI.add_context_menu_handler do |menu|&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;select_one=Sketchup.active_model.selection[0]&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;if select_one.class==Sketchup::Group&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if select_one.attribute_dictionary("is_a_camera",false)!=nil&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;menu.add_item("go to view"){go_to_view(select_one)}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;end&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;end&lt;br /&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:Arial;"&gt;&lt;span style="color: rgb(102, 102, 102);font-family:Courier New;" &gt;&lt;span style="color: rgb(0, 0, 0);font-family:Arial;" &gt;&lt;span style="font-family:Arial;"&gt;When this is clicked, it calls the go_to_view() method. &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:Arial;"&gt;&lt;span style="color: rgb(102, 102, 102);font-family:Courier New;" &gt;&lt;span style="color: rgb(0, 0, 0);font-family:Arial;" &gt;Our second method, &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:Arial;"&gt;&lt;span style="color: rgb(102, 102, 102);font-family:Courier New;" &gt;&lt;span style="color: rgb(0, 0, 0);font-family:Arial;" &gt;&lt;span style="font-family:Arial;"&gt;go_to_view(),&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:Arial;"&gt;&lt;span style="color: rgb(102, 102, 102);font-family:Courier New;" &gt;&lt;span style="color: rgb(0, 0, 0);font-family:Arial;" &gt;  will take a selected Entity and recall the values stored in the &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:Arial;"&gt;&lt;span style="color: rgb(102, 102, 102);font-family:Courier New;" &gt;&lt;span style="color: rgb(0, 0, 0);font-family:Arial;" &gt;AttributeDictionary &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:Arial;"&gt;&lt;span style="color: rgb(102, 102, 102);font-family:Courier New;" &gt;&lt;span style="color: rgb(0, 0, 0);font-family:Arial;" &gt;"is_a_camera". It then uses these values to return to the stored camera position and settings.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:Arial;"&gt;&lt;span style="color: rgb(102, 102, 102);font-family:Courier New;" &gt;&lt;span style="color: rgb(0, 0, 0);font-family:Arial;" &gt;&lt;span style="font-family:Courier New;"&gt;&lt;span style="color: rgb(102, 102, 102);"&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;def go_to_view(sel)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;info=sel.attribute_dictionary("is_a_camera")&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;m=Sketchup.active_model&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;view=m.active_view&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;view.camera=Sketchup::Camera.new(info["eye"],info["target"],&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;info["up"],info["persp"],info["fov"])&lt;br /&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6313632118977055554-8465366960084804963?l=sketchupapi.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleSketchupApiBlog/~4/s6m7gAe1t7I" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://sketchupapi.blogspot.com/feeds/8465366960084804963/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6313632118977055554&amp;postID=8465366960084804963" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6313632118977055554/posts/default/8465366960084804963?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6313632118977055554/posts/default/8465366960084804963?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleSketchupApiBlog/~3/s6m7gAe1t7I/storing-and-retrieving-with.html" title="Storing and Retrieving with AttributeDictionary" /><author><name>Mason Thrall</name><uri>http://www.blogger.com/profile/17646040748392561252</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="05594564430906985990" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://sketchupapi.blogspot.com/2008/11/storing-and-retrieving-with.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0UBRXY6cCp7ImA9WxRXGE0.&quot;"><id>tag:blogger.com,1999:blog-6313632118977055554.post-6960733338322448815</id><published>2008-10-23T14:48:00.000-07:00</published><updated>2008-10-23T15:34:14.818-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-10-23T15:34:14.818-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="wxRuby" /><category scheme="http://www.blogger.com/atom/ns#" term="Ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="WebDialog" /><category scheme="http://www.blogger.com/atom/ns#" term="wxSU" /><title>wxSU and You</title><content type="html">&lt;span class="byline-author"&gt;Posted by Sang Ahn, SketchUp Software Engineer&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;A lot of you are already using the &lt;a href="http://code.google.com/apis/sketchup/docs/developers_guide/classes/UI/WebDialog.html" id="iban" title="WebDialog"&gt;WebDialog&lt;/a&gt; of the &lt;a href="http://code.google.com/apis/sketchup/" id="r9bq" title="SketchUp Ruby API"&gt;SketchUp Ruby API&lt;/a&gt;  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 &lt;a href="http://apps1.eere.energy.gov/buildings/energyplus/energy_design_plugin.cfm" id="ev4h" title="NREL"&gt;NREL&lt;/a&gt;, 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.&lt;div&gt;&lt;br /&gt;&lt;table style="width: auto;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;img src="http://lh3.ggpht.com/sanga20254/SQDyTM_eXHI/AAAAAAAAABU/bQH3K3fU_P4/s400/Picture%202.png" /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="font-family: arial,sans-serif; font-size: 11px; text-align: center;"&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;It's built on top of &lt;a href="http://wxruby.rubyforge.org/" id="xgq8" title="wxRuby"&gt;wxRuby&lt;/a&gt;, so your UI implementation is cross-platform and you won't have to do any extra work.  Best of all, it's &lt;a href="http://sourceforge.net/projects/wxsu/" id="wj4g" title="FREE"&gt;FREE&lt;/a&gt;!  Hats off to Peter.&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6313632118977055554-6960733338322448815?l=sketchupapi.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleSketchupApiBlog/~4/gUcdMq1f56M" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://sketchupapi.blogspot.com/feeds/6960733338322448815/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6313632118977055554&amp;postID=6960733338322448815" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6313632118977055554/posts/default/6960733338322448815?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6313632118977055554/posts/default/6960733338322448815?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleSketchupApiBlog/~3/gUcdMq1f56M/wxsu-and-you.html" title="wxSU and You" /><author><name>Sang Ahn</name><uri>http://www.blogger.com/profile/15950646401058474337</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="02517248003770367906" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh3.ggpht.com/sanga20254/SQDyTM_eXHI/AAAAAAAAABU/bQH3K3fU_P4/s72-c/Picture%202.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://sketchupapi.blogspot.com/2008/10/wxsu-and-you.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEIGRng9fCp7ImA9WxRXGE0.&quot;"><id>tag:blogger.com,1999:blog-6313632118977055554.post-1020286951999038029</id><published>2008-10-21T09:42:00.000-07:00</published><updated>2008-10-23T15:55:27.664-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-10-23T15:55:27.664-07:00</app:edited><title>Animate Yo' Cheese</title><content type="html">&lt;span class="byline-author"&gt;Posted by Scott Lininger, SketchUp Engineer&lt;br /&gt;&lt;br /&gt;Drawing &lt;a id="yzsf" title="food" href="http://sketchup.google.com/3dwarehouse/cldetails?mid=1057282acb5f8292dfbd9fb701f55f19&amp;amp;prevstart=0&amp;amp;scoring=p"&gt;foodstuffs&lt;/a&gt; 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 &lt;a id="jh08" title="manually" href="http://sketchup.google.com/support/bin/answer.py?answer=94859"&gt;manually&lt;/a&gt;, of course, or you can hide or change its appearance by using &lt;a id="j.b0" title="scenes" href="http://sketchup.google.com/support/bin/answer.py?hl=en&amp;amp;answer=39656"&gt;scenes&lt;/a&gt;, but wouldn't it be fun if there were a way to make it animate on its own?&lt;br /&gt;&lt;br /&gt;There are many plugins out there to help you create certain kinds of animations (&lt;a id="lwjp" title="Sketchy Physics" href="http://code.google.com/p/sketchyphysics/"&gt;Sketchy Physics&lt;/a&gt; and &lt;a id="is0k" title="Podium" href="http://www.suplugins.com/index.php?p=product&amp;amp;id=15&amp;amp;parent=0"&gt;Podium&lt;/a&gt; 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?&lt;br /&gt;&lt;br /&gt;Glad you asked. Let's sling some code (and some &lt;a id="fgxo" title="gouda" href="http://sketchup.google.com/3dwarehouse/details?mid=40f2597ec07a8750a8aae67c3e4a4955&amp;amp;prevstart=0"&gt;gouda&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;&lt;span style=""&gt;&lt;strong&gt;Our Example: Black hole ate my cheese&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;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 &lt;a id="f0b0" title="delicious" href="http://uk.youtube.com/watch?v=ogjfxhDiSEg&amp;amp;feature=related"&gt;delicious&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style=""&gt;&lt;strong&gt;Step 1: Create our "move" method&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;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 &lt;a id="o-ye" title="tweening animations" href="http://en.wikipedia.org/wiki/Tweening"&gt;tweening animations&lt;/a&gt;. We're going to use a simple averaging method, where the object moves halfway toward the destination with each call...&lt;br /&gt;&lt;br /&gt;blackhole.rb&lt;br /&gt;&lt;span style=";font-family:courier new;font-size:85%;"  &gt;&lt;br /&gt;# Define our method that does the transform.&lt;br /&gt;def move_halfway_toward(entity, target_pt)&lt;br /&gt;&amp;nbsp;&amp;nbsp;current_pt = entity.transformation.origin&lt;br /&gt;&amp;nbsp;&amp;nbsp;halfway = Geom::Point3d.linear_combination(0.5, current_pt, 0.5,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;target_pt)&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;# Undo our current transform with inverse,&lt;br /&gt;&amp;nbsp;&amp;nbsp;# then move to the halfway point.&lt;br /&gt;&amp;nbsp;&amp;nbsp;entity.transform! entity.transformation.inverse&lt;br /&gt;&amp;nbsp;&amp;nbsp;entity.transform! Geom::Transformation.new halfway&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;# Invalidate our view to force SU to refresh the screen. &lt;br /&gt;&amp;nbsp;&amp;nbsp;Sketchup.active_model.active_view.invalidate&lt;br /&gt;&lt;br /&gt;end &lt;br /&gt;&lt;br /&gt;# Create a rightclick handler that'll activate it.&lt;br /&gt;UI.add_context_menu_handler do |context_menu|&lt;br /&gt;&amp;nbsp;&amp;nbsp;context_menu.add_item('Move halfway to origin') {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;entity = Sketchup.active_model.selection[0]&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;origin_pt = Geom::Point3d.new 0, 0, 0&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;move_halfway_toward(entity, origin_pt)&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;end&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Create this new file called blackhole.rb, and save it in your &lt;a id="i1h." title="SketchUp/Plugins directory" href="http://code.google.com/apis/sketchup/docs/gsrubyfaq.html"&gt;SketchUp/Plugins directory&lt;/a&gt;. 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)&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style=""&gt;Step 2: use UI.start_timer to provide a timeline&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Now we add a bit more to make the method fire again and again and again, auto-magically. The secret is SketchUp's &lt;a id="ma_-" title="UI.start_timer" href="http://download.sketchup.com/OnlineDoc/gsu6_ruby/Docs/ruby-ui.html#start_timer"&gt;UI.start_timer&lt;/a&gt; method, which instructs the API to call a snippet of code on a regular basis.&lt;br /&gt;&lt;br /&gt;blackhole.rb (add these to the bottom of the existing file)&lt;br /&gt;&lt;span style=";font-family:courier new;font-size:85%;"  &gt;&lt;br /&gt;# Define our method that starts an animation.&lt;br /&gt;def start_animation(entity, target_pt)&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;# This calls our code snippet once every 10th of a second... &lt;br /&gt;&amp;nbsp;&amp;nbsp;frames_per_second = 10.0&lt;br /&gt;&amp;nbsp;&amp;nbsp;pause_length = 1.0 / frames_per_second&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;timer_id = UI.start_timer(pause_length, true) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;move_halfway_toward(entity, target_pt)&lt;br /&gt;&amp;nbsp;&amp;nbsp;# If we're within an inch of the origin, turn off the timer.&lt;br /&gt;&amp;nbsp;&amp;nbsp;new_location = entity.transformation.origin&lt;br /&gt;&amp;nbsp;&amp;nbsp;distance_from_target = new_location.distance target_pt&lt;br /&gt;&amp;nbsp;&amp;nbsp;if distance_from_target &amp;lt 1.0&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;UI.stop_timer timer_id&lt;br /&gt;&amp;nbsp;&amp;nbsp;end&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# Create a rightclick handler that'll activate it.&lt;br /&gt;UI.add_context_menu_handler do |context_menu|&lt;br /&gt;&amp;nbsp;&amp;nbsp;context_menu.add_item('Animate to origin') {&lt;br /&gt;&amp;nbsp;&amp;nbsp;entity = Sketchup.active_model.selection[0]&lt;br /&gt;&amp;nbsp;&amp;nbsp;origin_pt = Geom::Point3d.new 0, 0, 0&lt;br /&gt;&amp;nbsp;&amp;nbsp;start_animation(entity, origin_pt)&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;end&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=""&gt;Restart SU, &lt;a id="a1mc" title="download some cheese" href="http://sketchup.google.com/3dwarehouse/search?q=cheese&amp;amp;btnG=Search&amp;amp;styp=m&amp;amp;reps=1"&gt;&lt;span style=""&gt;download some cheese&lt;/a&gt;&lt;span style=""&gt;, and get to animating! If you're motivated, you could try these fun, extra credit assignments:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style=""&gt;Experiment with the frames_per_second to change the speed. (easy)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;span style=""&gt;Use &lt;a id="gr.x" title="UI.inputbox" href="http://download.sketchup.com/OnlineDoc/gsu6_ruby/Docs/ruby-ui.html#inputbox"&gt;&lt;span style=""&gt;UI.inputbox&lt;/a&gt;&lt;span style=""&gt; to ask for an X, Y, Z location to animate to. (medium) &lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;span style=""&gt;Send a &lt;a id="w:zk" title="raytest" href="http://download.sketchup.com/OnlineDoc/gsu6_ruby/Docs/ruby-model.html#raytest"&gt;&lt;span style=""&gt;raytest&lt;/a&gt;&lt;span style=""&gt; from the base of your cheese downward, to determine the nearest "ground" geometry, and have the cheese animate to land right on it! (tough) &lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;span style=""&gt;Use a &lt;a id="s3kk" title="custom tool" href="http://download.sketchup.com/OnlineDoc/gsu6_ruby/Docs/ruby-tool.html"&gt;&lt;span style=""&gt;custom tool&lt;/a&gt;&lt;span style=""&gt; to activate animations with a single click! (semi-soft, with a salty rind) &lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6313632118977055554-1020286951999038029?l=sketchupapi.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleSketchupApiBlog/~4/ulRHDTRKQz4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://sketchupapi.blogspot.com/feeds/1020286951999038029/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6313632118977055554&amp;postID=1020286951999038029" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6313632118977055554/posts/default/1020286951999038029?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6313632118977055554/posts/default/1020286951999038029?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleSketchupApiBlog/~3/ulRHDTRKQz4/animate-yo-cheese.html" title="Animate Yo' Cheese" /><author><name>Scott Lininger</name><uri>http://www.blogger.com/profile/05141972816510160560</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="17366763003152500127" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://sketchupapi.blogspot.com/2008/10/animate-yo-cheese.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEcDRHY8fCp7ImA9WxRRF04.&quot;"><id>tag:blogger.com,1999:blog-6313632118977055554.post-916467564039101878</id><published>2008-09-29T16:16:00.000-07:00</published><updated>2008-09-29T16:47:55.874-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-09-29T16:47:55.874-07:00</app:edited><title>Reading Textures from a SketchUp Model Using the Reader SDK</title><content type="html">&lt;span class="byline-author"&gt;Posted by Sang Ahn, SketchUp Software Engineer&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;In case you haven't looked yet, we have an &lt;a id="h96l" href="http://code.google.com/apis/sketchup/docs/downloadsdksubmit.html" title="SDK"&gt;SDK&lt;/a&gt; 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 &lt;a id="q9v." href="http://www.luxology.com/whatismodo/plugins/plugin_sketchup_importer.aspx" title="application"&gt;application&lt;/a&gt; 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.&lt;br /&gt;First, using the SkechUp document object, create the texture writer object:&lt;/div&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;ISkpApplication* sketchup_application = NULL;&lt;br /&gt;sketchup_document-&gt;get_Application(&amp;amp;sketchup_application);&lt;br /&gt;ISkpTextureWriter* texture_writer = NULL;&lt;br /&gt;sketchup_application-&gt;CreateTextureWriter(&amp;amp;texture_writer);&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;div&gt;Next, retrieve the ISkpCorrectPerspective interface of the texture writer:&lt;/div&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;div&gt;ISkpCorrectPerspective* perspective = NULL;&lt;br /&gt;texture_writer-&gt;QueryInterface(IID_ISkpCorrectivePerspective,&lt;br /&gt;&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;amp;perspective);&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;div&gt;For each face retrieve its UV helper object using the perspective object:&lt;/div&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;div&gt;ISkpUVHelper* uv_helper = NULL;&lt;br /&gt;face-&gt;GetUVHelper(face,&lt;br /&gt;&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp true,  // front face&lt;br /&gt;&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp perspective,&lt;br /&gt;&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;amp;uv_helper);&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;div&gt;Finally, create the triangulated mesh:&lt;/div&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;div&gt;ISkpPolygonMesh* mesh = NULL;&lt;br /&gt;face-&gt;CreateMesh(&lt;br /&gt;&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp PolygonMeshPoints |&lt;br /&gt;&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp PolygonMeshUVQFront |&lt;br /&gt;&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp PolygonMeshUVQBack,&lt;br /&gt;&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp perspective, &amp;amp;mesh);&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;div&gt;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.&lt;/div&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;div&gt;double position[] = {0, 0, 0};&lt;br /&gt;mesh-&gt;_GetPoint(index, position);&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;div&gt;Finally, retrieve the uvq value that corresponds to the vertex position.  The uvq value does not need to be transformed like the position value:&lt;/div&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;div&gt;double uvq[] = {0, 0, 0};&lt;br /&gt;uv_helper-&gt;GetFrontUVQ(&lt;br /&gt;&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp position[0],&lt;br /&gt;&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp position[1],&lt;br /&gt;&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp position[2],&lt;br /&gt;&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp &amp;amp;uvq[0],&lt;br /&gt;&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp &amp;amp;uvq[1],&lt;br /&gt;&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp &amp;amp;uvq[1]);&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;div style="text-align: auto;"&gt;Stay tuned for further tips and tricks.&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6313632118977055554-916467564039101878?l=sketchupapi.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleSketchupApiBlog/~4/b8jHphiLFIM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://sketchupapi.blogspot.com/feeds/916467564039101878/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6313632118977055554&amp;postID=916467564039101878" title="16 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6313632118977055554/posts/default/916467564039101878?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6313632118977055554/posts/default/916467564039101878?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleSketchupApiBlog/~3/b8jHphiLFIM/reading-textures-from-sketchup-model.html" title="Reading Textures from a SketchUp Model Using the Reader SDK" /><author><name>Sang Ahn</name><uri>http://www.blogger.com/profile/15950646401058474337</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="02517248003770367906" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">16</thr:total><feedburner:origLink>http://sketchupapi.blogspot.com/2008/09/reading-textures-from-sketchup-model.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0ADSH89fyp7ImA9WxZVEU4.&quot;"><id>tag:blogger.com,1999:blog-6313632118977055554.post-6183793072424688681</id><published>2008-03-21T15:47:00.000-07:00</published><updated>2008-03-21T15:49:39.167-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-03-21T15:49:39.167-07:00</app:edited><title>Inserting an External SketchUp Component (of some Pants)</title><content type="html">Posted by Scott Lininger, SketchUp Software Engineer&lt;br /&gt;&lt;br /&gt;You've just SketchUped an &lt;i id="c-ny"&gt;amazing&lt;/i&gt; &lt;a title="Robot Monkey" href="http://sketchup.google.com/3dwarehouse/details?mid=64e8de6ff3a7f4bd4a61afe7d0ea14a6&amp;amp;prevstart=0" id="e_jw"&gt;Robot Monkey&lt;/a&gt;, and you're ready to include him in your company brochure. Excitedly, you email the &lt;a title="3D PDF" href="http://wiki.renderplus.com/index.php?title=RPS_3D_PDF" id="mr6y"&gt;3D PDF&lt;/a&gt; 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.&lt;br /&gt;&lt;br /&gt;Fortunately, you anticipated this problem and have a very nice model of some &lt;a title="Monkey Pants" href="http://sketchup.google.com/3dwarehouse/details?mid=3a527cc9f19c7c4bce48c8156131b77c&amp;amp;prevstart=0" id="lrrk"&gt;respectable trousers&lt;/a&gt;. Now you just need to insert them into your model, preferably by using the Ruby API.&lt;br /&gt;&lt;br /&gt;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.)&lt;br /&gt;&lt;br /&gt;&lt;span id="gvhv"   style="font-family:Courier New;font-size:85%;"&gt;pants_def = Sketchup.active_model.definitions.load("C:\pants.skp")&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span id="jndq"   style="font-family:Courier New;font-size:85%;"&gt;Sketchup.active_model.place_component(pants_def)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If everything typed out okay, then you should be inserting some snazzy pants using the standard "place component" tool. Hooray!&lt;br /&gt;&lt;br /&gt;"But that's not very useful," you say, "It's easier to use the Component Browser to do &lt;i id="x08_"&gt;that&lt;/i&gt;! What if I don't know the path to my pants? What if you want to place my pants in a particular spot?"&lt;br /&gt;&lt;br /&gt;Okay, okay. Here's a more complete snippet that keeps the power in the control of the Ruby.&lt;br /&gt;&lt;br /&gt;&lt;span id="f_i1" style="color: rgb(61, 133, 198);font-size:85%;" &gt;&lt;span id="que0"  style="font-family:Courier New;"&gt;# First, load our pants (heh). This time we'll search for&lt;br /&gt;# the file inside our Components directory.&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span id="z5-x"   style="font-family:Courier New;font-size:85%;"&gt;pants_path = Sketchup.find_support_file "pants.skp" ,"Components"&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span id="db:8"   style="font-family:Courier New;font-size:85%;"&gt;pants_def = model.definitions.load pants_path&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span id="a89k" style="color: rgb(56, 118, 29);font-size:85%;" &gt;&lt;br /&gt;&lt;/span&gt;&lt;span id="gfi7" style="color: rgb(61, 133, 198);font-size:85%;" &gt;&lt;span id="f2tt"  style="font-family:Courier New;"&gt;# Then define a location, and place our pants there.&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span id="lq6:"   style="font-family:Courier New;font-size:85%;"&gt;pants_location = Geom::Point3d.new 100,200,0&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span id="tnaa"   style="font-family:Courier New;font-size:85%;"&gt;  transform = Geom::Transformation.new &lt;/span&gt;&lt;span id="dl_a"   style="font-family:Courier New;font-size:85%;"&gt;pants_location&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span id="f2z3"   style="font-family:Courier New;font-size:85%;"&gt;entities = Sketchup.active_model.active_entities&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span id="i3ww"   style="font-family:Courier New;font-size:85%;"&gt;instance = entities.add_instance pants_def, transform&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;And at long last, your Monkey has Pants, and you're the new company hero!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6313632118977055554-6183793072424688681?l=sketchupapi.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleSketchupApiBlog/~4/8FEdM2JswwU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://sketchupapi.blogspot.com/feeds/6183793072424688681/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6313632118977055554&amp;postID=6183793072424688681" title="10 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6313632118977055554/posts/default/6183793072424688681?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6313632118977055554/posts/default/6183793072424688681?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleSketchupApiBlog/~3/8FEdM2JswwU/inserting-external-sketchup-component.html" title="Inserting an External SketchUp Component (of some Pants)" /><author><name>Scott Lininger</name><email>noreply@blogger.com</email></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">10</thr:total><feedburner:origLink>http://sketchupapi.blogspot.com/2008/03/inserting-external-sketchup-component.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ak8AQnY6cCp7ImA9WxZQGUg.&quot;"><id>tag:blogger.com,1999:blog-6313632118977055554.post-8593359162888132674</id><published>2008-02-19T08:11:00.000-08:00</published><updated>2008-02-25T09:00:43.818-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-02-25T09:00:43.818-08:00</app:edited><title>Sharing data between SketchUp Ruby and Javascript</title><content type="html">Posted by Scott Lininger, SketchUp Software Engineer&lt;br /&gt;&lt;br /&gt;If you are building rich WebDialogs in your SketchUp Plugin, then you are probably using Javascript + DHTML (Dynamic HTML) to show the UI and handle user input. In practical terms, this means that you could easily have as much Javascript code in your plugin as Ruby code! But the SketchUp API documentation doesn't give much guidance on using Javascript to talk to SketchUp. What's a coder to do?&lt;br /&gt;&lt;br /&gt;Sharing data between Javascript and Ruby can be a bit of a black art. The Ruby API provides two mechanisms that we can leverage:&lt;br /&gt;&lt;br /&gt;1. WebDialog.add_action_callback() allows us to define a Ruby method that a WebDialog can call. This allows us to send data DOWN from Javascript to Ruby.&lt;br /&gt;&lt;br /&gt;2. WebDialog.execute_script() allows us to run a bit of Javascript code from inside Ruby. This allows us to send data UP from Ruby to Javascript.&lt;br /&gt;&lt;br /&gt;By using these two mechanisms together, we can create a nice, generic way for Javascript to get whatever it needs from Ruby.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:180%;"&gt;Step 1: Using add_action_callback to request some data&lt;/span&gt;&lt;br /&gt;For our example, let's imagine we have two files inside our Plugins directory: selectionInfo.rb and selectionInfo.html. Together, these files provide a new feature to SketchUp: a floating window that shows us how many objects are selected inside SketchUp.&lt;br /&gt;&lt;br /&gt;Our first step is to show a WebDialog and establish our action callback. Here's the minimal code required to make this work:&lt;br /&gt;&lt;br /&gt;selectionInfo.rb&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;# Create the WebDialog instance&lt;br /&gt;my_dialog = UI::WebDialog.new("Selection Info", false, "Selection Info", 200, 200, 200, 200, true)&lt;br /&gt;&lt;br /&gt;# Attach an action callback&lt;br /&gt;my_dialog.add_action_callback("get_data") do |web_dialog,action_name|&lt;br /&gt; UI.messagebox("Ruby says: Your javascript has asked for " + action_name.to_s)&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# Find and show our html file&lt;br /&gt;html_path = Sketchup.find_support_file "selectionInfo.html" ,"Plugins"&lt;br /&gt;my_dialog.set_file(html_path)&lt;br /&gt;my_dialog.show()&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;selectionInfo.html&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;&amp;lt;html&amp;gt;&lt;br /&gt;&amp;lt;script&amp;gt;&lt;br /&gt;function callRuby(actionName) {&lt;br /&gt; query = 'skp:get_data@' + actionName;&lt;br /&gt; window.location.href = query;&lt;br /&gt;}&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt; &amp;lt;h3 id="output"&amp;gt;You have 0 things selected.&amp;lt;/h3&amp;gt;&lt;br /&gt; &amp;lt;input type="button" onclick="callRuby('pull_selection_count')" value="Refresh"&amp;gt;&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If you create these two files and save them into your Plugins directory, you'll see a very simple WebDialog the next time you restart SketchUp. Click on the "Refresh" button and you'll see a messagebox that was generated by our Ruby (but controlled based on data from the Javascript.)&lt;br /&gt;&lt;br /&gt;Make sense? We now have a mechanism for sending data down to Ruby, which is a way for Javascript to ask Ruby a question. Now we just need Ruby to provide an answer...&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:180%;"&gt;Step 2: Using execute_script to send some data&lt;/span&gt;&lt;br /&gt;The next step in our data sharing scheme requires us to respond. Let's add a few lines of code to our files... (Changed code is highlighted in yellow.)&lt;br /&gt;&lt;br /&gt;selectionInfo.rb&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;# Create the WebDialog instance&lt;br /&gt;my_dialog = UI::WebDialog.new("Selection Info", false, "Selection Info", 200, 200, 200, 200, true)&lt;br /&gt;&lt;br /&gt;# Attach an action callback&lt;br /&gt;my_dialog.add_action_callback("get_data") do |web_dialog,action_name|&lt;br /&gt;&lt;span style="background-color:yellow;"&gt;  if action_name=="pull_selection_count"&lt;br /&gt;   total_selected = Sketchup.active_model.selection.length&lt;br /&gt;   js_command = "passFromRubyToJavascript("+ total_selected.to_s + ")"&lt;br /&gt;   web_dialog.execute_script(js_command)&lt;br /&gt; end&lt;/span&gt;&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# Find and show our html file&lt;br /&gt;html_path = Sketchup.find_support_file "selectionInfo.html" ,"Plugins"&lt;br /&gt;my_dialog.set_file(html_path)&lt;br /&gt;my_dialog.show()&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;selectionInfo.html&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;&amp;lt;html&amp;gt;&lt;br /&gt;&amp;lt;script&amp;gt;&lt;br /&gt;function callRuby(actionName) {&lt;br /&gt; query = 'skp:get_data@' + actionName;&lt;br /&gt; window.location.href = query;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="background-color:yellow;"&gt;function passFromRubyToJavascript(value) {&lt;br /&gt; var message = "You have " + value + " items selected.";&lt;br /&gt; document.getElementById('output').innerHTML = message;&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt; &amp;lt;h3 id="output"&amp;gt;You have 0 things selected.&amp;lt;/h3&amp;gt;&lt;br /&gt; &amp;lt;input type="button" onclick="callRuby('pull_selection_count')" value="Refresh"&amp;gt;&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Save these changes, and then restart SketchUp. Now when you click on the "Refresh" button, you get an updated web page showing the number of objects selected.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:180%;"&gt;Looking ahead: Using JSON for more complex data&lt;/span&gt;&lt;br /&gt;We've been working with an extremely simple example where we're passing a single number. In a real world application you would probably be sending more complex data. In this case, JSON (Javascript Object Notation) is the perfect mechanism. It's a way where you can pass nested objects and arrays in a single command.&lt;br /&gt;&lt;br /&gt;We'll explore more about JSON in a future blog post. But for now, consider the following example.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;# Passing lots of data about a component&lt;br /&gt;js_command = "passFromRubyToJavascript({typename:'ComponentInstance',name:'Bryce',x:10.5,y:13.5,z:0.0})"&lt;br /&gt;web_dialog.execute_script(js_command)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This kind of approach is a great way to allow Javascript to get large, structured data sets out of SketchUp whenever your application needs them. Stay tuned for a deeper exploration of this idea.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6313632118977055554-8593359162888132674?l=sketchupapi.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleSketchupApiBlog/~4/4NXNMFApyAI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://sketchupapi.blogspot.com/feeds/8593359162888132674/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6313632118977055554&amp;postID=8593359162888132674" title="13 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6313632118977055554/posts/default/8593359162888132674?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6313632118977055554/posts/default/8593359162888132674?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleSketchupApiBlog/~3/4NXNMFApyAI/sharing-data-between-sketchup-ruby-and.html" title="Sharing data between SketchUp Ruby and Javascript" /><author><name>Scott Lininger</name><email>noreply@blogger.com</email></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">13</thr:total><feedburner:origLink>http://sketchupapi.blogspot.com/2008/02/sharing-data-between-sketchup-ruby-and.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUUBRXc5cCp7ImA9WB9bEUw.&quot;"><id>tag:blogger.com,1999:blog-6313632118977055554.post-1015915740369056521</id><published>2007-12-19T10:37:00.000-08:00</published><updated>2007-12-19T18:20:54.928-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2007-12-19T18:20:54.928-08:00</app:edited><title>WebDialog</title><content type="html">&lt;span class="byline-author"&gt;Posted by Sang Ahn, SketchUp Software Engineer&lt;br /&gt;&lt;br /&gt;&lt;/span&gt; &lt;div&gt; One of the interesting features of SketchUp's Ruby API is the &lt;a id="p.rj" href="http://code.google.com/apis/sketchup/docs/developers_guide/classes/UI/WebDialog.html" title="UI::WebDialog"&gt;UI::WebDialog&lt;/a&gt; class.  Since WebDialog supports DHTML and JavaScripts, you can provide a rich, custom user experience for your SketchUp plugin users.  You may be thinking, just another dialog box pretending to be a browser-lite, right?&lt;span style="color: rgb(255, 0, 0);"&gt;  &lt;/span&gt;But there's more: with WebDialog you can call Ruby code from within the DHTML content of the dialog's document.  No, this isn't some kind of listen-to-port-80-and-redirect trick.  You define a block of execution in your Ruby code, assign it to the WebDialog object by name, and when the user selects the input element with that name the block is executed.  Let's say you have an input element such as this:&lt;/div&gt;&lt;br /&gt;&lt;code&gt;&amp;lt;a href="skp:myAction@Hello"&amp;gt;&lt;/code&gt;&lt;span style="font-family:Courier New;"&gt;say hi!&amp;lt;/a&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;Now, all you have to do is define a block of execution and assign it with the name "myAction."&lt;/div&gt;&lt;br /&gt;&lt;code&gt;dialog.add_action_callback("myAction") { |d, p| puts p }&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt; When the user clicks on the input element, it's the equivalent to &lt;/div&gt;&lt;br /&gt;&lt;code&gt; proc = Proc.new { |d, p| puts d} &lt;/code&gt;&lt;br /&gt;&lt;code&gt; proc.call(dialog, "Hello") &lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;Simple and useful.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6313632118977055554-1015915740369056521?l=sketchupapi.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleSketchupApiBlog/~4/Lqw2J7LQomg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://sketchupapi.blogspot.com/feeds/1015915740369056521/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6313632118977055554&amp;postID=1015915740369056521" title="6 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6313632118977055554/posts/default/1015915740369056521?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6313632118977055554/posts/default/1015915740369056521?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleSketchupApiBlog/~3/Lqw2J7LQomg/webdialog.html" title="WebDialog" /><author><name>Sang Ahn</name><uri>http://www.blogger.com/profile/15950646401058474337</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="02517248003770367906" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">6</thr:total><feedburner:origLink>http://sketchupapi.blogspot.com/2007/12/webdialog.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D04BQ3s4fip7ImA9WB9UFkg.&quot;"><id>tag:blogger.com,1999:blog-6313632118977055554.post-6148463781565257509</id><published>2007-12-14T10:15:00.000-08:00</published><updated>2007-12-14T10:12:32.536-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2007-12-14T10:12:32.536-08:00</app:edited><title>Hello World</title><content type="html">&lt;span class="byline-author"&gt;Posted by the SketchUp API team&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Welcome to the Google SketchUp API Blog.  We are very excited to have this venue to post information and updates for developers who are creating tools and exporters for  SketchUp.  This blog will cover both the SketchUp Ruby API and the SketchUp SDK (beta).  We hope to be posting regularly about new API features and fixes, and from time to time we'll also be sharing examples of what you can do with our API's. We encourage you to post any comments and concerns you have, and look forward to hearing from you!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6313632118977055554-6148463781565257509?l=sketchupapi.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/GoogleSketchupApiBlog/~4/a0pUgVsX_yA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://sketchupapi.blogspot.com/feeds/6148463781565257509/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6313632118977055554&amp;postID=6148463781565257509" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6313632118977055554/posts/default/6148463781565257509?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6313632118977055554/posts/default/6148463781565257509?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/GoogleSketchupApiBlog/~3/a0pUgVsX_yA/posted-by-sketchup-api-team-welcome-to.html" title="Hello World" /><author><name>A Googler</name><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="08971260574430529266" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://sketchupapi.blogspot.com/2007/12/posted-by-sketchup-api-team-welcome-to.html</feedburner:origLink></entry></feed>
