/// <summary> /// Draws a rectangle using coordinates of two opposing corners. /// </summary> /// <param name="x1">X-coordinate of first corner.</param> /// <param name="y1">Y-coordinate of first corner.</param> /// <param name="x2">X-coordinate of second corner.</param> /// <param name="y2">Y-coordinate of second corner.</param> /// <param name="ColorAlgorithm">Coloring algorithm to use.</param> /// <param name="PreviousColors">Returns an enumerable set of colors representing the colors overwritten when drawing the rectangle.</param> public static void DrawRectangle(int x1, int y1, int x2, int y2, ProceduralColorAlgorithm ColorAlgorithm, BinaryWriter PreviousColors) { DrawLine(x1, y1, x2, y1, ColorAlgorithm, PreviousColors); DrawLine(x2, y1, x2, y2, ColorAlgorithm, PreviousColors); DrawLine(x2, y2, x1, y2, ColorAlgorithm, PreviousColors); DrawLine(x1, y2, x1, y1, ColorAlgorithm, PreviousColors); }
/// <summary> /// Fills a rectangle using coordinates of two opposing corners. /// </summary> /// <param name="x1">X-coordinate of first corner.</param> /// <param name="y1">Y-coordinate of first corner.</param> /// <param name="x2">X-coordinate of second corner.</param> /// <param name="y2">Y-coordinate of second corner.</param> /// <param name="ColorAlgorithm">Coloring algorithm to use.</param> /// <param name="BackgroundColor">Expected background color</param> /// <param name="Collision">If any of the pixels overwritten by the rectangle is NOT the background color.</param> public static void FillRectangle(int x1, int y1, int x2, int y2, ProceduralColorAlgorithm ColorAlgorithm, Color BackgroundColor, out bool Collision) { Collision = false; if (!ClipBox(ref x1, ref y1, ref x2, ref y2, rasterClipLeft, rasterClipTop, rasterClipRight, rasterClipBottom)) return; bool b; while (y1 <= y2) { DrawScanLine(x1, x2, y1++, ColorAlgorithm, BackgroundColor, out b); Collision |= b; } }
/// <summary> /// Draws a rectangle using coordinates of two opposing corners. /// </summary> /// <param name="x1">X-coordinate of first corner.</param> /// <param name="y1">Y-coordinate of first corner.</param> /// <param name="x2">X-coordinate of second corner.</param> /// <param name="y2">Y-coordinate of second corner.</param> /// <param name="ColorAlgorithm">Coloring algorithm to use.</param> public static void DrawRectangle(int x1, int y1, int x2, int y2, ProceduralColorAlgorithm ColorAlgorithm) { DrawLine(x1, y1, x2, y1, ColorAlgorithm); DrawLine(x2, y1, x2, y2, ColorAlgorithm); DrawLine(x2, y2, x1, y2, ColorAlgorithm); DrawLine(x1, y2, x1, y1, ColorAlgorithm); }
/// <summary> /// Draws a rectangle using coordinates of two opposing corners. /// </summary> /// <param name="x1">X-coordinate of first corner.</param> /// <param name="y1">Y-coordinate of first corner.</param> /// <param name="x2">X-coordinate of second corner.</param> /// <param name="y2">Y-coordinate of second corner.</param> /// <param name="ColorAlgorithm">Coloring algorithm to use.</param> /// <param name="BackgroundColor">Expected background color</param> /// <param name="Collision">If any of the pixels overwritten by the rectangle is NOT the background color.</param> public static void DrawRectangle(int x1, int y1, int x2, int y2, ProceduralColorAlgorithm ColorAlgorithm, Color BackgroundColor, out bool Collision) { bool b; DrawLine(x1, y1, x2, y1, ColorAlgorithm, BackgroundColor, out Collision); DrawLine(x2, y1, x2, y2, ColorAlgorithm, BackgroundColor, out b); Collision |= b; DrawLine(x2, y2, x1, y2, ColorAlgorithm, BackgroundColor, out b); Collision |= b; DrawLine(x1, y2, x1, y1, ColorAlgorithm, BackgroundColor, out b); Collision |= b; }
/// <summary> /// Draws a rounded rectangle using coordinates of two opposing corners. /// </summary> /// <param name="x1">X-coordinate of first corner.</param> /// <param name="y1">Y-coordinate of first corner.</param> /// <param name="x2">X-coordinate of second corner.</param> /// <param name="y2">Y-coordinate of second corner.</param> /// <param name="RadiusX">Radius of the corners of the rounded rectangle, along the X-axis.</param> /// <param name="RadiusY">Radius of the corners of the rounded rectangle, along the Y-axis.</param> /// <param name="ColorAlgorithm">Coloring algorithm to use.</param> /// <param name="PreviousColors">Returns an enumerable set of colors representing the colors overwritten when drawing the rounded rectangle.</param> public static void DrawRoundedRectangle(int x1, int y1, int x2, int y2, int RadiusX, int RadiusY, ProceduralColorAlgorithm ColorAlgorithm, BinaryWriter PreviousColors) { if (RadiusX < 0 || RadiusY < 0) return; int dx, dy, x, y; int dxprim, dyprim; double cx, cy, d1, d2, d3, t, uprim, tprim; Color cl; if (x2 < x1) { dx = x1; x1 = x2; x2 = dx; } if (y2 < y1) { dy = y1; y1 = y2; y2 = dy; } int CenterX1 = x1 + RadiusX; int CenterX2 = x2 - RadiusX; int CenterY1 = y1 + RadiusY; int CenterY2 = y2 - RadiusY; if (CenterX1 + 1 <= CenterX2 - 1) { DrawScanLine(CenterX1 + 1, CenterX2 - 1, y1, ColorAlgorithm, PreviousColors); DrawScanLine(CenterX1 + 1, CenterX2 - 1, y2, ColorAlgorithm, PreviousColors); } if (CenterY1 + 1 <= CenterY2 - 1) { DrawVerticalLine(x1, CenterY1 + 1, CenterY2 - 1, ColorAlgorithm, PreviousColors); DrawVerticalLine(x2, CenterY1 + 1, CenterY2 - 1, ColorAlgorithm, PreviousColors); } cx = 1.0 / (RadiusX * RadiusX + 0.01); cy = 1.0 / (RadiusY * RadiusY + 0.01); if (RadiusX > RadiusY) { dx = -RadiusX; dy = 0; dxprim = dx + 1; dyprim = dy + 1; x = CenterX1 + dx; y = CenterY2 + dy; cl = Raster[x, y]; Raster[x, y] = ColorAlgorithm(x, y, cl); PreviousColors.Write(cl.ToArgb()); x = CenterX1 + dx; y = CenterY1 - dy; cl = Raster[x, y]; Raster[x, y] = ColorAlgorithm(x, y, cl); PreviousColors.Write(cl.ToArgb()); x = CenterX2 - dx; y = CenterY2 + dy; cl = Raster[x, y]; Raster[x, y] = ColorAlgorithm(x, y, cl); PreviousColors.Write(cl.ToArgb()); x = CenterX2 - dx; y = CenterY1 - dy; cl = Raster[x, y]; Raster[x, y] = ColorAlgorithm(x, y, cl); PreviousColors.Write(cl.ToArgb()); t = dx * dx * cx; tprim = dxprim * dxprim * cx; uprim = dyprim * dyprim * cy; do { d1 = Math.Abs(tprim + dy * dy * cy - 1); // Pixel to the right d2 = Math.Abs(tprim + uprim - 1); // Pixel down to the right d3 = Math.Abs(t + uprim - 1); // Pixel downwards if (d1 <= Math.Min(d2, d3)) { dx++; t = tprim; dxprim++; tprim = dxprim * dxprim * cx; } else if (d2 <= Math.Min(d1, d3)) { dx++; dy++; t = tprim; dxprim++; dyprim++; tprim = dxprim * dxprim * cx; uprim = dyprim * dyprim * cy; } else { dy++; dyprim++; uprim = dyprim * dyprim * cy; } x = CenterX1 + dx; y = CenterY2 + dy; cl = Raster[x, y]; Raster[x, y] = ColorAlgorithm(x, y, cl); PreviousColors.Write(cl.ToArgb()); x = CenterX1 + dx; y = CenterY1 - dy; cl = Raster[x, y]; Raster[x, y] = ColorAlgorithm(x, y, cl); PreviousColors.Write(cl.ToArgb()); x = CenterX2 - dx; y = CenterY2 + dy; cl = Raster[x, y]; Raster[x, y] = ColorAlgorithm(x, y, cl); PreviousColors.Write(cl.ToArgb()); x = CenterX2 - dx; y = CenterY1 - dy; cl = Raster[x, y]; Raster[x, y] = ColorAlgorithm(x, y, cl); PreviousColors.Write(cl.ToArgb()); } while (dx < 0); } else { dx = 0; dy = -RadiusY; dxprim = dx + 1; dyprim = dy + 1; x = CenterX2 + dx; y = CenterY1 + dy; cl = Raster[x, y]; Raster[x, y] = ColorAlgorithm(x, y, cl); PreviousColors.Write(cl.ToArgb()); x = CenterX2 + dx; y = CenterY2 - dy; cl = Raster[x, y]; Raster[x, y] = ColorAlgorithm(x, y, cl); PreviousColors.Write(cl.ToArgb()); x = CenterX1 - dx; y = CenterY1 + dy; cl = Raster[x, y]; Raster[x, y] = ColorAlgorithm(x, y, cl); PreviousColors.Write(cl.ToArgb()); x = CenterX1 - dx; y = CenterY2 - dy; cl = Raster[x, y]; Raster[x, y] = ColorAlgorithm(x, y, cl); PreviousColors.Write(cl.ToArgb()); t = dx * dx * cx; tprim = dxprim * dxprim * cx; uprim = dyprim * dyprim * cy; do { d1 = Math.Abs(tprim + dy * dy * cy - 1); // Pixel to the right d2 = Math.Abs(tprim + uprim - 1); // Pixel down to the right d3 = Math.Abs(t + uprim - 1); // Pixel downwards if (d1 <= Math.Min(d2, d3)) { dx++; t = tprim; dxprim++; tprim = dxprim * dxprim * cx; } else if (d2 <= Math.Min(d1, d3)) { dx++; dy++; t = tprim; dxprim++; dyprim++; tprim = dxprim * dxprim * cx; uprim = dyprim * dyprim * cy; } else { dy++; dyprim++; uprim = dyprim * dyprim * cy; } x = CenterX2 + dx; y = CenterY1 + dy; cl = Raster[x, y]; Raster[x, y] = ColorAlgorithm(x, y, cl); PreviousColors.Write(cl.ToArgb()); x = CenterX2 + dx; y = CenterY2 - dy; cl = Raster[x, y]; Raster[x, y] = ColorAlgorithm(x, y, cl); PreviousColors.Write(cl.ToArgb()); x = CenterX1 - dx; y = CenterY1 + dy; cl = Raster[x, y]; Raster[x, y] = ColorAlgorithm(x, y, cl); PreviousColors.Write(cl.ToArgb()); x = CenterX1 - dx; y = CenterY2 - dy; cl = Raster[x, y]; Raster[x, y] = ColorAlgorithm(x, y, cl); PreviousColors.Write(cl.ToArgb()); } while (dy < 0); } }
/// <summary> /// Draws a polygon using an array of coordinates to its nodes. /// </summary> /// <param name="Points">Points in the polygon.</param> /// <param name="ColorAlgorithm">Coloring algorithm to use.</param> /// <param name="PreviousColors">Returns an enumerable set of colors representing the colors overwritten when drawing the polygon.</param> public static void DrawPolygon(Point[] Points, ProceduralColorAlgorithm ColorAlgorithm, BinaryWriter PreviousColors) { int c = Points.Length; if (c <= 1) return; Point Prev = Points[c - 1]; foreach (Point P in Points) { DrawLine(Prev.X, Prev.Y, P.X, P.Y, ColorAlgorithm, PreviousColors); Prev = P; } }
/// <summary> /// Draws a line between (<paramref name="x1"/>,<paramref name="y"/>) and (<paramref name="x2"/>,<paramref name="y"/>), using the color <paramref name="Color"/>. /// </summary> /// <param name="x1">X-coordinate of first point.</param> /// <param name="x2">X-coordinate of second point.</param> /// <param name="y">Y-coordinate.</param> /// <param name="ColorAlgorithm">Coloring algorithm to use.</param> /// <param name="BackgroundColor">Expected background color</param> /// <param name="Collision">If any of the pixels overwritten by the line is NOT the background color.</param> public static void DrawScanLine(int x1, int x2, int y, ProceduralColorAlgorithm ColorAlgorithm, Color BackgroundColor, out bool Collision) { Collision = false; if (!ClipScanLine(ref x1, ref x2, y, rasterClipLeft, rasterClipTop, rasterClipRight, rasterClipBottom)) return; int c = x2 - x1 + 1; int p = y * rasterStride + (x1 << 2); int o = (y / RasterBlockSize) * rasterBlocksX; int p1 = o + (x1 / RasterBlockSize); int p2 = o + (x2 / RasterBlockSize); byte BgR = BackgroundColor.R; byte BgG = BackgroundColor.G; byte BgB = BackgroundColor.B; byte BgA = BackgroundColor.A; byte R, G, B, A; Color Color; while (c-- > 0) { R = raster[p++]; G = raster[p++]; B = raster[p++]; A = raster[p]; p -= 3; Color = Color.FromArgb(A, R, G, B); if (!Collision && Color != BackgroundColor) Collision = true; Color = ColorAlgorithm(x1++, y, Color); R = Color.R; G = Color.G; B = Color.B; A = Color.A; raster[p++] = Color.R; raster[p++] = Color.G; raster[p++] = Color.B; raster[p++] = Color.A; } c = p2 - p1 + 1; while (c-- > 0) rasterBlocks[p1++] = true; }
/// <summary> /// Fills an ellipse /// </summary> /// <param name="CenterX">X-coordinate of the center of the ellipse.</param> /// <param name="CenterY">Y-coordinate of the center of the ellipse.</param> /// <param name="RadiusX">Radius of the ellipse, along the X-axis.</param> /// <param name="RadiusY">Radius of the ellipse, along the Y-axis.</param> /// <param name="ColorAlgorithm">Coloring algorithm to use.</param> /// <param name="BackgroundColor">Expected background color</param> /// <param name="Collision">If any of the pixels overwritten by the ellipse is NOT the background color.</param> public static void FillEllipse(int CenterX, int CenterY, int RadiusX, int RadiusY, ProceduralColorAlgorithm ColorAlgorithm, Color BackgroundColor, out bool Collision) { Collision = false; if (RadiusX < 0 || RadiusY < 0) return; FillRoundedRectangle(CenterX - RadiusX, CenterY - RadiusY, CenterX + RadiusX, CenterY + RadiusY, RadiusX, RadiusY, ColorAlgorithm, BackgroundColor, out Collision); }
/// <summary> /// Draws a line between (<paramref name="x1"/>,<paramref name="y1"/>) and (<paramref name="x2"/>,<paramref name="y2"/>), using the color <paramref name="Color"/>. /// </summary> /// <param name="x1">X-coordinate of first point.</param> /// <param name="y1">Y-coordinate of first point.</param> /// <param name="x2">X-coordinate of second point.</param> /// <param name="y2">Y-coordinate of second point.</param> /// <param name="ColorAlgorithm">Coloring algorithm to use.</param> /// <param name="BackgroundColor">Expected background color</param> /// <param name="Collision">If any of the pixels overwritten by the line is NOT the background color.</param> public static void DrawLine(int x1, int y1, int x2, int y2, ProceduralColorAlgorithm ColorAlgorithm, Color BackgroundColor, out bool Collision) { Collision = false; if (!ClipLine(ref x1, ref y1, ref x2, ref y2, rasterClipLeft, rasterClipTop, rasterClipRight, rasterClipBottom)) return; int dx = x2 - x1; int dy = y2 - y1; int t; double a; double step; Color cl; if (Math.Abs(dx) > Math.Abs(dy)) { if (x2 < x1) { t = x1; x1 = x2; x2 = t; t = y1; y1 = y2; y2 = t; dx = -dx; dy = -dy; } a = y1; step = ((double)dy) / dx; while (x1 <= x2) { t = (int)(a + 0.5); cl = Raster[x1, t]; if (!Collision && (cl != BackgroundColor)) Collision = true; Raster[x1, t] = ColorAlgorithm(x1, t, cl); x1++; a += step; } } else { if (y2 < y1) { t = x1; x1 = x2; x2 = t; t = y1; y1 = y2; y2 = t; dx = -dx; dy = -dy; } a = x1; if (dy == 0) // only occurs if dx==dy==0, i.e. one point. Will cause no error. step = 0; else step = ((double)dx) / dy; while (y1 <= y2) { t = (int)(a + 0.5); cl = Raster[t, y1]; if (!Collision && (cl != BackgroundColor)) Collision = true; Raster[t, y1] = ColorAlgorithm(x1, t, cl); y1++; a += step; } } }
/// <summary> /// Draws a line between (<paramref name="x1"/>,<paramref name="y1"/>) and (<paramref name="x2"/>,<paramref name="y2"/>), using the color <paramref name="Color"/>. /// </summary> /// <param name="x1">X-coordinate of first point.</param> /// <param name="y1">Y-coordinate of first point.</param> /// <param name="x2">X-coordinate of second point.</param> /// <param name="y2">Y-coordinate of second point.</param> /// <param name="ColorAlgorithm">Coloring algorithm to use.</param> /// <param name="PreviousColors">Returns an enumerable set of colors representing the colors overwritten when drawing the line.</param> public static void DrawLine(int x1, int y1, int x2, int y2, ProceduralColorAlgorithm ColorAlgorithm, BinaryWriter PreviousColors) { if (!ClipLine(ref x1, ref y1, ref x2, ref y2, rasterClipLeft, rasterClipTop, rasterClipRight, rasterClipBottom)) return; int dx = x2 - x1; int dy = y2 - y1; int t; double a; double step; Color cl; if (Math.Abs(dx) > Math.Abs(dy)) { if (x2 < x1) { t = x1; x1 = x2; x2 = t; t = y1; y1 = y2; y2 = t; dx = -dx; dy = -dy; } a = y1; step = ((double)dy) / dx; while (x1 <= x2) { t = (int)(a + 0.5); cl = Raster[x1, t]; PreviousColors.Write(cl.ToArgb()); Raster[x1, t] = ColorAlgorithm(x1, t, cl); x1++; a += step; } } else { if (y2 < y1) { t = x1; x1 = x2; x2 = t; t = y1; y1 = y2; y2 = t; dx = -dx; dy = -dy; } a = x1; if (dy == 0) // only occurs if dx==dy==0, i.e. one point. Will cause no error. step = 0; else step = ((double)dx) / dy; while (y1 <= y2) { t = (int)(a + 0.5); cl = Raster[t, y1]; PreviousColors.Write(cl.ToArgb()); Raster[t, y1] = ColorAlgorithm(x1, t, cl); y1++; a += step; } } }
/// <summary> /// Fills an area limited by a boundary different in color from the current pixel. /// </summary> /// <param name="x">X-coordinate where to start.</param> /// <param name="y">Y-coordinate where to start.</param> /// <param name="ColorAlgorithm">Coloring algorithm to use.</param> public static void FillFlood(int x, int y, ProceduralColorAlgorithm ColorAlgorithm) { LinkedList<Point> Queue = new LinkedList<Point>(); Color Bg = Raster[x, y]; Point P; Queue = new LinkedList<Point>(); Queue.AddLast(new Point(x, y)); Raster[x, y] = ColorAlgorithm(x, y, Bg); while (Queue.First != null) { P = Queue.First.Value; Queue.RemoveFirst(); x = P.X; y = P.Y; if (x > rasterClipLeft && Raster[x - 1, y] == Bg) { Raster[x - 1, y] = ColorAlgorithm(x, y, Bg); Queue.AddLast(new Point(x - 1, y)); } if (x < rasterClipRight && Raster[x + 1, y] == Bg) { Raster[x + 1, y] = ColorAlgorithm(x, y, Bg); Queue.AddLast(new Point(x + 1, y)); } if (y > rasterClipTop && Raster[x, y - 1] == Bg) { Raster[x, y - 1] = ColorAlgorithm(x, y, Bg); Queue.AddLast(new Point(x, y - 1)); } if (y < rasterClipBottom && Raster[x, y + 1] == Bg) { Raster[x, y + 1] = ColorAlgorithm(x, y, Bg); Queue.AddLast(new Point(x, y + 1)); } } }
/// <summary> /// Fills a polygon using an array of coordinates to its nodes. /// </summary> /// <param name="Points">Points in the polygon.</param> /// <param name="ColorAlgorithm">Coloring algorithm to use.</param> /// <param name="PreviousColors">Returns an enumerable set of colors representing the colors overwritten when filling the polygon.</param> public static void FillPolygon(Point[] Points, ProceduralColorAlgorithm ColorAlgorithm, BinaryWriter PreviousColors) { LinkedList<int>[] Edges; LinkedList<int> List; int MinY, MaxY; int y; int? PrevX; FindEdges(Points, out MinY, out MaxY, out Edges); for (y = MinY; y <= MaxY; y++) { List = Edges[y]; if (List == null) continue; PrevX = null; foreach (int x in List) { if (PrevX.HasValue) { DrawScanLine(PrevX.Value, x, y, ColorAlgorithm, PreviousColors); PrevX = null; } else PrevX = x; } } }
/// <summary> /// Fills a polygon using an array of coordinates to its nodes. /// </summary> /// <param name="Points">Points in the polygon.</param> /// <param name="ColorAlgorithm">Coloring algorithm to use.</param> /// <param name="BackgroundColor">Expected background color</param> /// <param name="Collision">If any of the pixels overwritten by the polygon is NOT the background color.</param> public static void FillPolygon(Point[] Points, ProceduralColorAlgorithm ColorAlgorithm, Color BackgroundColor, out bool Collision) { LinkedList<int>[] Edges; LinkedList<int> List; int MinY, MaxY; int y; int? PrevX; bool Collision2; FindEdges(Points, out MinY, out MaxY, out Edges); Collision = false; for (y = MinY; y <= MaxY; y++) { List = Edges[y]; if (List == null) continue; PrevX = null; foreach (int x in List) { if (PrevX.HasValue) { DrawScanLine(PrevX.Value, x, y, ColorAlgorithm, BackgroundColor, out Collision2); Collision |= Collision2; PrevX = null; } else PrevX = x; } } }
/// <summary> /// Fills a rectangle using coordinates of two opposing corners. /// </summary> /// <param name="x1">X-coordinate of first corner.</param> /// <param name="y1">Y-coordinate of first corner.</param> /// <param name="x2">X-coordinate of second corner.</param> /// <param name="y2">Y-coordinate of second corner.</param> /// <param name="ColorAlgorithm">Coloring algorithm to use.</param> /// <param name="PreviousColors">Returns an enumerable set of colors representing the colors overwritten when filling the rectangle.</param> public static void FillRectangle(int x1, int y1, int x2, int y2, ProceduralColorAlgorithm ColorAlgorithm, BinaryWriter PreviousColors) { if (!ClipBox(ref x1, ref y1, ref x2, ref y2, rasterClipLeft, rasterClipTop, rasterClipRight, rasterClipBottom)) return; while (y1 <= y2) DrawScanLine(x1, x2, y1++, ColorAlgorithm, PreviousColors); }
/// <summary> /// Draws a line between (<paramref name="x1"/>,<paramref name="y"/>) and (<paramref name="x2"/>,<paramref name="y"/>), using the color <paramref name="Color"/>. /// </summary> /// <param name="x1">X-coordinate of first point.</param> /// <param name="x2">X-coordinate of second point.</param> /// <param name="y">Y-coordinate.</param> /// <param name="ColorAlgorithm">Coloring algorithm to use.</param> /// <param name="PreviousColors">Returns an enumerable set of colors representing the colors overwritten when drawing the line.</param> public static void DrawScanLine(int x1, int x2, int y, ProceduralColorAlgorithm ColorAlgorithm, BinaryWriter PreviousColors) { if (!ClipScanLine(ref x1, ref x2, y, rasterClipLeft, rasterClipTop, rasterClipRight, rasterClipBottom)) return; int c = x2 - x1 + 1; int p = y * rasterStride + (x1 << 2); int o = (y / RasterBlockSize) * rasterBlocksX; int p1 = o + (x1 / RasterBlockSize); int p2 = o + (x2 / RasterBlockSize); byte R, G, B, A; Color Color; while (c-- > 0) { R = raster[p++]; G = raster[p++]; B = raster[p++]; A = raster[p]; p -= 3; Color = Color.FromArgb(A, R, G, B); PreviousColors.Write(Color.ToArgb()); Color = ColorAlgorithm(x1++, y, Color); raster[p++] = Color.R; raster[p++] = Color.G; raster[p++] = Color.B; raster[p++] = Color.A; } c = p2 - p1 + 1; while (c-- > 0) rasterBlocks[p1++] = true; }
/// <summary> /// Draws an ellipse /// </summary> /// <param name="CenterX">X-coordinate of the center of the ellipse.</param> /// <param name="CenterY">Y-coordinate of the center of the ellipse.</param> /// <param name="RadiusX">Radius of the ellipse, along the X-axis.</param> /// <param name="RadiusY">Radius of the ellipse, along the Y-axis.</param> /// <param name="ColorAlgorithm">Coloring algorithm to use.</param> public static void DrawEllipse(int CenterX, int CenterY, int RadiusX, int RadiusY, ProceduralColorAlgorithm ColorAlgorithm) { if (RadiusX < 0 || RadiusY < 0) return; DrawRoundedRectangle(CenterX - RadiusX, CenterY - RadiusY, CenterX + RadiusX, CenterY + RadiusY, RadiusX, RadiusY, ColorAlgorithm); }
/// <summary> /// Draws a line between (<paramref name="x"/>,<paramref name="y1"/>) and (<paramref name="x"/>,<paramref name="y2"/>), using the color <paramref name="Color"/>. /// </summary> /// <param name="x">X-coordinate</param> /// <param name="y1">Y-coordinate of first point.</param> /// <param name="y2">Y-coordinate of second point.</param> /// <param name="ColorAlgorithm">Coloring algorithm to use.</param> /// <param name="BackgroundColor">Expected background color</param> /// <param name="Collision">If any of the pixels overwritten by the line is NOT the background color.</param> public static void DrawVerticalLine(int x, int y1, int y2, ProceduralColorAlgorithm ColorAlgorithm, Color BackgroundColor, out bool Collision) { Collision = false; if (!ClipVerticalLine(x, ref y1, ref y2, rasterClipLeft, rasterClipTop, rasterClipRight, rasterClipBottom)) return; int c = y2 - y1 + 1; int p = y1 * rasterStride + (x << 2); int o = (x / RasterBlockSize); int p1 = (y1 / RasterBlockSize) * rasterBlocksX + o; int p2 = (y2 / RasterBlockSize) * rasterBlocksX + o; int delta = rasterStride - 4; byte BgR = BackgroundColor.R; byte BgG = BackgroundColor.G; byte BgB = BackgroundColor.B; byte BgA = BackgroundColor.A; byte R, G, B, A; Color Color; while (c-- > 0) { R = raster[p++]; G = raster[p++]; B = raster[p++]; A = raster[p]; p -= 3; Color = Color.FromArgb(A, R, G, B); if (!Collision && Color != BackgroundColor) Collision = true; Color = ColorAlgorithm(x, y1++, Color); R = Color.R; G = Color.G; B = Color.B; A = Color.A; raster[p++] = Color.R; raster[p++] = Color.G; raster[p++] = Color.B; raster[p++] = Color.A; p += delta; } while (p1 < p2) { rasterBlocks[p1] = true; p1 += rasterBlocksX; } }
/// <summary> /// Fills an ellipse /// </summary> /// <param name="CenterX">X-coordinate of the center of the ellipse.</param> /// <param name="CenterY">Y-coordinate of the center of the ellipse.</param> /// <param name="RadiusX">Radius of the ellipse, along the X-axis.</param> /// <param name="RadiusY">Radius of the ellipse, along the Y-axis.</param> /// <param name="ColorAlgorithm">Coloring algorithm to use.</param> /// <param name="PreviousColors">Returns an enumerable set of colors representing the colors overwritten when filling the ellipse.</param> public static void FillEllipse(int CenterX, int CenterY, int RadiusX, int RadiusY, ProceduralColorAlgorithm ColorAlgorithm, BinaryWriter PreviousColors) { if (RadiusX < 0 || RadiusY < 0) return; FillRoundedRectangle(CenterX - RadiusX, CenterY - RadiusY, CenterX + RadiusX, CenterY + RadiusY, RadiusX, RadiusY, ColorAlgorithm, PreviousColors); }
/// <summary> /// Draws a line between (<paramref name="x"/>,<paramref name="y1"/>) and (<paramref name="x"/>,<paramref name="y2"/>), using the color <paramref name="Color"/>. /// </summary> /// <param name="x">X-coordinate</param> /// <param name="y1">Y-coordinate of first point.</param> /// <param name="y2">Y-coordinate of second point.</param> /// <param name="ColorAlgorithm">Coloring algorithm to use.</param> /// <param name="PreviousColors">Returns an enumerable set of colors representing the colors overwritten when drawing the line.</param> public static void DrawVerticalLine(int x, int y1, int y2, ProceduralColorAlgorithm ColorAlgorithm, BinaryWriter PreviousColors) { if (!ClipVerticalLine(x, ref y1, ref y2, rasterClipLeft, rasterClipTop, rasterClipRight, rasterClipBottom)) return; int c = y2 - y1 + 1; int p = y1 * rasterStride + (x << 2); int o = (x / RasterBlockSize); int p1 = (y1 / RasterBlockSize) * rasterBlocksX + o; int p2 = (y2 / RasterBlockSize) * rasterBlocksX + o; int delta = rasterStride - 4; byte R, G, B, A; Color Color; while (c-- > 0) { R = raster[p++]; G = raster[p++]; B = raster[p++]; A = raster[p]; p -= 3; Color = Color.FromArgb(A, R, G, B); PreviousColors.Write(Color.ToArgb()); Color = ColorAlgorithm(x, y1++, Color); raster[p++] = Color.R; raster[p++] = Color.G; raster[p++] = Color.B; raster[p++] = Color.A; p += delta; } while (p1 < p2) { rasterBlocks[p1] = true; p1 += rasterBlocksX; } }
/// <summary> /// Fills a rounded rectangle using coordinates of two opposing corners. /// </summary> /// <param name="x1">X-coordinate of first corner.</param> /// <param name="y1">Y-coordinate of first corner.</param> /// <param name="x2">X-coordinate of second corner.</param> /// <param name="y2">Y-coordinate of second corner.</param> /// <param name="RadiusX">Radius of the corners of the rounded rectangle, along the X-axis.</param> /// <param name="RadiusY">Radius of the corners of the rounded rectangle, along the Y-axis.</param> /// <param name="ColorAlgorithm">Coloring algorithm to use.</param> /// <param name="PreviousColors">Returns an enumerable set of colors representing the colors overwritten when filling the rounded rectangle.</param> public static void FillRoundedRectangle(int x1, int y1, int x2, int y2, int RadiusX, int RadiusY, ProceduralColorAlgorithm ColorAlgorithm, BinaryWriter PreviousColors) { if (RadiusX < 0 || RadiusY < 0) return; int dx0; int dx, dy; int dxprim, dyprim; double cx, cy, d1, d2, d3, t, uprim, tprim; if (x2 < x1) { dx = x1; x1 = x2; x2 = dx; } if (y2 < y1) { dy = y1; y1 = y2; y2 = dy; } int CenterX1 = x1 + RadiusX; int CenterX2 = x2 - RadiusX; int CenterY1 = y1 + RadiusY; int CenterY2 = y2 - RadiusY; cx = 1.0 / (RadiusX * RadiusX + 0.01); cy = 1.0 / (RadiusY * RadiusY + 0.01); if (RadiusX > RadiusY) { dx0 = dx = -RadiusX; dy = 0; dxprim = dx + 1; dyprim = dy + 1; t = dx * dx * cx; tprim = dxprim * dxprim * cx; uprim = dyprim * dyprim * cy; do { d1 = Math.Abs(tprim + dy * dy * cy - 1); // Pixel to the right d2 = Math.Abs(tprim + uprim - 1); // Pixel down to the right d3 = Math.Abs(t + uprim - 1); // Pixel downwards if (d1 <= Math.Min(d2, d3)) { dx++; t = tprim; dxprim++; tprim = dxprim * dxprim * cx; } else if (d2 <= Math.Min(d1, d3)) { DrawScanLine(CenterX1 + dx0, CenterX2 - dx0, CenterY2 + dy, ColorAlgorithm, PreviousColors); if (dy > 0 || CenterY1 < CenterY2) DrawScanLine(CenterX1 + dx0, CenterX2 - dx0, CenterY1 - dy, ColorAlgorithm, PreviousColors); dx0 = ++dx; dy++; t = tprim; dxprim++; dyprim++; tprim = dxprim * dxprim * cx; uprim = dyprim * dyprim * cy; } else { DrawScanLine(CenterX1 + dx0, CenterX2 - dx0, CenterY2 + dy, ColorAlgorithm, PreviousColors); if (dy > 0 || CenterY1 < CenterY2) DrawScanLine(CenterX1 + dx0, CenterX2 - dx0, CenterY1 - dy, ColorAlgorithm, PreviousColors); dx0 = dx; dy++; dyprim++; uprim = dyprim * dyprim * cy; } } while (dx < 0); DrawScanLine(CenterX1 + dx0, CenterX2 - dx0, CenterY2 + dy, ColorAlgorithm, PreviousColors); DrawScanLine(CenterX1 + dx0, CenterX2 - dx0, CenterY1 - dy, ColorAlgorithm, PreviousColors); } else { dx = 0; dy = -RadiusY; dxprim = dx + 1; dyprim = dy + 1; t = dx * dx * cx; tprim = dxprim * dxprim * cx; uprim = dyprim * dyprim * cy; do { d1 = Math.Abs(tprim + dy * dy * cy - 1); // Pixel to the right d2 = Math.Abs(tprim + uprim - 1); // Pixel down to the right d3 = Math.Abs(t + uprim - 1); // Pixel downwards if (d1 <= Math.Min(d2, d3)) { dx++; t = tprim; dxprim++; tprim = dxprim * dxprim * cx; } else if (d2 <= Math.Min(d1, d3)) { DrawScanLine(CenterX2 + dx, CenterX1 - dx, CenterY1 + dy, ColorAlgorithm, PreviousColors); DrawScanLine(CenterX2 + dx, CenterX1 - dx, CenterY2 - dy, ColorAlgorithm, PreviousColors); dx++; dy++; t = tprim; dxprim++; dyprim++; tprim = dxprim * dxprim * cx; uprim = dyprim * dyprim * cy; } else { DrawScanLine(CenterX2 + dx, CenterX1 - dx, CenterY1 + dy, ColorAlgorithm, PreviousColors); DrawScanLine(CenterX2 + dx, CenterX1 - dx, CenterY2 - dy, ColorAlgorithm, PreviousColors); dy++; dyprim++; uprim = dyprim * dyprim * cy; } } while (dy < 0); DrawScanLine(CenterX2 + dx, CenterX1 - dx, CenterY1, ColorAlgorithm, PreviousColors); if (CenterY1 < CenterY2) DrawScanLine(CenterX2 + dx, CenterX1 - dx, CenterY2, ColorAlgorithm, PreviousColors); } if (CenterY1 + 1 <= CenterY2 - 1) FillRectangle(x1, CenterY1 + 1, x2, CenterY2 - 1, ColorAlgorithm, PreviousColors); }
/// <summary> /// Draws a polygon using an array of coordinates to its nodes. /// </summary> /// <param name="Points">Points in the polygon.</param> /// <param name="ColorAlgorithm">Coloring algorithm to use.</param> /// <param name="BackgroundColor">Expected background color</param> /// <param name="Collision">If any of the pixels overwritten by the polygon is NOT the background color.</param> public static void DrawPolygon(Point[] Points, ProceduralColorAlgorithm ColorAlgorithm, Color BackgroundColor, out bool Collision) { Collision = false; int c = Points.Length; if (c <= 1) return; Point Prev = Points[c - 1]; bool Collision2; foreach (Point P in Points) { DrawLine(Prev.X, Prev.Y, P.X, P.Y, ColorAlgorithm, BackgroundColor, out Collision2); Collision |= Collision2; Prev = P; } }