Ejemplo n.º 1
0
        /// <summary>
        /// This is the method that actually does the work.
        /// </summary>
        /// <param name="DA">The DA object is used to retrieve from inputs and store in outputs.</param>
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            List <Curve> boundary = new List <Curve>();

            DA.GetDataList <Curve>(0, boundary);

            int zoom = -1;

            DA.GetData <int>(1, ref zoom);

            string fileloc = "";

            DA.GetData <string>(2, ref fileloc);
            if (!fileloc.EndsWith(@"\"))
            {
                fileloc = fileloc + @"\";
            }

            string prefix = "";

            DA.GetData <string>(3, ref prefix);
            if (prefix == "")
            {
                prefix = mbSource;
            }

            string URL = mbURL;
            //DA.GetData<string>(4, ref URL);

            ///get a valid mapbox token to send along with query
            string mbToken = "";

            DA.GetData <string>(4, ref mbToken);
            if (mbToken == "")
            {
                string hmbToken = System.Environment.GetEnvironmentVariable("HERONMAPBOXTOKEN");
                if (hmbToken != null)
                {
                    mbToken = hmbToken;
                    AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "Using Mapbox token stored in Environment Variable HERONMAPBOXTOKEN.");
                }
                else
                {
                    AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "No Mapbox token is specified.  Please get a valid token from mapbox.com");
                    return;
                }
            }

            bool run = false;

            DA.GetData <bool>("Run", ref run);

            GH_Structure <GH_String>    mapList  = new GH_Structure <GH_String>();
            GH_Structure <GH_Rectangle> imgFrame = new GH_Structure <GH_Rectangle>();
            GH_Structure <GH_String>    tCount   = new GH_Structure <GH_String>();


            for (int i = 0; i < boundary.Count; i++)
            {
                GH_Path path                = new GH_Path(i);
                int     tileTotalCount      = 0;
                int     tileDownloadedCount = 0;


                //Get image frame for given boundary and  make sure it's valid
                if (!boundary[i].GetBoundingBox(true).IsValid)
                {
                    AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Boundary is not valid.");
                    return;
                }
                BoundingBox boundaryBox = boundary[i].GetBoundingBox(true);

                ///TODO: look into scaling boundary to get buffer tiles

                ///file path for final image
                string imgPath = fileloc + prefix + "_" + i + ".jpg";

                //location of final image file
                mapList.Append(new GH_String(imgPath), path);

                //create cache folder for images
                string        cacheLoc      = fileloc + @"HeronCache\";
                List <string> cacheFileLocs = new List <string>();
                if (!Directory.Exists(cacheLoc))
                {
                    Directory.CreateDirectory(cacheLoc);
                }

                //tile bounding box array
                List <Point3d> boxPtList = new List <Point3d>();

                //get the tile coordinates for all tiles within boundary
                var ranges = Convert.GetTileRange(boundaryBox, zoom);
                List <List <int> > tileList = new List <List <int> >();
                var x_range = ranges.XRange;
                var y_range = ranges.YRange;

                if (x_range.Length > 100 || y_range.Length > 100)
                {
                    AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "This tile range is too big (more than 100 tiles in the x or y direction). Check your units.");
                    return;
                }

                //cycle through tiles to get bounding box
                for (int y = (int)y_range.Min; y <= y_range.Max; y++)
                {
                    for (int x = (int)x_range.Min; x <= x_range.Max; x++)
                    {
                        //add bounding box of tile to list
                        boxPtList.AddRange(Convert.GetTileAsPolygon(zoom, y, x).ToList());
                        cacheFileLocs.Add(cacheLoc + mbSource.Replace(" ", "") + zoom + x + y + ".jpg");
                        tileTotalCount = tileTotalCount + 1;
                    }
                }

                tCount.Insert(new GH_String(tileTotalCount + " tiles (" + tileDownloadedCount + " downloaded / " + (tileTotalCount - tileDownloadedCount) + " cached)"), path, 0);

                //bounding box of tile boundaries
                BoundingBox bbox = new BoundingBox(boxPtList);

                var rect = BBoxToRect(bbox);
                imgFrame.Append(new GH_Rectangle(rect), path);

                AddPreviewItem(imgPath, boundary[i], rect);

                ///tile range as string for (de)serialization of TileCacheMeta
                string tileRangeString = zoom.ToString()
                                         + x_range[0].ToString()
                                         + y_range[0].ToString()
                                         + x_range[1].ToString()
                                         + y_range[1].ToString();

                ///check if the existing final image already covers the boundary.
                ///if so, no need to download more or reassemble the cached tiles.
                if ((TileCacheMeta == tileRangeString) && Convert.CheckCacheImagesExist(cacheFileLocs))
                {
                    if (File.Exists(imgPath))
                    {
                        using (Bitmap imageT = new Bitmap(imgPath))
                        {
                            ///getting commments currently only working for JPG
                            ///TODO: get this to work for any image type or
                            ///find another way to check if the cached image covers the boundary.
                            string imgComment = imageT.GetCommentsFromJPG();

                            imageT.Dispose();

                            ///check to see if tilerange in comments matches current tilerange
                            if (imgComment == (mbSource.Replace(" ", "") + tileRangeString))
                            {
                                AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "Using existing image.");
                                continue;
                            }
                        }
                    }
                }



                ///Query Mapbox URL
                ///download all tiles within boundary
                ///merge tiles into one bitmap
                ///API to query
                string mbURLauth = mbURL + mbToken;


                ///Do the work of assembling image
                ///setup final image container bitmap
                int    fImageW    = ((int)x_range.Length + 1) * 512;
                int    fImageH    = ((int)y_range.Length + 1) * 512;
                Bitmap finalImage = new Bitmap(fImageW, fImageH);


                int imgPosW = 0;
                int imgPosH = 0;

                if (run == true)
                {
                    using (Graphics g = Graphics.FromImage(finalImage))
                    {
                        g.Clear(Color.Black);
                        for (int y = (int)y_range.Min; y <= (int)y_range.Max; y++)
                        {
                            for (int x = (int)x_range.Min; x <= (int)x_range.Max; x++)
                            {
                                ///create tileCache name
                                string tileCache    = mbSource.Replace(" ", "") + zoom + x + y + ".jpg";
                                string tileCahceLoc = cacheLoc + tileCache;

                                ///check cache folder to see if tile image exists locally
                                if (File.Exists(tileCahceLoc))
                                {
                                    Bitmap tmpImage = new Bitmap(Image.FromFile(tileCahceLoc));
                                    ///add tmp image to final
                                    g.DrawImage(tmpImage, imgPosW * 512, imgPosH * 512);
                                    tmpImage.Dispose();
                                }

                                else
                                {
                                    tileList.Add(new List <int> {
                                        zoom, y, x
                                    });
                                    string urlAuth = Convert.GetZoomURL(x, y, zoom, mbURLauth);

                                    System.Net.WebClient client = new System.Net.WebClient();
                                    client.DownloadFile(urlAuth, tileCahceLoc);
                                    Bitmap tmpImage = new Bitmap(Image.FromFile(tileCahceLoc));
                                    client.Dispose();

                                    ///add tmp image to final
                                    g.DrawImage(tmpImage, imgPosW * 512, imgPosH * 512);
                                    tmpImage.Dispose();
                                    tileDownloadedCount = tileDownloadedCount + 1;
                                }

                                ///increment x insert position, goes left to right
                                imgPosW++;
                            }
                            ///increment y insert position, goes top to bottom
                            imgPosH++;
                            imgPosW = 0;
                        }
                        ///garbage collection
                        g.Dispose();

                        ///add tile range meta data to image comments
                        finalImage.AddCommentsToJPG(mbSource.Replace(" ", "") + tileRangeString);

                        ///save the image
                        finalImage.Save(imgPath, System.Drawing.Imaging.ImageFormat.Jpeg);
                    }
                }

                //garbage collection
                finalImage.Dispose();


                //add to tile count total
                tCount.Insert(new GH_String(tileTotalCount + " tiles (" + tileDownloadedCount + " downloaded / " + (tileTotalCount - tileDownloadedCount) + " cached)"), path, 0);

                //write out new tile range metadata for serialization
                TileCacheMeta = tileRangeString;

                //AddPreviewItem(imgPath, boundary[i], rect);
            }


            DA.SetDataTree(0, mapList);
            DA.SetDataTree(1, imgFrame);
            DA.SetDataTree(2, tCount);
            DA.SetDataList(3, "copyright Mapbox");
        }
Ejemplo n.º 2
0
        /// <summary>
        /// This is the method that actually does the work.
        /// </summary>
        /// <param name="DA">The DA object is used to retrieve from inputs and store in outputs.</param>
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            List <Curve> boundary = new List <Curve>();

            DA.GetDataList(0, boundary);

            int zoom = -1;

            DA.GetData(1, ref zoom);

            string filePath = string.Empty;

            DA.GetData(2, ref filePath);
            if (!filePath.EndsWith(@"\"))
            {
                filePath = filePath + @"\";
            }

            string prefix = string.Empty;

            DA.GetData(3, ref prefix);
            if (prefix == string.Empty)
            {
                prefix = slippySource;
            }

            string URL = slippyURL;

            string userAgent = string.Empty;

            DA.GetData(4, ref userAgent);

            bool run = false;

            DA.GetData <bool>("Run", ref run);

            GH_Structure <GH_String>    mapList  = new GH_Structure <GH_String>();
            GH_Structure <GH_Rectangle> imgFrame = new GH_Structure <GH_Rectangle>();
            GH_Structure <GH_String>    tCount   = new GH_Structure <GH_String>();



            for (int i = 0; i < boundary.Count; i++)
            {
                GH_Path path                = new GH_Path(i);
                int     tileTotalCount      = 0;
                int     tileDownloadedCount = 0;


                ///Get image frame for given boundary and  make sure it's valid
                if (!boundary[i].GetBoundingBox(true).IsValid)
                {
                    AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Boundary is not valid.");
                    return;
                }
                BoundingBox boundaryBox = boundary[i].GetBoundingBox(true);

                ///TODO: look into scaling boundary to get buffer tiles

                ///file path for final image
                string imgPath = filePath + prefix + "_" + i + ".jpg";

                if (!tilesOut)
                {
                    //location of final image file
                    mapList.Append(new GH_String(imgPath), path);
                }

                ///create cache folder for images
                string        cacheLoc       = filePath + @"HeronCache\";
                List <string> cacheFilePaths = new List <string>();
                if (!Directory.Exists(cacheLoc))
                {
                    Directory.CreateDirectory(cacheLoc);
                }

                ///tile bounding box array
                List <Point3d> boxPtList = new List <Point3d>();

                ///get the tile coordinates for all tiles within boundary
                var ranges = Convert.GetTileRange(boundaryBox, zoom);
                List <List <int> > tileList = new List <List <int> >();
                var x_range = ranges.XRange;
                var y_range = ranges.YRange;

                if (x_range.Length > 100 || y_range.Length > 100)
                {
                    AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "This tile range is too big (more than 100 tiles in the x or y direction). Check your units.");
                    return;
                }

                List <Rectangle3d> tileRectangles = new List <Rectangle3d>();

                ///cycle through tiles to get bounding box
                for (int y = (int)y_range.Min; y <= y_range.Max; y++)
                {
                    for (int x = (int)x_range.Min; x <= x_range.Max; x++)
                    {
                        ///add bounding box of tile to list
                        List <Point3d> boxPts = Convert.GetTileAsPolygon(zoom, y, x).ToList();
                        boxPtList.AddRange(Convert.GetTileAsPolygon(zoom, y, x).ToList());
                        string cacheFilePath = cacheLoc + slippySource.Replace(" ", "") + zoom + "-" + x + "-" + y + ".jpg";
                        cacheFilePaths.Add(cacheFilePath);

                        tileTotalCount = tileTotalCount + 1;

                        if (tilesOut)
                        {
                            mapList.Append(new GH_String(cacheFilePath), path);
                            Rectangle3d tileRectangle = BBoxToRect(new BoundingBox(boxPts));
                            tileRectangles.Add(tileRectangle);
                            imgFrame.Append(new GH_Rectangle(tileRectangle), path);
                        }
                    }
                }

                tCount.Insert(new GH_String(tileTotalCount + " tiles (" + tileDownloadedCount + " downloaded / " + (tileTotalCount - tileDownloadedCount) + " cached)"), path, 0);

                ///bounding box of tile boundaries
                BoundingBox bbox = new BoundingBox(boxPtList);

                var rect = BBoxToRect(bbox);
                if (!tilesOut)
                {
                    imgFrame.Append(new GH_Rectangle(rect), path);
                }

                //AddPreviewItem(imgPath, boundary[i], rect);

                ///tile range as string for (de)serialization of TileCacheMeta
                string tileRangeString = zoom.ToString()
                                         + x_range[0].ToString()
                                         + y_range[0].ToString()
                                         + x_range[1].ToString()
                                         + y_range[1].ToString();

                ///check if the existing final image already covers the boundary.
                ///if so, no need to download more or reassemble the cached tiles.
                if ((TileCacheMeta == tileRangeString) && Convert.CheckCacheImagesExist(cacheFilePaths))
                {
                    if (File.Exists(imgPath) && !tilesOut)
                    {
                        using (Bitmap imageT = new Bitmap(imgPath))
                        {
                            ///getting commments currently only working for JPG
                            ///TODO: get this to work for any image type or
                            ///find another way to check if the cached image covers the boundary.
                            string imgComment = imageT.GetCommentsFromJPG();

                            imageT.Dispose();

                            ///check to see if tilerange in comments matches current tilerange
                            if (imgComment == (slippySource.Replace(" ", "") + tileRangeString))
                            {
                                AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "Using existing image.");
                                AddPreviewItem(imgPath, boundary[i], rect);
                                continue;
                            }
                        }
                    }

                    if (tilesOut)
                    {
                        for (int t = 0; t < cacheFilePaths.Count; t++)
                        {
                            if (File.Exists(cacheFilePaths[t]))
                            {
                                AddPreviewItem(cacheFilePaths[t], tileRectangles[t].ToNurbsCurve(), tileRectangles[t]);
                            }
                        }
                        continue;
                    }
                }



                ///Query Slippy URL
                ///download all tiles within boundary
                ///merge tiles into one bitmap
                ///API to query


                ///Do the work of assembling image
                ///setup final image container bitmap
                int    fImageW    = ((int)x_range.Length + 1) * 256;
                int    fImageH    = ((int)y_range.Length + 1) * 256;
                Bitmap finalImage = new Bitmap(fImageW, fImageH);


                int imgPosW = 0;
                int imgPosH = 0;

                using (Graphics g = Graphics.FromImage(finalImage))
                {
                    g.Clear(Color.Black);
                    for (int y = (int)y_range.Min; y <= (int)y_range.Max; y++)
                    {
                        for (int x = (int)x_range.Min; x <= (int)x_range.Max; x++)
                        {
                            //create tileCache name
                            string tileCache    = slippySource.Replace(" ", "") + zoom + "-" + x + "-" + y + ".jpg";
                            string tileCacheLoc = cacheLoc + tileCache;

                            //check cache folder to see if tile image exists locally
                            if (File.Exists(tileCacheLoc))
                            {
                                Bitmap tmpImage = new Bitmap(Image.FromFile(tileCacheLoc));
                                ///add tmp image to final
                                g.DrawImage(tmpImage, imgPosW * 256, imgPosH * 256);
                                tmpImage.Dispose();
                            }

                            else
                            {
                                tileList.Add(new List <int> {
                                    zoom, y, x
                                });
                                string urlAuth = Convert.GetZoomURL(x, y, zoom, slippyURL);

                                Bitmap tmpImage             = new Bitmap(256, 256);
                                System.Net.WebClient client = new System.Net.WebClient();

                                ///insert header if required
                                client.Headers.Add("user-agent", userAgent);
                                if (run == true)
                                {
                                    try
                                    {
                                        client.DownloadFile(urlAuth, tileCacheLoc);
                                        tmpImage = new Bitmap(Image.FromFile(tileCacheLoc));
                                    }
                                    catch (WebException e)
                                    {
                                        using (Graphics tmp = Graphics.FromImage(tmpImage)) { tmp.Clear(Color.White); }
                                        AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, e.Message);
                                    }
                                }
                                client.Dispose();

                                //add tmp image to final
                                g.DrawImage(tmpImage, imgPosW * 256, imgPosH * 256);
                                tmpImage.Dispose();
                                tileDownloadedCount = tileDownloadedCount + 1;
                            }

                            //increment x insert position, goes left to right
                            imgPosW++;
                        }
                        //increment y insert position, goes top to bottom
                        imgPosH++;
                        imgPosW = 0;
                    }
                    //garbage collection
                    g.Dispose();

                    //add tile range meta data to image comments
                    finalImage.AddCommentsToJPG(slippySource.Replace(" ", "") + tileRangeString);



                    //save the image
                    finalImage.Save(imgPath, System.Drawing.Imaging.ImageFormat.Jpeg);
                }

                //garbage collection
                finalImage.Dispose();

                if (!tilesOut)
                {
                    AddPreviewItem(imgPath, boundary[i], rect);
                }
                else
                {
                    for (int t = 0; t < cacheFilePaths.Count; t++)
                    {
                        if (File.Exists(cacheFilePaths[t]))
                        {
                            AddPreviewItem(cacheFilePaths[t], tileRectangles[t].ToNurbsCurve(), tileRectangles[t]);
                        }
                    }
                }

                //add to tile count total
                tCount.Insert(new GH_String(tileTotalCount + " tiles (" + tileDownloadedCount + " downloaded / " + (tileTotalCount - tileDownloadedCount) + " cached)"), path, 0);

                //write out new tile range metadata for serialization
                TileCacheMeta = tileRangeString;
            }


            DA.SetDataTree(0, mapList);
            DA.SetDataTree(1, imgFrame);
            DA.SetDataTree(2, tCount);
            ///Add copyright info here
            DA.SetDataList(3, "");
        }
Ejemplo n.º 3
0
        /// <summary>
        /// This is the method that actually does the work.
        /// </summary>
        /// <param name="DA">The DA object is used to retrieve from inputs and store in outputs.</param>
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            List <Curve> boundary = new List <Curve>();

            DA.GetDataList <Curve>(0, boundary);

            int zoom = -1;

            DA.GetData <int>(1, ref zoom);

            string folderPath = string.Empty;

            DA.GetData <string>(2, ref folderPath);
            if (!folderPath.EndsWith(@"\"))
            {
                folderPath = folderPath + @"\";
            }

            string prefix = string.Empty;

            DA.GetData <string>(3, ref prefix);
            if (prefix == "")
            {
                prefix = mbSource;
            }

            string URL = mbURL;

            ///get a valid mapbox token to send along with query
            string mbToken = string.Empty;

            DA.GetData <string>(4, ref mbToken);
            if (mbToken == "")
            {
                string hmbToken = System.Environment.GetEnvironmentVariable("HERONMAPBOXTOKEN");
                if (hmbToken != null)
                {
                    mbToken = hmbToken;
                    AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "Using Mapbox token stored in Environment Variable HERONMAPBOXTOKEN.");
                }
                else
                {
                    AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "No Mapbox token is specified.  Please get a valid token from mapbox.com");
                    return;
                }
            }

            bool run = false;

            DA.GetData <bool>("Run", ref run);

            GH_Structure <GH_String>    mapList  = new GH_Structure <GH_String>();
            GH_Structure <GH_Rectangle> imgFrame = new GH_Structure <GH_Rectangle>();
            GH_Structure <GH_String>    tCount   = new GH_Structure <GH_String>();

            /*
             * ///Save for later development of warping
             * ///Setup for warping
             * RESTful.GdalConfiguration.ConfigureGdal();
             * RESTful.GdalConfiguration.ConfigureOgr();
             *
             * OSGeo.OSR.SpatialReference userSRS = new OSGeo.OSR.SpatialReference("");
             * userSRS.SetFromUserInput("WGS84");
             *
             * OSGeo.OSR.SpatialReference mapboxSRS = new OSGeo.OSR.SpatialReference("");
             * mapboxSRS.SetFromUserInput("EPSG:3857");
             *
             * ///Set transform from input spatial reference to Rhino spatial reference
             * OSGeo.OSR.SpatialReference rhinoSRS = new OSGeo.OSR.SpatialReference("");
             * rhinoSRS.SetWellKnownGeogCS("WGS84");
             *
             * ///This transform moves and scales the points required in going from userSRS to XYZ and vice versa
             * //Transform userSRSToModelTransform = Heron.Convert.GetUserSRSToModelTransform(userSRS);
             * Transform modelToUserSRSTransform = Heron.Convert.GetModelToUserSRSTransform(userSRS);
             * Transform mapboxSRSToModelTransform = Heron.Convert.GetUserSRSToModelTransform(mapboxSRS);
             * Transform modelToMapboxSRSTransform = Heron.Convert.GetModelToUserSRSTransform(mapboxSRS);
             */

            for (int i = 0; i < boundary.Count; i++)
            {
                GH_Path path                = new GH_Path(i);
                int     tileTotalCount      = 0;
                int     tileDownloadedCount = 0;


                //Get image frame for given boundary and  make sure it's valid
                if (!boundary[i].GetBoundingBox(true).IsValid)
                {
                    AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Boundary is not valid.");
                    return;
                }
                BoundingBox boundaryBox = boundary[i].GetBoundingBox(true);

                ///TODO: look into scaling boundary to get buffer tiles

                ///file path for final image
                string imgPath = folderPath + prefix + "_" + i + ".jpg";

                if (!tilesOut)
                {
                    //location of final image file
                    mapList.Append(new GH_String(imgPath), path);
                }

                //create cache folder for images
                string        cacheLoc       = folderPath + @"HeronCache\";
                List <string> cacheFilePaths = new List <string>();
                if (!Directory.Exists(cacheLoc))
                {
                    Directory.CreateDirectory(cacheLoc);
                }

                //tile bounding box array
                List <Point3d> boxPtList = new List <Point3d>();

                //get the tile coordinates for all tiles within boundary
                var ranges = Convert.GetTileRange(boundaryBox, zoom);
                List <List <int> > tileList = new List <List <int> >();
                var x_range = ranges.XRange;
                var y_range = ranges.YRange;

                if (x_range.Length > 100 || y_range.Length > 100)
                {
                    AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "This tile range is too big (more than 100 tiles in the x or y direction). Check your units.");
                    return;
                }

                List <Rectangle3d> tileRectangles = new List <Rectangle3d>();

                //cycle through tiles to get bounding box
                for (int y = (int)y_range.Min; y <= y_range.Max; y++)
                {
                    for (int x = (int)x_range.Min; x <= x_range.Max; x++)
                    {
                        //add bounding box of tile to list
                        List <Point3d> boxPts = Convert.GetTileAsPolygon(zoom, y, x).ToList();
                        boxPtList.AddRange(boxPts);
                        string cacheFilePath = cacheLoc + mbSource.Replace(" ", "") + zoom + "-" + x + "-" + y + ".jpg";
                        cacheFilePaths.Add(cacheFilePath);

                        tileTotalCount = tileTotalCount + 1;

                        if (tilesOut)
                        {
                            mapList.Append(new GH_String(cacheFilePath), path);
                            Rectangle3d tileRectangle = BBoxToRect(new BoundingBox(boxPts));
                            tileRectangles.Add(tileRectangle);
                            imgFrame.Append(new GH_Rectangle(tileRectangle), path);
                        }
                    }
                }

                tCount.Insert(new GH_String(tileTotalCount + " tiles (" + tileDownloadedCount + " downloaded / " + (tileTotalCount - tileDownloadedCount) + " cached)"), path, 0);

                //bounding box of tile boundaries
                BoundingBox bbox = new BoundingBox(boxPtList);

                var rect = BBoxToRect(bbox);
                if (!tilesOut)
                {
                    imgFrame.Append(new GH_Rectangle(rect), path);
                }

                ///tile range as string for (de)serialization of TileCacheMeta
                string tileRangeString = zoom.ToString()
                                         + x_range[0].ToString()
                                         + y_range[0].ToString()
                                         + x_range[1].ToString()
                                         + y_range[1].ToString();

                ///check if the existing final image already covers the boundary.
                ///if so, no need to download more or reassemble the cached tiles.

                if ((TileCacheMeta == tileRangeString) && Convert.CheckCacheImagesExist(cacheFilePaths))
                {
                    if (File.Exists(imgPath) && !tilesOut)
                    {
                        using (Bitmap imageT = new Bitmap(imgPath))
                        {
                            ///getting commments currently only working for JPG
                            ///TODO: get this to work for any image type or
                            ///find another way to check if the cached image covers the boundary.
                            string imgComment = string.Empty;

                            ///Save for later development of warping
                            //if (!warped)
                            imgComment = imageT.GetCommentsFromJPG();

                            imageT.Dispose();

                            ///check to see if tilerange in comments matches current tilerange
                            if (imgComment == (mbSource.Replace(" ", "") + tileRangeString))
                            {
                                AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "Using existing image.");
                                AddPreviewItem(imgPath, boundary[i], rect);
                                continue;
                            }
                        }
                    }

                    if (tilesOut)
                    {
                        for (int t = 0; t < cacheFilePaths.Count; t++)
                        {
                            if (File.Exists(cacheFilePaths[t]))
                            {
                                AddPreviewItem(cacheFilePaths[t], tileRectangles[t].ToNurbsCurve(), tileRectangles[t]);
                            }
                        }
                        continue;
                    }
                }



                ///Query Mapbox URL
                ///download all tiles within boundary
                ///merge tiles into one bitmap
                ///API to query
                string mbURLauth = mbURL + mbToken;


                ///Do the work of assembling image
                ///setup final image container bitmap
                int    fImageW    = ((int)x_range.Length + 1) * 512;
                int    fImageH    = ((int)y_range.Length + 1) * 512;
                Bitmap finalImage = new Bitmap(fImageW, fImageH);


                int imgPosW = 0;
                int imgPosH = 0;

                /*
                 * ///Save for later development of warping
                 * List<GCP> gcpList = new List<GCP>();
                 */

                using (Graphics g = Graphics.FromImage(finalImage))
                {
                    g.Clear(Color.Black);
                    for (int y = (int)y_range.Min; y <= (int)y_range.Max; y++)
                    {
                        for (int x = (int)x_range.Min; x <= (int)x_range.Max; x++)
                        {
                            ///create tileCache name
                            string tileCache    = mbSource.Replace(" ", "") + zoom + "-" + x + "-" + y + ".jpg";
                            string tileCacheLoc = cacheLoc + tileCache;

                            /*
                             * ///Save for later development of warping
                             * ///Get GCPs for warping
                             * Point3d tileCorner = Heron.Convert.GetTileAsPolygon(zoom, y, x)[3];
                             * var tileCorner3857 = Convert.Point3dToOgrPoint(tileCorner, modelToMapboxSRSTransform);
                             * GCP gcp = new GCP(tileCorner3857.GetX(0), tileCorner3857.GetY(0), tileCorner3857.GetZ(0), imgPosW * 512, imgPosH * 512, tileCorner3857.ToString(), zoom + x + y + "");
                             * gcpList.Add(gcp);
                             */

                            ///check cache folder to see if tile image exists locally
                            if (File.Exists(tileCacheLoc))
                            {
                                Bitmap tmpImage = new Bitmap(Image.FromFile(tileCacheLoc));
                                ///add tmp image to final
                                g.DrawImage(tmpImage, imgPosW * 512, imgPosH * 512);
                                tmpImage.Dispose();
                            }

                            else
                            {
                                tileList.Add(new List <int> {
                                    zoom, y, x
                                });
                                string urlAuth = Convert.GetZoomURL(x, y, zoom, mbURLauth);

                                Bitmap tmpImage = new Bitmap(512, 512);

                                System.Net.WebClient client = new System.Net.WebClient();
                                if (run == true)
                                {
                                    try
                                    {
                                        client.DownloadFile(urlAuth, tileCacheLoc);
                                        tmpImage = new Bitmap(Image.FromFile(tileCacheLoc));
                                    }
                                    catch (WebException e)
                                    {
                                        using (Graphics tmp = Graphics.FromImage(tmpImage)) { tmp.Clear(Color.White); }
                                        AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, e.Message);
                                    }
                                }
                                client.Dispose();


                                ///add tmp image to final
                                g.DrawImage(tmpImage, imgPosW * 512, imgPosH * 512);
                                tmpImage.Dispose();
                                tileDownloadedCount = tileDownloadedCount + 1;
                            }

                            ///increment x insert position, goes left to right
                            imgPosW++;
                        }
                        ///increment y insert position, goes top to bottom
                        imgPosH++;
                        imgPosW = 0;
                    }
                    ///garbage collection
                    g.Dispose();

                    ///add tile range meta data to image comments
                    finalImage.AddCommentsToJPG(mbSource.Replace(" ", "") + tileRangeString);

                    ///Save for later development of warping
                    ///if (!warped)
                    ///save the image
                    finalImage.Save(imgPath, ImageFormat.Jpeg);
                }

                /*
                 * ///Save for later development of warping
                 * byte[] imageBuffer;
                 * string memFilename = "/vsimem/inmemfile";
                 * string memTranslated = "/vsimem/inmemfileTranslated";
                 * string memWarped = "/vsimem/inmemfileWarped";
                 * using (MemoryStream stream = new MemoryStream())
                 * {
                 *  finalImage.Save(stream, ImageFormat.Jpeg);
                 *  imageBuffer = stream.ToArray();
                 * }
                 */

                //garbage collection
                finalImage.Dispose();

                /*
                 * ///Save for later development of warping
                 * Gdal.FileFromMemBuffer(memFilename, imageBuffer);
                 * Dataset gdalImage = Gdal.Open(memFilename, Access.GA_ReadOnly);
                 * var upperLeft3857 = Convert.Point3dToOgrPoint(rect.Corner(3), modelToMapboxSRSTransform);
                 * var lowerRight3857 = Convert.Point3dToOgrPoint(rect.Corner(1), modelToMapboxSRSTransform);
                 * var upperLeft4326 = Convert.Point3dToOgrPoint(rect.Corner(3), modelToUserSRSTransform);
                 * var lowerRight4326 = Convert.Point3dToOgrPoint(rect.Corner(1), modelToUserSRSTransform);
                 * List<string> translateOptions = new List<string> { "-a_srs", "EPSG:3857",
                 *  "-r", "bilinear",
                 *  "-a_ullr", upperLeft3857.GetX(0).ToString(), upperLeft3857.GetY(0).ToString(), lowerRight3857.GetX(0).ToString(), lowerRight3857.GetY(0).ToString() };
                 * Dataset gdalTranslated = Gdal.wrapper_GDALTranslate(memTranslated, gdalImage, new GDALTranslateOptions(translateOptions.ToArray()), null, null);
                 *
                 * var wkt = gdalTranslated.GetProjection();
                 * //gdalTranslated.SetGCPs(gcpList.ToArray(), wkt);
                 *
                 * List<string> warpOptions = new List<string> { "-t_srs", "EPSG:4326",
                 *  "-r", "bilinear",
                 *  //"-multi",
                 *  //"-wo", "NUM_THREADS=6",
                 *  "-overwrite",
                 *  //"-order", "1",
                 *  //"-tps",
                 *  "-te_srs", "EPSG:3857",
                 *  "-te", upperLeft3857.GetX(0).ToString(), lowerRight3857.GetY(0).ToString(), lowerRight3857.GetX(0).ToString(), upperLeft3857.GetY(0).ToString() };
                 *
                 * ///https://github.com/OSGeo/gdal/issues/813
                 * ///https://lists.osgeo.org/pipermail/gdal-dev/2017-February/046046.html
                 * ///Odd way to go about setting source dataset in parameters for Warp is a known issue
                 *
                 * var ptr = new[] { Dataset.getCPtr(gdalTranslated).Handle };
                 * var gcHandle = GCHandle.Alloc(ptr, GCHandleType.Pinned);
                 * try
                 * {
                 *  var dss = new SWIGTYPE_p_p_GDALDatasetShadow(gcHandle.AddrOfPinnedObject(), false, null);
                 *  Dataset gdalWarped = Gdal.wrapper_GDALWarpDestName(memWarped, 1, dss, new GDALWarpAppOptions(warpOptions.ToArray()), null, null);
                 *  var driver = Gdal.GetDriverByName("JPEG");
                 *  List<string> copyOptions = new List<string> { "QUALITY=95", "COMMENT=" + mbSource.Replace(" ", "") + tileRangeString};
                 *  var copy = driver.CreateCopy(imgPath, gdalWarped, 0, copyOptions.ToArray(), null, null);
                 *  copy.Dispose();
                 *  driver.Dispose();
                 *  gdalWarped.Dispose();
                 * }
                 * finally
                 * {
                 *  if (gcHandle.IsAllocated)
                 *      gcHandle.Free();
                 * }
                 *
                 * gdalImage.Dispose();
                 * gdalTranslated.Dispose();
                 * Gdal.Unlink(memFilename);
                 * Gdal.Unlink(memTranslated);
                 * Gdal.Unlink(memWarped);
                 */

                if (!tilesOut)
                {
                    AddPreviewItem(imgPath, boundary[i], rect);
                }
                else
                {
                    for (int t = 0; t < cacheFilePaths.Count; t++)
                    {
                        if (File.Exists(cacheFilePaths[t]))
                        {
                            AddPreviewItem(cacheFilePaths[t], tileRectangles[t].ToNurbsCurve(), tileRectangles[t]);
                        }
                    }
                }

                //add to tile count total
                tCount.Insert(new GH_String(tileTotalCount + " tiles (" + tileDownloadedCount + " downloaded / " + (tileTotalCount - tileDownloadedCount) + " cached)"), path, 0);

                //write out new tile range metadata for serialization
                TileCacheMeta = tileRangeString;
            }

            List <string> mbAtts = new List <string> {
                "© Mapbox, © OpenStreetMap", "https://www.mapbox.com/about/maps/", "http://www.openstreetmap.org/copyright"
            };

            DA.SetDataTree(0, mapList);
            DA.SetDataTree(1, imgFrame);
            DA.SetDataTree(2, tCount);
            DA.SetDataList(3, mbAtts);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// This is the method that actually does the work.
        /// </summary>
        /// <param name="DA">The DA object is used to retrieve from inputs and store in outputs.</param>
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            List <Curve> boundary = new List <Curve>();

            DA.GetDataList <Curve>(0, boundary);

            int zoom = -1;

            DA.GetData <int>(1, ref zoom);

            string fileloc = "";

            DA.GetData <string>(2, ref fileloc);
            if (!fileloc.EndsWith(@"\"))
            {
                fileloc = fileloc + @"\";
            }

            string prefix = "";

            DA.GetData <string>(3, ref prefix);

            string URL = slippyURL;
            //DA.GetData<string>(4, ref URL);

            string userAgent = "";

            DA.GetData <string>(4, ref userAgent);

            bool run = false;

            DA.GetData <bool>("Run", ref run);

            GH_Structure <GH_String>  mapList  = new GH_Structure <GH_String>();
            GH_Structure <GH_Curve>   imgFrame = new GH_Structure <GH_Curve>();
            GH_Structure <GH_Integer> tCount   = new GH_Structure <GH_Integer>();


            for (int i = 0; i < boundary.Count; i++)
            {
                GH_Path path = new GH_Path(i);


                ///Get image frame for given boundary and  make sure it's valid
                if (!boundary[i].GetBoundingBox(true).IsValid)
                {
                    AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Boundary is not valid.");
                    return;
                }
                BoundingBox boundaryBox = boundary[i].GetBoundingBox(true);

                ///TODO: look into scaling boundary to get buffer tiles

                ///file path for final image
                string imgPath = fileloc + prefix + "_" + i + ".jpg";

                ///location of final image file
                mapList.Append(new GH_String(imgPath), path);

                ///create cache folder for images
                string        cacheLoc      = fileloc + @"HeronCache\";
                List <string> cacheFileLocs = new List <string>();
                if (!Directory.Exists(cacheLoc))
                {
                    Directory.CreateDirectory(cacheLoc);
                }

                ///tile bounding box array
                List <Point3d> boxPtList = new List <Point3d>();

                ///get the tile coordinates for all tiles within boundary
                List <List <int> > ranges = new List <List <int> >();
                ranges = Convert.GetTileRange(boundaryBox, zoom);

                List <List <int> > tileList = new List <List <int> >();
                List <int>         x_range  = ranges[0];
                List <int>         y_range  = ranges[1];

                ///cycle through tiles to get bounding box
                for (int y = y_range[0]; y <= y_range[1]; y++)
                {
                    for (int x = x_range[0]; x <= x_range[1]; x++)
                    {
                        ///add bounding box of tile to list
                        boxPtList.AddRange(Convert.GetTileAsPolygon(zoom, y, x).ToList());
                        cacheFileLocs.Add(cacheLoc + slippySource.Replace(" ", "") + zoom + x + y + ".png");
                    }
                }

                ///bounding box of tile boundaries
                BoundingBox bboxPts = new BoundingBox(boxPtList);

                ///convert bounding box to polyline
                List <Point3d> imageCorners = bboxPts.GetCorners().ToList();
                imageCorners.Add(imageCorners[0]);
                imgFrame.Append(new GH_Curve(new Rhino.Geometry.Polyline(imageCorners).ToNurbsCurve()), path);

                ///tile range as string for (de)serialization of TileCacheMeta
                string tileRangeString = zoom.ToString()
                                         + x_range[0].ToString()
                                         + y_range[0].ToString()
                                         + x_range[1].ToString()
                                         + y_range[1].ToString();

                ///check if the existing final image already covers the boundary.
                ///if so, no need to download more or reassemble the cached tiles.
                if ((TileCacheMeta == tileRangeString) && Convert.CheckCacheImagesExist(cacheFileLocs))
                {
                    if (File.Exists(imgPath))
                    {
                        using (Bitmap imageT = new Bitmap(imgPath))
                        {
                            ///getting commments currently only working for JPG
                            ///TODO: get this to work for any image type or
                            ///find another way to check if the cached image covers the boundary.
                            string imgComment = imageT.GetCommentsFromJPG();

                            imageT.Dispose();

                            ///check to see if tilerange in comments matches current tilerange
                            if (imgComment == (slippySource.Replace(" ", "") + tileRangeString))
                            {
                                AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "Using existing image.");
                                continue;
                            }
                        }
                    }
                }



                ///Query Slippy URL
                ///download all tiles within boundary
                ///merge tiles into one bitmap
                ///API to query


                ///Do the work of assembling image
                ///setup final image container bitmap
                int    fImageW    = (x_range[1] - x_range[0] + 1) * 256;
                int    fImageH    = (y_range[1] - y_range[0] + 1) * 256;
                Bitmap finalImage = new Bitmap(fImageW, fImageH);


                int imgPosW = 0;
                int imgPosH = 0;

                if (run == true)
                {
                    using (Graphics g = Graphics.FromImage(finalImage))
                    {
                        g.Clear(Color.Black);
                        for (int y = y_range[0]; y <= y_range[1]; y++)
                        {
                            for (int x = x_range[0]; x <= x_range[1]; x++)
                            {
                                //create tileCache name
                                string tileCache    = slippySource.Replace(" ", "") + zoom + x + y + ".png";
                                string tileCahceLoc = cacheLoc + tileCache;

                                //check cache folder to see if tile image exists locally
                                if (File.Exists(tileCahceLoc))
                                {
                                    Bitmap tmpImage = new Bitmap(Image.FromFile(tileCahceLoc));
                                    ///add tmp image to final
                                    g.DrawImage(tmpImage, imgPosW * 256, imgPosH * 256);
                                    tmpImage.Dispose();
                                }

                                else
                                {
                                    tileList.Add(new List <int> {
                                        zoom, y, x
                                    });
                                    string urlAuth = Convert.GetZoomURL(x, y, zoom, slippyURL);

                                    System.Net.WebClient client = new System.Net.WebClient();

                                    ///insert header if required
                                    client.Headers.Add("user-agent", userAgent);

                                    client.DownloadFile(urlAuth, tileCahceLoc);
                                    Bitmap tmpImage = new Bitmap(Image.FromFile(tileCahceLoc));
                                    client.Dispose();

                                    //add tmp image to final
                                    g.DrawImage(tmpImage, imgPosW * 256, imgPosH * 256);
                                    tmpImage.Dispose();
                                }

                                //increment x insert position, goes left to right
                                imgPosW++;
                            }
                            //increment y insert position, goes top to bottom
                            imgPosH++;
                            imgPosW = 0;
                        }
                        //garbage collection
                        g.Dispose();

                        //add tile range meta data to image comments
                        finalImage.AddCommentsToJPG(slippySource.Replace(" ", "") + tileRangeString);

                        //save the image
                        finalImage.Save(imgPath, System.Drawing.Imaging.ImageFormat.Jpeg);
                    }
                }

                //garbage collection
                finalImage.Dispose();


                //add to tile count total
                tCount.Append(new GH_Integer(tileList.Count), path);

                //write out new tile range metadata for serialization
                TileCacheMeta = tileRangeString;
            }


            DA.SetDataTree(0, mapList);
            DA.SetDataTree(1, imgFrame);
            DA.SetDataTree(2, tCount);
            DA.SetDataList(3, "copyright Slippy");
        }