diff --git a/OSCADSharp/OSCADSharp/Solids/Imported/PolygonalImageProcessor.cs b/OSCADSharp/OSCADSharp/Solids/Imported/PolygonalImageProcessor.cs index a810ba7..842542e 100644 --- a/OSCADSharp/OSCADSharp/Solids/Imported/PolygonalImageProcessor.cs +++ b/OSCADSharp/OSCADSharp/Solids/Imported/PolygonalImageProcessor.cs @@ -5,14 +5,89 @@ using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; +using OSCADSharp.DataBinding; namespace OSCADSharp.Solids.Imported { + + /// /// Processes a bitmap image by treating contiguous same-color regions as cubes /// internal class PolygonalImageProcessor : IImageProcessor { + #region Private Classes + private class Polygon : OSCADObject + { + private List points; + + public Polygon(List points) + { + this.points = points; + } + + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("polygon(points=["); + + Point pt; + for (int i = 0; i < this.points.Count; i++) + { + pt = this.points[i]; + if(i == 0) + sb.Append(String.Format("[{0}, {1}]", pt.X, pt.Y)); + else + sb.Append(String.Format(", [{0}, {1}]", pt.X, pt.Y)); + } + + sb.Append("]);"); + + return sb.ToString(); + } + + public override void Bind(string property, Variable variable) + { + throw new NotImplementedException(); + } + + public override Bounds Bounds() + { + var bottomLeft = new Vector3(int.MaxValue, int.MaxValue, 0); + var topRight = new Vector3(int.MinValue, int.MinValue, 1); + + + foreach (var point in this.points) + { + if (point.X < bottomLeft.X) + bottomLeft.X = point.X; + + if (point.Y < bottomLeft.Y) + bottomLeft.Y = point.Y; + + if (point.X > topRight.X) + topRight.X = point.X; + + if (point.Y > topRight.Y) + topRight.Y = point.Y; + } + + return new Spatial.Bounds(bottomLeft, topRight); + } + + public override OSCADObject Clone() + { + return new Polygon(this.points); + } + + public override Vector3 Position() + { + var bounds = this.Bounds(); + return Vector3.Average(bounds.TopRight, bounds.BottomLeft); + } + } + #endregion + #region Private Fields private string imagePath; #endregion @@ -31,9 +106,8 @@ namespace OSCADSharp.Solids.Imported public OSCADObject ProcessImage() { var polygons = this.processImage(); - OSCADObject obj = new OSCADObject.MultiStatementObject("union()", polygons); - obj = obj.Rotate(0, 0, 180); - obj = obj.Translate(ImageBounds.Length, ImageBounds.Width, 0); + OSCADObject obj = new OSCADObject.MultiStatementObject("union()", polygons); + obj = obj.Scale(1, -1, 1).Translate(0, ImageBounds.Width, 0); return obj; } @@ -52,12 +126,43 @@ namespace OSCADSharp.Solids.Imported var separatedColors = this.separateColors(img); IEnumerable>> contiguousSections = new List>>(); - foreach (var colorGroup in separatedColors.Values) + //Parallel.ForEach(separatedColors.Values, (colorGroup) => + foreach (var colorGroup in separatedColors.Values) { var sections = this.getContiguousSections(colorGroup); contiguousSections = contiguousSections.Concat(sections); + }//); + + return this.convertToPolygons(contiguousSections); + } + + private List convertToPolygons(IEnumerable>> contiguousSections) + { + List objects = new List(); + StringBuilder sb = new StringBuilder(); + + foreach (var section in contiguousSections) + { + //TODO: Reorder sections for correct polygon winding + + var color = section[0].Value; + OSCADObject pgon = new Polygon(section.Select(sec => sec.Key).ToList()); + pgon = pgon.Color(String.Format("[{0}, {1}, {2}]", color.R == 0 ? 0 : color.R / 255, color.G == 0 ? 0 : color.G / 255, color.B == 0 ? 0 : color.B / 255), color.A); + objects.Add(pgon); + + //foreach (var pair in section) + //{ + // var position = pair.Key; + // var color = pair.Value; + + + // //var cube = new Cube().Color(String.Format("[{0}, {1}, {2}]", color.R == 0 ? 0 : color.R / 255, color.G == 0 ? 0 : color.G / 255, color.B == 0 ? 0 : color.B / 255), color.A); + // //cube = cube.Translate(position.X, position.Y, 0); + // //objects.Add(cube); + //} } - throw new NotImplementedException(); + + return objects; } private List>> getContiguousSections(List> colorGrouping) @@ -71,13 +176,73 @@ namespace OSCADSharp.Solids.Imported { var origin = colorGrouping[0]; colorGrouping.RemoveAt(0); - sections.Add(this.getNeighbors(origin, grid, colorGrouping, topLeft, bottomRight)); + sections.Add(this.getConnectedPixelsOfSameColor(origin, grid, colorGrouping, topLeft, bottomRight)); + } + + foreach (var section in sections) + { + this.removeCenterPixels(section, grid, topLeft, bottomRight); } return sections; } - private List> getNeighbors(KeyValuePair origin, KeyValuePair?[,] grid, + private void removeCenterPixels(List> section, KeyValuePair?[,] grid, Point topLeft, Point bottomRight) + { + + for (int i = section.Count - 1; i >= 0; i--) + { + var origin = section[i].Key; + var color = section[i].Value; + + // We only care about cardinal directions for the purpose of removing pixels + // that lie in the center of a grouping (to avoid redundant vertexes + List neighboringPoints = new List() { + new Point(origin.X, origin.Y + 1), //Above + new Point(origin.X, origin.Y - 1), //Below + new Point(origin.X - 1, origin.Y), //Left + new Point(origin.X + 1, origin.Y), //Right + }; + + bool isOnanEdge = false; + foreach (var pt in neighboringPoints) + { + //If out of bounds, we found an edge + if (pt.X < topLeft.X || pt.X > bottomRight.X || pt.Y < topLeft.Y || pt.Y > bottomRight.Y) + { + isOnanEdge = true; + break; + } + + int x = pt.X - topLeft.X; + int y = pt.Y - topLeft.Y; + + if(grid[x, y] == null) + { + isOnanEdge = true; + break; + } + + if (grid[x, y] != null) + { + var nbr = (KeyValuePair)grid[x, y]; + if(!nbr.Value.Equals(color)) + { + isOnanEdge = true; + break; + } + } + } + + if (!isOnanEdge) + { + section.RemoveAt(i); + } + + } + } + + private List> getConnectedPixelsOfSameColor(KeyValuePair origin, KeyValuePair?[,] grid, List> colorGrouping, Point topLeft, Point bottomRight) {