Changes between Initial Version and Version 1 of Thin.pl


Ignore:
Timestamp:
Dec 16, 2008, 9:27:17 AM (16 years ago)
Author:
hobu
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Thin.pl

    v1 v1  
     1{{{
     2#!perl
     3
     4#!/usr/bin/perl
     5# Script : thin.pl
     6#
     7# Purpose: An adaption of the ArcView Avenue example script genfeat.ave. It's
     8#          basically the Douglas-Peucker generalization algorithm.
     9#
     10# Initial Coding: 04/10/2000
     11#
     12# Last Modified: 10/10/2005
     13#
     14# Author  : Stephen Lime (steve.lime@dnr.state.mn.us)
     15# Version : 1.0
     16# comments: initial implementation
     17#
     18# Author  : Tom Kralidis
     19# Version : 1.1
     20# comments: updating, cleanup and newer perl mapscript methods, reporting
     21#
     22
     23use strict;
     24use warnings;
     25use POSIX;
     26use XBase;
     27use mapscript;
     28use Getopt::Long;
     29use File::Copy;
     30
     31my ($infile, $outfile, $tolerance);
     32
     33GetOptions("input=s", \$infile, "output=s", \$outfile, "tolerance=n", \$tolerance);
     34
     35if(!$infile or !$outfile or !$tolerance) {
     36  print "Usage: $0 --input=[filename] --output=[filename] --tolerance=[maximum distance between vertices]\n";
     37  exit 0;
     38}
     39
     40die "Tolerance must be greater than zero." unless $tolerance > 0;
     41
     42# initialize counters for reporting
     43my $incount  = 0;
     44my $outcount = 0;
     45
     46# open the input shapefile
     47my $inSHP = new mapscript::shapefileObj($infile, -1) or die "Unable to open shapefile $infile.";
     48
     49die "Cannot thin point/multipoint shapefiles." unless ($inSHP->{type} == 5 or $inSHP->{type} == 3);
     50
     51# create the output shapefile
     52
     53unlink "$outfile.shp";
     54unlink "$outfile.shx";
     55unlink "$outfile.dbf";
     56
     57my $outSHP = new mapscript::shapefileObj($outfile, $inSHP->{type}) or die "Unable to create shapefile '$outfile'. $!\n";
     58
     59copy("$infile.dbf", "$outfile.dbf") or die "Can't copy file $infile.dbf to $outfile.dbf: $!\n";
     60
     61my $inshape = new mapscript::shapeObj(-1); # something to hold shapes
     62
     63for(my $i=0; $i<$inSHP->{numshapes}; $i++) {
     64
     65  $inSHP->get($i, $inshape);
     66  my $outshape = new mapscript::shapeObj(-1);
     67
     68  for(my $j=0; $j<$inshape->{numlines}; $j++) {
     69
     70    my $inpart  = $inshape->get($j);
     71    my $outpart = new mapscript::lineObj();
     72
     73    my @stack = ();
     74
     75    $incount += $inpart->{numpoints};
     76
     77    my $anchor = $inpart->get(0); # save first point
     78    $outpart->add($anchor);
     79    my $aIndex = 0;
     80
     81    my $fIndex = $inpart->{numpoints} - 1;
     82    push @stack, $fIndex;
     83
     84    # Douglas - Peucker algorithm
     85    while(@stack) {
     86
     87      $fIndex = $stack[$#stack];
     88      my $fPoint = $inpart->get($fIndex);
     89
     90      my $max = $tolerance; # comparison values
     91      my $maxIndex = 0;
     92
     93      # process middle points
     94      for (($aIndex+1) .. ($fIndex-1)) {
     95
     96        my $point = $inpart->get($_);
     97        #my $dist = $point->distanceToLine($anchor, $fPoint);
     98        my $dist = $point->distanceToSegment($anchor, $fPoint);
     99
     100        if($dist >= $max) {
     101          $max = $dist;
     102          $maxIndex = $_;
     103        }
     104      }
     105
     106      if($maxIndex > 0) {
     107        push @stack, $maxIndex;
     108      } else {
     109        $outpart->add($fPoint);
     110        $anchor = $inpart->get(pop @stack);
     111        $aIndex = $fIndex;
     112      }
     113    }
     114
     115    # check for collapsed polygons, use original data in that case
     116    if(($outpart->{numpoints} < 4) and ($inSHP->{type} == 5)) {
     117      $outpart = $inpart;
     118    }
     119
     120    $outcount += $outpart->{numpoints};
     121    $outshape->add($outpart);
     122
     123  } # for each part
     124
     125  $outSHP->add($outshape);
     126  undef($outshape); # free memory associated with shape
     127
     128} # for each shape
     129
     130$outSHP = ''; # write the file
     131
     132undef $inSHP;
     133undef $outSHP;
     134
     135my $reduction = ((($outcount / $incount) * 100) - 100) * -1;
     136
     137print <<END;
     138
     139$0 Summary:
     140
     141Input File  : $infile  ($incount vertices)
     142Output File : $outfile ($outcount vertices)
     143Tolerance   : $tolerance
     144Reduction   : $reduction%
     145
     146END
     147
     148}}}