Advertisement
Guest User

LineDrawAndClip 2

a guest
Oct 23rd, 2018
93
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 9.43 KB | None | 0 0
  1. using System;
  2.  
  3. namespace simpleLines
  4. {
  5.     class Program
  6.     {
  7.  
  8.         #region DRIVER CODE
  9.         const char smiley = '☻';
  10.         static void Main(string[] args)
  11.         {
  12.             Console.ReadKey();
  13.             ConsoleKey escKey;
  14.             while (true)
  15.             {
  16.                 Random Rand = new Random();
  17.                 Rectangle clipBox = new Rectangle(8, 20, 95, 55);
  18.                 Console.ForegroundColor = ConsoleColor.DarkMagenta;
  19.                 DrawRect(clipBox);
  20.                 Console.ForegroundColor = ConsoleColor.DarkYellow;
  21.  
  22.                 int x1, y1, x2, y2;
  23.                 x1 = y1 = x2 = y2 = 0;
  24.                 DrawLine(x1, y1, x2, y2, smiley);
  25.  
  26.                 x1 = Rand.Next(0, Console.WindowWidth);
  27.                 x2 = Rand.Next(0, Console.WindowWidth);
  28.  
  29.                 while (x2 == x1)
  30.                 {
  31.                     x2 = Rand.Next(0, Console.WindowWidth);
  32.                 }
  33.                 y1 = Rand.Next(0, Console.WindowHeight);
  34.                 y2 = Rand.Next(0, Console.WindowHeight);
  35.                 while (y2 == y1)
  36.                 {
  37.                     y2 = Rand.Next(0, Console.WindowHeight);
  38.                 }
  39.                 Console.ForegroundColor = ConsoleColor.Yellow;
  40.  
  41.                 DrawLine(x1, y1, x2, y2, smiley);
  42.                 //Console.ReadLine();
  43.                 //clipLineAndDraw(x1, y1, x2, y2, smiley, clipBox);
  44.                 ClipSegment(clipBox, new PointF(x1, y1), new PointF(x2, y2));
  45.                 escKey = Console.ReadKey().Key;
  46.                 if (escKey == ConsoleKey.Escape)
  47.                 {
  48.                     return;
  49.                 }
  50.             }
  51.         }
  52.         #endregion
  53.  
  54.         #region LINE CLIPPING
  55.  
  56.         [Flags]
  57.         enum OutCode
  58.         {
  59.             Inside = 0,
  60.             Left = 1,
  61.             Right = 2,
  62.             Bottom = 4,
  63.             Top = 8
  64.         }
  65.  
  66.  
  67.  
  68.         private static OutCode ComputeOutCode(float x, float y, Rectangle r)
  69.         {
  70.             var code = OutCode.Inside;
  71.             if (x < r.xmin) code |= OutCode.Left;
  72.             if (x > r.xmax) code |= OutCode.Right;
  73.             if (y < r.ymin) code |= OutCode.Top;
  74.             if (y > r.ymax) code |= OutCode.Bottom;
  75.             return code;
  76.         }
  77.  
  78.         private static PointF CalculateIntersection(Rectangle r, PointF p1, PointF p2, OutCode clipTo)
  79.         {
  80.             var dx = (p2.X - p1.X);
  81.             var dy = (p2.Y - p1.Y);
  82.  
  83.             var slopeY = dx / dy; // slope to use for possibly-vertical lines
  84.             var slopeX = dy / dx; // slope to use for possibly-horizontal lines
  85.  
  86.             if (clipTo.HasFlag(OutCode.Top))
  87.             {
  88.                 return new PointF(
  89.                     p1.X + slopeY * (r.ymin - p1.Y),
  90.                     r.ymin
  91.                     );
  92.             }
  93.             if (clipTo.HasFlag(OutCode.Bottom))
  94.             {
  95.                 return new PointF(
  96.                     p1.X + slopeY * (r.ymax - p1.Y),
  97.                     r.ymax
  98.                     );
  99.             }
  100.             if (clipTo.HasFlag(OutCode.Right))
  101.             {
  102.                 return new PointF(
  103.                     r.xmax,
  104.                     p1.Y + slopeX * (r.xmax - p1.X)
  105.                     );
  106.             }
  107.             if (clipTo.HasFlag(OutCode.Left))
  108.             {
  109.                 return new PointF(
  110.                     r.xmin,
  111.                     p1.Y + slopeX * (r.xmin - p1.X)
  112.                     );
  113.             }
  114.             throw new ArgumentOutOfRangeException("clipTo = " + clipTo);
  115.         }
  116.  
  117.         public static void ClipSegment(Rectangle r, PointF p1, PointF p2)
  118.         {
  119.             // classify the endpoints of the line
  120.             var outCodeP1 = ComputeOutCode(p1.X, p1.Y, r);
  121.             var outCodeP2 = ComputeOutCode(p2.X, p2.Y, r);
  122.             var accept = false;
  123.  
  124.             while (true)
  125.             { // should only iterate twice, at most
  126.               // Case 1:
  127.               // both endpoints are within the clipping region
  128.                 if ((outCodeP1 | outCodeP2) == OutCode.Inside)
  129.                 {
  130.                     accept = true;
  131.                     break;
  132.                 }
  133.  
  134.                 // Case 2:
  135.                 // both endpoints share an excluded region, impossible for a line between them to be within the clipping region
  136.                 if ((outCodeP1 & outCodeP2) != 0)
  137.                 {
  138.                     break;
  139.                 }
  140.  
  141.                 // Case 3:
  142.                 // The endpoints are in different regions, and the segment is partially within the clipping rectangle
  143.  
  144.                 // Select one of the endpoints outside the clipping rectangle
  145.                 var outCode = outCodeP1 != OutCode.Inside ? outCodeP1 : outCodeP2;
  146.  
  147.                 // calculate the intersection of the line with the clipping rectangle
  148.                 var p = CalculateIntersection(r, p1, p2, outCode);
  149.  
  150.                 // update the point after clipping and recalculate outcode
  151.                 if (outCode == outCodeP1)
  152.                 {
  153.                     p1 = p;
  154.                     outCodeP1 = ComputeOutCode(p1.X, p1.Y, r);
  155.                 }
  156.                 else
  157.                 {
  158.                     p2 = p;
  159.                     outCodeP2 = ComputeOutCode(p2.X, p2.Y, r);
  160.                 }
  161.             }
  162.             // if clipping area contained a portion of the line
  163.             if (accept)
  164.             {
  165.                 Console.ForegroundColor = ConsoleColor.Green;
  166.  
  167.                 DrawLine((int)p1.X, (int)p1.Y, (int)p2.X, (int)p2.Y, smiley);
  168.                 Console.ForegroundColor = ConsoleColor.Yellow;
  169.  
  170.                 //return new Tuple<PointF, PointF>(p1, p2);
  171.             }
  172.  
  173.             // the line did not intersect the clipping area
  174.             return;
  175.         }
  176.  
  177.         #endregion
  178.         #region RECTANGLE (depends on line drawing)
  179.         public struct Rectangle
  180.         {
  181.             public int xmin, ymin, xmax, ymax;
  182.             public Rectangle(int x_min, int y_min, int x_max, int y_max)
  183.             {
  184.                 xmin = x_min;
  185.                 ymin = y_min;
  186.                 xmax = x_max;
  187.                 ymax = y_max;
  188.             }
  189.         }
  190.         static void DrawRect(Rectangle rect)
  191.         {
  192.             DrawLine(rect.xmin, rect.ymin, rect.xmin, rect.ymax + 1, '!');
  193.             DrawLine(rect.xmax, rect.ymin, rect.xmax, rect.ymax + 1, '!');
  194.             DrawLine(rect.xmin, rect.ymin, rect.xmax + 1, rect.ymin, '=');
  195.             DrawLine(rect.xmin, rect.ymax, rect.xmax + 1, rect.ymax, '=');
  196.         }
  197.         #endregion
  198.         #region POINTFLOAT
  199.  
  200.         public struct PointF
  201.         {
  202.             public float X, Y;
  203.             public PointF(float x, float y)
  204.             {
  205.                 X = x;
  206.                 Y = y;
  207.             }
  208.         }
  209.  
  210.         #endregion
  211.         #region LINE DRAWING
  212.         //the language is c#, but optimised for portability with c, hence the lack of maths libraries used and the use of unsafe code
  213.         static unsafe void DrawLine(int FROM_X, int FROM_Y, int TO_X, int TO_Y, char drawchar)
  214.         {
  215.             int     WorldWidth = FROM_X - TO_X;
  216.             int     WorldHeight = FROM_Y - TO_Y;
  217.             bool    LineIsFlipped = ((WorldWidth < 0) != (WorldHeight < 0));
  218.             WorldWidth      =   WorldWidth < 0 ? -WorldWidth : WorldWidth;
  219.             WorldHeight     =   WorldHeight < 0 ? -WorldHeight : WorldHeight;
  220.             int     WorldPositionX = FROM_X < TO_X ? FROM_X : TO_X;
  221.             int     WorldPositionY = FROM_Y < TO_Y ? FROM_Y : TO_Y;
  222.             int  *  LocalX  =   WorldWidth > WorldHeight ? &WorldPositionX : &WorldPositionY;
  223.             int  *  LocalY  =   WorldWidth < WorldHeight ? &WorldPositionX : &WorldPositionY;
  224.             int  *  LocalWidth  =   WorldWidth > WorldHeight ? &WorldWidth : &WorldHeight;
  225.             int  *  LocalHeight =   WorldWidth < WorldHeight ? &WorldWidth : &WorldHeight;
  226.             float   SlopeAmount         = (float)*LocalHeight / (float)*LocalWidth;
  227.             float   SlopeTotal          = 0;
  228.             int     ReverseLineOffset   = LineIsFlipped ? *LocalHeight : 0;
  229.                     SlopeAmount         = LineIsFlipped ? -SlopeAmount : SlopeAmount;
  230.             int LocalOriginalX = *LocalX;
  231.             int LocalOriginalY = *LocalY;
  232.             if (*LocalWidth == *LocalHeight)
  233.             {
  234.                 if (LineIsFlipped)
  235.                 {
  236.                     for (int i = 0; i < WorldWidth; i++)
  237.                     {
  238.                         Console.SetCursorPosition((i + WorldWidth) - WorldPositionX, i + WorldPositionY);
  239.                         Console.Write(drawchar);
  240.                     }
  241.                     return;
  242.                 }
  243.                 else
  244.                 {
  245.                     for (int i = 0; i < WorldWidth; i++)
  246.                     {
  247.                         Console.SetCursorPosition(i + WorldPositionX, i + WorldPositionY);
  248.                         Console.Write(drawchar);
  249.                     }
  250.                     return;
  251.                 }
  252.             }
  253.             for (int i = 0; i < *LocalWidth; i++)
  254.             {
  255.                 *LocalX = LocalOriginalX + i;
  256.                 *LocalY = LocalOriginalY + (int)SlopeTotal + ReverseLineOffset;
  257.                 SlopeTotal += SlopeAmount;
  258.                 Console.SetCursorPosition(WorldPositionX, WorldPositionY);
  259.                 Console.Write(drawchar);
  260.             }
  261.         }
  262.         #endregion
  263.     }
  264. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement