SolveResults Compute(string fileLoc, List <Color> colors, int tskId) { var rc = new SolveResults(); bool filterColors = colors.Any(); List <GH_Colour> topCols = new List <GH_Colour>(); List <GH_Integer> colCount = new List <GH_Integer>(); GH_Structure <GH_Point> colLocation = new GH_Structure <GH_Point>(); try { using (Bitmap bitmap = new Bitmap(fileLoc)) { GH_Integer pixCount = new GH_Integer(); GH_Convert.ToGHInteger(bitmap.Height * bitmap.Width, 0, ref pixCount); rc.PixCount = pixCount; ///https://www.grasshopper3d.com/forum/topics/unsafe?page=1&commentId=2985220%3AComment%3A808291&x=1#2985220Comment808291 GH_MemoryBitmap sampler = new GH_MemoryBitmap(bitmap); Color col = Color.Transparent; for (int x = 0; x < bitmap.Width; x++) { for (int y = 0; y < bitmap.Height; y++) { ///GH_MemoryBitmap Sample is faster than GetPixel //col = bitmap.GetPixel(x, y); if (sampler.Sample(x, y, ref col)) { if (colors.Contains(col)) { GH_Path path = new GH_Path(tskId, colors.IndexOf(col)); colLocation.Append(new GH_Point(new Point3d(x, y, 0)), path); } else if (!filterColors) { colors.Add(col); GH_Path path = new GH_Path(tskId, colors.IndexOf(col)); colLocation.Append(new GH_Point(new Point3d(x, y, 0)), path); } } } } sampler.Release(false); bitmap.Dispose(); } } catch { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Could not load image from file path: " + fileLoc); } List <GH_Colour> ghColors = new List <GH_Colour>(); foreach (var c in colors) { ghColors.Add(new GH_Colour(c)); } rc.TopColors = ghColors; rc.ColorLocation = colLocation; return(rc); }
SolveResults Compute(string fileLoc, int numColors) { var rc = new SolveResults(); Dictionary <Color, int> dictColors = new Dictionary <Color, int>(); Dictionary <Color, List <GH_Point> > dictColorLocation = new Dictionary <Color, List <GH_Point> >(); List <GH_Colour> topCols = new List <GH_Colour>(); List <GH_Integer> colCount = new List <GH_Integer>(); GH_Structure <GH_Point> colLocation = new GH_Structure <GH_Point>(); try { using (Bitmap bitmap = new Bitmap(fileLoc)) { GH_Integer pixCount = new GH_Integer(); GH_Convert.ToGHInteger(bitmap.Height * bitmap.Width, 0, ref pixCount); rc.PixCount = pixCount; ///https://www.grasshopper3d.com/forum/topics/unsafe?page=1&commentId=2985220%3AComment%3A808291&x=1#2985220Comment808291 GH_MemoryBitmap sampler = new GH_MemoryBitmap(bitmap); Color col = Color.Transparent; for (int x = 0; x < bitmap.Width; x++) { for (int y = 0; y < bitmap.Height; y++) { ///GH_MemoryBitmap Sample is faster than GetPixel //col = bitmap.GetPixel(x, y); if (sampler.Sample(x, y, ref col)) { if (!dictColors.ContainsKey(col)) { dictColors.Add(col, 1); //dictColorLocation.Add(col, new List<GH_Point> { new GH_Point(new Point3d(x,y,0)) }); } else { dictColors[col]++; //dictColorLocation[col].Add(new GH_Point(new Point3d(x,y,0))); } } } } if (numColors > dictColors.Count || numColors <= 0) { numColors = dictColors.Count; } var sortedColorDict = (from entry in dictColors orderby entry.Value descending select entry) .Take(numColors) .ToDictionary(pair => pair.Key, pair => pair.Value); //var sortedColorLocation = (from entry in dictColorLocation orderby entry.Value.Count descending select entry) // .Take(numColors) // .ToDictionary(pair => pair.Key, pair => pair.Value); foreach (var clr in sortedColorDict) { GH_Colour gh_Col = new GH_Colour(); GH_Convert.ToGHColour(clr.Key, 0, ref gh_Col); topCols.Add(gh_Col); GH_Integer gh_Count = new GH_Integer(); GH_Convert.ToGHInteger(clr.Value, 0, ref gh_Count); colCount.Add(gh_Count); } /*int i = 0; * foreach (var clr in sortedColorLocation) * { * GH_Path path = new GH_Path(i); * colLocation.AppendRange(clr.Value, path); * i++; * } */ sampler.Release(false); bitmap.Dispose(); } } catch { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Could not load image from file path: " + fileLoc); } rc.TopColors = topCols; rc.ColorCount = colCount; //rc.ColorLocation = colLocation; return(rc); }
public static Bitmap ConvertCubicToEquirectangular(Bitmap bm, int w) { //algorithm from https://stackoverflow.com/questions/34250742/converting-a-cubemap-into-equirectangular-panorama //for cube maps with the following format: // empty top empty empty // left forward right backward // empty bottom empty empty Bitmap equiTexture = new Bitmap(w, w / 2, System.Drawing.Imaging.PixelFormat.Format24bppRgb); GH_MemoryBitmap ghEquiMap = new GH_MemoryBitmap(equiTexture); ///GH_MemoryBitmap Sample faster than GetPixel ///https://www.grasshopper3d.com/forum/topics/unsafe?page=1&commentId=2985220%3AComment%3A808291&x=1#2985220Comment808291 GH_MemoryBitmap ghBitmap = new GH_MemoryBitmap(bm); double u, v; //Normalised texture coordinates, from 0 to 1, starting at lower left corner double phi, theta; //Polar coordinates int cubeFaceWidth, cubeFaceHeight; cubeFaceWidth = bm.Width / 4; //4 horizontal faces cubeFaceHeight = bm.Height / 3; //3 vertical faces for (int j = 0; j < equiTexture.Height; j++) { //Rows start from the bottom v = 1 - ((double)j / equiTexture.Height); theta = v * Math.PI; for (int i = 0; i < equiTexture.Width; i++) { //Columns start from the left u = ((double)i / equiTexture.Width); phi = u * 2 * Math.PI; double x, y, z; //Unit vector x = Math.Sin(phi) * Math.Sin(theta) * -1; y = Math.Cos(theta); z = Math.Cos(phi) * Math.Sin(theta) * -1; double xa, ya, za; double a; double[] maxArr = new double[3] { Math.Abs(x), Math.Abs(y), Math.Abs(z) }; //a = Math.Max(new double[3] { Math.Abs(x), Math.Abs(y), Math.Abs(z) }); a = maxArr.Max(); //Vector Parallel to the unit vector that lies on one of the cube faces xa = x / a; ya = y / a; za = z / a; Color color = Color.Transparent; int xPixel, yPixel; int xOffset, yOffset; if (xa == 1) { //Right xPixel = (int)((((za + 1) / 2) - 1) * cubeFaceWidth); xOffset = 2 * cubeFaceWidth; //Offset yPixel = (int)((((ya + 1) / 2)) * cubeFaceHeight); yOffset = cubeFaceHeight; //Offset } else if (xa == -1) { //Left xPixel = (int)((((za + 1) / 2)) * cubeFaceWidth); xOffset = 0; yPixel = (int)((((ya + 1) / 2)) * cubeFaceHeight); yOffset = cubeFaceHeight; } else if (ya == 1) { //Up xPixel = (int)((((xa + 1) / 2)) * cubeFaceWidth); xOffset = cubeFaceWidth; yPixel = (int)((((za + 1) / 2) - 1) * cubeFaceHeight); yOffset = 2 * cubeFaceHeight; } else if (ya == -1) { //Down xPixel = (int)((((xa + 1) / 2)) * cubeFaceWidth); xOffset = cubeFaceWidth; yPixel = (int)((((za + 1) / 2)) * cubeFaceHeight); yOffset = 0; } else if (za == 1) { //Front xPixel = (int)((((xa + 1) / 2)) * cubeFaceWidth); xOffset = cubeFaceWidth; yPixel = (int)((((ya + 1) / 2)) * cubeFaceHeight); yOffset = cubeFaceHeight; } else if (za == -1) { //Back xPixel = (int)((((xa + 1) / 2) - 1) * cubeFaceWidth); xOffset = 3 * cubeFaceWidth; yPixel = (int)((((ya + 1) / 2)) * cubeFaceHeight); yOffset = cubeFaceHeight; } else { //Debug.LogWarning("Unknown face, something went wrong"); xPixel = 0; yPixel = 0; xOffset = 0; yOffset = 0; } xPixel = Math.Abs(xPixel); yPixel = Math.Abs(yPixel); xPixel += xOffset; yPixel += yOffset; if (xPixel < 0 || yPixel < 0) { throw new ArgumentNullException("x = " + xPixel.ToString() + " y = " + yPixel.ToString()); } if (xPixel > (bm.Width - 1)) { xPixel = xPixel - 1; //throw new ArgumentNullException("x = " + xPixel.ToString() + " y = " + yPixel.ToString()+" i="+i+" j="+j); } if (yPixel > (bm.Height - 1)) { yPixel = yPixel - 1; //throw new ArgumentNullException("x = " + xPixel.ToString() + " y = " + yPixel.ToString()+" i="+i+" j="+j); } //sampler.Sample(xPixel, yPixel, ref color); color = ghBitmap.Colour(xPixel, yPixel); ghEquiMap.Colour(i, j, color); } } ghBitmap.Release(false); ghEquiMap.Release(true); return(equiTexture); }
/// <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 <Plane> camPlanes = new List <Plane>(); DA.GetDataList <Plane>(0, camPlanes); string folder = string.Empty; DA.GetData <string>(1, ref folder); bool saveCubemaps = !string.IsNullOrEmpty(folder); if (saveCubemaps) { folder = Path.GetFullPath(folder); if (!folder.EndsWith(Path.DirectorySeparatorChar.ToString())) { folder += Path.DirectorySeparatorChar; } } string prefix = string.Empty; DA.GetData <string>(2, ref prefix); int imageWidth = 0; DA.GetData <int>(3, ref imageWidth); imageWidth = imageWidth / 4; Size size = new Size(imageWidth, imageWidth); string displayMode = string.Empty; DA.GetData <string>(4, ref displayMode); List <Color> colors = new List <Color>(); DA.GetDataList <Color>(5, colors); bool filterColors = colors.Any(); GH_Structure <GH_Mesh> ghObstacles = new GH_Structure <GH_Mesh>(); DA.GetDataTree <GH_Mesh>(6, out ghObstacles); ///Flatten obstacle meshes and join them into one mesh ghObstacles.FlattenData(); Mesh obstacles = new Mesh(); bool showRays = false; if (ghObstacles.DataCount > 0) { showRays = true; foreach (var obstacle in ghObstacles) { Mesh temp = new Mesh(); GH_Convert.ToMesh(obstacle, ref temp, GH_Conversion.Primary); obstacles.Append(temp); } } bool run = false; DA.GetData <bool>(7, ref run); int pad = camPlanes.Count.ToString().Length; List <string> cubemaps = new List <string>(); GH_Structure <GH_Line> rayTree = new GH_Structure <GH_Line>(); GH_Structure <GH_Colour> colorTree = new GH_Structure <GH_Colour>(); ///Save the intial camera saveCam = camFromVP(Rhino.RhinoDoc.ActiveDoc.Views.ActiveView.ActiveViewport); ///Set the display mode to be used for bitmaps ///TODO: Add menu item to use "Heron View Analysis" display mode DisplayModeDescription viewMode = Rhino.RhinoDoc.ActiveDoc.Views.ActiveView.ActiveViewport.DisplayMode; if (DisplayModeDescription.FindByName(displayMode) != null) { viewMode = DisplayModeDescription.FindByName(displayMode); } Message = viewMode.EnglishName; if (run) { for (int i = 0; i < camPlanes.Count; i++) { ///TODO: setup ability to save cameras to the Rhino doc ///Setup camera Rhino.Display.RhinoView view = Rhino.RhinoDoc.ActiveDoc.Views.ActiveView; Rhino.Display.RhinoViewport vp = view.ActiveViewport; ///Get the bounding box of all visible object in the doc for use in setting up the camera ///target so that the far frustrum plane doesn't clip anything double zoomDistance = Rhino.RhinoDoc.ActiveDoc.Objects.BoundingBoxVisible.Diagonal.Length; Plane camPlane = camPlanes[i]; Point3d camPoint = camPlane.Origin; Vector3d camDir = camPlane.YAxis; Point3d tarPoint = Transform.Translation(camDir * zoomDistance / 2) * camPoint; vp.ChangeToPerspectiveProjection(false, 12.0); vp.Size = size; vp.DisplayMode = viewMode; //view.Redraw(); ///Set up final bitmap Bitmap cubemap = new Bitmap(imageWidth * 4, imageWidth * 3); ///Place the images on cubemap bitmap using (Graphics gr = Graphics.FromImage(cubemap)) { ///Grab bitmap ///Set up camera directions Point3d tarLeft = Transform.Translation(-camPlane.XAxis * zoomDistance / 2) * camPoint; Point3d tarFront = Transform.Translation(camPlane.YAxis * zoomDistance / 2) * camPoint; Point3d tarRight = Transform.Translation(camPlane.XAxis * zoomDistance / 2) * camPoint; Point3d tarBack = Transform.Translation(-camPlane.YAxis * zoomDistance / 2) * camPoint; Point3d tarUp = Transform.Translation(camPlane.ZAxis * zoomDistance / 2) * camPoint; Point3d tarDown = Transform.Translation(-camPlane.ZAxis * zoomDistance / 2) * camPoint; List <Point3d> camTargets = new List <Point3d>() { tarLeft, tarFront, tarRight, tarBack, tarUp, tarDown }; ///Loop through pano directions int insertLoc = 0; for (int d = 0; d < 4; d++) { ///Set camera direction vp.SetCameraLocations(camTargets[d], camPoint); //view.Redraw(); Bitmap bitmap = new Bitmap(view.CaptureToBitmap(size, viewMode)); if (saveCubemaps) { gr.DrawImage(bitmap, insertLoc, imageWidth); } if (showRays) { GH_MemoryBitmap sampler = new GH_MemoryBitmap(bitmap); Color col = Color.Transparent; for (int x = 0; x < bitmap.Width; x++) { for (int y = 0; y < bitmap.Height; y++) { if (sampler.Sample(x, y, ref col)) { if (colors.Contains(col)) { GH_Path path = new GH_Path(i, colors.IndexOf(col)); Line line = vp.ClientToWorld(new System.Drawing.Point(x, y)); Ray3d ray = new Ray3d(vp.CameraLocation, -line.Direction); double rayEnd = (double)Rhino.Geometry.Intersect.Intersection.MeshRay(obstacles, ray); Point3d rayIntersection = ray.PointAt(rayEnd); Line ln = new Line(camPoint, rayIntersection); if (ln.IsValid & rayEnd > 0) { rayTree.Append(new GH_Line(ln), path); colorTree.Append(new GH_Colour(col), path); } } else if (!filterColors) { colors.Add(col); GH_Path path = new GH_Path(i, colors.IndexOf(col)); Line line = vp.ClientToWorld(new System.Drawing.Point(x, y)); Ray3d ray = new Ray3d(vp.CameraLocation, -line.Direction); double rayEnd = (double)Rhino.Geometry.Intersect.Intersection.MeshRay(obstacles, ray); Point3d rayIntersection = ray.PointAt(rayEnd); Line ln = new Line(camPoint, rayIntersection); if (ln.IsValid & rayEnd > 0) { rayTree.Append(new GH_Line(ln), path); colorTree.Append(new GH_Colour(col), path); } } } } } sampler.Release(false); } insertLoc = insertLoc + imageWidth; bitmap.Dispose(); } ///Get up and down views ///Get up view vp.SetCameraLocations(tarUp, camPoint); view.Redraw(); Bitmap bitmapUp = new Bitmap(view.CaptureToBitmap(size, viewMode)); if (showRays) { GH_MemoryBitmap sampler = new GH_MemoryBitmap(bitmapUp); Color col = Color.Transparent; for (int x = 0; x < bitmapUp.Width; x++) { for (int y = 0; y < bitmapUp.Height; y++) { if (sampler.Sample(x, y, ref col)) { if (colors.Contains(col)) { GH_Path path = new GH_Path(i, colors.IndexOf(col)); Line line = vp.ClientToWorld(new System.Drawing.Point(x, y)); Ray3d ray = new Ray3d(vp.CameraLocation, -line.Direction); double rayEnd = (double)Rhino.Geometry.Intersect.Intersection.MeshRay(obstacles, ray); Point3d rayIntersection = ray.PointAt(rayEnd); Line ln = new Line(camPoint, rayIntersection); if (ln.IsValid & rayEnd > 0) { rayTree.Append(new GH_Line(ln), path); colorTree.Append(new GH_Colour(col), path); } } else if (!filterColors) { colors.Add(col); GH_Path path = new GH_Path(i, colors.IndexOf(col)); Line line = vp.ClientToWorld(new System.Drawing.Point(x, y)); Ray3d ray = new Ray3d(vp.CameraLocation, -line.Direction); double rayEnd = (double)Rhino.Geometry.Intersect.Intersection.MeshRay(obstacles, ray); Point3d rayIntersection = ray.PointAt(rayEnd); Line ln = new Line(camPoint, rayIntersection); if (ln.IsValid & rayEnd > 0) { rayTree.Append(new GH_Line(ln), path); colorTree.Append(new GH_Colour(col), path); } } } } } sampler.Release(false); } bitmapUp.RotateFlip(RotateFlipType.Rotate180FlipNone); if (saveCubemaps) { gr.DrawImage(bitmapUp, imageWidth, 0); } bitmapUp.Dispose(); ///Get down view vp.SetCameraLocations(tarDown, camPoint); view.Redraw(); Bitmap bitmapDown = new Bitmap(view.CaptureToBitmap(size, viewMode)); if (saveCubemaps) { gr.DrawImage(bitmapDown, imageWidth, imageWidth * 2); } if (showRays) { GH_MemoryBitmap sampler = new GH_MemoryBitmap(bitmapDown); Color col = Color.Transparent; for (int x = 0; x < bitmapDown.Width; x++) { for (int y = 0; y < bitmapDown.Height; y++) { if (sampler.Sample(x, y, ref col)) { if (colors.Contains(col)) { GH_Path path = new GH_Path(i, colors.IndexOf(col)); Line line = vp.ClientToWorld(new System.Drawing.Point(x, y)); Ray3d ray = new Ray3d(vp.CameraLocation, -line.Direction); double rayEnd = (double)Rhino.Geometry.Intersect.Intersection.MeshRay(obstacles, ray); Point3d rayIntersection = ray.PointAt(rayEnd); Line ln = new Line(camPoint, rayIntersection); if (ln.IsValid & rayEnd > 0) { rayTree.Append(new GH_Line(ln), path); colorTree.Append(new GH_Colour(col), path); } } else if (!filterColors) { colors.Add(col); GH_Path path = new GH_Path(i, colors.IndexOf(col)); Line line = vp.ClientToWorld(new System.Drawing.Point(x, y)); Ray3d ray = new Ray3d(vp.CameraLocation, -line.Direction); double rayEnd = (double)Rhino.Geometry.Intersect.Intersection.MeshRay(obstacles, ray); Point3d rayIntersection = ray.PointAt(rayEnd); Line ln = new Line(camPoint, rayIntersection); if (ln.IsValid & rayEnd > 0) { rayTree.Append(new GH_Line(ln), path); colorTree.Append(new GH_Colour(col), path); } } } } } sampler.Release(false); } bitmapDown.Dispose(); } ///End pano directions loop if (saveCubemaps) { ///Save cubemap bitmap string s = i.ToString().PadLeft(pad, '0'); string saveText = folder + prefix + "_" + s + ".png"; cubemap.Save(saveText, System.Drawing.Imaging.ImageFormat.Png); cubemaps.Add(saveText); } cubemap.Dispose(); } } ///Restore initial camera setCamera(saveCam, Rhino.RhinoDoc.ActiveDoc.Views.ActiveView.ActiveViewport); Rhino.RhinoDoc.ActiveDoc.Views.ActiveView.Redraw(); DA.SetDataList(0, cubemaps); DA.SetDataTree(1, rayTree); DA.SetDataTree(2, colorTree); }