sketchucation logo sketchucation
    • Login
    1. Home
    2. bentleykfrog
    3. Posts
    ⚠️ Attention | Having issues with Sketchucation Tools 5? Report Here
    B
    Offline
    • Profile
    • Following 0
    • Followers 0
    • Topics 7
    • Posts 84
    • Groups 1

    Posts

    Recent Best Controversial
    • RE: [Plugin] CameraControls

      Nice Plugin Rick,

      Its really helpful when aligning the camera to a face in parallel projection and then rotating so the view is "upright". One problem I found is that in parallel projection the camera zooms out to the extents when adjusting the values. I had a look at the code and the simple solution is to store and maintain the camera.height value for non-perspective views, ie:

      maintaining:

      if (!perspective)
        @view.camera.height = @height
      end
      

      storing:

      @height = @camera.height if set == "all" || set == "camera"
      
      posted in Plugins
      B
      bentleykfrog
    • RE: Drawing a line for the camera?

      @sketchnl said:

      @sketchnl said:

      @bentleykfrog said:

      @mitcorb said:

      I am gonna hazard a guess that it is "Proper Animation"? Search this
      hope this helps.....
      -niall

      Thanks People, this is so useful

      No worries Jeremy.

      Here's the link to Revert Curve by Fredo6

      posted in Plugins
      B
      bentleykfrog
    • RE: Drawing a line for the camera?

      @mitcorb said:

      I am gonna hazard a guess that it is "Proper Animation"? Search this keyword/phrase in this Forum, maybe.

      I think Proper Animation would be good for animating objects rather than the camera. For camera animations it uses Sketchup scenes.

      @sketchnl said:

      I have a project where people want to see the inside of a house. My problem is animating the camera along a path.

      There's two plugins that I can think of, both could do what you're looking for with a little tweaking.

      http://www.smustard.com/script/FlightPath
      http://www.smustard.com/script/FlightPath2

      FlightPath allows you to take a curve and use it as a camera path. There are a couple of issues with this that could cause some headaches for you. I've had to rely on other plugins to get a good result with FlightPath, so I'll quickly go through them.

      The first issue is creating a curve. If you've got a complex path that contains a lot of circles, straight lines and bezier curves thaen you'll need to weld this into one single curve before you start to use the tool. I'm still using the old [url=http://modelisation.nancy.archi.fr/rld/plugin_details.php?id=474:ztq958a5]Weld plugin by Rick Wilson[/url:ztq958a5] for this job, and it seems to work fine, but Diggsey has written [url=http://forums.sketchucation.com/viewtopic.php?t=36822:ztq958a5]Recurve Plugin[/url:ztq958a5], which contains a lot more features than Weld, though I'm yet to try it out.

      The second issue is the vertices in the curve you've created. FlightPath works by creating a scene at each vertex on your curve, then animating between each scene with Sketchup's scene transitions. It regulates speed by changing the scene transition time rather than changing the vertex position. So this means that if you have vertices placed in an irregular fashion you might get some unusual results. It also means that effects like acceleration are a bit difficult to do. To get evenly spaced vertices I use a tool called [url=http://forums.sketchucation.com/viewtopic.php?t=13563:ztq958a5]BezierSpline by Fredo6[/url:ztq958a5]. When you right-click on your curve, you have a submenu called "BZ - Convert to". In this submenu you have the option to Polyline Divide. This will give you the option to divide your curve by any number you like. You'll have to play around a bit with the number to get a good result.

      There's also a plugin called [url=http://www.ohyeahcad.com/suanimate/:ztq958a5]SU Animate by OhYeahCAD[/url:ztq958a5]. Its very similar to FlightPath in the way it animates the camera, so I won't talk much on it.

      Now for a bit of self promotion. I'm currently working on [url=http://forums.sketchucation.com/viewtopic.php?f=323&t=35140:ztq958a5]Sketchup Floating Camera[/url:ztq958a5], which will give you a video game like ability to animate the camera. Its on the shelf at the moment as I've got some uni work that needs dire attention, but when completed it will give some nice physics effects with the camera animation. And coupled with [url=http://forums.sketchucation.com/viewtopic.php?t=23517:ztq958a5]Chris Fullmer's Camera Recorder[/url:ztq958a5], it will give you the option to edit and smooth out the camera flight path you've recorded, to make presentations nicer. Hopefully I'll get this out in the next 4 weeks, after all the bugs have been ironed out.

      hope this helps,

      -niall

      posted in Plugins
      B
      bentleykfrog
    • RE: [Plugin] BezierSpline - v2.2a - 22 Apr 21

      @unknownuser said:

      @bentleykfrog said:

      cool tool, just one suggestion. It would be helpful to reverse the direction of the polyline divide function so you can choose which end the dividing starts at. Currently, for curves that have an incorrect start and end, I have to explode my curve, then recreate the curve using the classic bezier curve tool, then use polyline divide.

      Sorry for my ignorance if this feature already exists.

      The feature does not exist in BezierSpline, but you can use the plugin RevertCurve to inverse the direction of the curve.

      Fredo

      Ahh! awesome, thanks again Fredo6

      posted in Plugins
      B
      bentleykfrog
    • RE: [Plugin] BezierSpline - v2.2a - 22 Apr 21

      Ohh, I forgot to post an example of how I've used the tool. I used Polyline divide in the image below on the lines that set out the rows of vines, then I used Chris Fullmer's Component Stringer to set out the vine components along these paths. Very happy with the result β˜€
      Polyline Divide usage example

      posted in Plugins
      B
      bentleykfrog
    • RE: [Plugin] BezierSpline - v2.2a - 22 Apr 21

      cool tool, just one suggestion. It would be helpful to reverse the direction of the polyline divide function so you can choose which end the dividing starts at. Currently, for curves that have an incorrect start and end, I have to explode my curve, then recreate the curve using the classic bezier curve tool, then use polyline divide.

      Sorry for my ignorance if this feature already exists.

      posted in Plugins
      B
      bentleykfrog
    • RE: Preview - Sketchup Floating Camera [Update 2011-03-19]]

      @wimve said:

      Wow looks great. Although not tested yet I have a question already: is it possible to include a "flightpath" ? So a predefined camera path.

      For instance when you want to walk through several rooms it is hard to move around nicely with only the keyboard keys. But if you draw a line at the desired eyeheight which the camera has to follow this would be easier.

      I haven't looked into this but it could be possible, but its sort of going in the opposite direction to what the plugin does currently. I'll elaborate a little.

      First off, I think Rick Wilson's plugin FlightPath2 handles flight paths, or there's also SU Animate. Have you tried these plugins? This is what comes to mind when I think of implementing a flight path in the plugin, are you thinking of something similar or do you have something different in mind.

      In my current internal build of the script, you can use it in combination with either Chris Fullmer's Camera Recorder or Pixero's version of Chris Fullmer's Camera Recorder to record the Camera's flight path whilst using the Camera Float Tool. In Pixero's version, you can then modify this path (ie. remove all the bumps from the flight path) and then produce a final animation from the revised flight path. I used this technique in the first video to get a 'more-smooth' animation through the model and to produce a video that is rendered with shadows (obviously navigating with the Camera Float Tool with shadows on will slow down your movements significantly).

      Also from your query, I decided to test the tool on a very tight model (Le Corbusier's Villa Savoye by Robert-34000 on the 3d Warehouse). This model has insanely tight stairs and a ramp and its internal arrangement is all over the place (IMO obviously). I've recorded the video for you to see how it faired:

      [flash=800,480:3r7gzeob]http://www.youtube.com/v/fXncZU60Ftc[/flash:3r7gzeob]

      If you notice at around the 42 second mark, I accidentally jump onto the ballustrade of the ramp. You should be able to edit this out using Pixero's version of Chris Fullmer's Camera Recorder. Also notice, that since I couldn't be bothered removing all the doors in the building, that I disable collision every time I want to pass through a door.

      I'm also planning to add a different scale for looking up and down so you get better control whilst navigating through your model.

      posted in Plugins
      B
      bentleykfrog
    • RE: Preview - Sketchup Floating Camera [Update 2011-03-19]]

      @jclements said:

      Looks pretty neat.

      I do like the idea of holding the camera at a fixed altitude.

      If you could then have ability to focus on a point or selected object or just the center to the screen and orbit about it at a fixed radius, that would be very useful .... like what what can be done in Google Earth with the Shift-Alt-left-arrowkey or Shift-Alt-right-arrowkey combinations.

      Good suggestion, that would be a cool feature to have. In this release I'm just focussing on navigation from the human proportion coupled with the ability to float if you need to πŸ˜‰ I'll look into more sophisticated methods of camera animation in the next release.

      posted in Plugins
      B
      bentleykfrog
    • RE: [code] Load Instructor v1.0.1

      Just updated the code with a very quick fix.

      In the previous version on PC, there was an error produced in the ruby console along the lines of "Directory Not Empty". In early beta versions the temporary folder name was created from a unique string using a timestamp. In the current version, consistent temporary folder names was implemented, so any previous directories needed to be deleted.. I've expanded the delete method in the script to search the subdirectories of the temporary folder if it exists and clear them out before deletion. This stops the error.

      Also, when the temporary location was more than one folder deep (ie. my_script/instructor), the folder 'my_script' was not being created. V 1.0.1 searches each folder in your custom temporary path and creates the folder if it doesn't exist, removing this error.

      This update is essential for proper implementation of Load Instructor.

      posted in Developers' Forum
      B
      bentleykfrog
    • RE: Instructor content

      Just a quick reply before I have to run some errands.

      @bentleykfrog said:

      Ahh, I see. In my case, using Alex's Plugin Loader, when a new script is loaded $LOAD_PATH's aren't updated to show the file's folder location.

      I should have elaborated on what I meant by $LOAD_PATH. In this case, I meant the folders that are represented in the $LOAD_PATH array. As a case example, take my University. There's only read access granted to anything below C:/Program Files & C:/Program Files (x86). They don't provide a script that will load some read/writeable directories to the $LOAD_PATH array. I'm asserting that if there was a similar setup, but had Alex's Plugin Loader underneath one of the $LOAD_PATH's in C:/Program Files & C:/Program Files (x86), you would need to bundle load_instructor.rb with your script, and provide an absolute path to it using require(). This is probably quite rare though, but its one of the reasons I provide the Advanced Use of the Load Instructor.

      got to go, will respond to your post in more detail when I get some more free time.

      -niall

      posted in Developers' Forum
      B
      bentleykfrog
    • RE: [code] Load Instructor v1.0.1

      @dan rathbun said:


      Excellent Help File Niall !!!!


      A little boo-boo, help file says version 1.0 which it should be, but the script header still has beta 0.2 listed.

      A few clarifications for section 5
      (You missed the 'b' in my surname. Rathbun is a version of Rathbone, but the immigrant to America was illiterate.)

      😳 Sorry for incorrectly spelling your name Dan. I've updated the pdf and the load_instructor.rb file to fix all that you've picked up on. Hopefully there's no more spelling errors πŸ˜‰

      posted in Developers' Forum
      B
      bentleykfrog
    • RE: Instructor content

      @dan rathbun said:

      @bentleykfrog said:

      Thats cool then, I don't really see an issue passing @@tool_filepath as an argument to lins_setup(). With default values and your script in the $LOAD_PATH's, lins_setup('my_scripts_files') won't require @@tool_filepath.

      You're missing the point of the @@tool_filepath variable.
      In the simple default mode, YOU set the script_folder argument of lins_setup() to have a default value so the method can be called with no arguments, like so:
      def lins_setup( instructor_folder=false, temp_folder=false, script_folder=File.dirname(@@tool_filepath) )

      I'm still trying to wrap my head around this. In the code's current state, using the default mode, the script_folder argument just specifies a relative path from any of the $LOAD_PATH's to the 'instructor' folder's parent. So absolute paths from different volumes won't work with this, unfortunately. The default mode assumes that you'll have access to the $LOAD_PATH's, or use a script that adds accessible folder to the $LOAD_PATH. Some plugin loader's don't do this 😞

      @dan rathbun said:

      @bentleykfrog said:

      You'll just need it [ @@tool_filepath] for requiring the mixin possibly?

      No.. the plugin script's path has nothing to do with what path the user decides to use for their mixin library. The mixin lbrary folder should be in a subfolder of one of the $LOAD_PATH members, so Ruby will have no problem finding it.

      Ahh, I see. In my case, using Alex's Plugin Loader, when a new script is loaded $LOAD_PATH's aren't updated to show the file's folder location. So I'm thinking of instances where a Sketchup user doesn't have access to the $LOAD_PATH's but does have a plugin loader script installed. So in this case, you would need to bundle up load_instructor.rb with your plugin's files. Then, we need to pass an absolute path to require() representing the location of load_instructor.rb. I was thinking that you would use File.dirname( @@tool_filepath for this, or in my Advanced Use example for .rb files I use File.dirname( __FILE__ ).

      @dan rathbun said:

      @bentleykfrog said:

      With custom values you'll need to pass absolute values as the second and third arguments so you'll need to use File.join( @@tool_filepath, 'my_scripts_files/instructor-boogaloo'), so that's quite easy to do, and I've documented it under Advanced Use.

      Actually as I said (above,) it's:
      File.dirname(@@tool_filepath)
      as @@tool_filepath will be a relative path that contains the tool script filename on the end.

      You're right, I forgot about that πŸ˜•

      posted in Developers' Forum
      B
      bentleykfrog
    • [code] Load Instructor v1.0.1

      load_instructor is a Mixin Module that automates copying of instructor files to the temporary directory on pc to bypass the issue with getInstructorContentDirectory only accepting relative paths. Whether it needs to copy the files or not, it will provide a getInstructorContentDirectory method to your class that will return a relative path to your instructor folder. This means its possible to keep your script completely portable cross-platform and ensures that your instructor is loaded to the Instructor window.

      A basic definition of use is included in the comments section of the script.

      Installation instructions.

      • Extract the zip file after downloading
      • Copy the /mixin/ directory to your Plugins or Tools folder
      • Read the code comments or the Users Guide attached to this post for integration with your script

      File structure:

      • [Plugins OR Tools Folder]/mixin/
      • [Plugins OR Tools Folder]/mixin/load_instructor.rb

      Users Guide
      Load Instructor - Users Guide [Updated 2011-03-15]

      Changelog

      • v 1.0.1 (2011-03-17)

      • Added folder in temp path creation if folders in path don't exist

      • Added proper temp file deletion (fix to File Not Found Error)

      Attached is the Module


      Load Instructor Version 1.0.1 [Updated 2011-03-17]

      posted in Developers' Forum
      B
      bentleykfrog
    • RE: Instructor content

      @dan rathbun said:

      Here's an example of a rbs loader script that loads a scrambled tool script named testtool.rbs:

      module Niall
      >   class TestTool
      >     require('mixin/load_instructor.rb')
      >     include( Mixin;;LoadInstructor )
      >     @@tool_filepath = File.dirname(__FILE__)+'/testtool.rbs'
      >     Sketchup.require( @@tool_filepath )
      >   end # class
      > end # module
      

      In this example, the author does the 'mixing' in the loader, sets @@tool_filepath and uses it in his call to load the rbs.

      Thats cool then, I don't really see an issue passing @@tool_filepath as an argument to lins_setup(). With default values and your script in the $LOAD_PATH's, lins_setup('my_scripts_files') won't require @@tool_filepath. You'll just need it for requiring the mixin possibly? With custom values you'll need to pass absolute values as the second and third arguments so you'll need to use File.join( @@tool_filepath, 'my_scripts_files/instructor-boogaloo'), so that's quite easy to do, and I've documented it under Advanced Use.

      Looks like I'm ready to release this code, I'll start a new topic.

      posted in Developers' Forum
      B
      bentleykfrog
    • RE: Instructor content

      Dan, your advice is invaluable. There's still a couple of things I'm concerned about:

      @dan rathbun said:

      The way I had it.. it would use __FILE__ as a default for non-scrambled files, and insist on a explicit assignment of the @@tool_filepath variable for rbs files.
      By instead, adding the required argument script_folder to the lins_setup() method, you have also defeated the default initialize() method that is mixed in (it has no arguments in the lins_setup() call.)
      I think it will work better for newbie's the previous way.

      The issue I had with the previous version was the way that load_instructor.rb constructed the default path to the /instructor/ folder. The previous version used __FILE__ from /mixin/load_instructor.rb and then navigated back to the folder that contained the /mixin/ folder. From that path it used /instructor/, so it meant that you would have issues if you had more than one ruby script using Load Instructor. So there needs to be a string attribute that identifies the name of the folder that contains /instructor/ to avoid this conflict between plugins. If the LoadInstructor mixin is going to be stored in a file that is separate from your script then calling __FILE__ will only be able to identify /load_instructor.rb and wont be able to identify the filename of the script that the LoadInstructor mixin was loaded into (unless there's a method for getting around this).

      Regarding the @@tool_filepath issue, you should still be able to declare these paths in the second and third attributes of lins_setup()? like:

      @@tool_filepath = VertexToolsPath
      
      def initialize
        instructor_folder = File.join( @@tool_filepath ,'your_scripts_folder/instructor')
        temp_folder       = (RUBY_PLATFORM =~ /darwin/i) ? '' ; File.join(ENV["TEMP"], 'your_scripts_folder/instructor')
        lins_setup('',instructor_folder,temp_folder)
      end
      

      And if you're storing all the files beneath any of the load path's, you shouldn't need to worry about the second and third attributes, or @@tool_filepath for that matter, like:

      def initialize
        lins_setup('your_scripts_folder')
      end
      

      @dan rathbun said:

      The $LOAD_PATH members can be manipulated. Making an assumption about where the the first member points could cause problems. (Refering to the lins_get_default_instructor_folder() method.)

      Hmmm, it should be best then if I threw an error if the /instructor/ folder can't be found, like (using your @@tool_filepath check):

      def lins_get_default_instructor_folder(script_folder)
        instructor_folder = ''
        $LOAD_PATH.each {|load_path|
          check_path = File.join(load_path, script_folder, 'instructor')
          if check_path != '(eval)' && File.exist?(check_path)
            instructor_folder = File.join(load_path, script_folder, 'instructor')
            break
          end
        }
        if instructor_folder.empty?
          file_path = File.join(script_folder, 'instructor')
          raise(ScriptError,"#{self.class.name}; Instructor folder error. Could not find #{file_path} beneath any of the $LOAD_PATH's.")
        else
          return instructor_folder
        end #if
      end #def
      

      I've adopted all your other suggestions to the script, I just have to sort out the former issues before I'll produce the first release.

      posted in Developers' Forum
      B
      bentleykfrog
    • RE: Instructor content

      @bentleykfrog said:

      Its a long way around but I'm thinking that it would be possible to write the required files and folders to the /temp/ folder on the C:/ drive before the tool loads, then use a relative path to the /temp/instructor/ directory in getInstructorContentDirectory. This would avoid the volume traversal problem but I think it would be a bit of a headache.

      Script Updated on 2011-03-13: See http://forums.sketchucation.com/viewtopic.php?f=180&t=31060&p=315364#p315364

      Here's a very long post and a very-rough draft of the Instructor-copy-to-temp-folder script. I've tested this on Windows 7 with Sketchup 8 and I used [url=http://forums.sketchucation.com/viewtopic.php?t=17660:2t71i41l]Alex's Plugin Loader[/url:2t71i41l] for testing on other drives. So far, it works quite well. I'm just rolling over testing on the mac and will update this if there needs to be changes.

      I'm not sure about alot of things, to say the least;

      • file chmod permissions on close? (ie. Security, should we go for a File.chmod(0644, temp_abs_path+entry) before close?)
      • file encoding copy? I'm using the texture writer to supplement the simplicity of my File.write code but I'm thinking that if encoding is preserved the script might not have the issue of corrupt images on copy (can we use require "fileutils", I've got no experience with ruby extensions)
      • block devices and character devices? 😲 (this flies way over my head)
      • And add more to that 'fifo', 'link', 'socket'
      • File.executable? checks? (probably not needed as sketchup loads the plugin script unless the plugin and instructor content are in completely foreign folders (thomthom?))
      • Temp directory clearing? is this necessary on tool close or would it be better to store a default with the script and maintain the files on exit, and check if the files exist and are consistent on next load? (probably better to clear and load for each sketchup session?)
      • Not sure about flash/movie/audio/etc.. files, (my target.write code doesn't like anything more complex than a text file, there's probably some encoding settings that I'm missing out on as in my first point that is corrupting the file on write. If fileutils is not possible then maybe encoding settings might solve this)
      • How about server locations on windows like "\someserver" instead of "C:\" πŸ˜•

      Also, please forgive the amateur coding, its my first try at something that is cut-and-paste portable. But I'm open for critique/suggestions for improvement (though its a little off topic, best to PM)

      # ##-------------------------##
      # ##----DEFINITION OF USE----##
      # ##-------------------------##
      # #first add the load instructor to your module
      # #or whatever module you'd like to add it to
      # #in this example, I've added it to MyModule
      
      # #calling the load instructor
      # #specifying no attributes should return the base temp and 
      # #construct a instructor path by; [ruby_script_name]/instructor
      # instructor_copy = MyModule;;LoadInstructor.new
      # #after calling the load instructor, you can set the
      # #instructor_folder & temp_folder if you need to adjust
      # #the default values
      # instructor_copy.instructor_folder = [custom instructor folder]
      # instructor_copy.temp_folder = [custom temp folder]
      # #or you can call the load instructor with custom directories like this
      # temp_folder = ([PLATFORM].grep(/mswin/)==[PLATFORM]) ? ENV["TEMP"] ; ENV["TMPDIR"]
      # instructor_folder = File.join(File.join(File.basename( __FILE__ ),"floating_camera"), "instructor")
      # instructor_copy = MyModule;;LoadInstructor.new( instructor_folder , temp_folder )
      # #we need to copy the files to the temp directory
      # #if needed by this method
      # instructor_copy.copyInstructor
      # #any errors in the copy will be reported to the ruby console
      
      # #after this has completed, you can return the instructor temp 
      # #folder path (relative to the temp folder) by;
      # instructor_temp_folder = instructor_copy.returnTempInstructorFolderName
      # #this will be helpful if you're storing the instructor temp 
      # #folder location in a class variable to check if you need 
      # #to run the script per sketchup session (returns false if 
      # #no temp folder created)
      
      # #finally, you can get the relative path from the sketchup 
      # #tools folder to the instructor folder (whether it was 
      # #copied to the temp folder or not) by calling
      # @@relative_instructor_folder = instructor_copy.returnRelativePath
      
      # #as an example, you can put these calls inside your tools 
      # #initialize method, like the example below. Initialize 
      # #will be called before getInstructorContentDirectory
      # def initialize
      	# instructor = CControl;;LoadInstructor.new
      	# instructor.copyInstructor
      	# @@relative_instructor_path = instructor.returnRelativePath
      # end #def
      
      # #and then add this def to your tool to give sketchup the
      # #relative path
      # def getInstructorContentDirectory
      	# return @@relative_instructor_path
      # end #def
      
      # #now you should have a consistent Instructor Directory
      # #across drives
      
      	#need to check if paths are relative or absolute
      	class LoadInstructor
      		attr_accessor ;instructor_folder, ;temp_folder
      		def initialize(instructor_folder=false, temp_folder=false)
      			if instructor_folder
      				@instructor_folder = instructor_folder
      			else
      				@instructor_folder = self.getDefaultInstructorFolder
      			end
      			if temp_folder
      				@temp_folder = temp_folder
      			elsif [PLATFORM].grep(/mswin/)!=[PLATFORM]
      				@temp_folder = @instructor_folder
      			else
      				@temp_folder = self.getDefaultTempFolder
      			end
      		end #def
      		
      		def getDefaultInstructorFolder
      			dir = File.expand_path(File.dirname( __FILE__ ))
      			file_ext = File.extname( __FILE__)
      			file_basename = File.basename( __FILE__ , file_ext)
      			dir = dir + "/" + file_basename + "/instructor"
      			return dir
      		end #def
      		
      		def getDefaultTempFolder
      			temp_folder = File.expand_path(ENV["TEMP"])
      			return temp_folder
      		end #def
      		
      		# adapted from http://boonedocks.net/mike/archives/162-Determining-Image-File-Types-in-Ruby.html
      		# checks for jpg,png,tif,tga & bmp and variations in their data formats
      		def getImageType(file)
      		
      			filestart = IO.read(file,30)
      			case filestart
      				when /^BM/
      					#puts "BMP; "+file
      					return 'bmp'
      				when /^GIF8/
      					#puts "GIF; "+file
      					return 'gif'
      				when /^MM\x00\*(\x00){3}/
      					#when /^MM.\*.{3}/
      					#puts "TIF MAC; "+file
      					return 'tif'
      				when /^II\*\x00\x08(\x00){3}\x15/
      					#when /^II\*./
      					#puts "TIF PC; "+file
      					return 'tif'
      				when /^\x89PNG/
      					#puts "PNG; "+file
      					return 'png'
      				when /^\xff\xd8\xff\xe0\x00\x10JFIF/
      					#puts "JPG; "+file
      					return 'jpg'
      				when /^\xff\xd8\xff\xe0/
      					#puts "JPG; "+file
      					return 'jpg'
      				when /^\xff\xd8\xff\xe1(.*){2}Exif/
      					#puts "JPG; "+file
      					return 'jpg'
      				when /^\x00\x00\x0A\x00/
      					#puts "TGA Compressed; "+file
      					return 'tga'
      				when /^\x00\x00\x02\x00/
      					#puts "TGA; "+file
      					return 'tga'
      				else
      					#check for tga files by extension
      					fileext = File.extname(file)
      					case fileext
      						when /^\.(?i)(tga|vda|icb|vst)/
      							#puts "TGA by extension; "+file
      							return 'tga'
      						when /^\.(?i)(tif|tiff)/
      							#puts "TIF by extension; "+file
      							return 'tif'
      					end #case
      					puts "unknown; "+IO.read(file,20).dump
      					return 'unknown'
      			end
      		end
      		
      		def checkValidity(filename)
      			filetype = File.ftype(filename) #grabs the file type; 'file','directory','characterSpecial','blockSpecial',
      																			#'fifo','link','socket','unknown'
      			case filetype
      				when "file"
      					if (!File.readable?(filename))
      						puts "file is not readable; "+filename
      						return "unreadable"
      					end #if
      					if (!File.size?(filename))
      						puts "file exists but has 0 size; "+filename
      						return "invalidsize"
      					end #if
      					image_type = self.getImageType(filename)
      					if(image_type == 'unknown')
      						puts "file exists but is unknown (assume text file); "+filename
      						return "unknowntype"
      					end #if
      					#puts "found image file; "+filename
      					return "imgfile"
      				when "directory"
      					#puts "found directory; "+filename
      					return "directory"
      			end #case
      		end #def
      		
      		#call like self.copyInstructorFiles([base_dir_of_instructor_folder],[base_dir_of_instructor_folder])
      		#dir changes on recursion through the child directories and basedir stays constant to
      		#maintain the folder/file structure in the temp folder
      		def copyInstructorFiles(temp_folder, dir, basedir)
      			entries = Dir.entries(dir)
      			if (dir != basedir)
      				temp_path = dir.dup
      				temp_path.slice!(basedir)
      				temp_folder_abs_path = temp_folder+temp_path
      				Dir.delete(temp_folder_abs_path) if(File.exists?(temp_folder_abs_path))
      				Dir.mkdir(temp_folder_abs_path, 0700)
      			else
      				temp_folder_abs_path = temp_folder
      			end #if
      			entries.delete(".")
      			entries.delete("..")
      			
      			#create a group and a texture writer object for copying imgfiles
      			entries.each {|entry|
      				entry_absolute_path = File.join(dir, entry)
      				file_validity = self.checkValidity(entry_absolute_path)
      				case file_validity
      					when "directory"
      						#recurse through the child directories and copy the files
      						self.copyInstructorFiles(temp_folder,entry_absolute_path,basedir)
      					when "imgfile"
      						grp = Sketchup.active_model.entities.add_group
      						tw  = Sketchup.create_texture_writer
      						#so create a material name
      						filename = File.basename(entry_absolute_path)
      						fileext  = File.extname(filename)
      						filebase = File.basename(entry_absolute_path, fileext)
      						matname = "instructor_"+filebase + rand(1000).to_s
      						
      						#load the image into a material
      						mat = Sketchup.active_model.materials.add(matname)
      						mat.texture = entry_absolute_path
      						mat.texture.size = [mat.texture.image_height,mat.texture.image_width]
      						
      						#apply the material to a group and export to temp directory
      						grp.material = mat
      						tw.load(grp)
      						result = tw.write(grp, File.join(temp_folder_abs_path,entry))
      						
      						case result
      							when 0
      								#puts "file written; "+temp_folder_abs_path+"/"+filename
      							when 1; puts "file failed (invalid tiff); "+temp_folder_abs_path+"/"+filename
      							when 2; puts "file failed (unknown); "+temp_folder_abs_path+"/"+filename
      						end #case
      						
      						#delete the material
      						grp.material = nil
      						Sketchup.active_model.materials.remove mat
      						grp.erase! if grp.valid?
      					when "unknowntype"
      						source = File.open(entry_absolute_path)
      						target = File.open(File.join(temp_folder_abs_path,entry), "w")
      						
      						target.write( source.read(64) ) while not source.eof?
      						
      						source.close
      						target.close
      				end #case
      			}
      		end #def
      		
      		def copyInstructor
      			@instructor_folder = File.expand_path(@instructor_folder)
      			@temp_folder       = File.expand_path(@temp_folder)		
      			#on mac there's no need to copy, just to generate a correct relative path
      			#as other volumes can be accessed through the /volumes/ folder
      			#so @instructor_folder == @temp_folder only on mac
      			if @instructor_folder != @temp_folder
      				#check if paths are on the same drive in windows, if they are
      				#there's no need to copy as they can be accessed through relative paths
      				instructor_path_array = @instructor_folder.split("/")
      				temp_path_array = @temp_folder.split("/")
      				if instructor_path_array[0] != temp_path_array[0]
      					#check if the temp path is equal to ENV["TEMP"]
      					#if so we need to generate a unique instructor folder id
      					if @temp_folder == File.expand_path( ENV["TEMP"] )
      						temp_instructor_folder = File.join(@temp_folder, "instructor-"+Time.now.to_f.round.to_s)
      					elsif (temp_path_array[temp_path_length-1] != "instructor")
      						temp_instructor_folder = File.join(@temp_folder, "instructor")
      					else
      						temp_instructor_folder = @temp_folder
      					end #if
      					Dir.delete(temp_instructor_folder) if(File.exists?(temp_instructor_folder))
      					Dir.mkdir(temp_instructor_folder, 0700)
      					self.copyInstructorFiles(temp_instructor_folder,@instructor_folder,@instructor_folder)
      					@temp_folder = temp_instructor_folder
      				else
      					puts "on same drive"
      				end
      			else
      				puts "on a mac"
      			end #if
      		end #def
      		
      		def returnTempInstructorFolderName
      			#return the relative path from ENV["TEMP"] so user can store this
      			#in a default and use it for consistency between plugins and sessions
      			instructor_path_array = @instructor_folder.split("/")
      			temp_path_array = @temp_folder.split("/")
      			if (@instructor_folder != @temp_folder) && (instructor_path_array[0] != temp_path_array[0])
      				temp_instructor_folder_name = @temp_folder.dup
      				temp_instructor_folder_name.slice!(File.expand_path( ENV["TEMP"] ))
      				return temp_instructor_folder_name[1,temp_instructor_folder_name.length]
      			else
      				return false
      			end
      		end #def
      		
      		def returnRelativePath
      			tool_path = Sketchup.get_resource_path( 'helpcontent/tool' )
      			temp_path = @temp_folder
      			#need to reverse loop through tool path by the separator until
      			#we get a match starting at the first line of the temp path
      			relativity_index = 0
      			common_directory_path = temp_path
      			tool_path_array = File.expand_path(tool_path).split('/')
      			0.upto(tool_path_array.length-1) {|i|
      				common_directory = tool_path_array[0, tool_path_array.length - i]
      				if [PLATFORM].grep(/mswin/)==[PLATFORM]
      					common_directory_path = common_directory.join('/')
      				else
      					common_directory_path = '/'+common_directory.join('/')
      				end
      				if common_directory_path == temp_path[0,common_directory_path.length]
      					break
      				end
      				relativity_index = relativity_index.next
      			}
      			
      			temp_path = temp_path[common_directory_path.length,temp_path.length]
      			path_to_common = "..#{File;;SEPARATOR}" * relativity_index
      			relative_path = File.join( path_to_common, temp_path)
      			return relative_path
      		end #def
      	
      	end #class
      

      Script Updated on 2011-03-13: See http://forums.sketchucation.com/viewtopic.php?f=180&t=31060&p=315364#p315364


      Load Instructor [Updated 10-03-2011:3.20am]

      posted in Developers' Forum
      B
      bentleykfrog
    • RE: Instructor content

      I've updated Dan's edit of the load_instructor script to address some issues:

      • script now contains getInstructorContentDirectory method as per Dan's suggestion
      • script methods converted from camelCase
      • added prefix 'lins_' to each method to reduce chance of method name conflicts
      • removed returns when not needed
      • made the temp directory creation more consistent
      • modified the precedence of mac over temp file setting
      • added private method calls to relative_instructor_path & temp_instructor_folder methods
      • added plugin folder name attribute to lins_setup() to resolve FILE issue when load_instructor.rb installed into [any $LOAD_PATH]/mixin/load_instructor.rb and default values of instructor folder and temp folder used
      • added $LOAD_PATH check for plugins instructor folder if no instructor_folder attribute is set to lins_setup
      • since we're specifying a folder name even on default, unique temp folder name creation was removed

      Read the definition of use in the code to get a better understanding of how to use Load Instructor.

      Issues I'm unsure of:

      • I removed the @@tool_filepath setting as I'm not sure what to do with it. If the scripts are intended to be truly portable, then how does an .rbs file require() other files? ThomThom's vertex tools method suggests that their code will already have a variable showing the scripts location, with which you could set the instructor folder location from, and use the location folder attribute of lins_setup().
      • Sketchup loaded from a server location? (ie. portable versions of Sketchup?)
      • Attaching an AppObserver for onQuit to delete the temp file? (I wouldn't have a clue about this: I'm concerned that it might overwrite other plugins' onQuit method, and I'm guessing that onQuit won't be called when there's a bugsplat, so maybe its better to have consistent temp folder directories as in this update? and rely on the system/users preference for temp folder clearing?)

      Thanks to Dan for all the tips/advice/&code, you've been more than helpful.


      Load Instructor [Updated 13-03-2011:7.12am]

      posted in Developers' Forum
      B
      bentleykfrog
    • RE: Instructor content

      @chris fullmer said:

      @dan rathbun said:

      (Issue) Does Sketchup always call the getInstructorContentDirectory() callback regardless of whether the Instructor window is open or closed?

      I'm pretty sure it does not. If you put a UI.messagebox into the getInstructorContentDirectory() callback method, it does not pop up unless the instructor is actually open.

      I get the same results on mac. Also, I notice that it calls getInstructorContentDirectory() onMouseOver and onMouseOut of the instructor dialog. Not sure if its a webkit quirk or if its intended, will check on pc.

      posted in Developers' Forum
      B
      bentleykfrog
    • RE: Instructor content

      @bentleykfrog said:

      Only question now is can sketchup run from a '\Server' path?? as this would ruin the comparison. πŸ˜•

      Actually that should read "can the default temp folder run from a '\Server' path?? as this would ruin the comparison"

      posted in Developers' Forum
      B
      bentleykfrog
    • RE: Instructor content

      @dan rathbun said:

      ...I tested: File.expand_path("#{ENV['LOGONSERVER']}/NetPlugins/TestScript.rb")

      //JEDI/NetPlugins/TestScript.rb
      .. so expanding the path will not break code by reverting to a drive letter prepended absolute path...

      Nice find Dan, and this should (hopefully:untested:willcheck) work with the temp copy script, as it compares the array[0] of somepath.split("/") with the same of the temp directory to start the copy to the temp folder. So on pc this would be like comparing 'C:' with '' (before this there's a short-circuit for mac). Only question now is can sketchup run from a '\Server' path?? as this would ruin the comparison. πŸ˜•

      posted in Developers' Forum
      B
      bentleykfrog
    • 1 / 1