Changes between Initial Version and Version 1 of PerlMapScriptExamples35ex19


Ignore:
Timestamp:
Jan 29, 2009, 7:04:57 AM (15 years ago)
Author:
jmckenna
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • PerlMapScriptExamples35ex19

    v1 v1  
     1= query_points2.pl =
     2
     3Improved perl mapscript 3.6.6 example of creating a queryable layer of point objects, by creating them as Layer Features without an associated shape file or database connection. The points are in the perl program. Of course the points could come from any database or text file or etc. The .map EXTENT must match the points you want to display. One other subtle point: The points layer in the map file must have a TEMPLATE for the layer to queryable, even though it is not used. See the comments in the code.
     4----
     5{{{
     6#!perl
     7#!/usr/bin/perl
     8# This is an example of creating a layer of point objects (actually buoys in the Gulf of Maine, U.S.) It should be
     9# easily adaptable to any set of points.  It creates the points as features in the layer which means that they
     10# can still be retrieved using $layer->queryByPoint() even though no shape file or database connection exists
     11# for them.
     12# In this revised edition:
     13# a) the points are drawn using $point->draw(). This allows us to do a getClass() for each point and set class values
     14#    such as $class->{size} for each point.
     15# b) We still call addFeature() so that the layer is queryable, which is the main point.
     16# c) We use a numeric key value as the $shape->{index} which maps to our "database". This will be returned by
     17#    queryByPoint().
     18# d) We no longer need to call $layer->draw() since we already called $point->draw(). Thus the features serve as
     19#    an invisible layer just for querying.
     20# Author: Eric Bridger eric@gomoos.org eric@maine.com
     21# Data: Thu Aug 28 10:56:06 EDT 2003
     22# This has been tested with mapserver 3.6.X not 4.0
     23
     24use strict;
     25use mapscript;
     26use CGI ":cgi";
     27
     28$ENV{MS_ERRORFILE} = '/path/to/mapserver.log';
     29
     30my $q = new CGI;
     31my $msg = '';
     32
     33# A hash of points. First field is the key value used in addFeature() and returned by queryByPoint().
     34# This could come from any external database, etc.
     35my %points = (
     36        10202 =>        {'longitude' => -67.0173,
     37                                'latitude'  => 44.8911,
     38                                'size'  => 5,
     39                                'label'  => 'one',
     40                                },
     41        20103 =>        {'longitude' =>  -66.0146,
     42                                'latitude' => 45.2045,
     43                                'size'  => 10,
     44                                'label'  => 'two',
     45                                },
     46        30105 =>        {'longitude' => -68.3578,
     47                                'latitude' => 43.7148,
     48                                'size'  => 12,
     49                                'label'  => 'three',
     50                                },
     51        40102 =>        {'longitude' => -66.5528,
     52                                'latitude' => 43.6243,
     53                                'size'  => 18,
     54                                'label'  => 'four',
     55                                },
     56        50105 =>        {'longitude' => -68.9983,
     57                                'latitude' => 44.0555,
     58                                'size'  => 20,
     59                                'label'  => 'five',
     60                                },
     61        60102 =>        {'longitude' => -67.8800,
     62                                'latitude' => 43.4900,
     63                                'size'  => 10,
     64                                'label'  => 'six',
     65                                },
     66        70104 =>        {'longitude' => -70.5665,
     67                                'latitude' => 42.5185,
     68                                'size'  => 10,
     69                                'label'  => 'seven',
     70                                },
     71        80103 =>        {'longitude' => -70.4278,
     72                                'latitude' => 43.1807,
     73                                'size'  => 10,
     74                                'label'  => 'eight',
     75                                },
     76        90104 =>        {'longitude' => -68.1087,
     77                                'latitude' => 44.1058,
     78                                'size'  => 8,
     79                                'label'  => 'nine',
     80                                },
     81        100202 =>       {'longitude' => -70.0578,
     82                                'latitude' => 43.5673,
     83                                'size'  => 15,
     84                                'label'  => 'ten',
     85                                },
     86);
     87
     88my $image_name = sprintf("%0.10d",rand(1000000000)) . ".png";
     89# see points.map
     90my $map = new mapscript::mapObj("points2.map");
     91
     92if(!$map){
     93        warn "New mapObj() error: $mapscript::ms_error->{message}\n";
     94}
     95
     96# Create a point object representing the mouse click on the map.
     97my ($x, $y) = get_click($q, $map);
     98
     99my $click_pt = undef;
     100if($x != 0 && $y != 0){
     101        $click_pt = new mapscript::pointObj();
     102        $click_pt->{x} = $x;
     103        $click_pt->{y} = $y;
     104}
     105
     106my $img = $map->prepareImage();
     107
     108if(!$img){
     109        warn "prepareImage() error: $mapscript::ms_error->{message}\n";
     110}
     111
     112my $layerObj = undef;
     113
     114# Add points as Features to the point layer.
     115$layerObj = $map->getLayerByName('points');
     116my $point = new mapscript::pointObj();
     117
     118# Queries will return index into this array.
     119foreach my $point_id (keys %points){
     120        $point->{x} = $points{$point_id}{longitude};
     121        $point->{y} = $points{$point_id}{latitude};
     122        # Features require shape objects, which require lines, so create a single point line.
     123        my $line = new mapscript::lineObj();
     124        $line->add($point);
     125        my $shp = new mapscript::shapeObj($mapscript::MS_SHAPE_POINT);
     126        $shp->add($line);
     127        $shp->setBounds();
     128        # Don't set any text, $point->draw() will draw the text.
     129        #$shp->{text} = $point_id;
     130        # set the shape index to our database key value.
     131        # the $shp->{index} can be any NUMERIC value. If our database key values were alphanumeric
     132        # we would need to use a lookup array and set $shp-{index} to 0,1,2,...
     133        # queryByPoint() results will return this value, but it must be numeric.
     134        $shp->{index} = $point_id;
     135        $layerObj->addFeature($shp);
     136        # we only have one class in this layer.
     137        my $class = $layerObj->getClass(0);
     138        # set symbol size based on a value from our "database"
     139        $class->{size} = $points{$point_id}{size};
     140        $point->draw($map, $layerObj, $img, undef, $points{$point_id}{label});
     141}
     142
     143# Query based on the mouse click point.
     144if($click_pt){
     145        $msg .= "<p>\n";
     146        $layerObj = $map->getLayerByName('points');
     147       
     148        if($layerObj->queryByPoint($map,$click_pt,$mapscript::MS_SINGLE,0)){
     149                $msg .= "No Points found<br>\n";
     150        }else{
     151                my $results = $layerObj->{resultcache};
     152                # we only expect one result.
     153                my $rslt = $layerObj->getResult(0);
     154                # this is the numeric value we used for the shape passed to addFeature() above.
     155                my $point_id = $rslt->{shapeindex};
     156                $msg .= "Click found point: $point_id.<br>\n";
     157                $msg .= "name is:  $points{$point_id}{label}.<br>\n";
     158                $msg .= "size is:  $points{$point_id}{size}.<br>\n";
     159                $msg .= "lat:  $points{$point_id}{latitude} long:  $points{$point_id}{longitude}.<br>\n";
     160
     161        }
     162        $msg .= "</p>\n";
     163
     164}
     165
     166# display the click point
     167if($click_pt){
     168        $layerObj = $map->getLayerByName('click');
     169        $click_pt->draw($map, $layerObj, $img, undef, "Click");
     170}
     171
     172
     173$map->drawLabelCache($img);
     174
     175$img->saveImage($image_name, $mapscript::MS_PNG, $map->{transparent}, $map->{interlace}, 0);
     176
     177$img->free();
     178
     179# Output the HTML form and map
     180
     181print $q->header();
     182print $q->start_html(-title=>'MapServer - Dynamic Points', -bgcolor=>"#ffffff");
     183
     184print "<form name=\"pointmap\" action=\"points2.shtml\" method=\"GET\">\n";
     185print "<table border=\"1\" cellpadding=\"5\" cellspacing=\"2\">\n";
     186print "<tr>\n";
     187print "<td>\n";
     188print "<input border=\"2\" type=\"image\" name=\"img\" src=\"$image_name\">\n";
     189print "</td>\n";
     190print "</tr>\n";
     191print "</table>\n";
     192print "</form>\n";
     193print "$msg<br>\n";
     194print "<a href=\"points2.shtml\"> Start over </a><br>\n";
     195print "<p><br><br><br></p>\n";
     196
     197print $q->end_html();
     198
     199# translate mouse click x,y into map longitude, latitude based on map extent. This is based on set_extent() in
     200# mapquakes.pl
     201
     202sub get_click {
     203        my ($q, $map) = @_;
     204        my ($x, $y, $cx, $cy) = (0,0,0,0);
     205        my $minx = $map->{extent}->{minx};
     206        my $miny = $map->{extent}->{miny};
     207        my $maxx = $map->{extent}->{maxx};
     208        my $maxy = $map->{extent}->{maxy};
     209
     210        if($q->param('img.x')) { # Make sure we got a click
     211                $x = $q->param('img.x');
     212                $y = $q->param('img.y');
     213
     214                $cx = ($maxx-$minx)/($map->{width}-1); # calculate cellsize in x and y
     215                $cy = ($maxy-$miny)/($map->{height}-1);
     216
     217                $x = $minx + $cx*$x; # change x,y from image to map coordinates
     218                $y = $maxy - $cy*$y;
     219        }
     220
     221        return ($x, $y);
     222}
     223}}}
     224
     225= points2.map =
     226Really no different than query_points.map in the old example. except I have some commented out PROJECTION info which you can use if you have PROJ4 support. The PROJECTION does not effect the querying at all. Mapscript takes care of it.
     227{{{
     228MAP
     229  STATUS ON
     230  EXTENT -71.5 39.5 -63.0 46.0
     231  #EXTENT 306421.28 4373726.40 964564.13 5095536.32
     232  SIZE 504 385
     233  #SIZE 400 439
     234  IMAGETYPE PNG
     235  UNITS DD
     236  #UNITS METERS
     237  #PROJECTION
     238  #  "init=epsg:26919"
     239  #END
     240
     241SYMBOL
     242  TYPE ELLIPSE
     243  NAME "circle"
     244  POINTS 1 1 END
     245  FILLED TRUE
     246END
     247
     248SYMBOL
     249  TYPE VECTOR
     250  NAME "plus"
     251  POINTS .5 0 .5 1 -99 -99 0 .5 1 .5 END
     252END
     253
     254LAYER
     255  NAME "points"
     256  TYPE POINT
     257  STATUS ON
     258  TOLERANCE 10
     259  # Need fake template for querys to work
     260  TEMPLATE "bogus.html"
     261  CLASS
     262    NAME "buoy"
     263    SYMBOL "circle"
     264    SIZE 0
     265        COLOR 255 0 0
     266        OUTLINECOLOR 0 0 0
     267    LABEL
     268      COLOR 255 0 0
     269      TYPE BITMAP
     270      SIZE MEDIUM
     271      POSITION AUTO
     272      PARTIALS FALSE
     273      BUFFER 2
     274    END # end of label
     275  END
     276  #PROJECTION
     277  #  "proj=latlong"
     278  #END
     279END
     280
     281LAYER
     282  NAME "click"
     283  TYPE POINT
     284  STATUS ON
     285  CLASS
     286    NAME "click"
     287    SYMBOL "plus"
     288    SIZE  6
     289        COLOR 0 0 0
     290    LABEL
     291      TYPE BITMAP
     292      SIZE TINY
     293      COLOR 0 0 0
     294      POSITION AUTO
     295      PARTIALS FALSE
     296      BUFFER 1
     297    END
     298  END
     299END
     300
     301END
     302
     303}}}
     304----
     305back to PerlMapScript