Introduction
Don't expect this to be anything... it's just a bunch of relatively-disconnected words about what was going through my head at various times during the project, and how I fixed it, which I'm writing at the request of the professor. More or less...
Glyph shape
Each glyph is a Python class which, when instantiated, knows the properties of the glyph (weight, cap-height, slant, etc.). Using this information, it constructs the geometry of the glyph, which is made by combining two different primitives: line and circle. Both of these primitives can also be clipped by arbitrary polygons (this is how the C is constructed, for example: by taking a circle and clipping out a triangular wedge from it).
Geometry manipulation (basic boolean stuff; almost always either union, intersection, or difference) is done with the Shapely library, because I really didn't want to do that myself, as it's not very interesting.
Each glyph has a function which calculates its width relative to one em, information which is used heavily during the drawing phase.
The glyph shape function can be either very complicated (like, say, 2) or very simple, like that of the lowercase l:
mainLine = Line(self.p(0.5, 1.0), self.p(0.5, 0.0),
self.weight(), serif=5)
return [mainLine]That's a very simple one. 2, in comparison, is about 50 lines long...
The line constructor that you see above takes three required arguments: the location of both endpoints, and the weight of the line to be drawn. The optional
serif argument adds serifs, which we'll talk about later.
The 'p' function (I needed a really short name because I call it hundreds of times and wanted it to be neat - think of it as 'position') that I call there takes a percentage position (0.0 to 1.0) in x and y (measured from the bottom left, like things
should be done) and turns it into coordinates in the glyph's coordinate space. p also takes another argument which determines whether it should consider the top of the glyph to be at the cap-height or the x-height.
Many of the glyphs have small adjustments that are made to the shape of the glyph as the weight changes, in order to correct for unpleasant effects.
So, the l above makes a line from the top, halfway across the glyph, to the bottom, halfway across the glyph, at the full weight of the glyph, with the 5th serif type, which will be described below.
You can look at the rest of the glyph functions on GitHub:
Capitals,
lowercase,
numerals,
punctuation.
Strange or Missing GlyphsI added center-dot (for multiplication) and interrobang (at the request of my roommates) to the normal set of glyphs. My 0 is too wide, but I couldn't bring myself to make it an oval (or, more likely, similar to the shape of the 6 or 9). My angle-brackets are huge. HUGE! Maybe I'll fix them someday. I'm missing curly braces, because they'd be really annoying to draw. Much worse than 2, which was enough of a pain that I don't want to endure it again.
SerifsSerifs are actually added by the line drawing logic - each character doesn't really need to know how to draw a serif, it just needs to know what kind of serif it wants, and asks politely for that. There are 6 kinds of serifs a glyph can ask for on one of its lines:
0 - No serifs
1 - A vertical half serif on one end of the line. (E)
2 - A vertical half serif on both ends of the line. (T)
3 - A full serif on one end of the line. (A)
4 - A full serif on both ends of the line. (H)
5 - A full serif on one end of the line, a half serif on the other. (l)
6 - A half serif on one end of the line. (j)The fact that glyphs don't know about serifs is neat, because it means we can turn
off the serifs very easily, by just asking Line not to draw any! That's how we get the sans-serif variant, which isn't on the poster, but that's ok... it's just not as awesome.
PropertiesPHI = 1.618... (golden ratio)
Fixed glyph properties are as follows:
1 em = capHeight / PHI
xHeight = capHeight / PHIThe defaults for variable glyph properties are as follows:
weight = 3 (this is a unitless measure, where ultralight = 0.5 and heavy = 7)
slanted = False (not really italic, it's more slanted than anything)
outlined = False (this was more for testing, but turned it into outlines)
color = Black (obvious)
serifed = True (whether or not Line should draw serifs for this glyph)
autoKern = True (you'll see, in a bit)ItalicThe italic variant isn't nearly as neat as all the rest, it's just made quite literally by shearing the character with Cairo while it's being drawn. Not interesting, not particularly awesome, but it worked out OK. There's a pretty good chance it will break the consistency of inter-word spacing, but I'm not totally sure how to fix that (without doing the shearing beforehand, with Shapely... or manually).
WeightsTechnically, you can generate glyphs of whatever weight you want, because it's all procedurally generated. However, I blessed a few weights so that I didn't have to look at/tweak more than a few weights:
Ultralight = 0.5
Light = 2.0
Regular = 3.0
Bold = 5.0
Heavy = 7.0KerningKerning was a stickling point for the first few days. At that point, I was just throwing glyphs down and advancing the x position by the reported width of the glyph. We all know why this doesn't work, though, with the AV pair being the classic example.
So, instead, I wrote an optical autokerner in a few lines of Python. It works by placing the two glyphs on a plane and shifting them back and forth until it finds the boundary where they're
just touching, then adds the correct amount of kerning. There's a kerning table which gives adjustments relative to this value, but it only has a handful of entries (one case which was particularly problematic was +=, where the bar of the plus slid directly into the middle slot of the equal-sign, kerning them
way too tightly). It could probably do with a few entries, but after all this, I didn't have a lot of time to work on the kerning table, and I didn't really think it looked
terrible - at least not enough to worry about.
There's another issue with the optical autokerning: punctuation. Tiny little dots don't autokern well at all; also, quotes don't ever collide with lowercase letters, so that breaks things too... So I added a per-glyph override which instead kerns based on the bounding box of the glyph extended to basically-infinity in the vertical direction. This mostly fixes the problems with punctuation.
The autokerner is really quite slow (as you might expect), especially for large blocks of text, so there's a disk-based cache that stores the kerning values between runs. You have to delete it if you change the glyph shape, or your kerning will be horribly wrong. Also, the cache is per-capHeight-per-weight (as kerning values change slightly), so if you change the capHeight or weight, get ready to
wait again...
LayoutThe space character is also a glyph - it's a square block which is special-cased to not be drawn at all in the drawing logic. This fixed a lot of trouble I was having when advancing words in the "stupid" way (just adding some amount of x-advance each time you see a space character), where the space between the words ended up varying significantly, which was really tripping up reading.
My line-breaking algorithm is horribly primitive: it just draws words at a time; when it gets to each word, it checks to see if it's past the edge of the layout box. If it is, it moves down by the leading and moves back to the left side of the box. This is a problem mostly because it means the last word on a line could be (and usually
is) extending beyond the right side of the layout box. Also, it creates really crappy right rag unless you pay a lot of attention, because it's really not aware of the idea of rag.
If I had a ton more time, I'd implement Knuth's famous line-breaking algorithm (the one TeX uses), which is pretty much ideal, but since I don't have that kind of time, I decided against writing a poor knockoff. I've heard it's not actually
that complicated, but... relative terms...
Input FormatThe main program takes an XML file with a very simple format. For example, you can see the one that makes the description of the various weights that's on the poster
here.
There are only a few tags defined:
u, l, r, b, h = Weight (ultralight, light, regular, bold, heavy)
i = Slanted/Italic
br = Newline
textbox (attributes x, y, size, width, height) = A reflowing text container
leading, tracking, size (attribute px) = Obvious text properties
color (attributes r, g, b, a) = Obvious color properties
sans, serif = Turn on/off serifsMore StuffIf you have any questions, feel free to
email me.
The code is all open-source, under the relatively permissive 2-clause BSD license, which basically just says you can do what you want with it as long as you keep my copyright header around... (the terms are in LICENSE in the source directory, but they're exactly the same as all of the gazillions of other BSD projects out there). The code is
here.
Libraries/ThanksPython
GEOS +
Shapely
Cairo +
PyCairo
ElementTree
Apparently the semester's nearly over, or so I've been told (repeatedly. naggingly.)! In any case, I've gotten a lot more done on some things than I expected, and a lot less on others... it's always hard to predict how the semester will go.
A Font
For Typography, I've been working on the font + renderer + autokerner that I just wrote about the other day. I won't post any more pictures, just scroll down a little further to see that post!
Orbitals
For Parallel Programming, I've been working on a atomic orbital simulation, using OpenCL to evaluate the electron probability density function for a hydrogen atom at many, many points. It makes nice smooth images like this:

It's showing approximately a 20x speedup, moving from Zoe's CPU to GPU (Core i7 @ 2x2.66/3.33GHz to a NVIDIA GeForce 330M GT). The move from Zoe's CPU to Jayne's GPU (the 4890) is even more awesome; it's something like 40x faster!
Eventually (soon), I'm going to make an animation with it, and then it's time to write a paper!
Particles
For Advanced Computer Graphics, I've been working on a particle system simulator that uses (surprise!) OpenCL to simulate tons and tons of particles at once (millions, anyway). And render them, attractively (the renderer is still in its infancy). And it comes with a tool to design them, too (also incomplete).
I don't have any really interesting examples to show now, because I just got emitters to work. Below is a picture of something like 1,000,000 particles being blown away from the origin by two "simple"-type forces (they just push outward from a point, with inverse-square falloff).

And a video (which will only work if you're using a very recent Chrome or Safari, probably) of the same simulation, though with only 128K points. This simulation really isn't interesting because there's nothing complicated going on. I've got gravity working, which is a gazillion times more interesting and more complicated, but I'll post pictures and video of that some other day (it's also much, much slower).
It also turns out that the overhead of OpenCL isn't worth it for simple forces; it significantly speeds up complex (O(n^2)) forces like gravity (I'm aware of many ways to speed up n-body simulation, I just haven't had a chance to implement them yet), but for O(n) forces like below, it really only provides a tiny-to-near-zero gain.
Sheeple
All of this (plus normal coursework) leaves less time than desired for other things, but I still manage to occasionally put a few hours in to work on Sheeple. I feel bad that I don't have tons of time for RCOS work, though I will note that all of these projects are open source (all of them are under the 2-clause BSD license except Sheeple, which is GPLv3), so the general idea of promoting/using/writing OSS is still there :-)
I recently wrote and pushed a partial implementation of a Google Contacts backend for Sheeple. It's a lot smaller (and nicer, since it's written in Vala), and it's what I'd like to use for the time being while developing the UI and backend stuff, since it's a lot easier to change.
Another thing that contributes to slow Sheeple development is that everything now takes place in a VM; I don't have a native Linux install anymore, and I consider that a good thing. I've gotten sick of wasting time with a broken system, and I'm just not going to do that anymore - I don't care enough nor have enough time to spend to fix things, and I'm just generally all-around much happier in OS X. So both of my machines are running OS X, and I'm pretty sure that's how it's going to stay for the foreseeable future.
I should thank Moorthy and Sean O'Sullivan for putting up with me, and for constructing RCOS and keeping it alive. I wrote a long bit about what I think about RCOS and the people involved a few months ago, and that all still stands. Given this semester's overload (which will likely continue next semester) and how RCOS has worked out within this semester, I find it somewhat likely that I'm not going to participate next semester; I feel guilty about being paid to do much less work than I feel like I should be doing. I'll still hang around, certainly, and I'll (obviously) still write OSS, I'll even happily talk about stuff I'm working on, but the absence of that feeling of guilt/obligation/deadline (and also the ability to bounce between projects as I feel like it) will be quite the load off.
I've spent the last almost-exactly-one week working on my final project for Typography. During the first class, back in January, I decided that I'd try to put together a font for my final project.
I didn't get started as early as I perhaps should have, mostly because I have other final projects I've been working on all semester, so I decided to take this last week off from other projects and just concentrate on this.
Of course, there was no way anyone was going to get me to sit in a room with FontLab for hours on end (it's a horrible program), so I had to come up with something different to do, to make it an interesting project. I eventually decided to try a somewhat different approach: a procedurally-generated font.
Horton Slab (and its sans-serif variant, which you won't see here today) is implemented in Python; each glyph is a separate class with knowledge of its properties, and constructs its geometry from this knowledge. This means that — given enough care — you can automatically generate quite reasonable alternative faces (at different weights, with italics, with or without serifs, etc), reducing design time significantly.
Most of the ratios in the font are derived from phi, the golden ratio. The ratio of cap-height to x-height, serif thickness to stem thickness, height of the crossbar in A, E, F, G, H, etc. to the cap-height, the depth of the middle of M, and many, many other things. This isn't as strict as it could be, but I sometimes sacrificed phi-ness (the original guiding design property) for readability or beauty.
I also implemented a relatively primitive layout engine and an autokerner. There are only a few entries in my kerning overrides table (something like 10) — it turns out that a very simple approach to optical kerning actually works somewhat well.
All of the code is available on GitHub as always, and under a BSD license.
Everything you see below was designed in a silly XML-based markup that my layout engine accepts, and clicking on them will open the straight-out-of-engine PDF.

All of the glyphs I have at the moment:

Some pseudo-Latin filler text:

And a classic Sagan quote:

2009.12.13 in school
Fall semester is over! That's 5/8; just three to go!
I finished the Programming Languages final at 3:00 or so on Friday, stood up, and walked not only out of the DCC, but out of the semester, too! There's a little bit of cleanup left (a final in AI on Thursday, primarily), but after that I'm homeward bound.
I guess I'll say a few things about each class, since that seems to be the thing to do...
Intro to AI was — unless I'm way off base, which doesn't seem likely — the easiest full-sized class I've taken at RPI. The assignments were easy (and even relatively fun) — straight out of AIMA, implement in whatever language you choose, spend two weeks on it. That gave plenty of time to overdo the assignments, which doesn't seem to have phased/angered the professor. The tests weren't too bad; the first one was a little surprising (I came out of it thinking it was either the easiest test I'd taken here, or that I'd missed something vital and failed it, and ended up with a B), and the second is on Thursday.
Programming Languages is an interesting beast. A bunch of ex-Cary people took it along with me (as well as Mike, who dropped the class a week or two in, and has to take it some other semester); a good number of the ones I've talked to about it since believe (along with myself) that the class as it stands should be scrapped, in its entirety. I'm not sure I can/should totally explain why, just that the class is a mess and needs a rethink. It's a good idea — certainly! — to teach various paradigms and languages; I'm not completely convinced it's a good idea to use the professor's pet language to do so. Drop Erlang in in place of SALSA, a Scheme or a Lisp and/or Haskell in place of Oz, keep Prolog; this would help make the class a lot more real-world useful (I can't believe I'm putting Lisp, Erlang, and Haskell in a sentence about real-world usefulness...) without sacrificing (at all) the various lessons about language design and use (except the ones about how things should not be done, in the last few weeks). The other problems (the real ones)... I'll leave for people who take the class to discover on their own!
Intermediate Video was awesome. Well... there was a lot of strange contained within the videos we watched in class, but I suppose that comes with the territory! The awesome part was two things: a) getting to spend time working on video again (I bought FCS a few years back and have been upgrading it every once in a while since then; I don't get to use it very often these days, though), and b) the class. It was a tiny class; there were only nine of us! The nice part about it was that everybody got along; they made someone who didn't belong (me) feel like he fit right in, even if he sometimes took issue with being asked to find meaning in things which clearly didn't have any (I'm cool with art-for-art's sake, but leave it there, and don't try to make that sort of art have meaning!). And I had a lot of fun with the three projects during the course of the semester.
Quasars and Cosmology doesn't even count. One credit, no work (literally). Sit down for an hour once a week and look at pretty pictures of space. Awesome!
Machine Learning was really tough. It's yet another case of me distinctly lacking math experience (multivar and linear algebra, mostly, in this case, but there was also the fact that most of the calc I've studied has (yay!) rotted out of my brain). It sounds like it's going to have quite the curve, too, which is good! There was a lot of cool stuff in this class; it's the only CS course this semester where you could see something you were writing really work. I now know (and have implemented) a dozen different ways to classify digits from the USPS zipcode database — that's always fun! It was nice to not have any tests to speak of, but the homeworks were killer, and a very large chunk of the book (which is currently being co-written by the professor) never ended up getting posted to the website.
On the slate for next semester: Introductory Biology (YUCK, but that finishes my science requirement), Typography (I love being a fake EMAC), Parallel Programming, Advanced Computer Graphics (Cutler again!), and Intro to Economics (I need to take a bunch of humanities stuff, I figure ECON will go better than PSYC or PHIL).