Simulator Ruby Gem

Intro

I’ve been working on this off and on for awhile. Simulator is a Ruby gem which provides functionality for creating discrete time models, and running those models. You can find the Homepage for the Simulator gem on Github.

Take the following two examples included with the gem.

Ball Drop

Let’s say we want to model a ball that is dropped. Assuming I’m not modeling any bounces, I just need to show the affect of acceleration due to gravity on the position of the ball in space. Position is a function of velocity, which is a function of acceleration. We can model this system using the gem thusly.

# We create a model that simulates a ball drop
model = Simulator::Model.new do
  name = "Ball drop model"
  # create a couple static variables to represent acceleration with
  # default values
  var :ax, 0
  var :ay, - 9.8

  # create dynamic variables bound to some computation, with default
  # values.

  # velocity is affected by acceleration
  eqtn(:vx, 20) { vx + ax }
  eqtn(:vy, 50) { vy + ay }

  # position is affected by velocity
  eqtn(:x, 10) { x + vx }
  eqtn(:y, 100) { y + vy }
end

There is a simple DSL provided that makes creating the models easier. Hopefully it’s easy enough to follow. We initialize two static variables, ax and ay, which are set to 0 and -9.8, respectively (acceleration due to gravity is equal to -9.8m/s^2.)

Next, we create two “equations”. These are just dynamic variables, variables that depend on the values of other variables, or on some sort of computation. Note that we just pass regular ruby blocks to the eqtn method. These could really perform any ruby code. The result of the block gets stored in the variable given as a symbol. So, we state that the variable vy is dependent on a the addition of vy + ay. vy + ay will be the sum of the values vy and ay from the previous period. We do the same for vx.

Finally, the position of the ball, the coordinates x and y, depend on the velocity. We also set the default initial position of (10, 100).

Next, we create a “run” of the model, and step it 10 periods. This would be the equivalent of 10 seconds (because of what we set acceleration to).

model_run = model.new_run
model_run.step 10

Note that although we do not do so here, we could alter the values of run variables in each period, like so:

model_run.set ax: 5
model_run.step

This would give the ball an acceleration in the x direction, and this value would be propagated through subsequent periods (because the variable is static).

Once we have stepped the run, we can request the series data in case we want to plot it. We can retrieve and plot the data like so:

xs, ys = model_run.data.series :x, :y

require 'chunky_png'
image = ChunkyPNG::Image.new @width, @height,
  ChunkyPNG::Color::BLACK
pts.each do |pt|
  x, y = pt
  # flip y due to inverted coordinate system
  y = @height - y
  image.circle x, y, 3, ChunkyPNG::Color('red')
end
image.save filename

and we’d get something like this:
drop

Mortgages

A mortgage involves a balance, loan payment, and interest rate. Let’s create a model for that.

model = Model.new do
  name = "Mortgage model"

  # monthly steps
  var :base_rate, 0.08
  eqtn(:annual_rate) { base_rate }
  eqtn(:monthly_rate) { annual_rate / 12.0 }
  var :payment, 2000
  eqtn :balance, 250000 do
    balance * (1 + monthly_rate) - payment
  end
end

We want the period to be monthly instead of annually, so note the monthly_rate variable above. We also have various default values we will override in a bit. Let’s look at 3 types of mortgages, fixed, balloon, and variable. Fixed rate mortgages have a constant interest rate locked over a defined term (such as 30 years). Let’s see what happens to the balance at the end of 30 years for each of these loan types. A balloon loan has a lower monthly payment, but a large payment at the end of the term. A variable loan has a term where the interest rate is indexed to a published interest rate, and then a period where the rate is fixed. Below, we simplify things by assuming that we will just pay different amounts for each of the terms.

fixed = @model.new_run
fixed.set payment: 2100
fixed.step 30*12

# balloon
balloon = @model.new_run
balloon.set payment: 1850
balloon.step 30*12

variable = @model.new_run
# first 10 years, stick with low payment
variable.set payment: 1800
variable.step 10*12

# subsequent years, balloon to higher payment until its paid
variable.set payment: 2100
variable.step 20*12

And then we can get the series data and plot it similarly to before. It results in an image like the one below.

  • Fixed = yellow
  • Variable = blue
  • Balloon = red

mortgage

You can find the Homepage for the Simulator gem on Github and find the gem on RubyGems.

Generating offline maps for iOS applications

Introduction

Recently, I had to implement an offline mapping solution for an iOS application. Here’s a walkthrough of how to do it.

Summary

I generated a tile database using TileMill. I used the Route-Me iOS library which provides a map view that supports offline tile sources.

TileMill

Actually, generation of the tile database was the more time consuming part of the task, especially since I had not worked with maps before. Here’s a run down of what it took. TileMill will help you style maps.

Getting started, I installed the application and tried to use built-in features to style the map. I quickly realized I would need to import some data sources to get the map I wanted.

After more research, I found this project called OSM Bright by the company that produces TileMill, MapBox. I used the OSM Bright Mac OS X Quickstart to set everything up. The script that follows runs through most of the steps required in the Quickstart.

Database setup

Install GDAL complete, which is a prereq.

wget http://www.kyngchaos.com/files/software/frameworks/GDAL_Complete-1.9.dmg
hdiutil attach GDAL_Complete-1.9.dmg
open "/Volumes/GDAL Complete/GDAL Complete.pkg"
# Complete installation manually

Now, we’ll setup Postgres and the PostGIS extension.

    brew install postgresql
    # libpng is a dependency of gdal, which is a dependency of postgis
    brew install libpng && brew link -f libpng
    brew install postgis
    # initialize database
    initdb /usr/local/var/postgres -E utf8
    createdb `whoami` # creates a db for your username. For some reason initdb didn't do this for me and I was getting login issues without this existing.
    # make sure `which psql` = /usr/local/bin/psql
    pg_ctl -D /usr/local/var/postgres -l /usr/local/var/postgres/server.log start
    psql -c "create database osm;"
    psql -d osm -c "create extension postgis;"

osm2pgsql Tool setup

Now, we’ll setup the osm2pgsql tool which is used to load Open Street Map data into a Postgres database.

    # although there is a homebrew formula available, it did not seem to work on Mountain Lion
    # brew install --HEAD osm2pgsql
    wget http://dbsgeo.com/downloads/osm2pgsql/snow/intel/r26782.dmg
    hdiutil attach r26782.dmg
    open /Volumes/osm2pgsql-r26782M/osm2pgsql-r26782M.pkg
    # Go through the installation instructions

OSM data

We’re done setting up our database that will store Open Street Map data. Now, let’s download the data we’ll need. It’s OSM data for the Philadelpha Metro area in PBF format.

    # download relevant data from http://metro.teczno.com/#philadelphia
    wget http://osm-metro-extracts.s3.amazonaws.com/philadelphia.osm.pbf

And then we import it into the database.

    osm2pgsql -c -G -d osm -S /usr/local/share/osm2pgsql/default.style philadelphia.osm.pbf

Creating the TileMill project

Now, we can use the OSM Bright project to create a new TileMill project.

    git clone git://github.com/mapbox/osm-bright.git
    cd osm-bright
    vim configure.py # edit and add your postgres settings
    ./make.py

This will create a new project in your TileMill projects directory, which is probably ~/Documents/MapBox/project/. The directory name will be whatever was specified in configure.py.

Exporting mbtiles from TileMill

Open TileMill and select your project. If you didn’t change the name in configure.py, it will be called OSM Bright.

  • Edit the Project Settings by clicking the wrench icon at the top right. Zoom in on Philadelphia and change the Center location and Bounds using the interface.
  • Click save.
  • Click the Export Menu and select MBTiles. Select a zoom range. The higher the range you use, the larger your database will be. I though ranges between 13 and 18 worked best for my purposes. Save the mbtiles file with a name like Philadelphia.mbtiles.
  • The export will be queued and put in ~/Documents/MapBox/export/ when complete.

XCode Development

Project setup

Once you have created a new iOS application, we will setup the Route-Me MapView as a subproject. Below, the Header Search Paths and Link Binaries are the most important steps.

  • Clone the Route-Me repo into a vendor directory inside your project. (This is the convention I used, and I’m not sure if it is the best) git clone https://github.com/route-me/route-me vendor/route-me
  • Add the vendor/route-me/MapView/MapView.xcodeproj into your project.
  • In your Project Settings, click the application target > Build Settings > Enter “Header” into the Search Box, and add vendor/route-me/MapView/Map to the **Header Search Paths* key
  • Build Settings > Under Other Linker Flags > Add -all_load -ObjC
  • Go to Build Phases > Target Dependencies > Click +, Choose MapView > MapView
  • Go to Build Phases > Link Binaries > For each of the following libraries, Click +, select the binary, and then click the Add button.
    • libMapView.a
    • libsqlite3.dylib
    • CoreLocation.framework
    • QuartzCore.framework
  • Add the Philadelphia.mbtiles file you created before to the project.

Development

Go to your storyboard or nib and add a subview to your primary view. Give it the class RMMapView. Add outlets to your UIViewController for this map view. Make sure to wire the outlets up in Interface Builder as well.

    // In your header file
    #import <UIKit/UIKit.h>
    @class RMMapView;

    @interface MyViewController : UIViewController  {
        IBOutlet RMMapView *mapView;
    }

    @property (nonatomic, strong) IBOutlet RMMapView *mapView;
    @end
    // In your implementation file

    #import "RMMapView.h"

    // ...

    @implementation MyViewController
    @synthesize mapView;

    // ...

Set the map’s center point, default zoom level, and min and max zoom. The min zoom should match the one you specified when you exported the `mbtiles` file from TileMill.

    // In your implementation file
    - (void)viewDidLoad {
       // ...
       mapView.contents.minZoom = 15.f;
       mapView.contents.maxZoom = 17.f;
       mapView.contents.zoom = 16.5;
       [mapView.contents moveToLatLong: CLLocationCoordinate2DMake(39.949721,-75.150261)];
       // ...
    }

Run the app and you should see everything load. The map is loading live from http://openstreetmaps.org.

Set the tile source to use an offline source instead.

    // In your implementation file

    #import "RMMBTilesTileSource.h" // Add this header

    - (void)viewDidLoad {
       // ...

       mapView.contents.minZoom = 15.f;
       mapView.contents.maxZoom = 17.f;
       mapView.contents.zoom = 16.5;

       // the tile source *MUST* be set after min and max zoom
       NSURL *tileSetURL = [[NSBundle mainBundle]
           URLForResource:@"Philadelphia.mbtiles"
           withExtension:@"mbtiles"];
       mapView.contents.tileSource = [[RMMBTilesTileSource alloc] initWithTileSetURL: tileSetURL];

       [mapView.contents moveToLatLong: CLLocationCoordinate2DMake(39.949721,-75.150261)];
       // ...
    }

Conclusion

There you have it! You should have a map view displaying an offline-accessible view of Philadelphia. Route-Me is a great library which allows you to do other things like add paths and markers. If you had problems with any part of this, please let me know. An example project is provided at Github. It uses a tile database I generated myself using the instructions above.

Corona SDK Error: CGImageDestinationFinalize image destination does not have enough images

I am hacking around with Corona SDK. I got the following error when switching scenes to one that already existed. (I was implementing a “Go Back” button.)

Corona Simulator[5653] <Error>: CGImageCreate: invalid image size: 0 x 0.
Corona Simulator[5653] <Error>: CGContextDrawImage: invalid context 0x0
Corona Simulator[5653] <Error>: CGBitmapContextCreateImage: invalid context 0x0
ImageIO: <ERROR>  CGImageDestinationAddImage image parameter is nil
ImageIO: <ERROR>  CGImageDestinationFinalize image destination does not have enough images

The symptom was that a button from a previous scene wasn’t removed from the scene when I called storyboard.gotoScene. The problem was that I wasn’t adding the button to the scene view display object as a child. This particular error was hidden from me because it seems you do not need to call scene.view:insert(button) in order for the button to appear.

I had code that created a button using Corona’s Widget API with code like the following:

  local gameBtn = widget.newButton{
    label=label,
    labelColor = { default={255}, over={128} },
    default="button.png",
    over="button-over.png",
    width=300, height=80,
    fontSize=30,
    onRelease = onRelease -- event listener function
  }

A screencast of the bug behavior is shown as follows:

Cocos2d iOS Game: Balloon Burst

My employer gives us a week off for the holidays, so I’d been trying to decide what to do with all of the time. Although I originally didn’t want to work on any programming projects, I wound up working on a few. One of them was inspired by a play of the iOS game Train Yard. I was paying particular attention to the loading screen when I noticed it had been created using Cocos2d. I’d seen articles about the engine before, so I decided to take another look at the Website. I was curious about what other game engines were in popular use. Besides Unity, I didn’t notice any that were more popular than Cocos2d. I decided to investigate further and found a tutorial on the site.

Before I knew it, I was working through the tutorial. The API was simple, straight-forward, and intuitive, and I was soon done. Still, I wanted to use it for my own project. Unfortunately, the holidays were winding down, and Spring term classes will start soon, so time is very limited.

As a prepubescent child, I played a shareware game where balloons would rise on the screen. You’d use your mouse to draw a bowstring, flying an arrow horizontally through the balloon field, timing the ascent of a balloon. It’s this game that immediately came to mind when I tried to think of simple games. The satisfaction of that balloon popping noise made me long to play. (A satisfaction only outpaced by the sound of popping bubble-wrap.)

So, I decided to work on a game like that other game, and started on making balloons float up. I went to http://openclipart.org and found a great balloon-popping sound at http://soundbible.com. I started out by using CCActions, a CCSequence composed of CCMoveUp and CCCallFuncND to perform cleanup. The balloons would randomly spawn at a certain interval below the screen, and rise to a height above the screen, out of the viewport, and be removed from the layer.

Somewhere along the line, I decided that an bow and arrow would be unnecessary, and that touching a balloon would be enough to pop it. At the same time, I’d target the game at children. I implemented procedures to detect a balloon touch, show a particle effect upon touch, play the popping noise, and remove the balloon from the layer immediately.

Play-testing confirmed this mechanic was a little boring in of itself. I figured that popping balloons should release things stored inside, so you should be able to earn points for popping balloons and touching a “treasure item” dropped from the balloon, things like: diamonds, coins, and treasure boxes. I also added clouds in the background, a timer, and score display, the concept of rounds, and a game over state.

I got this working, but it didn’t seem especially targeted towards children. Lisa, my wife, tried it and confirmed as much. We talked about marking each balloon with a letter, and using the balloons to spell words or elsewise learn about words.

After thinking for a bit, I decided that balloons marked with a letter would release a word starting with that letter. When you touched the word dropped by a balloon, that word would be spoken aloud. I downloaded Audacity, and had Lisa recite a list of words. I spliced them and loaded them into my project Resources folder. Once I got the code working, so that the word sound would play when the word was touched, the audio seemed to low, like it had not been normalized. Even after reducing the volume of the background music and popping sound, the words weren’t loud enough. We’ll have to redo the word sounds at some point.

At this point, I’m mostly done, but may add some more graphics and clean up the code. This project has been a great introduction to Cocos2D and Objective-C programming, in general.

Check out game footage below and the complete source code, including assets, on Github: http://github.com/jamiely/ios-balloon-burst

OSX Lion Rubygame Install

I tried setting up Rubygame on Snow Leopard this time last year. I had many difficulties setting up SDL. I had some time to kill so I tried to set it up again, this time on my new MacBook Air running Lion.

This old blog post from 2005 helped me this time around: http://inquirylabs.com/blog2005/?p=21 to nail down the requirements. Instead of following the installation instructions here, I used Homebrew to set things up.

One of the key requirements is rubysdl, ruby bindings for the SDL multimedia library, and the rsdl gem. The following Gist is a rubysdl Homebrew formula that will help install the required packages: https://gist.github.com/1394440. The SGE formula is not part of the included formulas. I forked the following Gist to provide SGE: https://gist.github.com/1394414/.


# install the sge graphics lib
wget https://gist.github.com/raw/1394414/4a6bfa4a8bab179ebe263b1d044a4322c7628f60/sge.rb
brew install sge

# install rubysdl ruby sdl bindings
wget https://raw.github.com/gist/1394440/8a71160306ad277f08fbad3eaf028b2e8700f2f1/rubysdl.rb
brew install rubysdl

# install the required gem
gem install rsdl
gem install rubygame

Afterwards, most of the rubygame samples ran fine, but the ones requiring opengl had issues. I installed ruby 1.9.2 using rbenv, compiled a new dynamic library libruby.dylib, based on the 1.9.2 source. Then, I cloned this repo providing an upgraded ruby-opengl gem: https://github.com/theymaybecoders/ruby-opengl.

# clone the repo
git clone https://github.com/theymaybecoders/ruby-opengl
cd ruby-opengl

# make sure that the libruby.1.9.1.dylib compiled from the 
# ruby 1.9.2 source is present in the gcc class path. For 
# me, it was ~/.rbenv/versions/1.9.2-p290/lib/libruby.dylib
# use build option --enable-shared

rake

# build the gem
rake gem

# install the gem
gem install pkg/ruby-opengl-0.60.1.gem

Afterwards, the rubygame opengl samples compiled fine.

Dominos-Style Game

My wife loves PopCap’s game Alchemy. It’s a dominoes-like game, where you match up alchemic symbols and various colors. The object of the game is to turn each board-square from lead to gold. I have been wanting to try out the limejs game library, which is based on Google’s Closure compiler, so I decided to write a quick implementation of the game. You can find the source on Github.

You can try out the game online. To play, place pieces adjacent to other pieces which match in symbol or color. A placed piece must match all the pieces adjacent to it. A wild card piece, denoted with the ‘*’ symbol, matches all pieces. Filling a row or column with pieces will mark the corresponding spaces as cleared. The object of the game is to get each space marked as cleared.

Edit (20100214 11:00 PM): Added win condition and box showing how many spaces cleared.
Edit (20100215 11:00 PM): Added leveling. The board starts small with few pieces and keeps getting bigger with each round.

Mobile JS Framework Comparison

I did a quick matrix to compare various mobile JS frameworks in late May. It is probably a little outdated, especially with the recent Sencha merger, and I did not know DashCode could create web applications at the time, but maybe it will help someone. Enjoy! http://bit.ly/d6Gsaj

Scifihifi-iPhone Keychain Wrapper

Here’s a great wrapper that really simplifies working with KeyChain in iOS http://log.scifihifi.com/post/55837387/simple-iphone-keychain-code. The code is on GitHub as well http://github.com/ldandersen/scifihifi-iphone/tree/master/security/.

Apple’s official documentation is here, and there is also a sample project, but it’s not a good example for getting up and running quickly. The version of the project (last updated 10/2009) doesn’t even run on the simulator.

Mediawiki-Usage/Changes Storage and Visualizations

A coworker and I have been doing some work on visualizations of wiki updates. The server-side code, written in Ruby, stores changes from a media-wiki feed.

Media-wiki Changes Feed

Media-wiki Changes Feed

I got a chance to use the Google Visualization API, which is really simple and useful for a wide variety of domains.

He also turned me on to HAML, which offers a concise, structured way of specifying HTML.

Project Page: http://github.com/hectcastro/mediawiki-usage/
Demo: http://www.angelforge.org/mediawiki-usage/

Media-wiki Changes Visualization

Media-wiki Changes Visualization

Graphiz Problem!

I was working on the Drupal OrgChart module tonight, specifically the rendering of the chart image via GraphViz, and I got stuck for at least an hour on a trifle! I planned to use the PEAR library for GraphViz (Image_GraphViz) and I wrote a function using the class it provides. I run the procedure and get weird errors about not being able to find files and such. After debugging for awhile, I find out that there is a property binPath that is not present. I had expected this to point to my install of GraphViz, which I knew to be especially important because it was in a weird macports directory.

It turns out that I had not installed the version I needed! I didn’t realize the version I wanted was beta, and to download a beta package, you need to explicitly state so in the PEAR command.

sudo pear install Image_GraphViz-beta
#instead of
sudo pear install Image_GraphViz

After downloading the most recent package, it turned out my code worked almost perfectly. What a waste of a night!

The past few days, I also worked on a few other modifications. I removed the requirement for a “subordinate_id” field. Also, I made the profile field names options in the administrative settings page.

The project page is here: http://code.google.com/p/drupal-orgchart/.