-
Notifications
You must be signed in to change notification settings - Fork 2
PerlMapScriptExamples42ex1
#!perl
#!/usr/bin/perl
This has been tested with mapserver 4.2 beta3. I found that Perl mapscript4.0.2 was not quite ready for prime
time. Missing methods: class->getStyle(), colorObj support, etc. It illustrates some of the changes needed to
adapt a mapscript3.6 application to mapscript4.2. Thanks to Sean Giles for all his work on mapscript.
########################
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() and getStyle() for each point
c) We use a numeric key value as the $shape->{index} which maps to our "database". This will be returned by
d) No need to call $layer->draw() since we already called $point->draw(). Thus the features serve as
Author: Eric Bridger eric@gomoos.org eric@maine.com
########################
use strict;
use mapscript42;
use CGI ":cgi";
$ENV{MS_ERRORFILE} = '/tmp/mapserver4.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("tmp/%0.10d",rand(1000000000)) . ".png";
my $map = new mapscript42::mapObj("points42.map");
if(!$map){
warn "New mapObj() error: $mapscript42::ms_error->{message}\n";
}
my $circle_idx = $map->{symbolset}->index("circle");
my $plus_idx = $map->{symbolset}->index("plus");
my $blue = new mapscript42::colorObj(0,0,255);
my $red = new mapscript42::colorObj(255,0,0);
my $black = new mapscript42::colorObj(0,0,0);
my ($x, $y) = get_click($q, $map);
my $click_pt = undef;
if($x != 0 && $y != 0){
$click_pt = new mapscript42::pointObj();
$click_pt->{x} = $x;
$click_pt->{y} = $y;
}
my $img = $map->draw();
if(!$img){
warn "prepareImage() error: $mapscript42::ms_error->{message}\n";
}
my $layerObj = undef;
$layerObj = $map->getLayerByName('points');
foreach my $point_id (keys %points){
my $point = new mapscript42::pointObj();
$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 mapscript42::lineObj();
$line->add($point);
my $shp = new mapscript42::shapeObj($mapscript42::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);
# TWO APPROACHES illustrated here.
# NEW SYTLE OBJ
#my $style = new mapscript42::styleObj();
# OR
# EXISTING STYLE OBJ: This picks up defaults from map file e.g. black outline color
my $style = $class->getStyle(0);
# Add new style.
#my $style = new mapscript42::styleObj($class);
# point size based on our "database"
$style->{size} = $points{$point_id}{size};
if($point_id == 40102){
$style->{symbol} = $plus_idx;
}else{
$style->{symbol} = $circle_idx;
}
#$style->{symbol} = $plus_idx;
# COLORS
# just to illustrate assigning a reference to a colorObj.
my $color = $red;
if($point_id == 20103){
$color = $black;
}
$style->{color} = $color;
# since this is a STYLE from the map file we don't need this.
# it's in the map file.
$style->{outlinecolor} = $black;
$class->{label}->{color} = $blue;
$point->draw($map, $layerObj, $img, undef, $points{$point_id}{label});
# NEW STYLE must REMOVE if you inserted it.
#$class->removeStyle(0);
}
if($click_pt){
$msg .= "
\n";
# this is un-needed.
$layerObj = $map->getLayerByName('points');
if($layerObj->queryByPoint($map,$click_pt,$mapscript42::MS_SINGLE,0)){
$msg .= "No Points found<br>\n";
}else{
# In 4.2 $layerObj-{resultcache} is no longer used.
# use $num_results = $layerObj->getNumResults() then
# foreach my $i (0 .. $num_results-1){
# my $rslt = $layerObj->getResult($i);
#}
# 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->save($image_name);
NOTA BENA Deconstructors (~) have been created for all mapscript objects. Don't call $imgObj->free().
#$img->free();
print $q->header();
print $q->start_html(-title=>'MapServer4.2 - Dynamic Points', -bgcolor=>"#ffffff");
print "<form name="pointmap" action="points42.cgi" 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 "
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);
}
= points42.map =
MAP
NAME "points42"
STATUS ON
EXTENT -71.5 39.5 -63.0 46.0
SIZE 504 385
IMAGETYPE PNG
UNITS DD
PROJECTION
"proj=latlong"
END
OUTPUTFORMAT
NAME PNG
DRIVER "GD/PNG"
MIMETYPE "image/png"
# 24bit
IMAGEMODE RGB
# 8 bit psuedo color
#IMAGEMODE PC256
#EXTENSION "png"
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"
STYLE
SYMBOL "circle"
SIZE 0
COLOR 0 255 0
OUTLINECOLOR 0 0 0
END
LABEL
COLOR 255 0 0
TYPE BITMAP
SIZE MEDIUM
POSITION AUTO
PARTIALS FALSE
BUFFER 2
END # end of label
END
PROJECTION
"proj=latlong"
END
END
LAYER
NAME "click"
TYPE POINT
STATUS ON
CLASS
NAME "click"
STYLE
SYMBOL "plus"
SIZE 6
COLOR 0 0 0
END
LABEL
TYPE BITMAP
SIZE TINY
COLOR 0 0 0
POSITION AUTO
PARTIALS FALSE
BUFFER 1
END
END
END
END
----
back to PerlMapScrip