/* 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, }; } }