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.

Reply via email to