Files
protoloon/js/CodecHighResLocation.js
2026-04-02 17:39:02 -06:00

154 lines
4.3 KiB
JavaScript

/*
Copyright (c) 2023-forever Douglas Malnati. All rights reserved.
See the /faq/tos page for details.
(If this generated header is stamped on a file which is a 3rd party file or under a different license or copyright, then ignore this copyright statement and use that file's terms.)
*/
import { WsprCodecMaker } from '/pro/codec/WsprCodec.js';
import { WSPREncoded } from '/js/WSPREncoded.js';
export class CodecHighResLocation
extends WsprCodecMaker
{
static HDR_TYPE = 3;
static HDR_TELEMETRY_TYPE = 0;
static HDR_RESERVED = 0;
static REFERENCE_RESERVED = 0;
static REFERENCE_ESTABLISHED_GRID4 = 1;
static REFERENCE_GRID_WIDTH_DEG = 2;
static REFERENCE_GRID_HEIGHT_DEG = 1;
constructor()
{
super();
this.SetCodecDefFragment("HighResLocation", `
{ "name": "Reference", "unit": "Enum", "lowValue": 0, "highValue": 1, "stepSize": 1 },
{ "name": "Latitude", "unit": "Idx", "lowValue": 0, "highValue": 12352, "stepSize": 1 },
{ "name": "Longitude", "unit": "Idx", "lowValue": 0, "highValue": 24617, "stepSize": 1 },
`);
}
GetReferenceReservedValue()
{
return CodecHighResLocation.REFERENCE_RESERVED;
}
GetHdrTypeValue()
{
return CodecHighResLocation.HDR_TYPE;
}
GetHdrTelemetryTypeValue()
{
return CodecHighResLocation.HDR_TELEMETRY_TYPE;
}
GetHdrReservedValue()
{
return CodecHighResLocation.HDR_RESERVED;
}
GetReferenceEstablishedGrid4Value()
{
return CodecHighResLocation.REFERENCE_ESTABLISHED_GRID4;
}
GetReferencedGridWidthDeg()
{
return CodecHighResLocation.REFERENCE_GRID_WIDTH_DEG;
}
GetReferencedGridHeightDeg()
{
return CodecHighResLocation.REFERENCE_GRID_HEIGHT_DEG;
}
GetLatitudeBinCount()
{
let codec = this.GetCodecInstance();
return codec.GetLatitudeIdxHighValue() - codec.GetLatitudeIdxLowValue() + 1;
}
GetLongitudeBinCount()
{
let codec = this.GetCodecInstance();
return codec.GetLongitudeIdxHighValue() - codec.GetLongitudeIdxLowValue() + 1;
}
GetReferenceGridSouthwestCorner(grid4)
{
return WSPREncoded.DecodeMaidenheadToDeg(grid4.substring(0, 4), { snap: "southwest" });
}
IsCodecHighResLocation(codec)
{
return codec?.GetHdrTypeEnum?.() == this.GetHdrTypeValue();
}
IsReferenceEstablishedGrid4(referenceEnum)
{
return Number(referenceEnum) == this.GetReferenceEstablishedGrid4Value();
}
EncodeLocationToFieldValues(lat, lng)
{
let grid4 = WSPREncoded.GetReferenceGrid4(lat, lng);
let [baseLat, baseLng] = this.GetReferenceGridSouthwestCorner(grid4);
let latDegDiff = Number(lat) - baseLat;
let lngDegDiff = Number(lng) - baseLng;
let latIsInBounds = latDegDiff >= 0 && latDegDiff < this.GetReferencedGridHeightDeg();
let lngIsInBounds = lngDegDiff >= 0 && lngDegDiff < this.GetReferencedGridWidthDeg();
if (!latIsInBounds || !lngIsInBounds)
{
throw new RangeError(
`Location ${lat}, ${lng} is outside reference grid ${grid4}.`
);
}
let latitudeIdx = Math.floor(latDegDiff * this.GetLatitudeBinCount() / this.GetReferencedGridHeightDeg());
let longitudeIdx = Math.floor(lngDegDiff * this.GetLongitudeBinCount() / this.GetReferencedGridWidthDeg());
return {
grid4,
referenceEnum: this.GetReferenceEstablishedGrid4Value(),
latitudeIdx,
longitudeIdx,
};
}
DecodeFieldValuesToLocation(grid4, referenceEnum, latitudeIdx, longitudeIdx)
{
if (!this.IsReferenceEstablishedGrid4(referenceEnum))
{
return null;
}
latitudeIdx = Number(latitudeIdx);
longitudeIdx = Number(longitudeIdx);
if (isNaN(latitudeIdx) || isNaN(longitudeIdx))
{
return null;
}
let [baseLat, baseLng] = this.GetReferenceGridSouthwestCorner(grid4);
let lat = baseLat + (latitudeIdx + 0.5) * this.GetReferencedGridHeightDeg() / this.GetLatitudeBinCount();
let lng = baseLng + (longitudeIdx + 0.5) * this.GetReferencedGridWidthDeg() / this.GetLongitudeBinCount();
return {
lat,
lng,
};
}
}