Re: looking for a hexagon tiling module

Discussion in 'Perl Misc' started by Peter J. Holzer, Apr 7, 2012.

  1. ["Followup-To:" header set to comp.lang.perl.misc.]
    On 2012-04-06 18:37, Eli the Bearded <*@eli.users.panix.com> wrote:
    > I'd like a module to manipulate co-ordinates on an X,Y plane that
    > have an overlapping hexagon grid. Consider, for example, a game
    > that uses a hexagonal grid to move around. Chinese Checkers (star
    > halma) is one such game. You would want functions to turn a mouse
    > click into a hexagon tile id of some sort, and you'd want functions
    > to calculate how to draw the tiles if the side is S pixels, or
    > if you want to fit N tiles across on a M wide field.
    >
    > I don't want to implement a game, I do want to be able to divide a
    > pixel plane into hexagons, calculate which pixels would be interior,
    > which pixels would be a border, know which hexagons are complete
    > and which are clipped. I don't want something that is tied to a
    > particular drawing system, because it probably won't be the one I
    > want to use.

    [...]
    > As an example, here's this bit of ASCII art I must have spent
    > all of five minutes on. The hexagonal tiles are numbered with
    > example coordinates. There is a image area superimposed upon
    > this grid with a border of : + and =. The upper left hand corner
    > is about one quarter of the 0,0 hex grid. Cell 1,2 is the upper-
    > most, leftmost full hexagon, cell 1,1 is the leftmost, upper-
    > most full hexagon. 12 characters right and 16 down from the +
    > in the image corner is the * in cell 3,2. 18 characters right
    > and 5 down from the + is the L on the border of 0,3 and 1,3.
    >
    > ___ ___ ___ ___
    > / \ / \ / \ / \
    > / \ / \ / \ / \
    > / 0,0 \___/ 0,2 \___/ 0,4 \___/ 0,6 \_
    > \ +===/===\=======/===\=======/===\=======/=
    > \ : / \ / \ / \ /
    > \_:_/ 0,1 \___/ 0,3 \___/ 0,5 \___/
    > / : \ / \ / \ / \
    > / : \ / \ / \ / \
    > / 1,0 \___/ 1,2 \_L_/ 1,4 \___/ 1,6 \_
    > \ : / \ / \ / \ /
    > \ : / \ / \ / \ /
    > \_:_/ 1,1 \___/ 1,3 \___/ 1,5 \___/
    > / : \ / \ / \ / \
    > / : \ / \ / \ / \
    > / 2,0 \___/ 2,2 \___/ 2,4 \___/ 2,6 \_
    > \ : / \ / \ / \ /
    > \ : / \ / \ / \ /
    > \_:_/ 2,1 \___/ 2,3 \___/ 2,5 \___/
    > / : \ / \ / \ / \
    > / : \ / * \ / \ / \
    > / 3,0 \___/ 3,2 \___/ 3,4 \___/ 2,6 \_
    > \ : / \ / \ / \ /
    > \ : / \ / \ / \ /
    > \_:_/ 3,1 \___/ 3,3 \___/ 3,5 \___/
    > / : \ / \ / \ / \
    >


    I took that as a challenge for a bit of weekend programming ;-)

    It doesn't do everything you want (must leave some of the fun to you)
    but it should get you started:


    package Math::HexGrid;

    use warnings;
    use strict;
    use 5.010;
    use POSIX qw(floor);

    our $VERSION = 0.001;

    sub new {
    my ($class, $s, $h) = @_;

    # $s is the length of a side of a cell,
    # $h is the height of half a cell.
    # we can compute that from $s or let the user specify it.
    $h = int($s * sqrt(3) / 2) unless defined $h;
    my $self = { s => $s, h => $h };
    bless $self, $class;
    return $self;
    }

    sub center_of_hex {
    my ($self, $ind_x, $ind_y) = @_;

    my ($s, $h) = @{$self}{'s', 'h'};
    my ($px_x, $px_y);

    # That's simple. The horizontal differenc between the center of
    # (0,0) and (0,2) is obviously 3 * $s. (0,1) sits between them
    # but is offset by $h in the y axis.
    if ($ind_x % 2 == 0) {
    $px_x = $ind_x * 3/2 * $s;
    $px_y = $ind_y * 2 * $h;
    } else {
    $px_x = $ind_x * 3/2 * $s;
    $px_y = ($ind_y * 2 + 1) * $h;
    }
    return ($px_x, $px_y);
    }

    sub hex_from_coord {
    my ($self, $px_x, $px_y) = @_;

    my ($s, $h) = @{$self}{'s', 'h'};

    # Not quite as simple, but if you squint a bit
    # you can see that the pattern repeats every
    # 3 * $s horizontally and every 2 * $h vertically.
    # so we split the plane into rectangles of this size
    my $seg_x = floor($px_x / (3 * $s));
    my $seg_y = floor($px_y / (2 * $h));
    my $rel_x = $px_x - $seg_x * 3 * $s;
    my $rel_y = $px_y - $seg_y * 2 * $h;

    my ($ind_x, $ind_y);

    # and then we split those rectangles into vertical stripes
    # again.
    # Everything between +/- 0.5 $s horizontally from the center of a
    # cell belongs to that cell.
    # but between that the cells overlap and we have to check on which
    # side of the diagonals the pixel is.
    given ($rel_x) {
    when ($_ < 0.5 * $s) {
    $ind_x = $seg_x * 2;
    $ind_y = $seg_y + ($rel_y >= $h);
    }
    when ($_ < 1 * $s) {
    my $r_x = ($_ - $s / 2) / ($s / 2);
    my $r_y = abs(($rel_y - $h) / $h);
    if ($r_y < $r_x) {
    $ind_x = $seg_x * 2 + 1;
    $ind_y = $seg_y;
    } else {
    $ind_x = $seg_x * 2;
    $ind_y = $seg_y + ($rel_y >= $h);
    }
    }
    when ($_ < 2 * $s) {
    $ind_x = $seg_x * 2 + 1;
    $ind_y = $seg_y;
    }
    when ($_ < 2.5 * $s) {
    my $r_x = (2.5 * $s - $_) / ($s / 2);
    my $r_y = abs(($rel_y - $h) / $h);
    if ($r_y < $r_x) {
    $ind_x = $seg_x * 2 + 1;
    $ind_y = $seg_y;
    } else {
    $ind_x = $seg_x * 2 + 2;
    $ind_y = $seg_y + ($rel_y >= $h);
    }
    }
    when ($_ < 3 * $s) {
    $ind_x = $seg_x * 2 + 2;
    $ind_y = $seg_y + ($rel_y >= $h);
    }
    }
    return ($ind_x, $ind_y);

    }

    1;

    hp

    PS: I did see Derek's posting just before posting this, but afaics he
    concentrates on rendering graphics while my code does just geometry, no
    graphics at all (although I've also written a small test script to
    create a PNG with hex-tiles).

    --
    _ | Peter J. Holzer | Deprecating human carelessness and
    |_|_) | Sysadmin WSR | ignorance has no successful track record.
    | | | |
    __/ | http://www.hjp.at/ | -- Bill Code on
    Peter J. Holzer, Apr 7, 2012
    #1
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. =?Utf-8?B?U3JpZGhhcg==?=

    stretching the background image instead of tiling

    =?Utf-8?B?U3JpZGhhcg==?=, Nov 23, 2005, in forum: ASP .Net
    Replies:
    3
    Views:
    8,195
    Mats Lycken
    Nov 30, 2005
  2. Anders Thorsen Holm

    Re: Repeating a tiling image in a table cell

    Anders Thorsen Holm, Jul 15, 2003, in forum: HTML
    Replies:
    0
    Views:
    2,890
    Anders Thorsen Holm
    Jul 15, 2003
  3. Nik Coughlin
    Replies:
    9
    Views:
    393
    Jeremy
    Nov 28, 2007
  4. Simon Strandgaard

    [ann] prime-patterns; hexagon-0.1

    Simon Strandgaard, Oct 4, 2003, in forum: Ruby
    Replies:
    2
    Views:
    130
    Simon Strandgaard
    Oct 7, 2003
  5. Mart van de Wege

    Re: looking for a hexagon tiling module

    Mart van de Wege, Apr 8, 2012, in forum: Perl Misc
    Replies:
    0
    Views:
    589
    Mart van de Wege
    Apr 8, 2012
Loading...

Share This Page