GribApiDotNet / GribApi.NET

A powerful .NET library for reading and writing GRIB 1 and 2 files
Apache License 2.0
54 stars 28 forks source link

Cherry-picking values for a specific lat/long #55

Closed guilhermecgs closed 7 years ago

guilhermecgs commented 7 years ago

If a have a temperature message at altitude = 1000ft, how can I get the temperature value at a given lat/lon without having to iterate the whole grid?

IdahoSixString commented 7 years ago

I have yet to find a way to get specific geo spatial data without enumerating the enumerable of geo spatial data. However, what you can do it enumerate the geoSpatialData then break out of the enumeration when you have found the item you are looking for. This is similar to almost any LINQ extension IE FirstOrDefault or First.

Also I noticed in my grib file that the longitude was presented in 0 to 360 instead of -180 to 180. Which if you need to convert the code is here. Otherwise you can get rid of the ternary operator

                foreach (var geoSpatialValue in gribDataGribMessage.GeoSpatialValues)
                {
                    System.Device.Location.GeoCoordinate geoCoordinate = new System.Device.Location.GeoCoordinate(geoSpatialValue.Latitude, geoSpatialValue.Longitude > 180 ? geoSpatialValue.Longitude - 360 : geoSpatialValue.Longitude);
                    var distanceInMeters = geoCoordinate.GetDistanceTo(new System.Device.Location.GeoCoordinate(42.8933, -115.8707));
                    if (distanceInMeters < 15)
                    {
                        // Do something with your item
                        // No need to continue on we found the piece of info we want.
                        break;
                    }
                }
guilhermecgs commented 7 years ago

what about this?

`

namespace weather_decoding_extracting { public class ExtendedGribMessage { private readonly GribMessage baseGribMessage; private Double firstLatitude { get; set; } private Double lastLatitude { get; set; }

    private Double firstLongitude { get; set; }
    private Double lastLongitude { get; set; }

    private Double gridSpacing { get; set; }

    private Double missingValue { get; set; }

    private double[] rawValues;

    public ExtendedGribMessage(GribMessage gribMessage)
    {
        this.baseGribMessage = gribMessage;

        // a copy of the raw values stored in the message
        this.baseGribMessage.Values(out rawValues);

        this.firstLatitude = Convert.ToDouble(this.baseGribMessage["latitudeOfFirstGridPointInDegrees"].AsDouble());
        this.lastLatitude = Convert.ToDouble(this.baseGribMessage["latitudeOfLastGridPointInDegrees"].AsDouble());
        this.firstLongitude = Convert.ToDouble(this.baseGribMessage["longitudeOfFirstGridPointInDegrees"].AsDouble());
        this.lastLongitude = Convert.ToDouble(this.baseGribMessage["longitudeOfLastGridPointInDegrees"].AsDouble());

        this.gridSpacing = Convert.ToDouble(this.baseGribMessage["iDirectionIncrementInDegrees"].AsDouble());
        this.missingValue = Convert.ToDouble(this.baseGribMessage["missingValue"].AsInt());

        if (Convert.ToDouble(this.baseGribMessage["iDirectionIncrementInDegrees"].AsDouble()) != Convert.ToDouble(this.baseGribMessage["jDirectionIncrementInDegrees"].AsDouble())) throw new Exception("Grid not uniform");
        if (this.gridSpacing <= 0) throw new Exception("Invalid GridSpacing");

        int numberOfValues = Convert.ToInt32(this.baseGribMessage["numberOfValues"].AsInt());
        if (0 != getFinalIndex(this.firstLatitude, this.firstLongitude)) throw new Exception("Invalid Grid Index");
        if (numberOfValues != getFinalIndex(this.lastLatitude, this.lastLongitude) + 1) throw new Exception("Invalid Grid Index");
    }

    public GeoSpatialValue getGeoSpatialValue(GeoCoordinate geoCoordinate)
    {
        GeoCoordinate nearestGridPoint = NearestGridPoint(geoCoordinate);

        try
        {
            int index = getFinalIndex(nearestGridPoint.Latitude, nearestGridPoint.Longitude);
            double value = rawValues[index];

            GeoSpatialValue result;

            if (index < rawValues.Length)
            {
                result = new GeoSpatialValue(nearestGridPoint.Latitude, nearestGridPoint.Longitude, value, false);
            }
            else
            {
                result = new GeoSpatialValue(nearestGridPoint.Latitude, nearestGridPoint.Longitude, this.missingValue, true);
            }
            return result;
        }
        catch (Exception ex)
        {
            GeoSpatialValue result = new GeoSpatialValue(nearestGridPoint.Latitude, nearestGridPoint.Longitude, this.missingValue, true);
            return result;
        }
    }

    public GeoCoordinate NearestGridPoint(GeoCoordinate geoCoordinate)
    {
        return new GeoCoordinate(roundToGridSpacing(geoCoordinate.Latitude), roundToGridSpacing(geoCoordinate.Longitude));
    }

    private Double roundToGridSpacing(Double value)
    {
        Double roundDown = Math.Floor(value / this.gridSpacing) * this.gridSpacing;
        Double roundUp = (Math.Floor(value / this.gridSpacing) + 1 ) * this.gridSpacing;

        Double errorDown = Math.Abs(value - roundDown);
        Double errorUp = Math.Abs(value - roundUp);

        if (errorDown < errorUp) return roundDown;
        else return roundUp;
    }

    private int getLatitudeIndex(Double latitude)
    {
        return Convert.ToInt32(Math.Abs(latitude - this.firstLatitude) / gridSpacing);
    }

    private int getLongitudeIndex(Double longitude)
    {
        return Convert.ToInt32(Math.Abs(longitude - this.firstLongitude) / gridSpacing);
    }

    private int getFinalIndex(Double latitude, Double longitude)
    {
        int sizeLongitude = Convert.ToInt32(Math.Abs(this.lastLongitude - this.firstLongitude) / this.gridSpacing) + 1;
        return getLatitudeIndex(latitude) * sizeLongitude + getLongitudeIndex(longitude);
    }

}

}

`

0x1mason commented 7 years ago

@guilhermecgs @IdahoSixString Could you use GribFindNearest as described here? I'm adding this functionality to the upcoming release: https://github.com/0x1mason/GribApi.NET/issues/43

0x1mason commented 7 years ago

@guilhermecgs You can use the new GribMessage::FindNearestCoordinates method in 1.0.0-beta2.