# ATITD Map Images
# ================
#
# Images of the complete map of a telling. Can draw stuff and output as PNG or
# JPEG.

package ATITD::Map;

use strict;
use warnings;

use GD;

# Creates a new map for a telling from an image file.
sub new {
	my ($class, $telling, $filename) = @_;
	
	GD::Image->trueColor(1);
	
	my $self = bless {
		telling => $telling,
		image => GD::Image->new($filename),
	}, $class;
	
	return $self;
}

# Our telling.
sub telling { $_[0]->{telling} }

# Our image.
sub image { $_[0]->{image} }

# Translate coordinates from the ATITD space into the image space.
sub translate {
	my ($self, $x, $y) = @_;
	my $telling = $self->telling;
	my $new_x = ($x - $telling->left) / $telling->width * $self->image->width;
	my $new_y = (-$y + $telling->top) / $telling->height * $self->image->height;

	return wantarray ? ($new_x, $new_y) : [$new_x, $new_y];
}

# Render a line
sub render_line {
	my ($self, $from, $to, $color, $thickness) = @_;
	my $image = $self->image;
	
	# Dashed line
	if ($thickness < 0) {
		my $col = $image->colorAllocate(@$color);
		
		$image->setStyle(($col) x 7, (gdTransparent) x 5);
		$image->line(@$from, @$to, gdStyled);
	}
	
	# Normal line
	elsif ($thickness == 1) {
		my $col = $image->colorAllocate(@$color);

		$image->line(@$from, @$to, $col);
	}
	
	# Thick line
	else {
		my $brush = GD::Image->new($thickness, $thickness);
		my $col = $brush->colorAllocate(@$color);
		
		$brush->fill(0, 0, $col);		
		$image->setBrush($brush);
		$image->line(@$from, @$to, gdBrushed);
	}
	
	return $self;
}

# Render a line with an arrow in the middle
sub render_arrow {
	my ($self, $from, $to, $color, $thickness) = @_;
	my $image = $self->image;
	my $arrow = GD::Polygon->new;
	my $col = $image->colorAllocate(@$color);
	my $middle = [
		($to->[0] - $from->[0]) / 2 + $from->[0], 
		($to->[1] - $from->[1]) / 2 + $from->[1],
	];
	
	$arrow->addPt(@$middle);
	$arrow->addPt(@{$self->rotate($middle, $from, 6 + $thickness * 2,  .4)});
	$arrow->addPt(@{$self->rotate($middle, $from, 6 + $thickness * 2, -.4)});
	
	$self->render_line($from, $to, $color, $thickness);
	$image->filledPolygon($arrow, $col);
	
	return $self;
}

# Rotate a vector and resize it to a certain length
sub rotate {
	my ($self, $origin, $direction, $length, $radians) = @_;
	my $sin = sin $radians;
	my $cos = cos $radians;
	my $orig_x = $direction->[0] - $origin->[0];
	my $orig_y = $direction->[1] - $origin->[1];
	my $x = $orig_x * $cos - $orig_y * $sin;
	my $y = $orig_x * $sin + $orig_y * $cos;
	my $len = sqrt($x * $x + $y * $y);
	
	$x *= $length / $len;
	$y *= $length / $len;
	
	return [$x + $origin->[0], $y + $origin->[1]];
}

# Return the image as JPEG
sub as_jpeg { $_[0]->image->jpeg($_[1]) }

# Return the image as PNG
sub as_png { $_[0]->image->png }

1;
