context: //  Copyright (c) 2008, Michael unfried
  //  Email:  serbius3@gmail.com
  //  All rights reserved.
  
  //  Redistribution and use in source and binary forms, with or without modification, 
  //  are permitted provided that the following conditions are met:
  
  //  Redistributions of source code must retain the above copyright notice, 
  //  this list of conditions and the following disclaimer. 
  //  Redistributions in binary form must reproduce the above copyright notice, 
  //  this list of conditions and the following disclaimer in the documentation 
  //  and/or other materials provided with the distribution. 
  
  //  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  //  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  //  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  //  PURPOSE. IT CAN BE DISTRIBUTED FREE OF CHARGE AS LONG AS THIS HEADER 
  //  REMAINS UNCHANGED.
  using System;
  using System.Collections;
  using System.Drawing;
  using System.Drawing.Drawing2D;
  using System.Text;
  using RainstormStudios;
  
  namespace RainstormStudios.Drawing
  {
      /// <summary>
      /// A simple struct for storing a single, two-point line and also provides a number of static methods for performing geometric equations on lines.
      /// </summary>
      public struct Line : ICloneable
      {
          #region Declarations
          //***************************************************************************
          // Public Fields
          // 
          public static readonly Line
              Empty;
          public Point
              PointA, PointB;
          #endregion
  
          #region Public Properties
          //***************************************************************************
          // Public Properties
          // 
          public bool Valid
          { get { return (!PointA.IsEmpty && !PointB.IsEmpty); } }
          public float Slope
          { get { return FindSlope(this); } }
          public int Length
          { get { return FindDistance(this); } }
          public Point MidPoint
          { get { return Line.FindMidPoint(this); } }
          #endregion
  
          #region Class Constructors
          //***************************************************************************
          // Class Constructors
          // 
          public Line(Point a, Point b)
          {
              this.PointA = a;
              this.PointB = b;
          }
          #endregion
  
          #region Public Methods
          //***************************************************************************
          // Public Methods
          // 
          public object Clone()
          {
              return MemberwiseClone();
          }
          public void Clear()
          {
              PointA = Point.Empty;
              PointB = Point.Empty;
          }
          public void Offset(Point value)
          {
              Offset(value.X, value.Y);
          }
          public void Offset(int x, int y)
          {
              PointA.X += x;
              PointA.Y += y;
              PointB.X += x;
              PointB.Y += y;
          }
          public void Rotate(float degree)
          {
              this = Line.Rotate(this, degree);
          }
          public Rectangle GetBounds()
          {
              int left = System.Math.Min(PointA.X, PointB.X);
              int right = System.Math.Max(PointA.X, PointB.X);
              int top = System.Math.Min(PointA.Y, PointB.Y);
              int bottom = System.Math.Max(PointA.Y, PointB.Y);
  
              return Rectangle.FromLTRB(left, top, right, bottom);
          }
          public void Transform(Matrix mat)
          {
              this = Line.Transform(this, mat);
          }
          public double GetTheta(Line val)
          {
              return Line.FindAngle(this, val);
          }
          #endregion
  
          #region Static Methods
          //***************************************************************************
          // Static Methods
          // 
          public static bool IsEmpty(Line value)
          {
              try
              {
                  Point x = value.PointA;
                  Point y = value.PointB;
                  return false;
              }
              catch
              {
                  return true;
              }
          }
          public static float FindSlope(Line val)
          {
              return FindSlope(val.PointA, val.PointB);
          }
          public static float FindSlope(Point val1, Point val2)
          {
              return LineF.FindSlope(new PointF((float)val1.X, (float)val1.Y), new PointF((float)val2.X, (float)val2.Y));
          }
          public static int FindAngle(Line line1, Line line2)
          {
              return (int)FindAngle(line1.PointA, line1.PointB, line2.PointA, line2.PointB);
          }
          public static int FindAngle(Point line1a, Point line1b, Point line2a, Point line2b)
          {
              return (int)FindAngle(
                  FindSlope(line1a, line1b),
                  FindSlope(line2a, line2b));
          }
          /// <summary>Returns the acute angle of where two lines intersect.  The obtuse angle can be determined by "180 - result".</summary>
          /// <param name="slope1">The slope of line1.</param>
          /// <param name="slope2">The slope of line2.</param>
          /// <returns></returns>
          public static double FindAngle(float slope1, float slope2)
          {
              return FindAngleInRadians(slope1, slope2) * (180 / System.Math.PI);
          }
          /// <summary>Returns the acute angle of where two lines intersect.  1 radian = (180/PI).</summary>
          /// <param name="slope1">The slope of line1.</param>
          /// <param name="slope2">The slope of line2.</param>
          /// <returns></returns>
          public static double FindAngleInRadians(float slope1, float slope2)
          {
              return System.Math.Atan((slope2 - slope1) / (1 + (slope1 * slope2)));
          }
          public static int FindDistance(Line val)
          {
              return FindDistance(val.PointA, val.PointB);
          }
          public static int FindDistance(Point p1, Point p2)
          {
              return (int)LineF.FindDistance(new LineF(
                  new PointF((float)p1.X, (float)p1.Y),
                  new PointF((float)p2.X, (float)p2.Y)));
          }
          public static Line Rotate(Line val, float degree)
          {
              LineF r = LineF.Rotate(new LineF(
                  new PointF(val.PointA.X, val.PointA.Y),
                  new PointF(val.PointB.X, val.PointB.Y)), degree);
              return new Line(Point.Round(r.PointA), Point.Round(r.PointB));
          }
          public static Line Transform(Line val, Matrix mat)
          {
              LineF r = LineF.Transform(new LineF(
                  new PointF(val.PointA.X, val.PointA.Y),
                  new PointF(val.PointB.X, val.PointB.Y)), mat);
              return new Line(Point.Round(r.PointA), Point.Round(r.PointB));
          }
          public static Line Round(LineF value)
          {
              return new Line(
                  new Point(
                      (int)System.Math.Round(value.PointA.X),
                      (int)System.Math.Round(value.PointA.Y)),
                  new Point(
                      (int)System.Math.Round(value.PointB.X),
                      (int)System.Math.Round(value.PointB.Y)));
          }
          public static Line Truncate(LineF value)
          {
              return new Line(
                  new Point(
                      (int)System.Math.Truncate(value.PointA.X),
                      (int)System.Math.Truncate(value.PointA.Y)),
                  new Point(
                      (int)System.Math.Truncate(value.PointB.X),
                      (int)System.Math.Truncate(value.PointB.Y)));
          }
          public static Line Ceiling(LineF value)
          {
              return new Line(
                  new Point(
                      (int)System.Math.Ceiling(value.PointA.X),
                      (int)System.Math.Ceiling(value.PointA.Y)),
                  new Point(
                      (int)System.Math.Ceiling(value.PointB.X),
                      (int)System.Math.Ceiling(value.PointB.Y)));
          }
          public static Line Floor(LineF value)
          {
              return new Line(
                  new Point(
                      (int)System.Math.Floor(value.PointA.X),
                      (int)System.Math.Floor(value.PointA.Y)),
                  new Point(
                      (int)System.Math.Floor(value.PointB.X),
                      (int)System.Math.Floor(value.PointB.Y)));
          }
          public static Point FindMidPoint(Line value)
          {
              return Point.Round(LineF.FindMidPoint(new LineF(
                                                  new PointF((float)value.PointA.X, (float)value.PointA.Y),
                                                  new PointF((float)value.PointB.X, (float)value.PointB.Y))));
          }
          #endregion
      }
      /// <summary>
      /// A simple struct for storing a single, two-point line with floating decimal coordinate values and provides a number of static methods for perfoming geometric equations on lines.
      /// </summary>
      public struct LineF : ICloneable
      {
          #region Declarations
          //***************************************************************************
          // Public Fields
          // 
          public static readonly LineF
              Empty;
          public PointF
              PointA, PointB;
          #endregion
  
          #region Public Properties
          //***************************************************************************
          // Public Properties
          // 
          public bool Valid
          { get { return (!PointA.IsEmpty && !PointB.IsEmpty); } }
          public float Slope
          { get { return FindSlope(this); } }
          public float Length
          { get { return FindDistance(this); } }
          public PointF MidPoint
          { get { return LineF.FindMidPoint(this); } }
          #endregion
  
          #region Class Constructors
          //***************************************************************************
          // Class Constructors
          // 
          public LineF(PointF a, PointF b)
          {
              this.PointA = a;
              this.PointB = b;
          }
          #endregion
  
          #region Public Methods
          //***************************************************************************
          // Public Methods
          // 
          public object Clone()
          {
              return MemberwiseClone();
          }
          public void Clear()
          {
              this.PointA = Point.Empty;
              this.PointB = Point.Empty;
          }
          public void Offset(PointF value)
          {
              Offset(value.X, value.Y);
          }
          public void Offset(float x, float y)
          {
              this.PointA.X += x;
              this.PointA.Y += y;
              this.PointB.X += x;
              this.PointB.Y += y;
          }
          public void Rotate(float degree)
          {
  
gt:             LineF r = Rotate(this, degree);