-2

I need to make a that scans every pixel on the screen.

I am currently using this:

public static void Spiral()
{

    // starting point
    x = ((int)Math.Floor(Screen.PrimaryScreen.Bounds.Height / 2.0)) - 1;
    y = ((int)Math.Floor(Screen.PrimaryScreen.Bounds.Width / 2.0)) - 1;

    for (int j = Screen.PrimaryScreen.Bounds.Height; j <= 2; k--)
    {
        for (int k = 0; k < (k < (Screen.PrimaryScreen.Bounds.Height - 1) ? 2 : 3); j++)
        {
            for (int i = 0; i < s; i++)
            {
                c++;
            }
            d = (d + 1) % 2;
        }
        s = s + 1;
    }
}

While this works, it only works with even dimensions (eg: 400x400) but for my use case i need to have it support uneven dimensions as well (eg: 1920x1080). I don't know how to alter this algorithm to make that happen.

I hope someone can help me with this since this kinda stuff is hard for me

EDIT: apparently i wasn't clear enough about what the issue is since it got closed? i'll eloborate (i hope it gets reopened soon):

lets say we got this image:

now currently only this part gets detected since the lowest dimension is the only one it can detect:

enter image description here

but i need the algorithm changed to support the whole image regardless if it's squared or not. Hope someone can help me solve this

Neoray
  • 71
  • 1
  • 6
  • 3
    What about it doesn't work with uneven dimensions? – devNull Sep 13 '20 at 02:14
  • For those who are curious, [the image came from this question](https://stackoverflow.com/questions/398299/looping-in-a-spiral). – user3386109 Sep 13 '20 at 03:17
  • 2
    This seemed like a perfectly good question that I was about to post an answer to. I don't understand why it was closed? – Enigmativity Sep 13 '20 at 04:33
  • 1
    I've got an answer waiting to post. I just need some more users to vote to reopen. – Enigmativity Sep 13 '20 at 11:39
  • Seems you only need to put some `Math.min(your_x_coord, max_x_screencoord)` (and the same for Y) into your code. Do that until both coords are out of the screenbounds and you are done. - then loop for both coords till the max value of both. Maybe that gets you onto a path to solve it yourself. – Patrick Artner Sep 13 '20 at 11:43
  • @CodeCaster - I'd love to give the answer that I've got ready to go, but I can't do it until the question is reopened. – Enigmativity Sep 13 '20 at 12:13
  • @Enigmativity I can tell you why I would consider this question incomplete - what's the algorithm? This has a name, it's not a new algorithm. It's a space filling curve, but not the kind used for GIS, and I haven't worked with graphics math for decades. It's almost certain the question of irregular dimensions in graphics processing was answered 40 years ago already, with multiple optimizations for the actual processing. – Panagiotis Kanavos Sep 14 '20 at 07:00
  • @Enigmativity it's also quite possible there's no need for a spiral - a spiral can speed up finding features expected to be near the center of the image, but what if we can just parallelize the operation, eg with PLINQ? Graphics algorithms can be accelerated with SIMD operations too – Panagiotis Kanavos Sep 14 '20 at 07:08
  • Do you need to build a spiral, or find first pixel that is closest to the center? – Antonín Lejsek Sep 14 '20 at 18:06

1 Answers1

0

Let's turn this into a simple sequence of points.

We know that we are going in one of four directions.

var steps = new (int dx, int dy)[] { (1, 0), (0, 1), (-1, 0), (0, -1) };

To create a spiral we move the first direction once, then the second once; then the next two twice, then the next two three times, then the next two four times, etc. If we hit the end of the list we then cycle back to the start. So if we start with n = 0 then we repeat each direction n / 2 + 1 times (knowing that this is integer maths).

Here's my Spiral generator method:

public IEnumerable<Point> Spiral(int x, int y)
{
    yield return new Point(x, y);
    var steps = new(int dx, int dy)[] { (1, 0), (0, 1), (-1, 0), (0, -1) };
    var i = 0;
    var n = 0;
    while (true)
    {
        for (var j = 0; j < n / 2 + 1; j++)
        {
            var (sx, sy) = steps[i];
            x += sx;
            y += sy;
            yield return new Point(x, y);
        }
        if (++i >= steps.Length)
            i = 0;
        n++;
    }
}

The first 50 points (i.e. Spiral(0, 0).Take(50)) are then this:

(0, 0), (1, 0), (1, 1), (0, 1), (-1, 1), (-1, 0), (-1, -1), (0, -1), (1, -1), (2, -1), (2, 0), (2, 1), (2, 2), (1, 2), (0, 2), (-1, 2), (-2, 2), (-2, 1), (-2, 0), (-2, -1), (-2, -2), (-1, -2), (0, -2), (1, -2), (2, -2), (3, -2), (3, -1), (3, 0), (3, 1), (3, 2), (3, 3), (2, 3), (1, 3), (0, 3), (-1, 3), (-2, 3), (-3, 3), (-3, 2), (-3, 1), (-3, 0), (-3, -1), (-3, -2), (-3, -3), (-2, -3), (-1, -3), (0, -3), (1, -3), (2, -3), (3, -3), (4, -3)

Now, it's super easy to generate the spiral you want.

If I assume that you're starting at the middle of the screen, then this is it:

IEnumerable<Point> query =
    Spiral(1920 / 2, 1080 / 2)
        .Where(z => z.X >= 0 && z.X < 1920)
        .Where(z => z.Y >= 0 && z.Y < 1080)
        .Take(1920 * 1080);

If we want to verify with the smaller screen as given in your question, the that looks like this:

IEnumerable<Point> query =
    Spiral(0, 0)
        .Where(z => z.Y >= -1 && z.Y <= 1)
        .Where(z => z.X >= -2 && z.X <= 2)
        .Take(5 * 3);

That gives:

(0, 0), (1, 0), (1, 1), (0, 1), (-1, 1), (-1, 0), (-1, -1), (0, -1), (1, -1), (2, -1), (2, 0), (2, 1), (-2, 1), (-2, 0), (-2, -1)


Here it is wrapped up in a single method:

public static void Spiral()
{
    IEnumerable<Point> SpiralPoints(int x, int y)
    {
        yield return new Point(x, y);
        var steps = new(int dx, int dy)[] { (1, 0), (0, 1), (-1, 0), (0, -1) };
        var i = 0;
        var n = 0;
        while (true)
        {
            for (var j = 0; j < n / 2 + 1; j++)
            {
                var (sx, sy) = steps[i];
                x += sx;
                y += sy;
                yield return new Point(x, y);
            }
            if (++i >= steps.Length)
                i = 0;
            n++;
        }
    }

    var w = Screen.PrimaryScreen.Bounds.Width;
    var h = Screen.PrimaryScreen.Bounds.Height;
    var l = Screen.PrimaryScreen.Bounds.Left;
    var r = Screen.PrimaryScreen.Bounds.Right;
    var t = Screen.PrimaryScreen.Bounds.Top;
    var b = Screen.PrimaryScreen.Bounds.Bottom;

    foreach (Point point in SpiralPoints(w / 2, h / 2)
        .Where(z => z.X >= l && z.X < r)
        .Where(z => z.Y >= t && z.Y < b)
        .Take(w * h))
    {
        /* Do Stuff With Each Point Here */
    }

}
Enigmativity
  • 113,464
  • 11
  • 89
  • 172
  • You can just use the LINQ stuff inside a method and that would do what you want. You can replace the tuple with `Point` very easily - just refactor like normal. – Enigmativity Sep 13 '20 at 22:29
  • Sorry, what did you mean by "point" - did you mean the struct `Point`? – Enigmativity Sep 13 '20 at 22:46
  • @Neoray - it would have been a good idea to include that in the question. :-) – Enigmativity Sep 13 '20 at 23:09
  • @Neoray - I just updated the answer to use `Point`. I hope you can see how I refactored it? – Enigmativity Sep 13 '20 at 23:14
  • @Neoray - Can you explain why you can't use LINQ because of "unsafe code"? – Enigmativity Sep 13 '20 at 23:25
  • @Neoray - No, there's no constraint on that I know of. I just did a test and and `unsafe` block was fine in the `foreach`. – Enigmativity Sep 13 '20 at 23:30
  • @Neoray - Just a side note: You don't need to do `x = ((int)Math.Floor(Screen.PrimaryScreen.Bounds.Width / 2.0)) - 1;` as `x = Screen.PrimaryScreen.Bounds.Width / 2 - 1;` works just the same and is going to prevent any possible rounding error. – Enigmativity Sep 13 '20 at 23:31
  • @Neoray - The algorithm should be quite fast. Can you explain more about detecting things on the outer edge of the screen? – Enigmativity Sep 14 '20 at 00:00
  • @Neoray - I made a change to my ode which halved the execution time for me. It went down from about 184 ms to 79 ms. What are you doing inside the loop? – Enigmativity Sep 14 '20 at 02:49
  • @Enigmativity that's why this question is incomplete. It's certain the actual graphics math problem has multiple solutions and optimizations since the 80s (if not earlier). Simply looking for a color *doesn't* require a spiral either, a simple search of all pixels would be enough, and easy to parallelize. Perhaps the OP is using *convolution* to find the approximate color? Again, no need for spirals, and as Photoshop has done since the 90s, edges can be handled easily, eg by using different weight on the edges, or assuming a neutral value outside the edges. Haven't worked on that for decades – Panagiotis Kanavos Sep 14 '20 at 07:06
  • @Neoray what are you actually trying to do? This looks like image processing - what specific task, algorithm, are you trying to implement? Why use a spiral in the first place if you intend to scan the entire image? Matrix operations are easy to parallelize and accelerate even if you don't use an explicitly parallel algorithm. You could use PLINQ to parallelize processing or SIMD operations through the Vector and Matrix classes to accelerate matrix operations like convolution. – Panagiotis Kanavos Sep 14 '20 at 07:12
  • @PanagiotisKanavos - I agree. On the face of it this was a straight forward question. The problem is when the OP starts introducing new constraints that should have been in the original question. – Enigmativity Sep 14 '20 at 07:32
  • @Neoray - Your question wasn't very clear to start with because you didn't put in enough detail. I managed to get it reopened because I thought I had a good answer to your question. Since answering you've raised a bunch of issues that were not in your question. I suggest that you evaluate my answer based on the question as presented and then post a new question with all of the detail you've now raised. How does that sound? – Enigmativity Sep 14 '20 at 11:38
  • 1
    @Enigmativity I appreciate the time and help you you put into this and your answer was very helpful. i'll definitely mark it as the best answer since it did answer the main problem i had. – Neoray Sep 14 '20 at 12:51