mattercontrol/MatterControlLib/DesignTools/Lithophane.cs
2019-01-11 17:10:45 -08:00

195 lines
5.6 KiB
C#

/*
Copyright (c) 2018, John Lewin
*/
using System;
using System.Diagnostics;
using System.Linq;
using MatterHackers.Agg;
using MatterHackers.Agg.Image;
using MatterHackers.PolygonMesh;
using MatterHackers.VectorMath;
namespace MatterHackers.MatterControl.Plugins.Lithophane
{
public static class Lithophane
{
class PixelInfo
{
public Vector3 Top { get; set; }
public Vector3 Bottom { get; set; }
}
public static Mesh Generate(IImageData resizedImage, double maxZ, double nozzleWidth, double pixelsPerMM, bool invert, IProgress<ProgressStatus> reporter)
{
throw new NotImplementedException();
//// TODO: Move this to a user supplied value
//double baseThickness = nozzleWidth; // base thickness (in mm)
//double zRange = maxZ - baseThickness;
//// Dimensions of image
//var width = resizedImage.Width;
//var height = resizedImage.Height;
//var zScale = zRange / 255;
//var pixelData = resizedImage.Pixels;
//Stopwatch stopwatch = Stopwatch.StartNew();
//var mesh = new Mesh();
////var rescale = (double)onPlateWidth / imageData.Width;
//var rescale = 1;
//var progressStatus = new ProgressStatus();
//// Build an array of PixelInfo objects from each pixel
//// Collapse from 4 bytes per pixel to one - makes subsequent processing more logical and has minimal cost
//var pixels = pixelData.Where((x, i) => i % 4 == 0)
// // Interpolate the pixel color to zheight
// .Select(b => baseThickness + (invert ? 255 - b : b) * zScale)
// // Create a Vector3 for each pixel at the computed x/y/z
// .Select((z, i) => mesh.CreateVertex(new Vector3(
// i % width * rescale,
// (i - i % width) / width * rescale * -1,
// z)))
// // Create a mirrored vector for the pixel at z0 and return with top/bottom paired together
// .Select(vec => new PixelInfo()
// {
// Top = vec,
// Bottom = mesh.CreateVertex(new Vector3(
// vec.Position.X,
// vec.Position.Y,
// 0))
// }).ToArray();
//Console.WriteLine("ElapsedTime - PixelInfo Linq Generation: {0}", stopwatch.ElapsedMilliseconds);
//stopwatch.Restart();
//// Select pixels along image edges
//var backRow = pixels.Take(width).Reverse().ToArray();
//var frontRow = pixels.Skip((height - 1) * width).Take(width).ToArray();
//var leftRow = pixels.Where((x, i) => i % width == 0).ToArray();
//var rightRow = pixels.Where((x, i) => (i + 1) % width == 0).Reverse().ToArray();
//int k,
// nextJ,
// nextK;
//var notificationInterval = 100;
//var workCount = (resizedImage.Width - 1) * (resizedImage.Height - 1) +
// (height - 1) +
// (width - 1);
//double workIndex = 0;
//// Vertical faces: process each row and column, creating the top and bottom faces as appropriate
//for (int i = 0; i < resizedImage.Height - 1; ++i)
//{
// var startAt = i * width;
// // Process each column
// for (int j = startAt; j < startAt + resizedImage.Width - 1; ++j)
// {
// k = j + 1;
// nextJ = j + resizedImage.Width;
// nextK = nextJ + 1;
// // Create north, then south face
// mesh.CreateFace(new IVertex[] { pixels[k].Top, pixels[j].Top, pixels[nextJ].Top, pixels[nextK].Top });
// mesh.CreateFace(new IVertex[] { pixels[j].Bottom, pixels[k].Bottom, pixels[nextK].Bottom, pixels[nextJ].Bottom });
// workIndex++;
// if (workIndex % notificationInterval == 0)
// {
// progressStatus.Progress0To1 = workIndex / workCount;
// reporter.Report(progressStatus);
// }
// }
//}
//// Side faces: East/West
//for (int j = 0; j < height - 1; ++j)
//{
// //Next row
// k = j + 1;
// // Create east, then west face
// mesh.CreateFace(new IVertex[] { leftRow[k].Top, leftRow[j].Top, leftRow[j].Bottom, leftRow[k].Bottom });
// mesh.CreateFace(new IVertex[] { rightRow[k].Top, rightRow[j].Top, rightRow[j].Bottom, rightRow[k].Bottom });
// workIndex++;
// if (workIndex % notificationInterval == 0)
// {
// progressStatus.Progress0To1 = workIndex / workCount;
// reporter.Report(progressStatus);
// }
//}
//// Side faces: North/South
//for (int j = 0; j < width - 1; ++j)
//{
// // Next row
// k = j + 1;
// // Create north, then south face
// mesh.CreateFace(new IVertex[] { frontRow[k].Top, frontRow[j].Top, frontRow[j].Bottom, frontRow[k].Bottom });
// mesh.CreateFace(new IVertex[] { backRow[k].Top, backRow[j].Top, backRow[j].Bottom, backRow[k].Bottom });
// workIndex++;
// if (workIndex % notificationInterval == 0)
// {
// progressStatus.Progress0To1 = workIndex / workCount;
// reporter.Report(progressStatus);
// }
//}
//Console.WriteLine("ElapsedTime - Face Generation: {0}", stopwatch.ElapsedMilliseconds);
//return mesh;
}
public interface IImageData
{
byte[] Pixels { get; }
int Width { get; }
int Height { get; }
}
public class ImageBufferImageData : IImageData
{
ImageBuffer resizedImage;
public ImageBufferImageData(ImageBuffer image, double pixelWidth)
{
resizedImage = this.ToResizedGrayscale(image, pixelWidth);
resizedImage.FlipY();
}
public int Width => resizedImage.Width;
public int Height => resizedImage.Height;
private ImageBuffer ToResizedGrayscale(ImageBuffer image, double onPlateWidth = 0)
{
var ratio = onPlateWidth / image.Width;
var resizedImage = image.CreateScaledImage(ratio);
var grayImage = resizedImage.ToGrayscale();
// Render grayscale pixels onto resized image with larger pixel format needed by caller
resizedImage.NewGraphics2D().Render(grayImage, 0, 0);
return resizedImage;
}
public byte[] Pixels => resizedImage.GetBuffer();
}
}
}