Monday, February 24, 2014

Make (Polygon) Faces Anywhere and Produce a Sketchup Model

Sketchup Make is a helpful tool from Google that allows you to fairly quickly create a visual of your building project ideas.  The commands are relatively simple, although you can get a great deal of (intentional) variety in your results with practice.  Sketchup (including Sketchup Make) also allows the user to extend the functionality of the program using Ruby scripts (I say scripts because in Sketchup they are not compiled prior to use but either interpreted or compiled/run every use—not sure which).

But if you'd rather not learn Ruby right now or if perhaps programming just isn't your thing, there's a simple tool that can help you turn columns of numbers into a Sketchup model. I've written a text file importer (specifically, *.csv file format) that will interpret each row of numbers as the vertices of a face or of a polyline (depending on the beginning of the line).

The deal is, you need to make a CSV file (Comma Separated Values) which has all of the points you need in it. You can make these in Excel.
Fig. 1. Screen shot of a *.csv file open in Excel. Each group of 3 consecutive numbers is interpreted as a 3D point.
Any number of points is allowed per line, though you'll need them to be co-planar if you want a face.
The next two screen shots show an example of how you can set up a spreadsheet to calculate a segment approximation of a sphere. (Kind of like a segment of an orange.)  Click on them to see them at full size.

Fig. 2. Segment of a sphere calculation
Fig. 3. View of the formulae used. Not very complicated, but very organized.
Note that you will need to have the vertices for a face in either clockwise or counter-clockwise order. Copy the vertices on the right, go to a separate sheet of the workbook, and use the paste values option. Save your spreadsheet and then Save As, select "CSV" and name your file appropriately. (This will make the CSV file you need but if you want to go on making changes to your original spreadsheet, you would be best to reopen that spreadsheet. As per the usual behaviour of Save As, your original spreadsheet prior to Save As is now closed and you only appear to still be in the same spreadsheet. Kind of irritating.)

Fig. 4. Save As dialog in Excel. Select CVS format.
Here is an animation of a model that I started with a CSV file using the paraboloid tab of the pictured spreadsheet. I then did a rotate-copy a few times to get the completed shape.


8 segment approximation to a paraboloid from Darren Irvine on Vimeo.

What Do I Need in the CSV File?

Each line must start with line or face followed by a comma. Commas are what separate the entries. New lines separate each line and face. The lines are treated as polylines.  For a face you will need at least 9 numbers (or 12, 15, 18, etc., numbers) separated by commas after the first item, like so,

     face,0,0,0,10,10  ,11 ,  55,100 ,  44

Extraneous spaces are okay as long as they don't interrupt a number. It's okay if your lines trail off, as in

     face,0,0,0,10,10,11,55,100,44,,,,,

But you don't want blank entries in the middle like

     face,0,0,,0,10,10,11,55,,100,44

or random non-numeric data like this

     face,0,0,don't put this here,0,face (not here, at the beginning!), 2343, random illegᾳλ χaρaχτeρs: θ, 40,44

Faces will only work as intended if you list the points in either clockwise or counter-clockwise order. You'll end up with a tangled mess otherwise. As for polylines (line), the script will just assume you know what you're doing, although you still should give it point information as for faces.

My script shouldn't cause your system to crash if you feed it bad data, but just the same, play it safe and save your Sketchup model prior to running the script. The import does not start a new file on its own, it imports into the current model—which may be empty.

What Tools Do I Need?

  • Sketchup Make (or above): Sketchup Make is free.
  • dsi_csvfaces.rb: you can obtain the ruby here. Copy it into your Plugins directory. In Sketchup 2015 this is C:\Users\<your_windows_user_name>\AppData\Roaming\SketchUp\SketchUp [n]\SketchUp\Plugins (see http://www.sketchup.com/intl/en/developer/docs/loading).
  • An example:  Have a look at my example spreadsheet which contains a way to approximate a segment of a sphere and a paraboloid.
  • A little ingenuity: make the CSV file anyway you know how. Excel is only one option, but I think it's one that many users are likely to be adept at. You may want to use a programming language (perhaps you're a programmer, but not into Ruby or have intellectual investment in some other means). You may want to use a computer algebra system like Maxima (free), Maple V, or Mathematica. Maybe Javascript. All at your option. You just need a CSV file.

Friday, February 7, 2014

Round 'em up!

Over the past several months I have been dabbling in Common Lisp (LISt Processing language).  Lisp, I think, is the ugly duckling of the programming languages.  The facetious "Lost In Stupid Parentheses" seems more apt as an acronym.

My first encounter with this ungainly language (Lisp) was in AutoLisp (and Visual Lisp). I was on a hiatus from programming regularly and discovered this immediately discouraging language that was the "easiest" way to interact with AutoCAD programmatically. (I don't consider AutoCAD scripts to be programming, though I would still include them under the more general category automation.) I did not make much headway at that time and it frankly amazes me that any non-programmer will step up to the challenge and learn it.

But then there was Maxima. I was happy with Maxima as a free computer algebra system. But in the documentation I found the spectre of Lisp. Specifically, Common Lisp. The computations in Maxima are all in Lisp (though there is probably some non-Lisp they use to glue together a Windows interface for Maxima). Maxima itself supports a fairly robust set of programming constructs as far as doing calculations are concerned.
  • Input/output from files
  • Controlled loops
  • if-then-else
  • functions
  • plotting (via gnuplot—included in standard installs)
  • formatted output
    • nice math notation display
    • export to latex or image
Maxima is built on top of Lisp and you really have all the abilities of Lisp in Maxima (if you know how to get at them). But, being as I am, always in search of a better way of doing something, I am also concerned with whether a technology built on top of another is "hiding" some of the features of the underlying technology. Perhaps hiding isn't exactly the right way to put it, but learning Lisp is a paradigm shift from most other (Algol-like) programming languages I was familiar with, while on the other hand, learning Maxima didn't take me through that paradigm shift.

The two most interesting features of Lisp to me are the emphasis on function references and macros. But they both help you to do the same thing: reduce the repetition in your code. Mind you, they serve this end in very different ways.

When I wanted to implement Jarvis's march [1, p. 955] to encircle a list of points in a "convex hull" it was particularly the function referencing that made the implementation of the code fairly simple.

Fig 1. The red lines join together the red + signs which indicate the convex hull for these points.
The general idea of Jarvis's march is you find an outside point to start from and then keep picking the next point so that you never have to switch directions as you walk around. I started at the left most point. In the event of a tie, I choose the lower of these. (That would place us at about (0.1, 15.0).) I decided to walk around the points in a counter-clockwise direction. To decide which point comes next, I need to find the point which requires the right-most turn. So I begin by choosing the first of the remaining points (in whatever order I received them). I go through the remaining points and test whether I would need to make a right turn or left turn to point toward them (from my vantage point on the starting point of the hull chosen at my first step). If it is a right turn, then I have a new winner which replaces the first and I continue moving forward to the points not yet checked. The algorithm is really a repeated application of a maximum function where maximum is defined according to a different function than normal. What I need are predicate functions which define the rules for choosing a winner (a "maximum") and a routine to separate the winner from the remaining points that can accept a predicate function as a parameter.  Here's the code for, remove-winner:


The idea of remove-winner is to use the test function (supplied by the caller) to determine whether the next item is "better" than the current winner. If you passed in the function < (using the syntax #'<) you would get the smallest value in the list (provided it was a list of numbers). Notice the thought process in this function is not just to find the max and return it, but rather to produce a list which includes the "winner" and the rest of the values (that didn't win) separately. We don't just need to know the winner, we need to separate the winner from the rest.

When we get to the convex-hull routine, we can use the same routine (remove-winner) using two different tests: one to find the initial element and another to find the successive elements.



The first occasion we use remove-winner, the function is of the same sort we would use to perform a two key sort. In the main body of the routine, we have a more interesting function which accepts two points, calculates their direction vectors (using the current head node of the hull as the origin) and decides whether the second is a right turn away from the first, in which case it declares the second to be the (current) winner.

Can you do this [abstract the predicate] in other languages? Yes. In many other languages you could implement the routine substantially like this. But the key is this: would you ever think to do it this way if you were using VB.NET or C# or C++? Maybe. But not because of your experience with those languages, but because of your experiences with Lisp or F# or other languages which feature a functional style of programming.

Fig. 1 was produced from running a small bit of Maxima code which loads some routines from a separate package written in Lisp (including the above routines).  You can download both files to try them out:
You will need to have Maxima installed to try this example out.

Sources:
  1. Cormen, T.H., Leiserson, C.E., Rivest, R.L., & Stein, C., Introduction to Algorithms, Second Ed., McGraw-Hill Book Company / The MIT Press, 2001.