Lesson 4 – part 2 – the wombats

So in true Blue Peter style, Here's one I made earlier, try to read it:

  1. #setup stuff
  2. mod = Sketchup.active_model
  3.  
  4. ent = mod.entities
  5. sel = mod.selection
  6. materials = mod.materials
  7.  
  8. #some cube variables
  9. edgeLength = 1000.mm
  10. gap = 100.mm
  11. offset = 0
  12.  
  13. #tell ruby where our textures are
  14. Dir.chdir (‘ C:\Users\bdoherty\Desktop\BVN_Photos‘)
  15.  
  16. Dir.foreach(“.“) { |file|
  17.   type = file.split(‘.‘)[1]
  18.   unless type == nil
  19.     type.downcase!
  20.     if (type ==’png‘) or (type==’jpg‘)
  21.       puts file
  22.       #create a cube
  23.       #setup the corner points
  24.       #                         x                    y           z
  25.       points=[Geom::Point3d.new(0          + offset, 0,          0),
  26.               Geom::Point3d.new(edgeLength + offset, 0,          0),
  27.               Geom::Point3d.new(edgeLength + offset, edgeLength, 0),
  28.               Geom::Point3d.new(0          + offset, edgeLength, 0)]
  29.       #add the bottom face
  30.       myCubeBase = ent.add_face points
  31.       myCubeBase.reverse! #flip it. ! means -in place- i.e. myCubeBase = myCubeBase.reverse
  32.       #do a push pull to make it into a cube**********
  33.       # Adds a material to the “in-use” material pallet.
  34.       materialName = file.chomp(‘.jpg‘)
  35.       m = materials.add materialName
  36.       # pulls a texture out of a folder
  37.       m.texture = file
  38.       unless m.texture == nil
  39.         m.texture.size = edgeLength
  40.       end
  41.       myCubeBase.material = m
  42.       myCube = myCubeBase.pushpull(edgeLength, true)
  43.       offset += edgeLength + gap
  44.     end
  45.   end
  46. }

How did that feel? Are you starting to be able to read the code? You aren't just learning to program, you are aquiring a new kind of literacy! (That's a pretty big and exciting idea!)

Even to the untrained eye, there is a bit more going on here. Not a huge amount, the code in part 1 was 39 lines long, and the code in this part is 52, not an encyclopedia of code more, so lets unpick what it does.

Line 10 is the first time that anything new happens. There is a new variable that defines the gap between the boxes as we go along. With each new box we draw, we add 1 box width and 1 gap to the place that we start drawing the box. This is so we don't just draw all the boxes on top of each other. The first time around the loop the offset from the origin is nothing, so we define offset = 0.

Now there is a furious flurry of activity, lines 14 to 21 are doing a lot of work.

14 sets the currently active directory to be wherever you are hiding your pile of images. It is a method on the Dir class so if you want to read about it then it is in the docs. This is like the conductor raising his baton, and the moment of silence becore the cacophany starts.

Line 16 is a sneaky one, it really gets things going. Dir.foreach(“.“) is saying to ruby “for each thing in the current directory" "." is  old fashioned

speak for this directory "ahem, as I was saying, for each thing in the current directory, throw out the name of that thing"

I was camping once, and there was a noise outside the tent, on poking my head out I could see that it was a wombat. He had prised the lid off our food tub, and had climbed inside. He was throwing the food out to his acomplice who was then ferrying it off to their burrow. This part of the foreach loop is like the wombat in the food tub.

If the wombat in the food tub is getting all the glory, the next bit is doing all the work. { |file| catches the filename, calls it file while it is holding it, and runs off into the burrow.

The burrow is defined by the curley braces {} they even look a bit like a burrow! While the filename is in the burrow we can call it file, but not when it is outside, ruby doesn't think it exists outside. This is more scope. (Remember scope from the first part of this lesson?)

Lets follow our industrious wombat sidekick down the burrow, and see what's inside…

Actually, I lied a little bit when I said that the wombat in the tub was the one who did the renaming. As _Why puts it, |file| is like a chute that is just inside the burrow.

Imagine Alice falling down the rabbit hole. In Lewis Carrol's version she is Alice when she goes in, and Alice when she gets to the bottom, but in our version there is a sign at the top of the rabbit hole that reads "become file". Then as we are falling down the hole we reach into the cupboards and draws that surround us and pull out the f hat, the i tie, and the le jumpsuit. The inhabitants of wonderland now thing that we are the famous mr file, and not just an imposter dressed as him.

So now we are dressed as file we need to pass some more tests. This is called defensive programming; it is important never to underestimate how many ways that programs can go wrong when you feed them duff information, defensive programming is a bit like a border guard, checking your papers, then sending you on for an interview, then doing a retina scan, an xray, calling your references, doing an aptitude test…

type = file.split(‘.‘)[1] is the first stage, it is like taking your laptop out of your bag at the airport. Because file is a string it can be fiddled with by the string methods as we played with in the first lesson. Split takes a file name like britneynaked.txt or mThatcher_BrightonBeach.jpg and if we ask it to split on . we get the arrays [‘britneynaked’, ‘txt’] and [‘mThatcher_BrightonBeach’, ‘jpg]. So because arrays are indexed from 0 we know that the file extention is in the 1st box. We take that information, and store it in type.

Ruby's unless blocks really are a thing of wonder. They are a part of ruby’s unparallelled readability. Try it, read it out loud: "unless type equals nil do this stuff". What unless type == nil does is make sure that the there really is something to check for hidden inside the type.

type.downcase! is like the helpful people in the customs queue who tell you where to stand and what to say before you get interviewed by the big scary if block. It does an in-place converstion from aNy CaSE to all lowercase. That way we can be sure that 'apples'=='apples' because 'APPLES' does not equal 'apples'.

'apples'=='apples' ==> true

'APPLES'=='apples' ==> false


if (type == ‘png‘) or (type == ‘jpg‘)

The next line checks to see if type is either a .png or a .jpg. It is a conditional statement so it must eventualy resolve to a single true or false value. This is something that cauught me out so may times when I was learning to program; I would always write if (type == ‘png or  ‘jpg‘) but as far as the computer is concerned this is meaningless. It helps to think of this as a tree.

Each bracket resolves to a true or false value, and then that gets resolved, and eventually we end up with a single value. A true or false value is called a bool after George Boole. He invented a kind of mathematical logic that was only concerned with truth values. There are other types of logic that have more than two values, but they are pretty hardcore (fuzzy and ternary to name a couple).

So after that excursion, we have made a check that the file that we are dealing with is in fact a png or a jpg. The defensive programing won't allow things that pass that test through, so we have a better chance that there will be fewer errors within that block.

An object is a special programing concept, very similar indeded to its real world counterpart. In simple terms, objects have methods and properties. Methods are things that the object can do, and preoperties are facts about the object.

Instantiate means that you create an instance of an object. So in this case when we instantiate a new point, we make a new point object.

The bit where we define the corner points of the face has changed a little bit here too. Instead of using the lightweight point substiture of a three element array i.e. [xValue, yValue, zValue] this time we are going to instantiate a point object.

Geom::Point3d.new(xValue, yValue, zValue)

Point3d is an object in the Geom class. We won't go into the details of what all of this means, all that matters is that it has a method called .new that makes it make a new one using the arguments provided. This line does the same thing as it did before, except this time we are instantiating the points more explicitly. This doesn't do much from the computer's point of view (it would be useful if we were assigning them to a variable because we could refer to myPoint.x rather than myArrayMasqueradingAsAPoint[0]) but its real use is that it makes the code readable.

The next line that is different is the one where the material gets named:

materialName = file.chomp(‘.jpg‘)

So what is going on here is that we call up the power of the chomp method (which belongs to the string class) by dangling a bit of bloody tuna carved into the shape of the word '.jpg' off the back of the plane, and waiting for the great white shark of string to come and chomp it off. We could carve anything into the argument, so if I wanted to chomp 'plane' off the end of 'aeroplane' then I would say 'aeroplane'.chomp('plane') and it would give me back 'aero'. This is to give us the name of the person in the picture, without the file extention.

We've seen unless before, so We can skip that and move straight down to line 48.

Remember that we are doing the stuff between the {} braces lots of times; once for each file in the folder. This means that we can use this precess to change things outside the loop each time we go around. Imagine that we are on a roundabout, and each time we pass the start we lean out and take an ice cream. Now imagine really really hard (because this part is totally unbelievable) that you don't like flakes.

If you pulled out all the flakes and stacked them on the seat beside you, after a while you'd have a lot of flakes. One for each time you'd been around.

What we are doing is that each time we go around we are adding a number (in this case two numbers; gap and edgeLength) to the current offset. This means that the next time that offset is used it will be a bit bigger than last time round, and so on until there are no more photos to make boxes out of.

some faces mapped onto boxes

And that, dearly beloved, is how to make a lot of boxes with faces on them.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s