Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- namespace simpleLines
- {
- class Program
- {
- #region DRIVER CODE
- const char smiley = '☻';
- static void Main(string[] args)
- {
- Console.ReadKey();
- ConsoleKey escKey;
- while (true)
- {
- Random Rand = new Random();
- Rectangle clipBox = new Rectangle(8, 20, 95, 55);
- Console.ForegroundColor = ConsoleColor.DarkMagenta;
- DrawRect(clipBox);
- Console.ForegroundColor = ConsoleColor.DarkYellow;
- int x1, y1, x2, y2;
- x1 = y1 = x2 = y2 = 0;
- DrawLine(x1, y1, x2, y2, smiley);
- x1 = Rand.Next(0, Console.WindowWidth);
- x2 = Rand.Next(0, Console.WindowWidth);
- while (x2 == x1)
- {
- x2 = Rand.Next(0, Console.WindowWidth);
- }
- y1 = Rand.Next(0, Console.WindowHeight);
- y2 = Rand.Next(0, Console.WindowHeight);
- while (y2 == y1)
- {
- y2 = Rand.Next(0, Console.WindowHeight);
- }
- Console.ForegroundColor = ConsoleColor.Yellow;
- DrawLine(x1, y1, x2, y2, smiley);
- //Console.ReadLine();
- //clipLineAndDraw(x1, y1, x2, y2, smiley, clipBox);
- ClipSegment(clipBox, new PointF(x1, y1), new PointF(x2, y2));
- escKey = Console.ReadKey().Key;
- if (escKey == ConsoleKey.Escape)
- {
- return;
- }
- }
- }
- #endregion
- #region LINE CLIPPING
- [Flags]
- enum OutCode
- {
- Inside = 0,
- Left = 1,
- Right = 2,
- Bottom = 4,
- Top = 8
- }
- private static OutCode ComputeOutCode(float x, float y, Rectangle r)
- {
- var code = OutCode.Inside;
- if (x < r.xmin) code |= OutCode.Left;
- if (x > r.xmax) code |= OutCode.Right;
- if (y < r.ymin) code |= OutCode.Top;
- if (y > r.ymax) code |= OutCode.Bottom;
- return code;
- }
- private static PointF CalculateIntersection(Rectangle r, PointF p1, PointF p2, OutCode clipTo)
- {
- var dx = (p2.X - p1.X);
- var dy = (p2.Y - p1.Y);
- var slopeY = dx / dy; // slope to use for possibly-vertical lines
- var slopeX = dy / dx; // slope to use for possibly-horizontal lines
- if (clipTo.HasFlag(OutCode.Top))
- {
- return new PointF(
- p1.X + slopeY * (r.ymin - p1.Y),
- r.ymin
- );
- }
- if (clipTo.HasFlag(OutCode.Bottom))
- {
- return new PointF(
- p1.X + slopeY * (r.ymax - p1.Y),
- r.ymax
- );
- }
- if (clipTo.HasFlag(OutCode.Right))
- {
- return new PointF(
- r.xmax,
- p1.Y + slopeX * (r.xmax - p1.X)
- );
- }
- if (clipTo.HasFlag(OutCode.Left))
- {
- return new PointF(
- r.xmin,
- p1.Y + slopeX * (r.xmin - p1.X)
- );
- }
- throw new ArgumentOutOfRangeException("clipTo = " + clipTo);
- }
- public static void ClipSegment(Rectangle r, PointF p1, PointF p2)
- {
- // classify the endpoints of the line
- var outCodeP1 = ComputeOutCode(p1.X, p1.Y, r);
- var outCodeP2 = ComputeOutCode(p2.X, p2.Y, r);
- var accept = false;
- while (true)
- { // should only iterate twice, at most
- // Case 1:
- // both endpoints are within the clipping region
- if ((outCodeP1 | outCodeP2) == OutCode.Inside)
- {
- accept = true;
- break;
- }
- // Case 2:
- // both endpoints share an excluded region, impossible for a line between them to be within the clipping region
- if ((outCodeP1 & outCodeP2) != 0)
- {
- break;
- }
- // Case 3:
- // The endpoints are in different regions, and the segment is partially within the clipping rectangle
- // Select one of the endpoints outside the clipping rectangle
- var outCode = outCodeP1 != OutCode.Inside ? outCodeP1 : outCodeP2;
- // calculate the intersection of the line with the clipping rectangle
- var p = CalculateIntersection(r, p1, p2, outCode);
- // update the point after clipping and recalculate outcode
- if (outCode == outCodeP1)
- {
- p1 = p;
- outCodeP1 = ComputeOutCode(p1.X, p1.Y, r);
- }
- else
- {
- p2 = p;
- outCodeP2 = ComputeOutCode(p2.X, p2.Y, r);
- }
- }
- // if clipping area contained a portion of the line
- if (accept)
- {
- Console.ForegroundColor = ConsoleColor.Green;
- DrawLine((int)p1.X, (int)p1.Y, (int)p2.X, (int)p2.Y, smiley);
- Console.ForegroundColor = ConsoleColor.Yellow;
- //return new Tuple<PointF, PointF>(p1, p2);
- }
- // the line did not intersect the clipping area
- return;
- }
- #endregion
- #region RECTANGLE (depends on line drawing)
- public struct Rectangle
- {
- public int xmin, ymin, xmax, ymax;
- public Rectangle(int x_min, int y_min, int x_max, int y_max)
- {
- xmin = x_min;
- ymin = y_min;
- xmax = x_max;
- ymax = y_max;
- }
- }
- static void DrawRect(Rectangle rect)
- {
- DrawLine(rect.xmin, rect.ymin, rect.xmin, rect.ymax + 1, '!');
- DrawLine(rect.xmax, rect.ymin, rect.xmax, rect.ymax + 1, '!');
- DrawLine(rect.xmin, rect.ymin, rect.xmax + 1, rect.ymin, '=');
- DrawLine(rect.xmin, rect.ymax, rect.xmax + 1, rect.ymax, '=');
- }
- #endregion
- #region POINTFLOAT
- public struct PointF
- {
- public float X, Y;
- public PointF(float x, float y)
- {
- X = x;
- Y = y;
- }
- }
- #endregion
- #region LINE DRAWING
- //the language is c#, but optimised for portability with c, hence the lack of maths libraries used and the use of unsafe code
- static unsafe void DrawLine(int FROM_X, int FROM_Y, int TO_X, int TO_Y, char drawchar)
- {
- int WorldWidth = FROM_X - TO_X;
- int WorldHeight = FROM_Y - TO_Y;
- bool LineIsFlipped = ((WorldWidth < 0) != (WorldHeight < 0));
- WorldWidth = WorldWidth < 0 ? -WorldWidth : WorldWidth;
- WorldHeight = WorldHeight < 0 ? -WorldHeight : WorldHeight;
- int WorldPositionX = FROM_X < TO_X ? FROM_X : TO_X;
- int WorldPositionY = FROM_Y < TO_Y ? FROM_Y : TO_Y;
- int * LocalX = WorldWidth > WorldHeight ? &WorldPositionX : &WorldPositionY;
- int * LocalY = WorldWidth < WorldHeight ? &WorldPositionX : &WorldPositionY;
- int * LocalWidth = WorldWidth > WorldHeight ? &WorldWidth : &WorldHeight;
- int * LocalHeight = WorldWidth < WorldHeight ? &WorldWidth : &WorldHeight;
- float SlopeAmount = (float)*LocalHeight / (float)*LocalWidth;
- float SlopeTotal = 0;
- int ReverseLineOffset = LineIsFlipped ? *LocalHeight : 0;
- SlopeAmount = LineIsFlipped ? -SlopeAmount : SlopeAmount;
- int LocalOriginalX = *LocalX;
- int LocalOriginalY = *LocalY;
- if (*LocalWidth == *LocalHeight)
- {
- if (LineIsFlipped)
- {
- for (int i = 0; i < WorldWidth; i++)
- {
- Console.SetCursorPosition((i + WorldWidth) - WorldPositionX, i + WorldPositionY);
- Console.Write(drawchar);
- }
- return;
- }
- else
- {
- for (int i = 0; i < WorldWidth; i++)
- {
- Console.SetCursorPosition(i + WorldPositionX, i + WorldPositionY);
- Console.Write(drawchar);
- }
- return;
- }
- }
- for (int i = 0; i < *LocalWidth; i++)
- {
- *LocalX = LocalOriginalX + i;
- *LocalY = LocalOriginalY + (int)SlopeTotal + ReverseLineOffset;
- SlopeTotal += SlopeAmount;
- Console.SetCursorPosition(WorldPositionX, WorldPositionY);
- Console.Write(drawchar);
- }
- }
- #endregion
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement