Implementation of Thaddeus Vincenty's algorithms to solve the direct and inverse geodetic problems. For more information, see Vincent's original publication on the NOAA website: See http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf
Ejemplo n.º 1
0
	/// <summary>
	/// Calculate the destination if we start at:
	///    Lincoln Memorial in Washington, D.C --> 38.8892N, 77.04978W
	///         and travel at
	///    51.7679 degrees for 6179.016136 kilometers
	/// 
	///    WGS84 reference ellipsoid
	/// </summary>
	static void TwoDimensionalDirectCalculation()
	{
	  // instantiate the calculator
	  GeodeticCalculator geoCalc = new GeodeticCalculator();

	  // select a reference elllipsoid
	  Ellipsoid reference = Ellipsoid.WGS84;

	  // set Lincoln Memorial coordinates
	  GlobalCoordinates lincolnMemorial;
	  lincolnMemorial = new GlobalCoordinates(
		  new Angle(38.88922), new Angle(-77.04978)
	  );

	  // set the direction and distance
	  Angle startBearing = new Angle(51.7679);
	  double distance = 6179016.13586;

	  // find the destination
	  Angle endBearing;
	  GlobalCoordinates dest = geoCalc.CalculateEndingGlobalCoordinates(reference, lincolnMemorial, startBearing, distance, out endBearing);

	  Console.WriteLine("Travel from Lincoln Memorial at 51.767921 deg for 6179.016 km");
	  Console.Write("   Destination: {0:0.0000}{1}", dest.Latitude.Degrees, (dest.Latitude > 0) ? "N" : "S" );
	  Console.WriteLine(", {0:0.0000}{1}", dest.Longitude.Degrees, (dest.Longitude > 0) ? "E" : "W");
	  Console.WriteLine("   End Bearing: {0:0.00} degrees", endBearing.Degrees);
	}
Ejemplo n.º 2
0
	/// <summary>
	/// Calculate the two-dimensional path from
	///    Lincoln Memorial in Washington, D.C --> 38.8892N, 77.04978W
	///         to
	///    Eiffel Tower in Paris --> 48.85889N, 2.29583E
	///         using
	///    WGS84 reference ellipsoid
	/// </summary>
	static void TwoDimensionalInverseCalculation()
	{
	  // instantiate the calculator
	  GeodeticCalculator geoCalc = new GeodeticCalculator();

	  // select a reference elllipsoid
	  Ellipsoid reference = Ellipsoid.WGS84;

	  // set Lincoln Memorial coordinates
	  GlobalCoordinates lincolnMemorial;
	  lincolnMemorial = new GlobalCoordinates(
		  new Angle(38.88922), new Angle(-77.04978)
	  );

	  // set Eiffel Tower coordinates
	  GlobalCoordinates eiffelTower;
	  eiffelTower = new GlobalCoordinates(
		  new Angle(48.85889), new Angle(2.29583)
	  );

	  // calculate the geodetic curve
	  GeodeticCurve geoCurve = geoCalc.CalculateGeodeticCurve(reference, lincolnMemorial, eiffelTower);
	  double ellipseKilometers = geoCurve.EllipsoidalDistance / 1000.0;
	  double ellipseMiles = ellipseKilometers * 0.621371192;

	  Console.WriteLine("2-D path from Lincoln Memorial to Eiffel Tower using WGS84");
	  Console.WriteLine("   Ellipsoidal Distance: {0:0.00} kilometers ({1:0.00} miles)", ellipseKilometers, ellipseMiles);
	  Console.WriteLine("   Azimuth:              {0:0.00} degrees", geoCurve.Azimuth.Degrees);
	  Console.WriteLine("   Reverse Azimuth:      {0:0.00} degrees", geoCurve.ReverseAzimuth.Degrees);
	}
Ejemplo n.º 3
0
    public void TestCalculateGeodeticMeasurement()
    {
      // instantiate the calculator
      GeodeticCalculator geoCalc = new GeodeticCalculator();

      // select a reference elllipsoid
      Ellipsoid reference = Ellipsoid.WGS84;

      // set Pike's Peak position
      GlobalPosition pikesPeak;
      pikesPeak = new GlobalPosition(new GlobalCoordinates(new Angle(38.840511), new Angle(-105.0445896)), 4301.0);

      // set Alcatraz Island coordinates
      GlobalPosition alcatrazIsland;
      alcatrazIsland = new GlobalPosition(new GlobalCoordinates(new Angle(37.826389), new Angle(-122.4225)), 0.0);

      // calculate the geodetic measurement
      GeodeticMeasurement geoMeasurement;

      geoMeasurement = geoCalc.CalculateGeodeticMeasurement(reference, pikesPeak, alcatrazIsland);

      Assert.AreEqual(-4301.0, geoMeasurement.ElevationChange, 0.001);
      Assert.AreEqual(1521788.826, geoMeasurement.PointToPointDistance, 0.001);
      Assert.AreEqual(1521782.748, geoMeasurement.EllipsoidalDistance, 0.001);
      Assert.AreEqual(271.21039153, geoMeasurement.Azimuth.Degrees, 0.0000001);
      Assert.AreEqual(80.38029386, geoMeasurement.ReverseAzimuth.Degrees, 0.0000001);
    }
Ejemplo n.º 4
0
    public void TestAntiPodal1()
    {
      // instantiate the calculator
      GeodeticCalculator geoCalc = new GeodeticCalculator();

      // select a reference elllipsoid
      Ellipsoid reference = Ellipsoid.WGS84;

      // set position 1
      GlobalCoordinates p1;
      p1 = new GlobalCoordinates(10, 80.6);

      // set position 2
      GlobalCoordinates p2;
      p2 = new GlobalCoordinates(-10, -100);

      // calculate the geodetic measurement
      GeodeticCurve geoCurve;

      geoCurve = geoCalc.CalculateGeodeticCurve(reference, p1, p2);

      Assert.AreEqual(19970718.422432076, geoCurve.EllipsoidalDistance, 0.001);
      Assert.AreEqual(90.0004877491174, geoCurve.Azimuth.Degrees, 0.0000001);
      Assert.AreEqual(270.0004877491174, geoCurve.ReverseAzimuth.Degrees, 0.0000001);
    }
Ejemplo n.º 5
0
 public static GeodeticMeasurement CalculateDistance(double lat1, double lon1, double lat2, double lon2)
 {
     GlobalCoordinates p1 = new GlobalCoordinates(new Angle(lat1), new Angle(lon1));
     GlobalCoordinates p2 = new GlobalCoordinates(new Angle(lat2), new Angle(lon2));
     GeodeticCalculator gc = new GeodeticCalculator();
     GlobalPosition gp1 = new GlobalPosition(p1);
     GlobalPosition gp2 = new GlobalPosition(p2);
     GeodeticMeasurement gm = gc.CalculateGeodeticMeasurement(Ellipsoid.WGS84, gp1, gp2);
     return gm;
 }
Ejemplo n.º 6
0
 public static void GetEnvelope(double lat, double lon, double dist, out double minLat, out double minLon, out double maxLat, out double maxLon)
 {
     var gc = new GeodeticCalculator();
     var endpoints = new List<GlobalCoordinates>();
     endpoints.Add(gc.CalculateEndingGlobalCoordinates(Ellipsoid.WGS84, new GlobalCoordinates(new Angle(lat), new Angle(lon)), new Angle(0), dist * 1000.0));
     endpoints.Add(gc.CalculateEndingGlobalCoordinates(Ellipsoid.WGS84, new GlobalCoordinates(new Angle(lat), new Angle(lon)), new Angle(90), dist * 1000.0));
     endpoints.Add(gc.CalculateEndingGlobalCoordinates(Ellipsoid.WGS84, new GlobalCoordinates(new Angle(lat), new Angle(lon)), new Angle(180), dist * 1000.0));
     endpoints.Add(gc.CalculateEndingGlobalCoordinates(Ellipsoid.WGS84, new GlobalCoordinates(new Angle(lat), new Angle(lon)), new Angle(270), dist * 1000.0));
     minLat = endpoints.Min(x => x.Latitude.Degrees);
     maxLat = endpoints.Max(x => x.Latitude.Degrees);
     minLon = endpoints.Min(x => x.Longitude.Degrees);
     maxLon = endpoints.Max(x => x.Longitude.Degrees);
 }
Ejemplo n.º 7
0
        private void DoGeodaeticCalculations ()
            {
            DataRow RootRow = MapDataWrapper.Instance.GetMapKachelRootImageRow (TypenName, RootKachelName);
            GeodeticCalculator GeoCalc = new GeodeticCalculator();
            Ellipsoid ReferenceModell = Ellipsoid.WGS84;
            GlobalCoordinates TopLeftStart = new GlobalCoordinates
                (new Angle(Convert.ToDouble(RootRow["TopY"])), new Angle(Convert.ToDouble(RootRow["LeftX"])));
            GlobalCoordinates TopRightEnd = new GlobalCoordinates
                (new Angle(Convert.ToDouble(RootRow["TopY"])), new Angle(Convert.ToDouble(RootRow["RightX"])));
            GlobalCoordinates BottomLeftStart = new GlobalCoordinates
                (new Angle(Convert.ToDouble(RootRow["BottomY"])), new Angle(Convert.ToDouble(RootRow["LeftX"])));
            GlobalCoordinates BottomRightEnd = new GlobalCoordinates
                (new Angle(Convert.ToDouble(RootRow["BottomY"])), new Angle(Convert.ToDouble(RootRow["RightX"])));

            GeodeticCurve TopCurve = GeoCalc.CalculateGeodeticCurve(ReferenceModell, TopLeftStart, TopRightEnd);
            double TopMeters = TopCurve.EllipsoidalDistance;

            GeodeticCurve BottomCurve = GeoCalc.CalculateGeodeticCurve(ReferenceModell, BottomLeftStart, BottomRightEnd);
            double BottomMeters = BottomCurve.EllipsoidalDistance;

            GeodeticCurve LeftCurve = GeoCalc.CalculateGeodeticCurve(ReferenceModell, BottomLeftStart, TopLeftStart);
            double LeftMeters = LeftCurve.EllipsoidalDistance;

            GeodeticCurve RightCurve = GeoCalc.CalculateGeodeticCurve(ReferenceModell, BottomRightEnd, TopRightEnd);
            double RightMeters = RightCurve.EllipsoidalDistance;

            LeftToRightDistance = (TopMeters + BottomMeters) / 2.0;
            BottomToTopDistance = (LeftMeters + RightMeters) / 2.0;

            LeftMeasure = new Point (Convert.ToDouble(RootRow["LeftX"]), Convert.ToDouble(RootRow["TopY"]));
            TopMeasure = new Point (Convert.ToDouble(RootRow["LeftX"]), Convert.ToDouble(RootRow["TopY"]));
            RightMeasure = new Point (Convert.ToDouble(RootRow["RightX"]), Convert.ToDouble(RootRow["BottomY"]));
            BottomMeasure = new Point (Convert.ToDouble(RootRow["RightX"]), Convert.ToDouble(RootRow["BottomY"]));
            double MaxDrawingAreaAspectRatio = MaxDrawingWidth / MaxDrawingHeight;
            double RootKachelAspectRatio = LeftToRightDistance / BottomToTopDistance;
            if (RootKachelAspectRatio >= MaxDrawingAreaAspectRatio)
                {
                FullDrawingWidth = MaxDrawingWidth;
                FullDrawingHeight = FullDrawingWidth / RootKachelAspectRatio;
                }
            else
                {
                FullDrawingHeight = MaxDrawingHeight;
                FullDrawingWidth = FullDrawingHeight * RootKachelAspectRatio;
                }
            }
Ejemplo n.º 8
0
        public override object Execute(object[] args, ExecutionContext ctx)
        {
            string ret = "";
            ArgumentChecker checker = new ArgumentChecker(this.GetType().Name);
            checker.CheckForNumberOfArguments(ref args, 3, null);
            Framework.Data.Location ll = Utils.Conversion.StringToLocation(args[0].ToString());
            double distance = Utils.Conversion.StringToDouble(args[1].ToString());
            double angle = Utils.Conversion.StringToDouble(args[2].ToString());

            if (ll != null)
            {
                GeodeticCalculator gc = new GeodeticCalculator();
                GlobalCoordinates p = gc.CalculateEndingGlobalCoordinates(Ellipsoid.WGS84, 
                    new GlobalCoordinates(new Angle(ll.Lat), new Angle(ll.Lon)), 
                    new Angle(angle), distance);
                ret = Utils.Conversion.GetCoordinatesPresentation(p.Latitude.Degrees, p.Longitude.Degrees);
            }

            return ret;
        }
Ejemplo n.º 9
0
    public void TestCalculateGeodeticCurve()
    {
      // instantiate the calculator
      GeodeticCalculator geoCalc = new GeodeticCalculator();

      // select a reference elllipsoid
      Ellipsoid reference = Ellipsoid.WGS84;

      // set Lincoln Memorial coordinates
      GlobalCoordinates lincolnMemorial;
      lincolnMemorial = new GlobalCoordinates(38.88922, -77.04978);

      // set Eiffel Tower coordinates
      GlobalCoordinates eiffelTower;
      eiffelTower = new GlobalCoordinates(48.85889, 2.29583);

      // calculate the geodetic curve
      GeodeticCurve geoCurve = geoCalc.CalculateGeodeticCurve(reference, lincolnMemorial, eiffelTower);

      Assert.AreEqual(6179016.136, geoCurve.EllipsoidalDistance, 0.001);
      Assert.AreEqual(51.76792142, geoCurve.Azimuth.Degrees, 0.0000001);
      Assert.AreEqual(291.75529334, geoCurve.ReverseAzimuth.Degrees, 0.0000001);
    }
Ejemplo n.º 10
0
	/// <summary>
	/// Calculate the three-dimensional path from
	///    Pike's Peak in Colorado --> 38.840511N, 105.0445896W, 4301 meters
	///        to
	///    Alcatraz Island --> 37.826389N, 122.4225W, sea level
	///        using
	///    WGS84 reference ellipsoid
	/// </summary>
	static void ThreeDimensionalInverseCalculation()
	{
	  // instantiate the calculator
	  GeodeticCalculator geoCalc = new GeodeticCalculator();

	  // select a reference elllipsoid
	  Ellipsoid reference = Ellipsoid.WGS84;

	  // set Pike's Peak position
	  GlobalPosition pikesPeak;
	  pikesPeak = new GlobalPosition(
		new GlobalCoordinates(new Angle(38.840511), new Angle(-105.0445896)),
		4301.0
	  );

	  // set Alcatraz Island coordinates
	  GlobalPosition alcatrazIsland;
	  alcatrazIsland = new GlobalPosition(
		new GlobalCoordinates(new Angle(37.826389), new Angle(-122.4225)),
		0.0
	  );

	  // calculate the geodetic measurement
	  GeodeticMeasurement geoMeasurement;
	  double p2pKilometers;
	  double p2pMiles;
	  double elevChangeMeters;
	  double elevChangeFeet;

	  geoMeasurement = geoCalc.CalculateGeodeticMeasurement(reference, pikesPeak, alcatrazIsland);
	  p2pKilometers = geoMeasurement.PointToPointDistance / 1000.0;
	  p2pMiles = p2pKilometers * 0.621371192;
	  elevChangeMeters = geoMeasurement.ElevationChange;
	  elevChangeFeet = elevChangeMeters * 3.2808399;

	  Console.WriteLine("3-D path from Pike's Peak to Alcatraz Island using WGS84");
	  Console.WriteLine("   Point-to-Point Distance: {0:0.00} kilometers ({1:0.00} miles)", p2pKilometers, p2pMiles);
	  Console.WriteLine("   Elevation change:        {0:0.0} meters ({1:0.0} feet)", elevChangeMeters, elevChangeFeet);
	  Console.WriteLine("   Azimuth:                 {0:0.00} degrees", geoMeasurement.Azimuth.Degrees);
	  Console.WriteLine("   Reverse Azimuth:         {0:0.00} degrees", geoMeasurement.ReverseAzimuth.Degrees);
	}
Ejemplo n.º 11
0
    public void TestAntiPodal2()
    {
      // instantiate the calculator
      GeodeticCalculator geoCalc = new GeodeticCalculator();

      // select a reference elllipsoid
      Ellipsoid reference = Ellipsoid.WGS84;

      // set position 1
      GlobalCoordinates p1;
      p1 = new GlobalCoordinates(11, 80);

      // set position 2
      GlobalCoordinates p2;
      p2 = new GlobalCoordinates(-10, -100);

      // calculate the geodetic measurement
      GeodeticCurve geoCurve;

      geoCurve = geoCalc.CalculateGeodeticCurve(reference, p1, p2);

      Assert.AreEqual(19893320.272061437, geoCurve.EllipsoidalDistance, 0.001);
      Assert.AreEqual(360.0, geoCurve.Azimuth.Degrees, 0.0000001);
      Assert.AreEqual(0.0, geoCurve.ReverseAzimuth.Degrees, 0.0000001);
    }
Ejemplo n.º 12
0
    public void TestPoleCrossing()
    {
      // instantiate the calculator
      GeodeticCalculator geoCalc = new GeodeticCalculator();

      // select a reference elllipsoid
      Ellipsoid reference = Ellipsoid.WGS84;

      // set Lincoln Memorial coordinates
      GlobalCoordinates lincolnMemorial;
      lincolnMemorial = new GlobalCoordinates(new Angle(38.88922), new Angle(-77.04978));

      // set a bearing of 1.0deg (almost straight up) and a distance
      Angle startBearing = new Angle(1.0);
      double distance = 6179016.13586;

      // set the expected destination
      GlobalCoordinates expected;
      expected = new GlobalCoordinates(new Angle(85.60006433), new Angle(92.17243943));

      // calculate the ending global coordinates
      Angle endBearing;
      GlobalCoordinates dest = geoCalc.CalculateEndingGlobalCoordinates(reference, lincolnMemorial, startBearing, distance, out endBearing);

      Assert.AreEqual(expected.Latitude.Degrees, dest.Latitude.Degrees, 0.0000001);
      Assert.AreEqual(expected.Longitude.Degrees, dest.Longitude.Degrees, 0.0000001);
    }
Ejemplo n.º 13
0
    public void TestInverseWithDirect()
    {
      // instantiate the calculator
      GeodeticCalculator geoCalc = new GeodeticCalculator();

      // select a reference elllipsoid
      Ellipsoid reference = Ellipsoid.WGS84;

      // set Lincoln Memorial coordinates
      GlobalCoordinates lincolnMemorial;
      lincolnMemorial = new GlobalCoordinates( new Angle(38.88922), new Angle(-77.04978));

      // set Eiffel Tower coordinates
      GlobalCoordinates eiffelTower;
      eiffelTower = new GlobalCoordinates(48.85889, 2.29583);

      // calculate the geodetic curve
      GeodeticCurve geoCurve = geoCalc.CalculateGeodeticCurve(reference, lincolnMemorial, eiffelTower);

      // now, plug the result into to direct solution
      GlobalCoordinates dest;
      Angle endBearing = new Angle();

      dest = geoCalc.CalculateEndingGlobalCoordinates(reference, lincolnMemorial, geoCurve.Azimuth, geoCurve.EllipsoidalDistance, out endBearing);

      Assert.AreEqual(eiffelTower.Latitude.Degrees, dest.Latitude.Degrees, 0.0000001);
      Assert.AreEqual(eiffelTower.Longitude.Degrees, dest.Longitude.Degrees, 0.0000001);
    }
Ejemplo n.º 14
0
 private void calculateProjection()
 {
     Framework.Data.Location ll = Utils.Conversion.StringToLocation(textBox3.Text);
     if (ll != null)
     {
         GeodeticCalculator gc = new GeodeticCalculator();
         GlobalCoordinates p = gc.CalculateEndingGlobalCoordinates(Ellipsoid.WGS84, new GlobalCoordinates(new Angle(ll.Lat), new Angle(ll.Lon)), new Angle((double)numericUpDown2.Value), radioButton1.Checked ? (double)numericUpDown1.Value : 1609.26939 * (double)numericUpDown2.Value);
         textBox4.Text = Utils.Conversion.GetCoordinatesPresentation(p.Latitude.Degrees, p.Longitude.Degrees);
     }
     else
     {
         textBox4.Text = "";
     }
 }
Ejemplo n.º 15
0
    public override async Task<bool> Load()
    {
      var client1 = new HttpClient();
      var request1 = new HttpRequestMessage(HttpMethod.Get, "http://mesonet-nexrad.agron.iastate.edu/level2/raw/" + this.siteName + "/dir.list");
      string scanList = await (await client1.SendAsync(request1)).Content.ReadAsStringAsync();
      var scans = scanList.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);

      var chosen = scans[scans.Length - 2].Split(' ')[1];

      var filelink = "http://mesonet-nexrad.agron.iastate.edu/level2/raw/" + this.siteName +"/" + chosen;

      var scaleColorsText = FileLoader.LoadTextFile("config/scale_BR.json");
      var scaleColors = JsonConvert.DeserializeObject<List<ColorScaleItem>>(scaleColorsText);

      cells = new List<RadarCell>();
      var uncompressedData = new MemoryStream();

      var start = DateTime.UtcNow;
      Debug.WriteLine("start");
      var client = new HttpClient();
      var request = new HttpRequestMessage(HttpMethod.Get, filelink);
      Stream contentStream = await (await client.SendAsync(request)).Content.ReadAsStreamAsync();
      var memoryReader = new MemoryStream((int)contentStream.Length);
      await contentStream.CopyToAsync(memoryReader);

      // Copy file into memory
      //var fileReader = File.OpenRead(this.filename);
      //var memoryReader = new MemoryStream((int)fileReader.Length);
      //fileReader.CopyTo(memoryReader);
      //fileReader.Close();
      memoryReader.Seek(0, SeekOrigin.Begin);


      var chunks = new List<Chunk>();
      var binaryReader = new BinaryReader(memoryReader);
      var bigEndianReader = new BigEndianReader(binaryReader);
      bigEndianReader.Skip(24);
      bool last = false;

      // Read each chunk, Get offset and size for each
      while (!last)
      {
        var chunkSize = bigEndianReader.ReadInt32();
        if (chunkSize < 0)
        {
          chunkSize *= -1;
          last = true;
        }
        if (chunkSize == 0)
        {
          continue;
        }
        var compressedSignifier = bigEndianReader.ReadChars(2);
        long pointer = bigEndianReader.BaseStream.Seek(-2, SeekOrigin.Current);
        bigEndianReader.Skip(chunkSize);
        chunks.Add(new Chunk
        {
          offset = (int)pointer,
          length = chunkSize,
          isCompressed = compressedSignifier == "BZ"
        });
      }

      bigEndianReader.Close();
      binaryReader.Close();
      var byteBuffer = memoryReader.GetBuffer();
      memoryReader.Close();

      var opts = new ParallelOptions
      {
        MaxDegreeOfParallelism = 6
      };

      // Decompress each chunk from file.
      Parallel.ForEach(chunks, opts, chunk =>
      {
        if (chunk.isCompressed)
        {
           chunk.uncompressed = new MemoryStream();
           var chunkStream = new MemoryStream(byteBuffer, chunk.offset, chunk.length);
           var chunkStart = DateTime.UtcNow; 
           ICSharpCode.SharpZipLib.BZip2.BZip2.Decompress(chunkStream, chunk.uncompressed, false);
           chunk.uncompressed.Seek(0, SeekOrigin.Begin);
        }
      });

      // Sum the sizes for each chunk
      var size = (int)chunks.Sum(x =>
      {
        if (x.isCompressed)
        {
          return x.uncompressed.Length;
        }
        else
        {
          return x.length;
        }
      });

      // 
      var uncompressedStream = new MemoryStream(size);
      foreach(var chunk in chunks){
        if (chunk.isCompressed)
        {
          chunk.uncompressed.CopyTo(uncompressedStream);
        }
        else
        {
          uncompressedStream.Write(byteBuffer, chunk.offset, chunk.length);
        }
      }


      Debug.WriteLine("took " + (DateTime.UtcNow - start).TotalMilliseconds + " ms file is reassembled");

      uncompressedStream.Seek(0, SeekOrigin.Begin);
      var uncompressedBinaryReader = new BinaryReader(uncompressedStream);
      var uncompressedReader = new BigEndianReader(uncompressedBinaryReader);
      var uncompressedLength = uncompressedStream.Length;

      var counts = new Dictionary<int, int>();
      var elevations = new Dictionary<int, int>();
      var azimuths = new Dictionary<int, float>();

      int record = 0;
      int message_offset31 = 0;

      int countRefs = 0;

      while (true)
      {
        long offset = record * 2432  + message_offset31;
        record++;

        if (offset >= uncompressedLength)
        {
          break;
        }
        uncompressedReader.BaseStream.Seek(offset, SeekOrigin.Begin);
        uncompressedReader.Skip(12);
        var messageSize = uncompressedReader.ReadUInt16();
        var idChannel = uncompressedReader.ReadBytes(1);
        var messageType = uncompressedReader.ReadBytes(1);

        uncompressedReader.Skip(8);
        var numSegments = uncompressedReader.ReadUInt16();
        var curSegment = uncompressedReader.ReadUInt16();
       
        if (!counts.ContainsKey(messageType[0]))
        {
          counts.Add(messageType[0], 1);
        }
        else
        {
          counts[messageType[0]]++;
        }
        
        if (messageType[0] == 31)
        {
          message_offset31 = message_offset31 + (messageSize * 2 + 12 - 2432);

          var identier = uncompressedReader.ReadChars(4);
          uncompressedReader.Skip(6);
          var azimuthNumber = uncompressedReader.ReadUInt16();
          var azimuthAngle = uncompressedReader.ReadFloat();
          var compressedFlag = uncompressedReader.ReadBytes(1)[0];
          var sp = uncompressedReader.ReadBytes(1)[0];
          var rlength = uncompressedReader.ReadInt16();
          var ars = uncompressedReader.ReadBytes(1)[0];

          if (!azimuths.ContainsKey(azimuthNumber))
          {
            azimuths.Add(azimuthNumber, azimuthAngle);
          }

          if (ars != 1)
          {
            //not HI res.
            continue;
          }

          var rs = uncompressedReader.ReadBytes(1)[0];
          var elevation_num = uncompressedReader.ReadBytes(1)[0]; // RDA elevation number
          var cut = uncompressedReader.ReadBytes(1); // sector number within cut
          var elevation = uncompressedReader.ReadFloat();

          if (elevation_num != 1)
          {
            continue;
          }

          if (!elevations.ContainsKey(elevation_num))
          {
            elevations.Add(elevation_num, 1);
          }
          else
          {
            elevations[elevation_num]++;
          }

          var rsbs = uncompressedReader.ReadBytes(1)[0];
          var aim = uncompressedReader.ReadBytes(1)[0];
          var dcount = uncompressedReader.ReadInt16();

          uint[] data_pointers = new uint[9];
          for (int i = 0; i < 9; i++)
          {
            data_pointers[i] = uncompressedReader.ReadUInt32();
          }
          for (int i = 0; i < 9; i++)
          {
            uncompressedReader.BaseStream.Seek(offset + 28+ data_pointers[i], SeekOrigin.Begin);
            uncompressedReader.Skip(1);
            var dataBlockName = uncompressedReader.ReadChars(3);

            if (dataBlockName == "REF")
            {
              uncompressedReader.Skip(4);
             
              var numGates = uncompressedReader.ReadUInt16();
              var firstGateDistance = uncompressedReader.ReadUInt16();
              var gateDistanceInterval = uncompressedReader.ReadUInt16();
              uncompressedReader.Skip(6);
              var dataMomentScale = uncompressedReader.ReadFloat();
              var dataMomentOffset = uncompressedReader.ReadFloat();

              for (int j = 0; j < numGates; j++)
              {
                  var gateBytes = uncompressedReader.ReadBytes(1)[0];

                  var dist = firstGateDistance + gateDistanceInterval * j;

                  var reflectivity = gateBytes * 0.5f - 33;

                  if (reflectivity < 1)
                  {
                    continue;
                  }
                  var cell = new RadarCell
                  {
                    reflectivity = reflectivity,
                    azimuth = azimuthAngle,
                    dist = dist,
                    azimuthNumber = azimuthNumber
                  };
                  this.cells.Add(cell);
              }
              countRefs++;
            } else if (this.latitude == 0 && dataBlockName == "VOL")
            {
              Debug.WriteLine("Found VOL");
              uncompressedReader.Skip(4);
              this.latitude = uncompressedReader.ReadFloat();
              this.longitude =  uncompressedReader.ReadFloat();
            }
          }
        } 
      }
      Debug.WriteLine("took " + (DateTime.UtcNow - start).TotalMilliseconds + " ms radar ready to render");

      this.vertexArray = new float[this.cells.Count * 3 * 6];
      this.colorArray = new float[this.cells.Count * 4 * 6];
      var earth = Ellipsoid.WGS84;
      var stationGeo = new GlobalCoordinates(new Angle(this.latitude), new Angle(this.longitude));
      var calc = new GeodeticCalculator();

      Parallel.For(0, this.cells.Count, opts, i =>
      {
        var cell = this.cells[i];

        if (cell.azimuthNumber == azimuths.Count())
        {
          cell.azimuth_after = azimuths[1];
        }
        else
        {
          cell.azimuth_after = azimuths[cell.azimuthNumber+1];
        }

        int bucket = -1;
        for(int j = 0; j < scaleColors.Count; j++){
           if( cell.reflectivity > scaleColors[j].dbZ )
           {
             bucket = j;
             break;
           }
        }

        switch (bucket)
        {
          case 0:
          case -1:
            //off scale.
            break;
          case 1:
          default:

            int[] lowColor = null;
            int[] highColor = null;

            if (bucket == 1)
            {
              lowColor = new int[] { scaleColors[0].range[0], scaleColors[0].range[1], scaleColors[0].range[2] };
              highColor = new int[] { scaleColors[1].range[0], scaleColors[1].range[1], scaleColors[1].range[2] };
            }
            else
            {
              lowColor = new int[] { scaleColors[bucket].range[3], scaleColors[bucket].range[4], scaleColors[bucket].range[5] };
              highColor = new int[] { scaleColors[bucket].range[0], scaleColors[bucket].range[1], scaleColors[bucket].range[2] };
            }
            var range = scaleColors[bucket - 1].dbZ - scaleColors[bucket].dbZ;
            var percentForLowColor = (cell.reflectivity - scaleColors[bucket].dbZ) / range;
            var percentForHighColor = 1 - percentForLowColor;

            cell.r = (percentForHighColor * highColor[0] + percentForLowColor * lowColor[0]) / 255.0f;
            cell.g = (percentForHighColor * highColor[1] + percentForLowColor * lowColor[1]) / 255.0f;
            cell.b = (percentForHighColor * highColor[2] + percentForLowColor * lowColor[2]) / 255.0f;
            break;
        }

        var r = cell.dist;
        int baseVertex = 3 * 6 * i;

        var top_left = calc.CalculateEndingGlobalCoordinates(earth, stationGeo, new Angle(cell.azimuth_after), r+250.0f);
        var top_right = calc.CalculateEndingGlobalCoordinates(earth, stationGeo, new Angle(cell.azimuth), r+250.0f);
        var bottom_right = calc.CalculateEndingGlobalCoordinates(earth, stationGeo, new Angle(cell.azimuth), r);
        var bottom_left = calc.CalculateEndingGlobalCoordinates(earth, stationGeo, new Angle(cell.azimuth_after), r);

        this.vertexArray[baseVertex + 0] = ConvertLongitude(top_left.Longitude.Degrees);//top left x
        this.vertexArray[baseVertex + 1] = ConvertLatitude(top_left.Latitude.Degrees);///top left y
        this.vertexArray[baseVertex + 3] = ConvertLongitude(top_right.Longitude.Degrees); //top right x
        this.vertexArray[baseVertex + 4] = ConvertLatitude(top_right.Latitude.Degrees); //top right y
        this.vertexArray[baseVertex + 6] = ConvertLongitude(bottom_right.Longitude.Degrees); //bottom right x
        this.vertexArray[baseVertex + 7] = ConvertLatitude(bottom_right.Latitude.Degrees); //bottom right y
        this.vertexArray[baseVertex + 9] = ConvertLongitude(bottom_right.Longitude.Degrees);//bottom right x
        this.vertexArray[baseVertex + 10] =ConvertLatitude(bottom_right.Latitude.Degrees); //bottom right y
        this.vertexArray[baseVertex + 12] = ConvertLongitude(bottom_left.Longitude.Degrees); //bottom left x
        this.vertexArray[baseVertex + 13] = ConvertLatitude(bottom_left.Latitude.Degrees);//bottom left y
        this.vertexArray[baseVertex + 15] = ConvertLongitude(top_left.Longitude.Degrees); //top left x
        this.vertexArray[baseVertex + 16] = ConvertLatitude(top_left.Latitude.Degrees); //top left y

        int baseColor = 4 * 6 * i;
        const float alpha = 0.6f;
        this.colorArray[baseColor + 0] = cell.r;
        this.colorArray[baseColor + 1] = cell.g;
        this.colorArray[baseColor + 2] = cell.b;
        this.colorArray[baseColor + 3] = alpha;
        this.colorArray[baseColor + 4] = cell.r;
        this.colorArray[baseColor + 5] = cell.g;
        this.colorArray[baseColor + 6] = cell.b;
        this.colorArray[baseColor + 7] = alpha;
        this.colorArray[baseColor + 8] = cell.r;
        this.colorArray[baseColor + 9] = cell.g;
        this.colorArray[baseColor + 10] = cell.b;
        this.colorArray[baseColor + 11] = alpha;
        this.colorArray[baseColor + 12] = cell.r;
        this.colorArray[baseColor + 13] = cell.g;
        this.colorArray[baseColor + 14] = cell.b;
        this.colorArray[baseColor + 15] = alpha;
        this.colorArray[baseColor + 16] = cell.r;
        this.colorArray[baseColor + 17] = cell.g;
        this.colorArray[baseColor + 18] = cell.b;
        this.colorArray[baseColor + 19] = alpha;
        this.colorArray[baseColor + 20] = cell.r;
        this.colorArray[baseColor + 21] = cell.g;
        this.colorArray[baseColor + 22] = cell.b;
        this.colorArray[baseColor + 23] = alpha;

      });

      //this.isLoaded = true;
      return true;
    }