diff --git a/OSCADSharp/OSCADSharp.ConsoleTests/Program.cs b/OSCADSharp/OSCADSharp.ConsoleTests/Program.cs
index 9eaaa50..92b3d14 100644
--- a/OSCADSharp/OSCADSharp.ConsoleTests/Program.cs
+++ b/OSCADSharp/OSCADSharp.ConsoleTests/Program.cs
@@ -57,7 +57,7 @@ namespace OSCADSharp.ConsoleTests
static void Main(string[] args)
{
- var img = new ImportedImage("seahawks coaster.png");
+ var img = ImportedImage.FromFile("seahawks coaster.png");
img.ToFile("seaImg").Open();
//makePeg();
diff --git a/OSCADSharp/OSCADSharp/OSCADSharp.csproj b/OSCADSharp/OSCADSharp/OSCADSharp.csproj
index 35f5d32..8e45585 100644
--- a/OSCADSharp/OSCADSharp/OSCADSharp.csproj
+++ b/OSCADSharp/OSCADSharp/OSCADSharp.csproj
@@ -48,6 +48,7 @@
+
diff --git a/OSCADSharp/OSCADSharp/Solids/Imported/CubistImageProcessor.cs b/OSCADSharp/OSCADSharp/Solids/Imported/CubistImageProcessor.cs
new file mode 100644
index 0000000..86ec37d
--- /dev/null
+++ b/OSCADSharp/OSCADSharp/Solids/Imported/CubistImageProcessor.cs
@@ -0,0 +1,178 @@
+using OSCADSharp.Spatial;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace OSCADSharp.Solids.Imported
+{
+ ///
+ /// Processes a bitmap image by treating contiguous same-color regions as cubes
+ ///
+ internal class CubistImageProcessor
+ {
+ #region Private Fields
+ private string imagePath;
+ List cubes = new List();
+ #endregion
+
+ #region Internal Fields
+ internal Bounds ImageBounds { get; set; }
+ #endregion
+
+ public CubistImageProcessor(string imagePath)
+ {
+ this.imagePath = imagePath;
+ }
+
+ internal OSCADObject ProcessImage()
+ {
+ this.cubes = this.processImage();
+ OSCADObject obj = new OSCADObject.MultiStatementObject("union()", cubes);
+ obj = obj.Rotate(0, 0, 180);
+ obj = obj.Translate(ImageBounds.Length, ImageBounds.Width, 0);
+
+ return obj;
+ }
+
+
+ private List processImage()
+ {
+ Bitmap img = new Bitmap(Image.FromFile(this.imagePath));
+
+ if (img.Width > 200 || img.Height > 200)
+ {
+ throw new InvalidOperationException("Cannot process images larger greater than 200x200 pixels");
+ }
+
+ this.ImageBounds = new Bounds(new Vector3(), new Vector3(img.Width, img.Height, 0));
+
+ List cubes = new List();
+ bool[,] visited = new bool[img.Width, img.Height];
+
+ Point? start = this.getNextPoint(img, ref visited, img.Width - 1, img.Height - 1);
+ do
+ {
+ System.Drawing.Color color = img.GetPixel(((Point)start).X, ((Point)start).Y);
+
+ var cube = this.traverseNext(img, (Point)start, ref visited, color);
+ if (cube != null)
+ {
+ this.markVisited(ref visited, cube, (Point)start, img);
+ if (color.A != 0)
+ {
+ cubes.Add(cube.Translate(((Point)start).X, ((Point)start).Y, 0)
+ .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));
+ }
+ }
+
+ start = this.getNextPoint(img, ref visited, img.Width - 1, img.Height - 1);
+ } while (start != null);
+
+ return cubes;
+ }
+
+ private void markVisited(ref bool[,] visited, Cube cube, Point start, Bitmap img)
+ {
+ var bounds = cube.Bounds();
+ for (int column = start.X; column < start.X + bounds.Width; column++)
+ {
+ for (int row = start.Y; row < start.Y + bounds.Length; row++)
+ {
+ visited[column, row] = true;
+ }
+ }
+ }
+
+ private Cube traverseNext(Bitmap img, Point start, ref bool[,] visited, System.Drawing.Color color, Cube cube = null)
+ {
+ bool canTraverse = true;
+ if (cube != null)
+ {
+ canContinueTraversal(img, ref start, ref visited, color, cube, ref canTraverse);
+ }
+ else
+ {
+ canTraverse = pixelCanBeTraversed(img, ref visited, new Point(start.X + 1, start.Y + 1), color) &&
+ pixelCanBeTraversed(img, ref visited, new Point(start.X + 1, start.Y), color) &&
+ pixelCanBeTraversed(img, ref visited, new Point(start.X, start.Y + 1), color);
+ }
+
+
+ if (canTraverse)
+ {
+ if (cube == null)
+ {
+ cube = new Cube();
+ cube.Size.X += 1;
+ cube.Size.Y += 1;
+
+ return traverseNext(img, start, ref visited, color, cube);
+ }
+ else
+ {
+ cube.Size.X += 1;
+ cube.Size.Y += 1;
+ return traverseNext(img, start, ref visited, color, cube);
+ }
+ }
+ else
+ {
+
+ if (cube == null)
+ {
+ return new Cube();
+ }
+ else
+ {
+ return cube;
+ }
+ }
+
+ }
+
+ private void canContinueTraversal(Bitmap img, ref Point start, ref bool[,] visited, Color color, Cube cube, ref bool canTraverse)
+ {
+ var bounds = cube.Bounds();
+ for (int column = start.X; column < start.X + bounds.Width && canTraverse; column++)
+ {
+ for (int row = start.Y; row < start.Y + bounds.Length && canTraverse; row++)
+ {
+ if (start.X + column >= img.Width || start.Y + row >= img.Height)
+ {
+ canTraverse = false;
+ }
+ else
+ {
+ canTraverse = canTraverse && pixelCanBeTraversed(img, ref visited, new Point(column, row), color);
+ }
+ }
+ }
+ }
+
+ private bool pixelCanBeTraversed(Bitmap img, ref bool[,] visited, Point pixel, Color colorToMatch)
+ {
+ return pixel.X < img.Width && pixel.Y < img.Height &&
+ visited[pixel.X, pixel.Y] == false && img.GetPixel(pixel.X, pixel.Y) == colorToMatch;
+
+ }
+
+ private Point? getNextPoint(Bitmap img, ref bool[,] visited, int width, int height)
+ {
+ for (int column = 0; column < width; column++)
+ {
+ for (int row = 0; row < height; row++)
+ {
+ if (visited[column, row] == false)
+ {
+ return new Point(column, row);
+ }
+ }
+ }
+
+ return null;
+ }
+ }
+}
diff --git a/OSCADSharp/OSCADSharp/Solids/Imported/ImportedImage.cs b/OSCADSharp/OSCADSharp/Solids/Imported/ImportedImage.cs
index e08471e..ba16bb9 100644
--- a/OSCADSharp/OSCADSharp/Solids/Imported/ImportedImage.cs
+++ b/OSCADSharp/OSCADSharp/Solids/Imported/ImportedImage.cs
@@ -14,183 +14,73 @@ namespace OSCADSharp.Solids.Imported
///
public class ImportedImage : OSCADObject
{
- #region Private Fields
- private string imagePath;
-
- List cubes;
+ #region Internal Properties
+ internal OSCADObject m_Object { get; set; }
+ internal Bounds m_Bounds { get; set; }
#endregion
-
+
#region Constructors / Initialization
- ///
- /// Creates an imported image with the default settings
- ///
- ///
- public ImportedImage(string imagePath)
+ public static ImportedImage FromFile(string imagePath)
{
- this.imagePath = imagePath;
- this.cubes = this.processImage();
+ var processor = new CubistImageProcessor(imagePath);
+ var obj = processor.ProcessImage();
+
+ var img = new ImportedImage() {
+ m_Object = obj,
+ m_Bounds = processor.ImageBounds
+ };
+
+ return img;
}
-
- private List processImage()
- {
- Bitmap img = new Bitmap(Image.FromFile(this.imagePath));
- if(img.Width > 200 || img.Height > 200)
- {
- throw new InvalidOperationException("Cannot process images larger greater than 200x200 pixels");
- }
-
- List cubes = new List();
- bool[,] visited = new bool[img.Width, img.Height];
-
- Point? start = this.getNextPoint(img, ref visited, img.Width-1, img.Height-1);
- do
- {
- System.Drawing.Color color = img.GetPixel(((Point)start).X, ((Point)start).Y);
-
- var cube = this.traverseNext(img, (Point)start, ref visited, color);
- if(cube != null)
- {
- this.markVisited(ref visited, cube, (Point)start, img);
- if(color.A != 0)
- {
- cubes.Add(cube.Translate(((Point)start).X, ((Point)start).Y, 0)
- .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));
- }
- }
-
- start = this.getNextPoint(img, ref visited, img.Width-1, img.Height-1);
- } while (start != null);
-
- return cubes;
- }
-
- private void markVisited(ref bool[,] visited, Cube cube, Point start, Bitmap img)
- {
- var bounds = cube.Bounds();
- for(int column = start.X; column < start.X + bounds.Width; column++)
- {
- for (int row = start.Y; row < start.Y + bounds.Length; row++)
- {
- visited[column, row] = true;
- }
- }
- }
-
- Cube traverseNext(Bitmap img, Point start, ref bool[,] visited, System.Drawing.Color color, Cube cube = null)
- {
- bool canTraverse = true;
- if(cube != null)
- {
- canContinueTraversal(img, ref start, ref visited, color, cube, ref canTraverse);
- }
- else
- {
- canTraverse = pixelCanBeTraversed(img, ref visited, new Point(start.X + 1, start.Y + 1), color) &&
- pixelCanBeTraversed(img, ref visited, new Point(start.X + 1, start.Y), color) &&
- pixelCanBeTraversed(img, ref visited, new Point(start.X, start.Y + 1), color);
- }
-
-
- if(canTraverse)
- {
- if (cube == null)
- {
- cube = new Cube();
- cube.Size.X += 1;
- cube.Size.Y += 1;
-
- return traverseNext(img, start, ref visited, color, cube);
- }
- else
- {
- cube.Size.X += 1;
- cube.Size.Y += 1;
- return traverseNext(img, start, ref visited, color, cube);
- }
- }
- else
- {
-
- if(cube == null)
- {
- return new Cube();
- }
- else
- {
- return cube;
- }
- }
-
- }
-
- private void canContinueTraversal(Bitmap img, ref Point start, ref bool[,] visited, Color color, Cube cube, ref bool canTraverse)
- {
- var bounds = cube.Bounds();
- for (int column = start.X; column < start.X + bounds.Width && canTraverse; column++)
- {
- for (int row = start.Y; row < start.Y + bounds.Length && canTraverse; row++)
- {
- if (start.X + column >= img.Width || start.Y + row >= img.Height)
- {
- canTraverse = false;
- }
- else
- {
- canTraverse = canTraverse && pixelCanBeTraversed(img, ref visited, new Point(column, row), color);
- }
- }
- }
- }
-
- bool pixelCanBeTraversed(Bitmap img, ref bool[,] visited, Point pixel, Color colorToMatch) {
- return pixel.X < img.Width && pixel.Y < img.Height &&
- visited[pixel.X, pixel.Y] == false && img.GetPixel(pixel.X, pixel.Y) == colorToMatch;
-
- }
-
- Point? getNextPoint(Bitmap img, ref bool[,] visited, int width, int height)
- {
- for (int column = 0; column < width; column++)
- {
- for (int row = 0; row < height; row++)
- {
- if(visited[column, row] == false)
- {
- return new Point(column, row);
- }
- }
- }
-
- return null;
- }
#endregion
#region OSCADObject Overrides
+ ///
+ /// Imported images have no bindable properties
+ ///
+ ///
+ ///
public override void Bind(string property, Variable variable)
{
- throw new NotImplementedException();
+ throw new NotSupportedException("Imported images have no bindable properties");
}
+ ///
+ /// Returns the approximate boundaries of this OpenSCAD object
+ ///
+ ///
public override Bounds Bounds()
{
- throw new NotImplementedException();
+ return m_Bounds;
}
+ ///
+ /// Gets a copy of this object that is a new instance
+ ///
+ ///
public override OSCADObject Clone()
{
- throw new NotImplementedException();
+ return this.m_Object.Clone();
}
+ ///
+ /// Gets the position of this object's center (origin) in
+ /// world space
+ ///
+ ///
public override Vector3 Position()
{
- throw new NotImplementedException();
+ return Vector3.Average(this.m_Bounds.BottomLeft, this.m_Bounds.TopRight);
}
+ ///
+ /// Converts this object to an OpenSCAD script
+ ///
+ /// Script for this object
public override string ToString()
{
- var obj = new MultiStatementObject("union()", cubes);
- return obj.ToString();
+ return this.m_Object.ToString();
}
#endregion
}