forked from MapServer/MapServer
-
Notifications
You must be signed in to change notification settings - Fork 2
PerlMapScriptExamples35ex7
Thomas Bonfort edited this page Apr 6, 2012
·
2 revisions
#!perl
#!/usr/bin/perl -w
#
# Copyright (C) 2002, Lowell Filak.
# You may distribute this file under the terms of the Artistic
# License.
#
# Given a shapefile name, a coordinate, & an item name
# this routine will select a shape,
# select all the shapes with the same item value, & create a shapefile of
# the selected shape(s).
#
# Required modules are mapscript (installed as part of make install),
# Getopt (normally included with Perl) & XBase.
# Please download boundary.tar.gz also, and:
# tar -xf boundary.tar.gz --ungzip
# Note: The suggested run assumes a pick point on a 600x600 image.
#
# Suggested run method = ./qry_point.pl -file=boundary -coorx=372 -coory=115 -item=loc_name
use mapscript;
use Getopt::Long;
use XBase;
#
# Retrieve the input values.
GetOptions('file=s' => \$file, 'coorx=s' => \$coorx, 'coory=s' => \$coory, 'item=s' => \$item);
#
# Check the input values.
if ( (!$file) || (!$coorx) || (!$coory) || (!$item) ) {
print "Syntax: find.pl -file=[filename] -coorx=[x_coordinate] -coory=[y_coordinate] -item=[item_name]\n";
exit 0;
}
#
# Upcase the item name.
$item = uc $item;
#
# Create mapfile name.
my $mapfile = $file . '.map';
#
# Open map using default map file.
my $map = new mapObj("$mapfile") or die('Unable to Open Default MapFile!');
#
# Subtract one pixel.
# Why is this done?: I don't directly recall but I think it has to do with
# mapextents starting at a positive integer while image starts at 0,0.
$imgx = $map->{width} - 1;
$imgy = $map->{height} - 1;
#
# Find the extents of the map.
$minx = $map->{extent}->{minx};
$miny = $map->{extent}->{miny};
$maxx = $map->{extent}->{maxx};
$maxy = $map->{extent}->{maxy};
#
# Caculate a delta x & delta y.
$dx = $maxx - $minx;
$dy = $maxy - $miny;
#
# Divide delta x & y by pixel extents to find factor x & y.
$fctrx = $dx / $imgx;
$fctry = $dy / $imgy;
#
# Adjust to real world coordinates.
$coorx = $coorx * $fctrx;
$coory = $coory * $fctry;
$coorx = $coorx + $minx;
$coory = $maxy - $coory;
#
#
# Create point object for pick query.
$pnt = new pointObj();
$pnt->{x} = $coorx;
$pnt->{y} = $coory;
#
# Print the point coordinates.
print "Selecting Using Point Coordinates: x=$coorx y=$coory\n";
#
# Get layer for boundary query.
# Note: Most of this is already set in the mapfile and is here for sample
# only.
my $lyr = $map->getLayerByName("$file") or die('Unable to Open Boundary Layer!');
$lyr->{status} = $mapscript::MS_ON;
$lyr->{type} = $mapscript::MS_LAYER_POLYGON;
$lyr->{data} = "$file";
#
# Query the layer using the created point.
$lyr->queryByPoint($map,$pnt,$mapscript::MS_SINGLE,0);
#
# Create a resultcache object to see how many results.
my $rsltcache = $lyr->{resultcache};
#
# How many matches did we find.
print "Found $rsltcache->{numresults} Result.\n";
#
# Grab the first result (there should only be one).
my $rslt = $lyr->getResult(0);
#
# What is the shape number.
my $record = $rslt->{shapeindex};
#
# Print the shape number.
print "The Query Found Shape #$record.\n";
#
# Query the dbf for the item matching records.
# Note: The routine is written to utilize dbf files as they originally are.
# Normally you would want to at least add a record number field to the
# dbf file so you could use the DBI & DBD::XBase modules to query
# the db. You could also load the dbf data into an dbms and use
# the DBI & DBD::x modules to query once the record number field
# exists.
#
# Open the db handle.
my $dbh = new XBase "$file" or die XBase->errstr;
#
# What is the number of the key field.
my @names = $dbh->field_names;
#
# How many fields are there.
my $fldcnt = $dbh->last_field;
#
# Set the field number to initially 0.
my $fieldnum = 0;
#
# Loop through the fields and find the one we want.
for ($field=0; $field<=$fldcnt; $field++){
#
# Is this the field we were looking for.
if ( $names[$field] eq $item ) {
#
# If so then exit loop.
$fieldnum = $field;
#
# Print the field number.
print "The Key Item is Field #$fieldnum.\n";
last;
}
else {
#
# Fall through.
}
}
#
# Grab the key record & the key item value.
my @row = $dbh->get_record_nf($record, $fieldnum) or die $dbh->errstr;
#
# What is the value for the key item.
my $value = $row[1];
#
# Print the key item value for the key record.
print "The Value of $item for Shape #$record = $value.\n";
#
# Start the number of results at 0.
my $results = 0;
#
# Open the selection set shapefile.
# Note: There is a way to obtain a selection set without saving to a
# shapefile, however due to the type of data I am accustomed to,
# by writing to a shapefile, a type of shapefile cache can be setup.
# By naming all shapefiles in a particular directory in a way
# that allows them to be reopened for any repetitious queries
# the actual work of the query can be bypassed.
my $shapesel = new shapefileObj('selected',$mapscript::MS_SHAPEFILE_POLYGON);
#
# Open the existing shapefile for grabbing the found shapes out of.
my $shapefile = new shapefileObj("$file",-1);
#
# Loop through each record (there are experimental modules for using indexes
# available according to xbase man page).
for ($record=0; $record<$dbh->last_record; $record++){
#
# Grab the record.
my @row = $dbh->get_record($record, "$item") or die $dbh->errstr;
#
# Is the record marked for deletion.
my $deleted = $row[0];
if ( $deleted == 1 ) {
#
# If so then skip it.
next;
}
else {
#
# Fall through.
}
#
# Set the value for the search field.
my $fndvalue = $row[1];
#
# Does the value from the field match the value for the key record.
if ( "$fndvalue" ne "$value" ) {
#
# If not skip it.
next;
}
else {
#
# Fall through.
}
#
# Print the found record information.
print "Record #$record Matches with a Value of $fndvalue - good thing :-)\n";
#
# Increment the results counter.
$results = $results + 1;
#
# Create the shape object for holding the found shapes.
my $shape = new shapeObj(-1);
#
# Grab shape #$record and stick it into the shape holder.
#
$shapefile->get($record - 1, $shape);
#
# Add that shape to the selection set shapefile.
$shapesel->add($shape);
}
#
# Close the new shapefile.
undef $shapesel;
#
# Create dbf to go with it.
my $newdbh = $dbh->create("name" => "selected.dbf");
#
# Reopen the selected set shapefile.
$shapesel = new shapefileObj("selected", -1);
#
# Get the extent of selected set.
$newrect = $shapesel->{bounds};
$newminx = $newrect->{minx};
$newmaxx = $newrect->{maxx};
$newminy = $newrect->{miny};
$newmaxy = $newrect->{maxy};
$numseld = $shapesel->{numshapes};
undef $shapesel;
#
# Print the extents.
print "The Extents of the Selected Set: minx=$newminx miny=$newminy maxx=$newmaxx maxy=$newmaxy.\n";
#
# Print the number of selected records.
print "The Number of Selected Shapes = $numseld.\n";
back to PerlMapScrip