using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using System.Diagnostics;

namespace Tutor_RT
{
    public partial class Form1 : Form
    {
        private double xmin, xmax, ymin, ymax;
        private double xFactor, yFactor;
        private Bitmap _backBuffer, HHG;
        V3 ex, ey, ez;
        Camera camera;
        Light light;
        Plane terrain;
        Sphere sphere_1, sphere_2, sphere_3;
        int img_width, img_height;
        List<Object> scene_objects = new List<Object>();
        double ambientlight, fuzzy;

        public Form1()
        {
            InitializeComponent();
            this.DoubleBuffered = true; //otherwise it's flickering
            xmax = 2.5;
            xmin = -2.5;
            //ymax = (xmax - xmin)/1920.0*1200.0;
            ymin = 0;
            ex = new V3(1, 0, 0); ey = new V3(0, 1, 0); ez = new V3(0, 0, 1);
            camera = new Camera(new V3(0, 1.5, +4), ex, ey, ez);
            terrain = new Plane(ey, 0, new Color_0_to_1(1, Color.White));
            scene_objects.Add(terrain);//Index 0
            sphere_1 = new Sphere(1 * ex + 1 * ey - 0.5 * ez, 0.75, new Color_0_to_1(1, Color.DarkGreen));
            scene_objects.Add(sphere_1);//Index 1
            sphere_2 = new Sphere(-1.75 * ex + 1 * ey - 1 * ez, 0.75, new Color_0_to_1(1, Color.Red));
            scene_objects.Add(sphere_2);//Index 2
            sphere_3 = new Sphere(-0.5 * ex + 2 * ey - 1 * ez, 0.75, new Color_0_to_1(1, Color.DarkViolet));
            scene_objects.Add(sphere_3);//Index 3
            light = new Light(-7 * ex + 20 * ey + 10 * ez, new Color_0_to_1(0, Color.WhiteSmoke));
            ambientlight = 0.5;//amount of light from surrounding; 0.1 dark white tiles
            fuzzy = 0.000001;
            HHG = new Bitmap(System.Environment.CurrentDirectory + "\\HHG.png");
            this.Text = "Calculations may take some time"; 
        }

        public int xX(double x)
        {
            return (int)Math.Round(xFactor * (x - xmin));
        }

        public int yY(double y)
        {
            return (int)Math.Round(yFactor * (ymax - y));
        }

        public List<double> find_pt_ob(Ray g)//find intersectionpoint(pt) and the object(ob)
        {//first: calculate all intersections
            List<double> L = new List<double>();//reserve
            L.Add(0); L.Add(0);//L[0]=lambda; L[1]=object index in scene_objects
            for (int n = 0; n < scene_objects.Count; n++)
                L.Add(((AObject)scene_objects[n]).Lambda_min(g));
            L[0] = L.Max(); L[1] = -1;//and then find the closest intersection to the screen
            if (L[0] > 0) //in front of the camera
                for (int n = 2; n < L.Count; n++)
                    if (0 < L[n] && L[n] <= L[0])
                    {//... now we look for smaller ones 
                        L[0] = L[n];
                        L[1] = n - 2;//0:terrain; 1:sphere
                    }//"n - 2": remember L[0] and L[1] are reserved
            return L;
        }

        public void raytracer(Graphics g)
        {
            img_width = this.ClientSize.Width; img_height = this.ClientSize.Height;
            //img_width = 640; img_height = 480;
            ymax = (xmax - xmin) / img_width * img_height;
            xFactor = img_width / (xmax - xmin);
            yFactor = img_height / (ymax - ymin);
            double dx = (xmax - xmin) / img_width, dy = (ymax - ymin) / img_height;
            double x1 = xmin, y1 = ymax;

            for (int x = 0; x < img_width; x++)
            {//ray tracing: how many rays we follow? img_width * img_height rays with its reflections
                for (int y = 0; y < img_height; y++)
                {//Set up a ray from the camera to the screen = image plane
                    Ray h = new Ray(camera.getcampos, new V3(x1, y1, 0) - camera.getcampos);
                    List<double> lambda = find_pt_ob(h);
                    if (lambda[1] == -1)//object is infinity
                        g.FillRectangle(new SolidBrush(Color.Black), xX(x1), yY(y1), 1, 1);
                    else//we hit terrain=plane or a sphere and calculate an appropriate color                   
                    {//determine point of intersection(pti)=initial point for further rays r, v ...
                        V3 pti = h.get_a + h.get_u * lambda[0];//... calculated with u
                        Color_0_to_1 intersection_color = getColorAt(pti, h.get_u, (int)lambda[1]);
                        g.FillRectangle(new SolidBrush(intersection_color.WinColor()), xX(x1), yY(y1), 1, 1);
                    }
                    y1 -= dy;
                }
                x1 += dx;
                y1 = ymax;
            }
        }

        public Color_0_to_1 getColorAt(V3 A, V3 u, int ico)//ico: index of closest object
        {//co is closest object we=eye=camera see; A: initial point; u: u of intersection ray
            Color_0_to_1 co_color;
            //A:--------terrain-HHG-------------------------------------------------------------------------
            if (ico == 0)//only terrain
            {
                int xx = Math.Min(xX(A.X), HHG.Width - 5), yy = Math.Min(xX(A.Z - 0.6), HHG.Height - 5);
                xx = xx < 0 ? 0 : xx; yy = yy < 0 ? 0 : yy;
                co_color = new Color_0_to_1(0, HHG.GetPixel(xx, yy));
            }
            else co_color = ((AObject)scene_objects[ico]).getColor;
            Color_0_to_1 final_color = ambientlight * co_color; //first portion of color
                                                                //B:--------------Color-from-the-r-direction-------------------------------
            V3 co_n = ((AObject)scene_objects[ico]).get_n(A);
            V3 r = u - 2 * co_n * u * co_n;//calculate refection r = u-2*<u,n0>*n0
            if (ico != 0)//except terrain
            {
                List<double> lambda_ref = find_pt_ob(new Ray(A, r));//ray x=A+lam*r hits the scene
                if (lambda_ref[1] != -1)//ray hits plane or sphere
                    if (lambda_ref[0] > fuzzy)
                    {//r only affects the final color if it is reflected from something                       
                        V3 a2 = A + r * lambda_ref[0];//a further intersection point ...
                        double s2 = ((AObject)scene_objects[(int)lambda_ref[1]]).getColor.C01_S;
                        /*recursive-call*/
                        final_color = final_color + s2 * getColorAt(a2, r, (int)lambda_ref[1]);
                    }//...and the second portion of color
            }
            //C:----------Contribution of the light sources
            V3 v = light.get_p - A;
            double cos_alpha = co_n * v.normalize;//<n0,v0> = cos(alpha)*1*1
            if (cos_alpha > 0)//that is if lightsource is in front and not behind(cos<0)
            {
                List<double> lambda2 = find_pt_ob(new Ray(A, v));//ray for shadow or not shadow
                bool noShadow = true;//c = 2, da 0 für lambda u. 1 für obj. reserviert sind
                for (int c = 2; c < lambda2.Count; c++)
                    if (fuzzy < lambda2[c] && lambda2[c] < v.Length)
                    { noShadow = false; break; }
                if (noShadow)
                    final_color = final_color + cos_alpha * co_color * light.getColor;
            }
            //D:----------------reflective-survace-------------
            if (ico != 0)//except terrain
            {
                double cos_beta = r.normalize * v.normalize;
                if (cos_beta > 0)//mirroring
                    final_color = final_color + Math.Pow(cos_beta, 10) * co_color.C01_S * light.getColor;
            }
            return final_color.clip();
        }

        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            _backBuffer = new Bitmap(this.ClientSize.Width, this.ClientSize.Height);
            Cursor.Current = Cursors.WaitCursor;
            Stopwatch dt = new Stopwatch(); dt.Start();
            raytracer(Graphics.FromImage(_backBuffer));
            dt.Stop();
            e.Graphics.DrawImageUnscaled(_backBuffer, 0, 0);//Copy back buffer to screen
            Cursor.Current = Cursors.Default;
            this.Text = "Time of calculation:  dt = " + dt.ElapsedMilliseconds + "ms";
        }
    }
}



namespace Tutor_RT
{
    public class Camera
    {
        //x: this.ClientSize.Width u, y: this.ClientSize.Height u
        public V3 campos, cam_x, cam_y, cam_z;

        #region Constructors

        public Camera()
        {
            campos = new V3();           
            cam_x = new V3();
            cam_y = new V3();
            cam_z = new V3(0, 0, 1);
        }

        public Camera(V3 pos, V3 x_dir, V3 y_dir, V3 z_dir)
        {
            campos = pos;
            cam_x = x_dir;
            cam_y = y_dir;
            cam_z = z_dir;
        }

        public V3 getcampos    //access to A
        {
            get { return campos; }
        }

        public V3 getcam_z    //access to u
        {
            get { return cam_z; }
        }

        public V3 getcam_x    //access to u
        {
            get { return cam_x; }
        }

        public V3 getcam_y    //access to u
        {
            get { return cam_y; }
        }
        #endregion
    }
}

using System;
using System.Drawing;

namespace Tutor_RT
{
    public class Color_0_to_1
    {
        public double special, red, green, blue;
        //special is for superpositions;
        //my color + color from surrounding; reflection, ...
        #region Constructors

        public Color_0_to_1()
        {
            special = 0;
            red = 0;
            green = 0;
            blue = 0;           
        }

        public Color_0_to_1(double s, double r, double g, double b)
        {
            special = s;
            red = r;
            green = g;
            blue = b;           
        }

        public Color_0_to_1(double s, Color col)
        {
            special = s;
            red = col.R / 255.0;
            green = col.G / 255.0;
            blue = col.B / 255.0;
        }

        #endregion

        public double C01_S {
            get { return special; }
            set { special = value; }
        }
        public double C01_R {
            get { return red; }
            set { red = value; }
        }
        public double C01_G {
            get { return green; }
            set { green = value; }
        }
        public double C01_B {
            get { return blue; }
            set { blue = value; }
        }
        
        public double brightness()
        {
            return (red + green + blue) / 3.0;
        }

        public static Color_0_to_1 operator *(double s, Color_0_to_1 c)
        {
            return new Color_0_to_1(s *c.C01_S, s* c.C01_R, s* c.C01_G, s* c.C01_B);
        }

        public static Color_0_to_1 operator +(Color_0_to_1 c1, Color_0_to_1 c2)
        {
            return new Color_0_to_1(c1.C01_S+c2.C01_S, c1.C01_R+c2.C01_R, c1.C01_G+c2.C01_G, c1.C01_B+c2.C01_B);
        }

        public static Color_0_to_1 operator *(Color_0_to_1 c1, Color_0_to_1 c2)
        {
            return new Color_0_to_1(c1.C01_S * c2.C01_S, c1.C01_R * c2.C01_R, c1.C01_G * c2.C01_G, c1.C01_B * c2.C01_B);
        }

        public Color_0_to_1 clip()
        {//distribute a surplus dc
            double rgb_sum = red + green + blue;//rgb_sum = 3 + dc
            double dc = rgb_sum - 3;
            if (dc > 0)
            {
                red = red + dc * (red / rgb_sum);//red-amount from surplus
                green = green + dc * (green / rgb_sum);//green-amount from surplus
                blue = blue + dc * (blue / rgb_sum);//blue-amount from surplus
            }
            red = Math.Max(0, red); red = Math.Min(red, 1);
            green = Math.Max(0, green); green = Math.Min(green, 1);
            blue = Math.Max(0, blue); blue = Math.Min(blue, 1);
            return new Color_0_to_1(special, red, green, blue);
        }

        public Color WinColor()
        {
            return Color.FromArgb(255, (int)Math.Floor(255*red), (int)Math.Floor(255 * green), (int)Math.Floor(255 * blue));
        }
    }
}

namespace Tutor_RT
{
    public class Light : Source
    {
        public V3 position;
        public Color_0_to_1 color;

        #region Constructors

        public Light()
        {
            position = new V3();
            color = new Color_0_to_1(0,1,1,1);
        }

        public Light(V3 pos, Color_0_to_1 col)
        {
            position = pos;
            color = col;
        }

        public override V3 get_p    //access to A
        {
            get { return position; }
        }

        public override Color_0_to_1 getColor    //access to u
        {
            get { return color; }
        }

        #endregion
    }
}

namespace Tutor_RT
{
    public class Plane : AObject
    {
        public V3 normal;//x=a+mue*u+nue*v; <n0,x>-<n0,a>=0=<n0,x>-d_PO
        public double d_PO;//d_PO(plane, A); distance of plane to A
        public Color_0_to_1 color;

        #region Constructors

        public Plane()
        {
            normal = new V3(1,0,0);
            d_PO = 0;
            color = new Color_0_to_1(0,0.5,0.5,0.5);
        }

        public Plane(V3 n, double d, Color_0_to_1 col)
        {
            normal = n.normalize;
            d_PO = d;
            color = col;
        }

        public double get_d_PO //d_PO(plane, A)
        {
            get { return d_PO; }
        }

        public override Color_0_to_1 getColor 
        {
            get { return color; }
        }

        #endregion

        public override V3 get_n(V3 point)    
        {
            return normal;
        }

        public override double Lambda_min(Ray ray)
        {
            double a = ray.get_u * normal;
            if (a == 0) return -1;//b = d_PO * normal 
            else  //r = <n,b-a>/<n,u>, g:x=a+r*u, E:<n,x>-<n,b>=0                
                return normal * (d_PO * normal - ray.get_a) / a;              
        }
    }
}

namespace Tutor_RT
{
    public class Ray
    {
        public V3 A, u;

        #region Constructors

        public Ray()
        {
            A = new V3();
            u = new V3(0,0,1);
        }

        public Ray(V3 o, V3 d)
        {
            A = o;
            u = d.normalize;
        }

        public V3 get_a    
        {
            get { return A; }
        }

        public V3 get_u    
        {
            get { return u; }
        }


        #endregion

        #region Operators

        public override bool Equals(object obj)
        {
            //return this.Equals(obj as Ray);
            return (A == (obj as Ray).A) && (u == (obj as Ray).u);
        }

        public override int GetHashCode()
        {
            return (A.GetHashCode() * u.GetHashCode() + 1);
        }

        public static bool operator ==(Ray r1, Ray r2)
        {
            return r1.Equals(r2);
        }

        public static bool operator !=(Ray r1, Ray r2)
        {
            return !r1.Equals(r2);
        }

        #endregion

        public override string ToString()
        {
            return string.Format("x = {0} + t * {1}", A.Text(), u.Text());
        }

    }
}

namespace Tutor_RT
{
    public abstract class Source
    {
        public Source() { }

        public virtual V3 get_p
        {
            get { return new V3(0, 0, 0); }
        }

        public virtual Color_0_to_1 getColor
        {
            get { return new Color_0_to_1(0, 1, 1, 1); }
        }
    }
}

using System;

namespace Tutor_RT
{
    public class Sphere : AObject
    {
        public V3 center;
        public double radius;
        public Color_0_to_1 color;

        #region Constructors

        public Sphere()
        {
            center = new V3();
            radius = 1;
            color = new Color_0_to_1(0, 0.5, 0.5, 0.5);
        }

        public Sphere(V3 m, double r, Color_0_to_1 col)
        {
            center = m;
            radius = r;
            color = col;
        }

        public V3 get_m    
        {
            get { return center; }
        }

        public double get_r    
        {
            get { return radius; }
        }

        public override Color_0_to_1 getColor    
        {
            get { return color; }
        }

        #endregion

        public override V3 get_n(V3 point)
        {
            V3 n0 = (point - center).normalize;
            return n0;
        }

        public override double Lambda_min(Ray ray)
        {
            //double a = 1; because a=u*u; ray g:x=a+r*u; u is normalized
            double b = 2 * (ray.get_a - get_m) * ray.get_u;
            double c = (ray.get_a - get_m) * (ray.get_a - get_m) - radius*radius;
            //double discriminant = b * b - 4 * a * c;
            double discriminant = b * b - 4 * c;

            if (discriminant > 0)//ray intersects sphere
            {
                //(-b +- sqrt(b^2-4ac))/(2a)
                double r1 = (-b - Math.Sqrt(discriminant)) / 2.0 - 0.0001;//a=1
                if (r1 > 0) return r1;//closest point of intersection
                else
                {//Camera is inside the sphere
                    double r2 = (-b + Math.Sqrt(discriminant)) / 2.0 - 0.0001;
                    return r2;
                }
            } else return -1;//no intersection of ray and sphere
        }
    }
}

using System;
using System.Drawing;

namespace Tutor_RT
{
    public class V3
    {
        public double X;
        public double Y;
        public double Z;

        #region Constructors

        public V3()
        {
            this.X = 0;
            this.Y = 0;
            this.Z = 0;
        }

        public V3(double x, double y, double z)
        {
            this.X = x;
            this.Y = y;
            this.Z = z;
        }

        #endregion

        #region Operators

        public override bool Equals(object obj)
        {
            return this.Equals(obj as V3);
        }

        public override int GetHashCode()
        {
            return ((int)X * 0x1ab) + ((int)Y * 0x1a) + (int)Z + 17;
        }

        public static bool operator ==(V3 v1, V3 v2)
        {
            return v1.X == v2.X && v1.Y == v2.Y && v1.Z == v2.Z;
        }

        public static bool operator !=(V3 v1, V3 v2)
        {
            return !(v1 == v2);
        }

        public static V3 operator +(V3 v1, V3 v2)
        {
            return new V3(v1.X + v2.X, v1.Y + v2.Y, v1.Z + v2.Z);
        }

        public static V3 operator -(V3 v)
        {
            return new V3(-v.X, -v.Y, -v.Z);
        }

        public static V3 operator -(V3 v1, V3 v2)
        {
            return new V3(v1.X - v2.X, v1.Y - v2.Y, v1.Z - v2.Z);
        }

        public static double operator *(V3 v1, V3 v2)
        {
            return v1.X * v2.X + v1.Y * v2.Y + v1.Z * v2.Z;
        }

        public static V3 operator *(V3 v, double factor)
        {
            return new V3(v.X * factor, v.Y * factor, v.Z * factor);
        }

        public static V3 operator *(double factor, V3 v)
        {
            return new V3(v.X * factor, v.Y * factor, v.Z * factor);
        }

        public static V3 operator /(V3 v, double divider)
        {
            return new V3(v.X / divider, v.Y / divider, v.Z / divider);
        }

        public static V3 operator ^(V3 v1, V3 v2)
        {
            return new V3(v1.Y * v2.Z - v2.Y * v1.Z, -(v1.X * v2.Z - v2.X * v1.Z), v1.X * v2.Y - v2.X * v1.Y);
        }

        #endregion

        #region Properties

        public Double Length
        {
            get { return System.Math.Sqrt(X * X + Y * Y + Z * Z); }
        }

        public V3 normalize
        {
            get { return new V3(X / Length, Y / Length, Z / Length); }
        }

        #endregion

        public String Text()
        {
            return System.String.Format("[{0:0.##}/{1:0.##}/{2:0.##}]", X, Y, Z);
        }

        public static int print_v(Graphics g, V3 v, int t_xpos, int t_ypos)
        {//v[row]
            Font fn = new Font("Consolas", 16, FontStyle.Italic);
            Brush br = new SolidBrush(Color.Blue);
            Pen pe = new Pen(Brushes.Blue, 2);
            int i, t_dy = 25, ax = 0, xpos = t_xpos + 10, ypos = t_ypos;
            SizeF SF;
            String precision = "0.###";
            double[] m = new double[] { v.X, v.Y, v.Z };
            //determin text_size of vector
            ax = 0;
            for (i = 0; i < 3; i++)//nr. of row
            {
                SF = g.MeasureString(m[i].ToString(precision), fn);
                if (((int)SF.Width) > ax) ax = (int)SF.Width;
            }
            //print column of the vector
            for (i = 0; i < 3; i++)//nr. of row
            {
                g.DrawString(m[i].ToString(precision), fn, br, xpos, ypos + 6 + t_dy * i);
            }
            xpos += ax;
            g.DrawBezier(pe, new Point(t_xpos + 10, t_ypos + 5), new Point(t_xpos, t_ypos + 10),
                             new Point(t_xpos, t_ypos + 85), new Point(t_xpos + 10, t_ypos + 90));
            g.DrawBezier(pe, new Point(xpos, t_ypos + 5), new Point(xpos + 10, t_ypos + 10),
                             new Point(xpos + 10, t_ypos + 85), new Point(xpos, t_ypos + 90));
            return xpos;
        }

        public static int print_dot(Graphics g, int t_xpos, int t_ypos)
        {
            Font fn = new Font("Consolas", 16, FontStyle.Italic);
            Brush br = new SolidBrush(Color.Blue);
            int xpos = t_xpos + 6, ypos = t_ypos;
            g.DrawString(".", fn, br, xpos, ypos + 26);
            return xpos + 18;
        }

        public static int print_num(Graphics g, double val, int t_xpos, int t_ypos)
        {
            Font fn = new Font("Consolas", 16, FontStyle.Italic);
            Brush br = new SolidBrush(Color.Blue);
            int xpos = t_xpos + 10, ypos = t_ypos;
            g.DrawString(val.ToString("0.###"), fn, br, xpos - 15, ypos + 31);
            return xpos + 10;
        }

        public static int print_dot_prod(Graphics g, V3 u, V3 v, int t_xpos, int t_ypos)
        {
            int x1 = t_xpos, y1 = t_ypos;
            x1 = print_v(g, u, x1, y1);
            x1 = print_dot(g, x1, y1);
            x1 = print_v(g, v, x1, y1);
            x1 = print_equal(g, x1, y1);
            x1 = print_num(g, u * v, x1, y1);
            return x1 + 10;
        }

        public static int print_cross_prod(Graphics g, V3 u, V3 v, int t_xpos, int t_ypos)
        {
            int x1 = t_xpos, y1 = t_ypos;
            x1 = print_v(g, u, x1, y1);
            x1 = print_x(g, x1, y1);
            x1 = print_v(g, v, x1, y1);
            x1 = print_equal(g, x1, y1);
            x1 = print_v(g, u ^ v, x1, y1);
            return x1 + 10;
        }

        public static int print_x(Graphics g, int t_xpos, int t_ypos)
        {
            Font fn = new Font("Consolas", 16, FontStyle.Italic);
            Brush br = new SolidBrush(Color.Blue);
            int xpos = t_xpos + 10, ypos = t_ypos;
            g.DrawString("\x00d7", fn, br, xpos, ypos + 31);
            return xpos + 25;
        }

        public static int print_equal(Graphics g, int t_xpos, int t_ypos)
        {
            Font fn = new Font("Consolas", 16, FontStyle.Italic);
            Brush br = new SolidBrush(Color.Blue);
            int xpos = t_xpos + 10, ypos = t_ypos;
            g.DrawString("=", fn, br, xpos, ypos + 31);
            return xpos + 25;
        }

    }

}

namespace Tutor_RT
{
    public abstract class AObject //AbstractObject
    {
        #region Constructors

        public AObject() { }

        #endregion

        public virtual Color_0_to_1 getColor
        {
            get { return new Color_0_to_1(); }
        }

        public virtual double Lambda_min(Ray ray)
        {
            return 0;
        }

        public virtual V3 get_n(V3 intersection_position)
        {
            return new V3(0, 0, 0);
        }

    }
}

*********************************************************************************
**************************Testprogramm für kreisförmig***************************
*********************************************************************************
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace circular
{
    public partial class Form1 : Form
    {
        private double xmin, xmax, ymin, ymax;
        private double xFactor, yFactor;

        public Form1()
        {
            InitializeComponent();
            xmin = -3; xmax = 3;
            ymin = 0;
        }

        public int xX(double x)
        {
            return (int)Math.Round(xFactor * (x - xmin));
        }

        public int yY(double y)
        {
            return (int)Math.Round(yFactor * (ymax - y));
        }

        public void drawCircle(Graphics g, Color c, int d, double center_x, double center_y, double radius)
        {
            g.DrawEllipse(new Pen(c,d), xX(center_x - radius), yY(center_y + radius), 2 * xX(xmin + radius), 2 * yY(ymax - radius));
        }

        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            ymax = (xmax - xmin) * this.ClientRectangle.Height / this.ClientRectangle.Width;
            xFactor = this.ClientRectangle.Width / (xmax - xmin);
            yFactor = this.ClientRectangle.Height / (ymax - ymin);
            Graphics g = e.Graphics;
            g.Clear(Color.Cornsilk);
            Font fn = new Font("Consolas", 14, FontStyle.Italic);
            Brush br = new SolidBrush(Color.Blue);
            g.DrawString(ymax.ToString(), fn, br, 10, 10);
            g.DrawString(xX(xmin).ToString(), fn, br, 10, 40);
            g.DrawString(yY(ymax).ToString(), fn, br, 10, 70);
            g.DrawLine(new Pen(Color.Black, 1), xX(0), yY(xmin), xX(0), yY(ymax));//yAchse
            for(int i = 1; i < ymax; i++)
                g.DrawLine(new Pen(Color.Black, 1), xX(0-0.1), yY(i), xX(0+0.1), yY(i));//yAchse
            drawCircle(g,Color.Red,1,-2,2.5,0.5); drawCircle(g, Color.Green,5, 2, 2.5, 0.5);
            drawCircle(g, Color.Blue,9, - 2, 0.7, 0.5); drawCircle(g, Color.BlueViolet,13, 2, 0.7, 0.5);
        }
    }
}


