Add starts_from and ends_to path functionality

main
Daniel Asher Resnick 4 months ago
parent f9c9b31089
commit b832bf9d00
  1. 4
      HexGrid.pm
  2. 77
      HexGrid/Path.pm
  3. 42
      tests/paths.pl

@ -140,12 +140,12 @@ sub subgrid_for_tiles($this, @coords_list)
my ($tile, $region) = $this->get_tile_and_region_at($coords->{nw}, $coords->{sw});
unless ($tile)
{
carp "No tile at " . $coords->{nw} . "," . $coords->{sw}, skipping.
carp "No tile at " . $coords->{nw} . "," . $coords->{sw} . ", skipping.";
next;
}
unless ($region)
{
carp "No region at " . $coords->{nw} . "," . $coords->{sw}, skipping.
carp "No region at " . $coords->{nw} . "," . $coords->{sw} . ", skipping.";
next;
}
unless(exists $subgrid->{regions}{$region->{name}})

@ -15,6 +15,8 @@ has id => (is => 'ro', required => 1);
has style => (is => 'rw', default => sub { {} });
has colour => (is => 'rw', alias => 'color', default => 'blue');
has css_class => (is => 'rw');
has starts_from => (is => 'rw');
has ends_to => (is => 'rw');
# Class
@ -48,24 +50,66 @@ sub render($this, $grid, $svg)
return unless @{$this->tiles};
my $g = $svg->g(id => $this->id, class => $this->css_class);
my ($x0, $x, $y0, $y);
my $current_tile = shift @{$this->tiles};
# Single tile
unless (@{$this->tiles})
{
my ($cx, $cy) = $grid->coords_of_centre($current_tile->nw, $current_tile->sw);
$g->circle(cx => $cx, cy => $cy,
r => $this->{style}{'stroke-width'} // $DEFAULT_WIDTH,
fill => $this->colour, style => $this->style, class => $this->css_class);
return;
if($this->starts_from)
{
my ($x1, $y1) = $grid->coords_of_edge($current_tile->nw, $current_tile->sw, $this->starts_from);
if($this->ends_to)
{
my ($x2, $y2) = $grid->coords_of_edge($current_tile->nw, $current_tile->sw, $this->ends_to);
# Curve from starts_from to ends_to with the centre as control point
$g->path(d => "M $x1,$y1 Q $cx,$cy $x2,$y2",
stroke => $this->colour, style => $this->style, class => $this->css_class);
}
else
{
# line from starts_from to the centre
$g->line(x1 => $x1, y1 => $y1, x2 => $cx, y2 => $cy,
stroke => $this->colour, style => $this->style, class => $this->css_class);
}
}
else
{
if($this->ends_to)
{
# line from the centre to ends_to
my ($x2, $y2) = $grid->coords_of_edge($current_tile->nw, $current_tile->sw, $this->ends_to);
$g->line(x1 => $cx, y1 => $cy, x2 => $x2, y2 => $y2,
stroke => $this->colour, style => $this->style, class => $this->css_class);
}
else
{
$g->circle(cx => $cx, cy => $cy,
r => $this->{style}{'stroke-width'} // $DEFAULT_WIDTH,
fill => $this->colour, style => $this->style, class => $this->css_class);
}
}
return $g;
}
my ($x0, $x, $y0, $y);
my $path_spec;
my $previous_tile = $current_tile;
$current_tile = shift @{$this->tiles};
my $next_edge = get_edge_direction($previous_tile, $current_tile);
($x0, $y0) = $grid->coords_of_centre($previous_tile->nw, $previous_tile->sw);
($x, $y) = $grid->coords_of_edge($previous_tile->nw, $previous_tile->sw, $next_edge);
$path_spec .= "M $x0,$y0 L $x,$y";
if($this->starts_from)
{
($x0, $y0) = $grid->coords_of_edge($previous_tile->nw, $previous_tile->sw, $this->starts_from);
$path_spec .= "M $x0,$y0 ";
my ($cx, $cy) = $grid->coords_of_centre($previous_tile->nw, $previous_tile->sw);
$path_spec .= curve_to($cx, $cy, $x, $y);
}
else
{
($x0, $y0) = $grid->coords_of_centre($previous_tile->nw, $previous_tile->sw);
$path_spec .= "M $x0,$y0 L $x,$y";
}
my $previous_edge; # not defined yet
my $next_tile; # not defined yet
@ -84,12 +128,23 @@ sub render($this, $grid, $svg)
$current_tile = $next_tile;
}
# When loop is done (or if it was empty) $current_tile is the last tile
# $next_edge will be the last used edge, so use it's opposite for the source of last line
($x, $y) = $grid->coords_of_centre($current_tile->nw, $current_tile->sw);
$path_spec .= " L $x,$y";
# $next_edge is the last used edge, so use it's opposite for the source of last line
if($this->ends_to)
{
($x, $y) = $grid->coords_of_centre($current_tile->nw, $current_tile->sw);
my ($xe, $ye) = $grid->coords_of_edge($current_tile->nw, $current_tile->sw, $this->ends_to);
$path_spec .= curve_to($x, $y, $xe, $ye);
}
else
{
($x, $y) = $grid->coords_of_centre($current_tile->nw, $current_tile->sw);
$path_spec .= " L $x,$y";
}
$g->path(d => $path_spec, fill => 'transparent',
stroke => $this->colour, style => $this->style, class => $this->css_class
);
return $g;
}
1;

@ -8,11 +8,11 @@ use Carp;
use Data::Dumper;
my $MAP_SIZE = 3;
my $MAP_SIZE = 5;
my $grid = HexGrid->new(defaults => {
style => { 'stroke-width' => 1, stroke => 'white' },
show_coords => 0});
show_coords => 1});
my $region = $grid->make_region("TEST");
for (my $nw=-$MAP_SIZE; $nw <= $MAP_SIZE; $nw++)
@ -23,13 +23,51 @@ for (my $nw=-$MAP_SIZE; $nw <= $MAP_SIZE; $nw++)
}
}
# generic "standard" path
$grid->make_path_from('test-id',
[[0,0], [1,0], [1,1], [2,0], [2,-1], [2,-2], [1,-2], [1,-1], [2,-1], [3,-1]],
colour => 'lime', css_class => 'path', style => { 'stroke-width' => 5 }
);
# Single tile paths
$grid->make_path_from('point-id', [[-1,1]],
colour => 'cyan', css_class => 'path', style => { 'stroke-width' => 5 }
);
$grid->add_path(HexGrid::Path->new(id => 'point-starts', tiles => [$grid->get_tile_at(-2,2)],
starts_from => $HexGrid::DIR{n},
colour => 'yellow', css_class => 'path', style => { 'stroke-width' => 5 }));
$grid->add_path(HexGrid::Path->new(id => 'point-ends', tiles => [$grid->get_tile_at(-3,3)],
ends_to => $HexGrid::DIR{nw},
colour => 'blue', css_class => 'path', style => { 'stroke-width' => 5 }));
$grid->add_path(HexGrid::Path->new(id => 'point-starts-ends-1', tiles => [$grid->get_tile_at(-2,3)],
starts_from => $HexGrid::DIR{sw}, ends_to => $HexGrid::DIR{ne},
colour => 'magenta', css_class => 'path', style => { 'stroke-width' => 5 }));
$grid->add_path(HexGrid::Path->new(id => 'point-starts-ends-2', tiles => [$grid->get_tile_at(-1,2)],
starts_from => $HexGrid::DIR{sw}, ends_to => $HexGrid::DIR{n},
colour => 'orange', css_class => 'path', style => { 'stroke-width' => 5 }));
# starts_from/ends_to paths
$grid->add_path(HexGrid::Path->new(id => 'starts', starts_from => $HexGrid::DIR{ne},
tiles => [$grid->get_tile_at(4,-1), $grid->get_tile_at(5,-1), $grid->get_tile_at(5,0)],
colour => 'yellow', css_class => 'path', style => { 'stroke-width' => 5 }));
$grid->add_path(HexGrid::Path->new(id => 'ends', ends_to => $HexGrid::DIR{nw},
tiles => [$grid->get_tile_at(4,1), $grid->get_tile_at(4,0), $grid->get_tile_at(3,1)],
colour => 'blue', css_class => 'path', style => { 'stroke-width' => 5 }));
$grid->add_path(HexGrid::Path->new(id => 'starts-ends',
starts_from => $HexGrid::DIR{sw}, ends_to => $HexGrid::DIR{s},
tiles => [$grid->get_tile_at(2,3), $grid->get_tile_at(3,3), $grid->get_tile_at(4,3)],
colour => 'magenta', css_class => 'path', style => { 'stroke-width' => 5 }));
#loop
$grid->make_path_from('loop-id',
[[-2,0], [-1,0], [-1,-1], [-2,-1], [-2,0]],
colour => 'red', css_class => 'path', style => { 'stroke-width' => 5 }

Loading…
Cancel
Save