-
Notifications
You must be signed in to change notification settings - Fork 0
PerlMapScriptExamples35ex19
Improved 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.
{{{
#!perl
#!/usr/bin/perl
This is an example of creating a layer of point objects (actually buoys in the Gulf of Maine, U.S.) It should be
easily adaptable to any set of points. It creates the points as features in the layer which means that they
can still be retrieved using $layer->queryByPoint() even though no shape file or database connection exists
a) the points are drawn using $point->draw(). This allows us to do a getClass() for each point and set class values
c) We use a numeric key value as the $shape->{index} which maps to our "database". This will be returned by
d) We no longer need to call $layer->draw() since we already called $point->draw(). Thus the features serve as
Author: Eric Bridger [email protected] [email protected]
use strict;
use mapscript;
use CGI ":cgi";
$ENV{MS_ERRORFILE} = '/path/to/mapserver.log';
my $q = new CGI;
my $msg = '';
my %points = (
10202 => {'longitude' => -67.0173,
'latitude' => 44.8911,
'size' => 5,
'label' => 'one',
},
20103 => {'longitude' => -66.0146,
'latitude' => 45.2045,
'size' => 10,
'label' => 'two',
},
30105 => {'longitude' => -68.3578,
'latitude' => 43.7148,
'size' => 12,
'label' => 'three',
},
40102 => {'longitude' => -66.5528,
'latitude' => 43.6243,
'size' => 18,
'label' => 'four',
},
50105 => {'longitude' => -68.9983,
'latitude' => 44.0555,
'size' => 20,
'label' => 'five',
},
60102 => {'longitude' => -67.8800,
'latitude' => 43.4900,
'size' => 10,
'label' => 'six',
},
70104 => {'longitude' => -70.5665,
'latitude' => 42.5185,
'size' => 10,
'label' => 'seven',
},
80103 => {'longitude' => -70.4278,
'latitude' => 43.1807,
'size' => 10,
'label' => 'eight',
},
90104 => {'longitude' => -68.1087,
'latitude' => 44.1058,
'size' => 8,
'label' => 'nine',
},
100202 => {'longitude' => -70.0578,
'latitude' => 43.5673,
'size' => 15,
'label' => 'ten',
},
);
my $image_name = sprintf("%0.10d",rand(1000000000)) . ".png";
my $map = new mapscript::mapObj("points2.map");
if(!$map){
warn "New mapObj() error: $mapscript::ms_error->{message}\n";
}
my ($x, $y) = get_click($q, $map);
my $click_pt = undef;
if($x != 0 && $y != 0){
$click_pt = new mapscript::pointObj();
$click_pt->{x} = $x;
$click_pt->{y} = $y;
}
my $img = $map->prepareImage();
if(!$img){
warn "prepareImage() error: $mapscript::ms_error->{message}\n";
}
my $layerObj = undef;
$layerObj = $map->getLayerByName('points');
my $point = new mapscript::pointObj();
foreach my $point_id (keys %points){
$point->{x} = $points{$point_id}{longitude};
$point->{y} = $points{$point_id}{latitude};
# Features require shape objects, which require lines, so create a single point line.
my $line = new mapscript::lineObj();
$line->add($point);
my $shp = new mapscript::shapeObj($mapscript::MS_SHAPE_POINT);
$shp->add($line);
$shp->setBounds();
# Don't set any text, $point->draw() will draw the text.
#$shp->{text} = $point_id;
# set the shape index to our database key value.
# the $shp->{index} can be any NUMERIC value. If our database key values were alphanumeric
# we would need to use a lookup array and set $shp-{index} to 0,1,2,...
# queryByPoint() results will return this value, but it must be numeric.
$shp->{index} = $point_id;
$layerObj->addFeature($shp);
# we only have one class in this layer.
my $class = $layerObj->getClass(0);
# set symbol size based on a value from our "database"
$class->{size} = $points{$point_id}{size};
$point->draw($map, $layerObj, $img, undef, $points{$point_id}{label});
}
if($click_pt){
$msg .= "
\n";
$layerObj = $map->getLayerByName('points');
if($layerObj->queryByPoint($map,$click_pt,$mapscript::MS_SINGLE,0)){
$msg .= "No Points found<br>\n";
}else{
my $results = $layerObj->{resultcache};
# we only expect one result.
my $rslt = $layerObj->getResult(0);
# this is the numeric value we used for the shape passed to addFeature() above.
my $point_id = $rslt->{shapeindex};
$msg .= "Click found point: $point_id.<br>\n";
$msg .= "name is: $points{$point_id}{label}.<br>\n";
$msg .= "size is: $points{$point_id}{size}.<br>\n";
$msg .= "lat: $points{$point_id}{latitude} long: $points{$point_id}{longitude}.<br>\n";
}
$msg .= "</p>\n";
}
if($click_pt){
$layerObj = $map->getLayerByName('click');
$click_pt->draw($map, $layerObj, $img, undef, "Click");
}
$map->drawLabelCache($img);
$img->saveImage($image_name, $mapscript::MS_PNG, $map->{transparent}, $map->{interlace}, 0);
$img->free();
print $q->header();
print $q->start_html(-title=>'MapServer - Dynamic Points', -bgcolor=>"#ffffff");
print "<form name="pointmap" action="points2.shtml" method="GET">\n";
print "<table border="1" cellpadding="5" cellspacing="2">\n";
print "
print "\n";
print "<input border="2" type="image" name="img" src="$image_name">\n";
print "\n";
print "\n";
print "\n";
print "\n";
print "$msg
\n";
print "<a href="points2.shtml"> Start over
\n";
print "
print $q->end_html();
translate mouse click x,y into map longitude, latitude based on map extent. This is based on set_extent() in
sub get_click {
my ($q, $map) = @_;
my ($x, $y, $cx, $cy) = (0,0,0,0);
my $minx = $map->{extent}->{minx};
my $miny = $map->{extent}->{miny};
my $maxx = $map->{extent}->{maxx};
my $maxy = $map->{extent}->{maxy};
if($q->param('img.x')) { # Make sure we got a click
$x = $q->param('img.x');
$y = $q->param('img.y');
$cx = ($maxx-$minx)/($map->{width}-1); # calculate cellsize in x and y
$cy = ($maxy-$miny)/($map->{height}-1);
$x = $minx + $cx*$x; # change x,y from image to map coordinates
$y = $maxy - $cy*$y;
}
return ($x, $y);
}
}}}
= points2.map =
Really 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.
{{{
MAP
STATUS ON
EXTENT -71.5 39.5 -63.0 46.0
#EXTENT 306421.28 4373726.40 964564.13 5095536.32
SIZE 504 385
#SIZE 400 439
IMAGETYPE PNG
UNITS DD
#UNITS METERS
#PROJECTION
#END
SYMBOL
TYPE ELLIPSE
NAME "circle"
POINTS 1 1 END
FILLED TRUE
END
SYMBOL
TYPE VECTOR
NAME "plus"
POINTS .5 0 .5 1 -99 -99 0 .5 1 .5 END
END
LAYER
NAME "points"
TYPE POINT
STATUS ON
TOLERANCE 10
TEMPLATE "bogus.html"
CLASS
NAME "buoy"
SYMBOL "circle"
SIZE 0
COLOR 255 0 0
OUTLINECOLOR 0 0 0
LABEL
COLOR 255 0 0
TYPE BITMAP
SIZE MEDIUM
POSITION AUTO
PARTIALS FALSE
BUFFER 2
END # end of label
END
#PROJECTION
#END
END
LAYER
NAME "click"
TYPE POINT
STATUS ON
CLASS
NAME "click"
SYMBOL "plus"
SIZE 6
COLOR 0 0 0
LABEL
TYPE BITMAP
SIZE TINY
COLOR 0 0 0
POSITION AUTO
PARTIALS FALSE
BUFFER 1
END
END
END
END
back to PerlMapScrip