sketchucation logo sketchucation
    • Login
    1. Home
    2. danielbowring
    3. Posts
    Oops, your profile's looking a bit empty! To help us tailor your experience, please fill in key details like your SketchUp version, skill level, operating system, and more. Update and save your info on your profile page today!
    ⚠️ Important | Libfredo 15.6b introduces important bugfixes for Fredo's Extensions Update
    Offline
    • Profile
    • Following 0
    • Followers 0
    • Topics 12
    • Posts 67
    • Groups 1

    Posts

    Recent Best Controversial
    • RE: Aborting a .rbz install

      Deleting it seems like overkill, you could employ something like this instead

      
      module AuthorModule
          def self.is_mac?()
              # ...
          end
      
          module PluginModule
      
          end if is_mac?
      
          mac_only_warning unless is_mac?
      end
      
      

      Or in the extension file

      
      if is_mac?
          extension = # ...
      else
          mac_only_warning
      end
      
      
      posted in Developers' Forum
      danielbowringD
      danielbowring
    • RE: Safe place to store user-defined parameters

      @fredo6 said:

      I will release the new versions of LibFredo6

      • with ENV["LOCALAPPDATA"] on Windows
      • with TIG's method on Mac, that is the parent directory of the ENV["TMPDIR"] folder. I think using ENV["HOME"] with some hidden subfolder would have been considered too intrusive.

      These will be root folders into which I will create the LibFredo6 subfolders for persisting data.

      I think in both cases these folder won't contain non-ascii characters, as they are defined and created by the system itself.

      Fredo

      ENV["LOCALAPPDATA"] may contain non-ascii characters, as it contains the current users username. Also, you should use ENV["LOCALAPPDATA"] || ENV["APPDATA"] so you can support XP at no extra effort πŸ˜„

      Bonus:

      posted in Developers' Forum
      danielbowringD
      danielbowring
    • RE: Safe place to store user-defined parameters

      @thomthom said:

      But as I mentioned - Ruby 1.8 cannot handle non-ASCII characters. Usernames might include Unicode characters and then all file operations on the user directory will simply fail.

      All the more reason to update the ruby installation. The provided order would still "work" if you checked each of the directories existed (because the check would "simply fail"), but it's certainly no supplement for the actual feature.

      It seems to be reoccurring that the SketchUp ruby API will gives you "clipped wings". I'm excited to see where it can go, but also impatient with its shortcomings (even though this one isn't really SU fault).

      Side-note: No unicode support seems strange for something coming out of japan πŸ˜›

      posted in Developers' Forum
      danielbowringD
      danielbowring
    • RE: Safe place to store user-defined parameters

      @tig said:

      BUT...
      No one has still answered my question... πŸ˜•
      What is wrong with using the container folder for the ENV for the OS's user's 'Temp' folder?
      That is easily found for either OS and is writable, like the Temp folder itself...
      Once you have the path to the user's 'Temp' folder we can then make an app-specific subfolder to hold our temporary files...
      AND from File.dirname(Temp) we can get the container-location into which we can make an app-specific subfolder to hold our 'permanent' files...
      I do it without problems on all OS's - the rest of you seem to obsessed with finding 'the exact right folder that we must use', when in truth there are several valid possibilities, and my earlier posts cover much of this too... KISS ?

      The temp directory is easy to get ( require 'tmpdir'; Dir.tmpdir) but only useful for temporary files.

      If you're writing something to the temp directory with the intention of reading it later, you're doing it wrongβ„’. The temp directory is for files that have no consequence if they are removed at a later date. The temp directory is for writing, and reading only when you've been explicitly told to.

      The "correct" place for persistent data for an application that is not part of the installation is the appdata location. These directories are separate for each user and guaranteed to be readable/writable for the associated user. This is normally were things like plugins/extensions would exist, also.

      A good example of this (if you have it installed) is Sublime Text. (On windows) it is installed to %PROGRAMFILES%/Sublime Text, which contains all required binaries and application defaults. Then in %LOCALAPPDATA%/Sublime Text/ (or %APPDATA%/Sublime Text 2/ for st2 user level information is available, including plugins, settings, key configurations, ...

      Driven has posted what appears to be the MAC equivalent of LOCALAPPDATA || APPDATA.

      So, the search order for a path to write to should be: (keeping in mind I'm no MAC expert)

      
      %LOCALAPPDATA% (win)
      %APPDATA%      (win)
      ~/Library/???/Sketchup/  [or similar] (MAC) ["~" -> "/Users/<username>/"]
      Sub-directory in SketchUp directory [plugin-data or similar] (if writable)
      temp directory (last resort)
      
      
      posted in Developers' Forum
      danielbowringD
      danielbowring
    • RE: Safe place to store user-defined parameters

      Come to think of it, this could go well as part of SketchupExtension

      Something like (for example only):

      
      APPDATA_DIRECTORY = get_appdata_directory_somehow()
      RESTRICTED_CHARACTERS = Regexp.new('[\\/;*?"<>|%]')
      
      class SketchupExtension
          def data_directory()
              dir = APPDATA_DIRECTORY
      
              if FileTest.writable?(dir)
                  if creator
                      dir = File.join(dir, creator.gsub(RESTRICTED_CHARACTERS, ''))
                      Dir.mkdir(dir) if !File.directory?(dir)
                  end
                  if name
                      dir = File.join(dir, name.gsub(RESTRICTED_CHARACTERS, ''))
                      Dir.mkdir(dir) if !File.directory?(dir)
                  end
                  return dir
              end
      
              if respond_to(;extension_path) && extension_path
                  dir = File.dirname(extension_path)
                  if File.directory?(dir) && FileTest.writable?(dir)
                      # Make a sub directory to avoid clashes
                      dir = File.join(dir, '__appdata__')
                      Dir.mkdir(dir) unless File.directory?(dir)
                      return dir
                  end
              end
      
              # Alternatively, return a default directory, such as
              #   SU/plugin_data/<creator>/<name>/
              raise RuntimeError.new('Not data directory could be located')
          end
      
      end
      
      

      Then usage would be something like:

      
      module AuthorModule
          module PluginModule
              EXTENSION = SketchupExtension.new('...', '...')
              # ....
              some_path = File.join(EXTENSION.data_directory, 'settings.txt')
          end
      end
      
      
      posted in Developers' Forum
      danielbowringD
      danielbowring
    • [Doc] Official LanguageHandler Docs

      In case you didn't notice, official docs for LanguageHandler have arrived: http://www.sketchup.com/intl/en/developer/docs/ourdoc/languagehandler.php

      Includes the description of the new feature (I.E, extensions-specific strings)

      posted in Developers' Forum
      danielbowringD
      danielbowring
    • RE: How to check syntax without executing

      @anton_s said:

      But I did got it figured out.
      The eval checks for the syntax errors first:

      begin
      >   eval('Sketchup.active_model.entities[0].material = 'green'; if true then')
      > rescue
      >   puts 'Error'
      > end
      

      In the result it will puts 'Error', without setting group's material green because eval checks for the correct syntax first, and then executes the script.

      That is probably going the be the best available approach (an AST would be nicer, but there isn't one available in SketchUps Ruby).

      
      def self.get_syntax_errors(code)
          code = "begin\n#{code}\nend if false"
          begin
              eval(code)
          rescue SyntaxError => e
              return e
          end
          return nil
      end
      
      

      Note that depending how you use this, you could introduce a security flaw. Imagine if I sent the following code to get_syntax_errors

      
          require 'fileutils'
          FileUtils.rm_rf('/')
      end
      begin
          puts "This will not run!
      
      

      And then put the file up for download somewhere

      posted in Developers' Forum
      danielbowringD
      danielbowring
    • RE: Safe place to store user-defined parameters

      Maybe something like:

      def appdata_dir()
          dir = ENV['LOCALAPPDATA'] || ENV['APPDATA'] || '~/Library'
          return dir if File.directory?(dir)
          return Sketchup.find_support_file('plugins')
      end
      

      Just remember make a (unique) directory for yourself.

      
      def author_appdata_dir(author_name, make=true)
          dir = File.join(appdata_dir(), author_name)
          Dir.mkdir(dir) if make && !File.directory?(dir)
          return dir
      end
      
      
      posted in Developers' Forum
      danielbowringD
      danielbowring
    • RE: What does SketchUp 2013 do for developers?

      @adamb said:

      It would be straight forward to build a well-known socket into SU for WebKit comms.

      Or would it better to finish off their original (not unreasonable) approach of having a skp:// scheme handler?

      Adam

      http would probably be better because it would "just work" on things like jQuery.ajax. Just bind listen on a particular port (if already taken, just keep trying the next one). Them it's just of matter of the client getting the information - for pages served by it it is as simple as document.location,, and for remote stuff maybe include it in the user-agent or some other standard header (like X-SketchUp-Server: localhost:8042). Then you're communication channel is good to go! πŸ˜„

      Edit: Idea: let plugin developers define subdomains (implemented by local DNS rules). That way we can separate out authors content over a fake domain. (eg, author.sketchup-dialog.com, then just use the header to tell the port it is listening on.

      posted in Developers' Forum
      danielbowringD
      danielbowring
    • RE: What does SketchUp 2013 do for developers?

      @thomthom said:

      You mean full library as in the Ruby Standard Library?

      Yes.

      posted in Developers' Forum
      danielbowringD
      danielbowring
    • RE: What does SketchUp 2013 do for developers?

      @thomthom said:

      Not following you on this one either. It's [ruby on rails] a web-framework. How much would that benefit SketchUp programming?

      Ah, but if we dropped[sup:224df3da]†[/sup:224df3da] window.load for javascript<->ruby communication and used xhrs instead, having a web framework could be really useful! That said, rails (and most frameworks) for that matter might be a bit bloated - given the situation many features would likely never be used. What would likely be better would be to implement something like wsgi or rack and then allow developers to deal with requests appropriately (and hopefully a dominant method/framework will arise, which can then hopefully be made available on the extension warehouse as a requirement/dependency library)

      [sup:224df3da]†[/sup:224df3da] I don't mean remove it; just make it a secondary, legacy option.

      Sidenote: I'd still love to see a newer ruby version (1.9.x, 2.x), a complete ruby install dedicated to SketchUp (no external installation required, full library available), and rubygems support (Possiblities: Add a custom named executable to the PATH skpgem install ... or give us a method to get the path of the executable #{Sketchup.GEM_PATH} install ...`` or give us a wrapper Sketchup::Gem.install(...) unless Sketchup::Gem.installed?(...)). Also, a single WebDialog implementation. Use something like WebKit or Gecko so we get the same behavior on both OSX and Windows, as well as some cool new toys (developer kit, HTML5 and CSS3 features, ...)

      posted in Developers' Forum
      danielbowringD
      danielbowring
    • RE: Webdialogs for SketchUp ......RIP!

      @thomthom said:

      hmm... I can see times where async can be useful, but more often I want synchronous communication.

      How often does it actually need to be synchronous though? That is, the code must be executed before the next line. Also, how often can that not be turned into a async form (callbacks, promises, ...)?

      My main point is that predictability and expectations are important in API design. Also, the current implementation (window.location = ...) can have side effects - for example it will block/cancel any current requests, such as redirects or xhrs.

      posted in Developers' Forum
      danielbowringD
      danielbowring
    • RE: Webdialogs for SketchUp ......RIP!

      @thomthom said:

      Yeah, I'm not finding any references of such a python framework - let alone just a framework in any language.

      And considering the advances of HTML5 and CSS3 - not only on the web but in apps on both mobile and win8 I don't see WebDialogs as a dead end. However, WebDialogs needs a cleanup and ship with a custom webcontrol independent from the OS and consistent across platforms.

      This whole thing after to rather be a UI concept, which would be limited to language.

      I think having the ruby<->js interactions done through XMLHTTPRequests would be great too, because then we know for certain it's asynchronous can can use existing frameworks to aid the communication.

      posted in Developers' Forum
      danielbowringD
      danielbowring
    • RE: Webdialogs for SketchUp ......RIP!

      @dan rathbun said:

      %(#BF4000)[If you trash Ruby.. I TRASH YOU ! 😠]

      I can appreciate that for 1.9.x or 2.x, but for 1.8.6?

      posted in Developers' Forum
      danielbowringD
      danielbowring
    • RE: [Question] DC Size and New Definitions

      @pcmoor said:

      0ne point I have found, the copy function within the DC does not make an instance, but another DC embedded within the group. this uses up memory, compare the file sizes of 100 normal copies compared to a DC copying its self. (note you also need to purge the file after going back from 100 to 1)

      This may explain your observations

      Confirm on the file size point;

      * 0 definitions, 0 instances - 6.93 KB (7,101 bytes)
      * 1 definitions, 0 instances - 12.2 KB (12,521 bytes)
      * 1 definitions, 100 "copy+paste" copies, 25 KB (25,620 bytes)
      * 1 definitions, 200 "copy+paste" copies, 39.7 KB (40,750 bytes)
      * 1 definition, 0 "dc-copies" (copies=0, no instance), 15.9 KB (16,373 bytes)
      * 1 definition, 1 "dc-copies" (copies=0), 17.0 KB (17,476 bytes)
      * 1 definitions, 100 "dc-copies" (copies=99) copies, 86.9 KB (89,005 bytes)
      * 1 definitions, 200 "dc-copies" (copies=199) copies, 160 KB (164,302 bytes)
      

      Those numbers don't seem to add up for your theory though (using a naive approach)

      
      >>> file_overhead = 7101
      >>> definition = 12521 - file_overhead
      >>> definition # Cost of definition excluding DC attributes
      5420
      >>> one_clone = 16373 - file_overhead
      >>> one_clone # Cost of definition including DC attributes
      9272
      >>> cp_100_cost = (25620 - (file_overhead + definition)) / 100.0
      >>> cp_100_cost
      130.99
      >>> cp_200_cost = (40750 - (file_overhead + definition)) / 200.0
      >>> cp_200_cost
      141.145 # Acceptable variance
      >>> dc_100_cost = (89005 - (file_overhead + one_clone)) / 100.0
      >>> dc_100_cost
      726.32
      >>> dc_200_cost = (164302 - (file_overhead + one_clone)) / 200.0
      >>> dc_200_cost
      739.645 # Acceptable variance
      
      

      If there was a copy of the definition for each of the "dc-copies" instances, you would expect the dc_*00_cost to be closer to the value for one_clone

      Also
      ` # 100 "copy-paste" instances

      Sketchup.active_model.selection.length
      100
      Sketchup.active_model.selection.first.definition.instances.length
      100
      Sketchup.active_model.selection.map() {|i| i.definition}.uniq.length
      1

      100 "dc-copies" instances

      Sketchup.active_model.selection.length
      100
      Sketchup.active_model.selection.first.definition.instances.length
      100
      Sketchup.active_model.selection.map() {|i| i.definition}.uniq.length
      1`

      I imagine some of the filesize distance would come from storing the attributes on each instance (although we have 63385 bytes to account for)
      Sketchup.active_model.selection.first.attribute_dictionary('dynamic_attributes').each() {|k, v| puts " #{k} = #{v.inspect}" } _copies_label = "Copies" _has_movetool_behaviors = 1.0 _hasbehaviors = 1.0 _lengthunits = "CENTIMETERS" _name = "Component#1" _y_error = "<span class=subformula-success>10.0</span>*200" _y_formula = "COPY * 200" _y_label = "Y" copies = "99" copy = 10 leny = 39.3700787401575 y = 787.40157480315
      I tested this by adding some position and scale attributes to the component, and the file size jumped up to 168 KB (172,766 bytes) (from 86.9 KB (89,005 bytes)) for 100 and 314 KB (321,979 bytes) (from 160 KB (164,302 bytes))for 200. (or 837.61 bytes/instance for 100 and 788.385 bytes/instance for 200). ~800 bytes for attributes only seems a bit heavy for only attributes but doesn;t come near the size of the definition (which, including attributes is 19.8 KB (20,351 bytes) [including file overhead] or 13250 bytes [exlcuding file overhead]

      In these tests, there was no excessive components to purge, but that was by design (single depth component. no per-instance formula).

      @pcmoor, This leads me to believe that this isn't the cause, but it still interesting information none-the-less. I do appreciate the input, though - and has given me food for thought on the cost of using copies.

      Edit: just as a double confirm, if I take the "dc-copies" component, set it copies to 0 and then "copy-paste" for a total of 100, the file size comes out roughly the same as if I had used "dc-copies" (copies=99), at 165 KB (169,312 bytes) (within 3 KB)

      posted in Dynamic Components
      danielbowringD
      danielbowring
    • RE: SketchUp Ruby API Suggestions

      That document's really interesting - do you mind if I add some of it to the repo (credit where due, ofc)?

      posted in Developers' Forum
      danielbowringD
      danielbowring
    • SketchUp Ruby API Suggestions

      @unknownuser said:

      After using the SketchUp Ruby API for some time, I've come across I few things I'd like to see done differently, or to be added. Here's my WIP list of suggestions.

      This is just as much organisation for me as it is getting this information out. I've kept it somewhat organized and well described, but there's still a lot of work to be done. Also, if I never do anything nothing will get done, so here's me doing something.

      https://github.com/dbowring/sketchup-suggestions

      posted in Developers' Forum
      danielbowringD
      danielbowring
    • RE: Add_polygon seems very slow

      The problem is you are using Point3d arguments - this means each call to add_polygon needs to call add_point three times. You can add all the points beforehand and then use their index to add the polygons. This should add a significant speed boost.

      Here's the code:

      t = Time.now
      lados_x = 100
      lados_y = 100
      mesh = Geom;;PolygonMesh.new((lados_x+1)*(lados_y+1),lados_x*lados_y)
      l1 = []
      for i in 0..lados_x
         l1[i] = mesh.add_point(Geom;;Point3d.new(i,0,0))
      end
      l2 = []
      for j in 1..lados_y
         for k in 0..lados_x
            l2[k] = mesh.add_point(Geom;;Point3d.new(k,j,0))
         end
         for i in 0..lados_x-1
            mesh.add_polygon l1[i], l1[i+1], l2[i+1]
            mesh.add_polygon l1[i], l2[i+1], l2[i]
         end
         l1 = l2.clone
      end
      
      
      ent=Sketchup.active_model.active_entities
      grupo = ent.add_group
      entities = grupo.entities
      entities.fill_from_mesh mesh, true, 0
      
      
      puts Time.now-t
      
      posted in Developers' Forum
      danielbowringD
      danielbowring
    • RE: [Question] DC Size and New Definitions

      Had a really good look at this over the weekend, and produced a "monkey patch" that makes size transformation per-instance

      NOTE: THIS IS NOT FOR GENERAL USE! DO NOT INSTALL FOR ANY OTHER REASON THAN INSPECTION, AND REMOVE THE SCRIPT (AND RESTART SKETCHUP) BEFORE CONTINUED USE!

      ` require 'dynamiccomponents.rb'
      Sketchup.require('DynamicComponents/ruby/dcobservers')

      path = ['@dc1', '@instance_attributes']
      path.inject($dc_observers) {|a, b|
      a.instance_variable_get(b)
      }.merge!({
      "lenx" => true,
      "leny" => true,
      "lenz" => true
      })`

      Here's my findings:

      *  In *most* cases, components can continue to exist and work as they are (e.g., the first sample file in this thread)
      *  In some cases, you need to reapply the formula (if made before this script was loaded, afterwards it will continue to work as expected (e.g., the third file on this thread)
      *  In the case where the *definition* depends on the size, everything breaks - but only when at a scale with a factor that is not 1 (i.e., anything except (1.0, 1.0, 1.0))
      

      In the last case, the scale will increase by the given factor (i.e, if it should be twice in the x direction compared to the original definition, it will be at first 2x (correctly), then on the next redraw 4x, then 8x, ...
      Aside from this, the functionality is (mostly) correct (There are a few situations where some definitions are duplicates, but it is certainly better than when everything has a new definition).

      This is about as far as I'll be able to get without word from the SketchUp team (or the ability to get at the source code).

      Once again - does anyone have anymore information, or is able to contact the SketchUp guys and get them to have a look at this thread?

      posted in Dynamic Components
      danielbowringD
      danielbowring
    • RE: [Question] DC Size and New Definitions

      OK - performing more tests it seems that the reason these create new definitions is because the formula differs. Instances from COPIES appear "immune" because the formula is the same, but the value of COPY is different per-instance. Since the forumula of each instance's attributes are equal, the same definition is used. As soon as you want to vary a formula, you need to create a new definition.

      This seems logical enough, but still doesn't answer the overriding question. The Size (LenX, LenY, LenZ) affect (and come from) the instance, but are limited by the definition. Position (X, Y, Z) understands this, and will let you enter different formula for the position on different instances without making a new definition, but Size does not.

      IMHO, the formula for size - like position - should be per-instance.

      The attached file demonstrates changing size (and keeping the same definition) by altering a "non-size" value and having the size vary based on it. (Use the "interact" tool on the first three, the last is static). This is a workable fix for some situation, but not all (For example, placing a component at the "corners" of a bounding box would still not be possible without using COPIES or different definitions)

      Does anyone have any more information on this, or a technical reason why this can't be the case?


      animate.skp

      posted in Dynamic Components
      danielbowringD
      danielbowring
    • 1 / 1