diff options
Diffstat (limited to 'FS')
-rw-r--r-- | FS/FS/Mason.pm | 1 | ||||
-rw-r--r-- | FS/FS/Schema.pm | 20 | ||||
-rw-r--r-- | FS/FS/sector_coverage.pm | 133 | ||||
-rw-r--r-- | FS/FS/tower.pm | 2 | ||||
-rw-r--r-- | FS/FS/tower_sector.pm | 45 | ||||
-rw-r--r-- | FS/MANIFEST | 2 | ||||
-rw-r--r-- | FS/t/sector_coverage.t | 5 |
7 files changed, 196 insertions, 12 deletions
diff --git a/FS/FS/Mason.pm b/FS/FS/Mason.pm index ee87b2de4..041b76c10 100644 --- a/FS/FS/Mason.pm +++ b/FS/FS/Mason.pm @@ -416,6 +416,7 @@ if ( -e $addl_handler_use_file ) { use FS::commission_schedule; use FS::commission_rate; use FS::saved_search; + use FS::sector_coverage; # Sammath Naur if ( $FS::Mason::addl_handler_use ) { diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index ced377592..66b9a51c3 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -4886,7 +4886,8 @@ sub tables_hashref { 'sector_range', 'decimal', 'NULL', '', '', '', #? 'downtilt', 'decimal', 'NULL', '', '', '', 'v_width', 'int', 'NULL', '', '', '', - 'margin', 'decimal', 'NULL', '', '', '', + 'db_high', 'int', 'NULL', '', '', '', + 'db_low', 'int', 'NULL', '', '', '', 'image', 'blob', 'NULL', '', '', '', 'west', 'decimal', 'NULL', '10,7', '', '', 'east', 'decimal', 'NULL', '10,7', '', '', @@ -4903,6 +4904,23 @@ sub tables_hashref { ], }, + 'sector_coverage' => { + 'columns' => [ + 'coveragenum', 'serial', '', '', '', '', + 'sectornum', 'int', '', '', '', '', + 'db_loss', 'int', '', '', '', '', + 'geometry', 'text', 'NULL', '', '', '', + ], + 'primary_key' => 'coveragenum', + 'unique' => [], + 'index' => [], + 'foreign_keys' => [ + { columns => [ 'sectornum' ], + table => 'tower_sector' + }, + ], + }, + 'part_virtual_field' => { 'columns' => [ 'vfieldpart', 'serial', '', '', '', '', diff --git a/FS/FS/sector_coverage.pm b/FS/FS/sector_coverage.pm new file mode 100644 index 000000000..fa6a9e154 --- /dev/null +++ b/FS/FS/sector_coverage.pm @@ -0,0 +1,133 @@ +package FS::sector_coverage; +use base qw( FS::Record ); + +use strict; +use FS::Record qw( qsearch qsearchs ); +use Cpanel::JSON::XS; + +=head1 NAME + +FS::sector_coverage - Object methods for sector_coverage records + +=head1 SYNOPSIS + + use FS::sector_coverage; + + $record = new FS::sector_coverage \%hash; + $record = new FS::sector_coverage { 'column' => 'value' }; + + $error = $record->insert; + + $error = $new_record->replace($old_record); + + $error = $record->delete; + + $error = $record->check; + +=head1 DESCRIPTION + +An FS::sector_coverage object represents a coverage map for a sector at +a specific signal strength level. FS::sector_coverage inherits from +FS::Record. The following fields are currently supported: + +=over 4 + +=item coveragenum + +primary key + +=item sectornum + +L<FS::tower_sector> foreign key + +=item db_loss + +The maximum path loss shown on this map, in dB. + +=item geometry + +A GeoJSON Geometry object for the area covered at this level. + +=back + +=head1 METHODS + +=over 4 + +=item new HASHREF + +Creates a new map. To add the example to the database, see L<"insert">. + +Note that this stores the hash reference, not a distinct copy of the hash it +points to. You can ask the object for a copy with the I<hash> method. + +=cut + +# the new method can be inherited from FS::Record, if a table method is defined + +sub table { 'sector_coverage'; } + +=item insert + +Adds this record to the database. If there is an error, returns the error, +otherwise returns false. + +=item delete + +Delete this record from the database. + +=item replace OLD_RECORD + +Replaces the OLD_RECORD with this one in the database. If there is an error, +returns the error, otherwise returns false. + +=cut + +# the replace method can be inherited from FS::Record + +=item check + +Checks all fields to make sure this is a valid example. If there is +an error, returns the error, otherwise returns false. Called by the insert +and replace methods. + +=cut + +# the check method should currently be supplied - FS::Record contains some +# data checking routines + +sub check { + my $self = shift; + + my $error = + $self->ut_numbern('coveragenum') + || $self->ut_number('sectornum') + || $self->ut_number('db_loss') + ; + return $error if $error; + + if ( length($self->geometry) ) { + # make sure it parses at least + local $@; + my $data = eval { decode_json($self->geometry) }; + if ( $@ ) { + # limit the length, in case it decides to return a large chunk of data + return "Error parsing coverage geometry: ".substr($@, 0, 100); + } + } + + $self->SUPER::check; +} + +=back + +=head1 BUGS + +=head1 SEE ALSO + +L<FS::Record> + +=cut + +1; + diff --git a/FS/FS/tower.pm b/FS/FS/tower.pm index f371ec9c7..a05160c4c 100644 --- a/FS/FS/tower.pm +++ b/FS/FS/tower.pm @@ -143,7 +143,7 @@ default sector. sub process_o2m { my $self = shift; my %opt = @_; - my $params = $opt{params}; + my $params = +{ %{$opt{params}} }; # Adjust to make sure our default sector is in the list. my $default_sector = $self->default_sector diff --git a/FS/FS/tower_sector.pm b/FS/FS/tower_sector.pm index 3fadc8685..acead9089 100644 --- a/FS/FS/tower_sector.pm +++ b/FS/FS/tower_sector.pm @@ -4,6 +4,7 @@ use base qw( FS::Record ); use Class::Load qw(load_class); use File::Path qw(make_path); use Data::Dumper; +use Cpanel::JSON::XS; use strict; @@ -75,10 +76,13 @@ The antenna beam elevation in degrees below horizontal. The -3dB vertical beamwidth in degrees. -=item margin +=item db_high -The signal loss margin allowed on the sector, in dB. This is normally -transmitter EIRP minus receiver sensitivity. +The signal loss margin to treat as "high quality". + +=item db_low + +The signal loss margin to treat as "low quality". =item image @@ -149,7 +153,8 @@ sub check { || $self->ut_numbern('v_width') || $self->ut_numbern('downtilt') || $self->ut_floatn('sector_range') - || $self->ut_numbern('margin') + || $self->ut_numbern('db_high') + || $self->ut_numbern('db_low') || $self->ut_anything('image') || $self->ut_sfloatn('west') || $self->ut_sfloatn('east') @@ -201,7 +206,7 @@ sub need_fields_for_coverage { downtilt => 'Downtilt', width => 'Horiz. width', v_width => 'Vert. width', - margin => 'Signal margin', + db_high => 'High quality', latitude => 'Latitude', longitude => 'Longitude', ); @@ -261,6 +266,7 @@ sub process_generate_coverage { my $tower = $sector->tower; load_class('Map::Splat'); + # since this is still experimental, put it somewhere we can find later my $workdir = "$FS::UID::cache_dir/cache.$FS::UID::datasrc/" . "generate_coverage/sector$sectornum-". time; @@ -274,9 +280,9 @@ sub process_generate_coverage { h_width => $sector->width, tilt => $sector->downtilt, v_width => $sector->v_width, - max_loss => $sector->margin, - min_loss => $sector->margin - 80, + db_levels => [ $sector->db_low, $sector->db_high ], dir => $workdir, + #simplify => 0.0004, # remove stairstepping in SRTM3 data? ); $splat->calculate; @@ -284,11 +290,30 @@ sub process_generate_coverage { foreach (qw(west east south north)) { $sector->set($_, $box->{$_}); } - $sector->set('image', $splat->mask); - # mask returns a PNG where everything below max_loss is solid colored, - # and everything above it is transparent. More useful for our purposes. + $sector->set('image', $splat->png); my $error = $sector->replace; die $error if $error; + + foreach ($sector->sector_coverage) { + $error = $_->delete; + die $error if $error; + } + # XXX undecided whether Map::Splat should even do this operation + # or how to store it + # or anything else + $DB::single = 1; + my $data = decode_json( $splat->polygonize_json ); + for my $feature (@{ $data->{features} }) { + my $db = $feature->{properties}{level}; + my $coverage = FS::sector_coverage->new({ + sectornum => $sectornum, + db_loss => $db, + geometry => encode_json($feature->{geometry}) + }); + $error = $coverage->insert; + } + + die $error if $error; } =head1 BUGS diff --git a/FS/MANIFEST b/FS/MANIFEST index 73a740f63..10dda5948 100644 --- a/FS/MANIFEST +++ b/FS/MANIFEST @@ -876,3 +876,5 @@ FS/commission_rate.pm t/commission_rate.t FS/saved_search.pm t/saved_search.t +FS/sector_coverage.pm +t/sector_coverage.t diff --git a/FS/t/sector_coverage.t b/FS/t/sector_coverage.t new file mode 100644 index 000000000..b30415888 --- /dev/null +++ b/FS/t/sector_coverage.t @@ -0,0 +1,5 @@ +BEGIN { $| = 1; print "1..1\n" } +END {print "not ok 1\n" unless $loaded;} +use FS::sector_coverage; +$loaded=1; +print "ok 1\n"; |