# intensityProcessor
# Copyright (C) 2022 Cliff Hammett
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
#################### META ###############################################################################
# Title : intensityProcessor.pm #
# Purpose : processes GPS and stimulation data #
# By : Cliff Hammett #
# #
# #
#################### PREQUISITES ########################################################################
# perl : tested on perl v5.26.1. Should run on other versions! #
# GIS::Distance : perl GIS library, available on CPAN #
# Math::Trig : perl trigonometry library, available on CPAN #
# #
# This module was written for operating on linux systems. It will probably run on Macs. It may need #
# some modification to run on windows #
# #
#################### USAGE ##############################################################################
# This module is used by peakSoundSplit #
#########################################################################################################
package intensityProcessor {
use strict;
use warnings;
use GIS::Distance;
use Math::Trig;
sub new{
my ($class, $rah, $start, $md, $ll) = @_;
my @poi = ();
my $this = {
_gis => GIS::Distance->new(),
_rah => $rah,
_p => 0,
_start => $start,
_lc => 0,
_spike => 0,
_maxDist => $md,
_legLen => $ll,
_poi => \@poi
};
bless $this, $class;
return $this;
}
sub initRecord{
my ($this, $i, $l) = @_;
print "initRecord\n";
my @loc = ($this->initLocEntry($i));
my $template = {
lat => 'tbc',
lon => 'tbc',
timeSt => $this->{_rah}->[$i]->{time},
timeTo => "tbc",
millisSt => $this->{_rah}->[$i]->{millis},
millisTo => "tbc",
intens_ttl => 0,
intens_avg => 0,
leg => $l,
rah_loc => \@loc,
};
$this->{_out}->[$this->{_p}] = $template;
$this->{_lc} = 0;
}
sub initLocEntry{
my ($this, $i) = @_;
my $rh_loc = {
lat => $this->{_rah}->[$i]->{lat},
lon => $this->{_rah}->[$i]->{lon},
st => $this->{_rah}->[$i]->{millis},
to => -1
} ;
return $rh_loc;
}
sub process{
my $this = shift;
$this->initRecord($this->{_start}, 0);
my $size = @{$this->{_rah}};
my $pspike = 0;
my %leg = (
st => $this->{_rah}->[$this->{_start}]->{millis},
no => 0
);
for (my $i=$this->{_start}+1; $i<$size-1; $i++){
my $r = $this->{_rah}->[$i];
my $o = $this->{_out}->[$this->{_p}];
print "$r->{spike} vs $pspike\n";
if ($pspike != $r->{spike}){ #check if spike state has changed
print "peak change detected\n";
$o->{intens_ttl} += $r->{spike};
}
$pspike = $r->{spike};
print "looking at $this->{_p}, point $this->{_lc}\n";
my $rl = $o->{rah_loc}->[$this->{_lc}];
if ($r->{lat} != $rl->{lat} || $r->{lon} != $rl->{lon}){ # has location changed?
my $rp = $this->{_rah}->[$i-1];
$rl->{to} = $rp->{millis};
my $rs = $o->{rah_loc}->[0];
my $dist = $this->getDistance($r,$rs);
print "$dist\n";
my $maxDist = $this->{_maxDist} - (sqrt($o->{intens_ttl})*5+($o->{intens_ttl}/6)); #experimental difference variance on stimulation
if($dist > $maxDist){ #is this more than the max distance for a geopoint?
$this->completeOutPoint($i);
$this->legAndPoiCheck($rp, \%leg);
$this->initRecord($i, $leg{no});
}else{
push @{$o->{rah_loc}}, $this->initLocEntry($i);
$this->{_lc} = @{$o->{rah_loc}}-1;
}
}
}
$this->completeOutPoint($size-1, \%leg);
$this->processPointsOfInterest($leg{st}, $this->{_rah}->[$size-1]->{millis});
return $this->{_out};
}
sub completeOutPoint{
my ($this, $i) = @_;
print "distance exceeded\n";
my $rp = $this->{_rah}->[$i-1];
my $o = $this->{_out}->[$this->{_p}];
$o->{timeTo} = $rp->{time};
$o->{millisTo} = $rp->{millis};
my $hv = ($o->{intens_ttl} * 50000) / ($o->{millisTo} - $o->{millisSt});
$o->{intens_avg} = int(sqrt($hv+$o->{intens_ttl}));
$this->avgGPS;
$this->{_p}++;
}
sub legAndPoiCheck{
my ($this, $rp, $leg) = @_;
my $rtn;
if ($rp->{millis} - $leg->{st} > $this->{_legLen}){#have we had the alloted time for this leg?
$this->processPointsOfInterest($leg->{st}, $rp->{millis});
$leg->{no}++;
$leg->{st} = $rp->{millis};
$rtn = 1;
}else{
$rtn = 0;
}
return $rtn
}
sub processPointsOfInterest{
my ($this, $milSt, $milEnd) = @_;
my $size = @{$this->{_rah}};
my $poiState = 0;
my @poiSet;
my %mon = (lat => 0,
lon => 0,
millis => 0);
for (my $i=0; $i+1<$size && $this->{_rah}->[$i]->{millis} < $milEnd; $i++){
my $r = $this->{_rah}->[$i];
if ($r->{millis} > $milSt){
if ($mon{lat} != $r->{lat} || $mon{lon} != $r->{lon}){
my $psize = @poiSet;
for (my $k=0; $k < $psize; $k++){
if (!$poiSet[$k]->{millisEnd} || !$poiSet[$k]->{latEnd}){
$poiSet[$k]->{millisEnd} = $r->{millis};
$poiSet[$k]->{latEnd} = $r->{lat};
$poiSet[$k]->{lonEnd} = $r->{lon};
}
}
%mon = (lat => $r->{lat},
lon => $r->{lon},
millis => $r->{millis});
}
if ($r->{interest} == 1 && $poiState == 0){
$poiState = 1;
print "entering point of interest at lat: $r->{lat}, lon: $r->{lon}, millis: $r->{millis}\n";
my %poi = ( latInterest => $r->{lat},
lonInterest => $r->{lon},
millisInterest => $r->{millis},
millisSt => $mon{millis});
push @poiSet, \%poi;
} elsif ($r->{interest} == 0 && $poiState == 1){
$poiState = 0;
}
}
}
push @{$this->{_poi}}, \@poiSet;
}
sub getDistance{
my ($this, $loc1, $loc2,) = @_;
my $distance = $this->{_gis}->distance( $loc1->{lat}, $loc1->{lon} => $loc2->{lat}, $loc2->{lon} );
return $distance->meters;
}
sub avgGPS{
my ($this) = @_;
my $o = $this->{_out}->[$this->{_p}];
my $rah_co = $o->{rah_loc};
my $size = @{$rah_co};
my $totweight = 0;
my $x = 0;
my $y = 0;
my $z = 0;
for (my $i=0; $i<$size; $i++){
print "lat $rah_co->[$i]->{lat} lon $rah_co->[$i]->{lon}\n";
my $radlat = $rah_co->[$i]->{lat} * (pi/180);
my $radlon = $rah_co->[$i]->{lon} * (pi/180);
#my $w = $rah_co->[$i]->{to} - $rah_co->[$i]->{st};
my $w = 1;
$totweight += $w;
$x += (cos($radlat) * cos($radlon)) * $w;
$y += (cos($radlat) * sin($radlon)) * $w;
$z += sin($radlat) * $w;
}
my $x_avg = $x/$totweight;
my $y_avg = $y/$totweight;
my $z_avg = $z/$totweight;
my $Lon = atan2($y_avg, $x_avg);
my $Hyp = sqrt(($x_avg * $x_avg) + ($y_avg * $y_avg));
my $Lat = atan2($z_avg, $Hyp);
$o->{lat} = $Lat * (180/pi);
$o->{lon} = $Lon * (180/pi);
}
}
1;