• Login
sketchucation logo sketchucation
  • Login
ℹ️ GoFundMe | Our friend Gus Robatto needs some help in a challenging time Learn More

Drawing an array of boxes

Scheduled Pinned Locked Moved Developers' Forum
15 Posts 3 Posters 763 Views
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.
  • Z Offline
    Zane
    last edited by 7 Apr 2011, 17:16

    
    module Examples 
    module SU 
    module Structure 
    require 'sketchup.rb' 
    class Building 
            def io_calcs 
                    #distprompts = [$exStrings.GetString("What is the distance between 
    the start of one column to the start of the next one? (make it at 
    least 1m more than the width of the foundation")] 
                    #distvalues = [5500] 
                    # Now display the inputbox 
                    #distresults = inputbox distprompts, distvalues, 
    $exStrings.GetString("Distance between each column  (mm)") 
                    #return if not distresults # This means that the user cancelled the 
    operation 
                    #coldistance = distresults 
                    ##Enter values from C++ here 
                    slab = IO.readlines('C;\\Users\\Zane\\My Documents\\slabout.txt') 
                    $slabdepth = slab[0].to_f.mm 
                    $slabwidth = slab[1].to_f.mm 
                    $slabheight = slab[2].to_f.mm 
                    UI.messagebox ("Sketchup will now take in the details and attempt to 
    draw the building", MB_OK) 
            end 
            def draw_slab 
                    # Makes the process seem to be one rather than many; undo will undo 
    the whole operation 
                    model = Sketchup.active_model 
                    model.start_operation $exStrings.GetString("Draw Slab") 
                    #Adds model to the active entities collection 
                    entities = model.active_entities 
                    #Creates the object as a group 
                    group = entities.add_group 
                    entities = group.entities 
                    #gives an initial location for the foundation 
                    $slabwidth += $start_of_slab 
                    #Creates an array of points for the base 
                    pts = [] 
                    pts[0] = [$start_of_slab, 0, 0] 
                    pts[1] = [$slabwidth, 0, 0] 
                    pts[2] = [$slabwidth, $slabdepth, 0] 
                    pts[3] = [$start_of_slab, $slabdepth, 0] 
                    base = entities.add_face pts 
                    # reverses direction of pushpull if incorrect. 
                    $slabheight = -$slabheight if( base.normal.dot(Z_AXIS) < 0 ) 
                    # pushpulls object 
                    base.pushpull $slabheight 
                    # ends operation 
                    model.commit_operation 
            end 
            def draw_slab_array #need to do 
                    $start_of_slab = 0.mm 
                    draw_slab 
                    wob = 30000.mm #not needed in the final one 
                    wobt = wob 
                    while ((wobt - $slabheight)>$slabheight) 
                            $start_of_slab = $slabwidth + $slabheight 
                            draw_slab 
                            wobt = wobt - $slabheight 
                    end 
                    $start_of_slab = wob - $slabheight 
                    draw_slab 
            end 
    end 
    if( not file_loaded?("structureclasstestforstartpoints.rb") ) 
        # Adds a separator to the menu 
            add_separator_to_menu("Draw") 
        # Adds item inside the menu allowing a bit of code to be 
        #carried out if clicked on 
            UI.menu("Draw").add_item($exStrings.GetString("Test Structural 
    Slab")) do 
                    frame = Building.new 
                    frame.io_calcs 
                    frame.draw_slab_array 
            end 
            file_loaded("structureclasstestforstartpoints.rb") 
    end 
    end #Structure 
    end #SU 
    end #Examples 
    
    
    
    1. Why is it that I need to create global variables for my program to
      say that the variable is recognised? Surely I can just use the
      variable anywhere in the class and it will work so long as it has been
      intialised before use?

    2. Do you guys see anything else wrong with the code?

    3. The code keeps looping in the while loop... help? (slabheight is about 7700)

    Thanks for your help guys!

    1 Reply Last reply Reply Quote 0
    • C Offline
      Cleverbeans
      last edited by 7 Apr 2011, 17:56

      There are only four points, so the only condition under which there would be repeated points are $start_of_slab == $slabwidth. If $slabwidth is 0 initially then when it's incremented it will take on teh value of $start_of_slab. Are you sure you didn't mean to type it $start_of_slab += $slabwidth? If you're using $start_of_slab as the initial position I expect that's the trouble.

      As for the variables there are more than one level of scope a variable can have. If you're not calling the Building.new method anywhere you're probably wanting class methods, which should read "def self.method_name" rather than just "def method_name", which will have access to class variables rather then using globals. Also, you cannot declare variables anywhere, if you're going to declare an instance variable it must be done within an instance method. There is some subtlety here between a class instance variable (not to be confused with a class variable) and a object instance variable which requires some care, since it's easy to declare it in the wrong location and get unintended behavior.

      Even better though, would be to get rid of the variables all together and use parameters and return values for your methods instead. This really helps when trying to track down where a bug is introduced since if the problem is with a global variable, every method that interacts with that variable has to be checked and it requires tracing all the method calls. If you've got parameters and return values you can verify each block independently which can save a lot of headaches. You can always put in useful default values, and array unpacking in Ruby is a really nice feature when you've got multiple return values like depth, width,height triplets. I don't see any explicit need to store the values as variables with the provided code, so maybe consider that approach if you can swing it.

      1 Reply Last reply Reply Quote 0
      • Z Offline
        Zane
        last edited by 7 Apr 2011, 18:08

        I used Building.new and called the io_calcs function as well as the draw_slab_array function, what does that mean about my variables then, should I be able to use them within the functions that are in the class?

        To my knowledge, within a class, Ruby makes all of it's variables and functions public unless specified otherwise, so it confuses me as to why I get this problem of the variable not being read

        1 Reply Last reply Reply Quote 0
        • C Offline
          Cleverbeans
          last edited by 7 Apr 2011, 18:21

          Each kind of variable is referenced differently to indicate it's scope. @@var is a class variable, @var is an instance variable, and var without a modifier is a method variable. method variables can only be referenced within that method, instance variables have unique values for each instance, and class variables are shared by all instances of a class including super/sub classes. Class instance variables exist as well, and use the @var syntax, but are declared outside of a method which can trip up the unaware coder. They act like class variables but without super/sub classes having access to them. This gives you granular control over the scope for the reasons mentioned above - variables with limited scope are easier to debug. Using that as a rule of thumb then a best -> worst listing would be method -> instance -> class instance -> class -> global. In your case I believe simply changing the $ to @ would give you the behavior you're looking for assuming you want distinct values every time you call Building.new

          1 Reply Last reply Reply Quote 0
          • Z Offline
            Zane
            last edited by 7 Apr 2011, 18:43

            Ahh i see, thanks for that 😄

            Another error now, the code keeps looping and doesn't stop (doesn't draw either), the values seem to be wrong also... nothing seems to be working :s

            1 Reply Last reply Reply Quote 0
            • C Offline
              Cleverbeans
              last edited by 7 Apr 2011, 19:06

              I would suggest breaking the code out into logical steps, and give each step a method. Normally I'd start with a blank file and write out what I want to happen in natural language as comments. Once I get it into a step-by-step form that makes sense I will declare method names around each step. Once I've done that I figure out what the inputs and outputs of each method should be and document them in a comment. Once that's done I pick the easiest one to test, write a simple test for it, then implement the method and see if it passes the test. Repeat until finished. It's hard to say why it's failing here because of all the variable kicking around, so maybe just try and split the methods into more bit sized portions then put it together at the end.

              1 Reply Last reply Reply Quote 0
              • Z Offline
                Zane
                last edited by 7 Apr 2011, 19:32

                I think i've found it with the help you gave there (just a snippet of the code where the error might be):

                
                class Building
                	def io_calcs
                		#distprompts = [$exStrings.GetString("What is the distance between the start of one column to the start of the next one? (make it at least 1m more than the width of the foundation")]
                		#distvalues = [5500]
                		# Now display the inputbox
                		#distresults = inputbox distprompts, distvalues, $exStrings.GetString("Distance between each column  (mm)")
                		#return if not distresults # This means that the user cancelled the operation
                		#coldistance = distresults
                		
                		
                		##Enter values from C++ here
                		
                		slab = IO.readlines('C;\\Users\\Zane\\My Documents\\slabout.txt')
                		@slabdepth = slab[0].to_f.mm
                		@slabwidth = slab[1].to_f.mm
                		@slabheight = slab[2].to_f.mm		
                		#UI.messagebox ("Sketchup will now take in the details and attempt to draw the building", MB_OK)
                	end
                
                

                It's either not taking in the values of slabheight, slapdepth nor slabwidth as i'm trying to take them in from an input file.
                It's not even letting me "puts" the variables nor any other string I tell it to output like:

                puts 'test'

                Ideally i want to input variables from a text file whose content is

                250
                5500
                7700

                and assign each one of these values to a variable, then use those respective variables.

                1 Reply Last reply Reply Quote 0
                • D Offline
                  Dan Rathbun
                  last edited by 7 Apr 2011, 23:14

                  The namespace Examples::SU I really intended for the Google supplied examples.

                  You should choose your own Toplevel namespace (Zane is good for now.)

                  Beneath that you will have you various plugin namespaces (module blocks.)

                  like this or similar:

                  module Zane
                    module BuildWizard # this plugin
                      module Structure
                        class Building
                        end # class
                        class Bridge
                        end # class
                        class Roadway
                        end # class
                      end # module Structure
                      module Widget
                      ebd # module Widget
                    end # module BuildWizard
                  end # module Zane
                  

                  etc..

                  Once your namespace heirarchy is defined (in the first loaded file of your plugin,) you can break up the various code blocks into separate files (and save some indentation by using qualified blocks:

                  file2

                  module Zane;;BuildWizard;;Structure
                    # define module vars and module methods
                  end
                  

                  file3

                  class Zane;;BuildWizard;;Structure;;Bridge
                    # define instance vars and instance methods
                  end
                  

                  file4

                  class Zane;;BuildWizard;;Structure;;Building
                    # define instance vars and instance methods
                  end
                  

                  file5

                  module Zane;;BuildWizard;;Widget
                    # define module vars and module methods
                  end
                  

                  .. etc...

                  and use the require("filename") where needed to load the various files that make up your plugin project.

                  I'm not here much anymore.

                  1 Reply Last reply Reply Quote 0
                  • Z Offline
                    Zane
                    last edited by 7 Apr 2011, 23:20

                    Sorry Dan, i'm a bit lost as to what you mean by your last post, why is it that I would split the file up into bits and what is the purpose of using modules, i've read they're similar to classes but nothing specified a distinct reason as to why they are as they are?

                    I'm also curious as to what you meant when you wrote module_function(:function) in the box.rb file, what does it do exactely? I presume it can only be used for external functions and not ones in classes?

                    1 Reply Last reply Reply Quote 0
                    • D Offline
                      Dan Rathbun
                      last edited by 7 Apr 2011, 23:27

                      @zane said:

                      I think i've found it with the help you gave there (just a snippet of the code where the error might be):

                      
                      > 		#distprompts = [$exStrings.GetString("What is the distance between the start of one column to the start of the next one? (make it at least 1m more than the width of the foundation")]
                      

                      $exStrings is not YOUR object. It is a hash of strings, created and used by the Google supplied code examples.

                      Create your own local string, or a LanguageHandler hash object within your plugin namespace (DO NOTuse a global like Google did, it is bad programming.)
                      Or just use a string literal.
                      distprompts = ["Column Spacing"]

                      Also with a prompt string that large, the UI.inputbox is likely to look crazy.

                      I'm not here much anymore.

                      1 Reply Last reply Reply Quote 0
                      • Z Offline
                        Zane
                        last edited by 7 Apr 2011, 23:33

                        ok, thanks for the headsup on that, any idea about the crazy looping issue or why I can't see the puts anymore? Oh, and that module question, sorry there's so much to ask.

                        1 Reply Last reply Reply Quote 0
                        • D Offline
                          Dan Rathbun
                          last edited by 8 Apr 2011, 01:10

                          Another booboo:

                          coldistance = distresults

                          A UI.inputbox returns an Array, not a single value.
                          So to get the first value from an inputbox:

                          coldistance = distresults[0]
                          or
                          coldistance = distresults.first

                          I'm not here much anymore.

                          1 Reply Last reply Reply Quote 0
                          • D Offline
                            Dan Rathbun
                            last edited by 8 Apr 2011, 01:27

                            @zane said:

                            I think i've found it with the help you gave there (just a snippet of the code where the error might be):

                            It's either not taking in the values of slabheight, slapdepth nor slabwidth as i'm trying to take them in from an input file.
                            It's not even letting me "puts" the variables nor any other string I tell it to output like:

                            try stripping each line of whitespsce and control characters:

                            
                            		slab = IO.readlines('C;\\Users\\Zane\\My Documents\\slabout.txt')
                            		@slabdepth = slab[0].strip.to_f.mm
                            		@slabwidth = slab[1].strip.to_f.mm
                            		@slabheight = slab[2].strip.to_f.mm
                            
                            

                            Eventually you'll want these values on one line separated by commas (likely with the tag "slab" as the first vaule.

                            
                              lines = IO.readlines('C;\\Users\\Zane\\My Documents\\slabout.txt')
                              lines.each {|line|
                                data = line.strip.split(',')
                                if data[0]=='slab'
                                  @slabdepth = data[1].to_f.mm
                                  @slabwidth = data[2].to_f.mm
                                  @slabheight = data[3].to_f.mm
                                elsif data[0]=='wall'
                                  # do something else
                                end
                              }
                            
                            

                            I'm not here much anymore.

                            1 Reply Last reply Reply Quote 0
                            • D Offline
                              Dan Rathbun
                              last edited by 8 Apr 2011, 02:04

                              @zane said:

                              Sorry Dan, i'm a bit lost as to what you mean by your last post, why is it that I would split the file up into bits ...

                              When you write complex plugins that have 1000s of lines of code, you WILL get tired of scrolling up and down. It is easier if you have a tabbed code editor to click another tab, find what you need in another file (a constant name, etc.,) and then click the tab of the file your working on. (I use Notepad++ which also allows splitting the editor into 2 panes.)

                              @zane said:

                              ...and what is the purpose of using modules, ...

                              See my info topic: [info] Using Ruby Modules

                              @zane said:

                              ...I've read they're similar to classes ...

                              Actually, class Class is the child subclass of class Module, and subclasses inherit objects (like methods,) from their superclass, so of course they are similar.

                              @zane said:

                              I'm also curious as to what you meant when you wrote module_function(:function) in the box.rbfile, what does it do exactly? I presume it can only be used for external functions and not ones in classes?

                              Well... you won't understand this issue until you do some reading... but basically the module_function() allows a coder to write a double-duty module, that can act as both a library module (it's methods are called from outside using name qualification,) and a Mixin-Module (that is mixed into classes, giving the class all it's instance methods.)
                              The box.rb is really a poor example of such a "double-duty" Module.

                              see Ruby Pick-Axe book: module_function

                              Jim asked a similar question, and I answered in the box.rb Example topic, see:
                              Re: module_function

                              Zane.. did you read my "Newbie's Guide" ? (If not click the Ruby Resource link in my signature.)

                              I'm not here much anymore.

                              1 Reply Last reply Reply Quote 0
                              • Z Offline
                                Zane
                                last edited by 9 Apr 2011, 21:53

                                Thanks Dan, I have read the pragmatic programmers book but that was a while back and unfortunately I have a deadline submission I need to meet next week, i've managed to get the C++ side of the coding done but am struggling with the Ruby and don't have time to re-assess what i've learnt, just need to sift through the relevant information and collaborate it.

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

                                Advertisement