/// <summary>
    /// Override the getSatelliteImagery to get an image from Bing's REST API
    /// </summary>
    /// <param name="x">Unity units in direction x from origin</param>
    /// <param name="z">Unity units in direction z from origin</param>
    /// <returns>A 2D texture of the image as a byte stream</returns>
    async Task <byte[]> IMapResources.getSatelliteImagery(float x, float z)
    {
        HttpClient client = new HttpClient();

        if (String.IsNullOrEmpty(restapiurl.subdomain))
        {
            await restapiurl.initializeURL();
        }

        //Use x and z to offset the quadkey
        int tilex           = 0;
        int tilez           = 0;
        int chosenZoomLevel = 14;

        QuadKeyFuncs.QuadKeyToTileXY(originQuadKey, out tilex, out tilez, out chosenZoomLevel);
        tilex = tilex + Convert.ToInt32(x) / 256;
        tilez = tilez + Convert.ToInt32(z) / 256;
        String newQuadKey = QuadKeyFuncs.TileXYToQuadKey(tilex, tilez, chosenZoomLevel);

        String quadKeyURL = restapiurl.exampleURL;

        quadKeyURL = quadKeyURL.Replace("{subdomain}", restapiurl.subdomain);
        quadKeyURL = quadKeyURL.Replace("r{quadkey}", "a" + (string)newQuadKey.ToString());
        quadKeyURL = quadKeyURL.Replace("{culture}", "en-US");
        var response = await client.GetAsync(quadKeyURL.Replace("\\", ""));

        var imageData  = response.Content;
        var imageBytes = await imageData.ReadAsByteArrayAsync();

        return(imageBytes);
    }
    /// <summary>
    /// Constructor for BingMapResources.
    /// </summary>
    public BingMapResources()
    {
        string[] lines  = System.IO.File.ReadAllLines(@"Assets/config");
        string   apikey = lines[0].Substring(17, lines[0].Length - 18);

        restapiurl = new imageURLRequest(apikey);

        originQuadKey = QuadKeyFuncs.getQuadKey(Globals.latitude, Globals.longitude, 14);
    }
    /// <summary>
    /// This function is the function run inside the Tile Prediction thread started in
    /// AppHandler's start function. It runs for the entire program, checking the current
    /// location of the camera and loading any tiles nearby that it can't find already into
    /// the database. Having the database work as a cache like this makes it easy to have tiles
    /// ready for the actual placement function later.
    /// </summary>
    async public void tilePredictor()
    {
        //Create a cache object to do a database check
        Cache         cache = new Cache();
        IMapResources BMR   = new BingMapResources();


        while (true)
        {
            // Check current position
            Vector3 currpos = Globals.position;
            int     x       = Convert.ToInt32(Math.Round(currpos[0] / 32));
            int     z       = Convert.ToInt32(Math.Round(currpos[2] / 32));

            //Check for tiles within needed range
            //We want all tiles in a 12x12 range
            for (int i = x - 6; i < x + 6; i++)
            {
                for (int j = z - 6; j < z + 6; j++)
                {
                    //Check if current tile exists
                    Tuple <int, int> tempTuple = new Tuple <int, int>(i, j);
                    if (!active.Contains(tempTuple))
                    {
                        //Make sure that the maps coordinates are converted from Unity to Bing Maps TileXY
                        int mapi = i * 256;
                        int mapj = -j * 256;
                        //Check the database for current tile using quadkey
                        //Calculate the quadkey for the given tile
                        String originQuadKey = QuadKeyFuncs.getQuadKey(Globals.latitude, Globals.longitude, 14);
                        //Use x and z to offset the quadkey
                        int initx = 0;
                        int initz = 0;
                        int initChosenZoomLevel = 14;
                        QuadKeyFuncs.QuadKeyToTileXY(originQuadKey, out initx, out initz, out initChosenZoomLevel);
                        initx = initx + Convert.ToInt32(mapi) / 256;
                        initz = initz + Convert.ToInt32(mapj) / 256;
                        String newQuadKey = QuadKeyFuncs.TileXYToQuadKey(initx, initz, initChosenZoomLevel);

                        bool inDatabase = cache.DBcheck(newQuadKey);

                        //If it doesn't exist in the database, we will add it ourselves
                        if (!inDatabase)
                        {
                            List <float> mesh = await getElevChunk((float)mapi, (float)mapj);

                            var mat = await BMR.getSatelliteImagery((float)mapi, (float)mapj);

                            cache.DBInsert(newQuadKey, mesh, mat);
                        }
                    }
                }
            }
        }
    }
Beispiel #4
0
    /// <summary>
    /// This function takes in two Unity coordinates and finds the quadkey
    /// of those coordinates based on the Global starting latitude and longitude.
    /// It then checks to see if that quad key already exists in the database.
    /// If it doesn't find the entry, it will return an empty mesh and material
    /// with a bool to indicate that these are not database entries, but rather
    /// defaults
    /// </summary>
    /// <param name="x">The X coordinate for the searched position in unity coordinates</param>
    /// <param name="z">The Z coordinate for the searched position in unity coordinates</param>
    /// <returns></returns>
    public static Tuple <Mesh, Material, bool> BuildTile(float x, float z)
    {
        //Calculate the quadkey for the original starting tile
        String originQuadKey       = QuadKeyFuncs.getQuadKey(Globals.latitude, Globals.longitude, 14);
        int    initx               = 0;
        int    initz               = 0;
        int    initChosenZoomLevel = 14;

        //Find the X and Y coordinate in Bing Maps Tiles
        QuadKeyFuncs.QuadKeyToTileXY(originQuadKey, out initx, out initz, out initChosenZoomLevel);
        //Offset the BingMapsAPI coordinates from the starting point by x and z in unity
        initx = initx + Convert.ToInt32(x) / 256;
        initz = initz + Convert.ToInt32(z) / 256;
        //Get a quadkey for the new location
        String currQuadKey = QuadKeyFuncs.TileXYToQuadKey(initx, initz, initChosenZoomLevel);

        //Check DB for current entry
        Cache cache       = new Cache();
        bool  entryExists = cache.DBcheck(currQuadKey);

        //Create an empty mesh and Material
        Mesh     mesh = new Mesh();
        Material mat  = new Material(Shader.Find("Standard"));

        if (entryExists)
        {
            Tuple <List <float>, Texture> TileTuple = cache.DBGet(currQuadKey);

            //Ready the mesh
            //Perform array size calculations
            int length     = TileTuple.Item1.Count;
            int side       = (int)Mathf.Sqrt(length);
            int sqrPtCount = (int)(Mathf.Pow((side - 1), 2) * 6);

            //Create empty vertices, uv, and triangles arrays and set their values
            Vector3[] vertices  = fillVert(length, side, TileTuple.Item1);
            Vector2[] uv        = fillUv(length, side);
            int[]     triangles = fillTri(sqrPtCount, side);

            //Create a new Mesh to render, assign its components, and recalculate
            //its normals for smooth rendering
            mesh.vertices  = vertices;
            mesh.uv        = uv;
            mesh.triangles = triangles;
            mesh.RecalculateNormals();

            //Ready the material
            mat.mainTexture      = TileTuple.Item2;
            mat.mainTextureScale = new Vector2((float)(1.0 / 32.0), (float)(1.0 / 32.0));
        }

        return(new Tuple <Mesh, Material, bool>(mesh, mat, entryExists));
    }
    /// <summary>
    /// Override the getMesh function to get data from Bing's REST API
    /// </summary>
    /// <param name="x">Unity units in direction x from origin</param>
    /// <param name="z">Unity units in direction z from origin</param>
    /// <returns>A list of elevation points</returns>
    List <float> IMapResources.getMesh(float x, float z)
    {
        //Use x and z to offset the quadkey
        int initx = 0;
        int initz = 0;
        int initChosenZoomLevel = 14;

        QuadKeyFuncs.QuadKeyToTileXY(originQuadKey, out initx, out initz, out initChosenZoomLevel);
        initx = initx + Convert.ToInt32(x) / 256;
        initz = initz + Convert.ToInt32(z) / 256;
        String newQuadKey = QuadKeyFuncs.TileXYToQuadKey(initx, initz, initChosenZoomLevel);

        double ucLat;
        double ucLong;

        QuadKeyFuncs.QuadKeyToLatLong(newQuadKey, out ucLat, out ucLong);
        double lcLat;
        double lcLong;
        //Get the lower right corner
        int tilex = 0;
        int tilez = 0;
        int chosenZoomLevel;

        QuadKeyFuncs.QuadKeyToTileXY(newQuadKey, out tilex, out tilez, out chosenZoomLevel);
        tilex = tilex + 1;
        tilez = tilez + 1;
        String lcquadkey = QuadKeyFuncs.TileXYToQuadKey(tilex, tilez, chosenZoomLevel);

        QuadKeyFuncs.QuadKeyToLatLong(lcquadkey, out lcLat, out lcLong);
        //Get chunks from database if it exists

        //Otherwise, get the mesh from Bing's REST API
        List <float> mesh = ElevationRequest(ucLat, ucLong, lcLat, lcLong, 32, newQuadKey.Length);


        return(mesh);
    }
Beispiel #6
0
    /// <summary>
    /// The start function that initializes the test of the location panel
    /// and finds the coordinate difference between tiles.
    /// </summary>
    void Start()
    {
        double lat0       = 0;
        double longitude0 = 0;
        double lat1       = 0;
        double longitude1 = 0;
        int    pixelX     = 0;
        int    pixelY     = 0;

        // Find coordinates at Tile 0,0
        QuadKeyFuncs.TileXYToPixelXY(0, 0, out pixelX, out pixelY);
        QuadKeyFuncs.PixelXYToLatLong(pixelX, pixelY, 14, out lat0, out longitude0);
        // Find coordinates at Tile 1,1
        QuadKeyFuncs.TileXYToPixelXY(1, 1, out pixelX, out pixelY);
        QuadKeyFuncs.PixelXYToLatLong(pixelX, pixelY, 14, out lat1, out longitude1);

        lat_diff  = (lat1 - lat0) / 256;
        long_diff = (longitude1 - longitude0) / 256;

        display = GetComponent <Text>();

        display.text = "Latitude:" +
                       "\nLongitude:";
    }
    /// <summary>
    /// This is an asynchronous version of the getElevFunction in BingMapResources.cs.
    /// It gets an elevation chunk from BingMaps Rest API using an offset from the
    /// starting latitude and longitude in globals.
    /// </summary>
    /// <param name="x">The Unity coordinate for X</param>
    /// <param name="z">The Unity coordinate for Z</param>
    /// <returns></returns>
    async public Task <List <float> > getElevChunk(float x, float z)
    {
        String originQuadKey = QuadKeyFuncs.getQuadKey(Globals.latitude, Globals.longitude, 14);

        int initx = 0;
        int initz = 0;
        int initChosenZoomLevel = 14;

        QuadKeyFuncs.QuadKeyToTileXY(originQuadKey, out initx, out initz, out initChosenZoomLevel);
        initx = initx + Convert.ToInt32(x) / 256;
        initz = initz + Convert.ToInt32(z) / 256;
        //Get the upper left corner
        String newQuadKey = QuadKeyFuncs.TileXYToQuadKey(initx, initz, initChosenZoomLevel);
        double ucLat;
        double ucLong;

        QuadKeyFuncs.QuadKeyToLatLong(newQuadKey, out ucLat, out ucLong);
        double lcLat;
        double lcLong;
        //Get the lower right corner
        int tilex = 0;
        int tilez = 0;
        int chosenZoomLevel;

        QuadKeyFuncs.QuadKeyToTileXY(newQuadKey, out tilex, out tilez, out chosenZoomLevel);
        tilex = tilex + 1;
        tilez = tilez + 1;
        String lcquadkey = QuadKeyFuncs.TileXYToQuadKey(tilex, tilez, chosenZoomLevel);

        QuadKeyFuncs.QuadKeyToLatLong(lcquadkey, out lcLat, out lcLong);

        //Request Bing API elevations using the corners as a bounding box
        String     requestString      = "http://dev.virtualearth.net/REST/v1/Elevation/Bounds?bounds=" + (lcLat) + "," + (lcLong) + "," + (ucLat) + "," + (ucLong) + "&rows=32&cols=32&key=" + Globals.BingAPIKey;
        HttpClient client             = new HttpClient();
        var        content            = "";
        bool       tooManyRequestFlag = false;

        do
        {
            tooManyRequestFlag = false;
            try
            {
                content = await client.GetStringAsync(requestString);
            }
            catch (HttpRequestException e)
            {
                if (e.Message == "429 (Too Many Requests)")
                {
                    tooManyRequestFlag = true;
                }
                else
                {
                    throw e;
                }
            }
        } while (tooManyRequestFlag);

        int i;
        int j;
        int k;

        //Convert the retrieved elevations into a usable chunk
        int           start             = content.IndexOf("\"elevations\"") + 14;
        int           end               = content.IndexOf("\"zoomLevel\"") - 2;
        String        elevation_string  = content.Substring(start, end - start);
        List <String> elevation_strings = elevation_string.Split(',').ToList();
        List <float>  retrieved_chunk   = new List <float>();

        for (k = 0; k < elevation_strings.Count; k++)
        {
            retrieved_chunk.Add(Convert.ToSingle(elevation_strings[k]));
        }

        //Flip the values in the retrieved chunks so that it matches the order of satellite imagery
        //Note that elevations in Bing go from the bottom up in a square while the imagery uses the
        //top left corner as its baseline. We chose to change the order of the elevations
        List <float> newElevChunk = new List <float>();

        for (i = 0; i < Math.Sqrt(retrieved_chunk.Count); i++)
        {
            for (j = 0; j < Math.Sqrt(retrieved_chunk.Count); j++)
            {
                newElevChunk.Add(retrieved_chunk[(31 - j) * Convert.ToInt32(Math.Sqrt(retrieved_chunk.Count)) + (31 - i)]);
            }
        }
        return(newElevChunk);
    }