Blob Blame Raw
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
using System.Collections.Generic;

namespace Faraday {
    public class MainWindow : Form {
        static public void Main() { Application.Run(new MainWindow()); }

		double tangentLength = 1000.0;
		double normalLength = 50.0;
		double pointRadius = 4.0;

		double targetX = 0.0;
		double targetY = 0.0;

		double aaRadius = 25.0;
		double radiusX = 400.0;
		double radiusY = 100.0;

		public MainWindow() {
            Paint += OnPaint;
			MouseMove += OnMouseMove;
            WindowState = FormWindowState.Maximized;
        }

        public void OnPaint(Object sender, PaintEventArgs e) {
            Draw(e.Graphics);
        }

        public void OnMouseMove(Object sender, MouseEventArgs e) {
			targetX = e.X - 0.5*ClientSize.Width;
			targetY = e.Y - 0.5*ClientSize.Height;
			Invalidate();
        }

        public void Draw(Graphics g) {
            g.Clear(Color.White);
			g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;

			double centerX = 0.5*ClientSize.Width;
			double centerY = 0.5*ClientSize.Height;

			g.DrawEllipse(
				Pens.Gray,
				(float)(centerX - radiusX),
				(float)(centerY - radiusY),
				(float)(2.0*radiusX),
				(float)(2.0*radiusY));

			g.FillEllipse(
				Brushes.Blue,
				(float)(centerX + targetX - pointRadius),
				(float)(centerY + targetY - pointRadius),
				(float)(2.0*pointRadius),
				(float)(2.0*pointRadius));

			if (Math.Abs(targetX) > 0.0 || Math.Abs(targetY) > 0.0) {
				double targetL = Math.Sqrt(
					targetY*targetY +
					targetX*targetX);
				double targetNormX = targetX/targetL;
				double targetNormY = targetY/targetL;

				g.DrawLine(
					Pens.Black,
					(float)centerX,
					(float)centerY,
					(float)(centerX + tangentLength*targetNormX),
					(float)(centerY + tangentLength*targetNormY));

				double crossL = Math.Sqrt(
					targetY*targetY*radiusX*radiusX +
					targetX*targetX*radiusY*radiusY);
				double crossX = targetX*radiusX*radiusY/crossL;
				double crossY = targetY*radiusX*radiusY/crossL;

				g.FillEllipse(
					Brushes.Blue,
					(float)(centerX + crossX - pointRadius),
					(float)(centerY + crossY - pointRadius),
					(float)(2.0*pointRadius),
					(float)(2.0*pointRadius));

				double tangentL = Math.Sqrt(
					targetY*targetY*radiusX*radiusX*radiusX*radiusX +
					targetX*targetX*radiusY*radiusY*radiusY*radiusY);
				double tangentX = targetY*radiusX*radiusX/tangentL;
				double tangentY = -targetX*radiusY*radiusY/tangentL;

				g.DrawLine(
					Pens.Blue,
					(float)(centerX + crossX - tangentX*tangentLength),
					(float)(centerY + crossY - tangentY*tangentLength),
					(float)(centerX + crossX + tangentX*tangentLength),
					(float)(centerY + crossY + tangentY*tangentLength));

				double normalX = -tangentY;
				double normalY = tangentX;

				g.DrawLine(
					Pens.Blue,
					(float)(centerX + crossX),
					(float)(centerY + crossY),
					(float)(centerX + crossX + normalX*normalLength),
					(float)(centerY + crossY + normalY*normalLength));

				double dot = normalX*targetNormX + normalY*targetNormY;
				double aa = aaRadius/dot;
				//double aaX = aa*targetNormX;
				//double aaY = aa*targetNormY;

				double dotInv =
					tangentL/(targetX*targetX*radiusY*radiusY + targetY*targetY*radiusX*radiusX);
				double aaX = aaRadius*targetX*dotInv;
				double aaY = aaRadius*targetY*dotInv;

				g.DrawLine(
					Pens.Red,
					(float)(centerX + targetX - aaX),
					(float)(centerY + targetY - aaY),
					(float)(centerX + targetX + aaX),
					(float)(centerY + targetY + aaY));
				g.FillEllipse(
					Brushes.Red,
					(float)(centerX + targetX - aaX - pointRadius),
					(float)(centerY + targetY - aaY - pointRadius),
					(float)(2.0*pointRadius),
					(float)(2.0*pointRadius));
				g.FillEllipse(
					Brushes.Red,
					(float)(centerX + targetX + aaX - pointRadius),
					(float)(centerY + targetY + aaY - pointRadius),
					(float)(2.0*pointRadius),
					(float)(2.0*pointRadius));
			}
        }
    }
}