[mapserver-users] perl Geo::Shapelib save method problem

Alan Swithenbank alans at cuervo.stanford.edu
Mon Dec 7 20:53:00 EST 2009


Hi,

I have curious and annoying problem, (mapserver version 5.0.3 on Ubuntu
9.10). Rather than launch into it by immediately posting a bunch of
convoluted perl code, I thought I would try and describe it briefly first
and see if that rings a bell for anyone.

I have been using the Geo::Shapelib perl module to create ESRI
shapefiles, which work fine when loaded by a cgi-bin perl mapscript
routine. The problem is if I attempt to create shapefiles "on the fly"
from the running cgi-bin routine, the Geo::Shapelib $shapefile -> save( )
method does not create the shapefiles. The routine does not crash, the
files simply never are generated. If the same routine is run from the 
command line, the files are generated. I express the full path to the
shape file directory, and have gone so far as to launch a separate
creation routine via the perl system command and even to fork the
cgi-bin process and launch the separate creation routine via exec. No
luck. And, both the separate system command program launch and the process
fork work to create viable shapefiles when the main cgi-bin routine is
launched from the commandline. If anyone else has seen something like this
I'd be interested to hear about it. (BTW, I do not have any problems
creating the associated .map files on the fly from the routine running as
cgi-bin, but, those I generate completely from my own code.)

I dug through the Geo::Shapelib source code for the save method a bit,
and the problem seems related to it's custom create routines for
generating file handles balking in the cgi environment. I REALLY don't
want to go there if I don't have too...;^) In fact, I'm not wedded to
Geo::Shapelib. I'd be happy to use the mapscript API directly from perl to
generate shapefiles. But, by my Googling expeditions, it looks as if as
time goes on, less and less information about perl mapscript becomes
available. (I can't even dredge the old and often mentioned perl mapscript
wiki out of the internet archives.)

Perhaps I just need a pointer to a bit more detail on generating
shapefiles from peal mapscript. For some obligatory code, below are the
guts of what I have done to create shapefiles using the Geo::Shapefile
module. The required information are all availble in a hash generated
from a previous database query at this point. Thanks for any thoughts!


Alan Swithenbank
Research Programmer
Stanford University
Tagging of Pacific Pelagics Project



#==============================================================================
#                          GENERATE ESRI SHAPEFILE
#==============================================================================

# Get indexes in hash key array for lon and lat:

my $lonidx;
my $latidx;
my $i = 0;
foreach (@hashkeys) {
   if ($_ =~ m/lon/) {
     $lonidx = $i;
   }
   if ($_ =~ m/lat/) {
     $latidx = $i;
   }
   $i++;
}

# Get indexes in hash key array for all elements except lon and lat:

my @fieldidxs = ();
foreach my $i (0..scalar(@hashkeys)-1) {
   if ($i != $lonidx && $i != $latidx) {
     push(@fieldidxs,$i);
   }
}

# Get key value names for all elements except lon and lat:

my @Fieldnames = ();                  # array of names for fields except lon lat
@Fieldnames = @hashkeys[@fieldidxs];

my @Fieldtypes = ();                  # array of types for fields except lon lat
$i = 0;
foreach (2..scalar(@hashkeys)-1) {
   $Fieldtypes[$i++] = "String:15";
}

my $shapefile = new Geo::Shapelib;
$shapefile->{Name} = $savefile;
$shapefile->{Shapetype} = $shapetype;       # polyline = 3
$shapefile->{FieldNames} = \@Fieldnames;    # array reference!
$shapefile->{FieldTypes} = \@Fieldtypes;    # array reference!

# Create a reference record from the start date of the query data:

my @record = ();
my $j = 0;
foreach my $key (@Fieldnames) {
   $record[$j++] = $datahash{$key}[0];
}

# Create line string for current shape element:

my @vertices = ();
my $shapeid = 0;
my $lastptt = $datahash{ptt}[0];  # get first PTT value for splitting 
tracks
foreach my $i (0..$rowcnt-1) {
   my $lon = $datahash{$hashkeys[$lonidx]}[$i];
   my $lat = $datahash{$hashkeys[$latidx]}[$i];
   my $currentptt = $datahash{ptt}[$i];
   if ($currentptt != $lastptt) {

# add current PTT shape element:

     add_new_shape($shapefile,$shapeid,$shapetype,\@record,\@vertices);

# do updates for next PTT shape element:

     $lastptt = $currentptt;
     $shapeid++;
     @record = ();
     $j = 0;
     foreach my $key (@Fieldnames) {
       $record[$j++] = $datahash{$key}[$i];
     }
     @vertices = ();
   }

   push(@vertices,[$lon,$lat]); # push after possible update so don't lose one

}

# make sure at least one shape gets added!

add_new_shape($shapefile,$shapeid,$shapetype,\@record,\@vertices);

# Save shapefile and return filename:

$shapefile -> save($savefile);

# The print print below does not show up when the save method is called
# from cgi-bin, so, apparently the save method heads off into limbo.

print "hello: $savefile<br>\n";

exit;

#==============================================================================
#                                SUBROUTINES
#==============================================================================

#------------------------------ add new shape ---------------------------------

sub add_new_shape {

# Add a new shape section to current shapefile under construction.

   my $shapefile = $_[0];
   my $shapeid = $_[1];
   my $shapetype = $_[2];
   my $recordref = $_[3];
   my $verticesref = $_[4];

   my @record = ();
   @record = @$recordref;
   my @vertices = ();
   @vertices = @$verticesref;

   return unless scalar(@vertices) > 2;  # don't add a degenerate shape

   push @{$shapefile->{ShapeRecords}},\@record;  # array reference!

   push @{$shapefile->{Shapes}}, {
       SHPType => $shapetype,
       ShapeId => $shapeid,
       NVertices => scalar(@vertices),
       Vertices => [@vertices]                   # array reference!
   };

   return;

}




More information about the mapserver-users mailing list