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);


            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_Curve>  imgFrame = new GH_Structure <GH_Curve>();
            GH_Structure <GH_String> tCount   = new GH_Structure <GH_String>();
            GH_Structure <GH_Mesh>   tMesh    = new GH_Structure <GH_Mesh>();

            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
                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 + ".png";

                //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 + ".png");
                        tileTotalCount = tileTotalCount + 1;
                    }
                }

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

                //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.
                ///temporarily disable until how to tag images with meta data is figured out

                /*
                 * if (TileCacheMeta == tileRangeString && Convert.CheckCacheImagesExist(cacheFileLocs))
                 * {
                 *  if (File.Exists(imgPath))
                 *  {
                 *      using (Bitmap imageT = new Bitmap(imgPath))
                 *      {
                 *          //System.Drawing.Imaging.PropertyItem prop = imageT.GetPropertyItem(40092);
                 *          //string imgComment = Encoding.Unicode.GetString(prop.Value);
                 *          string imgComment = imageT.GetCommentsFromImage();
                 *          //AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, imgComment);
                 *          imageT.Dispose();
                 *          //check to see if tilerange in comments matches current tilerange
                 *          if (imgComment == (mbSource.Replace(" ", "") + tileRangeString))
                 *          {
                 *              AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, "Using existing topo image.");
                 *
                 *              Mesh eMesh = TopoMeshFromImage(imgPath, boundaryBox, zoom);
                 *              tMesh.Append(new GH_Mesh(eMesh), path);
                 *              continue;
                 *          }
                 *
                 *      }
                 *
                 *  }
                 *
                 * }
                 */


                ///Query Mapbox URL
                ///download all tiles within boundary
                ///merge tiles into one bitmap

                ///API to query
                ///string mbURL = "https://api.mapbox.com/v4/mapbox.terrain-rgb/{z}/{x}/{y}@2x.pngraw?access_token=" + mbToken;
                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, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

                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 + ".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 * 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.AddCommentsToPNG(mbSource.Replace(" ", "") + tileRangeString);

                        //save out assembled image
                        finalImage.Save(imgPath, System.Drawing.Imaging.ImageFormat.Png);
                    }
                }

                //garbage collection
                finalImage.Dispose();

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


                Mesh nMesh = TopoMeshFromImage(imgPath, boundaryBox, zoom);

                //mesh.Flip(true, true, true);
                tMesh.Append(new GH_Mesh(nMesh), path);

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

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