|
1 |
| -using System; |
| 1 | +using System; |
2 | 2 | using System.Collections.Generic;
|
3 | 3 | using System.Drawing;
|
4 |
| -using System.Numerics; |
5 | 4 |
|
6 |
| -namespace Algorithms.Other |
| 5 | +namespace Algorithms.Other; |
| 6 | + |
| 7 | +/// <summary> |
| 8 | +/// Flood fill, also called seed fill, is an algorithm that determines and |
| 9 | +/// alters the area connected to a given node in a multi-dimensional array with |
| 10 | +/// some matching attribute. It is used in the "bucket" fill tool of paint |
| 11 | +/// programs to fill connected, similarly-colored areas with a different color. |
| 12 | +/// (description adapted from https://en.wikipedia.org/wiki/Flood_fill) |
| 13 | +/// (see also: https://www.techiedelight.com/flood-fill-algorithm/). |
| 14 | +/// </summary> |
| 15 | +public static class FloodFill |
7 | 16 | {
|
| 17 | + private static readonly List<(int xOffset, int yOffset)> Neighbors = new() { (-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1) }; |
| 18 | + |
8 | 19 | /// <summary>
|
9 |
| - /// Flood fill, also called seed fill, is an algorithm that determines and |
10 |
| - /// alters the area connected to a given node in a multi-dimensional array with |
11 |
| - /// some matching attribute. It is used in the "bucket" fill tool of paint |
12 |
| - /// programs to fill connected, similarly-colored areas with a different color. |
13 |
| - /// (description adapted from https://en.wikipedia.org/wiki/Flood_fill) |
14 |
| - /// (see also: https://www.techiedelight.com/flood-fill-algorithm/). |
| 20 | + /// Implements the flood fill algorithm through a breadth-first approach using a queue. |
15 | 21 | /// </summary>
|
16 |
| - public static class FloodFill |
| 22 | + /// <param name="bitmap">The bitmap to which the algorithm is applied.</param> |
| 23 | + /// <param name="location">The start location on the bitmap.</param> |
| 24 | + /// <param name="targetColor">The old color to be replaced.</param> |
| 25 | + /// <param name="replacementColor">The new color to replace the old one.</param> |
| 26 | + public static void BreadthFirstSearch(Bitmap bitmap, (int x, int y) location, Color targetColor, Color replacementColor) |
17 | 27 | {
|
18 |
| - private static readonly List<(int xOffset, int yOffset)> Neighbors = new() { (-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1) }; |
19 |
| - |
20 |
| - /// <summary> |
21 |
| - /// Implements the flood fill algorithm through a breadth-first approach using a queue. |
22 |
| - /// </summary> |
23 |
| - /// <param name="bitmap">The bitmap to which the algorithm is applied.</param> |
24 |
| - /// <param name="location">The start location on the bitmap.</param> |
25 |
| - /// <param name="targetColor">The old color to be replaced.</param> |
26 |
| - /// <param name="replacementColor">The new color to replace the old one.</param> |
27 |
| - public static void BreadthFirstSearch(Bitmap bitmap, (int x, int y) location, Color targetColor, Color replacementColor) |
| 28 | + if (location.x < 0 || location.x >= bitmap.Width || location.y < 0 || location.y >= bitmap.Height) |
28 | 29 | {
|
29 |
| - if (location.x < 0 || location.x >= bitmap.Width || location.y < 0 || location.y >= bitmap.Height) |
30 |
| - { |
31 |
| - throw new ArgumentOutOfRangeException(nameof(location), $"{nameof(location)} should point to a pixel within the bitmap"); |
32 |
| - } |
| 30 | + throw new ArgumentOutOfRangeException(nameof(location), $"{nameof(location)} should point to a pixel within the bitmap"); |
| 31 | + } |
33 | 32 |
|
34 |
| - var queue = new List<(int x, int y)>(); |
35 |
| - queue.Add(location); |
| 33 | + var queue = new List<(int x, int y)>(); |
| 34 | + queue.Add(location); |
36 | 35 |
|
37 |
| - while (queue.Count > 0) |
38 |
| - { |
39 |
| - BreadthFirstFill(bitmap, location, targetColor, replacementColor, queue); |
40 |
| - } |
| 36 | + while (queue.Count > 0) |
| 37 | + { |
| 38 | + BreadthFirstFill(bitmap, location, targetColor, replacementColor, queue); |
41 | 39 | }
|
| 40 | + } |
42 | 41 |
|
43 |
| - /// <summary> |
44 |
| - /// Implements the flood fill algorithm through a depth-first approach through recursion. |
45 |
| - /// </summary> |
46 |
| - /// <param name="bitmap">The bitmap to which the algorithm is applied.</param> |
47 |
| - /// <param name="location">The start location on the bitmap.</param> |
48 |
| - /// <param name="targetColor">The old color to be replaced.</param> |
49 |
| - /// <param name="replacementColor">The new color to replace the old one.</param> |
50 |
| - public static void DepthFirstSearch(Bitmap bitmap, (int x, int y) location, Color targetColor, Color replacementColor) |
| 42 | + /// <summary> |
| 43 | + /// Implements the flood fill algorithm through a depth-first approach through recursion. |
| 44 | + /// </summary> |
| 45 | + /// <param name="bitmap">The bitmap to which the algorithm is applied.</param> |
| 46 | + /// <param name="location">The start location on the bitmap.</param> |
| 47 | + /// <param name="targetColor">The old color to be replaced.</param> |
| 48 | + /// <param name="replacementColor">The new color to replace the old one.</param> |
| 49 | + public static void DepthFirstSearch(Bitmap bitmap, (int x, int y) location, Color targetColor, Color replacementColor) |
| 50 | + { |
| 51 | + if (location.x < 0 || location.x >= bitmap.Width || location.y < 0 || location.y >= bitmap.Height) |
51 | 52 | {
|
52 |
| - if (location.x < 0 || location.x >= bitmap.Width || location.y < 0 || location.y >= bitmap.Height) |
53 |
| - { |
54 |
| - throw new ArgumentOutOfRangeException(nameof(location), $"{nameof(location)} should point to a pixel within the bitmap"); |
55 |
| - } |
56 |
| - |
57 |
| - DepthFirstFill(bitmap, location, targetColor, replacementColor); |
| 53 | + throw new ArgumentOutOfRangeException(nameof(location), $"{nameof(location)} should point to a pixel within the bitmap"); |
58 | 54 | }
|
59 | 55 |
|
60 |
| - private static void BreadthFirstFill(Bitmap bitmap, (int x, int y) location, Color targetColor, Color replacementColor, List<(int x, int y)> queue) |
| 56 | + DepthFirstFill(bitmap, location, targetColor, replacementColor); |
| 57 | + } |
| 58 | + |
| 59 | + private static void BreadthFirstFill(Bitmap bitmap, (int x, int y) location, Color targetColor, Color replacementColor, List<(int x, int y)> queue) |
| 60 | + { |
| 61 | + (int x, int y) currentLocation = queue[0]; |
| 62 | + queue.RemoveAt(0); |
| 63 | + |
| 64 | + if (bitmap.GetPixel(currentLocation.x, currentLocation.y) == targetColor) |
61 | 65 | {
|
62 |
| - (int x, int y) currentLocation = queue[0]; |
63 |
| - queue.RemoveAt(0); |
| 66 | + bitmap.SetPixel(currentLocation.x, currentLocation.y, replacementColor); |
64 | 67 |
|
65 |
| - if (bitmap.GetPixel(currentLocation.x, currentLocation.y) == targetColor) |
| 68 | + for (int i = 0; i < Neighbors.Count; i++) |
66 | 69 | {
|
67 |
| - bitmap.SetPixel(currentLocation.x, currentLocation.y, replacementColor); |
68 |
| - |
69 |
| - for (int i = 0; i < Neighbors.Count; i++) |
| 70 | + int x = currentLocation.x + Neighbors[i].xOffset; |
| 71 | + int y = currentLocation.y + Neighbors[i].yOffset; |
| 72 | + if (x >= 0 && x < bitmap.Width && y >= 0 && y < bitmap.Height) |
70 | 73 | {
|
71 |
| - int x = currentLocation.x + Neighbors[i].xOffset; |
72 |
| - int y = currentLocation.y + Neighbors[i].yOffset; |
73 |
| - if (x >= 0 && x < bitmap.Width && y >= 0 && y < bitmap.Height) |
74 |
| - { |
75 |
| - queue.Add((x, y)); |
76 |
| - } |
| 74 | + queue.Add((x, y)); |
77 | 75 | }
|
78 | 76 | }
|
79 | 77 | }
|
| 78 | + } |
80 | 79 |
|
81 |
| - private static void DepthFirstFill(Bitmap bitmap, (int x, int y) location, Color targetColor, Color replacementColor) |
| 80 | + private static void DepthFirstFill(Bitmap bitmap, (int x, int y) location, Color targetColor, Color replacementColor) |
| 81 | + { |
| 82 | + if (bitmap.GetPixel(location.x, location.y) == targetColor) |
82 | 83 | {
|
83 |
| - if (bitmap.GetPixel(location.x, location.y) == targetColor) |
84 |
| - { |
85 |
| - bitmap.SetPixel(location.x, location.y, replacementColor); |
| 84 | + bitmap.SetPixel(location.x, location.y, replacementColor); |
86 | 85 |
|
87 |
| - for (int i = 0; i < Neighbors.Count; i++) |
| 86 | + for (int i = 0; i < Neighbors.Count; i++) |
| 87 | + { |
| 88 | + int x = location.x + Neighbors[i].xOffset; |
| 89 | + int y = location.y + Neighbors[i].yOffset; |
| 90 | + if (x >= 0 && x < bitmap.Width && y >= 0 && y < bitmap.Height) |
88 | 91 | {
|
89 |
| - int x = location.x + Neighbors[i].xOffset; |
90 |
| - int y = location.y + Neighbors[i].yOffset; |
91 |
| - if (x >= 0 && x < bitmap.Width && y >= 0 && y < bitmap.Height) |
92 |
| - { |
93 |
| - DepthFirstFill(bitmap, (x, y), targetColor, replacementColor); |
94 |
| - } |
| 92 | + DepthFirstFill(bitmap, (x, y), targetColor, replacementColor); |
95 | 93 | }
|
96 | 94 | }
|
97 | 95 | }
|
|
0 commit comments