Actually, instead of drawing a hex, creating an array of points is more useful, especially when it comes time to creating the border. The hex, when you look at it, really only has a small number of important numbers that need to be calculated. Figure 1 shows the special points that are needed to create the hex and listing 1 shows the function used for creating the array of points.
figure 1 |
function buildHexPath(rect, pathlist)
{
var path = pathlist;
// make sure path list of points contains proper number of points
if (path == null)
path = new Array();
while (path.length < 7)
path.push(new BGLayers.Point());
while (path.length > 7)
path.pop();
var halfx = rect.x + rect.width / 2;
var x2 = rect.x + rect.width;
var y1a = rect.y + rect.height / 4;
var y1b = rect.y + 3 * rect.height / 4;
var y2 = rect.y + rect.height;
path[0].x = rect.x;
path[0].y = y1a;
path[1].x = halfx;
path[1].y = rect.y;
path[2].x = x2;
path[2].y = y1a;
path[3].x = x2;
path[3].y = y1b;
path[4].x = halfx;
path[4].y = y2;
path[5].x = rect.x;
path[5].y = y1b;
path[6].x = rect.x;
path[6].y = y1a;
return path;
}
The hex can now be drawn, but to create a border we need a pair of hexes. My first attempt to create a border hex was to create an inner hex and an outer hex and join the two together. This did not work as expected. If you look at figure 2, the first hex is the normal hex. The second hex is suppose to be the border. My immediate reaction was that the fill method didn’t support complex polygons. This isn’t that surprising of a limitation so I quickly wrote my plan B implementation.
figure 2 |
The third hex in this figure was created by drawing each segment of the hex separately. This was done in a similar way to the first attempt at creating a border. A outer hex and an inner hex are created and then the points are looped through and combined to create six separate polygons.
function drawHexBorder(ctx, rect, pct)
{
var outpath = buildHexPath(rect, null);
var wadj = rect.width * pct;
var hadj = rect.height * pct;
var inpath = buildHexPath(new BGLayers.Rectangle(rect.x+wadj, rect.y+hadj, rect.width - wadj-wadj, rect.height - hadj-hadj),null);
for(var cntr = 0; cntr < 6; ++cntr) {
ctx.beginPath();
ctx.moveTo(outpath[cntr].x,outpath[cntr].y);
ctx.lineTo(outpath[cntr+1].x,outpath[cntr+1].y);
ctx.lineTo(inpath[cntr+1].x,inpath[cntr+1].y);
ctx.lineTo(inpath[cntr].x,inpath[cntr].y);
ctx.lineTo(outpath[cntr].x,outpath[cntr].y);
ctx.closePath();
ctx.fill();
}
}
Once this was done I decided to spend a little bit of time researching how the cavas fill was suppose to work as I was positive that I had seen some drawings that had holes in it. After a few minutes of research (about the same amount of time it took me to write plan-b) I finally stumbled upon the winding rule for filling. It appears that the direction of the edge lines are used as part of determining of the points that are filled. While I have played with a number of fill algorithms, I have never actually implemented a winding algorithm but it does mean that by reversing the order of the points in the inner hexagon, the fill should work properly. This would allow the drawing of the border as a single drawing operation which should be more efficient.
No comments:
Post a Comment