Close
Angular React Web Components Blazor Blazor
Premium

Blazor World Utility

The resource topic provides implementation of utility that helps with generating Blazor geographic data.

Code Snippet

export default class WorldUtils {

    // calculate geo-paths between two locations using great circle formula
    public static calcPaths(origin: any, dest: any): any[] {
        let interval = 200;
        let paths: any[] = [[]];
        let pathID = 0;
        let distance = this.calcDistance(origin, dest);
        if (distance <= interval) {
            paths[pathID].push({ x: origin.lon, y: origin.lat });
            paths[pathID].push({ x: dest.lon, y: dest.lat });
        } else {
            let current = origin;
            let previous = origin;

            for (let dist = interval; dist <= distance; dist += interval)
            {
                previous = current
                paths[pathID].push({ x: current.lon, y: current.lat });

                let bearing = this.calcBearing(current, dest);
                current = this.calcDestination(current, bearing, interval);
                // ensure geo-path wrap around the world through the new date-line
                if (previous.lon > 150 && current.lon < -150) {
                    paths[pathID].push({ x: 180, y: current.lat });
                    paths.push([]);
                    pathID++
                    current = { lon: -180, lat: current.lat }
                } else if (previous.lon < -150 && current.lon > 150) {
                    paths[pathID].push({ x: -180, y: current.lat });
                    paths.push([]);
                    pathID++
                    current = { lon: 180, lat: current.lat }
                }
            }
            paths[pathID].push({ x: dest.lon, y: dest.lat });
        }
        return paths;
    }

    // calculate bearing angle between two locations
    public static calcBearing(origin: any, dest: any) : number
    {
        origin = this.toRadianLocation(origin);
        dest = this.toRadianLocation(dest);
        let range = (dest.lon - origin.lon);
        let y = Math.sin(range) * Math.cos(dest.lat);
        let x = Math.cos(origin.lat) * Math.sin(dest.lat) -
                Math.sin(origin.lat) * Math.cos(dest.lat) * Math.cos(range);
        let angle = Math.atan2(y, x);
        return this.toDegreesNormalized(angle);
    }

    // calculate destination for origin location and travel distance
    public static calcDestination(origin: any, bearing: number, distance: number): any {
        let radius = 6371.0;
        origin = this.toRadianLocation(origin);
        bearing = this.toRadians(bearing);
        distance = distance / radius; // angular distance in radians

        let lat = Math.asin(Math.sin(origin.lat) * Math.cos(distance) +
                       Math.cos(origin.lat) * Math.sin(distance) * Math.cos(bearing));
        let x = Math.sin(bearing) * Math.sin(distance) * Math.cos(origin.lat);
        let y = Math.cos(distance) - Math.sin(origin.lat) * Math.sin(origin.lat);
        let lon = origin.lon + Math.atan2(x, y);
        // normalize lon to coordinate between -180º and +180º
        lon = (lon + 3 * Math.PI) % (2 * Math.PI) - Math.PI;

        lon = this.toDegrees(lon);
        lat = this.toDegrees(lat);

        return { lon: lon, lat: lat };
    }

    // calculate distance between two locations
    public static calcDistance(origin: any, dest: any) : number {
        origin = this.toRadianLocation(origin);
        dest = this.toRadianLocation(dest);
        let sinProd = Math.sin(origin.lat) * Math.sin(dest.lat);
        let cosProd = Math.cos(origin.lat) * Math.cos(dest.lat);
        let lonDelta = (dest.lon - origin.lon);

        let angle = Math.acos(sinProd + cosProd * Math.cos(lonDelta));
        let distance = angle * 6371.0;
        return distance; // * 6371.0; // in km
    }

    public static toRadianLocation(geoPoint: any) : any {
        let x = this.toRadians(geoPoint.lon);
        let y = this.toRadians(geoPoint.lat);
        return { lon: x, lat: y };
    }

    public static toRadians(degrees: number) : number
    {
        return degrees * Math.PI / 180;
    }

    public static toDegrees(radians: number) : number {
        return (radians * 180.0 / Math.PI);
    }

    public static toDegreesNormalized(radians: number) : number
    {
        let degrees = this.toDegrees(radians);
        degrees = (degrees + 360) % 360;
        return degrees;
    }

    // converts latitude coordinate to a string
    public static toStringLat(latitude: number) : string {
        let str = Math.abs(latitude).toFixed(1) + "°";
        return latitude > 0 ? str + "N" : str + "S";
    }

    // converts longitude coordinate to a string
    public static toStringLon(coordinate: number) : string {
        let val = Math.abs(coordinate);
        let str = val < 100 ? val.toFixed(1) : val.toFixed(0);
        return coordinate > 0 ? str + "°E" : str + "°W";
    }

    public static toStringAbbr(value: number) : string {
        if (value > 1000000000000) {
            return (value / 1000000000000).toFixed(1) + " T"
        } else if (value > 1000000000) {
            return (value / 1000000000).toFixed(1) + " B"
        } else if (value > 1000000) {
            return (value / 1000000).toFixed(1) + " M"
        } else if (value > 1000) {
            return (value / 1000).toFixed(1) + " K"
        }
        return value.toFixed(0);
    }

    public static getLongitude(location: any) : number {
        if (location.x) return location.x;
        if (location.lon) return location.lon;
        if (location.longitude) return location.longitude;
        return Number.NaN;
    }

    public static getLatitude(location: any) : number {
        if (location.y) return location.y;
        if (location.lat) return location.lat;
        if (location.latitude) return location.latitude;
        return Number.NaN;
    }

    public static getBounds(locations: any[]) : any {
        let minLat = 90;
        let maxLat = -90;
        let minLon = 180;
        let maxLon = -180;

        for (const location of locations) {
            const crrLon = this.getLongitude(location);
            if (!Number.isNaN(crrLon)) {
                minLon = Math.min(minLon, crrLon);
                maxLon = Math.max(maxLon, crrLon);
            }

            const crrLat = this.getLatitude(location);
            if (!Number.isNaN(crrLat)) {
                minLat = Math.min(minLat, crrLat);
                maxLat = Math.max(maxLat, crrLat);
            }
        }

        const geoBounds = {
            left: minLon,
            top: minLat,
            width: Math.abs(maxLon - minLon),
            height: Math.abs(maxLat - minLat)
        };
        return geoBounds;
    }
}
    public static class WorldUtils
    {
        public static List<List<Point>> CalcPaths(GeoLocation origin, GeoLocation dest)
        {
            int interval = 200;
            List<List<Point>> paths = new List<List<Point>>() { new List<Point>() };
            int pathID = 0;
            double distance = WorldUtils.CalcDistance(origin, dest);

            if (distance <= interval)
            {
                Console.WriteLine("Distance Less Than Equal To Interval!");
                paths[pathID].Add(new Point() { X = dest.Lon, Y = dest.Lat });
            }
            else
            {
                Console.WriteLine("Distance Greater Than Interval!");
                GeoLocation current = origin;
                GeoLocation previous = origin;

                for (int dist = interval; dist <= distance; dist += interval)
                {
                    previous = current;

                    paths[pathID].Add(new Point() { X = current.Lon, Y = current.Lat });

                    double bearing = WorldUtils.CalcBearing(current, dest);
                    current = WorldUtils.CalcDestination(current, bearing, interval);

                    if (previous.Lon > 150 && current.Lon < -150)
                    {
                        paths[pathID].Add(new Point() { X = 180, Y = current.Lat });
                        paths.Add(new List<Point>());
                        pathID++;
                        current = new GeoLocation() { Lon = -180, Lat = current.Lat };
                    }
                    else if (previous.Lon < -150 && current.Lon > 150)
                    {
                        paths[pathID].Add(new Point() { X = -180, Y = current.Lat });
                        paths.Add(new List<Point>());
                        pathID++;
                        current = new GeoLocation() { Lon = 180, Lat = current.Lat };
                    }
                }

                paths[pathID].Add(new Point() { X = dest.Lon, Y = dest.Lat });

            }

            return paths;

        }

        public static double CalcBearing(GeoLocation origin, GeoLocation dest)
        {
            origin = WorldUtils.ToRadianLocation(origin);
            dest = WorldUtils.ToRadianLocation(dest);

            double range = (dest.Lon - origin.Lon);

            double y = Math.Sin(range) * Math.Cos(dest.Lat);
            double x = Math.Cos(origin.Lat) * Math.Sin(dest.Lat) - Math.Sin(origin.Lat) * Math.Cos(dest.Lat) * Math.Cos(range);
            double angle = Math.Atan2(y, x);

            return WorldUtils.ToDegreesNormalized(angle);
        }

        public static GeoLocation CalcDestination(GeoLocation origin, double bearing, double distance)
        {
            double radius = 6371.0;

            origin = WorldUtils.ToRadianLocation(origin);
            bearing = WorldUtils.ToRadians(bearing);

            distance = distance / radius;

            double lat = Math.Asin(Math.Sin(origin.Lat) * Math.Cos(distance) +
               Math.Cos(origin.Lat) * Math.Sin(distance) * Math.Cos(bearing));
            double x = Math.Sin(bearing) * Math.Sin(distance) * Math.Cos(origin.Lat);
            double y = Math.Cos(distance) - Math.Sin(origin.Lat) * Math.Sin(origin.Lat);
            double lon = origin.Lon + Math.Atan2(x, y);
            // normalize lon to coordinate between -180º and +180º
            lon = (lon + 3 * Math.PI) % (2 * Math.PI) - Math.PI;

            lon = WorldUtils.ToDegrees(lon);
            lat = WorldUtils.ToDegrees(lat);

            return new GeoLocation() { Lat = lat, Lon = lon };
        }

        public static double CalcDistance(GeoLocation origin, GeoLocation dest)
        {
            origin = WorldUtils.ToRadianLocation(origin);
            dest = WorldUtils.ToRadianLocation(dest);

            double sinProd = Math.Sin(origin.Lat) * Math.Sin(dest.Lat);
            double cosProd = Math.Cos(origin.Lat) * Math.Cos(dest.Lat);
            double lonDelta = (dest.Lon - origin.Lon);

            double angle = Math.Acos(sinProd + cosProd * Math.Cos(lonDelta));
            double distance = angle * 6371.0;
            return distance;
        }

        public static GeoLocation ToRadianLocation(GeoLocation geoPoint)
        {
            double x = WorldUtils.ToRadians(geoPoint.Lon);
            double y = WorldUtils.ToRadians(geoPoint.Lat);

            return new GeoLocation() { Lon = x, Lat = y };
        }

        public static double ToRadians(double degrees)
        {
            return degrees * Math.PI / 180;
        }

        public static double ToDegrees(double radians)
        {
            return (radians * 180.0 / Math.PI);
        }

        public static double ToDegreesNormalized(double radians)
        {
            double degrees = WorldUtils.ToDegrees(radians);
            degrees = (degrees + 360) % 360;
            return degrees;
        }

        public static string ToStringLat(double latitude)
        {
            string str = Math.Abs(latitude) + "°";
            return latitude > 0 ? str + "N" : str + "S";
        }

        public static string ToStringLon(double coordinate)
        {
            double val = Math.Abs(coordinate);
            string str = val.ToString();
            return coordinate > 0 ? str + "°E" : str + "°W";
        }

        public static string ToStringAbbr(double value)
        {
            if (value > 1000000000000)
            {
                return (value / 1000000000000).ToString("N1") + " T";
        }
            else if (value > 1000000000)
            {
                return (value / 1000000000).ToString("N1") + " B";
          }
            else if (value > 1000000)
            {
                return (value / 1000000).ToString("N1") + " M";
          }
            else if (value > 1000)
            {
                return (value / 1000).ToString("N1") + " K";
          }
            return value.ToString("N0");
        }

        public static double GetLongitude(GeoLocation location)
        {
            return location.Lon;
        }

        public static double GetLatitude(GeoLocation location)
        {
            return location.Lat;
        }

        public static Rect GetBounds(List<GeoLocation> locations)
        {
            double minLat = 90;
            double maxLat = -90;
            double minLon = 180;
            double maxLon = -180;

            foreach (GeoLocation gl in locations)
            {
                double curLon = WorldUtils.GetLongitude(gl);
                double curLat = WorldUtils.GetLatitude(gl);

                if (!double.IsNaN(curLon))
                {
                    minLon = Math.Min(minLon, curLon);
                    maxLon = Math.Max(maxLon, curLon);
                }

                if (!double.IsNaN(curLat))
                {
                    minLat = Math.Min(minLat, curLat);
                    maxLat = Math.Min(maxLat, curLat);
                }
            }

            Rect geoBounds = new Rect(minLon, minLat, Math.Abs(maxLon - minLon), Math.Abs(maxLat - minLat));
            return geoBounds;
        }

        public static List<Point> GetNightShapes()
        {
            List<Point> line = new List<Point>();

            for (int lon = -180; lon <= 180; lon += 1)
            {
                double x = lon;
                double y = 75 * Math.Cos(lon * Math.PI / 180);
                line.Add(new Point(x, y));
            }

            return line;
        }
    }

API References