Hi Benoit,
Attached is a small example that adds points to a shapefile. It was
written for a custom application, but you can easily adjust it to your
needs. As you can see, you don't even need MapScript to add points.
You can manipulate Shapefiles directly using Geo:: Shapelib module.
Hope this helps you.
Puneet.
On 4/23/07, Benoit Myard <[EMAIL PROTECTED]> wrote:
Hi list,
I'm trying to set up an application whose goal is to add Point data to
an existing map using Perl MapScript. My plan is to put all that's
static in a mapfile and to draw the points afterwards.
For now, I haven't managed to draw anything except what's in the
mapfile and I would like to know if there is anything special I should
know. For example, when you create a point, which projection is in use
?
I attached a sample script which should draw a big point over Paris
but actually doesn't.
Also, I noted that I can't "use strict;" since the MapScript Variables
(MS_ON, MS_SINGLE, ...) produce errors even when you prefix them with
'mapserver::' :
Argument "MS_ON" isn't numeric in subroutine entry at
/opt/csw/lib/perl/site_perl/mapscript.pm line 35.
Allthough there is not much documentation for the Perl-side of
MapScript, the MapScript API Reference should be sufficient. Just in
case someone is aware of some well-rounded documentation or examples
for Perl MapScript, it would be great to share with others :).
Thanks in advance.
--
Benoit Myard
--
Puneet Kishor http://punkish.eidesis.org/
Nelson Inst. for Env. Studies, UW-Madison http://www.nelson.wisc.edu/
Open Source Geospatial Foundation http://www.osgeo.org/education/
---------------------------------------------------------------------
collaborate, communicate, compete
=====================================================================
#!/usr/local/bin/perl
use strict;
use Geo::Shapelib;
# Search for "# REPLACE" below and replace the values per your shapefile
# Provide the parameters correctly to the insertShape() method below
insertShape(
shp_dir => "/full/path/to/shapefile/dir",
shp_name => "shp_name without extension",
h_img_dims => {img_width => 500, img_height => 400},
h_map_bbox => {map_minx => 2090491, map_miny => 482208, map_maxx => 2224055, map_maxy => 587708},
h_mouse_click => {mouse_x => 250, mouse_y => 110},
);
sub insertShape {
my (%args) = @_;
my $shp_dir = $args{shp_dir};
my $shp_name = $args{shp_name};
my $h_img_dims = $args{h_img_dims};
my $h_map_bbox = $args{h_map_bbox};
my $h_mouse_click = $args{h_mouse_click};
# Convert the mouse click to earth coordinates
my ($x, $y) = _pixel2earth(
h_img_dims => $h_img_dims,
h_map_bbox => $h_map_bbox,
h_mouse_click => $h_mouse_click,
);
# Create a new shapefile object for the existing shapefile
my $shapefile = new Geo::Shapelib "$shp_dir/$shp_name" or die "$!: Unable to open shapefile $shp_dir/$shp_name\n";
# Number of shapes in the existing shapefile
my $num_of_shapes = @{$shapefile->{Shapes}};
# Create a temp shapefile
my $tmp = "tmp";
$shapefile->create("$shp_dir/$tmp");
# Copy all the shapes to the new shapefile
for (0 .. $num_of_shapes - 1) {
my $s = $shapefile->{Shapes}->[$_];
my $r = $shapefile->{ShapeRecords}->[$_];
$shapefile->add($s, $r);
}
## Now add the new shape
# First, create a shape
my $s = { Vertices => [ [$x, $y, 0, 0,] ] };
# Now, create an attribute record for the new shape --
# Get the last shape from the existing shapefile. Shapes are indexed base 0,
# so the last shape will be total number of shapes minus 1
my $shp = $shapefile->get_record( ($num_of_shapes - 1), "$shp_dir/$shp_name");
# Create an attribute record by using the last shape as a template
my $r = {
AREA => 0,
PERIMETER => 0,
CACCIDEP_ => ++$shp->{CACCIDEP_}, # REPLACE
CACCIDEP_I => ++$shp->{CACCIDEP_I}, # REPLACE
};
# Add the new shape to the end of the shape ile
$shapefile->add($s, $r);
$shapefile->close();
# Back up the old files and replace it with the new files. Need to back up
# only the shp, dbf, and shx files as others are not touched at all.
for (qw(shp dbf shx)) {
rename("$shp_dir/$shp_name.$_", $shp_name . "_" . _timestamp() . ".$_") or die "$!: Unable to rename $shp_dir/$shp_name.$_\n";
rename("$shp_dir/$tmp.$_", "$shp_name.$_") or die "$!: Unable to rename $shp_dir/$tmp.$_\n";
}
}
sub _pixel2earth {
my (%args) = @_;
my $h_img_dims = $args{h_img_dims};
my $h_map_bbox = $args{h_map_bbox};
my $h_mouse_click = $args{h_mouse_click};
# Mouse clicks equivalent in earth coordinates
return (
$h_map_bbox->{map_minx} + ($h_mouse_click->{mouse_x} * ( ($h_map_bbox->{map_maxx} - $h_map_bbox->{map_minx}) / $h_img_dims->{img_width} )),
$h_map_bbox->{map_miny} + ($h_mouse_click->{mouse_y} * ( ($h_map_bbox->{map_maxy} - $h_map_bbox->{map_miny}) / $h_img_dims->{img_height} ))
);
}
sub _timestamp {
# 0 1 2 3 4 5 6 7 8
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
$mon += 1;
$year += 1900;
return "$year-$mon-$mday" . "_" . "$hour-$min-$sec";
}
1;
=head1 NAME
insertShape();
=head1 VERSION
This documentation refers to MedinaAccidents version 0.1. which deals with adding points to a shapefile.
=head1 SYNOPSIS
insertShape();
=head1 DESCRIPTION
This program adds a point feature to a points featureclass stored in a ESRI shapefile. It requires the full path to and name of the shapefile, x and y coordinates of the point in the same coordinate system as the shapefile, and any optional attributes to be updated.
=head1 METHODS
=over
=item sub insertShape()
The public method C<insertShape()> inserts a new shape feature into a shapefile featureclass. It requires 6 inputs as shown below --
# Full path to the shape featureclass. Do not add trailing /
my $shp_dir = "/path/to/shapefile";
# Name of the shape featureclass. Do not provide any suffix.
my $shp_name = "shapefile";
# Dimensions of the map image in pixels
my $h_img_dims = {
img_width => $img_width,
img_height => $img_height
};
# Dimensions of the map in earth coordinates
my $h_map_bbox = {
map_minx => $map_minx,
map_miny => $map_miny,
map_maxx => $map_maxx,
map_maxy => $map_maxy
};
# Coordinates of the mouse click
my $h_mouse_click = {
mouse_x => $mouse_x,
mouse_y => $mouse_y
};
insertShape(
shp_dir => $shp_dir,
shp_name => $shp_name,
h_img_dims => $h_img_dims,
h_map_bbox => $h_map_bbox,
h_mouse_click => $h_mouse_click,
id => $id,
);
=item sub _pixel2earth()
The private method C<_pixel2earth()> converts mouse click on an image into earth coordinates. This is a generic method, and doesn't care about the underlying coordinate system B<as long as> the coordinate system is Cartesian. If the coordinate system is geographic, that is, the coordinates are lat/long, this method will return values that will be increasingly inaccurate away from the Equator. This method takes 3 inputs, all hashrefs, and returns two scalars as follows --
my $h_img_dims = {
img_width => $img_width,
img_height => $img_height
};
my $h_map_bbox = {
map_minx => $map_minx,
map_miny => $map_miny,
map_maxx => $map_maxx,
map_maxy => $map_maxy
};
my $h_mouse_click = {
mouse_x => $mouse_x,
mouse_y => $mouse_y
};
my ($x, $y) = _pixel2earth(
h_img_dims => $h_img_dims,
h_map_bbox => $h_map_bbox,
h_mouse_click => $h_mouse_click,
);
=item sub _timestamp()
The private method C<_timestamp()> returns a date-time stamp suitable for branding backup files. This method requires no input, and returns a scalar as shown below --
my $timestamp = _timestamp();
=back
=head1 DEPENDENCIES
This module relies upon the following modules
=over
=item *
Geo::Shapelib
=back
=head1 INCOMPATIBILITIES
There are no known modules that are incompatible with this module.
=head1 BUGS AND LIMITATIONS
There are no known bugs in this module. Please report problems to Puneet Kishor.
=head1 AUTHORS
Puneet Kishor [EMAIL PROTECTED]
=head1 LICENCE AND COPYRIGHT
This program is copyright Puneet Kishor, 2007.
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See the Perl Artistic License at L<http://www.perl.com/pub/a/language/misc/Artistic.html>.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.