App-traveller
view release on metacpan or search on metacpan
lib/Traveller/Mapper.pm view on Meta::CPAN
xmlns:xlink="http://www.w3.org/1999/xlink"
width="${width}mm"
height="${height}mm"
viewBox="%s %s %s %s">
<desc>Traveller Subsector</desc>
<defs>
<style type="text/css"><![CDATA[
text {
font-size: 16pt;
font-family: Optima, "Optima Regular", Optima-Regular, Helvetica, sans-serif;
text-anchor: middle;
}
text a {
fill: blue;
text-decoration: underline;
}
.coordinates {
fill-opacity: 0.5;
}
.starport, .base {
font-size: 20pt;
}
.direction {
font-size: 24pt;
}
.legend {
text-anchor: start;
font-size: 14pt;
}
tspan.comm {
fill: #ff6347; /* tomato */
}
line.comm {
stroke-width: 10pt;
stroke: #ff6347; /* tomato */
}
tspan.trade {
fill: #afeeee; /* pale turquoise */
}
line.trade {
stroke-width: 6pt;
stroke: #afeeee; /* pale turquoise */
fill: none;
}
.travelzone {
opacity: 0.3;
}
.amber {
fill: none;
stroke-width: 1pt;
stroke: black;
}
.red {
fill: red;
}
#hex {
stroke-width: 3pt;
fill: none;
stroke: black;
}
#background {
fill: inherit;
}
#bg {
fill: inherit;
}
]]></style>
<polygon id="hex" points="%s,%s %s,%s %s,%s %s,%s %s,%s %s,%s" />
<polygon id="bg" points="%s,%s %s,%s %s,%s %s,%s %s,%s %s,%s" />
</defs>
<rect fill="white" stroke="black" stroke-width="10" id="frame"
x="%s" y="%s" width="%s" height="%s" />
EOT
my $scale = 100;
return sprintf($template,
map { sprintf("%.3f", $_ * $scale) }
# viewport
-0.5, -0.5, 3 + ($self->width - 1) * 1.5, ($self->height + 1.5) * sqrt(3),
# empty hex, once for the backgrounds and once for the stroke
@hex,
@hex,
# framing rectangle
-0.5, -0.5, 3 + ($self->width - 1) * 1.5, ($self->height + 1.5) * sqrt(3));
}
sub colour {
my $self = shift;
my $culture = shift or return "white";
# The same colours result from the same names.
my @colours = ("#d3d3d3", "#f5f5f5", "#eaeaea", "#fffeb0", "#fff0f5", "#eee0e5", "#ffe1ff",
"#eed2ee", "#c6e2ff", "#fdf5e6", "#e0ffff", "#d1eeee", "#c5fff5", "#eeeee0",
"#fff68f", "#eee685", "#fffacd", "#eee9bf", "#ffe7ba", "#ffefdb", "#ffe4e1",
"#eed5d2", "#e6e6fa", "#f0ffff", "#c5ffd5", "#e6ffe6", "#d5ffc5", "#f5f5dc");
my $i = unpack("%32W*", lc $culture) % @colours; # checksum
return $colours[$i];
}
sub background {
my $self = shift;
my $scale = 100;
return join("\n", map {
my $hex = $_;
my $x = $hex->x;
my $y = $hex->y;
my $c = $hex->colour || $self->colour($hex->culture);
sprintf(qq{ <use xlink:href="#bg" x="%.3f" y="%.3f" fill="$c"/>},
(1 + ($x-1) * 1.5) * $scale,
($y - $x%2/2) * sqrt(3) * $scale);
} @{$self->hexes});
}
sub grid {
my $self = shift;
my $scale = 100;
my $doc;
$doc .= join("\n",
map {
my $n = shift;
my $x = int($_/$self->height+1);
my $y = $_ % $self->height + 1;
my $svg = sprintf(qq{ <use xlink:href="#hex" x="%.3f" y="%.3f"/>\n},
(1 + ($x-1) * 1.5) * $scale,
($y - $x%2/2) * sqrt(3) * $scale);
$svg .= sprintf(qq{ <text class="coordinates" x="%.3f" y="%.3f">}
. qq{%02d%02d</text>\n},
(1 + ($x-1) * 1.5) * $scale,
($y - $x%2/2) * sqrt(3) * $scale - 0.6 * $scale,
$x, $y);
} (0 .. $self->width * $self->height - 1));
return $doc;
}
sub legend {
my $self = shift;
my $scale = 100;
my $doc;
my $uwp = '';
if ($self->source) {
$uwp = ' â <a xlink:href="' . $self->source . '">UWP</a>';
}
$doc .= sprintf(qq{ <text class="legend" x="%.3f" y="%.3f">â gas giant}
. qq{ â â Imperial consulate â â¼ TAS facility â â² scout base}
. qq{ â â
naval base â Ï research station â â pirate base}
. qq{ â <tspan class="comm">â®</tspan> communication}
. qq{ â <tspan class="trade">â®</tspan> trade$uwp</text>\n},
-10, ($self->height + 1) * sqrt(3) * $scale);
$doc .= sprintf(qq{ <text class="direction" x="%.3f" y="%.3f">coreward</text>\n},
$self->width/2 * 1.5 * $scale, -0.13 * $scale);
$doc .= sprintf(qq{ <text transform="translate(%.3f,%.3f) rotate(90)"}
. qq{ class="direction">trailing</text>\n},
($self->width + 0.4) * 1.5 * $scale, $self->height/2 * sqrt(3) * $scale);
$doc .= sprintf(qq{ <text class="direction" x="%.3f" y="%.3f">rimward</text>\n},
$self->width/2 * 1.5 * $scale, ($self->height + 0.7) * sqrt(3) * $scale);
$doc .= sprintf(qq{ <text transform="translate(%.3f,%.3f) rotate(-90)"}
. qq{ class="direction">spinward</text>\n},
-0.1 * $scale, $self->height/2 * sqrt(3) * $scale);
return $doc;
}
lib/Traveller/Mapper.pm view on Meta::CPAN
} elsif (not $C{$u} and not $C{$v}) {
$C{$v} = $C{$u} = ++$id;
}
}
}
return \@T;
}
sub route {
# Compute the shortest route between two hexes no longer than a
# certain distance and choosing intermediary steps from the array of
# possible candidates.
my ($self, $from, $to, $distance, $candidatesref, @seen) = @_;
# my $indent = ' ' x (4-$distance);
my @options;
foreach my $hex (nearby($from, $distance < 2 ? $distance : 2, $candidatesref)) {
push (@options, $hex) unless in($hex, @seen);
}
return unless @options and $distance;
if (in($to, @options)) {
return @seen, $from, $to;
}
my @routes;
foreach my $hex (@options) {
my @route = $self->route($hex, $to, $distance - distance($from, $hex),
$candidatesref, @seen, $from);
if (@route) {
push(@routes, \@route);
}
}
return unless @routes;
# return the shortest one
my @shortest;
foreach my $route (@routes) {
if ($#{$route} < $#shortest or not @shortest) {
@shortest = @{$route};
}
}
return @shortest;
}
sub trade_svg {
my $self = shift;
my $data = '';
my $scale = 100;
foreach my $edge (@{$self->routes}) {
my $u = @{$edge}[0];
my $v = @{$edge}[1];
my ($x1, $y1) = ($u->x, $u->y);
my ($x2, $y2) = ($v->x, $v->y);
$data .= sprintf(qq{ <line class="trade" x1="%.3f" y1="%.3f" x2="%.3f" y2="%.3f" />\n},
(1 + ($x1-1) * 1.5) * $scale, ($y1 - $x1%2/2) * sqrt(3) * $scale,
(1 + ($x2-1) * 1.5) * $scale, ($y2 - $x2%2/2) * sqrt(3) * $scale);
}
return $data;
}
sub svg {
my ($self, $width, $height) = @_;
my $data = $self->header($width, $height);
$data .= qq{ <g id='background'>\n};
$data .= $self->background;
$data .= qq{ </g>\n\n};
$data .= qq{ <g id='comm'>\n};
foreach my $hex (@{$self->hexes}) {
$data .= $hex->comm_svg();
}
$data .= qq{ </g>\n\n};
$data .= qq{ <g id='routes'>\n};
$data .= $self->trade_svg();
$data .= qq{ </g>\n\n};
$data .= qq{ <g id='grid'>\n};
$data .= $self->grid;
$data .= qq{ </g>\n\n};
$data .= qq{ <g id='legend'>\n};
$data .= $self->legend();
$data .= qq{ </g>\n\n};
$data .= qq{ <g id='system'>\n};
foreach my $hex (@{$self->hexes}) {
$data .= $hex->system_svg();
}
$data .= qq{ </g>\n};
$data .= $self->footer();
return $data;
}
sub text {
my ($self) = @_;
my $data = "Trade Routes:\n";
foreach my $edge (@{$self->routes}) {
my $u = @{$edge}[0];
my $v = @{$edge}[1];
$data .= $u->name . " - " . $v->name . "\n";
}
$data .= "\n";
$data .= "Raw Data:\n";
foreach my $hex (@{$self->hexes}) {
foreach my $routeref (@{$hex->routes}) {
$data .= join(' - ', map {$_->name} @{$routeref}) . "\n";
}
}
$data .= "\n";
$data .= "Communications:\n";
foreach my $hex (@{$self->hexes}) {
foreach my $comm (@{$hex->comm}) {
$data .= $hex->name . " - " . $comm->name . "\n";;
}
}
return $data;
}
1;
( run in 2.542 seconds using v1.01-cache-2.11-cpan-f56aa216473 )