邪恶八进制信息安全团队技术讨论组's Archiver

冰血封情 2005-4-17 15:36

[转载]Inverse Distance Weighted TerraServer Mapping of wireless Networks

  文章作者:David M. Zendzian [email]dmz@dmzs.com[/email]

[code]#!/usr/bin/perl
#
# David M. Zendzian [email]dmz@dmzs.com[/email]
# 2002-07-21 - v0.9
# 2002-09-17 - v0.9rc1
#
# [url]http://carte.dmzs.com/index.html[/url]
#
# carte.pl [-h] [-t] [-d] [-s] [-o] [-m] [-y <opacity>] [-p <destpath>] -i <infile>
#  -i <scanfile>: input file from netstumbler text output (required)
#  -p <datapath>: where to store datafiles, default /tmp/
#  -y <opacity>: Set the opacity of the overlay images. Default 60
#  -t: Do not download terraserver map (offline and already have maps)
#     otherwise: Save terraserver map as <datapath>/<mac>/terramap.png
#  -s: create simple signal &#39;dots&#39; overlay image: <datapath>/<mac>/overlay-circle.png & merge with terramap for map-circle.png
#  -o: create SNR Overlay image: <datapath>/<mac>/overlay-idw.png & merge with terramap for map-idw.png
#  -m: Do not merge overlay with terramap
#  -d: debug
#  -h: this page
#
#   requires Image::Magick from [url]ftp://ftp.wizards.dupont.com/pub/ImageMagick/[/url]
#   requires Image::Grab from [url]http://mah.everybody.org/hacks/perl/Image-Grab/[/url] and cpan
#
# will parse <infile> which should be a NetStumbler text export with GPS scan info of the format:
# Latitude    Longitude     ( SSID )      Type   ( BSSID )     Time (GMT)    [ SNR Sig Noise ]     # ( Name )    Flags  Channelbits    BcnIntvl
#
# This data will be pushed into WarDrive hash
# Work will be done per each MAC
# Find center Latitude/Longitude
# Grab 3x3 image map from acme.com:
#  [url]www.acme.com/mapper/save.cgi?lat=<lat>&long=<W?-[/url]|><long>&scale=11&theme=Image&width=3&height=3&dot=No
# create overlay of all Sig found for MAC
# merge overlay with acme/terraserver image
# goto next MAC group
# --
#   Known Problems:
#       If Network Name is blank or has spaces then the split will break, bad regex :/
#       doesn&#39;t test input file for escapes in mac which would cause outputfile to be able to be written anywhere (don&#39;t run as root!)
#       Terraserver images are a little out of date (not much I can do about this, but if you know your area it might help :/
#         I will get to overlaying over streetmap @ future point
#       Acme mapper for some reason doesn&#39;t grab the image you request, but one a little offset :/
#
#   TODO:
#     provide gtk interface
#     create user defined image scale map
#     create animated view of idw-overlay creation
#     perldoc
#     inline::c optimizations
#   
# (C) 2002, DMZS, Inc -- [email]info@dmzs.com[/email]
#
# (BSD License)
# Copyright (c) 2002, David M. Zendzian/DMZ Service, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the
# distribution.
#
# Neither the name of DMZ Services, Inc  nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
# HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
# WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# p.s. If you are out to make $$ off this endevor, please consider dropping [email]dmz@dmzs.com[/email] a note so we can participate (:
#
# Greets & thanks go out to:
# --------------------------
# Tony <tony [at] berkeleywireless [dot] net> -- for getting me into this!
# Glenn [at] netmud [dot] com for the insite needed to make lat/long/pixel conversion work and allowing me to browse some of his code (see next line)
#  Contains portions (some modified) of Copyright 2002 (see below), Netmud, LLC.  All rights reserved: (getPixelWeight_Trivial distance_cmp getPixel getLatLong)
# W. Slavin <afr [at] netstumbler [dot] com> -- for making netstumbler & all of this possible
# Jeffrey A. Poskanzer <jeff [at] acme [dot] com> -- for such an awsome wrapper for terraserver & assistance with rad to deg conversion
# Mike Kershaw <dragorn [at] nerv-un [dot] net> -- for kismit & code that helped me understand what i was doing with deg to rad conversion :)
# Peter <shipley [at] dis [dot] org> -- for the wireless insight & views into other ways of mapping wireless networks
# Change [at] dmzs [dot] com -- for letting me borrow hardware, FIRE & being a general good human being
# tvsg [dot] org people for helping get my academic spirit flowing again
# Whole crew at W-F-B for listening to these crazy ideas
# My wife for letting me work too much
#
# NetMud License (getPixelWeight_Trivial distance_cmp getPixel getLatLong)
# Copyright (c) 2002 Netmud, LLC.  All rights reserved.
# #
# # Redistribution and use in source and binary forms, with or without
# # modification, are permitted provided that the following conditions
# # are met:
# # 1. Redistributions of source code must retain the above copyright
# #   notice, this list of conditions and the following disclaimer.
# # 2. Redistributions in binary form must reproduce the above copyright
# #   notice, this list of conditions and the following disclaimer in the
# #   documentation and/or other materials provided with the distribution.
# # 3. All advertising materials mentioning features or use of this software
# #   must display the following acknowledgement:
# #    This product includes software developed by Netmud, LLC
# # 4. The name of Netmud, LLC may not be used to endorse or promote products
# #    derived from this software without specific prior written permission.
# #
# # PORTIONS OF THIS SOFTWARE IS PROVIDED BY NETMUD ``AS IS&#39;&#39; AND ANY EXPRESS OR IMPLIED
# # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
# # NO EVENT SHALL NETMUD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# # Questions?  Email me at: [email]glenn@netmud.com[/email]
#
#

use Getopt::Std;
use Image::Grab;
use Image::Magick;
use Data::Dumper;
#use Curses;

#initscr();
&getopts(&#39;dhstmoy:p:i:&#39;);
use vars qw($opt_d,$opt_h,$opt_m,$opt_s,$opt_t,$opt_o,$opt_p,$opt_i,$opt_y,$datapath,$overlay_idw,$overlay_circle,$get_terra,$debug,$logfiledata);

# need to sync this with the size that terraserver returns and make cmd line variable
my $IMAGEWIDTH=600;
my $get_terra = 1;
my $merge_map = 1;

if (!$opt_i || $opt_h) { help(); }
if (!$opt_p) { $datapath = "/tmp/"; } else { $datapath = $opt_p; mkdir "$datapath" if !stat "$datapath"; }
if (!$opt_y) { $opacity=60; } else { $opacity=$opt_y; }
if ($opt_m) { $merge_map = 0; }
if ($opt_o) { $overlay_idw = 1; }
if ($opt_s) { $overlay_circle = 1; }
if ($opt_t) { $get_terra = 0; }
if ($opt_d) { $debug = 1; }

&ScanInputLog($opt_i);

my ($filename) = $opt_i;
my (@data, $mac, $ssid, $time, $tz, $lat_1, $lat, $long_1, $long, $type, $srn, $sig, $noise, $flags, $channelbits,
   $max_lat, $min_lat, $max_long, $min_long, $maplat, $maplong, $terraservermap, $map_circle, $map_idw, $long_width, $lat_height);
my %nodes_latlong = ( );
my %nodes = ( );
my $image_width = $IMAGEWIDTH;      # pixels
my $image_height = $image_width;    # the code assumes the image is square

banner("Processing",$filename) if $debug;

# For each mac address, process the datapoints
foreach $mac (sort keys %logfiledata) {
  banner("$mac",$filename) if $debug;
  mkdir "$datapath/$mac" if !stat "$datapath/$mac";

  ($max_lat, $min_lat, $max_long, $min_long, $maplat, $maplong) = findmaxmin_latlong($mac);

  ($min_lat, $max_lat, $min_long, $max_long) = process_datapoints($mac, $max_lat, $min_lat, $max_long, $min_long, $maplat, $maplong);

  $terraservermap=$datapath."/".$mac."/terramap.png";
  get_terramap($maplat,$maplong, $mac, $terraservermap) if $get_terra;

  ($map_circle) = create_overlay_circle($mac, $terraservermap, $min_long, $min_lat) if $overlay_circle;

  ($map_idw) = create_overlay_idw($mac, $terraservermap, $max_lat, $min_lat, $max_long, $min_long, $maplat, $maplong) if $overlay_idw;
}
banner("Processing Done",$filename) if $debug;
#endwin();
  

#end of program logic
# -------------------------------------------------------------------------------------------
# Subroutines

# Print Help
sub help {
  print("usage: ./carte.pl <options> -i <scanfile>\n");
  print("Available Options\n");
  print("\t-i <scanfile>: input file from netstumbler text output (required) \n");
  print("\t-p <datapath>: where to store datafiles, default /tmp/ \n");
  print("\t-y <opacity>: Set the opacity of the overlay images. Default 60 \n");
  print("\t-t: Do not download terraserver map (offline and already have maps)\n");
  print("\t   otherwise: Save terraserver map as <datapath>/<mac>/terramap.png\n");
  print("\t-s: create simple signal &#39;dots&#39; overlay image: <datapath>/<mac>/overlay-circle.png & merge with terramap for map-circle.png\n");
  print("\t-o: create SNR Overlay image: <datapath>/<mac>/overlay-idw.png & merge with terramap for map-idw.png\n");
  print("\t-m: Do not merge overlay with terramap\n");
  print("\t-d: debug\n");
  print("\t-h: this page\n");
  exit(0);
}

# Print banner
sub banner {
  my($banner_type, $banner_info) = @_;
  #clear();
  #refresh();
  print("\n#####################################################################\n");
  print("#######     $banner_type | $banner_info \n");
  print("#####################################################################\n\n");
}

sub ScanInputLog {
  my ($filename) = @_;
  my ($data, $counter, $lat_1,$lat,$long_1,$long,$ssid,$type,$mac,$time,$srn,$sig,$noise,$flags,$channelbits);

  banner("Parsing",$filename) if $debug;
  open(INPUTLOG, $filename) or die "Unable to open $filename $!\n";

  while (<INPUTLOG>) {
   # skip any lines that start with #
   next if /^#/;
   # use an array slice to select fields we want
   # note: this needs to be cleaned up & done better. If you have a ( ) with nothing for SSID or somewhere it expects info, it will cause all kinds of wierdness
   ($lat_1, $lat, $long_1, $long, $ssid, $type, $mac, $time, $tz, $srn, $sig, $noise, $name, $flags, $channelbits, $bcnintvl) = split(/[\s\ \[\]\(\)\#]+/);
   
   # skip any lines with lat and long of 0
   next if (($lat==0) && ($long==0));

   # change : to - for mac address
   $mac =~ s/:/-/g;
   
   ##print("$lat_1, $lat, $long_1, $long, $ssid, $type, $mac, $time, $tz, $srn, $sig, $noise, $name, $flags, $channelbits\n") if $debug;

   # push value into hash $logfiledata{mac}=({ssid, time, $tz, lat_1, lat, long_1, long, type, srn, sig, noise, flags, channelbits}, ...)
   $data = {SSID=>$ssid, TIME=>$time, TZ=>$tz, LAT1=>$lat_1, LAT=>$lat, LONG1=>$long_1, LONG=>$long, TYPE=>$type, SRN=>$srn, SIG=>$sig, NOISE=>$noise, FLAGS=>$flags, CHANNELBITS=>$channelbits};

   push (@{$logfiledata{"$mac"}},$data);
   
   ##banner("Dumping Logfiledata",$mac) if $debug;
   ##print Dumper @{$logfiledata{"$mac"}};
   ##banner("Done Dumping Logfiledata",$mac) if $debug;
  }
  close (INPUTLOG);
  banner("Parsing Complete",$filename) if $debug;
}

sub findmaxmin_latlong {
  my ($mac) = @_;
  my ($key, $data, $lat_1, $lat, $long_1, $long,
      $max_lat, $min_lat, $max_long, $min_long, $maplat, $maplong);

  banner("Finding Max & Min",$mac) if $debug;

  my $min_lat = 360;    # Assume the extremes
  my $min_long = 360;
  my $max_lat = -360;
  my $max_long = -360;

  $numcoords = 0;

  #
  # find max/min lat & long to get center of map needed
  print ("coord#\t| lat_1\t| lat\t\t| long_1| long\n") if $debug;

  foreach $data (@{$logfiledata{"$mac"}}) {
   $lat_1 = $data->{LAT1};
   $lat = $data->{LAT};
   $long_1 = $data->{LONG1};
   $long = $data->{LONG};

   $numcoords++;

   # Determine if lat/long is max/min.
   $lat *= -1 if $lat_1 eq "S";
   $long *= -1 if $long_1 eq "W";
   $min_lat = $lat if ($lat < $min_lat);
   $min_long = $long if ($long < $min_long);
   $max_lat = $lat if ($lat > $min_lat);
   $max_long = $long if ($long > $max_long);
   print ("$numcoords\t| $lat_1\t| $lat\t| $long_1\t| $long\n") if $debug;
  }

  # find center of coordinates
  $maplat = $max_lat - (($max_lat - $min_lat) / 2);
  $maplong = $max_long - (($max_long - $min_long) / 2);

  print ("\nmaplat=$maplat\t| maplong=$maplong\t| max_lat=$max_lat\t| min_lat=$min_lat\t| max_long=$max_long\t| min_long=$min_long\n") if $debug;
  print ("data range: $min_lat,$min_long-$max_lat,$max_long\n") if $debug;
  banner("Finding Max & Min complete",$mac) if $debug;
  return($max_lat, $min_lat, $max_long, $min_long, $maplat, $maplong);
}

sub get_terramap {
   my ($maplat,$maplong,$mac,$terraservermap) = @_;
   my ($url, $pic);

   # get map from acme and save under $datapath/$mac-terramap.png
   banner("Getting acme/terraserver map for ",$mac) if $debug;
   $url = "[url]http://www.acme.com/mapper/save.cgi?lat=[/url]".$maplat."&long=".$maplong."&scale=10&theme=Image&width=3&height=3&dot=No";
   print ("URL\t| $url\n\n") if $debug;
   $pic = new Image::Grab;
   $pic->regexp(&#39;.*save_image\.cgi.*&#39;);
   $pic->search_url($url);
   $pic->grab;
   
   # Now to save the image to disk
   # should just convert blob over to imagemagic image and pass back...
   # probably don&#39;t need to convert to png, but for alpha channel...
   open(IMAGE, ">terramap.jpg"); # || die "terramap.jpg: $!";
   binmode IMAGE;
   print IMAGE $pic->image;
   close IMAGE;
   $terramap = new Image::Magick;
   $terramap->Read("terramap.jpg");
   $terramap->Write($terraservermap);
   unlink("terramap.jpg");
   print("Filename\t| $terraservermap\n") if $debug;
   banner("Done Getting acme/terraserver map for ",$mac) if $debug;
}
   
# Convert lat/long to nearest pixel x/y
sub getPixel
{
  my ($lat, $long, $min_long, $min_lat, $long_width, $lat_height, $image_width, $image_height) = @_;
  my $x = ($long - $min_long) * ($image_width / $long_width);
  my $y = $image_height - ($lat - $min_lat) * ($image_height / $lat_height);
  return (int($x), int($y));
}

sub process_datapoints {
  my ($mac, $max_lat, $min_lat, $max_long, $min_long, $maplat, $maplong) = @_;
  my (@data, $ssid, $time, $tz, $lat_1, $lat, $long_1, $long, $type, $srn, $sig, $noise, $flags, $channelbits);

  banner("Processing datapoints, creating data hashes for overlays",$mac);
  # Plot imagepoints
  $numcoords=0;

  # Save the highest signal recorded at this lat/long, if there
  # are multiple:
  foreach $data (@{$logfiledata{"$mac"}}) {
   $lat_1 = $data->{LAT1};
   $lat = $data->{LAT};
   $long_1 = $data->{LONG1};
   $long = $data->{LONG};
   $srn = $data->{SRN};
   $numcoords++;
   $lat *= -1 if $lat_1 eq "S";
   $long *= -1 if $long_1 eq "W";
   my $latlong = $lat . "," . $long;
  
   if ( (! $nodes_latlong{$latlong}) || ($nodes_latlong{$latlong} < $srn) ) {
    $nodes_latlong{$latlong} = $srn;
   }
   print ("$numcoords\t| $lat_1\t| $lat\t| $long_1\t| $long\n") if $debug;
  }

  $long_width = ($max_long - $min_long) * 3.0;
  $lat_height = ($max_lat - $min_lat) * 3.0;

  print ("\nmin=$min_lat\t| min_long=$min_long\t| | max_lat=$max_lat\t| max_long=$max_long\n") if $debug;
  print ("data range: $min_lat,$min_long-$max_lat,$max_long\n") if $debug;
  print ("original width * 3=$long_width, height * 3=$lat_height\n") if $debug;

  # Adjust the lat/long range to be square (max of width & height):
  if ($long_width > $lat_height) {
   $lat_height = $long_width;
  } else {
   $long_width = $lat_height;
  }
  print ("adjusted width=$long_width, height=$lat_height\n") if $debug;

  # Adjust the data range to cover twice the area:
  my $middle_lat = ($min_lat + $max_lat) / 2.0;
  my $middle_long = ($min_long + $max_long) / 2.0;
  print ("middle_lat=$middle_lat, middle_long=$middle_long\n") if $debug;
  $min_lat = $middle_lat - ($lat_height / 2.0);
  $min_long = $middle_long - ($long_width / 2.0);
  $max_lat = $min_lat + $lat_height;
  $max_long = $min_long + $long_width;
  my $degrees_per_pixel = $long_width / $image_width;
  if (!$degrees_per_pixel) {
   print("Not enough data");
   return(0);
  }
  print ("one pixel is ", $degrees_per_pixel, " degrees of longitude.\n") if $debug;

  # Convert the &#39;nodes_latlong&#39; hash from lat/long to x/y:
  foreach my $key (keys(%nodes_latlong)) {
   my ($lat, $long) = split(&#39;,&#39;, $key);
   my ($x, $y) = getPixel($lat, $long, $min_long, $min_lat, $long_width, $lat_height, $image_width, $image_height);
   my $xy = $x . "," . $y;
   $nodes{$key} = $nodes_latlong{$key};   # just copy the data
   print ("xy=$xy\t| $nodes{$key}\n") if $debug;
  }
  banner("Done processing datapoints for overlays",$mac);
  return($min_lat,$max_lat,$min_long,$max_long);
}

sub create_overlay_circle {
  my ($mac, $terraservermap, $min_long, $min_lat) = @_;

  # Plot scan into image and save as $mac/overlay.png
  banner("Creating Simple-Circle Overlay Image",$mac) if $debug;

  # Create overlay image and have background be uniform grey with opacity channel set
  my $plotcircle = Image::Magick->new(size=>"${image_width}x${image_height}");
  my $g = 255 - $opacity/100 * 255;
  my $bgcolor = sprintf "#%02x%02x%02x%02x", $g,$g,$g,$g;
  $plotcircle->Read("xc:$bgcolor");

  # Plot Each signal onto overlay image
  foreach my $key (keys(%nodes_latlong)) {
   my ($lat, $long) = split(&#39;,&#39;, $key);
   my ($x, $y) = getPixel($lat, $long, $min_long, $min_lat, $long_width, $lat_height, $image_width, $image_height);
   my $right = 5 + $x;
   my $weight = $nodes_latlong{$key};
   my $color = &#39;red&#39;;
   if ($weight > 25) {
    $color = &#39;green&#39;;
    $right += 20;
   } elsif ($weight > 18) {
    $color = &#39;green&#39;;
    $right += 20;
   } elsif ($weight > 12) {
    $color = &#39;yellow&#39;;
    $right += 12;
   } elsif ($weight > 4) {
    $color = &#39;red&#39;;
    $right += 5;
   } elsif ($weight > 1) {
    $color = &#39;black&#39;;
    $right += 2;
   } else {
   }
   $plotcircle->Draw( primitive=>&#39;circle&#39;, fill=>$color, stroke=>$color, strokewidth=>1, points => "$x,$y $right,$y");
   print ("Draw( fill=>$color, stroke=>$color, strokewidth=>1, primitive => &#39;circle&#39;, points => $x,$y $right,$y weight=$weight\n") if $debug;
  }

  # Create transparancy mask and add to overlay
  my $mask = Image::Magick->new(size=>"${image_width}x${image_height}");
  my $g = 255 - $opacity/100 * 255;
  my $color = sprintf "#%02x%02x%02x", $g,$g,$g;
  $mask->Read("xc:$color");
  my $cur_mask = $plotcircle->Clone();
  $cur_mask->Channel(&#39;Matte&#39;);
  $rc = $mask->Composite(image => $cur_mask, compose => &#39;Plus&#39;);
  warn $rc if $rc;
  $rc = $plotcircle->Composite(image => $mask, compose => &#39;ReplaceMatte&#39;);
  warn $rc if $rc;

  # Write out the created overlay
  my $plotimage = $datapath."/".$mac."/overlay-circle.png";
  $plotcircle->Write($plotimage);
  print("\nFilename\t| $plotimage") if $debug;

  # Merge overlay with terramapfile
  if ($merge_map) {
   my $map_circle = Image::Magick->new();
   $map_circle->Read($terraservermap);
   $rc = $map_circle->Composite(image => $plotcircle, compose => &#39;Over&#39;);
   warn $rc if $rc;

   # Write out the terramap with simple circles overlayed
   my $mapimage = $datapath."/".$mac."/map-circle.png";
   $map_circle->Write($mapimage);
   print("\nFilename\t| $mapimage") if $debug;
  }
  banner("Done Creating Simple Image",$mac) if $debug;
  return($map_circle);
}

# Convert pixel x/y to lat/long
# # The way this works now returns the lat/long of the "top left" of the pixel.
# # XXX Maybe it should return the lat/long at the center instead.
sub getLatLong
{
  my ($x, $y, $max_lat, $min_long, $lat_height, $long_width, $image_height, $image_width) = @_;
  my $lat = $max_lat - ($y * $lat_height / $image_height);
  my $long = $min_long + ($x * $long_width / $image_width);
  ##print ("x=$x, y=$y, max_lat=$max_lat, min_long=$min_long, lat_height=$lat_height, long_width=$long_width, image_height=$image_height, image_width=$image_width, lat=$lat, long=$long\n");
  return ($lat, $long);
}

my $sort_lat = 0;
my $sort_long = 0;
sub distance_cmp
{
  my ($lat1, $long1) = split(&#39;,&#39;, $a);
  my ($lat2, $long2) = split(&#39;,&#39;, $b);
  my $dist1 = (($lat1 - $sort_lat)**2) + (($long1 - $sort_long)**2);
  my $dist2 = (($lat2 - $sort_lat)**2) + (($long2 - $sort_long)**2);
  return $dist1 <=> $dist2;
}

# Inline::C ??
# 2002/07/28 - Removed all code that was mentioned as not needed - DMZ
sub getPixelWeight_Trivial
{
  my ($x, $y, $max_lat, $min_long, $lat_height, $long_width, $image_height, $image_width, %nodes) = @_;
  my ($pix_lat, $pix_long) = getLatLong($x, $y, $max_lat, $min_long, $lat_height, $long_width, $image_height, $image_width);
  my $weight = 0;      # What we&#39;re returning
  my $weightcap = 0;    # The highest weight actually seen.  We never return a value greater than this (because signal isn&#39;t cumulative).
  my @nodekeys = keys(%nodes);

  ##print ("x=$x, y=$y, max_lat=$max_lat, min_long=$min_long, latheight=$lat_height, longwidth=$long_width, imageheight=$image_height, imagewidth=$image_width\n");
  ##print ("x=$x, y=$y, pix_lat=$pix_lat, pix_long=$pix_long\n");

  # Sort the node keys by distance to this point:
  $sort_lat = $pix_lat;
  $sort_long = $pix_long;
  my @sortedkeys = sort distance_cmp @nodekeys;
  # Only use the N closest nodes:
  # XXX This may break for data sets with less than 6 points:
  foreach my $i (0..6) {
   my $key = $sortedkeys[$i];
   my ($i_lat, $i_long) = split(&#39;,&#39;, $key);
   my $dist_i = ((($i_lat - $pix_lat)**2) + (($i_long - $pix_long)**2));
   ##print ("ilat=$i_lat\t| plat=$pix_lat\t| ilong=$i_long\t| plong=$pix_long\t| dist=$dist_i\n") if $debug;

   # Where did 0.000000025197117696 come from?  Great question!
   # Let me know if you figure it out!  I just screwed around
   # until I was happy with the output I was getting.
   # Maybe it&#39;s some kind of mapping between pixels & lat/long
   # (and should really relate to $degrees_per_pixel)
   $dist_i = (0.000000025197117696) / ($dist_i) unless ($dist_i eq 0);
   my $tempweight = $dist_i * $nodes{$key};
   $weightcap = $nodes{$key} if ($nodes{$key} > $weightcap);
   ##print ("dist=$dist_i\t| tempweight=$tempweight\t| weight=$nodes{$key}\t| W=$weight\n") if $debug;
   if ($tempweight > 0.000001) {
    # If the weight is close enough to 0, don&#39;t bother counting this data point.  (hack)
    $weight += $tempweight;
   }
  }
  $weight = $weightcap if ($weight > $weightcap); # Cap at weightcap
  #print ("Weight\t| $weight\n") if $debug;
  return ($weight);
}

sub create_overlay_idw {
  my ($mac, $terraservermap, $max_lat, $min_lat, $max_long, $min_long, $maplat, $maplong) = @_;
  my (@data, $ssid, $time, $tz, $lat_1, $lat, $long_1, $long, $type, $srn, $sig, $noise, $flags, $channelbits);
  my @weights = ();             # One per pixel
  my $minweight = 999999999;
  my $maxweight = 0;
  my $weightsum = 0;
   
  # Loop through all the pixels in the output and calculate the weight for each:
  foreach my $x_pix (0..$image_width) {
   foreach my $y_pix (0..$image_height) {
    $weights[$x_pix][$y_pix] = getPixelWeight_Trivial($x_pix, $y_pix, $max_lat, $min_long, $lat_height, $long_width, $image_height, $image_width, %nodes);
    $minweight = $weights[$x_pix][$y_pix] if ($weights[$x_pix][$y_pix] < $minweight);
    print ("for $x_pix, $y_pix, weight=$weights[$x_pix][$y_pix], minweight=$minweight\n") if (($x_pix eq $y_pix) && $debug);
    #print ("for $x_pix, $y_pix, weight=$weights[$x_pix][$y_pix], minweight=$minweight\n") if $debug;
   }
  }
  
  # Create overlay image and have background be uniform grey with opacity channel set
  my $plotidw = Image::Magick->new(size=>"${image_width}x${image_height}");
  my $g = 255 - $opacity/100 * 255;
  my $bgcolor = sprintf "#%02x%02x%02x%02x", $g,$g,$g,$g;
  $plotidw->Read("xc:$bgcolor");

  print ("Generating overlay image:\n") if $debug;
  # The colors used here are just what I liked.  Tweak &#39;em, make &#39;em configurable, whatever:
  foreach my $x_pix (0..$image_width) {
   foreach my $y_pix (0..$image_height) {
    my $weight = $weights[$x_pix][$y_pix];
    my $red = $g;
    my $green = $g;
    my $blue = $g;
    if ($weight > 25) {
      $red = 100; #int(128 * $weight);
      $green = 133;
      $blue = 142;
    } elsif ($weight > 18) {
      $red = 122;
      $green = 165; #int(128 * ($weight + 0.4));
      $blue = 128;
    } elsif ($weight > 12) {
      $red = 168;
      $green = 181; #int(128 * ($weight + 0.4));
      $blue = 112;
    } elsif ($weight > 4) {
      $red = 183;
      $green = 162;
      $blue = 71;
    } elsif ($weight > 1) {
      $red = 172;
      $green = 152;
      $blue = 119;
    } else {
      $red = $green = $blue = $g;
    }
    my $colorstring = sprintf("#%02x%02x%02x%02x", $red, $green, $blue, $g);
    if (length($colorstring) > 9) {
      print ("red=$red, green=$green, blue=$blue, weight=$weight\n") if $debug;
    }
    $plotidw->Set("Pixel[$x_pix,$y_pix]"=>$colorstring);
    print ("x=$x_pix,y=$y_pix\t| colorstring = $colorstring\n") if ($debug && ($x_pix eq $y_pix));
   }
  }

  # Create transparancy mask and add to overlay
  my $mask = Image::Magick->new(size=>"${image_width}x${image_height}");
  my $g = 255 - $opacity/100 * 255;
  my $color = sprintf "#%02x%02x%02x", $g,$g,$g;
  $mask->Read("xc:$color");
  my $cur_mask = $plotidw->Clone();
  $cur_mask->Channel(&#39;Matte&#39;);
  $rc = $mask->Composite(image => $cur_mask, compose => &#39;Plus&#39;);
  warn $rc if $rc;
  $rc = $plotidw->Composite(image => $mask, compose => &#39;ReplaceMatte&#39;);
  warn $rc if $rc;

  # Write out the created overlay
  my $plotimage = $datapath."/".$mac."/overlay-idw.png";
  $plotidw->Write($plotimage);
  print("\nFilename\t| $plotimage") if $debug;

  # Merge overlay with terramapfile
  if ($merge_map) {
   my $map_idw = Image::Magick->new();
   $map_idw->Read($terraservermap);
   $rc = $map_idw->Composite(image => $plotidw, compose => &#39;Over&#39;);
   warn $rc if $rc;
   my $mapimage = $datapath."/".$mac."/map-idw.png";
   $map_idw->Write($mapimage);

   # Write out the terramap with idw overlayed
   print("\nFilename\t| $mapimage") if $debug;
  }

  banner("Done Creating Overlay Image",$mac) if $debug;
  return($map_idw) if $merge_map;
}[/code]

页: [1]
© 1999-2008 EvilOctal Security Team