1

Please disregard below; I forgot how integer overflow works >.<

After seeing the incredible answers on this Code Golf question, I thought I might mess around with generating my own images in C#. I stumbled around for a while trying to make an XOR plot and found that directly writing to components (e.g. red = a ^ b) didn't work, but writing trig functions around logarithms around a core a ^ b did; is there any reason for that?

Core color generator (plots an XOR graph):

ColorVec currColor = new ColorVec((float)Math.Sin(Math.Log(j ^ i)),
                                  (float)Math.Cos(Math.Log(j ^ i)),
                                  (float)Math.Tan(Math.Log(i ^ j)));

Constructor for ColorVec:

public ColorVec(float xR, float yG, float zB)
{
    red = xR;
    green = yG;
    blue = zB;
}

Functions to convert between floating-point colors and the eight-bit colors expected by Bitmap:

public byte GetIntRed()
{
   return (byte)(red * 255);
}

public byte GetIntGreen()
{
   return (byte)(green * 255);
}

public byte GetIntBlue()
{
   return (byte)(blue * 255);
}

Program code:

class Program
{
    static void Main(string[] args)
    {
        short width = 2048;
        Random rand = new Random();
        Bitmap imageWriting = new Bitmap(width, width);

        for (short i = 0; i < width; i += 1)
        {
            Console.WriteLine(String.Concat("Working... (writing batch ", i, " of ", width, ")"));

            for (short j = 0; j < width; j += 1)
            {
                ColorVec currColor = new ColorVec((float)Math.Sin(Math.Log(j ^ i)),
                                                  (float)Math.Cos(Math.Log(j ^ i)),
                                                  (float)Math.Tan(Math.Log(i ^ j)));

                imageWriting.SetPixel(i, j, Color.FromArgb(1, currColor.GetIntRed(),
                                                              currColor.GetIntGreen(),
                                                              currColor.GetIntBlue()));
            }
        }

        imageWriting.Save("test.bmp", System.Drawing.Imaging.ImageFormat.Bmp);
    }
}
Paul Ferris
  • 346
  • 5
  • 17
  • Your `Sin/Cos` will also return negative values. Can you show the `GetIntRed()`? – Jeroen van Langen Apr 13 '17 at 11:06
  • Question is not very clear (at least for me). "Classic plots ... were a lot harder to generate", what do you mean by harder? – Evk Apr 13 '17 at 11:32
  • I'd assumed that e.g. I could create an XOR plot by setting each channel to i ^ j or j ^ i (and obviously converting to floats/eight-bit values as appropriate) individually. That didn't work, which meant the actual way to do it was harder than I expected. It's mostly extraneous to the problem, I can take that bit out if you want. – Paul Ferris Apr 13 '17 at 11:37
  • What color does -255 red value have? – Jeroen van Langen Apr 13 '17 at 12:34
  • Serious question? Red is clipped back to zero, the other components are left the way they were. – Paul Ferris Apr 13 '17 at 12:45
  • It was. Clipped? casting to byte does not clip to 0 or to 255. `(byte)-50 = 206`. This is what you meant? – Jeroen van Langen Apr 13 '17 at 13:15
  • ...I forgot that [byte] was an unsigned type. I've gotten too used to signed primitives :P. No, I thought the bitmapper would clip negatives back into the 0..1 range. I didn't really account for integer overflow/underflow at all. – Paul Ferris Apr 13 '17 at 13:25
  • Does this insight change the problem you're facing? – Jeroen van Langen Apr 13 '17 at 18:41
  • It helps. It's definitely starting to seem like I didn't really know what I was doing when I asked this question :P – Paul Ferris Apr 13 '17 at 20:05

1 Answers1

1

I think that question is not very clear, but still will try to provide some thoughts.

So you are trying in some sense to draw a 3D plot: two variables are i and j coodinate and third variable is color. Your function i^j (or any other such function) returns an integer, and now you need to map that integer to some color. This can be done in many ways, most straight-forward is just:

var color = Color.FromArgb(i ^ j); // will produce more clear plot than your way

This will treat one byte of the result as aplha, and 3 others as r\g\b parts. You are using another way, but it does not have any special meaning. Sin, Cos, Tan functons just have range (-1;1), so when you multiply the result by 255 and convert to byte (conversion of negative float to byte also works) - you get a valid color part. Log function is not necessary, but if you apply it - resulting colors will be just different.

Evk
  • 98,527
  • 8
  • 141
  • 191
  • Thanks, but that's not quite what I'm looking for - I was wondering why the sin/log trick works at all. I should have mentioned that it doesn't work if I only calculate the log or only calculate the sin. I have to do both for anything to appear. – Paul Ferris Apr 13 '17 at 12:22
  • That's not true - if I run your code without `Math.Log` (just `Math.Sin(j ^ i)` etc) - it will produce a plot, with different colors (so it's not like there are "nothing" on that plot). – Evk Apr 13 '17 at 12:25
  • Strange... I could have sworn I remembered it the last time I tried that, but I just did it as well and it worked perfectly. I must have made a mistake somewhere and accidentally fixed it afterwards. Is there something I can do when the fundamental reasoning behind my question is way-off and I've realized that it doesn't make any sense? – Paul Ferris Apr 13 '17 at 12:30
  • 1
    Well you can delete it for example. Or edit in a way it starts to make sense :) – Evk Apr 13 '17 at 12:39