195 lines
5.6 KiB
C#
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();
|
|
}
|
|
}
|
|
}
|