sketchucation logo sketchucation
    • Login
    ℹ️ Licensed Extensions | FredoBatch, ElevationProfile, FredoSketch, LayOps, MatSim and Pic2Shape will require license from Sept 1st More Info

    Custom Dynamic Component Functions = Ruby links

    Scheduled Pinned Locked Moved Developers' Forum
    30 Posts 9 Posters 12.1k Views 9 Watching
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • TIGT Offline
      TIG Moderator
      last edited by

      Please read this http://cfcl.com/twiki/bin/view/Projects/SketchUp/DA_Adding_Functions
      which covers how to add your own 'custom functions' to a DC. There are also some other useful sections about DC attributes etc... This is actually Rich Morin's [although I did help in a small way with some coding ideas...] and it does refer back to this forum too...
      This DC 'custom function' possibility is potentially a wide reaching effect because any Ruby API method can be invoked this way as a DC function.
      Jim and Dan have already discussed it in this thread http://forums.sketchucation.com//viewtopic.php?f=10&t=21474 specific to adding an extra trig function... but it's wider implications for extending DCs doesn't seem to have 'clicked' yet...
      As well as returning values it could also execute code which might in turn modify the DC itself - e.g. swap in/out sub-DCs... Someone recently asked about filleting two edges into an arc inside a DC, where the angle between the lines and the arc's radius were infinitely variable [so no chance of a set of possible solutions to be nested in it] - now I think this method could allow it to be done as a custom function, calling a complex Ruby code script, that modifies a unique instance of a sub-DC, which is itself within the calling DC, and could indeed do the required complex math/trig to form the fillet, face it and extrude it into a 3d form. I'm not saying it'd be easy to do... BUT I now think that it is at least possible...
      β˜€

      TIG

      1 Reply Last reply Reply Quote 0
      • TIGT Offline
        TIG Moderator
        last edited by

        To use custom functions here's an example

        if defined?($dc_observers)
          # Open SketchUp's Dynamic Component Functions (V1) class.
          # only if DC extension is active
          
        class DCFunctionsV1
        
          protected
          
          # return volume
          # Usage; =volume()
          def volume(a)
            return @source_entity.volume
          end
          protected;volume
          
          # open UI.messagebox
          # Usage; =messagebox()
          def messagebox(a)
            UI.messagebox(@source_entity.to_s+' '+a.to_s)
          end#if
          protected;messagebox
          
        end#class
        
        end#if
        

        Put this code in a .rb file that loads when Sketchup runs - it adds two new functions to your DC: 'volume' - which returns the volume in cu" - and a 'messagebox' - which displays the id of the DC itself and any value[s] passed to it.
        In the following example it displays the id + volume, with an 'onClick'...
        Make a simple DC and add three items:
        two Custom Attributes
        mymessage: =messagebox(myvolume) myvolume: =volume()
        and a Behavior
        onClick: redraw(mymessage())
        Now when you click on the DC instance it displays a messagebox showing its instance id and volume...
        I know this is pretty useless stuff... BUT it shows that we can run things outside of the DC in Ruby to change the model, or the DC itself [ @source_entity.definition.entities...]
        ... πŸ˜„

        TIG

        1 Reply Last reply Reply Quote 0
        • K Offline
          kwalkerman
          last edited by

          Cool!

          1 Reply Last reply Reply Quote 0
          • jason_marantoJ Offline
            jason_maranto
            last edited by

            This is very cool! I've been wondering about this for a long time and it looks like I will need to dig deeper into ruby now β˜€

            Best,
            Jason.

            I create video tutorial series about several 2D & 3D graphics programs.

            1 Reply Last reply Reply Quote 0
            • jeff hammondJ Offline
              jeff hammond
              last edited by

              @tig said:

              Someone recently asked about filleting two edges into an arc inside a DC, where the angle between the lines and the arc's radius were infinitely variable [so no chance of a set of possible solutions to be nested in it] - now I think this method could allow it to be done as a custom function, calling a complex Ruby code script, that modifies a unique instance of a sub-DC, which is itself within the calling DC, and could indeed do the required complex math/trig to form the fillet, face it and extrude it into a 3d form. I'm not saying it'd be easy to do... BUT I now think that it is at least possible...
              β˜€

              so i guess that was me that asked about filleting inside a DC.. i've done it only using DC's custom functions instead of going out to ruby:

              http://forums.sketchucation.com/viewtopic.php?f=289&t=37037

              but.. it results in a collection of edges inside various sub-components.. do you think it's possible to use ruby along with the DC to somehow extract all of the edges and face them as a single component?

              a real use for me being able to do something like that would be for a stair stringer which isn't actually a collection of individual components.. i'd like to be able to make a stair DC in which i can pull out the stringer and it's one solid piece.
              ❓

              [or, it'd be sweet if i could make the stringer out of individual solid components which then automatically uses the solid tools' outer shell to make it a single component with no coplanar lines etc..
              ❓

              dotdotdot

              1 Reply Last reply Reply Quote 0
              • TIGT Offline
                TIG Moderator
                last edited by

                Jeff

                I think it would be possible...
                We can form the outline in DC code or a DC-Ruby hybrid and then ass the face and pushpull it in Ruby etc within the DC's definition entities...
                Can you outline 'blow-by-blow' exactly what is is you want to do so I could perhaps sketch out how it might be done in DC_Ruby ?

                TIG

                1 Reply Last reply Reply Quote 0
                • jeff hammondJ Offline
                  jeff hammond
                  last edited by

                  i'm having second thoughts about diving too far into this stuff πŸ˜„

                  but, with the stairs, i think i can accomplish what i want with a few clicks using the outliner, selection toys, and outer shell.
                  i'm going to try to make the stairs today and i'll upload a .skp showing the DC result and the desired 'finished' component.

                  with the other thing (the arc to angle blend), i would want it to do everything it's doing except there's a face or possibly a thickness to it.. (imagine that outline being drawn on a piece of 3/4ply and cut out).
                  i can accomplish that now but i have to explode everything a few times in order to make a face.. i haven't used bomb.rb in a year or two because it was super slow but maybe it wouldn't be that bad on this(?).. i'll give that a shot in a little bit.

                  dotdotdot

                  1 Reply Last reply Reply Quote 0
                  • TIGT Offline
                    TIG Moderator
                    last edited by

                    To make the DC stringer as a 'solid 3D object' you'd still do the 'inputs' as before, BUT then output them to a new custom function - called say '=jcstringer(height,riser,board)' in the DC that runs when you update one of the values. You would not necessarily need the built-in DC functions used to calculate number of notches etc as these are now done inside Ruby-side code...
                    The associated custom Ruby code would be 'def jcstringer(a)', which always takes its input as one array 'a', so height=a[0].to_l, riser=a[1].to_l, board=a[2].to_l etc...
                    You could also pass a variable stringer-width, tread-width, and any other data etc etc...

                    We can readily find the DC instance's definition and thereby its entities.
                    First you'd erase that definition's entities: then take the passed values, use iterations etc and make a set of coplanar points for each vertex of the 'cut' stringer and add a face to the DC defn's entities using those. Then pushpull that face to the right width [here 2"] and finally do a Ruby-side DC redraw etc [if needed].
                    This way you'll get a full 3D solid object as the stringer without any subcomponents in it.
                    Whenever that stringer's value is changed the Ruby side discards the old geometry and makes new geometry...

                    Initially it might be easier to start with something like a simple L-shape 'box' with 3 or 4 changeable dims. Then try remaking that with a custom function in Ruby code called from the DC. Once that's cracked you can move on to the more complex iterations etc in the Ruby to make 'step-notches' etc...

                    TIG

                    1 Reply Last reply Reply Quote 0
                    • Dan RathbunD Offline
                      Dan Rathbun
                      last edited by

                      @unknownuser said:

                      (http://forums.sketchucation.com/viewtopic.php?f)":242wng0h]
                      @jim said:

                      Drop this in your plugins folder...

                      class DCFunctionsV1
                      > >   protected
                      > >   def atan2(*a)
                      > >     return Math;;atan2(a[0], a[1])
                      > >   end
                      > > end
                      > > 
                      

                      Lemme do a quick fix on that...

                      class DCFunctionsV1
                      >   protected
                      >   def atan2(a)
                      >     return Math;;atan2(a[0], a[1]).radians
                      >   end
                      > end
                      > 
                      

                      You are correct for the argument, in that the DC extension always passes the function arguments as an Array (so the ***** expansion operator is not needed.)

                      However, all the other trig functions do not have built-in radians to degrees conversion, and to follow convention, the internal code for the function should be as Jim showed.

                      If you wish degrees from a result that returns radians, you should use the DC function degrees( *radian_arg* ), as in:

                      degrees( atan2(n1,n2) )

                      require('dynamiccomponents.rb')
                      if defined?($dc_observers)
                        # only if DC extension is active
                        class DCFunctionsV1
                          protected
                          def atan2(a)
                            return Math;;atan2(a[0], a[1])
                          end #def
                        end #class
                      end #if
                      
                      

                      NOTE: modifying this class no longer makes it version 1

                      I'm not here much anymore.

                      1 Reply Last reply Reply Quote 0
                      • TIGT Offline
                        TIG Moderator
                        last edited by

                        Jeff

                        This is the cut-stringer as a Ruby formula

                        def jh_stringer(ar) ### ar==array of data...
                          ###
                          ents=Sketchup.active_model.entities ### for testing
                          ### for a DC class DCFunctionsV1 class def you change to
                          ### ents=@source_entity.definition.entities
                          ###
                          h=ar[0].to_l ### total height floor to floor e.g. 48"
                          r=ar[1].to_l ### max riser e.g. 7.25"
                          b=ar[2].to_l ### stringer board size e.g. 10" [from 2x10]
                          ###
                          g=9.25  ### going [i.e. tread size] 9.25"
                          t=2.00  ### stringer thickness 2"
                          tt=1.00 ### tread thickness say 1" ? ***
                          hh=h-tt
                          n=((hh/r)+0.5).round
                          r=h/n
                          a=Math.atan(r/g)
                          b1=r/Math.acos(a)
                          b2=b-b1
                          gg=g*n
                          bt=(b*Math.cos(a))-r
                          g1=gg-((hh-bt)/Math.tan(a))
                          pts=[[0,0,0]] ### start at the bottom of the first riser
                          n.times{|i|                     ### no lower tread to 1st riser
                            pts << [g*i,0,r+(r*i)-tt]     ### front edge of each tread
                            pts << [g+(g*i),0,r+(r*i)-tt] ### back edge of each tread
                          }
                          pts << [gg,0,(hh-bt)]   ### the top u/side of stringer
                          pts << [g1,0,0]         ### the bottpm u/side of stringer
                          ###
                          f=ents.add_face(pts)
                          f.pushpull(t)
                        end
                        

                        As a test def it makes the stringer in model entities.
                        See the note on how to add it to the DC definition etc...
                        Use as a custom function =jh_stringer(height, rise, stringer_boardwidth)

                        TIG

                        1 Reply Last reply Reply Quote 0
                        • jeff hammondJ Offline
                          jeff hammond
                          last edited by

                          tig, thanks

                          i gotta admit though, i really don't feel like going down that rabbit hole.. i can see the possible addiction and i don't think i can afford another addiction at this point in my life πŸ˜„

                          i tried out a new approach and i think it's going to work out good for me.. i can make these types of DCs a lot faster/easier because there are less factors to account for as these cutters only need to be exact on their cutting edges.. lengths/thicknesses/positions etc. can just run wild in many cases.
                          for final components with multiple parts, i'll be able to reuse certain cutters instead of needed to reenter the parameters etc..

                          here's the stringer example...

                          (not fine tuned enough to deal with out_of_norm dimensions --ie. 12" rise etc.)

                          i think this opens up a lot of possibilities with DCs (at least with the way my brain works πŸ˜„ )
                          i'll try some things out this week with more complex shapes (ie- the things that i'd actually want to use DCs for) and post the results if they end up being decent..

                          [edit] - i guess i should point out that this method requires sketchup PRO.. but that's obvious, right? : )


                          click pic -> bigger

                          dotdotdot

                          1 Reply Last reply Reply Quote 0
                          • jeff hammondJ Offline
                            jeff hammond
                            last edited by

                            so, i've yet to see a good example of a DC stair stringer so i tried making one of my own (all of the other ones appear to ignore the fact that stairs are typically built out of standard sized materials) [but, if anyone knows of some good ones, feel free to share : ) ] ..very early into it, i ran into the problem (rather, limitation?) of dynamic components..

                            you can't change angles of faces/edges/etc on a component.. to do that, you have to break the component down into smaller sub-components and by doing so, you lose the ability to have a single/solid component..

                            if you ruby geniuses could figure out a way to either A) add faces to nested edges or b) find a way to control individual faces/edges within a component via DC then these things could be awesome.. otherwise, DCs appear to be limited to cubes for any practical construction application (and that's a huge limit imo because the cube type stuff is super easy to draw anyway)..

                            here's the file for my Stringer dc:

                            (re-upped.. fixed small error)

                            if that stringer could somehow become one solid component then i'd be --> 😍

                            otherwise, it's still a decent (and definite timesaver) calculator for the stringer but it's not so good for making .skp drawings of them.. regardless, i'm going to expand on the DC to include the support wall and stringer cap which will still let me make super quick cutlists on the job site..

                            dotdotdot

                            1 Reply Last reply Reply Quote 0
                            • TIGT Offline
                              TIG Moderator
                              last edited by

                              That's fine if you're happiest with this approach...

                              TIG

                              1 Reply Last reply Reply Quote 0
                              • Q Offline
                                quiver
                                last edited by

                                @unknownuser said:

                                if you ruby geniuses could figure out a way to either A) add faces to nested edges or b) find a way to control individual faces/edges within a component via DC then these things could be awesome.. otherwise, DCs appear to be limited to cubes for any practical construction application (and that's a huge limit imo because the cube type stuff is super easy to draw anyway)..

                                I wholeheartedly echo that request.. this would overcome a variety of issues for my work. I design for events, and have made all my own lighting fixtures / speakers / projectors etc, which are all DC's that I can adjust the attributes of (some of my library is published here: http://sketchup.google.com/3dwarehouse/cldetails?mid=e94a8eafed72d755701d728505a21ed0&prevstart=12). But I come across that stumbling block frequently, with wanting to do something as simple as move one face of a cube (not in alignment with the cube, but side-to-side.. like a parrallelogram)..

                                Custom functions are a helpful half-way point but if everyone needs the same ruby script installed to be able to utilise it, they don't serve all that well. Is there any way to address individual edges/faces of a component using ruby in a DC spreadsheet formula? If I can do that, and modify them using existing functions, then I'd be more than satisfied.

                                Thanks !

                                1 Reply Last reply Reply Quote 0
                                • J Offline
                                  Jim
                                  last edited by

                                  @unknownuser said:

                                  --use component options to determine dimensions
                                  --in outliner, click on 'CUTTERS'
                                  --select 'Outer Shell' via solid tools
                                  --select 'Subtract' via solid tools
                                  --click on the orange board (stringer_uncut)
                                  --explode
                                  --the stringer will be a single solid component named 'Stringer'

                                  Once the DC is configured, these steps could be automated into a single step (via a menu or tool button.) I am making the assumption of consistent Component names being used i.e Components named "Cutters" are always subtacted from Components named "Stringer_Uncut"

                                  Hi

                                  1 Reply Last reply Reply Quote 0
                                  • jeff hammondJ Offline
                                    jeff hammond
                                    last edited by

                                    @jim said:

                                    Once the DC is configured, these steps could be automated into a single step (via a menu or tool button.) I am making the assumption of consistent Component names being used i.e Components named "Cutters" are always subtacted from Components named "Stringer_Uncut"

                                    hey Jim.

                                    since the time of this thread, I have automated the finishing parts of the DC using AppleScript. I found a pretty decent way to create macros for sketchup.. the macros are osx 'services' which (can) reside in a specific app's menus (or they can be available system wide)

                                    which reminds me. maybe I should type up a thread showing how to accomplish this.

                                    dotdotdot

                                    1 Reply Last reply Reply Quote 0
                                    • Dan RathbunD Offline
                                      Dan Rathbun
                                      last edited by

                                      Jeff.. please DO.

                                      Then if we can find a PC complement (likely OLE,) these "services" could be wrapped as Ruby objects or classes. A platform conditional if block would define the Ruby interface, using AppleScript on the Mac, and OLE on PC. In this way we could have a cross-platform Ruby interface for plugins.

                                      I'm not here much anymore.

                                      1 Reply Last reply Reply Quote 0
                                      • jeff hammondJ Offline
                                        jeff hammond
                                        last edited by

                                        @dan rathbun said:

                                        Jeff.. please DO.

                                        Then if we can find a PC complement (likely OLE,) these "services" could be wrapped as Ruby objects or classes. A platform conditional if block would define the Ruby interface, using AppleScript on the Mac, and OLE on PC. In this way we could have a cross-platform Ruby interface for plugins.

                                        hmm. I'm not too sure it would work with what you're suggesting. (at least the way I've been going about it)

                                        I'm doing GUI scripting so it's basically just keystrokes and menu items.. you can accomplish quite a bit this way (I actually have one script that uses a little but of ruby in there via the console πŸ˜„ )

                                        the thing that's good about it is it's not very complicated so a lot of people should be able to make their own macros this way (and a bonus is that you don't have to install any additional software)..

                                        dotdotdot

                                        1 Reply Last reply Reply Quote 0
                                        • J Offline
                                          Jim
                                          last edited by

                                          @unknownuser said:

                                          I'm doing GUI scripting so it's basically just keystrokes and menu items..

                                          The Windows equivalent can be accomplished via Windows Scripting.

                                          Here's a VBScript example:

                                          Sub Wait
                                          	Wscript.Sleep(1500)
                                          End Sub
                                          
                                          set WshShell = WScript.CreateObject("WScript.Shell")
                                          'WshShell.AppActivate "- SketchUp"
                                          Command = """C;\Program Files (x86)\Google\Google SketchUp 8\SketchUp.exe"""
                                          'MsgBox Command
                                          WshShell.Run(Command)
                                          Wait
                                          WshShell.SendKeys "%u" ' My SU Shortcut to open Ruby Console
                                          Wait
                                          WshShell.AppActivate "Ruby Console"
                                          Wait
                                          WshShell.SendKeys "require_all 'c;/plugins'{ENTER}"
                                          
                                          
                                          
                                          

                                          Hi

                                          1 Reply Last reply Reply Quote 0
                                          • jeff hammondJ Offline
                                            jeff hammond
                                            last edited by

                                            @jim said:

                                            @unknownuser said:

                                            I'm doing GUI scripting so it's basically just keystrokes and menu items..

                                            The Windows equivalent can be accomplished via Windows Scripting.

                                            Here's a VBScript example:

                                            set WshShell = WScript.CreateObject("WScript.Shell")
                                            > 'WshShell.AppActivate "- SketchUp"
                                            > Command = "C;\Program Files (x86)\Google\Google SketchUp 8\SketchUp.exe"
                                            > MsgBox Command
                                            > WshShell.Run Command
                                            > WScript.Sleep 1000
                                            > WshShell.SendKeys "%u" ' My SU Shortcut to open Ruby Console
                                            > WScript.Sleep 1000
                                            > WshShell.AppActivate "Ruby Console"
                                            > WScript.Sleep 1000
                                            > WshShell.SendKeys "require_all 'c;/plugins'"
                                            > WScript.Sleep 1000
                                            > WshShell.SendKeys "{ENTER}"
                                            > 
                                            

                                            is something like that easy to run from within sketchup? (that's sort of the beauty of osx services.. they become a menu item so activating the script is the same for anything else in sketchup.)

                                            regardless, you guys could probably write a macro recorder in ruby that in turn produces these services :enlighten:

                                            nothing to do with recording cursor movement etc.. AppleScript can't handle it.. (eg- edit component, select all, explode, generate faces, exit component)

                                            those steps are what ruby watches, then places the commands in a .scpt format and moves them to the services folder.

                                            [edit-- sorry for not cleaning up the quotes in my replies.. im on a phone and deleting big chunks of text is no fun πŸ˜„ ]

                                            dotdotdot

                                            1 Reply Last reply Reply Quote 0
                                            • 1
                                            • 2
                                            • 1 / 2
                                            • First post
                                              Last post
                                            Buy SketchPlus
                                            Buy SUbD
                                            Buy WrapR
                                            Buy eBook
                                            Buy Modelur
                                            Buy Vertex Tools
                                            Buy SketchCuisine
                                            Buy FormFonts

                                            Advertisement