using System; using System.IO; using System.Drawing; using System.Drawing.Imaging; using System.Windows.Forms; using ClassLibrary; namespace Treko3D { #region RakurseArc public class RakurseArc { int _mmToPixelsCoeff; double _xa; double _ya; double _angle; double _sweepAngle; double _sweepAngleAnimation = 1; // 1 degree for preview double _angleRad; double _sweepAngleRad; double _radius; double _radius_base = 0.0; // !!! _radius_base for debug only RectDouble _rect; RectDouble _rectCircumf; public int MmToPixelsCoeff { get { return _mmToPixelsCoeff; } set { _mmToPixelsCoeff = value; } } public double Xa { get { return _xa; } set { _xa = value; } } public double Ya { get { return _ya; } set { _ya = value; } } public double Angle { get { return _angle; } set { _angle = value; } } public double SweepAngle { get { return _sweepAngle; } set { _sweepAngle = value; } } public double SweepAngleAnimation { get { return _sweepAngleAnimation; } set { _sweepAngleAnimation = value; } } public double AngleRad { get { return _angleRad; } set { _angleRad = value; } } public double SweepAngleRad { get { return _sweepAngleRad; } set { _sweepAngleRad = value; } } public double Radius { get { return _radius; } set { _radius = value; } } public RectDouble Rect { get { return _rect; } set { _rect = value; } } //Arc circumference rectangle (smaller than Rect) public RectDouble RectCircumf { get { return _rectCircumf; } set { _rectCircumf = value; } } RakurseArc() { } public RakurseArc(double xa, double ya, double angle, double sweepAngle, int mmToPixelsCoeff) { _xa = xa; _ya = ya; _angle = angle;// - sweepAngle/2; _sweepAngle = sweepAngle; _angleRad = _angle * Math.PI / 180; _sweepAngleRad = _sweepAngle * Math.PI / 180; _mmToPixelsCoeff = mmToPixelsCoeff; //_radius = r; } public int MmToPixels(double x) { return Convert.ToInt32(x * _mmToPixelsCoeff); } public void CalcRadiusFromColors(double radiusMax, int r, int g, int b) { int color = (r + g + b) / 3; _radius = _radius_base + color * radiusMax / 255; // !!! _radius_base for debug only } // We have radius in mm // The width of frame 0.2 mm or 1024 pixels // So the size of radius in pixels Rpix = _radius*1024/0.2 // This is rectangle only for draw arc public void CalcRectangleOfArc() { //_rect = new Rectangle(20, 20, 20, 20); //return; double A = 0; if (_radius > 0) { // distances to center of arc from center of arc segment double dx = _radius * Math.Cos(_angleRad + A); double dy = _radius * Math.Sin(_angleRad + A); // center of arc coordinates from left upper point of hologram double xc = _xa - dx; double yc = _ya - dy; // point 0 of rectangle double x0 = xc - _radius; double y0 = yc - _radius; // point 1 of rectangle double rectWidth = _radius * 2; double rectHeight = rectWidth; _rect = new RectDouble(x0, y0, rectWidth, rectHeight); // !!! //_rect = new Rectangle(10, 10, 20, 20); } } // Circumference rectangle to check if it intersects with frame // to draw in it public void CalcRectangleCircumfOfArc() { //_rect = new Rectangle(20, 20, 20, 20); //return; double A = 0; if (_radius > 0) { // distances to center of arc from center of arc segment double dx = _radius * Math.Cos(_angleRad + A); double dy = _radius * Math.Sin(_angleRad + A); // center of arc coordinates from left upper point of hologram double xc = _xa - dx; double yc = _ya - dy; // point 0 of rectangle //double x0 = xc + _radius * Math.Cos(_angleRad - _sweepAngleRad / 2 + A); //double y0 = yc + _radius * Math.Sin(_angleRad - _sweepAngleRad / 2 + A); //double x1 = xc + _radius * Math.Cos(_angleRad + _sweepAngleRad / 2 - A); //double y1 = yc + _radius * Math.Sin(_angleRad + _sweepAngleRad / 2 - A); double x0 = xc + _radius * Math.Cos(_angleRad + A); double y0 = yc + _radius * Math.Sin(_angleRad + A); double x1 = xc + _radius * Math.Cos(_angleRad - A); double y1 = yc + _radius * Math.Sin(_angleRad - A); double x0Rect = Math.Min(x0, x1); double y0Rect = Math.Min(y0, y1); double rectWidth = Math.Abs(x0 - x1); double rectHeight = Math.Abs(y0 - y1); _rectCircumf = new RectDouble(x0Rect, y0Rect, rectWidth, rectHeight); } } public bool DrawArc(Graphics g) { if (_radius != 0) { Pen pen = new Pen(Color.White, 1); //Rect.DrawArc(g, pen, _mmToPixelsCoeff, Convert.ToSingle(_angle - _sweepAngle / 2), Convert.ToSingle(_sweepAngle)); Rect.DrawArc(g, pen, _mmToPixelsCoeff, Convert.ToSingle(_angle), Convert.ToSingle(_sweepAngle)); pen.Dispose(); //Rect.DrawGradationArc(g, _mmToPixelsCoeff, Convert.ToSingle(_angle - _sweepAngle/2), Convert.ToSingle(_sweepAngle)); return true; } else return false; } public bool DrawAnimationArc(Graphics g, int angPreview, int parallaxAng) { if (_radius != 0) { //if (_angle - _sweepAngle > 0 && _angle != -4.5 && _angle != 4.5) //{ // int i = 0; //} angPreview = -angPreview; if (parallaxAng == 0) { Pen pen = new Pen(Color.White, 1); //if (angPreview <= _angle - _sweepAngle / 2 && angPreview >= _angle + _sweepAngle / 2) if (angPreview <= _angle && angPreview >= _angle + _sweepAngle) //Rect.DrawArc(g, pen, _mmToPixelsCoeff, Convert.ToSingle(angPreview - _sweepAngleAnimation / 2), Convert.ToSingle(_sweepAngleAnimation)); Rect.DrawArc(g, pen, _mmToPixelsCoeff, Convert.ToSingle(angPreview), Convert.ToSingle(_sweepAngleAnimation)); pen.Dispose(); } else { Pen pen1 = new Pen(Color.Red, 1); Pen pen2 = new Pen(Color.FromArgb(0, 150, 255), 1); //if (angPreview <= _angle - _sweepAngle / 2 && angPreview >= _angle + _sweepAngle / 2) if (angPreview <= _angle && angPreview >= _angle + _sweepAngle) //Rect.DrawArc(g, pen1, _mmToPixelsCoeff, Convert.ToSingle(angPreview - _sweepAngleAnimation / 2), Convert.ToSingle(_sweepAngleAnimation)); Rect.DrawArc(g, pen1, _mmToPixelsCoeff, Convert.ToSingle(angPreview), Convert.ToSingle(_sweepAngleAnimation)); //if (angPreview + parallaxAng <= _angle - _sweepAngle / 2 && angPreview + parallaxAng >= _angle + _sweepAngle / 2) if (angPreview + parallaxAng <= _angle && angPreview + parallaxAng >= _angle + _sweepAngle) //Rect.DrawArc(g, pen2, _mmToPixelsCoeff, Convert.ToSingle(angPreview + parallaxAng - _sweepAngleAnimation / 2), Convert.ToSingle(_sweepAngleAnimation)); Rect.DrawArc(g, pen2, _mmToPixelsCoeff, Convert.ToSingle(angPreview + parallaxAng), Convert.ToSingle(_sweepAngleAnimation)); pen1.Dispose(); pen2.Dispose(); } return true; } else return false; } public bool DrawArcFromZeroCoord(Graphics g, Pen pen) { if (_radius != 0) { //Rect.DrawArcFromZeroCoord(g, pen, _mmToPixelsCoeff, Convert.ToSingle(_angle - _sweepAngle / 2), Convert.ToSingle(_sweepAngle)); Rect.DrawArcFromZeroCoord(g, pen, _mmToPixelsCoeff, Convert.ToSingle(_angle), Convert.ToSingle(_sweepAngle)); return true; } else return false; } public bool DrawArcInFrame(RectDouble rect, Graphics g, int mmToPixelsCoeff, int[] profileColor) { if (_radius != 0) { //Rect.DrawArcInFrame(rect, _rectCircumf, g, pen, _mmToPixelsCoeff, Convert.ToSingle(_angle - _sweepAngle / 2), Convert.ToSingle(_sweepAngle)); //Rect.DrawGradationArcInFrame(rect, _rectCircumf, g, mmToPixelsCoeff, Convert.ToSingle(_angle - _sweepAngle / 2), Convert.ToSingle(_sweepAngle), profileColor); Rect.DrawGradationArcInFrame(rect, _rectCircumf, g, mmToPixelsCoeff, Convert.ToSingle(_angle), Convert.ToSingle(_sweepAngle), profileColor); return true; } else return false; } private void ClearRakurseArcBuffer() { //Array.Clear(_rakurseArc, 0, _rakurseArc.Length); } private int recalcRange(int val, int _grayHigh, int _grayLow) { int delta = _grayHigh - _grayLow; int newRangeValue = _grayLow + (val * delta / 256); return newRangeValue; } } #endregion #region Voxel public class Voxel : IDisposable { #region Local bool _empty = false; int _mmToPixelsCoeff; double _xc; double _yc; double _width; double _height; int _nRakurses; double _radiusMax; RectDouble _rectMax; private RakurseArc[] _rakurseArcs; #endregion #region Get/Set public bool Empty { get { return _empty; } set { _empty = value; } } public int MmToPixelsCoeff { get { return _mmToPixelsCoeff; } set { _mmToPixelsCoeff = value; } } public double Xc { get { return _xc; } } public double Yc { get { return _yc; } } public double Width { get { return _width; } } public double Height { get { return _height; } } public int NRakurses { get { return _nRakurses; } } public RakurseArc[] RakurseArcs { get { return _rakurseArcs; } } public double RadiusMax { get { return _radiusMax; } set { _radiusMax = value; } } public RectDouble RectMax { get { return _rectMax; } set { _rectMax = value; } } #endregion Voxel() { } public Voxel(double xc, double yc, int nRakurses, double radiusMax, int mmToPixelsCoeff) { _xc = xc; _yc = yc; _nRakurses = nRakurses; _radiusMax = radiusMax; _mmToPixelsCoeff = mmToPixelsCoeff; //int ArcHeight=0; //int ArcWidth=0; _rakurseArcs = new RakurseArc[nRakurses]; int sweepAngle = -180 / nRakurses; //contrclockwhise int curAngle = 0; for (int nArc = 0; nArc < _rakurseArcs.Length; nArc++) { _rakurseArcs[nArc] = new RakurseArc(_xc, _yc, curAngle, sweepAngle, mmToPixelsCoeff); curAngle += sweepAngle; } } public bool DrawArcs(Image imgTreko3D) { Pen whitePen = new Pen(Color.White, 1); Graphics g = Graphics.FromImage(imgTreko3D); //.CreateGraphics(); using (g) foreach (RakurseArc rArc in _rakurseArcs) { rArc.MmToPixelsCoeff = _mmToPixelsCoeff; rArc.DrawArc(g); //if (rArc.DrawArc(g) == true) // _empty = false; //else // _empty = true; } whitePen.Dispose(); g.Dispose(); return _empty; //pbVoxel.Scale() } public bool DrawAnimationArcs(Image imgTreko3D, int angPreview, int parallaxAng) { Pen whitePen = new Pen(Color.White, 1); Graphics g = Graphics.FromImage(imgTreko3D); //.CreateGraphics(); using (g) foreach (RakurseArc rArc in _rakurseArcs) { rArc.MmToPixelsCoeff = _mmToPixelsCoeff; rArc.DrawAnimationArc(g, angPreview, parallaxAng); //if (rArc.DrawAnimationArc(g, angPreview) == true) // _empty = false; //else // _empty = true; } whitePen.Dispose(); g.Dispose(); return _empty; //pbVoxel.Scale() } public void DrawArcs(Bitmap bmp) { Pen whitePen = new Pen(Color.White, 2); Graphics g = Graphics.FromImage(bmp); //.CreateGraphics(); using (g) foreach (RakurseArc rArc in _rakurseArcs) rArc.DrawArcFromZeroCoord(g, whitePen); whitePen.Dispose(); g.Dispose(); //pbVoxel.Scale() } public void CalcСircumfRectangle() { RectDouble rect; double xMin = double.MaxValue; double yMin = double.MaxValue; double xMax = double.MinValue; double yMax = double.MinValue; foreach (RakurseArc rArc in _rakurseArcs) { if (rArc.Radius == 0) // The pixel in source rakurse file is black continue; rect = rArc.Rect; if (xMin > rect.X) { xMin = rect.X; } if (yMin > rect.Y) { yMin = rect.Y; } if (xMax < rect.X + rect.Width) { xMax = rect.X + rect.Width; } if (yMax < rect.Y + rect.Height) { yMax = rect.Y + rect.Height; } } RectMax = new RectDouble(xMin, yMin, xMax - xMin, yMax - yMin); } public void Dispose() { RectMax = null; //for (int i = 0; i < _rakurseArcs.Length; i++) //{ // _rakurseArcs[i].Rect = null; // _rakurseArcs[i].RectCircumf = null; // _rakurseArcs[i] = null; //} //_rakurseArcs = null; } } #endregion #region Strip public class Strip : IDisposable { #region Private private bool _empty = false; private Treko3D _treko3DObj; private int _mmToPixelsCoeff; private string[] _rakurseFiles; private Bitmap[] _rakurseBmps; private int _nRakurses; private int _imageWidth; private int _imageHeight; private double _radiusMax; private Bitmap _stripBmp; private Voxel[] _voxelArray; private int _stripWidth; private int _stripHeight; private double _voxelStep; private int _nStrip; private string _prefix; #endregion #region Get/Set public bool Empty { get { return _empty; } set { _empty = value; } } public Treko3D Treko3Dobj { get { return _treko3DObj; } set { _treko3DObj = value; } } public int MmToPixelsCoeff { get { return _mmToPixelsCoeff; } set { _mmToPixelsCoeff = value; } } public string[] RakurseFiles { get { return _rakurseFiles; } set { _rakurseFiles = value; } } public Bitmap[] RakurseBmps { get { return _rakurseBmps; } set { _rakurseBmps = value; } } public int ImageWidth { get { return _imageWidth; } set { _imageWidth = value; } } public int ImageHeight { get { return _imageHeight; } set { _imageHeight = value; } } public double RadiusMax { get { return _radiusMax; } set { _radiusMax = value; } } public int NRakurses { get { return _nRakurses; } set { _nRakurses = value; } } public Bitmap StripBmp { get { return _stripBmp; } set { _stripBmp = value; } } public Voxel[] VoxelArray { get { return _voxelArray; } set { _voxelArray = value; } } public double VoxelStep { get { return _voxelStep; } set { _voxelStep = value; } } public int StripWidth { get { return _stripWidth; } set { _stripWidth = value; } } public int StripHeight { get { return _stripHeight; } set { _stripHeight = value; } } public int NStrip { get { return _nStrip; } set { _nStrip = value; } } #endregion Strip() { } public Strip(int nStrip, Treko3D treko3DObj) //string[] rakurseFiles) { _empty = false; _nStrip = nStrip; _treko3DObj = treko3DObj; _rakurseFiles = treko3DObj.RakurseFiles; _nRakurses = _rakurseFiles.Length; _radiusMax = treko3DObj.RadiusMax; //_mmToPixelsCoeff = treko3DObj.MmToPixelsCoeff; _voxelStep = treko3DObj.Step; _rakurseBmps = treko3DObj.RakurseBmps; _imageWidth = _rakurseBmps[0].Width; _imageHeight = _rakurseBmps[0].Height; _treko3DObj.ImageWidthPix = _imageWidth; _treko3DObj.ImageHeightPix = _imageHeight; _voxelArray = new Voxel[_imageWidth]; // (_stripWidth, _stripHeight, _nRakurses, _color)[_imageWidth]; double xc = 0; double yc = _voxelStep * nStrip; for (int nCol = 0; nCol < _voxelArray.Length; nCol++) { _voxelArray[nCol] = new Voxel(xc, yc, _nRakurses, _radiusMax, _mmToPixelsCoeff); xc += _voxelStep; } } public void CalcVoxelsСircumfRectangle() { foreach (Voxel voxel in _voxelArray) if (voxel.Empty == false) voxel.CalcСircumfRectangle(); } public int MmToPixels(double x) { return Convert.ToInt32(x * _mmToPixelsCoeff); } public void AddRakurseFileToStrip(Bitmap sourceBmp, int nRakurse, int nRow, int decimate) { BitmapData sourceData = null; // Init sourceData = sourceBmp.LockBits(new Rectangle(0, nRow, _imageWidth, 1), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); // Process Size sizeSource = sourceBmp.Size; unsafe { byte* sourceScanlineBytes = (byte*)sourceData.Scan0; int* sourceScanline = (int*)sourceScanlineBytes; int i = 0; for (int nPixel = 0; nPixel < sizeSource.Width; nPixel += decimate) { int color = sourceScanline[nPixel]; if (color != -16777216) i = 1; FillStripRakurseArcArray(color, nRakurse, nPixel, nRow); } } // Finalize if (sourceData != null) sourceBmp.UnlockBits(sourceData); //if (destData != null) // StripBmp.UnlockBits(destData); } public void AddRakurseFileToStrip(Bitmap sourceBmp, int nRakurse, int nRow, int nVoxelStart, int nVoxelEnd) { BitmapData sourceData = null; // Init sourceData = sourceBmp.LockBits(new Rectangle(0, nRow, _imageWidth, 1), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); // Process Size sizeSource = sourceBmp.Size; unsafe { byte* sourceScanlineBytes = (byte*)sourceData.Scan0; int* sourceScanline = (int*)sourceScanlineBytes; int i = 0; for (int nPixel = nVoxelStart; nPixel < nVoxelEnd; nPixel++) { int color = sourceScanline[nPixel]; if (color != -16777216) i = 1; FillStripRakurseArcArray(color, nRakurse, nPixel, nRow); } } // Finalize if (sourceData != null) sourceBmp.UnlockBits(sourceData); //if (destData != null) // StripBmp.UnlockBits(destData); } public string GetUntilOrEmpty(string text, string stopAt = "_") { if (!String.IsNullOrWhiteSpace(text)) { int charLocation = text.IndexOf(stopAt, StringComparison.Ordinal); if (charLocation > 0) { return text.Substring(0, charLocation); } } return String.Empty; } private FileInfo getFileName(int nRow, string path) { string dir = Path.GetDirectoryName(path); string fileName = Path.GetFileNameWithoutExtension(path); _prefix = GetUntilOrEmpty(fileName, "_"); _prefix = "nika"; string fileExt = ".png"; // Path.GetExtension(path); path = Path.Combine(dir, _prefix + "_" + nRow + fileExt); return new FileInfo(path); } public void GenerateAndSaveStrips(string path, int decimate) { for (int nRow = 0; nRow < ImageHeight; nRow += decimate) { FileInfo stripFile = getFileName(nRow, path); GenerateAndSaveStrip(nRow, stripFile.FullName, decimate); } } public void GenerateAndSaveStrip(int nStrip, string fileName, int decimate) { ConstructStripUsingRakurses(nStrip, decimate); //ConvertToTwoDimensionalBitArray(_stripWidth, _stripHeight, _nRakurses); //// For test only //FileInfo txtFileInfo = getTextFileName(fileName); //FileInfo bmpFileInfo = getBmpFileName(fileName); //Voxel voxel = _voxelArray[0]; //RakurseColumn rakurseCol = voxel.RakurseColumns[0]; //print2DimBitArrayToTextFile(rakurseCol.RakurseColumnBuffer, rakurseCol.Width, rakurseCol.Height, txtFileInfo.FullName); //print2DimBitArrayToTextFile(_twoDimensionalResultArray, rakurseCol.Width*4, rakurseCol.Height, txtFileInfo.FullName); //print2DimBitArrayToPicture(rakurseCol.RakurseColumnBuffer, rakurseCol.Width, rakurseCol.Height, pngFileInfo.FullName); //int stripWidth = _twoDimensionalResultArray.GetLength(0); //int stripHeight = _twoDimensionalResultArray.GetLength(1); //print2DimBitArrayToPicture(_twoDimensionalResultArray, stripWidth, stripHeight, fileName); } public void GenerateStrip(int nStrip, int nVoxelStart, int nVoxelEnd) { ConstructStripUsingRakurses(nStrip, nVoxelStart, nVoxelEnd); } public void ConstructStripUsingRakurses(int nStrip, int decimate) { for (int i = 0; i < NRakurses; i++) { try { AddRakurseFileToStrip(RakurseBmps[i], i, nStrip, decimate); } catch (Exception exception) { MessageBox.Show(exception.Message, exception.GetType().FullName); } } } public void ConstructStripUsingRakurses(int nStrip, int nVoxelStart, int nVoxelEnd) { for (int i = 0; i < NRakurses; i++) { try { AddRakurseFileToStrip(RakurseBmps[i], i, nStrip, nVoxelStart, nVoxelEnd); } catch (Exception exception) { MessageBox.Show(exception.Message, exception.GetType().FullName); } } } // 1. Take Voxel from array of voxels by nCol index. // 2. In that Voxel take RakurseArc from array of rackurseArcs by nRakurse index. // 3. In that RakurseArc calculate radius=RadiusMax*Color/255. private void FillStripRakurseArcArray(int color, int nRakurse, int nCol, int nRow) { int r = (color >> 16) & 0xFF; int g = (color >> 8) & 0xFF; int b = color & 0xFF; Voxel voxel = _voxelArray[nCol]; RakurseArc rakurseArc = voxel.RakurseArcs[nRakurse]; rakurseArc.CalcRadiusFromColors(_radiusMax, r, g, b); rakurseArc.CalcRectangleOfArc(); rakurseArc.CalcRectangleCircumfOfArc(); // values r,g,b of each source pixel we need for statistics procedures //voxel.R = r; //voxel.G = g; //voxel.B = b; } public void DrawOnPictureBox(Image imgTreko3D, int mmToPixelsCoeff) { //_empty = true; _mmToPixelsCoeff = mmToPixelsCoeff; foreach (Voxel voxel in _voxelArray) { if (voxel.Empty == false) { voxel.MmToPixelsCoeff = _mmToPixelsCoeff; voxel.DrawArcs(imgTreko3D); voxel.Empty = voxel.DrawArcs(imgTreko3D); //if (voxel.Empty == false) // _empty = false; } } } public void DrawAnimation(Image imgTreko3D, int angPreview, int parallaxAng, int mmToPixelsCoeff) { _empty = true; _mmToPixelsCoeff = mmToPixelsCoeff; foreach (Voxel voxel in _voxelArray) { //if (voxel.Empty == false) //{ voxel.MmToPixelsCoeff = _mmToPixelsCoeff; voxel.Empty = voxel.DrawAnimationArcs(imgTreko3D, angPreview, parallaxAng); //if (voxel.Empty == false) // _empty = false; //} } } public void Dispose() { for (int i = 0; i < _voxelArray.Length; i++) { _voxelArray[i].Dispose(); _voxelArray[i] = null; } _voxelArray = null; if (_stripBmp != null) _stripBmp.Dispose(); } } #endregion }