Cogs and Levers A blog full of technical stuff

Scanline based filled Polygons

Introduction<

In a previous post I laid down some foundation code to get access to the pixel buffer when in context of a HTML canvas. Good for those who have experience writing graphics code directly against the video buffer - it almost feels like you’re writing to 0xA000 :-)<

Today’s post will focus on drawing polygons to the screen using scan lines.

Scan lines

The whole idea here is that a polygon can be represented on screen as a series of horizontal lines. Take the following picture for example. You can see the red and blue horizontal lines making up the filling of the polygon.

Scanlines

So, to define this all we do is take note of the minimum and maximum x values for every y-axis instance that there is a line on. We run through the array of values drawing horizontal lines at each instance, and then we have a polygon on screen - pretty easy.

Code

First of all, we’ll define our drawing primitive for a horizontal line.

var hline_c = function(x1, x2, y, w, r, g, b, a, buffer) {
   // calculate the offset into the buffer
   var ofs = (x1 + y * w) * 4;

   // draw all of the pixels
   for (var x = x1; x <= x2; x ++) {
      buffer[ofs] = r;
      buffer[ofs + 1] = g;
      buffer[ofs + 2] = b;
      buffer[ofs + 3] = a;

      // move onto the next pixel
      ofs += 4;
   }

};

We pass in the two x (x1 and x2) values for the line to go between, the y value for the line to sit on. To help with the offset calculation we also pass in the width w to correctly calculate the pitch. Finally the colour components and buffer to draw to are passed in. Setting this code up in a run loop, you end up with something like this:

Poly

Yep, there’s lots of horizontal lines. Referring to our horizontal line diagram above, we still need a way to walk the edges of the polygon so that we can get the minimum and maximum x values to start drawing. Because our basic unit is the pixel (considering we’re rasterising to a pixelated display), we can easily calculate the gradient of the line that we need by:

(change in x) / (change in y)

For a line given by (x1, y1) - (x2, y2), this translates into:
(x2 - x1) / (y2 - y1)

Taken out of context of maths, this just says to us: we want to walk from x1 to x2 using (y2 - y1) steps.

var scanline_c = function(x1, y1, x2, y2, miny, edges) {

   // flip the values if need be
   if (y1 > y2) {
      var y = y1;
      y1 = y2;
      y2 = y;

      var x = x1;
      x1 = x2;
      x2 = x;
   }

   // start at the start
   var x = x1;
   // change in x over change in y will give us the gradient
   var dx = (x2 - x1) / (y2 - y1);
   // the offset the start writing at (into the array)
   var ofs = y1 - miny;

   // cover all y co-ordinates in the line
   for (var y = y1; y <= y2; y ++) {
     
      // check if we've gone over/under the max/min
      if (edges[ofs].minx > x) edges[ofs].minx = x;
      if (edges[ofs].maxx < x) edges[ofs].maxx = x;

      // move along the gradient
      x += dx;
      // move along the buffer
      ofs ++;

   }

};

From the code above, we treat x1, y1 as the starting point and x2, y2 as the ending point. Our for-loop is biased in the positive direction, so it’s important for us to flip the values if they come in inverted. The edges array that’s passed in is prepared by the caller of this function. It’s initialized with very unreasonable minimum and maximum values. We than run over all 4 polygon edges

(x1, y1) -> (x2, y2)
(x2, y2) -> (x3, y3)
(x3, y3) -> (x4, y4)
(x4, y4) -> (x1, y1)

At the end of this process, edges is full of minimum/maximum values ready for drawing. Here’s the code for the polygon.

var polygon_c = function(x1, y1, x2, y2, x3, y3, x4, y4, w, r, g, b, a, buffer) {
   // work out the minimum and maximum y values
   var miny = y1, maxy = y1;

   if (y2 > maxy) maxy = y2;
   if (y2 < miny) miny = y2;
   if (y3 > maxy) maxy = y3;
   if (y3 < miny) miny = y3;
   if (y4 > maxy) maxy = y4;
   if (y4 < miny) miny = y4;

   // the height will determine the size of our edges array
   var h = maxy - miny;
   var edges = new Array();

   // build the array with unreasonable limits
   for (var i = 0; i <= h; i ++) {
      edges.push({
         minx:  1000000,
         maxx: -1000000
      });
   }

   // process each line in the polygon
   scanline_c(x1, y1, x2, y2, miny, edges);
   scanline_c(x2, y2, x3, y3, miny, edges);
   scanline_c(x3, y3, x4, y4, miny, edges);
   scanline_c(x4, y4, x1, y1, miny, edges);

   // draw each horizontal line
   for (var i = 0; i < edges.length; i ++) {
      hline_c(
         Math.floor(edges[i].minx),
         Math.floor(edges[i].maxx),
         Math.floor(i + miny),
         w, r, g, b, a, buffer);
   }
};

This really is just putting all the pieces together. The building of the edges array is important - as is using the y co-ordinate (adjusted back to zero by proxy of the minimum y value) as an array index. Once you’ve got this setup in a random position & colour loop, you’ll end up with something like this:

Polys

mmmm… Tasty.

Purging all of the data within Solr

During the test phases of getting your software setup, you’ll find it useful to completely toast what ever data you’ve already indexed to start fresh. This is as simple as issuing a delete query with open criteria *.*. The full query should translate to

<delete><query>*.*</query></delete>

As a URL it’ll look like this:

http://[your solr server]:8080/solr/update?stream.body=%3Cdelete%3E%3Cquery%3E*:*%3C/query%3E%3C/delete%3E&commit=true

Note that there is a commit at the end of this URL which will perform the delete and commit the result all in the one invocation.

Pixel Access to the Canvas with Javascript

Introduction

Gaining pixel-level access using the HTML canvas opens up some possibilities for some frame-buffer style rasterisation. Today’s post will focus on the code required to get you access to this array. Here’s the code on how to get started:

// create the canvas object
var canvas = document.createElement("canvas");

// maximise the canvas to stretch over the window
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

// get the 2d drawing context for 
var cxt = canvas.getContext("2d");
// get the image data
var imageData = cxt.createImageData(width, height);

// save off the dimensions for later use
var width = canvas.width;
var height = canvas.height;

// get the canvas on the page
document.body.appendChild(canvas);

First of all, we programmatically create our canvas object using document.createElement. Using the inner dimensions of the window, we can then set the canvas’ size. Of course this can be custom set to the dimensions you require - I just like to take over the whole window! Using the canvas object, we then pull out the drawing context with getContext. The next part, using createImageData we then get a reference to the frame-buffer to draw to. This gives us read/write access to the canvas through an array. Finally, we’ll take note of the width and height (this will come in handy later) and then pop the canvas onto the page.

Frame-buffer structure

So, I say “frame-buffer” - but it’s just an array. It’s quite nicely laid out such that pixels start at every 4 elements within the array. The first element being the red component, second is green, third is blue and the fourth is the alpha. Calculating an offset into the array is a piece of cake. For example, take the following piece of code which will allow you to set a single pixel on the frame-buffer.

var setPixel = function(x, y, r, g, b, a, buffer) {
  // calculate the start of the pixel
  var offset = ((y * width) + x) * 4;
  
  // set the components
  buffer[offset] = r;
  buffer[offset] = g;
  buffer[offset] = b;
  buffer[offset] = a;
};

The main part to focus on here is the calculation of the offset. Above, I said it was important to take note of the dimensions - we’re only using the width here. This is pretty straight forward calculation of an offset within a linear data segment with Cartesian co-ordinates.

Flip out!

Now that we’ve drawn all of the data to the image buffer (frame-buffer), we need a way to get it back onto our canvas. This is simply done using putImageData.

cxt.putImageData(imageData, 0, 0);

That’s it for now.

mpt-statusd detected non-optimal RAID status

After installing Debian within a few VMWare virtual machines, I keep getting a rather annoying and persistent message spamming out my unix mail box as well as /var/log/messages.

mpt-statusd: detected non-optimal RAID status

Simplest solution that I’ve come across is to just . . .

$ sudo apt-get remove mpt-status

Yup! That’s it.

Complementing MongoDB with Full Text Search from Solr

Introduction

MongoDB is a great database, but one area that I’ve noticed it’s been deficient in is full text search. Thankfully, there are some great tools around that we can employ to compliment Mongo and give it this functionality. Today’s post will be a walk through to getting Solr & mongo-connector installed and configured on Debian Wheezy.

Get the software

First up, install Solr on tomcat with the tomcat administration tools

$ sudo apt-get install solr-tomcat tomcat6-admin

Straight after this has installed, you’ll need to configure a user to access these applications. Use your favorite text editor and open /etc/tomcat6/tomcat-users.xml. This file (like all of the configuration files) is really well commented. The steps I took here were:

  • Added a “role” node for “manager-gui”
  • Added “manager-gui” as a role to the “tomcat” user

In the end, you should have something sort-of like this:

<role rolename="tomcat"/>
<role rolename="manager-gui"/>
<user username="tomcat" password="tomcat" roles="tomcat,manager-gui"/>

Now that you’ve finished configuring all of the user access, restart tomcat.

$ sudo service tomcat restart

You can now check that tomcat is up and running by pointing your web browser at http://localhost:8080/. When you click on the manager-app link, you’ll be prompted for a username and password. As defined by the user configuration above, the username is “tomcat” and the password is “tomcat”. Have a click around, you should also see Solr installed in there also.

Solr Schema

Now it’s time we tell Solr exactly what we want to index. Remember, it’s going to be a client to our mongo database - so any interesting fields that you want indexed will need to be mentioned here. Solr’s schema file is found at /etc/solr/conf/schema.xml. Everyone’s requirements are way to broad for me to go into depth here on what to do, but it would be a good time to look up the documentation and learn about how you want your data attributed: http://wiki.apache.org/solr/SchemaXml.

Connecting to Mongo

Next, we’re going to connect Solr to mongo using mongo-connect. There’s some more software that’s needed to be installed here. mongo-connect is a python package that listens to mongo’s oplog for “interesting” things, and then stores them away into Solr for fast searching later. We will need pip, some xml dependencies that mongo-connect relies on - then we can install the connector.

 
$ sudo apt-get install python-dev python-pip
$ sudo apt-get install libxml2 libxml2-dev libxslt-dev
$ sudo pip install lxml cssselect
$ sudo pip install mongo-connector

Running the connector

Now that you’re all installed, it’s time to start indexing some data. Again, everyone’s requirements are going to be quite different - so it’s a good time to go out and take a look at the mongo-connector github page to understand the full usage of the command. A typical execution of the command would look like this:

$ mongo-connector -m localhost:27217 -t http://localhost:8080/solr -o oplog_progress.txt -n alpha.foo,test.test -u _id -k auth.txt -a admin -d ./doc_managers/solr_doc_manager.py

From here, mongo-connector listens to changes and stores them away in Solr so that your full text search facility has them available.

That’s it for Solr & MongoDB.