Changes between Initial Version and Version 1 of PerlMapScriptExamples35ex2


Ignore:
Timestamp:
Jan 28, 2009, 2:12:14 PM (15 years ago)
Author:
jmckenna
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • PerlMapScriptExamples35ex2

    v1 v1  
     1= mapquakes.pl =
     2Here's the pilot script that !MapScript was written from. It's called mapquakes.pl and is an example that integrates remote data (earthquake locations from the USGS) with a local raster image of the earth. Here's how it works:
     3
     41) use the perl LWP module to retrieve a text file from USGS servers that contains the locations and magnitudes of the most recent earthquakes worldwide
     5
     62) parse the file, storing the location and magnitude information
     7
     83) draw the raster layer (global topographic data)
     9
     104) loop through the quakes drawing each in turn, scaling the symbol by the magnitude. Each quake is labeled with an ID that is used to reference the quake in a lookup table that is presented below the interface.
     11
     125) save the final map, and return a page to the user
     13
     14The script shows how to build a simple pan/zoom interface and details how one might build maps from disparate sources. Map files and topographic data are available upon request. This should run just fine with MapServer version 3.5 and I will post a version that runs with 3.6 soon.
     15
     16Steve
     17
     18----
     19{{{
     20#!perl
     21#!/usr/bin/perl
     22
     23use CGI qw(:standard :html escape);
     24use LWP::Simple;
     25use mapscript;
     26
     27#
     28# defaults, make any necessary changes here...
     29#
     30$quake_map = '/home/sdlime/mapquakes/quakes.map';
     31$quake_source = 'ftp://ghtftp.cr.usgs.gov/pub/quake';
     32
     33@quakes = '';
     34$quake_data = '';
     35$quake_timestamp = '';
     36
     37$image_path = '/usr/local/apache/htdocs/tmp/';
     38$image_virtual_path = '/tmp/';
     39$image_id = $$ . time() . ".gif";
     40$map = '';
     41
     42$zoom_direction = 0;
     43$zoom_size = 2;
     44
     45sub get_quakes {   
     46    $quake_data = get $quake_source or die 'get failed';
     47
     48    my $i = 0;
     49    my $is_quake = 0;
     50
     51    foreach (split(/^/, $quake_data)) {   
     52        $quake_timestamp = $_ if /^Updated as of/;
     53       
     54        if($is_quake) {
     55            $quakes[$i]{lat} = substr($_, 18, 7);
     56            $quakes[$i]{lon} = substr($_, 26, 7);
     57            $quakes[$i]{magnitude} = substr($_, 40, 3);
     58           
     59            if($quakes[$i]{lon} =~ /E$/) {
     60                $quakes[$i]{lon} =~ s/E//;
     61            } else {
     62                $quakes[$i]{lon} =~ s/W//;
     63                $quakes[$i]{lon} *= -1;
     64            }
     65           
     66            if($quakes[$i]{lat} =~ /N$/) {
     67                $quakes[$i]{lat} =~ s/N//;
     68            } else {
     69                $quakes[$i]{lat} =~ s/S//;
     70                $quakes[$i]{lat} *= -1;
     71            }
     72
     73            $i++;
     74        }
     75
     76        $is_quake = 1 if /^yy/;
     77    }
     78
     79    return;
     80}
     81
     82sub set_extent() {
     83    my $zoom, @imgext;
     84    my $x, $y;
     85    my $cellsizex, $cellsizey; 
     86
     87    if($cgi->param('imgext')) { # if an interactive interface then calculate a new extent
     88        @imgext = split(' ', $cgi->param('imgext'));
     89        $x = $cgi->param('img.x');
     90        $y = $cgi->param('img.y');
     91        $zoom_size = $cgi->param('zoomsize');
     92        $zoom_direction = $cgi->param('zoomdir');
     93
     94        if($zoom_direction == 0) { # pan
     95            $zoom = 1;
     96        } else { # in or out
     97            $zoom = $zoom_size*$zoom_direction;
     98            $zoom = 1.0/abs($zoom) if $zoom < 0;
     99        }
     100
     101        $cx = ($imgext[2]-$imgext[0])/($map->{width}); # calculate cellsize in x and y
     102        $cy = ($imgext[3]-$imgext[1])/($map->{height});
     103
     104        $x = $imgext[0] + $cx*$x; # change x,y from image to map coordinates, offset from UL corner of previous image
     105        $y = $imgext[3] - $cy*$y;
     106
     107        $map->{extent}->{minx} = $x - .5*(($imgext[2] - $imgext[0])/$zoom); # calculate new extent
     108        $map->{extent}->{miny} = $y - .5*(($imgext[3] - $imgext[1])/$zoom);
     109        $map->{extent}->{maxx} = $x + .5*(($imgext[2] - $imgext[0])/$zoom);
     110        $map->{extent}->{maxy} = $y + .5*(($imgext[3] - $imgext[1])/$zoom);
     111   }
     112}
     113
     114sub render_quakes {
     115    die $mapscript::ms_error->{message} unless $map = new mapObj($quake_map);
     116   
     117    &set_extent();
     118
     119    my $img = $map->prepareImage();
     120
     121    my $point = new pointObj();
     122   
     123    my $layer = $map->getLayerByName('relief');
     124    $layer->draw($map, $img); # draw basemap
     125
     126    $layer = $map->getLayerByName('quakes');
     127    my $class = $layer->getClass(0);
     128    my $i = 1; # quake counter
     129    foreach my $q (@quakes) {
     130        $class->{size} = int($q->{magnitude}*2);
     131        $class->{maxsize} = $class->{minsize} = $class->{size}; # don't want to scale
     132
     133        $point->{x} = $q->{lon};
     134        $point->{y} = $q->{lat};
     135        $point->draw($map, $layer, $img, undef, "$i");
     136        $i++;
     137    }
     138
     139    #$layer = $map->getLayerByName('timestamp'); # add timestamp
     140    #$layer->{status} = 1; # turn the layer on
     141    #$class = $layer->getClass(0);
     142    #$class->setText($quake_timestamp);
     143    #$layer->draw($map, $img);
     144   
     145    $map->drawLabelCache($img);
     146    mapscript::msSaveImage($img, $image_path . $image_id, $map->{imagetype}, $map->{transparent}, $map->{interlace}, $map->{imagequality});
     147
     148    return;
     149}
     150
     151# here is the main program
     152$cgi = new CGI;
     153
     154&get_quakes();
     155&render_quakes();
     156
     157# now the html
     158
     159print header();
     160print start_html(-title=>'MapServer Test Suite - Earthquake Mapper', -bgcolor=>"#ffffff");
     161
     162print "<!-- " .mapscript::msGetVersion(). " -->";
     163print "<!-- " .$map->{scale}. " -->";
     164
     165print "<center><table width=\"600\"><tr><td>";
     166
     167print "<font size=\"+2\" face=\"arial,helvetica\"><b>MapScript - Earthquake Mapper</b></font><p>";
     168
     169print "This is a simple of example of using MapScript. Near real-time earthquake data is retrieved ";
     170print "from the USGS web servers. The resulting information is parsed using perl and each ";
     171print "quake is plotted on top of a basemap. The size of the marker indicates quake magnitude. ";
     172print "Many other possible enhancements.  If the interface seems a bit slow it's because the ";
     173print "USGS servers can be difficult to reach- the perils of remote data. Here's the ";
     174print "<a href=\"/mapserver_demos/tests/perl/quakes/mapquakes.pl\">source</a> code.<p>";
     175
     176print "<form name=\"mapquakes\" action=\"/cgi-bin/mapquakes.pl\" method=\"get\">";
     177print "<center>";
     178print "<input border=\"0\" type=\"image\" name=\"img\" src=\"". $image_virtual_path . $image_id ."\"><br>";
     179print "<input type=\"hidden\" name=\"imgext\" value=\"" . join(' ', $map->{extent}->{minx},$map->{extent}->{miny},$map->{extent}->{maxx},$map->{extent}->{maxy}) ."\">";
     180
     181if($zoom_direction == 0) {
     182    print "<input type=\"radio\" name=\"zoomdir\" value=\"1\"> zoom in   ";
     183    print "<input type=\"radio\" name=\"zoomdir\" value=\"0\" checked> pan   ";
     184    print "<input type=\"radio\" name=\"zoomdir\" value=\"-1\"> zoom out     ";
     185} else {
     186    if($zoom_direction == -1) {
     187        print "<input type=\"radio\" name=\"zoomdir\" value=\"1\"> zoom in   ";
     188        print "<input type=\"radio\" name=\"zoomdir\" value=\"0\"> pan   ";
     189        print "<input type=\"radio\" name=\"zoomdir\" value=\"-1\" checked> zoom out     ";
     190    } else {
     191        print "<input type=\"radio\" name=\"zoomdir\" value=\"1\" checked> zoom in   ";
     192        print "<input type=\"radio\" name=\"zoomdir\" value=\"0\"> pan   ";
     193        print "<input type=\"radio\" name=\"zoomdir\" value=\"-1\"> zoom out     ";
     194    }
     195}
     196
     197print "zoom size <input type=\"text\" size=\"2\" name=\"zoomsize\" value=\"$zoom_size\">";
     198
     199print "</center>";
     200print "</form>";
     201
     202print "<p><font face=\"arial,helvetica\"><b>Here's some of the output from the USGS:</b></font><p>";
     203print "<p><pre>";
     204
     205$show = 0;
     206$number = 0;
     207foreach (split(/^/, $quake_data)) {
     208    $show = 1 if /Updated/;   
     209   
     210    printf "<b>%2d</b>: ", $number if $show and $number;
     211    print "    ". $_ if $show and !$number;
     212    print $_ if $show and $number;
     213    $number++ if $show and $number;
     214
     215    $number = 1 if /^yy/;
     216}
     217
     218print "<\/pre>;";
     219
     220print "</td></tr></table>";
     221
     222print end_html();
     223exit(0);
     224}}}
     225
     226== Begin Quakes.map ==
     227{{{
     228MAP
     229  STATUS ON
     230  EXTENT -180 -90 180 90
     231  SIZE 561 281
     232  UNITS DD
     233  IMAGECOLOR 255 0 0
     234
     235  LAYER
     236    NAME relief
     237    TYPE RASTER
     238    DATA relief.tif
     239    STATUS DEFAULT
     240  END
     241
     242  SYMBOL
     243    TYPE ELLIPSE
     244    NAME "circle"
     245    POINTS 1 1 END
     246    FILLED
     247  END
     248
     249  LAYER
     250    NAME quakes
     251    TYPE POINT
     252    STATUS OFF
     253    SYMBOLSCALE 50000000
     254    CLASS
     255      NAME "Recent earth quakes."
     256      SYMBOL circle
     257      SIZE 15
     258      OUTLINECOLOR 0 0 0
     259      COLOR 255 0 0
     260      LABEL
     261        OUTLINECOLOR 0 0 0
     262        COLOR 255 255 255
     263        SIZE TINY
     264    POSITION AUTO
     265    PARTIALS FALSE
     266      END
     267    END
     268    TEMPLATE "dummy"
     269  END
     270
     271  LAYER
     272    NAME timestamp
     273    TYPE ANNOTATION
     274    STATUS OFF
     275    TRANSFORM FALSE
     276    CLASS
     277      TEXT 'This is where the timestamp goes.'
     278      LABEL
     279        COLOR 0 0 0
     280        OUTLINECOLOR 225 225 225
     281        SIZE MEDIUM
     282        POSITION CR
     283    FORCE ON
     284      END
     285    END
     286    FEATURE
     287      POINTS 5 270 END
     288    END
     289  END
     290END
     291}}}