% **********************************************

%Tento program je soucasti diplomove prace...
% Autor: Bogdan Szpyrc
% Email: szpyrc.bogdan@gmail.com

% Skola: VUT Brno

% % Fakulta: FEKT
% Obor: Biomedicinske a ekologicke inzenyrstvi
% **********************************************

%Program v C#


#### FORM: ####
﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.IO;
using System.Windows.Forms;
using System.Drawing.Imaging;
using System.Threading;


namespace NTmeasurementplugin
{
    public partial class Form1 : Form
    {
#region VARIABLES
    //    private static Bitmap bmpScreenshot;
    //    private static Graphics gfxScreenshot;
        Bitmap image;
        Point A;
        Point B;
        Point C;
        Point D;
        Point Ci;
        Point Di;
        Histogram Hist;
        NTdistances alldist;
        double scale=0;
        STAT statistic_data;
        int stat_count=0;

        int SetNT_sw=0; //pomocna pro vyber zpusobu zadavani NT
                        //1...Auto, 2...Semiauto, 3...Manual

        Bitmap anglerotate; //pomocny obrazek k nahledu uhlu pod kterym se dela profil
        Graphics g;
        Point diff = new Point(0,0);
        Point OldMousePos; //pro potlaceni chveni v obrze pri zadavani NT
       // MagnifyingGlass magnifyingGlass1;
        
        private struct NTprofile
          {
            public Point[] Profile; //hodnoty z obrazku (stupne sedi)
            public Point[] Line;    //body
            public float[,] Profile_in_float;
          }
        private struct Histogram
        {
            public int[] Values;
            public int CenterOfMass;
        }
        private struct NTdistances
        {
            public Point S;
            public Point[] C;
           public Point[] Cinter;
            public Point[] D;
           public Point[] Dinter;
            public double[] distances_px;
            public double maxdistance_px;
            public double meandistance_px;
            public double variance_px;
            public double[] rovc;
            public double[] rovd;
            public int st;
            public double quality;
        }


        private struct STAT
        {
            public double scale;
            public string imagename;

            public double maxNT;
            public double maxNTpx;
            public double meanNT;
            public double meanNTpx;
            
            public double variance;
            public double standard_dev;
            public Point A;
            public Point B;
            public Point C;
            public Point D;
            public int dyn1_px;
            public int dyn2_px;
        }
#endregion

        
        public Form1()
        {
            InitializeComponent();
           
        ///********************************************************///
            //printscreen
            image = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, PixelFormat.Format24bppRgb);
            Graphics gfxScreenshot = Graphics.FromImage(image);
            gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);
            SetBackgroundImage(image);
            //magnify
            magnifyingGlass1.UpdateTimer.Start();
            magnifyingGlass1.MovingGlass.MagnifyingGlass.Click += new EventHandler(MagnifyingGlass_Click);
            magnifyingGlass1.MovingGlass.VisibleChanged += new EventHandler(MovingGlass_VisibleChanged);
            magnifyingGlass1.MovingGlass.MagnifyingGlass.BeforeMakingScreenshot += new MagnifyingGlass.MakingScreenshotDelegate(MagnifyingGlass_BeforeMakingScreenshot);
            magnifyingGlass1.MovingGlass.MagnifyingGlass.AfterMakingScreenshot += new MagnifyingGlass.MakingScreenshotDelegate(MagnifyingGlass_AfterMakingScreenshot);
        }

        ///////////////////////////////////////////////

        ///////////////////////////////////////////////

        #region L O A D
        private void Form1_Load(object sender, EventArgs e)
        {

            this.Controls.Add(this.magnifyingGlass1);
         //   magnifyingGlass1.Visible = false;
            
            Cpoint.Visible = false;
            Dpoint.Visible = false;

            anglerotate = new Bitmap("anglerotate.jpg");

            //BTN_Load_Click(null, null);

        }
        #endregion

        #region BTNs
        private void BTN_Load_Click(object sender, EventArgs e)
        {
         /*   if (image != null)
            {
              
                image.Dispose();
            }
        */  
            /// STATISTIKA - reset
            statistic_data.imagename = null;
            statistic_data.maxNT = 0;
            statistic_data.maxNTpx = 0;
            statistic_data.meanNT = 0;
            statistic_data.meanNTpx = 0;
            statistic_data.scale = 0;
            statistic_data.A = new Point(0, 0);
            statistic_data.B = new Point(0, 0);
            statistic_data.C = new Point(0, 0);
            statistic_data.D = new Point(0, 0);
            statistic_data.dyn1_px = 0;
            statistic_data.dyn2_px = 0;
            statistic_data.variance = 0;
            statistic_data.standard_dev = 0;

          if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
               image = new Bitmap(openFileDialog1.FileName);

               SetBackgroundImage(image);

               statistic_data.imagename = openFileDialog1.FileName.ToString();

             }
          
        }

        private void BTN_Hist_Click(object sender, EventArgs e)
        {
            try
            {
                if (TB_Tolerance.Visible == false)
                {
                    histogram.Visible = true;
                    histogram.Refresh();
                    TB_Tolerance.Visible = true;
                    LBL_toler.Visible = true;
                    
                    PlotHistogram(Hist);
                    
                }
                else
                {
                    LBL_toler.Visible = false;
                    histogram.Visible = false;
                    TB_Tolerance.Visible = false;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Chyba v histogramu");
            }
        }
        
        private void BTN_PrtSc_Click(object sender, EventArgs e)
        {
            // If the user has chosen a path where to save the screenshot

            // Hide the form so that it does not appear in the screenshot
            this.Hide(); 
            Thread.Sleep(1000);
            // Set the bitmap object to the size of the screen
            image = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, PixelFormat.Format24bppRgb);
            // Create a graphics object from the bitmap
            Graphics gfxScreenshot = Graphics.FromImage(image);
            // Take the screenshot from the upper left corner to the right bottom corner
            gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);
            // Save the screenshot to the specified path that the user has chosen
           // image.Save(@"PtrScr.bmp", ImageFormat.Bmp);
            // Show the form again
           this.Show();

           SetBackgroundImage(image);

        }

        private void BTN_Close_Click(object sender, EventArgs e)
        {
            anglerotate.Dispose();
            this.Close();
        }

        private void BTN_Save_Click(object sender, EventArgs e)
        {
            image = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, PixelFormat.Format24bppRgb);
            // Create a graphics object from the bitmap
            Graphics gfxScreenshot = Graphics.FromImage(image);
            // Take the screenshot from the upper left corner to the right bottom corner
            gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);
            // Save the screenshot to the specified path that the user has chosen
            DirectoryInfo d = new DirectoryInfo(Directory.GetCurrentDirectory() + @"\NTs");

            DateTime date = DateTime.Today;
            string todaystring = "y" + date.Year.ToString() + @"m" +
                                       date.Month.ToString() + @"d" +
                                       date.Day.ToString();
            FileInfo[] f = d.GetFiles(todaystring+"*");
            string fn = f.Length.ToString();
            image.Save(d.ToString() + @"\" + todaystring + @"_" + fn + ".bmp", ImageFormat.Bmp);

            DialogResult myDialogResult = MessageBox.Show("Continue?", "SAVE OK", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
            if (myDialogResult == DialogResult.No)
            {
                this.Close();
            }

        }

        private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            if ((e.Control) && (e.KeyCode == Keys.S))
            {
                BTN_Save_Click(null, null);
            }
            //posun kurzoru o jeden pixel
            else if ((e.Control) && (e.KeyCode == Keys.Left))
            {   
                int x = ((PointToClient(Cursor.Position)).X);
                int y = PointToClient(Cursor.Position).Y;
                Cursor.Position = (new Point(--x, y));
            }
            else if ((e.Control) && (e.KeyCode == Keys.Right))
            {
                int x = ((PointToClient(Cursor.Position)).X);
                int y = PointToClient(Cursor.Position).Y;
                Cursor.Position = (new Point(++x, y));
            }
            else if ((e.Control) && (e.KeyCode == Keys.Up))
            {
                int x = ((PointToClient(Cursor.Position)).X);
                int y = PointToClient(Cursor.Position).Y;
                Cursor.Position = (new Point(x, --y));
            }
            else if ((e.Control) && (e.KeyCode == Keys.Down))
            {
                int x = ((PointToClient(Cursor.Position)).X);
                int y = PointToClient(Cursor.Position).Y;
                Cursor.Position = (new Point(x, ++y));
            }
            else if ((e.Control) && (e.KeyCode == Keys.L))
            {
                if (ChB_ShowNTLimiting.Checked)
                    ChB_ShowNTLimiting.Checked = false;
                else
                    ChB_ShowNTLimiting.Checked = true;
            }
        }

        #endregion

        #region SelectNT


        private void BTN_AutoNT_Click(object sender, EventArgs e)
       {
           if (SetNT_sw==0)
           {
               ResetPoints();
               RB_A.Text = "A";
               RB_B.Text = "B";
               SetNT_sw = 1;
               LBL_info.Text = "Zadejte jeden bod uvnitr NT";
               ChB_PROFILE.Checked = false;
           }
           else { 
               LBL_info.Text = "Vyberde moznost zadavani NT";
               SetNT_sw = 0;
           }
           
       }

       private void BTN_SemiautoNT_Click(object sender, EventArgs e)
         {
             if (!(RB_A.Checked | RB_B.Checked | RB_SetNT.Checked) & SetNT_sw==0)
             {
                 ResetPoints();
                 RB_A.Text = "A";
                 RB_B.Text = "B";
                 LBL_info.Text = "Zadejte bod A";
                 SetNT_sw = 2;
                 RB_A.Checked = true;
                 ChB_PROFILE.Checked = false;
             }
             else
             {
                 //odznaceni vsech RB
                 RB_A.Checked = false;
                 RB_B.Checked = false;
                 RB_SetNT.Checked = false;
                 SetNT_sw = 0;
                 LBL_info.Text = "Vyberde moznost zadavani NT";
             }
         }

       private void BTN_ManualNT_Click(object sender, EventArgs e)
        {
            if (SetNT_sw == 0)
            {
                ResetPoints();
                RB_A.Text = "C";
                RB_B.Text = "D";

                LBL_info.Text = "Zadejte bod C";
                SetNT_sw = 3;
                RB_A.Checked = true;
                ChB_PROFILE.Checked = true;
            }
            else
            {
                RB_A.Checked = false;
                RB_B.Checked = false;
                RB_SetNT.Checked = false;
                SetNT_sw = 0;
                LBL_info.Text = "Vyberde moznost zadavani NT";
            }

        }


       #endregion

        #region Insert Points ABCD - klik mysi
        public void Form1_MouseDown(object sender, MouseEventArgs e)
        {
        #region Lupa zap./vyp.
            if (e.Button == MouseButtons.Right)
            {
                if (magnifyingGlass1.Visible == false)
                {
                    magnifyingGlass1.Show();
                    GB_Zoom.Visible = true;
                }
                else
                {
                    magnifyingGlass1.Hide();
                    GB_Zoom.Visible = false;
                }
            }
        #endregion
            else
            {
                //Kresleni bodu 
                g = this.CreateGraphics();
                int crossize = 3;
                #region AutoSetNT
                if (SetNT_sw==1)
                {
                    if (!RB_SetNT.Checked)
                    {
                    Point p = PointToClient(Cursor.Position);

                    FloodFiller floodfiller = new FloodFiller();
                    byte toler=(byte)(TB_Tolerance.Value/4);
                    floodfiller.Tolerance[0] = toler;
                    floodfiller.Tolerance[1] = toler;
                    floodfiller.Tolerance[2] = toler;
                    floodfiller.FillStyle = (FloodFillStyle)Enum.Parse(typeof(FloodFillStyle), "Linear");

                    Bitmap temp_image = new Bitmap(image);
                    NTprofile NT = GetProfile(image, p, new Point(p.X + 30, p.Y), p);
                    Point min = GetNTMin(NT.Profile);
                    p = new Point(NT.Line[min.X].X, NT.Line[min.X].Y);

                    floodfiller.FloodFill(temp_image, p);
                    A = floodfiller.GetA();
                    B = floodfiller.GetB();
                    if (ChB_autocorrAB.Checked)
                    {
                        #region UPRAVA BODU AB
                        // * * * * * * * uprava bodu AB
                        NT = GetProfile(image, A, new Point(A.X + 30, A.Y), A);
                        min = GetNTMin(NT.Profile);
                        A = new Point(NT.Line[min.X].X, NT.Line[min.X].Y);

                        NT = GetProfile(image, B, new Point(B.X - 30, B.Y), B);
                        min = GetNTMin(NT.Profile);
                        B = new Point(NT.Line[min.X].X, NT.Line[min.X].Y);
                        
                            g.DrawLine(Pens.Green, new Point(A.X - crossize, A.Y), new Point(A.X + crossize, A.Y));
                            g.DrawLine(Pens.Green, new Point(A.X, A.Y - crossize), new Point(A.X, A.Y + crossize));
                            g.DrawLine(Pens.Green, new Point(B.X - crossize, B.Y), new Point(B.X + crossize, B.Y));
                            g.DrawLine(Pens.Green, new Point(B.X, B.Y - crossize), new Point(B.X, B.Y + crossize));
                        
                        #region nastaveni poc.bodu (nazavislost poradi zadani bodu AB)
                        int startindex;
                        int stopindex;
                        if (Math.Abs(B.Y - A.Y) < Math.Abs(A.X - B.X))
                        {
                            if (A.X <= B.X)
                            {
                                startindex = A.X;
                                stopindex = B.X;
                            }
                            else
                            {
                                startindex = B.X;
                                stopindex = A.X;
                            }
                        }
                        else
                        {
                            if (A.Y <= B.Y)
                            {
                                startindex = A.Y;
                                stopindex = B.Y;
                            }
                            else
                            {
                                startindex = B.Y;
                                stopindex = A.Y;
                            }
                        }
                        #endregion
                        Point[] Sline = new Point[stopindex - startindex + 1];
                        Point S_temp;
                        int j = 0;
                        for (int i = startindex; i <= stopindex; i++)
                        {
                            //Graphics g = this.CreateGraphics();
                            // pohyb kurzoru pouze po ose NT
                            Point n = new Point(B.Y - A.Y, A.X - B.X); //normalovy vektor
                            int mx = i;
                            int my = i;
                            int q = -(n.X * A.X + n.Y * A.Y); //s=-sum(n.*a);
                            // Rovnice primky px+ry+q=0, kde n=[p r]
                            if (Math.Abs(n.X) < Math.Abs(n.Y)) //horizontalni osa
                                S_temp = (new Point(mx, (Int16)(-1.0 / n.Y * (n.X * mx + q))));
                            else //vertikalni osa
                                S_temp = (new Point((Int16)(-1.0 / n.X * (n.Y * my + q)), my));
                            //

                            NT = GetProfile(image, A, B, S_temp);
                            min = GetNTMin(NT.Profile);

                            j = i - startindex;
                            Sline[j] = new Point(NT.Line[min.X].X, NT.Line[min.X].Y);
                        }
                        if (ChB_ShowNTLimiting.Checked)
                        {
                        g.DrawLines(Pens.Green, Sline);
                        }
                        //vse pro osu NT "rovnobeznou" s osu X
                        int stupen = 1;
                        double[] s = MNK(Sline, stupen);

                        int ys = 0;

                        for (int i = startindex; i <= stopindex; i++)
                        {
                            j = i - startindex;
                            ys = 0;
                            for (int k = stupen; k >= 0; k--)
                            {
                                ys += (int)(s[k] * Math.Pow(i, k));
                            }
                            Sline[j] = new Point(Sline[j].X, ys);
                        }
                        A = Sline[(int)(0.1 * Sline.Length)];
                        B = Sline[(int)(0.9 * Sline.Length)];

                        RB_A.Text = "A " + A.ToString();
                        RB_B.Text = "B " + B.ToString();

                        //vykresleni osy NT
                        if (ChB_ShowNTLimiting.Checked)
                        {
                            Graphics gg = this.CreateGraphics();
                            gg.DrawLines(Pens.Yellow, Sline);
                            gg.DrawLine(Pens.Yellow, new Point(A.X - crossize, A.Y), new Point(A.X + crossize, A.Y));
                            gg.DrawLine(Pens.Yellow, new Point(A.X, A.Y - crossize), new Point(A.X, A.Y + crossize));
                            gg.DrawLine(Pens.Yellow, new Point(B.X - crossize, B.Y), new Point(B.X + crossize, B.Y));
                            gg.DrawLine(Pens.Yellow, new Point(B.X, B.Y - crossize), new Point(B.X, B.Y + crossize));
                        }
                        // * * * * * * *
                        #endregion
                    }
                    alldist = FindMaxWidth(image, A, B);
                    Cursor.Position = alldist.S; //jednodussi postup pro hledani maxim
                    LBL_NTmean.Text = "NT mean: " + String.Format("{0:0.00}", PxToMm(alldist.meandistance_px)) + " mm = " + String.Format("{0:0.00}", alldist.meandistance_px) + " px";
                    LBL_NTvariance.Text = "NT variance: " + String.Format("{0:0.00}", PxToMm(alldist.variance_px)) + " mm";
                    LBL_NTSD.Text = "NT standard deviation: " + String.Format("{0:0.00}", Math.Sqrt(PxToMm(alldist.variance_px))) + " mm";
                    LBL_quality_if_inter.Text = "Quality: " + String.Format("{0:0.00}", (alldist.quality)) + " px = " + String.Format("{0:0.00}", PxToMm(alldist.quality)) +" mm";
                    LBL_NTmax.Text = "NT max: " + String.Format("{0:0.00}",PxToMm(alldist.maxdistance_px)) + " mm = " + String.Format("{0:0.00}",alldist.maxdistance_px) + " px";

                        //STATISTIKA
                    statistic_data.meanNT = PxToMm(alldist.meandistance_px);
                    statistic_data.meanNTpx = alldist.meandistance_px;
                    statistic_data.maxNT = PxToMm(alldist.maxdistance_px);
                    statistic_data.maxNTpx = alldist.maxdistance_px;
                    statistic_data.variance = alldist.variance_px;
                    statistic_data.standard_dev = Math.Sqrt(alldist.variance_px);

                            

                    //vykresleni grafu vzdalenosti NT
                    PlotDistances();
                    
                  // this.Refresh();
                  // floodfiller.CalcSPoint(temp_image);
                  // Cursor.Position = floodfiller.GetS();

                    //Paint A
                    g.DrawLine(Pens.Yellow, new Point(A.X - crossize, A.Y), new Point(A.X + crossize, A.Y));
                    g.DrawLine(Pens.Yellow, new Point(A.X, A.Y - crossize), new Point(A.X, A.Y + crossize));
                    //Paint B
                    g.DrawLine(Pens.Yellow, new Point(B.X - crossize, B.Y), new Point(B.X + crossize, B.Y));
                    g.DrawLine(Pens.Yellow, new Point(B.X, B.Y - crossize), new Point(B.X, B.Y + crossize));

                    RB_SetNT.Checked = true;
                    LBL_info.Text = "Vyberde moznost zadavani NT";
                    
                }
                    else 
                    {
                        Cpoint.Visible = false;
                        Dpoint.Visible = false;
                        //vykresleni ohrnaniceni NT
                        if (ChB_ShowNTLimiting.Checked)
                        {
                            Pen myPen = new Pen(System.Drawing.Color.Red, 1);
                            Graphics gg = this.CreateGraphics();
                            gg.DrawLines(myPen, alldist.C);
                            gg.DrawLines(Pens.Blue, alldist.Cinter);
                            gg.DrawLines(myPen, alldist.D);
                            gg.DrawLines(Pens.Blue, alldist.Dinter);

                        }
                        g.DrawLine(Pens.Yellow, new Point(Ci.X - crossize, Ci.Y), new Point(Ci.X + crossize, Ci.Y));
                        g.DrawLine(Pens.Yellow, new Point(Ci.X, Ci.Y - crossize), new Point(Ci.X, Ci.Y + crossize));
                        g.DrawLine(Pens.Yellow, new Point(Di.X - crossize, Di.Y), new Point(Di.X + crossize, Di.Y));
                        g.DrawLine(Pens.Yellow, new Point(Di.X, Di.Y - crossize), new Point(Di.X, Di.Y + crossize));
                       
                        RB_SetNT.Checked = false;
                        LBL_DownRisk.Text = "Risk: " + String.Format("{0:0.00}", DownRisk_NT(TB_Age.Value, (double)TB_CRL.Value, PxToMm(NTdist_in_px(Ci, Di)))) + " %";
                        SetNT_sw = 0;
                    }
                }


                #endregion
                #region SemiautoNT
                else if (SetNT_sw == 2)
                {
                    
                    if (RB_A.Checked)
                    {
                        //this.Refresh();

                        A = PointToClient(Cursor.Position);
                        RB_A.Text = "A " + A.ToString();
                        #region comment
                        //pointA.Location = (new Point(A.X - 8, A.Y - 10));
                        //pointA.Visible = true;
                        //pointA.Refresh();

                        //   g.DrawEllipse(Pens.Yellow, A.X-3, A.Y-3, 6, 6); //korekce aby to bylo ve stredu
                        #endregion
                        g.DrawLine(Pens.Blue, new Point(A.X - crossize, A.Y), new Point(A.X + crossize, A.Y));
                        g.DrawLine(Pens.Blue, new Point(A.X, A.Y - crossize), new Point(A.X, A.Y + crossize));

                        LBL_info.Text = "Zadejte bod B";
                        RB_B.Checked = true;
                    }
                    else if (RB_B.Checked)
                    {
                        
                        B = PointToClient(Cursor.Position);
                        RB_B.Text = "B " + B.ToString();
                        #region comment

                        //pointB.Location = (new Point(B.X - 8, B.Y - 10));
                        //pointB.Visible = true;
                        //pointB.Refresh();

                        // g.DrawEllipse(Pens.Yellow, B.X - 3, B.Y - 3, 6, 6); //korekce Bby to bylo ve stredu
                        #endregion

           
                        g.DrawLine(Pens.Blue, new Point(B.X - crossize, B.Y), new Point(B.X + crossize, B.Y));
                        g.DrawLine(Pens.Blue, new Point(B.X, B.Y - crossize), new Point(B.X, B.Y + crossize));

                        if (ChB_autocorrAB.Checked)
                        {
                            #region UPRAVA BODU AB
                            // * * * * * * * uprava bodu AB
                            NTprofile NT = GetProfile(image, A, new Point(A.X + 30, A.Y), A);
                            Point min = GetNTMin(NT.Profile);
                            A = new Point(NT.Line[min.X].X, NT.Line[min.X].Y);

                            NT = GetProfile(image, B, new Point(B.X - 30, B.Y), B);
                            min = GetNTMin(NT.Profile);
                            B = new Point(NT.Line[min.X].X, NT.Line[min.X].Y);
                           
                                g.DrawLine(Pens.Green, new Point(A.X - crossize, A.Y), new Point(A.X + crossize, A.Y));
                                g.DrawLine(Pens.Green, new Point(A.X, A.Y - crossize), new Point(A.X, A.Y + crossize));
                                g.DrawLine(Pens.Green, new Point(B.X - crossize, B.Y), new Point(B.X + crossize, B.Y));
                                g.DrawLine(Pens.Green, new Point(B.X, B.Y - crossize), new Point(B.X, B.Y + crossize));
                            
                            #region nastaveni poc.bodu (nazavislost poradi zadani bodu AB)
                            int startindex;
                            int stopindex;
                            if (Math.Abs(B.Y - A.Y) < Math.Abs(A.X - B.X))
                            {
                                if (A.X <= B.X)
                                {
                                    startindex = A.X;
                                    stopindex = B.X;
                                }
                                else
                                {
                                    startindex = B.X;
                                    stopindex = A.X;
                                }
                            }
                            else
                            {
                                if (A.Y <= B.Y)
                                {
                                    startindex = A.Y;
                                    stopindex = B.Y;
                                }
                                else
                                {
                                    startindex = B.Y;
                                    stopindex = A.Y;
                                }
                            }
                            #endregion
                            Point[] Sline = new Point[stopindex - startindex + 1];
                            Point S_temp;
                            int j = 0;
                            for (int i = startindex; i <= stopindex; i++)
                            {
                                //Graphics g = this.CreateGraphics();
                                // pohyb kurzoru pouze po ose NT
                                Point n = new Point(B.Y - A.Y, A.X - B.X); //normalovy vektor
                                int mx = i;
                                int my = i;
                                int q = -(n.X * A.X + n.Y * A.Y); //s=-sum(n.*a);
                                // Rovnice primky px+ry+q=0, kde n=[p r]
                                if (Math.Abs(n.X) < Math.Abs(n.Y)) //horizontalni osa
                                    S_temp = (new Point(mx, (Int16)(-1.0 / n.Y * (n.X * mx + q))));
                                else //vertikalni osa
                                    S_temp = (new Point((Int16)(-1.0 / n.X * (n.Y * my + q)), my));
                                //

                                NT = GetProfile(image, A, B, S_temp);
                                min = GetNTMin(NT.Profile);

                                j = i - startindex;
                                Sline[j] = new Point(NT.Line[min.X].X, NT.Line[min.X].Y);
                            }

                            if (ChB_ShowNTLimiting.Checked)
                            {
                            g.DrawLines(Pens.Green, Sline);
                            }
                                
                            //vse pro osu NT "rovnobeznou" s osu X
                            int stupen = 1;
                            double[] s = MNK(Sline, stupen);

                            int ys = 0;

                            for (int i = startindex; i <= stopindex; i++)
                            {
                                j = i - startindex;
                                ys = 0;
                                for (int k = stupen; k >= 0; k--)
                                {
                                    ys += (int)(s[k] * Math.Pow(i, k));
                                }
                                Sline[j] = new Point(Sline[j].X, ys);
                            }
                            A = Sline[0];//(int)(0.1 * Sline.Length)];
                            B = Sline[Sline.Length-1];//(int)(0.9 * Sline.Length)];

                            RB_A.Text = "A " + A.ToString();
                            RB_B.Text = "B " + B.ToString();

                            //vykresleni osy NT
                            if (ChB_ShowNTLimiting.Checked)
                            {
                                Graphics gg = this.CreateGraphics();
                                gg.DrawLines(Pens.Yellow, Sline);
                                gg.DrawLine(Pens.Yellow, new Point(A.X - crossize, A.Y), new Point(A.X + crossize, A.Y));
                                gg.DrawLine(Pens.Yellow, new Point(A.X, A.Y - crossize), new Point(A.X, A.Y + crossize));
                                gg.DrawLine(Pens.Yellow, new Point(B.X - crossize, B.Y), new Point(B.X + crossize, B.Y));
                                gg.DrawLine(Pens.Yellow, new Point(B.X, B.Y - crossize), new Point(B.X, B.Y + crossize));
                            }
                            // * * * * * * *
                            #endregion
                        }

                        alldist = FindMaxWidth(image, A, B);
                        Cursor.Position = alldist.S; //jednodussi postup pro hledani maxim
                        PlotDistances();
                        LBL_NTmean.Text = "NT mean: " + String.Format("{0:0.00}", PxToMm(alldist.meandistance_px)) + " mm = " + String.Format("{0:0.00}", alldist.meandistance_px) + " px";
                        LBL_NTvariance.Text = "NT variance: " + String.Format("{0:0.00}", PxToMm(alldist.variance_px)) + " mm";
                        LBL_NTSD.Text = "NT standard deviation: " + String.Format("{0:0.00}", Math.Sqrt(PxToMm(alldist.variance_px))) + " mm";
                        LBL_quality_if_inter.Text = "Quality: " + String.Format("{0:0.00}", (alldist.quality)) + " px = " + String.Format("{0:0.00}", PxToMm(alldist.quality)) + " mm";
                        LBL_NTmax.Text = "NT max: " + String.Format("{0:0.00}", PxToMm(alldist.maxdistance_px)) + " mm = " + String.Format("{0:0.00}", alldist.maxdistance_px) + " px";

                        LBL_info.Text = "Neleznete nejsirsi bod";
                        RB_SetNT.Checked = true;
                    }
                    else if (RB_SetNT.Checked)
                    {
                        #region comment
                        /*  
                    C = PointToClient(Cursor.Position);
                    RB_C.Text = "C " + C.ToString();
                    pointC.Location = (new Point(C.X - 8, C.Y - 10));
                    pointC.Visible = true;
                    pointC.Refresh();
                    
                    //g.DrawEllipse(Pens.Yellow, C.X - 3, C.Y - 3, 6, 6); //korekce Cby to bylo ve stredu
                    g.DrawLine(Pens.Blue, new Point(C.X - crossize, C.Y), new Point(C.X + crossize, C.Y));
                    g.DrawLine(Pens.Blue, new Point(C.X, C.Y - crossize), new Point(C.X, C.Y + crossize));
                 */
                        #endregion

                        Cpoint.Visible = false;
                        Dpoint.Visible = false;
                        //vykresleni ohrnaniceni NT
                        if (ChB_ShowNTLimiting.Checked)
                        {
                            Pen myPen = new Pen(System.Drawing.Color.Red, 1);
                            Graphics gg = this.CreateGraphics();
                            gg.DrawLines(myPen, alldist.C);
                            gg.DrawLines(Pens.Blue, alldist.Cinter);
                            gg.DrawLines(myPen, alldist.D);
                            gg.DrawLines(Pens.Blue, alldist.Dinter);
                          //  gg.DrawLines(Pens.Yellow, Sline);

                        }
                        g.DrawLine(Pens.Yellow, new Point(Ci.X - crossize, Ci.Y), new Point(Ci.X + crossize, Ci.Y));
                        g.DrawLine(Pens.Yellow, new Point(Ci.X, Ci.Y - crossize), new Point(Ci.X, Ci.Y + crossize));
                        g.DrawLine(Pens.Yellow, new Point(Di.X - crossize, Di.Y), new Point(Di.X + crossize, Di.Y));
                        g.DrawLine(Pens.Yellow, new Point(Di.X, Di.Y - crossize), new Point(Di.X, Di.Y + crossize));
                       
                        RB_SetNT.Checked = false;
                        LBL_DownRisk.Text = "Risk: " + String.Format("{0:0.00}", DownRisk_NT(TB_Age.Value, (double)TB_CRL.Value, PxToMm(NTdist_in_px(Ci, Di)))) + " %";
                        LBL_info.Text = "Vyberde moznost zadavani NT";
                       
                        //STATISTIKA
                        statistic_data.meanNT = PxToMm(alldist.meandistance_px);
                        statistic_data.meanNTpx = alldist.meandistance_px;
                        statistic_data.maxNT = PxToMm(alldist.maxdistance_px);
                        statistic_data.maxNTpx = alldist.maxdistance_px;
                        statistic_data.variance = alldist.variance_px;
                        statistic_data.standard_dev = Math.Sqrt(alldist.variance_px);

                        SetNT_sw = 0;
                        if (ChB_savestat.Checked)
                        BTN_savestat_Click(null, null);
                    }
                }
                #endregion
                #region ManNT
                else if (SetNT_sw == 3)
                {
                    if (RB_A.Checked)
                    {
                        //this.Refresh();
                        LBL_NTmean.Text = "NT mean: ";// +String.Format("{0:0.00}", alldist.meandistance) + " mm = " + String.Format("{0:0.00}", alldist.meandistance_px) + " px";
                        LBL_NTvariance.Text = "NT variance: "; 
                        LBL_NTSD.Text = "NT standard deviation: ";
                       
                        C = PointToClient(Cursor.Position);
                        RB_A.Text = "C " + C.ToString();

                        g.DrawLine(Pens.Yellow, new Point(C.X - crossize, C.Y), new Point(C.X + crossize, C.Y));
                        g.DrawLine(Pens.Yellow, new Point(C.X, C.Y - crossize), new Point(C.X, C.Y + crossize));

                        LBL_info.Text = "Zadejte bod D";
                        RB_B.Checked = true;
                    }
                    else if (RB_B.Checked)
                    {

                        D = PointToClient(Cursor.Position);
                        RB_B.Text = "D " + D.ToString();

                        g.DrawLine(Pens.Yellow, new Point(D.X - crossize, D.Y), new Point(D.X + crossize, D.Y));
                        g.DrawLine(Pens.Yellow, new Point(D.X, D.Y - crossize), new Point(D.X, D.Y + crossize));

                        LBL_info.Text = "Vyberde moznost zadavani NT";
                        RB_B.Checked = false;
                        //LBL_DownRisk.Text = "Risk: " + String.Format("{0:0.00}", DownRisk_NT(TB_Age.Value, (double)TB_CRL.Value, PxToMm(NTdist_in_px(C, D)))) + " %";
                        SetNT_sw = 0;
                    }
                }
                #endregion
                #region init test
                else if (SetNT_sw == 4) //initial test
                {
                     if (RB_A.Checked)
                     {
                      
                        A = PointToClient(Cursor.Position);
                        RB_A.Text = "A " + A.ToString();
                       
                        g.DrawLine(Pens.Blue, new Point(A.X - crossize, A.Y), new Point(A.X + crossize, A.Y));
                        g.DrawLine(Pens.Blue, new Point(A.X, A.Y - crossize), new Point(A.X, A.Y + crossize));

                        LBL_info.Text = "Zadejte bod B";
                        RB_B.Checked = true;
                     }
                     else if (RB_B.Checked)
                     {

                         B = PointToClient(Cursor.Position);
                         RB_B.Text = "B " + B.ToString();


                         g.DrawLine(Pens.Blue, new Point(B.X - crossize, B.Y), new Point(B.X + crossize, B.Y));
                         g.DrawLine(Pens.Blue, new Point(B.X, B.Y - crossize), new Point(B.X, B.Y + crossize));

                         SetNT_sw = -1;
                         RB_B.Checked = false;
                     }
                }
                #endregion
                magnifyingGlass1.Refresh();
            }
        }
        #endregion

        #region Moving Mouse
        private void Form1_MouseMove(object sender, MouseEventArgs e)
        {
            label1.Text = PointToClient(Cursor.Position).ToString();
          
                if ((RB_SetNT.Checked) & (OldMousePos != Cursor.Position))
                {
                    if (Form1.ModifierKeys == Keys.Shift)
                    {
                        if ((OldMousePos.X > Cursor.Position.X) & TB_shift.Value<60)
                        {
                           
                            TB_shift.Value += 5;
                        }
                        else if ((OldMousePos.X < Cursor.Position.X) & TB_shift.Value>10)
                        {
                           
                            TB_shift.Value -= 5;
                        }
                    }
                   
                        OldMousePos = Cursor.Position;
                        // pohyb kurzoru pouze po ose NT
                        Point n = new Point(B.Y - A.Y, A.X - B.X); //normalovy vektor
                        int mx = MousePosition.X;
                        int my = MousePosition.Y;
                        int q = -(n.X * A.X + n.Y * A.Y); //s=-sum(n.*a);
                        // Rovnice primky px+ry+q=0, kde n=[p r]
                        if (Math.Abs(n.X) < Math.Abs(n.Y)) //horizontalni osa
                            Cursor.Position = (new Point(mx, (Int16)(-1.0 / n.Y * (n.X * mx + q))));
                        else //vertikalni osa
                            Cursor.Position = (new Point((Int16)(-1.0 / n.X * (n.Y * my + q)), my));
                        //

                        magnifyingGlass1.Refresh();
                        pictureBox1.Refresh();
                        LBL_NTdistance.Refresh();
                        LBL_DownRisk.Refresh();

                        NTprofile NT = GetProfile(image, A, B, PointToClient(Cursor.Position));
                        Point[] m = GetNTMaxs(NT);

                    //dynamika obrazu v NT oblasti
                        int max1 = m[0].Y;
                        int max2 = m[1].Y;
                        int min = GetMinimum(NT.Profile,m[0].X, m[1].X);

                      //  LBL_DR1.Text = "DR: " + String.Format("{0:0.00}",(10 * Math.Log((double)(min+1) / (double)max1))) + " dB";
                      //  LBL_DR2.Text = "DR: " + String.Format("{0:0.00}",(10 * Math.Log((double)(min+1) / (double)max2))) + " dB";
                        LBL_DR1.Text = "DR: " + String.Format("{0:0.00}", max1-min) + " lev.";
                        LBL_DR2.Text = "DR: " + String.Format("{0:0.00}", max2-min) + " lev.";

                        statistic_data.dyn1_px = max1 - min;
                        statistic_data.dyn2_px = max2 - min;
                    //

                       C = new Point(NT.Line[m[0].X].X, NT.Line[m[0].X].Y);
                       D = new Point(NT.Line[m[1].X].X, NT.Line[m[1].X].Y);
                      int t=0;
                   
                      while (t < alldist.Cinter.Length)
                      {
                          if (alldist.Cinter[t].X == C.X)
                          {
                              Ci = alldist.Cinter[t];
                          }
                          if (alldist.Dinter[t].X == D.X)
                          {
                              Di = alldist.Dinter[t];
                          }
                          t++;
                      }
                      

                    //potreba dodelat zpetnou projekci kolme k ose NT
                    /*
                    int yc, yd, j;

                      j = PointToClient(Cursor.Position).X;
                           yc = 0; yd = 0;
                           for (int k = alldist.st; k >= 0; k--)
                           {
                               yc += (int)(alldist.rovc[k] * Math.Pow(j, k));
                               yd += (int)(alldist.rovd[k] * Math.Pow(j, k)); 
                            }
                            C =  new Point(j, yc);
                            D =  new Point(j, yd);

                    */
                        LBL_NTdistance.Text = "NT: " + String.Format("{0:0.00}", PxToMm(NTdist_in_px(Ci, Di))) + " mm = " + String.Format("{0:0.00}", NTdist_in_px(Ci, Di)) + " px";
                        LBL_DownRisk.Text = "Risk: " + String.Format("{0:0.00}", DownRisk_NT(TB_Age.Value, (double)TB_CRL.Value, PxToMm(NTdist_in_px(Ci, Di)))) + " %";
                    
                    //STATISTIKA
                    /*    statistic_data.maxNT = PxToMm(NTdist_in_px(Ci, Di));
                        statistic_data.maxNTpx = NTdist_in_px(Ci, Di);*/

                        double xscale = (double)(pictureBox1.Width) / NT.Profile.Length;
                        // double xscale = NT.Profile_in_float.Length/(2*(double)(pictureBox1.Width));


                        Point[] p = new Point[pictureBox1.Width];
                        for (int i = 0; i < p.Length; i++)
                        {
                            p[i] = new Point(i, 255 - (Int16)(NT.Profile[(Int16)((double)i / xscale)].Y)); //prevzorkovani
                            // p[i] = new Point(i, 255 - (Int16)(NT.Profile_in_float[1,(Int16)((double)i * xscale)])); //prevzorkovani
                        }

                        //vykreslovani bodu NT
                        Cpoint.Location = (new Point(Ci.X - 7, Ci.Y - 7));
                        Dpoint.Location = (new Point(Di.X - 7, Di.Y - 7));
                        Cpoint.Visible = true;
                        Dpoint.Visible = true;
                        Graphics g = pictureBox1.CreateGraphics();
                        g.DrawLines(Pens.White, p);
                        /*  g.DrawLine(Pens.Red, new Point((Int16)(m[0].X / xscale * 4), 255 - m[0].Y), new Point((Int16)(m[0].X / xscale*4), 255));
                          g.DrawLine(Pens.Red, new Point((Int16)(m[1].X / xscale*4), 255 - m[1].Y), new Point((Int16)(m[1].X / xscale*4), 255));
                          g.DrawEllipse(Pens.Red, (Int16)(m[0].X / xscale*4) - 5, 255 - m[0].Y - 5, 10, 10);
                          g.DrawEllipse(Pens.Red, (Int16)(m[1].X / xscale*4) - 5, 255 - m[1].Y - 5, 10, 10);
                       */
                        g.DrawLine(Pens.Red, new Point((Int16)(m[0].X * xscale), 255 - m[0].Y), new Point((Int16)(m[0].X * xscale), 255));
                        g.DrawLine(Pens.Red, new Point((Int16)(m[1].X * xscale), 255 - m[1].Y), new Point((Int16)(m[1].X * xscale), 255));
                        g.DrawEllipse(Pens.Red, (Int16)(m[0].X * xscale) - 5, 255 - m[0].Y - 5, 10, 10);
                        g.DrawEllipse(Pens.Red, (Int16)(m[1].X * xscale) - 5, 255 - m[1].Y - 5, 10, 10);
                    //interpolovane krivky
                        g.DrawLine(Pens.Blue, new Point((Int16)((C.Y - Ci.Y + m[0].X) * xscale), 0), new Point((Int16)((C.Y - Ci.Y + m[0].X) * xscale), 255));
                        g.DrawLine(Pens.Blue, new Point((Int16)((D.Y - Di.Y + m[1].X) * xscale), 0), new Point((Int16)((D.Y - Di.Y + m[1].X) * xscale), 255));
                        
                        //vykresleni ohrnaniceni NT
                        if (ChB_ShowNTLimiting.Checked)
                        {
                            Pen myPen = new Pen(System.Drawing.Color.Red,1);
                            Graphics gg = this.CreateGraphics();
                                gg.DrawLines(myPen, alldist.C);
                               gg.DrawLines(Pens.Blue, alldist.Cinter);
                                gg.DrawLines(myPen, alldist.D);
                                gg.DrawLines(Pens.Blue, alldist.Dinter);
                            
                        }
                    }
                else if ((SetNT_sw == 3)&(RB_B.Checked))
                {
                    LBL_NTdistance.Text = "NT max: " + String.Format("{0:0.00}", PxToMm(NTdist_in_px(C, PointToClient(Cursor.Position)))) + " mm = " + String.Format("{0:0.00}", NTdist_in_px(C, PointToClient(Cursor.Position))) + " px";
                    LBL_DownRisk.Text = "Risk: " + String.Format("{0:0.00}", DownRisk_NT(TB_Age.Value, (double)TB_CRL.Value, PxToMm(NTdist_in_px(C, PointToClient(Cursor.Position))))) + " %";
                }

                if (ChB_PROFILE.Checked)
                {
                    
                        double shift = 20;
                        double angle = TB_angle.Value*Math.PI/180; //otoceni o 90 aby se dala jednoduse pouzit fce GetProfile - prohozeni Sin a Cos
                        Point S = Cursor.Position;
                        Point X = new Point(S.X + (int)(shift * Math.Sin(angle)), S.Y + (int)(shift * Math.Cos(angle)));
                        Point Y = new Point(S.X - (int)(shift * Math.Sin(angle)), S.Y - (int)(shift * Math.Cos(angle)));


                        NTprofile PROFILE = GetProfile(image, X, Y, S);

                         X = new Point(S.X + (int)(shift * Math.Cos(angle)), S.Y + (int)(shift * Math.Sin(angle)));
                         Y = new Point(S.X - (int)(shift * Math.Cos(angle)), S.Y - (int)(shift * Math.Sin(angle)));
                        NTprofile PROFILE2 = GetProfile(image, X, Y, S);

                            double xscale = (double)(pictureBox1.Width) / PROFILE.Profile.Length;
                            //vykresleni
                            pictureBox1.Refresh();
                            Point[] p = new Point[pictureBox1.Width];
                            Point[] p2 = new Point[pictureBox1.Width];
                            for (int i = 0; i < p.Length; i++)
                            {
                                p[i] = new Point(i, 255 - (Int16)(PROFILE.Profile[(Int16)((double)i / xscale)].Y)); //prevzorkovani
                                p2[i] = new Point(i, 255 - (Int16)(PROFILE2.Profile[(Int16)((double)i / xscale)].Y)); //prevzorkovani
                            }
                            Graphics g = pictureBox1.CreateGraphics();
                            g.DrawLines(Pens.Yellow, p);
                            g.DrawLines(Pens.Red, p2);
                            g.DrawEllipse(Pens.White, p[(int)(p.Length / 2)].X - 5, p[(int)(p.Length / 2)].Y - 5, 10, 10);
                            
                        //g.DrawEllipse(Pens.Green, p2[(int)(p2.Length / 2)].X - 5, p2[(int)(p2.Length / 2)].Y - 5, 10, 10);

                    
                    }
            
         }
        #endregion

        #region Histogram
         Histogram GetHistogram(Bitmap image)
        {
        Histogram output;

            /*int LTx=140; //levy hodrni roh x-ova souradnice
              int LTy=90;*/
              int W = image.Width;
              int H = image.Height;


              BitmapData temp_b = image.LockBits(new Rectangle(0, 0, W, H), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);// PixelFormat.Format32bppArgb);
              System.IntPtr Scan0 = temp_b.Scan0;

             output.Values = new int[256];
        
             unsafe
             {
                 //resolve pointer 
                  byte* scan0 = (byte*)(void*)Scan0;

                for (int i = 275; i < W-255; i++) //1025
                 {
                     for (int j = 90; j < H-374; j++) //650
                     {

             /*     for (int i = 0; i < W ; i++)
                 {
                     for (int j = 0; j < H; j++)
                     {*/
                         //BGR  //index: (stride * y) + (x * 4);
                       output.Values[(int)(.114 * (scan0[*scan0 + CoordsToIndex(i, j, temp_b.Stride, temp_b.PixelFormat) + 0]) +
                                           .587 * (scan0[*scan0 + CoordsToIndex(i, j, temp_b.Stride, temp_b.PixelFormat) + 1]) +
                                           .299 * (scan0[*scan0 + CoordsToIndex(i, j, temp_b.Stride, temp_b.PixelFormat) + 2]))
                                           ]++;

                    //b//  output.Values[(int)(0.114 * image.GetPixel(i,j).B + 0.587 * image.GetPixel(i,j).G + 0.299 * image.GetPixel(i,j).R)]++;
                     }//for j
                 }//for i
             }//unsafe

               image.UnlockBits(temp_b);
             
             #region MassOfHist
                           
                    //Calculate Mass Center Of Histogram
                         
                         int[] vec = new int[output.Values.Length];
                         int[] vec0 = new int[output.Values.Length];
                         for (int i = 0; i < output.Values.Length; i++) { vec0[i] = i; }
                         double max = 1.79769e+308;
                         int t = 0;
                       for (int m = 0; m<output.Values.Length; m++)
                       {
                        // distance from com
                        for (int i = 0; i < output.Values.Length; i++) { vec[i] = Math.Abs(m - vec0[i]); }
                      
                           // divide histgram to two classes 
                        int[] classa = new int[m];
                        int[] veca = new int[m];
                        double vala=0;
                           for (int i = 0; i<m; i++)
                           {
                            classa[i]=output.Values[i];
                            veca[i]=vec[i];
                            vala+=classa[i]*veca[i];
                           }

                        int[] classb = new int[output.Values.Length-m];
                        int[] vecb = new int[output.Values.Length-m];
                        double valb=0;
                           for (int i = 0; i<output.Values.Length-m; i++)
                           {
                            classb[i]=output.Values[m+i];
                            vecb[i]=vec[m+i];
                            valb+=classb[i]*vecb[i];
                           }

                        // calculate difference of two moments
                     
                           if (Math.Abs(vala - valb) < max)
                           {
                               max = Math.Abs(vala - valb);
                               t = m;
                           }
                       }
                   
                       output.CenterOfMass = 3*t; //hodnota 3 byla zjistena emipricky

                       
             #endregion
        /*
             int temp=0;
           output.CenterOfMass = 0;
           //while (temp < ((H-180) * (W-280)) / 2)
           while (temp < ((1025-275) * (650-90)) / 2)
           {
               temp += output.Values[output.CenterOfMass++];
           } */

         return output;
             
    }
             
         private void PlotHistogram(Histogram hist)
        {
             int max = 0;
             for (int k = 0; k < hist.Values.Length; k++)
             {
                 if (max < hist.Values[k])
                 {
                     max = hist.Values[k];
                 }
             }
             max = max / 2000;

             Graphics g = histogram.CreateGraphics();
             for (int k = 0; k < hist.Values.Length; k++)
             {
                 g.DrawLine(Pens.Red, new Point(k, (int)(100 - hist.Values[k] / max)), new Point(k, 100));
             }
            g.DrawLine(Pens.White, new Point(hist.CenterOfMass, 0), new Point(hist.CenterOfMass, 100));
         }


         private void TB_Tolerance_Scroll(object sender, EventArgs e)
         {
             Hist.CenterOfMass = (int)TB_Tolerance.Value;
             LBL_toler.Text = (Hist.CenterOfMass).ToString();
         }

         #endregion

        #region Setting Scale
        private Point[] SetAutoScale(Bitmap image)
        {
            int shift = 0;
            int X = 125;// 255;
            int Y1 = 400;
            int Y2 = 400;
            Point[] o = new Point[2];
            // 1 pokus
            S1.Text = "<--- S";
            S2.Text = "<--- S";
            while (!((Math.Abs(Y2 - Y1) < 250) & (Math.Abs(Y2 - Y1) > 20)) & (shift < 30))
            {
                Y1=Y1 - shift;
                while ((image.GetPixel(X, Y1).R <= 10 & image.GetPixel(X, Y1).G <= 10 & image.GetPixel(X, Y1).B <= 10) & Y1 > 1)
                {
                    Y1--;
                }
                Y1--;
                Y2 = Y2 - shift;
                while ((image.GetPixel(X, Y2).R <= 10 & image.GetPixel(X, Y2).G <= 10 & image.GetPixel(X, Y2).B <= 10) & Y2 < image.Height - 1)
                {
                    Y2++;
                }
                Y2++;
      
                o[0] = new Point(X + 0, Y1-- - S1.Height / 2);
                o[1] = new Point(X + 0, Y2++ - S2.Height / 2);
                shift += 10;
            }

            if (shift == 30) //2pokus
            {
                shift = 0;
                X = 255;
                Y1 = 400;
                Y2 = 400;
                S1.Text = "S --->";
                S2.Text = "S --->";
                while (!((Math.Abs(Y2 - Y1) < 250) & (Math.Abs(Y2 - Y1) > 20)) & (shift < 30))
                {
                    Y1 = Y1 - shift;
                    while ((image.GetPixel(X, Y1).R <= 10 & image.GetPixel(X, Y1).G <= 10 & image.GetPixel(X, Y1).B <= 10) & Y1 > 1)
                    {
                        Y1--;
                    }
                    Y1--;
                    Y2 = Y2 - shift;
                    while ((image.GetPixel(X, Y2).R <= 10 & image.GetPixel(X, Y2).G <= 10 & image.GetPixel(X, Y2).B <= 10) & Y2 < image.Height - 1)
                    {
                        Y2++;
                    }
                    Y2++;

                    o[0] = new Point(X - S1.Width - 2, Y1-- - S1.Height / 2);
                    o[1] = new Point(X - S2.Width - 2, Y2++ - S2.Height / 2);
                   

                    shift += 10;
                }
            }

            //nezdarilo se
            if (shift==30)
            {
                o[0] = new Point(X - S1.Width - 2, 410);
                o[1] = new Point(X - S2.Width - 2, 510);
            }

            
            return o;
        }



        private void S1_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
               // int d = Math.Abs(PointToClient(Cursor.Position).Y - S1.Location.Y);
                S1.Location = new Point(S1.Location.X, PointToClient(Cursor.Position).Y - 8);
                scale = SetScale(S1.Location, S2.Location);
                LBL_scale.Text = "Scale: " + scale + " px/cm";
                if (C.X != 0)
                {
                    LBL_NTdistance.Text = "NT: " + String.Format("{0:0.00}", PxToMm(NTdist_in_px(Ci, Di))) + " mm";
                    LBL_DownRisk.Text = "Risk: " + String.Format("{0:0.00}", DownRisk_NT(TB_Age.Value, (double)TB_CRL.Value, PxToMm(NTdist_in_px(Ci, Di)))) + " %";
                       
                }
            }
        }

        private void S2_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                //int d = Math.Abs(PointToClient(Cursor.Position).Y - S2.Location.Y);
                S2.Location = new Point(S2.Location.X, PointToClient(Cursor.Position).Y - 8);
                scale = SetScale(S1.Location, S2.Location);
                LBL_scale.Text = "Scale: " + scale + " px/cm";

                if (C.X != 0)
                {
                    LBL_NTdistance.Text = "NT: " + String.Format("{0:0.00}", PxToMm(NTdist_in_px(Ci, Di))) + " mm";
                    LBL_DownRisk.Text = "Risk: " + String.Format("{0:0.00}", DownRisk_NT(TB_Age.Value, (double)TB_CRL.Value, PxToMm(NTdist_in_px(Ci, Di)))) + " %";
                       
                }
            }
        }

        #endregion

#region LUPA
        #region MagnifyGlass_FCN
        private void MovingGlass_VisibleChanged(object sender, EventArgs e)
        {
            // Make this not the top window if the moving glass is shown because it will hide the glass display otherwise
            TopMost = !magnifyingGlass1.MovingGlass.Visible;
        }

        private void MagnifyingGlass_Click(object sender, EventArgs e)
        {
            // Select the color trough the moving glass
            SelectColor();
        }

        private void magnifyingGlass1_DisplayUpdated(MagnifyingGlass sender)
        {
            // Update the current color preview panels background color
          //  panel1.BackColor = magnifyingGlass1.PixelColor;
        }

        private void GUI_Deactivate(object sender, EventArgs e)
        {
            // Select the current color if the form lost the focus
            if (!magnifyingGlass1.MovingGlass.Visible)
            {
                SelectColor();
            }
        }

        private void SelectColor()
        {
            // Show the selected color and properties
      /*      panel2.BackColor = panel1.BackColor;
            label1.Text = "R: " + panel2.BackColor.R.ToString();
            label2.Text = "G: " + panel2.BackColor.G.ToString();
            label3.Text = "B: " + panel2.BackColor.B.ToString();
            // Try to activate the form after selecting a color because we lost the focus for sure
            Activate();*/
        }

        private void MagnifyingGlass_AfterMakingScreenshot(object sender)
        {
            // Show this again after the screenshot has been taken
            Show();
        }

        private void MagnifyingGlass_BeforeMakingScreenshot(object sender)
        {
            // Hide this before the moving glass will take thescreenshot for working with it as screen image
            Hide();
        }
        #endregion

        #region Zoom MagnifyGlass
        private void BTN_ZomIn_Click(object sender, EventArgs e)
        {
            magnifyingGlass1.PixelSize = magnifyingGlass1.PixelSize*3/2;
            if (magnifyingGlass1.PixelSize > 5)
                BTN_ZoomIn.Enabled = false;

            BTN_ZoomOut.Enabled = true;
           
        }

        private void BTN_ZoomOut_Click(object sender, EventArgs e)
        {
            magnifyingGlass1.PixelSize = magnifyingGlass1.PixelSize*2/3;
            if (magnifyingGlass1.PixelSize < 4)
                BTN_ZoomOut.Enabled = false;

            BTN_ZoomIn.Enabled = true;
        }

        #endregion

        #region Move MagnifyGlass
        private void magnifyingGlass1_MouseUp(object sender, MouseEventArgs e)
        {
            Point CurPos = new Point(((Cursor.Position)).X - diff.X,
                                     ((Cursor.Position)).Y - diff.Y);

            magnifyingGlass1.Location = PointToClient(CurPos);
        } 
        
        private void magnifyingGlass1_MouseDown(object sender, MouseEventArgs e)
        { 
            diff.X = (this.PointToClient(Cursor.Position)).X - magnifyingGlass1.Location.X;
            diff.Y = (this.PointToClient(Cursor.Position)).Y - magnifyingGlass1.Location.Y;
        }
        #endregion
 #endregion

#region Help fcs

         private void SetBackgroundImage(Bitmap image)
        {
            try
            {
                this.BackgroundImage = image;

                if (image.Height > 450) //nastaveni scale u mensich obrazku se nepravadi aby nedochazelo k err
                {
                    Point[] S1S2 = SetAutoScale(image);
                    S1.Location = S1S2[0];
                    S2.Location = S1S2[1];
                    scale = SetScale(S1.Location, S2.Location);
                    LBL_scale.Text = "Scale: " + scale + " px/cm";

                    //STATISTIKA
                    statistic_data.scale = scale;
                }

                Hist = GetHistogram(image);

                TB_Tolerance.Value = Hist.CenterOfMass;
                LBL_toler.Text = Hist.CenterOfMass.ToString();
            }
            catch (Exception ex)
            {

            }
        }

         private void ResetPoints()
        {
            //nulovani bodu ABCD pro vypocet profilu
            A = new Point(0, 0);
            B = new Point(0, 0);
            C = new Point(0, 0);
            D = new Point(0, 0);
            Ci = new Point(0, 0);
            Di = new Point(0, 0);
               LBL_NTdistance.Text = "NT: ";
               LBL_NTmean.Text = "NT mean: ";
               LBL_NTmax.Text = "NT max: ";
               LBL_NTvariance.Text = "NT variance: ";
               LBL_NTSD.Text = "NT standard deviation: ";
               LBL_quality_if_inter.Text = "Quality: ";
            //skryti bodu ABDC
            this.Refresh();
        }

         private NTprofile GetProfile(Bitmap InputIm, Point a, Point b, Point s)
         {
             int shift = (int)TB_shift.Value;
             
             NTprofile output;

                 Point n = new Point(b.X - a.X, b.Y - a.Y); //kolmy vektor ka bodum AB
                 int q = -(n.X*s.X + n.Y*s.Y); //s=-sum(n.*a);
                 // Rovnice primky px+ry+q=0, kde n=[p r]
                
                 //Odkomentovat kdyz nezalezi na poradi
                 if (Math.Abs(n.X) < Math.Abs(n.Y))
                 {
                     int dist =  1 + 2*shift;
                     output.Line = new Point[dist];
                     output.Profile = new Point[dist];
                     int[] temp = new int[dist];
                     int j = 0;
                    
                         for (int i = s.X - shift; i <= s.X + shift; i++)
                         {
                             temp[j++] = i;
                         }

                     for (int i = 0; i < temp.Length; i++)
                     {
                         output.Line[i] = new Point(temp[i], (Int16)(-1.0 / n.Y * (n.X * temp[i] + q)));
                         if ((output.Line[i].X >= 0 & output.Line[i].Y >= 0) & (output.Line[i].X < InputIm.Width & output.Line[i].Y < InputIm.Height))
                         output.Profile[i] = new Point(i, (Int16)(.299 * (InputIm.GetPixel(output.Line[i].X, output.Line[i].Y).R)
                                                            + .587 * (InputIm.GetPixel(output.Line[i].X, output.Line[i].Y).G)
                                                            + .114 * (InputIm.GetPixel(output.Line[i].X, output.Line[i].Y).B)
                                                          ));
                         
                             

                     }
                 }
                 else
                 {   
                     int dist = 1 + 2 * shift;
                     output.Line = new Point[dist];
                     output.Profile = new Point[dist];
                     int[] temp = new int[dist];
                     int j = 0;

                    
                         for (int i = s.Y + shift; i >= s.Y - shift; i--)
                         {
                             temp[j++] = i;
                         }
                    
                     for (int i = 0; i < temp.Length; i++)
                     {
                         output.Line[i] = new Point((Int16)((-1.0 / n.X) * (n.Y * temp[i] + q)), temp[i]);
                        if ((output.Line[i].X >= 0 & output.Line[i].Y >= 0) & (output.Line[i].X < InputIm.Width & output.Line[i].Y < InputIm.Height))
                         output.Profile[i] = new Point(i, (Int16)(.299 * (InputIm.GetPixel(output.Line[i].X, output.Line[i].Y).R)
                                                            + .587 * (InputIm.GetPixel(output.Line[i].X, output.Line[i].Y).G)
                                                            + .114 * (InputIm.GetPixel(output.Line[i].X, output.Line[i].Y).B)
                                                          ));


                     }
                  }

            //kdyz je pouzite splinove rozpoznavani maxim
                 float[,] xxx=new float[1,1];
                 output.Profile_in_float = xxx; //Spline(output.Profile, 0);

            return output;
         }

         private Point GetNTMin(Point[] Profile)
         {
             //byte max = 0;
             Point min = new Point(255, 255);

             for (int i = Profile.Length / 2 - 10; i <= Profile.Length / 2 + 10; i++)
             {
                 if (Profile[i].Y < min.Y)
                 {
                     min = Profile[i];
                     
                 }
             }

            return min;

         }

         private int GetMinimum(Point[] Profile, int max1_index, int max2_index)
         {
             int output=255;
             for (int i=max1_index; i<=max2_index; i++)
             {
                 if (Profile[i].Y<output)
                 {
                     output=Profile[i].Y;
                 }
             }
             return output;
         }

         private Point[] GetNTMaxs(NTprofile NT)
         {
             #region old
             /*byte max = 0;
             Point[] max = { new Point(0, 0), new Point(0, 0) };

             for (int i = NT.Profile.Length / 2; i >= 0; i--)
             {
                 if (NT.Profile[i].Y > max[0].Y)
                 {
                     max[0] = NT.Profile[i];

                 }
             }

             for (int i = NT.Profile.Length / 2; i < NT.Profile.Length; i++)
             {
                 if (NT.Profile[i].Y > max[1].Y)
                 {
                     max[1] = NT.Profile[i];

                 }
             }

             return max;*///
             #endregion

             #region NEW_onlyProfile
             int i;
              int v_max1 = 0;
             int v_max2 = 0;
             int v_min = 256;

            for (i = 0; i < NT.Profile.Length; i++)
             {
                 if (v_max1 < NT.Profile[i].Y & i < NT.Profile.Length / 2)
                 {
                     v_max1 = NT.Profile[i].Y;
                 }
                 else if (v_max2 < NT.Profile[i].Y & i > NT.Profile.Length / 2)
                     v_max2 = NT.Profile[i].Y;

                 if ((i > (NT.Profile.Length / 2) - 20 )&( i < (NT.Profile.Length / 2)+20))
                 { 
                 if (v_min > NT.Profile[i].Y)
                     v_min = NT.Profile[i].Y;
                 }
             }

             //int t = ((NT.Profile_in_float.Length) / 2) / NT.Profile.Length;

             Point[] max = { new Point(0, 0), new Point(0, 0) };
             i = NT.Profile.Length / 2 - 3;
             while ((i > 3)
                        &
                        !((//NT.Profile[i + 2].Y <= NT.Profile[i + 1].Y &
                          NT.Profile[i + 1].Y <= NT.Profile[i].Y &
                          NT.Profile[i].Y >= NT.Profile[i - 1].Y)// &
                          //NT.Profile[i - 1].Y >= NT.Profile[i - 2].Y)  
                         &
                         (NT.Profile[i].Y > v_min + (2*(v_max1 - v_min) / 4)))
                    )
             {
                 i--;
             }
             max[0] = NT.Profile[i];

             i = NT.Profile.Length / 2 + 3;
             while ((i < NT.Profile.Length - 3)
                        &
                        !((//NT.Profile[i - 2].Y <= NT.Profile[i - 1].Y &
                          NT.Profile[i - 1].Y <= NT.Profile[i].Y &
                          NT.Profile[i].Y >= NT.Profile[i + 1].Y)// &
                         // NT.Profile[i + 1].Y >= NT.Profile[i + 2].Y)
                         &
                         (NT.Profile[i].Y > v_min+(2*(v_max2-v_min) / 4)))
                   )
             {
                 i++;
             }
             max[1] = NT.Profile[i];

             return max;
             #endregion
             
              #region NEW
            /*
             int i;
             int v_max1 = 0;
             int v_max2 = 0;
             for (i = 0; i < NT.Profile.Length; i++)
             {
                 if (v_max1 < NT.Profile[i].Y & i<NT.Profile.Length/2)
                     v_max1 = NT.Profile[i].Y;
                 else if (v_max2 < NT.Profile[i].Y & i>NT.Profile.Length/2)
                     v_max2 = NT.Profile[i].Y;
             }
             
             int t = ((NT.Profile_in_float.Length)/2) / NT.Profile.Length;
             
             Point[] max = { new Point(0, 0), new Point(0, 0) };
             i = NT.Profile_in_float.Length / 4 - 3;
             while (    (i > 2) 
                        &
                        !(//NT.Profile_in_float[1, i + 2] < NT.Profile_in_float[1, i + 1] &
                          NT.Profile_in_float[1, i + 1] < NT.Profile_in_float[1, i] &
                          NT.Profile_in_float[1, i] > NT.Profile_in_float[1, i - 1])// &
                         // NT.Profile_in_float[1, i - 1] > NT.Profile_in_float[1, i - 2])  
                        |
                        !(NT.Profile_in_float[1, i] > v_max1/2)
                    )

                             {
                                 i--;
                             }
             max[0] = NT.Profile[(int)(i / t)];

             i = NT.Profile_in_float.Length / 4 + 3;
             while (    (i < NT.Profile_in_float.Length/2-2) 
                        &
                        !(//NT.Profile_in_float[1, i - 2] < NT.Profile_in_float[1, i - 1] &
                          NT.Profile_in_float[1, i - 1] < NT.Profile_in_float[1, i] &
                          NT.Profile_in_float[1, i] > NT.Profile_in_float[1, i + 1])// &
                        //  NT.Profile_in_float[1, i + 1] > NT.Profile_in_float[1, i + 2])
                        |
                        !(NT.Profile_in_float[1, i] > v_max2/2)
                   )

                             {
                                 i++;
                             }
             max[1] = NT.Profile[(int)(i / t)];

             return max;
            */
             #endregion
             
         }

         private void solveTridiag(float[] sub, float[] diag, float[] sup, ref float[] b, int n)
         {
             /*                  solve linear system with tridiagonal n by n matrix a
                                 using Gaussian elimination *without* pivoting
                                 where   a(i,i-1) = sub[i]  for 2<=i<=n
                                         a(i,i)   = diag[i] for 1<=i<=n
                                         a(i,i+1) = sup[i]  for 1<=i<=n-1
                                 (the values sub[1], sup[n] are ignored)
                                 right hand side vector b[1:n] is overwritten with solution 
                                 NOTE: 1...n is used in all arrays, 0 is unused */
             int i;
             /*                  factorization and forward substitution */
             for (i = 2; i <= n; i++)
             {
                 sub[i] = sub[i] / diag[i - 1];
                 diag[i] = diag[i] - sub[i] * sup[i - 1];
                 b[i] = b[i] - sub[i] * b[i - 1];
             }
             b[n] = b[n] / diag[n];
             for (i = n - 1; i >= 1; i--)
             {
                 b[i] = (b[i] - sup[i] * b[i + 1]) / diag[i];
             }
         }

         private float[,] Spline(Point[] Profile, int precision)
        {
            int np = Profile.Length; //points.Count;           // number of points
            float[] yCoords = new float[np];        // Newton form coefficients
            float[] xCoords = new float[np];        // x-coordinates of nodes
            float y;
            float x;
            float oldy = 0;
            float oldx = 0;

                 int npp = np * precision;          // number of points used for drawing
                 float[,] output = new float[2,npp];
 
                 if (np > 0)
                 {
                     // draw the control points
                     for (int i = 0; i < np; i++)
                     {
                         Point p = Profile[i];
                         xCoords[i] = p.X;
                         yCoords[i] = p.Y;
                     //  g.DrawRectangle(pointsPen, p.x - p.PT_SIZE, p.y - p.PT_SIZE, p.PT_SIZE * 2, p.PT_SIZE * 2);

                     }
                    //
#region POLY - coment
                     /*
                             // use divided difference algorithm to compute Newton form coefficients
                             for (int k = 1; k <= np - 1; k++)
                             {
                                 for (int i = 0; i <= np - 1 - k; i++)
                                 {
                                     yCoords[i] = (yCoords[i + 1] - yCoords[i]) / (xCoords[i + k] - xCoords[i]);
                                 }
                             }

                             // for equidistant points along x-axis evaluate polynomial and draw line
                             float dt = ((float)this.graphPanel.Width - 1) / npp;
                             for (int k = 0; k <= npp; k++)
                             {
                                 x = k * dt;
                                 // evaluate polynomial at t
                                 y = yCoords[0];
                                 for (int i = 1; i <= np - 1; i++)
                                 {
                                     y = y * (x - xCoords[i]) + yCoords[i];
                                 }
                                 // draw line
                                 try
                                 {
                                     g.DrawLine(linePen, (int)oldx, (int)oldy, (int)x, (int)y);
                                 }
                                 catch (Exception ex)
                                 {
                                     Console.WriteLine(ex.Message + " x1={0} y1={1} x2={2} y2={3}", oldx, oldy, x, y);
                                 }
                                 oldx = x;
                                 oldy = y;
                             }*/
#endregion
                         
                             if (np > 1)
                             {
                                 float[] a = new float[np];
                                 float x1;
                                 float x2;
                                 float[] h = new float[np];
                                 for (int i = 1; i <= np - 1; i++)
                                 {
                                     h[i] = xCoords[i] - xCoords[i - 1];
                                 }
                                 if (np > 2)
                                 {
                                     float[] sub = new float[np - 1];
                                     float[] diag = new float[np - 1];
                                     float[] sup = new float[np - 1];

                                     for (int i = 1; i <= np - 2; i++)
                                     {
                                         diag[i] = (h[i] + h[i + 1]) / 3;
                                         sup[i] = h[i + 1] / 6;
                                         sub[i] = h[i] / 6;
                                         a[i] = (yCoords[i + 1] - yCoords[i]) / h[i + 1] - (yCoords[i] - yCoords[i - 1]) / h[i];
                                     }
                                     solveTridiag(sub, diag, sup, ref a, np - 2);
                                 }
                                 // note that a[0]=a[np-1]=0
                                 // draw

                                 oldx = xCoords[0];
                                 oldy = yCoords[0];
                           
                                 int k = 0;
                                 for (int i = 1; i <= np - 1; i++)
                                 {   // loop over intervals between nodes
                                     for (int j = 1; j <= precision; j++)
                                     {
                                         x1 = (h[i] * j) / precision;
                                         x2 = h[i] - x1;
                                         y = ((-a[i - 1] / 6 * (x2 + h[i]) * x1 + yCoords[i - 1]) * x2 +
                                             (-a[i] / 6 * (x1 + h[i]) * x2 + yCoords[i]) * x1) / h[i];
                                         x = xCoords[i - 1] + x1;

                                         output[0,k] = x;
                                         output[1,k] = y;
                                         k++;
                                        
                                         oldx = x;
                                         oldy = y;
                                     }
                                 }
                             }
                            
                     }

                 return output;
                 }

         private void Dpoint_MouseDown(object sender, MouseEventArgs e)
         {
             Form1_MouseDown(sender, e);
         }

         private void Cpoint_MouseDown(object sender, MouseEventArgs e)
         {
             Form1_MouseDown(sender, e);
         }
  
         double SetScale(Point S1, Point S2) //return count of pixel in 1cm
         {
             return Math.Abs(S1.Y - S2.Y); ;
         }

         double NTdistance(Point C, Point D, double scale) //return NT distance in mm
         {
           //  scale = 10;
             double NTpx = Math.Sqrt(((D.X - C.X) * (D.X - C.X)) + ((D.Y - C.Y) * (D.Y - C.Y)));
             return ((NTpx / scale) * 10); //NT in mm
         }

         double NTdist_in_px(Point C, Point D) //return NT distance in mm
         {
             double NTpx;
             return NTpx = Math.Sqrt(((D.X - C.X) * (D.X - C.X)) + ((D.Y - C.Y) * (D.Y - C.Y)));
         }

         int CoordsToIndex(int x, int y, int stride, PixelFormat format)
         {
             int shift = 1; //Format8BppIndexed

             if ((format == PixelFormat.Format24bppRgb) | (format == PixelFormat.Format32bppRgb)) //PixelFormat.Format32bppRgb ???
                 shift = 3;
             else if ((format == PixelFormat.Format32bppPArgb)|(format == PixelFormat.Format32bppArgb))
                 shift = 4;
            

             return (stride * y) + (x * shift);
         }

        //Rotate image
          private Bitmap rotateImage(Bitmap b, float angle, Point o)
          {
              //create a new empty bitmap to hold rotated image
              Bitmap returnBitmap = new Bitmap(b.Width, b.Height);
              //make a graphics object from the empty bitmap
              Graphics g = Graphics.FromImage(returnBitmap);
              //move rotation point to center of image
              g.TranslateTransform((float)o.X, (float)o.Y);
              //rotate
              g.RotateTransform(angle);
              //move image back
              g.TranslateTransform(-(float)o.X, -(float)o.Y);
              //draw passed in image onto graphics object
              g.DrawImage(b, new Point(0, 0));
              return returnBitmap;
          }

          private NTdistances FindMaxWidth(Bitmap image, Point A, Point B)
        {
                                //nalezeni nesirsiho mista
                        Point S_temp;
                        int j;                         

                        #region nastaveni poc.bodu (nazavislost poradi zadani bodu AB)
                        int startindex;
                        int stopindex;
                        if (Math.Abs(B.Y - A.Y) < Math.Abs(A.X - B.X))
                        {
                            if (A.X <= B.X)
                            {
                                startindex = A.X;
                                stopindex = B.X;
                            }
                            else
                            {
                                startindex = B.X;
                                stopindex = A.X;
                            }
                        }
                        else
                        {
                            if (A.Y <= B.Y)
                            {
                                startindex = A.Y;
                                stopindex = B.Y;
                            }
                            else
                            {
                                startindex = B.Y;
                                stopindex = A.Y;
                            }
                        }
                        #endregion
                        NTdistances output;// = new NTdistances();
                        output.distances_px = new double[stopindex-startindex+1];
                        output.C = new Point[stopindex - startindex + 1];
                        output.Cinter = new Point[stopindex - startindex + 1];
                        output.D = new Point[stopindex - startindex + 1];
                        output.Dinter = new Point[stopindex - startindex + 1];          
                        output.S = new Point(0,0);
                        output.maxdistance_px = 0;
                        output.variance_px = 0;
                        output.meandistance_px = 0;
                        output.maxdistance_px = 0;
                        output.meandistance_px = 0;
                        output.quality = 0;
                        double[] no_inter_dist = new double[stopindex - startindex + 1];

                        for (int i = startindex; i <= stopindex; i++)
                        {
                            //Graphics g = this.CreateGraphics();
                            // pohyb kurzoru pouze po ose NT
                            Point n = new Point(B.Y - A.Y, A.X - B.X); //normalovy vektor
                            int mx = i;
                            int my = i;
                            int q = -(n.X * A.X + n.Y * A.Y); //s=-sum(n.*a);
                            // Rovnice primky px+ry+q=0, kde n=[p r]
                            if (Math.Abs(n.X) < Math.Abs(n.Y)) //horizontalni osa
                                S_temp = (new Point(mx, (Int16)(-1.0 / n.Y * (n.X * mx + q))));
                            else //vertikalni osa
                                S_temp = (new Point((Int16)(-1.0 / n.X * (n.Y * my + q)), my));
                            //

                            NTprofile NT = GetProfile(image, A, B, S_temp);
                            Point[] m = GetNTMaxs(NT);

                            C = new Point(NT.Line[m[0].X].X, NT.Line[m[0].X].Y);
                            D = new Point(NT.Line[m[1].X].X, NT.Line[m[1].X].Y);

                            j = i - startindex;
                            output.C[j] = C;
                            output.D[j] = D;
                        }
                            #region Comment
                            /*
                            output.distances[j] = NTdistance(C, D, scale);
                            output.distances_px[j] = NTdist_in_px(C, D);
                            output.meandistance += output.distances[j];
                            output.meandistance_px += output.distances_px[j];
                            //vypocet rozptylu
                            if (NTdistance(C, D, scale) > output.maxdistance)
                            {
                                output.maxdistance=NTdistance(C, D, scale);
                                output.maxdistance_px = NTdist_in_px(C,D);
                               output.S = S_temp;
                            }

                        }
              //pomocne vypocty 
                        output.meandistance = output.meandistance / output.distances.Length;
                        output.meandistance_px = output.meandistance_px / output.distances_px.Length; //?
                        output.variance=0;
                    //  StreamWriter t = new StreamWriter(Directory.GetCurrentDirectory() + @"\paths.bosz", false);
                        for (int i=0;i<output.distances_px.Length;i++)
                        {
                            output.variance += (output.distances_px[i] - output.meandistance_px) * (output.distances_px[i] - output.meandistance_px); 
                        } 
                    //t.Close();
                        output.variance = output.variance/output.distances_px.Length;
              //
                            */
                        #endregion

              //vse pro osu NT "rovnobeznou" s osu X
                       int stupen = 2;
                       double[] c = MNK(output.C, stupen);
                       double[] d = MNK(output.D, stupen);
                       int yc, yd;

                       for (int i = startindex; i <= stopindex; i++)
                       {
                           j = i - startindex;
                           yc = 0; yd = 0;
                            for (int k=stupen;k>=0;k--)
                           {
                               yc += (int)(c[k] * Math.Pow(i, k));
                               yd += (int)(d[k] * Math.Pow(i, k)); 
                            }
                            output.Cinter[j] = new Point(output.C[j].X, yc);
                            output.Dinter[j] = new Point(output.D[j].X, yd);

                           //////////////////////////////////
                           //kvalita interpolace
                           output.quality+=Math.Abs(NTdist_in_px(output.C[j], output.D[j]) - NTdist_in_px(output.Cinter[j], output.Dinter[j]));

                                
                           //////////////////////////////////
                            no_inter_dist[j]=NTdist_in_px(output.C[j], output.D[j]);
                            output.distances_px[j] = NTdist_in_px(output.Cinter[j], output.Dinter[j]);
                            output.meandistance_px += output.distances_px[j];
                            //vypocet maxima
                            if ((NTdist_in_px(output.Cinter[j], output.Dinter[j]) > output.maxdistance_px) & 
                                j>(int)(0.1*output.distances_px.Length) &
                                j<(int)(0.9*output.distances_px.Length) )
                            {
                                output.maxdistance_px = NTdist_in_px(output.Cinter[j], output.Dinter[j]);
                                output.S = new Point((int)(output.Cinter[j].X), (int)(output.Cinter[j].Y));
                              //  output.S = new Point((int)(output.Cinter[j].X - (output.Cinter[j].X - output.Dinter[j].X)),
                              //      (int)(output.Cinter[j].Y - (output.Cinter[j].Y - output.Dinter[j].Y)));
                            }
                        }
              
                        output.meandistance_px = output.meandistance_px / output.distances_px.Length;

                         //presun kurzoru na misto stredni hodnoty
                       /* j=0;
                        while ((output.meandistance_px >= output.distances_px[j] + 1 | output.meandistance_px <= output.distances_px[j] - 1) & j < output.distances_px.Length - 1)
                        {j++;}

                        output.S = new Point((int)(output.Cinter[j].X - (output.Cinter[j].X - output.Dinter[j].X)),
                                              (int)(output.Cinter[j].Y - (output.Cinter[j].Y - output.Dinter[j].Y)));
                       */
                       //pomocne vypocty 
                        
                        
                        for (int i = 0; i < output.distances_px.Length; i++)
                        {
                            output.variance_px += (output.distances_px[i] - output.meandistance_px) * (output.distances_px[i] - output.meandistance_px);
                        }
                        output.quality = output.quality / output.distances_px.Length;
                        output.variance_px = output.variance_px / output.distances_px.Length;
                            output.rovc = c;
                            output.rovd = d;
                            output.st = stupen;
                        return output;
            }

          private double PxToMm(double px)
          {
              double mm = (px/ scale) * 10 ;

              return mm;
          }

          public double[] LineFit(Point[] Data)
          {

              int I = 0;
              double SumX = 0;
              double SumY = 0;
              double SumX2 = 0;
              double SumXY = 0;
              double D = 0;



              for (I = 0; I < Data.Length; I++)
              {

                  SumX += Data[I].X;
                  SumY += Data[I].Y;
                  SumX2 += Data[I].X * Data[I].X;
                  SumXY += Data[I].X * Data[I].Y;
              }

              D = Data.Length * SumX2 - SumX * SumX;

              Double[] outPut = new double[2];
              outPut[0] = (SumY * SumX2 - SumXY * SumX) / D; //Intercept +b
              outPut[1] = (Data.Length * SumXY - SumY * SumX) / D; //Slope ax

              return outPut;
          }

          double[] MNK(Point[] p, int n) //n...stupen
          {
              int m = p.Length-1;
              
              double [] x = new double[p.Length];

              double [] y = new double[p.Length];


              double [] a = new double[n+1];

              double[] t = new double[10];

              double[] s = new double[20];

              double[,] sw = new double[10, 11];

              int i, j, k;

              double r;

              for (i = 0; i < p.Length; i++)
              {
                  x[i] = (double)(p[i].X);
                  y[i] = (double)(p[i].Y);
              }

              for (i = 0; i <= n; i++)
              {

                  t[i] = 0.0;

                  for (j = 0; j <= m; j++)

                      if (i == 0) t[i] += y[j];

                      else if (x[j] != 0) t[i] += Math.Exp(i * Math.Log(x[j])) * y[j];

              }



              for (i = 0; i <= 2 * n; i++)
              {

                  s[i] = 0.0;

                  for (j = 0; j <= m; j++)

                      if (i == 0 || x[j] == 0) s[i] += x[j];

                      else s[i] += Math.Exp(i * Math.Log(x[j])) * x[j];

              }



              for (i = 0; i <= n; i++)

                  for (j = 0; j <= n; j++)
                  {

                      if (i == 0 && j == 0) sw[0, 0] = m + 1;

                      else sw[i, j] = s[i + j - 1];

                  }



              for (i = 0; i <= n; i++)

                  sw[i, n + 1] = t[i];



              for (i = 0; i <= n; i++)
              {

                  r = sw[i, i];

                  for (j = i; j <= n + 1; j++) sw[i, j] /= r;



                  for (j = i + 1; j <= n; j++)
                  {

                      r = sw[j, i];

                      for (k = i; k <= n + 1; k++) sw[j, k] -= sw[i, k] * r;

                  }

              }



              for (i = n; i >= 0; i--)
              {

                  r = sw[i, n + 1];

                  for (j = i + 1; j <= n; j++) r -= sw[i, j] * a[j];

                  a[i] = r;

              }

              return a;

          }

          private void PlotDistances()
          {
              int xpos = 250;
              int ypos = image.Height - 10;
              Graphics gg = this.CreateGraphics();
              Point[] pp = new Point[alldist.distances_px.Length];
              Point[] pposx = new Point[alldist.distances_px.Length];
              Point[] ppmean = new Point[alldist.distances_px.Length];
              for (int i = 0; i < alldist.distances_px.Length; i++)
              {
                  pp[i] = new Point(xpos + i, ypos - (int)alldist.distances_px[i]);
                  pposx[i] = new Point(xpos + i, ypos);
                  ppmean[i] = new Point(xpos + i, ypos - (int)alldist.meandistance_px);
              }

              Font f = new Font("Verdana", 8);
              SolidBrush brush = new SolidBrush(Color.Yellow);

              gg.DrawString("px", f, brush, xpos-20, ypos - (int)alldist.maxdistance_px - 5);


              gg.DrawLine(Pens.Blue, new Point(xpos, ypos), new Point(xpos, ypos - (int)alldist.maxdistance_px - 5));//os y
              gg.DrawLines(Pens.Blue, pposx);
              
              gg.DrawLines(Pens.Red, pp);
              gg.DrawLines(Pens.Green, ppmean);
          }
#endregion

          #region DOWN SYNDROME RISK
          /*DOWN SYNDROME RISK*/
          ///////////////////
          double DownRisk_NT(int age, double CRL, double NT)
        {
        // **********************************************
        // Tato funkce je soucasti diplomove prace...             
        // Autor: Bogdan Szpyrc    
        // Email: szpyrc.bogdan@gmail.com
        // Skola: VUT Brno
        // // Fakulta: FEKT                                                                    
        // Obor: Biomedicinske a ekologicke inzenyrstvi               
        // **********************************************
        // P R A C O V N I   V E R Z E   1 . 1   ! ! ! 
        // DownRisk_NT je funkce pro vypocet rizika Downova syndromu
        // v prvnim trimestru tehotenstvi. Data pro vypocet vychazeji ze studii
        // provedenych ve VB prof. Nicolaidesem.
        // 
        // U P O Z O R N E N I   ! ! !
        // Funkce ma pouze informativni charakter - v zadnem pripade vysledky
        // nelze povazovat za smerodatne a pro urceni rizika je nutno pouzit
        // nektereho z autorizovanych programu.
        // 
        // Deklarace fce: 
        // DownRisk_NT(age, CRL, NT, alldata, graph)
        //                   age ... vek matky (20-42)
        //                   CRL ... temeno konstrcni delka (45-84mm)
        //                   NT ... sirka sijoveho projasneni (0.5-4mm)
        //                   alldata ... vystup funce jsou vsechna razika pro
        //                       vsechna NT a MA [hodnoty NT, vek matky] ('y'); 
        //                       vystup je hodnota rizika vypoctena pro zadane hodnoty
        //                   graph ... graficke zobrazeni vysledku ('y' - ano; 'n'-
        //                   ne)
        //                    
        // pozn.: Pri zadani hodnot age=0, CRL=0 a NT=0 uzivatel je vyzvan k rucnimu
        // zdani techto hodnot.
        // 
        // (C) 2009 Bogdan Szpyrc
        // Email: szpyrc.bogdan@gmail.com
        // University of Technolgy Brno

        //// Overeni vstupnich dat
        if (!(age<=42 && age>=20))
           return 0;
        else if (!(CRL<=84 && CRL>=45))
           return 0;
        else if (!(NT<=4 && NT>=0.5))
           return 0;
           

//// Vstupni data a vypocet aproximace
//int k=8; //stupen polynomu

double[] MA = {20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42}; // vek matky
double[] risk_MA = {0.09363296,
                    0.09516604,
                    0.09691960,
                    0.09911416,
                    0.10197021,
                    0.10570825,
                    0.11066396,
                    0.11763379,
                    0.12752938,
                    0.14126237,
                    0.15974441,
                    0.18416206,
                    0.21691974,
                    0.26109661,
                    0.32051282,
                    0.40160643,
                    0.51020408,
                    0.65789474,
                    0.85470085,
                    1.12359551,
                    1.47058824,
                    1.96078431,
                    2.63157895}; // risk odvozen z veku matky v //







// // // // INNTERPOLACE SPLAJNEM // // // // // //
//float[,] MA_risk_CS = Spline(MA, risk_MA,5);
// // // // // // // // // // // // //

double[] deltaNT = {-0.5, 0, 0.5, 1, 1.5, 2, 2.5}; // odchylka od medianu NT
double[] LR = {0.6, 1, 1.5, 3, 10, 28, 56}; // risk (Likelihood Ratio)
// // // // INNTERPOLACE SPLAJNEM // // // // // //
float[,] delta_CS = Spline(deltaNT, LR,40);
// // // // // // // // // // // // //


////  Vypocet rizika

    double delta=0.0179*CRL+0.3945; //median pro danou CRL

/*    double[] all_NT=new double[(40-7)]; for (int i=0;i<=40-8; i++) {all_NT[i]=(8+i)/10.0;} //pouzitelne tloustky NT
    int index=(int)Math.Round(Math.Abs((NT-0.8))*10); //
            //xx...odchylka od medianu NT pro denou CRL
    double[] xx=new double[(all_NT.Length)]; for (int i=0; i<all_NT.Length;i++) {xx[i]=Math.Abs(all_NT[i]-delta);} //Math.Abs <-> xx(find(all_NT<delta))=xx(find(all_NT<delta)).*(-1);
*/


    //apriorni riziko z vek matky
    double maternal_apriori = risk_MA[age - 20];
    double NT_risk = (NT-delta);

    int m = 0;
    while (NT_risk > delta_CS[0, m])
    {
        m++;
    }
    double LR_risk = delta_CS[1, m];


            return LR_risk*maternal_apriori; 
    

/*
NT_risk = ppval(delta_CS,xx);
maternal_age=min(MA):max(MA);
maternal_age_risk = ppval(MA_risk_CS,maternal_age);



// vypocet celkoveho rizika
all_risk=repmat(maternal_age_risk,length(NT_risk),1) .* repmat(NT_risk,length(maternal_age_risk),1)';
all_risk(all_risk>100) = 100;
  
  

            risk=all_risk(index, find(maternal_age==age));
            */
        /////////////////////////////////////////
    }

          private float[,] Spline(double[] X, double[] Y, int precision)
        {
            int np = X.Length; //points.Count;           // number of points
            float[] yCoords = new float[np];        // Newton form coefficients
            float[] xCoords = new float[np];        // x-coordinates of nodes
            float y;
            float x;
            float oldy = 0;
            float oldx = 0;

                 int npp = np * precision;          // number of points used for drawing
                 float[,] output = new float[2,npp];
                 for (int i = 0; i < np; i++)
                 {
                     xCoords[i] = (float)X[i];
                     yCoords[i] = (float)Y[i];
                 }

                 if (np > 0)
                 {

                    //
#region POLY - coment
                     /*
                             // use divided difference algorithm to compute Newton form coefficients
                             for (int k = 1; k <= np - 1; k++)
                             {
                                 for (int i = 0; i <= np - 1 - k; i++)
                                 {
                                     yCoords[i] = (yCoords[i + 1] - yCoords[i]) / (xCoords[i + k] - xCoords[i]);
                                 }
                             }

                             // for equidistant points along x-axis evaluate polynomial and draw line
                             float dt = ((float)this.graphPanel.Width - 1) / npp;
                             for (int k = 0; k <= npp; k++)
                             {
                                 x = k * dt;
                                 // evaluate polynomial at t
                                 y = yCoords[0];
                                 for (int i = 1; i <= np - 1; i++)
                                 {
                                     y = y * (x - xCoords[i]) + yCoords[i];
                                 }
                                 // draw line
                                 try
                                 {
                                     g.DrawLine(linePen, (int)oldx, (int)oldy, (int)x, (int)y);
                                 }
                                 catch (Exception ex)
                                 {
                                     Console.WriteLine(ex.Message + " x1={0} y1={1} x2={2} y2={3}", oldx, oldy, x, y);
                                 }
                                 oldx = x;
                                 oldy = y;
                             }*/
#endregion
                             if (np > 1)
                             {
                                 float[] a = new float[np];
                                 float x1;
                                 float x2;
                                 float[] h = new float[np];
                                 for (int i = 1; i <= np - 1; i++)
                                 {
                                     h[i] = xCoords[i] - xCoords[i - 1];
                                 }
                                 if (np > 2)
                                 {
                                     float[] sub = new float[np - 1];
                                     float[] diag = new float[np - 1];
                                     float[] sup = new float[np - 1];

                                     for (int i = 1; i <= np - 2; i++)
                                     {
                                         diag[i] = (h[i] + h[i + 1]) / 3;
                                         sup[i] = h[i + 1] / 6;
                                         sub[i] = h[i] / 6;
                                         a[i] = (yCoords[i + 1] - yCoords[i]) / h[i + 1] - (yCoords[i] - yCoords[i - 1]) / h[i];
                                     }
                                     solveTridiag(sub, diag, sup, ref a, np - 2);
                                 }
                                 // note that a[0]=a[np-1]=0
                                 // draw

                                 oldx = xCoords[0];
                                 oldy = yCoords[0];
                           
                                 int k = 0;
                                 for (int i = 1; i <= np - 1; i++)
                                 {   // loop over intervals between nodes
                                     for (int j = 1; j <= precision; j++)
                                     {
                                         x1 = (h[i] * j) / precision;
                                         x2 = h[i] - x1;
                                         y = ((-a[i - 1] / 6 * (x2 + h[i]) * x1 + yCoords[i - 1]) * x2 +
                                             (-a[i] / 6 * (x1 + h[i]) * x2 + yCoords[i]) * x1) / h[i];
                                         x = xCoords[i - 1] + x1;

                                         output[0,k] = x;
                                         output[1,k] = y;
                                         k++;
                                        
                                         oldx = x;
                                         oldy = y;
                                     }
                                 }
                             }
                            
                     }

                 return output;
                 }
     
          private void TB_Age_Scroll(object sender, EventArgs e)
          {
              TB_Age.Value = (int)TB_Age.Value;
              LBL_Age.Text=(TB_Age.Value).ToString();
              if (C.X!=0 & D.X!=0)
                  LBL_DownRisk.Text = "Risk: " + String.Format("{0:0.00}", DownRisk_NT(TB_Age.Value, (double)TB_CRL.Value, PxToMm(NTdist_in_px(Ci, Di)))) + " %";
                       
          }

          private void TB_CRL_Scroll(object sender, EventArgs e)
          {
              TB_CRL.Value = (int)TB_CRL.Value;
              TeB_CRL.Text = TB_CRL.Value.ToString();
              if (C.X != 0 & D.X != 0)
                  LBL_DownRisk.Text = "Risk: " + String.Format("{0:0.00}", DownRisk_NT(TB_Age.Value, (double)TB_CRL.Value, PxToMm(NTdist_in_px(Ci, Di)))) + " %";
                    
          }

          private void TeB_CRL_TextChanged(object sender, EventArgs e)
          {
             
              if ((Convert.ToInt32(TeB_CRL.Text) >= TB_CRL.Minimum) &
                  (Convert.ToInt32(TeB_CRL.Text) <= TB_CRL.Maximum))
              {
                  TB_CRL.Value = Convert.ToInt32(TeB_CRL.Text);
              }
             
          }

          private void TeB_CRL_KeyPress(object sender, KeyPressEventArgs e)
          {
              int isNumber = 0;
              e.Handled = !int.TryParse(e.KeyChar.ToString(), out isNumber);

          }

          private void TB_angle_Scroll(object sender, EventArgs e)
          {
              LBL_angle.Text = TB_angle.Value.ToString();

              //create a new empty bitmap to hold rotated image
              Bitmap bmpp = new Bitmap(anglerotate);
              //make a graphics object from the empty bitmap
              bmpp = rotateImage(bmpp,180- TB_angle.Value, new Point(50, 50));
              PB_angle.Image = bmpp;
          }
          #endregion


        //STATISTIKA
          private void BTN_savestat_Click(object sender, EventArgs e)
          {
              statistic_data.A = A;
              statistic_data.B = B;
              statistic_data.scale = scale;

              if (Ci.X == 0)
              {
                  statistic_data.C = C;
              }
              else
              {
                  statistic_data.C = Ci;
              }
              
              if (Di.X == 0)
              {
                  statistic_data.D = D;
              }
              else
              {
                  statistic_data.D = Di;
              }


                  BTN_savestat.Text = "Save statistic (" + ++stat_count + ")";

                  StreamWriter t = new StreamWriter(Directory.GetCurrentDirectory() + @"\stat.txt", true);
                  t.Write(statistic_data.imagename + ";");
                  t.Write(statistic_data.maxNT + ";");
                  t.Write(statistic_data.maxNTpx + ";");
                  t.Write(statistic_data.meanNT + ";");
                  t.Write(statistic_data.meanNTpx + ";");
                  t.Write(statistic_data.variance + ";");
                  t.Write(statistic_data.standard_dev + ";");
                  t.Write(statistic_data.scale + ";");
                  t.Write(statistic_data.dyn1_px + ";");
                  t.Write(statistic_data.dyn2_px + ";");

                  t.Write(statistic_data.A.X + ";");
                  t.Write(statistic_data.A.Y + ";");
                  t.Write(statistic_data.B.X + ";");
                  t.Write(statistic_data.B.Y + ";");
                  t.Write(statistic_data.C.X + ";");
                  t.Write(statistic_data.C.Y + ";");
                  t.Write(statistic_data.D.X + ";");
                  t.Write(statistic_data.D.Y + ";\n\r");

                  t.Close();

              if (stat_count < Int16.Parse(TB_pocetiteraci.Text) )
              {
                  ResetPoints();
                  RB_A.Text = "A";
                  RB_B.Text = "B";
                  LBL_info.Text = "Zadejte bod A";
                  SetNT_sw = 2;
                  RB_A.Checked = true;
                  ChB_PROFILE.Checked = false;
              }
              else
              {
                  t = new StreamWriter(Directory.GetCurrentDirectory() + @"\stat.txt", true);
                  t.Write("\n\r\n\r image_name;Ntmax;Ntmax_px;Ntmean;Ntmean_px;variance;stand_dev;scale;dyn1;dyn2;Ax;Ay;Bx;By;Cx;Cy;Dx;Dy;\n\r");
                  t.Close();
                  stat_count = 0;
                  BTN_savestat.Text = "Save statistic (" + stat_count + ")";
                  BTN_Load_Click(null, null);
              }

          }

          private void BTN_algtest_Click(object sender, EventArgs e)
          {
              if (SetNT_sw != -1)
              {
                  SetNT_sw = 4;
                  RB_A.Checked = true;

              }
              else if (SetNT_sw==-1)
              {
                  Point defA = A;
                  Point defB = B;

                  for (int pokus = 0; pokus < Int16.Parse(TB_pocetiteraci.Text); pokus++)
                  {
                      int crossize = 3;
                      #region SemiautoNT

//(int)(Math.Pow((double)-1, (double)pokus) * 
                      int meze = Int16.Parse(TB_rozptylbodu.Text);
                      Random random = new Random();
                      int ax = random.Next(-meze, meze);
                      int ay = random.Next(-meze, meze);
                      int bx = random.Next(-meze, meze);
                      int by = random.Next(-meze, meze);

                      A = new Point(defA.X + ax, defA.Y + ay); 
                      B = new Point(defB.X + bx, defB.Y + by); //defB;
                      Point tempA = A;
                      Point tempB = B;
                      RB_A.Text = "A " + A.ToString();
                      RB_B.Text = "B " + B.ToString();


                      g.DrawLine(Pens.Green, new Point(A.X - crossize, A.Y), new Point(A.X + crossize, A.Y));
                      g.DrawLine(Pens.Green, new Point(A.X, A.Y - crossize), new Point(A.X, A.Y + crossize));
                      g.DrawLine(Pens.Green, new Point(B.X - crossize, B.Y), new Point(B.X + crossize, B.Y));
                      g.DrawLine(Pens.Green, new Point(B.X, B.Y - crossize), new Point(B.X, B.Y + crossize));
                      
                      NTprofile NT;
                      if (ChB_autocorrAB.Checked)
                      {
                          #region UPRAVA BODU AB
                          // * * * * * * * uprava bodu AB
                          NT = GetProfile(image, A, new Point(A.X + 30, A.Y), A);
                          Point min = GetNTMin(NT.Profile);
                          A = new Point(NT.Line[min.X].X, NT.Line[min.X].Y);

                          NT = GetProfile(image, B, new Point(B.X - 30, B.Y), B);
                          min = GetNTMin(NT.Profile);
                          B = new Point(NT.Line[min.X].X, NT.Line[min.X].Y);
                          // g.DrawLine(Pens.Green, new Point(A.X - crossize, A.Y), new Point(A.X + crossize, A.Y));
                          //  g.DrawLine(Pens.Green, new Point(A.X, A.Y - crossize), new Point(A.X, A.Y + crossize));
                          //  g.DrawLine(Pens.Green, new Point(B.X - crossize, B.Y), new Point(B.X + crossize, B.Y));
                          //  g.DrawLine(Pens.Green, new Point(B.X, B.Y - crossize), new Point(B.X, B.Y + crossize));

                          #region nastaveni poc.bodu (nazavislost poradi zadani bodu AB)
                          int startindex;
                          int stopindex;
                          if (Math.Abs(B.Y - A.Y) < Math.Abs(A.X - B.X))
                          {
                              if (A.X <= B.X)
                              {
                                  startindex = A.X;
                                  stopindex = B.X;
                              }
                              else
                              {
                                  startindex = B.X;
                                  stopindex = A.X;
                              }
                          }
                          else
                          {
                              if (A.Y <= B.Y)
                              {
                                  startindex = A.Y;
                                  stopindex = B.Y;
                              }
                              else
                              {
                                  startindex = B.Y;
                                  stopindex = A.Y;
                              }
                          }
                          #endregion
                          Point[] Sline = new Point[stopindex - startindex + 1];
                          Point S_temp;
                          int j = 0;
                          for (int i = startindex; i <= stopindex; i++)
                          {
                              //Graphics g = this.CreateGraphics();
                              // pohyb kurzoru pouze po ose NT
                              Point n = new Point(B.Y - A.Y, A.X - B.X); //normalovy vektor
                              int mx = i;
                              int my = i;
                              int q = -(n.X * A.X + n.Y * A.Y); //s=-sum(n.*a);
                              // Rovnice primky px+ry+q=0, kde n=[p r]
                              if (Math.Abs(n.X) < Math.Abs(n.Y)) //horizontalni osa
                                  S_temp = (new Point(mx, (Int16)(-1.0 / n.Y * (n.X * mx + q))));
                              else //vertikalni osa
                                  S_temp = (new Point((Int16)(-1.0 / n.X * (n.Y * my + q)), my));
                              //

                              NT = GetProfile(image, A, B, S_temp);
                              min = GetNTMin(NT.Profile);

                              j = i - startindex;
                              Sline[j] = new Point(NT.Line[min.X].X, NT.Line[min.X].Y);
                          }

                          //   g.DrawLines(Pens.Green, Sline);

                          //vse pro osu NT "rovnobeznou" s osu X
                          int stupen = 1;
                          double[] s = MNK(Sline, stupen);

                          int ys = 0;

                          for (int i = startindex; i <= stopindex; i++)
                          {
                              j = i - startindex;
                              ys = 0;
                              for (int k = stupen; k >= 0; k--)
                              {
                                  ys += (int)(s[k] * Math.Pow(i, k));
                              }
                              Sline[j] = new Point(Sline[j].X, ys);
                          }
                          A = Sline[(int)(0.1 * Sline.Length)];
                          B = Sline[(int)(0.9 * Sline.Length)];

                          RB_A.Text = "A " + A.ToString();
                          RB_B.Text = "B " + B.ToString();

                          //vykresleni osy NT
                          if (ChB_ShowNTLimiting.Checked)
                          {
                              Graphics gg = this.CreateGraphics();
                              gg.DrawLines(Pens.Yellow, Sline);
                              gg.DrawLine(Pens.Yellow, new Point(A.X - crossize, A.Y), new Point(A.X + crossize, A.Y));
                              gg.DrawLine(Pens.Yellow, new Point(A.X, A.Y - crossize), new Point(A.X, A.Y + crossize));
                              gg.DrawLine(Pens.Yellow, new Point(B.X - crossize, B.Y), new Point(B.X + crossize, B.Y));
                              gg.DrawLine(Pens.Yellow, new Point(B.X, B.Y - crossize), new Point(B.X, B.Y + crossize));
                          }
                          // * * * * * * *
                          #endregion
                      }
                      alldist = FindMaxWidth(image, A, B);
                           LBL_NTdistance.Text = "NT max: " + String.Format("{0:0.00}", PxToMm(alldist.maxdistance_px)) + " mm = " + String.Format("{0:0.00}", alldist.maxdistance_px) + " px";
                           LBL_NTmean.Text = "NT mean: " + String.Format("{0:0.00}", PxToMm(alldist.meandistance_px)) + " mm = " + String.Format("{0:0.00}", alldist.meandistance_px) + " px";
                           LBL_NTvariance.Text = "NT variance: " + String.Format("{0:0.00}", PxToMm(alldist.variance_px)) + " mm";
                           LBL_NTSD.Text = "NT standard deviation: " + String.Format("{0:0.00}", Math.Sqrt(PxToMm(alldist.variance_px))) + " mm";
                           LBL_DownRisk.Text = "Risk: " + String.Format("{0:0.00}", DownRisk_NT(TB_Age.Value, (double)TB_CRL.Value, PxToMm(NTdist_in_px(Ci, Di)))) + " %";
                    
                           NT = GetProfile(image, A, B, alldist.S);
                           Point[] m = GetNTMaxs(NT);

                           //dynamika obrazu v NT oblasti
                           int max1 = m[0].Y;
                           int max2 = m[1].Y;
                           int min0 = GetMinimum(NT.Profile, m[0].X, m[1].X);
                       //    LBL_DR1.Text = "DR: " + String.Format("{0:0.00}", max1 - min0) + " lev.";
                       //    LBL_DR2.Text = "DR: " + String.Format("{0:0.00}", max2 - min0) + " lev.";

                           statistic_data.dyn1_px = max1 - min0;
                           statistic_data.dyn2_px = max2 - min0;
                           //


                           //vykresleni ohrnaniceni NT
                      if (ChB_ShowNTLimiting.Checked)
                      {
                          Pen myPen = new Pen(System.Drawing.Color.Red, 1);
                          Graphics gg = this.CreateGraphics();
                          gg.DrawLines(myPen, alldist.C);
                          gg.DrawLines(Pens.Blue, alldist.Cinter);
                          gg.DrawLines(myPen, alldist.D);
                          gg.DrawLines(Pens.Blue, alldist.Dinter);
                          //  gg.DrawLines(Pens.Yellow, Sline);

                      
                          g.DrawLine(Pens.Yellow, new Point(Ci.X - crossize, Ci.Y), new Point(Ci.X + crossize, Ci.Y));
                          g.DrawLine(Pens.Yellow, new Point(Ci.X, Ci.Y - crossize), new Point(Ci.X, Ci.Y + crossize));
                          g.DrawLine(Pens.Yellow, new Point(Di.X - crossize, Di.Y), new Point(Di.X + crossize, Di.Y));
                          g.DrawLine(Pens.Yellow, new Point(Di.X, Di.Y - crossize), new Point(Di.X, Di.Y + crossize));
                    }
                    
                      //STATISTIKA
                      statistic_data.meanNT = PxToMm(alldist.meandistance_px);
                      statistic_data.meanNTpx = alldist.meandistance_px;
                      statistic_data.maxNT = PxToMm(alldist.maxdistance_px);
                      statistic_data.maxNTpx = alldist.maxdistance_px;
                      statistic_data.variance = alldist.variance_px;
                      statistic_data.standard_dev = Math.Sqrt(alldist.variance_px);
                      A = tempA; B = tempB;
//Thread.Sleep(1000);
                      if (alldist.variance_px < 20)
                      {
                          if (ChB_savestat.Checked)
                              BTN_savestat_Click(null, null);
                      }
                      else
                          pokus--;
                      
                    #endregion
                  }
                      
                 
                     
                  SetNT_sw = 0;
              }

          }

          private void button1_Click(object sender, EventArgs e)
          {
               StreamWriter  t = new StreamWriter(Directory.GetCurrentDirectory() + @"\t.txt", true);
              int index = 2;
              for (int i = 0; i < 220; i++)
              {
                  if (i>0)
                  index=103+index;

                  t.Write("=data.A" + index.ToString() + ";" +
                          "=AVERAGE(data.B" + index.ToString() + ":data.B" + (index + 99).ToString() + ");" +
                          "=STDEV(data.B" + index.ToString() + ":data.B" + (index + 99).ToString() + ");" +
                          "=AVERAGE(data.C" + index.ToString() + ":data.C" + (index + 99).ToString() + ");" +
                          "=STDEV(data.C" + index.ToString() + ":data.C" + (index + 99).ToString() + ");" +
                          "=AVERAGE(data.D" + index.ToString() + ":data.D" + (index + 99).ToString() + ");" +
                          "=STDEV(data.D" + index.ToString() + ":data.D" + (index + 99).ToString() + ");" +
                          "=AVERAGE(data.E" + index.ToString() + ":data.E" + (index + 99).ToString() + ");" +
                          "=STDEV(data.E" + index.ToString() + ":data.E" + (index + 99).ToString() + ");" +
                          "=AVERAGE(data.F" + index.ToString() + ":data.F" + (index + 99).ToString() + ");" +
                          "=STDEV(data.F" + index.ToString() + ":data.F" + (index + 99).ToString() + ");" +
                          "=AVERAGE(data.G" + index.ToString() + ":data.G" + (index + 99).ToString() + ");" +
                          "=STDEV(data.G" + index.ToString() + ":data.G" + (index + 99).ToString() + ");" +
                          "=AVERAGE(data.H" + index.ToString() + ":data.H" + (index + 99).ToString() + ");" +
                          "=STDEV(data.H" + index.ToString() + ":data.H" + (index + 99).ToString() + ");" +
                          "=AVERAGE(data.I" + index.ToString() + ":data.I" + (index + 99).ToString() + ");" +
                          "=STDEV(data.I" + index.ToString() + ":data.I" + (index + 99).ToString() + ");" +
                          "=AVERAGE(data.J" + index.ToString() + ":data.J" + (index + 99).ToString() + ");" +
                          "=STDEV(data.J" + index.ToString() + ":data.J" + (index + 99).ToString() + ");" +

                          "\n\r"                                               
                      );
              }
               
              t.Close();
          }
         
    }
}

#region not used
/*       /////////////////////////////////////
        #region Corventing - not use
         ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

           private byte[] ConvertBitmap(Bitmap bitmap)
           {
               //Code excerpted from Microsoft Robotics Studio v1.5
               BitmapData raw = null;  //used to get attributes of the image
               byte[] rawImage = null; //the image as a byte[]

               try
               {
                   //Freeze the image in memory
                   raw = bitmap.LockBits(
                       new Rectangle(0, 0, (int)bitmap.Width, (int)bitmap.Height),
                       ImageLockMode.ReadOnly,
                       PixelFormat.Format24bppRgb
                   );

                   int size = raw.Height * raw.Stride;
                   rawImage = new byte[size];

                   //Copy the image into the byte[]
                   System.Runtime.InteropServices.Marshal.Copy(raw.Scan0, rawImage, 0, size);
               }
               finally
               {
                   if (raw != null)
                   {
                       //Unfreeze the memory for the image
                       bitmap.UnlockBits(raw);
                   }
               }
               return rawImage;
           }

        public static byte[] SelPxs(byte[] InputVector)
        {
            byte[] OutputVector = new byte[10000];

            System.Buffer.BlockCopy(InputVector, 0, OutputVector, 0, 10000);
            return OutputVector;
        }

        public static byte[] GetVectorFromArray(byte[,] InputArray)
        {
            byte[] OutputVector = new byte[InputArray.GetLength(0) * InputArray.GetLength(1)];
            System.Buffer.BlockCopy(InputArray, 0, OutputVector, 0, InputArray.GetLength(0) * InputArray.GetLength(1));

            return OutputVector;
        }

        public static byte[,,] GetBitmapArraySafe(Bitmap bitMapa)
        {
            byte[,,] bitmapArray = new byte[bitMapa.Width, bitMapa.Height, 3];
            Color barva;
           // byte intensity;
            byte red;
            byte green;
            byte blue;

            for (int y=0; y<bitMapa.Height; y++)
                for(int x=0; x<bitMapa.Width; x++)
                {
                    barva = bitMapa.GetPixel(x,y);
                    red = barva.R;
                    green = barva.G;
                    blue = barva.B;
                    bitmapArray[x,y,0] = red;
                    bitmapArray[x,y,1] = green;
                    bitmapArray[x,y,2] = blue;
                } //for for

            return bitmapArray;
        }
   
        public static Bitmap SaveArrayToBitmapSafe(byte[, ,] bitmapArray)
        {
            Bitmap bitMap = new Bitmap(bitmapArray.GetLength(0), bitmapArray.GetLength(1)); //, PixelFormat.Format24bppRgb);

            for (int y = 0; y < bitMap.Height; y++)
                for (int x = 0; x < bitMap.Width; x++)
                {
                    bitMap.SetPixel(x, y, Color.FromArgb(
                                    bitmapArray[x, y, 0],       //R
                                    bitmapArray[x, y, 1],       //G
                                    bitmapArray[x, y, 2]));     //B
                } //for for

            return bitMap;
        }

        public static byte[,] ConvertToGrayScale(byte[, ,] picArray)
        {
            byte[,] grayArray = new byte[picArray.GetLength(0), picArray.GetLength(1)];
            byte intensity;
            byte red;
            byte green;
            byte blue;

            for (int y=0; y<picArray.GetLength(1); y++) //radky
                for (int x = 0; x < picArray.GetLength(1); x++) //sloupce
                {
                    red = (byte)(picArray[x, y, 0] * 0.299);
                    green = (byte)(picArray[x, y, 1] * 0.587);
                    blue = (byte)(picArray[x, y, 2] * 0.114);
                    intensity = (byte)(red + green + blue);
                    grayArray[x, y] = intensity;
                } //for for

            return grayArray;
        }

     
       

       


      // private Point pictureBox1_MouseDown(object sender, MouseEventArgs e)
      //  {
            //Point SetPoint = new Point((e.X) * 2, (e.Y) * 2);
            //return SetPoint;
     //       return PointToClient(Cursor.Position);

     //   }

        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#endregion
       

*/
#endregion


#### MAGNIFYGLASS ####
using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;

namespace NTmeasurementplugin
{
    /// <summary>
    /// A fixed magnifying glass for placing on a control
    /// </summary>
    public partial class MagnifyingGlass : UserControl
    {
        private System.Windows.Forms.Timer _UpdateTimer = new System.Windows.Forms.Timer();
        private int _PixelSize = 5;
        private int _PixelRange = 10;
        private bool _ShowPixel = true;
        private bool _ShowPosition = true;
        private string _PosFormat = "#x ; #y";
        private bool _FollowCursor = false;
        internal Bitmap _ScreenShot = null;
        internal MovingMagnifyingGlass _DisplayForm = null;
        private Point _LastPosition = Point.Empty;
        private MovingMagnifyingGlass _MovingGlass = null;
        private ContentAlignment _PosAlign = ContentAlignment.TopLeft;
        private bool _UseMovingGlass = false;

        /// <summary>
        /// Instance of the magnifying glass with moving glass, if the user clicks on this one
        /// </summary>
        public MagnifyingGlass()
            : this(true)
        {
        }

        /// <summary>
        /// Instance of the magnifying glass
        /// </summary>
        /// <param name="movingGlass">Create a moving glass if the user clicks on this one?</param>
        public MagnifyingGlass(bool movingGlass)
        {
            if (movingGlass)
            {
                // Moving glass is enabled
                _MovingGlass = new MovingMagnifyingGlass();
                MovingGlass.MagnifyingGlass.ShowPosition = false;
                MovingGlass.MagnifyingGlass.DisplayUpdated += new DisplayUpdatedDelegate(MagnifyingGlass_DisplayUpdated);
                MovingGlass.MagnifyingGlass.Click += new EventHandler(_MovingGlass_Click);
                MouseWheel += new MouseEventHandler(MagnifyingGlass_MouseWheel);
                Cursor = Cursors.SizeAll;
                UseMovingGlass = true;
            }
            _UpdateTimer.Tick += new System.EventHandler(_UpdateTimer_Tick);
            Click += new System.EventHandler(MagnifyingGlass_Click);
            CalculateSize();
        }

        #region Properties
        [Description("Magnifying ratio (calculate PixelRange*PixelSize*2+PixelSize for the final control size, min. 3)")]
        public int PixelSize
        {
            get
            {
                return _PixelSize;
            }
            set
            {
                int temp = value;
                if (temp < 3)
                {
                    // Minimum size
                    temp = 3;
                }
                if ((double)temp / 2 == (double)Math.Floor((double)temp / 2))
                {
                    // Use only integers that can't be divided by 2
                    temp++;
                }
                _PixelSize = temp;
                CalculateSize();
            }
        }

        
        [Description("Get/set if the moving glass feature should be used")]
        public bool UseMovingGlass
        {
            get
            {
                return _UseMovingGlass;
            }
            set
            {
                if (MovingGlass != null)
                {
                    _UseMovingGlass = value;
                }
            }
        }

        [Description("Get/set the align of the position (choose everything, but not the middle")]
        public ContentAlignment PosAlign
        {
            get
            {
                return _PosAlign;
            }
            set
            {
                _PosAlign = (!value.ToString().ToLower().StartsWith("middle")) ? value : ContentAlignment.TopLeft;
            }
        }

        [Description("Get/set the position display string format (you have to use #x and #y for the corrdinates values)")]
        public string PosFormat
        {
            get
            {
                return _PosFormat;
            }
            set
            {
                // Settings without the #x and #y variables will be ignored
                _PosFormat = (value != null && value != "" && value.Contains("#x") && value.Contains("#y")) ? value : "#x ; #y";
                Invalidate();
            }
        }

        [Description("The moving glass, if the user clicks on this")]
        public MovingMagnifyingGlass MovingGlass
        {
            get
            {
                return _MovingGlass;
            }
        }

        /// <summary>
        /// Returns true, if enabled, visible and not in designer mode
        /// </summary>
        [Browsable(false)]
        public bool IsEnabled
        {
            get
            {
                return Visible && Enabled && !DesignMode;
            }
        }

        [Browsable(false)]
        internal bool FollowCursor
        {
            get
            {
                return _FollowCursor;
            }
            set
            {
                if (!(_FollowCursor = value))
                {
                    // Exit the following mode
                    if (_ScreenShot != null)
                    {
                        _ScreenShot.Dispose();
                        _ScreenShot = null;
                    }
                }
            }
        }

        [Description("Get/set the pixel range (calculate PixelRange*PixelSize*2+PixelSize for the final control size, min. 1)")]
        public int PixelRange
        {
            get
            {
                return _PixelRange;
            }
            set
            {
                int temp = value;
                if (temp < 1)
                {
                    // Minimum range is one pixel
                    temp = 1;
                }
                _PixelRange = temp;
                CalculateSize();
            }
        }

        [Description("Get/set if the active pixel should be shown")]
        public bool ShowPixel
        {
            get
            {
                return _ShowPixel;
            }
            set
            {
                _ShowPixel = value;
                Invalidate();
            }
        }

        [Description("Get/set if the current cursor position should be shown")]
        public bool ShowPosition
        {
            get
            {
                return _ShowPosition;
            }
            set
            {
                _ShowPosition = value;
                Invalidate();
            }
        }

        [Description("Get the control size (settings will be ignored)")]
        new public Size Size
        {
            get
            {
                return base.Size;
            }
            set
            {
                // Settings will be ignored 'cause size will be calculated internal
            }
        }

        [Description("Get the timer that updates the display in an interval")]
        public Timer UpdateTimer
        {
            get
            {
                return _UpdateTimer;
            }
        }

        [Description("Get the color of the current pixel")]
        public Color PixelColor
        {
            get
            {
                Bitmap bmp = null;
                try
                {
                    // Make a screenshot of the pixel from the current cursor position
                    bmp = new Bitmap(1, 1);
                    using (Graphics g = Graphics.FromImage(bmp))
                    {
                        bool makeScreenshot = !FollowCursor;// Make a real screenshot?
                        if (makeScreenshot)
                        {
                            if (MovingGlass != null)
                            {
                                //Only make a real screenshot if the moving glass is inactive
                                makeScreenshot &= !MovingGlass.Visible;
                            }
                        }
                        if (!FollowCursor)
                        {
                            // Make a real screenshot
                            g.CopyFromScreen(Cursor.Position, new Point(0, 0), bmp.Size);
                        }
                        else
                        {
                            // Use the screen image for the screenshot
                            bool createScreenshot = false;// Did we create a screenshot for this?
                            if (FollowCursor)
                            {
                                // Create the screenshot only if it wasn't done yet
                                createScreenshot = _ScreenShot == null;
                            }
                            else
                            {
                                // Create the screenshot only of the moving glass has not done it yet
                                createScreenshot = MovingGlass.MagnifyingGlass._ScreenShot == null;
                            }
                            if (createScreenshot)
                            {
                                // Create a new screen image
                                MakeScreenshot();
                            }
                            if (FollowCursor)
                            {
                                // We're the moving glass
                                g.DrawImage(_ScreenShot, new Rectangle(new Point(0, 0), new Size(1, 1)), new Rectangle(Cursor.Position, new Size(1, 1)), GraphicsUnit.Pixel);
                            }
                            else
                            {
                                // Use the moving glasses screenshot
                                g.DrawImage(MovingGlass.MagnifyingGlass._ScreenShot, new Rectangle(new Point(0, 0), new Size(1, 1)), new Rectangle(Cursor.Position, new Size(1, 1)), GraphicsUnit.Pixel);
                            }
                            if (createScreenshot)
                            {
                                // Destroy the screenshot if we only needed to create one for this
                                _ScreenShot.Dispose();
                            }
                        }
                    }
                    // Return the pixel color
                    return bmp.GetPixel(0, 0);
                }
                finally
                {
                    bmp.Dispose();
                }
            }
        }
        #endregion

        #region Painting
        protected override void OnPaintBackground(PaintEventArgs e)
        {
            // Only paint the background, if we're disabled or in DesignMode
            if (!IsEnabled)
            {
                base.OnPaintBackground(e);
            }
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            if (!IsEnabled)
            {
                // Draw only if visible, enabled and not in DesignMode
                return;
            }
            // Set the InterpolationMode to NearestNeighbor to see the pixels clearly
            e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
            // Prepare some shortcut variables for a better overview
            Point pos = Cursor.Position;
            Rectangle scr = Screen.PrimaryScreen.Bounds;// The screen size
            Point zeroPoint = new Point(0, 0);
            #region Set the new display window location if we follow the cursor
            if (FollowCursor)
            {
                Point loc = new Point(Cursor.Position.X - PixelRange * PixelSize, Cursor.Position.Y - PixelRange * PixelSize);
                if (loc.X < 0)
                {
                    loc = new Point(0, loc.Y);
                }
                if (loc.X + Width > Screen.PrimaryScreen.Bounds.Width)
                {
                    loc = new Point(Screen.PrimaryScreen.Bounds.Width - Width, loc.Y);
                }
                if (loc.Y < 0)
                {
                    loc = new Point(loc.X, 0);
                }
                if (loc.Y + Height > Screen.PrimaryScreen.Bounds.Height)
                {
                    loc = new Point(loc.X, Screen.PrimaryScreen.Bounds.Height - Height);
                }
                _DisplayForm.Location = loc;
            }
            #endregion
            #region Make the screenshot
            Rectangle shot = new Rectangle(zeroPoint, new Size(Size.Width / PixelSize, Size.Height / PixelSize));// The final screenshot size and position
            Point defaultLocation = new Point(pos.X - PixelRange, pos.Y - PixelRange);// The screenshot default location
            shot.Location = defaultLocation;
            if (shot.Location.X < 0)
            {
                // The area is going over the left screen border
                shot.Size = new Size(shot.Size.Width + shot.Location.X, shot.Size.Height);
                shot.Location = new Point(0, shot.Location.Y);
            }
            else if (shot.Location.X > scr.Width)
            {
                // The area is going over the right screen border
                shot.Size = new Size(shot.Location.X - scr.Width, shot.Size.Height);
            }
            if (shot.Location.Y < 0)
            {
                // The area is going over the upper screen border
                shot.Size = new Size(shot.Size.Width, shot.Size.Height + shot.Location.Y);
                shot.Location = new Point(shot.Location.X, 0);
            }
            else if (shot.Location.Y > scr.Height)
            {
                // The area is going over the bottom screen border
                shot.Size = new Size(shot.Size.Width, shot.Location.Y - scr.Height);
            }
            Bitmap screenShot=new Bitmap(shot.Width, shot.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);// The screenshot imag;
            using (Graphics g = Graphics.FromImage(screenShot))
            {
                bool makeScreenshot = !FollowCursor;// Make areal screenshot?
                if (makeScreenshot)
                {
                    if (MovingGlass != null)
                    {
                        // Only make a real screenshot if the moving glass is inactive
                        makeScreenshot &= !MovingGlass.Visible;
                    }
                }
                if (makeScreenshot)
                {
                    // Make screenshot
                    g.CopyFromScreen(shot.Location, zeroPoint, shot.Size);
                }
                else
                {
                    // Copy from work screenshot
                    if (FollowCursor)
                    {
                        // We're the moving glass
                        g.DrawImage(_ScreenShot, new Rectangle(zeroPoint, screenShot.Size), shot, GraphicsUnit.Pixel);
                    }
                    else
                    {
                        // We're not the moving glass, but we should use the work screenshot 
                        // of the moving glass, 'cause if it's fully visible we'd copy the 
                        // moving glass display area...
                        g.DrawImage(MovingGlass.MagnifyingGlass._ScreenShot, new Rectangle(zeroPoint, screenShot.Size), shot, GraphicsUnit.Pixel);
                    }
                }
            }
            #endregion
            #region Paint the screenshot scaled to the display
            Rectangle display = new Rectangle(zeroPoint, Size);// The rectangle within the display to show the screenshot
            Size displaySize = new Size(shot.Width * PixelSize, shot.Height * PixelSize);// The default magnified screenshot size
            if (defaultLocation.X < 0 || defaultLocation.X > scr.Width)
            {
                if (defaultLocation.X < 0)
                {
                    // Display the screenshot with right align
                    display.Location = new Point(display.Width - displaySize.Width, display.Location.Y);
                }
                // Change the display area width to the width of the magnified screenshot
                display.Size = new Size(displaySize.Width, display.Size.Height);
            }
            if (defaultLocation.Y < 0 || defaultLocation.Y > scr.Height)
            {
                if (defaultLocation.Y < 0)
                {
                    // Display the screenshot with bottom align
                    display.Location = new Point(display.Location.X, display.Height - displaySize.Height);
                }
                // Change the display area height to the height of the magnified screenshot
                display.Size = new Size(display.Size.Width, displaySize.Height);
            }
            if (displaySize != Size)
            {
                // Paint the background 'cause the magnified screenshot size is different from the display size and we have a out-of-screen area
                e.Graphics.FillRectangle(new SolidBrush(BackColor), new Rectangle(zeroPoint, Size));
            }
            // Scale and paint the screenshot
            e.Graphics.DrawImage(screenShot, display);
            screenShot.Dispose();
            #endregion
            #region Paint everything else to the display
            // Show the current pixel in a black/white bordered rectangle in the middle of the display
            if (ShowPixel)
            {
                int xy = PixelSize * PixelRange;
                e.Graphics.DrawRectangle(new Pen(new SolidBrush(Color.Black)), new Rectangle(new Point(xy, xy), new Size(PixelSize, PixelSize)));
                e.Graphics.DrawRectangle(new Pen(new SolidBrush(Color.White)), new Rectangle(new Point(xy + 1, xy + 1), new Size(PixelSize - 2, PixelSize - 2)));
            }
            // Show the cursor position coordinates on a fixed colored background rectangle in the display
            if (ShowPosition)
            {
                // Parse the format string
                string posText = PosFormat;
                posText = posText.Replace("#x", pos.X.ToString());
                posText = posText.Replace("#y", pos.Y.ToString());
                // Calculate where to paint
                Size textSize = e.Graphics.MeasureString(posText, Font).ToSize();
                if (textSize.Width + 6 <= Width && textSize.Height + 6 <= Height)// Continue only if the display is bigger or equal to the needed size
                {
                    string posString = PosAlign.ToString().ToLower();// The align as text (for less code)
                    Point posZero = Point.Empty;// The zero coordinates for the position display
                    if (posString.StartsWith("top"))
                    {
                        posZero = new Point(0, 0);
                    }
                    else
                    {
                        posZero = new Point(0, Height - textSize.Height);
                    }
                    if (posString.Contains("center"))
                    {
                        posZero = new Point((int)Math.Ceiling((double)(Width - textSize.Width) / 2), posZero.Y);
                    }
                    else if (posString.Contains("right"))
                    {
                        posZero = new Point(Width - textSize.Width - 6, posZero.Y);
                    }
                    // Paint the text background rectangle and the text on it
                    e.Graphics.FillRectangle(new SolidBrush(BackColor), new Rectangle(posZero, new Size(textSize.Width + 6, textSize.Height + 6)));
                    e.Graphics.DrawString(posText, Font, new SolidBrush(ForeColor), new PointF(posZero.X + 3, posZero.Y + 3));
                }
            }
            #endregion
        }
        #endregion

        /// <summary>
        /// Set a new size
        /// </summary>
        /// <param name="pixelSize">Pixel size value</param>
        /// <param name="pixelRange">Pixel range value</param>
        public void SetNewSize(int pixelSize, int pixelRange)
        {
            SuspendLayout();
            PixelSize = pixelSize;
            PixelRange = pixelRange;
            ResumeLayout(true);
        }

        private void CalculateSize()
        {
            // Calculate the new control size depending on the magnifying ratio and the pixel range to display
            int wh = PixelSize * (PixelRange * 2 + 1);
            base.Size = new Size(wh, wh);
        }

        private void _UpdateTimer_Tick(object sender, EventArgs e)
        {
            try
            {
                // Redraw and continue the timer if we're visible, enabled and not in DesignMode
                // The timer is also disabled here because the Timer component seems to have an error (it will crashafter a while!?). Restarting the timer is a workaround.
                UpdateTimer.Stop();
                if (IsEnabled)
                {
                    if (_LastPosition == Cursor.Position)
                    {
                        // Refresh only if the position has changed
                        return;
                    }
                    // Remember the current cursor position
                    _LastPosition = Cursor.Position;
                    // Repaint everything
                    Invalidate();
                    // Release the event after the display has been updated
                    OnDisplayUpdated();
                }
            }
            finally
            {
                // Restart the timer
                UpdateTimer.Start();
            }
        }

        /// <summary>
        /// Delegate for the DisplayUpdated event
        /// </summary>
        /// <param name="sender">The sending MagnifyingGlass control</param>
        public delegate void DisplayUpdatedDelegate(MagnifyingGlass sender);
        /// <summary>
        /// Fired after the display has been refreshed by the UpdateTimer or the moving glass
        /// </summary>
        public event DisplayUpdatedDelegate DisplayUpdated;
        private void OnDisplayUpdated()
        {
            if (DisplayUpdated != null)
            {
                DisplayUpdated(this);
            }
        }

        #region Moving glass related methods
        private void MagnifyingGlass_Click(object sender, EventArgs e)
        {
            // Show the moving glass
            if (MovingGlass != null && IsEnabled && UseMovingGlass)
            {
                MovingGlass.Show();
            }
        }

        private void MagnifyingGlass_MouseWheel(object sender, MouseEventArgs e)
        {
            // Resize on mouse wheel actions
            if (_DisplayForm != null && e.Delta != 0)
            {
                if (e.Delta > 0)
                {
                    if ((PixelRange + 1) * PixelRange * 2 <= Screen.PrimaryScreen.Bounds.Width && (PixelRange + 1) * PixelRange * 2 <= Screen.PrimaryScreen.Bounds.Height)
                    {
                        PixelRange++;
                        PixelSize += 2;
                    }
                }
                else
                {
                    if (PixelRange - 1 >= 5)
                    {
                        PixelRange--;
                    }
                    if (PixelSize > 3)
                    {
                        PixelSize -= 2;
                    }
                }
            }
        }

        private void _MovingGlass_Click(object sender, EventArgs e)
        {
            // Hide the moving glass on mouse click
            MovingGlass.Hide();
        }

        private void MagnifyingGlass_DisplayUpdated(MagnifyingGlass sender)
        {
            // Refresh if the moving one has refreshed
            Invalidate();
            OnDisplayUpdated();
        }

        internal void MakeScreenshot()
        {
            // Copy the current screen without this control for the following glass
            OnBeforeMakingScreenshot();
            _ScreenShot = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
            using (Graphics g = Graphics.FromImage(_ScreenShot))
            {
                bool visible = _DisplayForm.Visible;
                if (visible)
                {
                    _DisplayForm.Visible = false;
                }
                g.CopyFromScreen(new Point(0, 0), new Point(0, 0), _ScreenShot.Size);
                g.Flush();
                if (visible)
                {
                    _DisplayForm.Visible = true;
                }
            }
            OnAfterMakingScreenshot();
        }

        /// <summary>
        /// Delegate for the BeforeMakingScreenshot and the AfterMakingScreenshot events
        /// </summary>
        /// <param name="sender">The sending MagnifyingGlass object</param>
        public delegate void MakingScreenshotDelegate(object sender);
        /// <summary>
        /// Fired before making a screenshot
        /// </summary>
        public event MakingScreenshotDelegate BeforeMakingScreenshot;
        /// <summary>
        /// Fired after making a screenshot
        /// </summary>
        public event MakingScreenshotDelegate AfterMakingScreenshot;
        private void OnBeforeMakingScreenshot()
        {
            if (BeforeMakingScreenshot != null)
            {
                BeforeMakingScreenshot(this);
            }
        }
        private void OnAfterMakingScreenshot()
        {
            if (AfterMakingScreenshot != null)
            {
                AfterMakingScreenshot(this);
            }
        }
        #endregion

        private void InitializeComponent()
        {
            this.SuspendLayout();
            // 
            // MagnifyingGlass
            // 
            this.Name = "MagnifyingGlass";
            this.Size = new System.Drawing.Size(300, 150);
            this.Load += new System.EventHandler(this.MagnifyingGlass_Load);
            this.ResumeLayout(false);

        }

        private void MagnifyingGlass_Load(object sender, EventArgs e)
        {

        }
    }

    /// <summary>
    /// A free magnifying glass that follows the cursor
    /// </summary>
    public class MovingMagnifyingGlass : Form
    {
        private MagnifyingGlass _MagnifyingGlass = new MagnifyingGlass(false);

        public MovingMagnifyingGlass()
        {
            Opacity = .75;// Added because it makes things easier
            ShowInTaskbar = false;
            ShowIcon = false;
            FormBorderStyle = FormBorderStyle.None;
            MagnifyingGlass.PixelSize = 10;
            MagnifyingGlass.PixelRange = 5;
            MagnifyingGlass.BackColor = Color.Black;
            MagnifyingGlass.ForeColor = Color.White;
            MagnifyingGlass.UpdateTimer.Interval = 50;
            MagnifyingGlass._DisplayForm = this;
            MagnifyingGlass.FollowCursor = true;
            MagnifyingGlass.BorderStyle = BorderStyle.FixedSingle;
            MagnifyingGlass.Resize += new EventHandler(MagnifyingGlass_Resize);
            MagnifyingGlass.Location = new Point(0, 0);
            Controls.Add(MagnifyingGlass);
            Size = MagnifyingGlass.Size;
            Text = "Moving magnifying glass";
        }

        /// <summary>
        /// Show the window and enable the timer
        /// </summary>
        new public void Show()
        {
            MagnifyingGlass.MakeScreenshot();
            Cursor.Position = new Point(0, 0);
            base.Show();
            MagnifyingGlass.UpdateTimer.Start();
            Cursor.Hide();
        }

        /// <summary>
        /// Hide the window and disable the timer
        /// </summary>
        new public void Hide()
        {
            base.Hide();
            MagnifyingGlass.UpdateTimer.Stop();
            Cursor.Show();
            MagnifyingGlass._ScreenShot.Dispose();
            MagnifyingGlass._ScreenShot = null;
        }

        private void MagnifyingGlass_Resize(object sender, EventArgs e)
        {
            // Always stay as big as the glass
            Size = MagnifyingGlass.Size;
        }

        /// <summary>
        /// The magnifying glass object
        /// </summary>
        [Description("The magnifying glass object")]
        public MagnifyingGlass MagnifyingGlass
        {
            get
            {
                return _MagnifyingGlass;
            }
        }
    }
}


#### FLOODFILTER ####
using System; 
using System.Drawing; 
using System.Drawing.Imaging; 
using System.Drawing.Drawing2D; 
using System.Diagnostics; 
using System.Collections; 
using System.Runtime.InteropServices; 
using System.Threading; 
using System.Windows.Forms;

namespace NTmeasurementplugin
{ 
	using System; 
 
	
	public class FloodFiller : AbstractFloodFiller { 
		 
		private int m_fillcolor=255<<8;
   
		///  
		/// Default constructor - initializes all fields to default values 
		///  
		public FloodFiller() { 
		} 
		 		 
		///initializes the FloodFill operation 
		public override void FloodFill(Bitmap bmp, Point pt) 
		{ 
			 		 
			//get the color's int value, and convert it from RGBA to BGRA format (as GDI+ uses BGRA) 
            m_fillcolor=ColorTranslator.ToWin32(m_fillcolorcolor); 
			m_fillcolor=BGRA(GetB(m_fillcolor),GetG(m_fillcolor),GetR(m_fillcolor),GetA(m_fillcolor)); 
			 
			//get the bits 
            BitmapData bmpData=bmp.LockBits(new Rectangle(0,0,bmp.Width,bmp.Height),ImageLockMode.ReadWrite,PixelFormat.Format32bppArgb); 
			System.IntPtr Scan0 = bmpData.Scan0; 
		     
		    unsafe 
		    { 
		    	//resolve pointer 
		        byte * scan0=(byte *)(void *)Scan0; 
		    	//get the starting color 
		    	//[loc += Y offset + X offset] 
		    	int loc = CoordsToIndex(pt.X,pt.Y,bmpData.Stride);//((bmpData.Stride*(pt.Y-1))+(pt.X*4)); 
		    	int color = *((int*)(scan0+loc)); 
		    	 
		    	//create the array of bools that indicates whether each pixel 
                        //has been checked.  (Should be bitfield, but C# doesn't support bitfields.) 
                        PixelsChecked=new bool[bmpData.Width+1,bmpData.Height+1]; 
		    	 
		    	//do the first call to the loop 
		    	switch(m_FillStyle) 
		    	{ 
		    		case FloodFillStyle.Linear : 
				    	if(m_FillDiagonal) 
				    	{ 
				    		LinearFloodFill8(scan0,pt.X,pt.Y,new Size(bmpData.Width,bmpData.Height),bmpData.Stride,(byte*)&color); 
				    	}else{ 
				    		LinearFloodFill4(scan0,pt.X,pt.Y,new Size(bmpData.Width,bmpData.Height),bmpData.Stride,(byte*)&color); 
				    	} 
				    	break; 
		    		case FloodFillStyle.Queue : 
		    			QueueFloodFill(scan0,pt.X,pt.Y,new Size(bmpData.Width,bmpData.Height),bmpData.Stride,(byte*)&color); 
		    			break; 
		    		case FloodFillStyle.Recursive : 
				    	if(m_FillDiagonal) 
				    	{ 
				    		RecursiveFloodFill8(scan0,pt.X,pt.Y,new Size(bmpData.Width,bmpData.Height),bmpData.Stride,(byte*)&color); 
				    	}else{ 
				    		RecursiveFloodFill4(scan0,pt.X,pt.Y,new Size(bmpData.Width,bmpData.Height),bmpData.Stride,(byte*)&color); 
				    	} 
				    	break; 
		        } 
		    } 
		     
		    bmp.UnlockBits(bmpData); 
		} 
		 
        public override void CalcSPoint(Bitmap bmp)
        {
            CalcSPoint_fc(bmp.Width, bmp.Height);
        }

		//*********** 
		//LINEAR ALGORITHM 
		//*********** 

		unsafe void LinearFloodFill4( byte* scan0, int x, int y,Size bmpsize, int stride, byte* startcolor) 
		{
          
			//offset the pointer to the point passed in 
			int* p=(int*) (scan0+(CoordsToIndex(x,y, stride))); 
			 
			 
			//FIND LEFT EDGE OF COLOR AREA 
			int LFillLoc=x; //the location to check/fill on the left 
			int* ptr=p; //the pointer to the current location 
			while(true) 
			{ 
				ptr[0]=m_fillcolor; 	 //fill with the color 
				PixelsChecked[LFillLoc,y]=true; 
				LFillLoc--; 		 	 //de-increment counter 
				ptr-=1;				 	 //de-increment pointer 
				if(LFillLoc<=0 || !CheckPixel((byte*)ptr,startcolor) ||  (PixelsChecked[LFillLoc,y])) 
					break;			 	 //exit loop if we're at edge of bitmap or color area 
				 
			} 
			LFillLoc++; 
			
 

			//FIND RIGHT EDGE OF COLOR AREA 
			int RFillLoc=x; //the location to check/fill on the left 
			ptr=p; 
			while(true) 
			{ 
				ptr[0]=m_fillcolor; //fill with the color 
				PixelsChecked[RFillLoc,y]=true; 
				RFillLoc++; 		 //increment counter 
				ptr+=1;				 //increment pointer 
				if(RFillLoc>=bmpsize.Width || !CheckPixel((byte*)ptr,startcolor) ||  (PixelsChecked[RFillLoc,y])) 
					break;			 //exit loop if we're at edge of bitmap or color area 
				 
			} 
			RFillLoc--;

            CheckPointsAB(LFillLoc,y, RFillLoc,y);
			 
			//START THE LOOP UPWARDS AND DOWNWARDS			 
			ptr=(int*)(scan0+CoordsToIndex(LFillLoc,y,stride)); 
			for(int i=LFillLoc;i<=RFillLoc;i++) 
			{ 
				//START LOOP UPWARDS 
				//if we're not above the top of the bitmap and the pixel above this one is within the color tolerance 
				if(y>0 && CheckPixel((byte*)(scan0+CoordsToIndex(i,y-1,stride)),startcolor) && (!(PixelsChecked[i,y-1]))) 
					LinearFloodFill4(scan0, i,y-1,bmpsize,stride,startcolor); 
				//START LOOP DOWNWARDS 
				if(y<(bmpsize.Height-1) && CheckPixel((byte*)(scan0+CoordsToIndex(i,y+1,stride)),startcolor) && (!(PixelsChecked[i,y+1]))) 
					LinearFloodFill4(scan0, i,y+1,bmpsize,stride,startcolor); 
				ptr+=1; 
			}

        }

        //*********** 
        //Calc S point
        //*********** 
        unsafe void CalcSPoint_fc(int W, int H)
        {
            #region Prevod masky na obrazke a rotace

                Bitmap bmpp = new Bitmap(W, H);
                BitmapData temp_b = bmpp.LockBits(new Rectangle(0, 0, bmpp.Width, bmpp.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); 
                System.IntPtr Scan0 = temp_b.Scan0;

                unsafe
                {
                    //resolve pointer 
                    byte* scan0 = (byte*)(void*)Scan0;

                    for (int i = 0; i < W; i++)
                    {
                        for (int j = 0; j < H; j++)
                        {
                            if (PixelsChecked[i, j] == true)
                            {
                                scan0[*scan0 + CoordsToIndex(i, j, temp_b.Stride) + 0] = 255; //B
                                scan0[*scan0 + CoordsToIndex(i, j, temp_b.Stride) + 1] = 255; //G
                                scan0[*scan0 + CoordsToIndex(i, j, temp_b.Stride) + 2] = 255; //R
                                scan0[*scan0 + CoordsToIndex(i, j, temp_b.Stride) + 3] = 255; //AlphaPixel
                            }
                         }
                    }
                }

                    bmpp.UnlockBits(temp_b);
                   
            Point o;
            //Potlaceni ztraty obrazu behem otaceni
            if (A.Y<B.Y)
                o=A;
            else
                o=B;

                    bmpp = rotateImage(bmpp, (float)GetNTangle(), o);
                   // pictureBox1.Image = bmpp;
                #endregion

                    #region Nalezeni maxima NT
                    temp_b = bmpp.LockBits(new Rectangle(0, 0, bmpp.Width, bmpp.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
                    Scan0 = temp_b.Scan0;
                        int max_value=0;
                        int max_pos=0;
                    unsafe
                    {
                        //resolve pointer 
                        byte* scan0 = (byte*)(void*)Scan0;
                        
                        int temp;
                      
                        for (int i = 0; i < W; i++)
                        {
                            temp = 0;
                            
                            for (int j = 0; j < H; j++)
                            {

                                if (scan0[*scan0 + CoordsToIndex(i, j, temp_b.Stride) + 0] == 255)
                                { temp++;}
                                else
                                {temp = 0;}

                                if (temp > max_value)
                                {
                                    max_value = temp;
                                    max_pos = i;
                                }
                            }
                        }
                    }
                    bmpp.UnlockBits(temp_b);
                    S = new Point(max_pos, A.Y);
                   
                      Point n = new Point(B.Y - A.Y, A.X - B.X); //normalovy vektor
                      int mx = S.X;
                      int my = S.Y;
                    int q = -(n.X * A.X + n.Y * A.Y); //s=-sum(n.*a);
                    // Rovnice primky px+ry+q=0, kde n=[p r]
                    if (Math.Abs(n.X) < Math.Abs(n.Y)) //horizontalni osa
                        S = (new Point(mx, (Int16)(-1.0 / n.Y * (n.X * mx + q))));
                    else //vertikalni osa
                        S = (new Point((Int16)(-1.0 / n.X * (n.Y * my + q)), my));
                    #endregion
        }


        #region O T H E R S
        unsafe void LinearFloodFill8( byte* scan0, int x, int y,Size bmpsize, int stride, byte* startcolor) //8
		{ 
			 
			//offset the pointer to the point passed in 
			int* p=(int*) (scan0+(CoordsToIndex(x,y, stride))); 
			 
			 
			//FIND LEFT EDGE OF COLOR AREA 
			int LFillLoc=x; //the location to check/fill on the left 
			int* ptr=p; //the pointer to the current location 
			while(true) 
			{ 
				ptr[0]=m_fillcolor; 	 //fill with the color 
				PixelsChecked[LFillLoc,y]=true; 
				LFillLoc--; 		 	 //de-increment counter 
				ptr-=1;				 	 //de-increment pointer 
				if(LFillLoc<=0 || !CheckPixel((byte*)ptr,startcolor) ||  (PixelsChecked[LFillLoc,y])) 
					break;			 	 //exit loop if we're at edge of bitmap or color area 
				 
			} 
			LFillLoc++; 
			 
			//FIND RIGHT EDGE OF COLOR AREA 
			int RFillLoc=x; //the location to check/fill on the left 
			ptr=p; 
			while(true) 
			{ 
				ptr[0]=m_fillcolor; //fill with the color 
				PixelsChecked[RFillLoc,y]=true; 
				RFillLoc++; 		 //increment counter 
				ptr+=1;				 //increment pointer 
				if(RFillLoc>=bmpsize.Width || !CheckPixel((byte*)ptr,startcolor) ||  (PixelsChecked[RFillLoc,y])) 
					break;			 //exit loop if we're at edge of bitmap or color area 
				 
			} 
			RFillLoc--;
            CheckPointsAB(LFillLoc, y, RFillLoc, y);
			 
			//START THE LOOP UPWARDS AND DOWNWARDS			 
			ptr=(int*)(scan0+CoordsToIndex(LFillLoc,y,stride)); 
			for(int i=LFillLoc;i<=RFillLoc;i++) 
			{ 
				//START LOOP UPWARDS 
				//if we're not above the top of the bitmap and the pixel above this one is within the color tolerance 
				//START LOOP DOWNWARDS 
				if(y>0) 
				{ 
					//UP 
					if(CheckPixel((byte*)(scan0+CoordsToIndex(i,y-1,stride)),startcolor) && (!(PixelsChecked[i,y-1]))) 
						LinearFloodFill8(scan0, i,y-1,bmpsize,stride,startcolor); 
					//UP-LEFT 
					if(x>0 && CheckPixel((byte*)(scan0+CoordsToIndex(i-1,y-1,stride)),startcolor) && (!(PixelsChecked[i-1,y-1]))) 
						LinearFloodFill8(scan0, i-1,y-1,bmpsize,stride,startcolor); 
					//UP-RIGHT 
					if(x<(bmpsize.Width-1) && CheckPixel((byte*)(scan0+CoordsToIndex(i+1,y-1,stride)),startcolor) && (!(PixelsChecked[i+1,y-1]))) 
						LinearFloodFill8(scan0, i+1,y-1,bmpsize,stride,startcolor); 
				} 
				 
				if(y<(bmpsize.Height-1))  
				{ 
					//DOWN 
					if(CheckPixel((byte*)(scan0+CoordsToIndex(i,y+1,stride)),startcolor) && (!(PixelsChecked[i,y+1]))) 
						LinearFloodFill8(scan0, i,y+1,bmpsize,stride,startcolor); 
					//DOWN-LEFT 
					if(x>0 && CheckPixel((byte*)(scan0+CoordsToIndex(i-1,y+1,stride)),startcolor) && (!(PixelsChecked[i-1,y+1]))) 
						LinearFloodFill8(scan0, i-1,y+1,bmpsize,stride,startcolor); 
					//UP-RIGHT 
					if(x<(bmpsize.Width-1) && CheckPixel((byte*)(scan0+CoordsToIndex(i+1,y+1,stride)),startcolor) && (!(PixelsChecked[i+1,y+1]))) 
						LinearFloodFill8(scan0, i+1,y+1,bmpsize,stride,startcolor); 
					 
				} 
				 
				ptr+=1; 
			} 
			 
		} 
		 
		//********* 
		//RECURSIVE ALGORITHM 
		//********* 
		 
    	public unsafe void RecursiveFloodFill8(byte* scan0, int x, int y,Size bmpsize, int stride, byte* startcolor) 
    	{ 
			//don't go over the edge 
        	if ((x < 0) || (x >= bmpsize.Width)) return; 
        	if ((y < 0) || (y >= bmpsize.Height)) return; 
    		int* p=(int*) (scan0+(CoordsToIndex(x,y, stride))); 
        	if (!(PixelsChecked[x,y]) && CheckPixel((byte*) p,startcolor))  
        	{ 
				p[0]=m_fillcolor; 	 //fill with the color 
				PixelsChecked[x,y]=true; 
        		 
        		//branch in all 8 directions 
            	RecursiveFloodFill8(scan0,x+1, y,bmpsize,stride, startcolor); 
            	RecursiveFloodFill8(scan0,x, y+1,bmpsize,stride, startcolor); 
            	RecursiveFloodFill8(scan0,x-1, y,bmpsize,stride, startcolor); 
            	RecursiveFloodFill8(scan0,x, y-1,bmpsize,stride, startcolor); 
            	RecursiveFloodFill8(scan0,x+1, y+1,bmpsize,stride, startcolor); 
            	RecursiveFloodFill8(scan0,x-1, y+1,bmpsize,stride, startcolor); 
            	RecursiveFloodFill8(scan0,x-1, y-1,bmpsize,stride, startcolor); 
            	RecursiveFloodFill8(scan0,x+1, y-1,bmpsize,stride, startcolor); 
        	} 
    	} 
 
    	public unsafe void RecursiveFloodFill4(byte* scan0, int x, int y,Size bmpsize, int stride, byte* startcolor) 
    	{ 
			//don't go over the edge 
        	if ((x < 0) || (x >= bmpsize.Width)) return; 
        	if ((y < 0) || (y >= bmpsize.Height)) return; 
    		 
    		//calculate pointer offset 
    		int* p=(int*) (scan0+(CoordsToIndex(x,y, stride))); 
    		 
    		//if the pixel is within the color tolerance, fill it and branch out 
        	if (!(PixelsChecked[x,y]) && CheckPixel((byte*) p,startcolor))  
        	{ 
				p[0]=m_fillcolor; 	 //fill with the color 
				PixelsChecked[x,y]=true; 
        		 
            	RecursiveFloodFill4(scan0,x+1, y,bmpsize,stride, startcolor); 
            	RecursiveFloodFill4(scan0,x, y+1,bmpsize,stride, startcolor); 
            	RecursiveFloodFill4(scan0,x-1, y,bmpsize,stride, startcolor); 
            	RecursiveFloodFill4(scan0,x, y-1,bmpsize,stride, startcolor); 
        	} 
    	} 
		 
		//******** 
		//QUEUE ALGORITHM 
		//******** 
		 
		public unsafe void QueueFloodFill(byte* scan0, int x, int y,Size bmpsize, int stride, byte* startcolor) 
		{ 
			CheckQueue=new Queue(); 
			 
			if(!m_FillDiagonal) 
			{ 
				//start the loop 
				QueueFloodFill4(scan0,x,y,bmpsize,stride,startcolor); 
				//call next item on queue 
				while(CheckQueue.Count>0) 
				{ 
					Point pt=(Point)CheckQueue.Dequeue(); 
					QueueFloodFill4(scan0,pt.X,pt.Y,bmpsize,stride,startcolor); 
				} 
			}else{ 
				//start the loop 
				QueueFloodFill8(scan0,x,y,bmpsize,stride,startcolor); 
				//call next item on queue 
				while(CheckQueue.Count>0) 
				{ 
					Point pt=(Point)CheckQueue.Dequeue(); 
					QueueFloodFill8(scan0,pt.X,pt.Y,bmpsize,stride,startcolor); 
				} 
			} 
		} 
		 
    	public unsafe void QueueFloodFill8(byte* scan0, int x, int y,Size bmpsize, int stride, byte* startcolor) 
    	{ 
			//don't go over the edge 
        	if ((x < 0) || (x >= bmpsize.Width)) return; 
        	if ((y < 0) || (y >= bmpsize.Height)) return; 
    		int* p=(int*) (scan0+(CoordsToIndex(x,y, stride))); 
        	if (!(PixelsChecked[x,y]) && CheckPixel((byte*) p,startcolor))  
        	{ 
				p[0]=m_fillcolor; 	 //fill with the color 
				PixelsChecked[x,y]=true; 
        		 
                        CheckQueue.Enqueue(new Point(x+1,y)); 
        		CheckQueue.Enqueue(new Point(x,y+1)); 
        		CheckQueue.Enqueue(new Point(x-1,y)); 
        		CheckQueue.Enqueue(new Point(x,y-1)); 
				 
                        CheckQueue.Enqueue(new Point(x+1,y+1)); 
        		CheckQueue.Enqueue(new Point(x-1,y-1)); 
        		CheckQueue.Enqueue(new Point(x-1,y+1)); 
        		CheckQueue.Enqueue(new Point(x+1,y-1)); 
        	} 
    	} 
 
    	public unsafe void QueueFloodFill4(byte* scan0, int x, int y,Size bmpsize, int stride, byte* startcolor) 
    	{ 
			//don't go over the edge 
        	if ((x < 0) || (x >= bmpsize.Width)) return; 
        	if ((y < 0) || (y >= bmpsize.Height)) return; 
    		 
    		//calculate pointer offset 
    		int* p=(int*) (scan0+(CoordsToIndex(x,y, stride))); 
    		 
    		//if the pixel is within the color tolerance, fill it and branch out 
        	if (!(PixelsChecked[x,y]) && CheckPixel((byte*) p,startcolor))  
        	{ 
				p[0]=m_fillcolor; 	 //fill with the color 
				PixelsChecked[x,y]=true; 
        		 
				CheckQueue.Enqueue(new Point(x+1,y)); 
        		CheckQueue.Enqueue(new Point(x,y+1)); 
        		CheckQueue.Enqueue(new Point(x-1,y)); 
        		CheckQueue.Enqueue(new Point(x,y-1)); 
        	}
        }
        #endregion
        
        #region H E L P E R   F C
        //********* 
		//HELPER FUNCTIONS 
		//********* 
		 
		/*Sees if a pixel is within the color tolerance range. 
		 * px - a pointer to the pixel to check 
		 * startcolor - a pointer to the color of the pixel we started at */
		unsafe bool CheckPixel(byte* px, byte* startcolor) 
		{ 
                        bool ret=true; 
			for(byte i=0;i<3;i++) 
				ret&= (px[i]>= (startcolor[i]-m_Tolerance[i])) && px[i] <= (startcolor[i]+m_Tolerance[i]);		     
		    return ret; 
		} 
		 
        //Find point AB
        unsafe void CheckPointsAB(int Ax, int Ay, int Bx, int By)
        {
            if (A.X > Ax)
            {
                A.X = Ax;
                A.Y = Ay;
            }

            if (B.X < Bx)
            {
                B.X = Bx;
                B.Y = By;
            }

        }

        //Rotate image
        private Bitmap rotateImage(Bitmap b, float angle, Point o)
        {
            //create a new empty bitmap to hold rotated image
            Bitmap returnBitmap = new Bitmap(b.Width, b.Height);
            //make a graphics object from the empty bitmap
            Graphics g = Graphics.FromImage(returnBitmap);
            //move rotation point to center of image
            g.TranslateTransform((float)o.X, (float)o.Y);
            //rotate
            g.RotateTransform(angle);
            //move image back
            g.TranslateTransform(-(float)o.X, -(float)o.Y);
            //draw passed in image onto graphics object
            g.DrawImage(b, new Point(0, 0));
            return returnBitmap;
        }

		///Given X and Y coordinates and the bitmap's stride, returns a pointer offset 
		int CoordsToIndex(int x, int y, int stride) 
		{ 
			return (stride*y)+(x*4); 
		} 
        #endregion
		 
		 
	} 
 
 
} 

#### ABSTRACT TO FF ####
using System; 
using System.Drawing; 
using System.Drawing.Imaging; 
using System.Drawing.Drawing2D; 
using System.Diagnostics; 
using System.Collections; 
using System.Runtime.InteropServices; 
using System.Threading; 
using System.Windows.Forms;

namespace NTmeasurementplugin
{ 
	using System; 
	 
	public enum FloodFillStyle 
	{ 
		Linear, 
		Queue, 
		Recursive 
	}; 
 	
	public abstract class AbstractFloodFiller : object { 
		 
 
		//private members with public accessors 
 
		protected Color m_fillcolorcolor=Color.Green; 
		protected byte[] m_Tolerance=new byte[]{32,32,32}; 
		protected int m_TimeBenchmark=0; 
		protected FloodFillStyle m_FillStyle=FloodFillStyle.Linear; 
		protected bool m_FillDiagonal=false; 
		protected Bitmap m_Bmp=null; 
		protected Point m_Pt=new Point();

        protected Point A = new Point(9999, 9999);
        protected Point B = new Point(0, 0);
        protected Point S;
        protected double NTangle;

		//private members 
		public bool[,] PixelsChecked;		 
		protected Queue CheckQueue=new Queue(); 
		 
		 
		///  
		/// Default constructor - initializes all fields to default values 
		///  
		public AbstractFloodFiller() { 
		} 
		 
		 
		public Color FillColor 
		{ 
			get 
			{ 
				return m_fillcolorcolor; 
			} 
			set 
			{ 
				m_fillcolorcolor=value; 
			} 
		} 
		 
		public byte[] Tolerance 
		{ 
			get 
			{ 
				return m_Tolerance; 
			} 
			set 
			{ 
				m_Tolerance=value; 
			} 
		} 
		 
		public int TimeBenchmark 
		{ 
			get 
			{ 
				return m_TimeBenchmark; 
			} 
		} 
		 
		public bool FillDiagonal 
		{ 
			get 
			{ 
				return m_FillDiagonal; 
			} 
			set 
			{ 
				m_FillDiagonal=value; 
			} 
		} 
		 
		public FloodFillStyle FillStyle 
		{ 
			get 
			{ 
				return m_FillStyle; 
			} 
			set 
			{ 
				m_FillStyle=value; 
			} 
		} 
		 
		public Bitmap Bmp 
		{ 
			get 
			{ 
				return m_Bmp; 
			} 
			set 
			{ 
				m_Bmp=value; 
			} 
		} 
		 
		public Point Pt 
		{ 
			get 
			{ 
				return m_Pt; 
			} 
			set 
			{ 
				m_Pt=value; 
			} 
		}		 
		 		 
		public void FloodFill() 
		{ 
			Exception ex=null; 
			 
			try 
			{ 
				FloodFill(m_Bmp,m_Pt); 
			}catch(Exception e){ 
				ex=e; 
				OnFillFinished(new FillFinishedEventArgs(ex)); 
				return; 
				 
			} 
			OnFillFinished(new FillFinishedEventArgs(ex)); 
		} 
		 
        //Getting Points ABS
        public Point GetA()
        {
            return A;
        }

        public Point GetB()
        {
            return B;
        }

        public Point GetS()
        {
            return S;
        }

        //Getting NT angle
        public double GetNTangle()
        {
            Point v = new Point(0, 1);
            Point u = new Point(A.X - B.X, B.Y - A.Y);

            double angle = get_angle_between_in_deg(v.X, v.Y, u.X, u.Y);
            return angle;
        }

		//initializes the FloodFill operation 
		public abstract void FloodFill(Bitmap bmp, Point pt);

        public abstract void CalcSPoint(Bitmap bmp);

        private double get_angle_between_in_deg(double ax, double ay, double bx, double by)
        {
            double dotproduct, lengtha, lengthb, result;

            dotproduct = (ax * bx) + (ay * by);
            lengtha = Math.Sqrt(ax * ax + ay * ay);
            lengthb = Math.Sqrt(bx * bx + by * by);

            result = (Math.Acos(dotproduct / (lengtha * lengthb))) * 180 / Math.PI;

            //  if(dotproduct < 0)
            {
                if (result > 0)
                    result -= 90;
                else
                    result += 90;
            }

            return result;
        }

		 
		//************** 
		//COLOR HELPER FUNCTIONS 
		//************** 
		public static byte GetR(int ARGB) 
		{ 
			return LoByte((byte)LoWord(ARGB)); 
			 
		} 
		 
		public static byte GetG(int ARGB) 
		{ 
			return HiByte((short)LoWord(ARGB)); 
			 
		} 
		 
		public static byte GetB(int ARGB) 
		{ 
			return LoByte((byte)HiWord(ARGB)); 
			 
		} 
		 
		public static byte GetA(int ARGB) 
		{ 
			return HiByte((byte)HiWord(ARGB)); 
			 
		} 
 
		public static int RGBA(byte R, byte G, byte B, byte A) 
		{ 
			return (int)(R+(G<<8)+(B<<16)+(A<<24)); 
		} 
 
		public static int RGB(byte R, byte G, byte B) 
		{ 
			return (int)(R+(G<<8)+(B<<16)); 
		} 
		 
		public static int BGRA(byte B, byte G, byte R, byte A) 
		{ 
			return (int)(B+(G<<8)+(R<<16)+(A<<24)); 
		} 
		 
		public static short LoWord(int n) 
		{ 
			return (short)(n & 0xffff); 
		} 
 
		public static short HiWord(int n) 
		{ 
			return (short)((n >> 16) & 0xffff); 
		} 
		 
		public static byte LoByte(short n) 
		{ 
			return (byte)(n & 0xff); 
		} 
 
		public static byte HiByte(short n) 
		{ 
			return (byte)((n >> 8) & 0xff); 
		} 
		 
		 
		//EVENTS/EVENT RAISERS 
		//------------- 
		 
		//raised when a fill operation is finished 
		public event FillFinishedEventHandler FillFinished; 
		protected void OnFillFinished(FillFinishedEventArgs args) 
		{ 
			if(FillFinished!=null) 
				FillFinished.BeginInvoke(this,args,null,null); 
		} 
		 
	} 
 
	public delegate void FillFinishedEventHandler(object sender, FillFinishedEventArgs e); 
	public class FillFinishedEventArgs : EventArgs 
	{ 
		Exception m_exception=null; 
		 
		public FillFinishedEventArgs(Exception e) 
		{ 
			m_exception=e; 
		} 
		 
		public Exception exception 
		{ 
			get 
			{ 
				return m_exception; 
			} 
		} 
	} 
 
}

