Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- =cut
- correct_point_names_in_FBK_data.pl
- Cleans raw field survey data in fieldbook (FBK) format by renaming all
- points according to their position to ease the reporting of deformation
- monitoring surveys.
- This program solves the following problem:
- We've done a monitoring survey. We want to make sure that all the points
- are named correctly. Sometimes points are named incorrectly by the
- surveyor working in the field. This makes it more difficult to process
- the data and create the report. This program automatically renames every
- point based on its position. And it gives you in the summary a list of
- any points it could not match by coordinates, which it’s up to you to
- decide what to do with.
- Data Formats:
- In the FBK file, angles can be in either decimal degrees (default) or
- DMS (DDD.MMSS) format. You have to tell this program which format your
- data is in.
- The coordinate database file must be a comma separated values file with
- this format: PointName, Northing, Easting, Height
- Usage Syntax:
- perl correct_point_names_in_FBK_data.pl
- angle_format # Specify decimal or dms, (decimal is default)
- input_file_name
- coordinate_database_file_name # Current coordinates are best
- output_path
- output_file_name
- log_file_name
- summary_file_name
- Usage Notes:
- full path must be given for:
- input_file_name
- coordinate_database_file_name
- output_path applies to: output_file_name, log_file_name, summary_file_name
- Usage Example:
- perl correct_point_names_in_FBK_data.pl decimal "C:\temp\monitor1\1-RawDataConversion\Epoch10\RawDataFromTPSObsReport.txt" "C:\temp\monitor1\AllPointsCurrentCoordinates.csv" "C:\temp\monitor1\1-RawDataConversion\Epoch10" "point_names_corrected.fbk" "point_names_correction_log.txt" "point_names_correction_summary.txt"
- =cut
- use strict;
- use warnings;
- my $huge = 9E99;
- sub Deg2Rad
- {
- my $angle = shift;
- return $angle * 0.01745329251;
- }
- sub sinD
- {
- my $angle = shift;
- return sin(Deg2Rad($angle));
- }
- sub cosD
- {
- my $angle = shift;
- return cos(Deg2Rad($angle));
- }
- sub dms2deg
- {
- my $x = shift;
- my $d = int $x;
- my $f = $x - $d;
- my $m = int(100.0 * $f);
- if ($m == 99) {
- $m = 59;
- }
- my $s = 10000.0 * ($f - 0.01 * $m);
- if ($s >= 99.9) {
- $s = 0.0;
- $m++;
- }
- if ($m == 60) {
- $m = 0;
- $d++;
- }
- return $d + ($m + $s / 60.0) / 60.0;
- }
- # settings / configuration
- my $max_sd = 0.06; # Maximum allowable slope distance for matching points to reference coordinates
- my $units = "m"; # m = metres
- my $angle_format = $ARGV[0];
- my $input_file = $ARGV[1];
- my $coord_db_file = $ARGV[2];
- my $output_path = $ARGV[3];
- my $output_file = $ARGV[4];
- my $log_file = $ARGV[5];
- my $summary_file = $ARGV[6];
- use constant
- {
- DECIMAL => 0,
- DMS => 1
- };
- if (lc($angle_format) eq "dms")
- {
- $angle_format = DMS;
- }
- else
- {
- $angle_format = DECIMAL;
- }
- sub fullpath
- {
- my $file = shift;
- return $output_path . "\\" . $file;
- }
- $output_file = fullpath($output_file);
- $log_file = fullpath($log_file);
- $summary_file = fullpath($summary_file);
- open my $handle, '<', $input_file;
- chomp(my @lines = <$handle>);
- close $handle;
- open $handle, '<', $coord_db_file;
- chomp(my @coord_db_lines = <$handle>);
- close $handle;
- open (LOGFILE, ">$log_file");
- open (SUMMARYFILE, ">$summary_file");
- print SUMMARYFILE "Summary for the process of making sure that all the points are named correctly.\n";
- print LOGFILE "Loading coordinates of points from database file \"$coord_db_file\"\n";
- my %coords = (); #HoA
- foreach my $line (@coord_db_lines)
- {
- if (length($line) > 0)
- {
- if ($line =~ /^([\w\s\.]+),([0-9\.-]+),([0-9\.-]+),([0-9\.-]+)$/)
- {
- # Pt, N, E, H
- my $pt = $1;
- my $n = $2;
- my $e = $3;
- my $h = $4;
- if (!exists($coords{$pt}))
- {
- push @{ $coords{$pt} }, $n;
- push @{ $coords{$pt} }, $e;
- push @{ $coords{$pt} }, $h;
- print LOGFILE "Loaded $pt.\n";
- }
- else
- {
- print LOGFILE "Point $pt already seen, so ignoring input line:\n$line\n";
- }
- }
- }
- }
- #system("pause");
- my $stn_id;
- my $stn_n;
- my $stn_e;
- my $stn_h;
- my $stn_hi;
- my $ht = 0.0;
- my $have_put_stn_line_in_summary = 0;
- my $stn_line = "";
- print LOGFILE "Reading FBK input file \"$input_file\"\n";
- print LOGFILE "Traversing and checking coordinates relative to points in database.\n";
- open (FILEOUT, ">$output_file");
- my $max_d = 0.0;
- my $max_pt;
- my @summary_lines = ();
- foreach my $line (@lines)
- {
- if (length($line) > 0)
- {
- if ($line eq "!Setup")
- {
- print FILEOUT "$line\n";
- }
- elsif ($line =~ /^NEZ "([\w\s\.]+)" ([0-9\.-]+ [0-9\.-]+ [0-9\.-]+)$/)
- {
- my $coords = $2;
- ($stn_n, $stn_e, $stn_h) = split / /, $coords;
- print FILEOUT "$line\n";
- }
- elsif ($line =~ /^STN "([\w\s\.]+)" ([0-9\.-]+)/)
- {
- $stn_id = $1;
- $stn_hi = $2;
- $stn_line = "New Station: $stn_id HI = $stn_hi NEH ($stn_n $stn_e $stn_h)";
- print LOGFILE "\n$stn_line\n";
- print FILEOUT "$line\n";
- print LOGFILE "Input Data Line, Given Point Name, Calculated Coordinates Northing, Easting, Height, >>> Closest Point By Coordinates, Slope Distance, Passed / Exceeded Allowable Coordinate Difference, Point Named Correctly, Renaming Point\n";
- $have_put_stn_line_in_summary = 0;
- }
- elsif ($line =~ /^F([\w]+) VA "([\w\s\.]+)" ([0-9\.-]+) ([0-9\.-]+) ([0-9\.-]+)$/)
- {
- my $face = $1;
- my $pt_id = $2;
- my $hz = $3;
- my $sd = $4;
- my $za = $5;
- my $hz_; #for internal use only
- my $za_; #for internal use only
- if ($angle_format == DECIMAL)
- {
- #angles are good
- $hz_ = $hz;
- $za_ = $za;
- }
- else
- {
- #convert angles from DMS into decimal
- $hz_ = dms2deg($hz);
- $za_ = dms2deg($za);
- }
- my $hd = $sd * sinD($za_);
- my $dh = $sd * cosD($za_) + $stn_hi - $ht;
- # traverse
- my $pt_n = $stn_n + $hd * cosD($hz_);
- my $pt_e = $stn_e + $hd * sinD($hz_);
- my $pt_h = $stn_h + $dh;
- my $rounded_coords = sprintf("%.3f, %.3f, %.3f", $pt_n, $pt_e, $pt_h);
- #print LOGFILE "Traversed to: $pt_id at NEH ($rounded_coords)\n";
- print LOGFILE "$line, $pt_id, $rounded_coords";
- =cut
- # lookup this point by name
- if ($coords{$pt_id})
- {
- my ($n, $e, $h) = $coords{$pt_id};
- my $dn = $pt_n - $n;
- my $de = $pt_e - $e;
- my $dh = $pt_h - $h;
- print "Differences from reference coordinates: NEH ($dn $de $dh)\n";
- }
- else
- {
- print "We do not have coordinates for this point number.\n";
- }
- =cut
- # find the closest point by coordinates
- my $min_d = $huge;
- my $min_hd = $huge;
- my $min_vdiff = $huge;
- my $min_pt;
- for my $pt ( keys %coords )
- {
- my @dbcoords = @{$coords{$pt}};
- my $n = $dbcoords[0];
- my $e = $dbcoords[1];
- my $h = $dbcoords[2];
- my $dn = $pt_n - $n;
- my $de = $pt_e - $e;
- my $dh = $pt_h - $h;
- my $dist_hd = sqrt($dn**2 + $de**2); # horizontal distance
- my $dist_3d = sqrt($dn**2 + $de**2 + $dh**2); # 3D slope distance
- if ($dist_3d < $min_d)
- {
- $min_d = $dist_3d;
- $min_pt = $pt;
- $min_hd = $dist_hd;
- $min_vdiff = $dh;
- }
- }
- my $rounded = sprintf("%.3f", $min_d);
- #print LOGFILE "Closest point by coordinates: $min_pt, slope distance = $rounded\n";
- print LOGFILE ", >>> $min_pt, $rounded";
- if ($min_d > $max_sd)
- {
- #print LOGFILE "Distance exceeds maximum allowable slope distance for matching points to reference coordinates.\n";
- #print LOGFILE "Input data line:\n$line\n";
- print LOGFILE ", Exceeded, ,\n";
- print FILEOUT "$line\n";
- if (!$have_put_stn_line_in_summary)
- {
- push @summary_lines, "\n$stn_line\n";
- $have_put_stn_line_in_summary = 1;
- }
- push @summary_lines, "\n $line\n";
- my $rounded_hd = sprintf("%.3f", $min_hd);
- my $rounded_vdiff = sprintf("%.3f", $min_vdiff);
- push @summary_lines, " Closest point: $min_pt\n slope distance = $rounded\n horizontal dist = $rounded_hd\n vertical diff = $rounded_vdiff\n";
- }
- else
- {
- # track maximum allowed distance and which point was measured
- if ($min_d > $max_d)
- {
- $max_d = $min_d;
- $max_pt = $min_pt;
- }
- if ($min_pt eq $pt_id)
- {
- #print LOGFILE "Point was named correctly.\n";
- print LOGFILE ", Passed, Named Correctly,\n";
- print FILEOUT "$line\n";
- }
- else
- {
- #print LOGFILE "Renaming point to $min_pt\n";
- print LOGFILE ", Passed, , Renaming\n";
- $pt_id = $min_pt;
- print FILEOUT "F$face VA \"$pt_id\" $hz $sd $za\n";
- }
- }
- }
- elsif ($line =~ /^PRISM ([0-9\.-]+)$/)
- {
- $ht = $1;
- print LOGFILE "New prism height " . $ht . "\n";
- print FILEOUT "$line\n";
- }
- }
- }
- print SUMMARYFILE "\nEvery point that was coordinated within the tolerance of $max_sd $units has been renamed (unless it was already named correctly).\n";
- my $rounded = sprintf("%.3f", $max_d);
- print SUMMARYFILE "\nThe maximum allowed slope distance within the tolerance was $rounded for point $max_pt\n";
- print SUMMARYFILE "\nFor all measurements listed below, the slope distance from the closest point in the database exceeds the maximum allowable slope distance for matching points to reference coordinates. Therefore these points as measured are not recognized and it's up to you what you want to do with them.\n";
- foreach my $line (@summary_lines)
- {
- print SUMMARYFILE $line;
- }
- close (FILEOUT);
- close (LOGFILE);
- close (SUMMARYFILE);
- print "\nGenerated Summary file : \"$summary_file\"\n";
- print "\nGenerated Output file (FBK data with point names corrected) : \"$output_file\"\n";
- print "\nGenerated Log file : \"$log_file\"\n";
Add Comment
Please, Sign In to add comment