Graphics-HotMap

 view release on metacpan or  search on metacpan

lib/Graphics/HotMap.pm  view on Meta::CPAN

            textSize => 8,
            textColor => 'magenta',
         },
         zoneA => {
            layerName => '40_anotherLayer',
            coordonates => [0,10,1,12],
            border => 1,
            text => 'black',
            textSize => 8,
            textColor => 'white',
         },
         zoneB => {
            layerName => '40_anotherLayer',
            coordonates => [1,10,2,12],
            border => 1,
            text => 'blue',
            textSize => 8,
            textColor => 'white',
         },
         zoneC => {
            layerName => '40_anotherLayer',
            coordonates => [2,10,3,12],
            border => 1,
            text => 'green',
            textSize => 8,
            textColor => 'white',
         },
         zoneD => {
            layerName => '40_anotherLayer',
            coordonates => [3,10,4,12],
            border => 1,
            text => 'cyan',
            textSize => 8,
            textColor => 'white',
         },
      },
      points => {
         '30_anotherLayer' => [
            [8,5,46],
            [10,9,22],
         ],
         '10_back' => [
            [13,1,50],
         ],
         '40_anotherLayer' => [
            [0,10,1],
            [1,10,2],
            [2,10,3],
            [3,10,4],
         ],
      },
   );

   # ..., and import/add it
   $hotMap->addConfs(\%other);

   # Run the interpolation and generate and image
   $hotMap->genImage;

   # Save the image a a PNG file
   $hotMap->genImagePng('MyTest.png');

   # print the text representation of the map
   print $hotMap->toString('floor') if $hotMap->scale < 3;

=head1 DESCRIPTION

Generate thermographic images from a few know points. Others values are interpolated. Graphics::HotMap use PDL to work on matrix.
PDL can compute very very large matrix in a few seconds.

See L<http://kumy.org/HotMap/HotMap.png>

=head2 FUNCTIONS

=over 4

=cut

use Data::Dumper;
use Image::Magick;
use Math::Gradient qw(multi_array_gradient);
use PDL;
use PDL::NiceSlice;
use PDL::IO::Pic;
use POSIX qw(strftime);
use File::Temp qw/ :POSIX /;
use File::Temp qw/ tempfile tempdir /;

use constant {
   PALETTE_SLICE => 35,
};

our $VERSION = '0.0001';

=item new(<HASH>)

=for ref

Construct and return a new HotMap Object;

=for usage

   Graphics::HotMap->new(
      outfileGif        => <File path>, # file to write GIF
      outfilePng        => <File path>, # file to write PNG
      legend            => [0|1],       # activate lengend
      legendNbGrad      => <number>,    # Number a graduation
      cross             => <bool>,      # activate crossing of known values
      crossValues       => <bool>,      # activate values printing whith cross
      minValue          => <number>,    # minimum value
      maxValue          => <number>,    # maximum value
      font              => <path to font file>,
      fontSize          => <number>,    # font size
      scale             => <number>,    # scale values and coordonates
      sizeX             => <number>,    # X size
      sizeY             => <number>,    # Y size
   );

=for exemple 

   my $hotMap = Graphics::HotMap->new(
      sizeX    => 10, 
      sizeY    => 10, 
      minValue => 1,
      maxvalue => 50,
   );


=cut

sub new {
   my ($class, %params) = (@_);
   my $self={};
   $self->{_outfileGif}   = $params{outfileGif}   || undef;
   $self->{_outfilePng}   = $params{outfilePng}   || undef;
   $self->{_legend}       = $params{legend}       || 0;
   $self->{_legendNbGrad} = $params{legendNbGrad} || 7;
   $self->{_crossMark}    = $params{cross}        || 0;
   $self->{_crossMarkTemp}= $params{crossTemp}    || 0;
   #$self->{_minValue}     = $params{minValue}     || 0;
   #$self->{_maxValue}     = $params{maxValue}     || 70;
   $self->{_font}         = $params{font}         || '/usr/share/fonts/truetype/freefont/FreeSans.ttf';
   $self->{_fontSize}     = $params{fontSize}     || 15;
   $self->{_text}         = ();
   $self->{_horodatage}   = $params{horodatage}   || [0, 0, 0];
   $self->{_scale}        = $params{echelle}      || 1;
   $self->{_verbose}      = $params{verbose}      || 0;
   $self->{_mapSize}{x}   = $params{sizeX}        || 30;
   $self->{_mapSize}{y}   = $params{sizeY}        || 20;
   $self->{_knownPoints}  = {};
   $self->{_mapPoints}    = PDL->zeroes(1);
   bless $self, $class;
   #$self->gradient(20, ([0,0,255],[0,255,255],[0,255,0],[255,255,0],[255,0,0]));
   return $self;
}

=item initKnownPoints()

=for ref

Reset all know points.

=cut

sub initKnownPoints {
   my $self = shift;

   $self->{_knownPoints} = {};
}

=item mapSize(<HASH>)

=for ref

Set or Return mapSize

=for exemple

   $hotMap->mapSize({sizeX => 15, sizeY => 15}); # Set map size
   @size = $hotMap->mapSize; # Return the actual map size

=cut

sub mapSize {
   my $self = shift;
   my ($dimentions) = @_;

   if (defined $dimentions) {
      die ("mapSize: You must set sizeX and sizeY.",$/)
         unless (defined $dimentions->{sizeX} && defined $dimentions->{sizeY});

      $self->{_mapSize}{x} = ($dimentions->{sizeX}  ) * $self->{_scale};
      $self->{_mapSize}{y} = ($dimentions->{sizeY}  ) * $self->{_scale};

      $self->{_mapPoints}  = PDL->zeroes($self->{_mapSize}{x}, $self->{_mapSize}{y});

lib/Graphics/HotMap.pm  view on Meta::CPAN

# generate gradient interpolation
   $self->_pdlDegrad($knownPointsSlice, $mapPointsSlice, $sliceColors, $gradientName);

# draw walls
   if (defined $zoneHash->{border}) {
       $mapPointsSlice->(0)    .= $zoneHash->{border};
       $mapPointsSlice->(-1)   .= $zoneHash->{border};
       $mapPointsSlice->(:,0)  .= $zoneHash->{border};
       $mapPointsSlice->(:,-1) .= $zoneHash->{border};
   }

   #$mapPointsSlice = byte($mapPointsSlice);
}

=for comment
Fetch zone

=cut

sub _genDegrad {
   my $self = shift;

   $self->_genGradient;

   foreach my $layerName (sort keys %{$self->{_zones}}) {
      foreach my $zoneName (sort keys %{$self->{_zones}{$layerName}}) {
         $self->_genDegradZone($layerName, $self->{_zones}{$layerName}{$zoneName});
      }
   }
}

=item genImage()

=for ref

Calculate the interpolation of all Zones.

=cut

sub genImage {
   my $self = shift;

   $self->{_mapPoints}  = PDL->zeroes($self->{_mapSize}{x}, $self->{_mapSize}{y});
   $self->_genDegrad;
   $self->_genPicture;
}

=for comment

This function will write image to disk.

=cut

sub _saveImg {
   my $self = shift;
   my ($outfile, $im) = @_;

   print $im->Write(filename=>$outfile); #, compression=>'JPEG', type => 'Palette');
}

=item genImagePng()

=for ref 

Write a PNG image from the interpolated table.

=for exemple

   $hotMap->genImagePng('<path_to_png'>);

=cut

sub genImagePng {
   my $self = shift;
   my $fileName = shift || $self->{_outfilePng} || die "No output PNG specified";
   $self->_saveImg($fileName,$self->{_im});
   return {
        width    => $self->{_im}->Get('width'),
        height   => $self->{_im}->Get('height'),
        filesize => $self->{_im}->Get('filesize'),
        mime     => $self->{_im}->Get('mime'),
        image    => $self->{_im},
        };
}

=item genImageGif()

=for ref 

Add a GIF image to the annimation from the interpolated table.

=for exemple

   $hotMap->genImageGif('<path_to_gif'>);

=cut

sub genImageGif {
   my $self = shift;
   my $fileName = shift || $self->{_outfileGif} || die "No output GIF specified";
   my $image = shift;
   my $im = $self->{_im};

   unless (defined $image) {
      $image = new Image::Magick(size => "$self->{_mapSize}{x}x$self->{_mapSize}{y}");
      $image->Read($fileName);
   }
   $image->Set(magick=>'GIF', loop=> 100);
   $im->Set(magick=>'GIF', delay=>100);
   push (@$image, $im);
   $self->_saveImg($fileName, $image);
   return {
        width    => $image->Get('width'),
        height   => $image->Get('height'),
        filesize => $image->Get('filesize'),
        mime     => $image->Get('mime'),
        image    => $image,
        };
}

=back

=head1 SEE ALSO

PDL

Math::Gradient

=head1 AUTHOR

Mathieu Alorent (cpan@kumy.net)

=cut

1;



( run in 2.879 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )