How to (make a ) scale for C# in a panel? - c#

Hi im new to c# and I am trying to learn how to (make a) scale in a panel. I have created a Mandelbrot, but now I have to zoom in on -2 to 2 in both axes.
My question is, how do I make a scale (e.g x,y 0.01) for this panel in which I can choose the center of the panel myself? I want my graph to go from -2 to 2 in both axes. I know I should be using Graphics.ScaleTransform to scale it and e.Graphics.TranslateTransform to center it, but I just can't figure out how.
This is my panel method :
public void panel1_Paint(object sender, PaintEventArgs e)
{
for (double p = 0; p < 400; p++)
{
for (double j = 0; j < 400; j++)
//over here I zoomed it in manually, but it was just to make sure the Mandelbrot was working
{
int mandel = mandelgetalberekening((p - 200)*0.01, (j-200)*0.01);
if (mandel % 2 == 0)
{
e.Graphics.FillRectangle(Brushes.Purple, (float)p, (float)j, 1, 1);
}
else
{
e.Graphics.FillRectangle(Brushes.White, (float)p, (float)j, 1, 1);
}
}
}
and if I try to use something like this I just gives me an empty window:
public void panel1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.ScaleTransform((float)0.01, (float)0.01);
for (double p = 0; p < 400; p++)
{
for (double j = 0; j < 400; j++)
{
int mandel = mandelgetalberekening((p - 200)*0.01, (j-200)*0.01);
if (mandel % 2 == 0)
{
e.Graphics.FillRectangle(Brushes.Purple, (float)p, (float)j, 1, 1);
}
else
{
e.Graphics.FillRectangle(Brushes.White, (float)p, (float)j, 1, 1);
}
}
}
``

Related

How to loop picturebox going left inifnity

I'm making a slideshow image and the direction of images is going left.
Now my problem is how can I make it an infinite loop? Once the last image appears, I want to show again the first image up to the last image again. How can I make this? Heres my code:
PictureBox[] clouds = new PictureBox[4];
public Form2()
{
InitializeComponent();
}
private void Form2_Load(object sender, EventArgs e)
{
speed = 3;
clouds[0] = pictureBox1;
clouds[1] = pictureBox2;
clouds[2] = pictureBox3;
clouds[3] = pictureBox4;
}
private void timer1_Tick(object sender, EventArgs e)
{
for (int x = 0; x < 4; x++)
{
clouds[x].Left -= 10;
if (clouds[x].Left == 0)
{
clouds[x].Left = +this.Width;
}
}
}
If I understand you right, you want
0, 1, 2, 3, 0, 1, 2, 3, 0, ...
sequence. It can be implemented as
// x = 0 - start with x = 0
// - no condition (infinte loop)
// x = (x + 1) %4 - modulo arithemetics: 0, 1, 2, 3, 0, 1, 2, 3, 0 ....
for (int x = 0; ; x = (x + 1) % 4) {
...
}
In general case for clouds[] array we can get rid of magic number 4
for (int x = 0; ; x = (x + 1) % array.Length) {
...
}

Edge Detection on 2d Black color rectangle with white Background

I am trying to find the edges of black color rectangle with white background, but I don't know how to find the edges of rectangle.
Code so far is:
private void Vicky(object sender, MouseEventArgs e)
{
OpenFileDialog file = new OpenFileDialog();
if (file.ShowDialog() == DialogResult.OK)
{
pictureBox1.Image = new Bitmap(file.FileName);
}
}
private void process(object sender, EventArgs e)
{
Bitmap bmp = new Bitmap(pictureBox1.Image);
for (int i = 0; i < bmp.Width; i++)
{
for (int j = 0; j < bmp.Height; j++)
{
Color pixelColor = bmp.GetPixel(i, j);
if (pixelColor.R == 0 && pixelColor.G == 0 && pixelColor.B == 0)
{
for (int x = i; x < bmp.Width; x++)
{
for (int y = x; y < bmp.Height; y++)
{
}
}
} // end if.
} // end inner for.
} //end outer for.
pictureBox1.Image = bmp;
} //end process.
Can't you just go to all 4 directions until you find a pixel that is not white?
int left, right, top, bottom;
for (int x = i; x < bmp.Width; x++)
{
Color c = bmp.GetPixel(x, y);
if (c.R != 0 || c.G != 0 || c.B != 0) {
right = x;
break;
}
}
for (int x = i; x > 0; x--)
{
Color c = bmp.GetPixel(x, y);
if (c.R != 0 || c.G != 0 || c.B != 0) {
left = x;
break;
}
}
// ... Two more loops for top and bottom
If you are sure edges are 1px wide and straight you could test bmp.GetPixel(i+1, j); and bmp.GetPixel(i, j+1); for blackness. That would mean you have top left corner. Then simply continue on both sides to determine width and height.
btw, you had 2 extra } in your code. Considering one was for closing the class, the other one was probably causing your code not to compile.

Slow Line drawing in GDI+

I'm completely new to Winforms and GDI+, I come from a WPF background. Using the simple code below to draw 1000 Lines I noticed that it doesn't draw the Lines at once like WPF does. It is slow and the process of drawing is actually noticable. Am I missing something in the code below?
private void button1_Click(object sender, EventArgs e)
{
Graphics g;
g = CreateGraphics();
var pn = new Pen(Color.Wheat, 1);
var x = 0;
var y = 0;
var n = 0;
while (n < 1000)
{
x = x + 5;
if (x > 1200)
{
x = 0;
y = y + 15;
}
g.DrawLine(pn, x, y, x, y + 10);
n++;
}
}

Cell-Based Liquid Simulation: Local pressure model?

I'm attempting to add semi-realistic water into my tile-based, 2D platformer. The water must act somewhat lifelike, with a pressure model that runs entirely local. (IE. Can only use data from cells near it) This model is needed because of the nature of my game, where you cannot be certain that the data you need isn't inside an area that isn't in memory.
I've tried one method so far, but I could not refine it enough to work with my constraints.
For that model, each cell would be slightly compressible, depending on the amount of water in the above cell. When a cell's water content was larger than the normal capacity, the cell would try to expand upwards. This created a fairly nice simulation, abeit slow (Not lag; Changes in the water were taking a while to propagate.), at times. When I tried to implement this into my engine, I found that my limitations lacked the precision required for it to work. I can provide a more indepth explanation or a link to the original concept if you wish.
My constraints:
Only 256 discrete values for water level. (No floating point variables :( ) -- EDIT. Floats are fine.
Fixed grid size.
2D Only.
U-Bend Configurations must work.
The language that I'm using is C#, but I can probably take other languages and translate it to C#.
The question is, can anyone give me a pressure model for water, following my constraints as closely as possible?
How about a different approach?
Forget about floats, that's asking for roundoff problems in the long run. Instead, how about a unit of water?
Each cell contains a certain number of units of water. Each iteration you compare the cell with it's 4 neighbors and move say 10% (change this to alter the propagation speed) of the difference in the number of units of water. A mapping function translates the units of water into a water level.
To avoid calculation order problems use two values, one for the old units, one for the new. Calculate everything and then copy the updated values back. 2 ints = 8 bytes per cell. If you have a million cells that's still only 8mb.
If you are actually trying to simulate waves you'll need to also store the flow--4 values, 16 mb. To make a wave put some inertia to the flow--after you calculate the desired flow then move the previous flow say 10% of the way towards the desired value.
Try treating each contiguous area of water as a single area (like flood fill) and track 1) the lowest cell(s) where water can escape and 2) the highest cell(s) from which water can come, then move water from the top to the bottom. This isn't local, but I think you can treat the edges of the area you want to affect as not connected and process any subset that you want. Re-evaluate what areas are contiguous on each frame (re-flood on each frame) so that when blobs converge, they can start being treated as one.
Here's my code from a Windows Forms demo of the idea. It may need some fine tuning, but seems to work quite well in my tests:
public partial class Form1 : Form
{
byte[,] tiles;
const int rows = 50;
const int cols = 50;
public Form1()
{
SetStyle(ControlStyles.ResizeRedraw, true);
InitializeComponent();
tiles = new byte[cols, rows];
for (int i = 0; i < 10; i++)
{
tiles[20, i+20] = 1;
tiles[23, i+20] = 1;
tiles[32, i+20] = 1;
tiles[35, i+20] = 1;
tiles[i + 23, 30] = 1;
tiles[i + 23, 32] = 1;
tiles[21, i + 15] = 2;
tiles[21, i + 4] = 2;
if (i % 2 == 0) tiles[22, i] = 2;
}
tiles[20, 30] = 1;
tiles[20, 31] = 1;
tiles[20, 32] = 1;
tiles[21, 32] = 1;
tiles[22, 32] = 1;
tiles[33, 32] = 1;
tiles[34, 32] = 1;
tiles[35, 32] = 1;
tiles[35, 31] = 1;
tiles[35, 30] = 1;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
using (SolidBrush b = new SolidBrush(Color.White))
{
for (int y = 0; y < rows; y++)
{
for (int x = 0; x < cols; x++)
{
switch (tiles[x, y])
{
case 0:
b.Color = Color.White;
break;
case 1:
b.Color = Color.Black;
break;
default:
b.Color = Color.Blue;
break;
}
e.Graphics.FillRectangle(b, x * ClientSize.Width / cols, y * ClientSize.Height / rows,
ClientSize.Width / cols + 1, ClientSize.Height / rows + 1);
}
}
}
}
private bool IsLiquid(int x, int y)
{
return tiles[x, y] > 1;
}
private bool IsSolid(int x, int y)
{
return tiles[x, y] == 1;
}
private bool IsEmpty(int x, int y)
{
return IsEmpty(tiles, x, y);
}
public static bool IsEmpty(byte[,] tiles, int x, int y)
{
return tiles[x, y] == 0;
}
private void ProcessTiles()
{
byte processedValue = 0xFF;
byte unprocessedValue = 0xFF;
for (int y = 0; y < rows; y ++)
for (int x = 0; x < cols; x++)
{
if (IsLiquid(x, y))
{
if (processedValue == 0xff)
{
unprocessedValue = tiles[x, y];
processedValue = (byte)(5 - tiles[x, y]);
}
if (tiles[x, y] == unprocessedValue)
{
BlobInfo blob = GetWaterAt(new Point(x, y), unprocessedValue, processedValue, new Rectangle(0, 0, 50, 50));
blob.ProcessMovement(tiles);
}
}
}
}
class BlobInfo
{
private int minY;
private int maxEscapeY;
private List<int> TopXes = new List<int>();
private List<int> BottomEscapeXes = new List<int>();
public BlobInfo(int x, int y)
{
minY = y;
maxEscapeY = -1;
TopXes.Add(x);
}
public void NoteEscapePoint(int x, int y)
{
if (maxEscapeY < 0)
{
maxEscapeY = y;
BottomEscapeXes.Clear();
}
else if (y < maxEscapeY)
return;
else if (y > maxEscapeY)
{
maxEscapeY = y;
BottomEscapeXes.Clear();
}
BottomEscapeXes.Add(x);
}
public void NoteLiquidPoint(int x, int y)
{
if (y < minY)
{
minY = y;
TopXes.Clear();
}
else if (y > minY)
return;
TopXes.Add(x);
}
public void ProcessMovement(byte[,] tiles)
{
int min = TopXes.Count < BottomEscapeXes.Count ? TopXes.Count : BottomEscapeXes.Count;
for (int i = 0; i < min; i++)
{
if (IsEmpty(tiles, BottomEscapeXes[i], maxEscapeY) && (maxEscapeY > minY))
{
tiles[BottomEscapeXes[i], maxEscapeY] = tiles[TopXes[i], minY];
tiles[TopXes[i], minY] = 0;
}
}
}
}
private BlobInfo GetWaterAt(Point start, byte unprocessedValue, byte processedValue, Rectangle bounds)
{
Stack<Point> toFill = new Stack<Point>();
BlobInfo result = new BlobInfo(start.X, start.Y);
toFill.Push(start);
do
{
Point cur = toFill.Pop();
while ((cur.X > bounds.X) && (tiles[cur.X - 1, cur.Y] == unprocessedValue))
cur.X--;
if ((cur.X > bounds.X) && IsEmpty(cur.X - 1, cur.Y))
result.NoteEscapePoint(cur.X - 1, cur.Y);
bool pushedAbove = false;
bool pushedBelow = false;
for (; ((cur.X < bounds.X + bounds.Width) && tiles[cur.X, cur.Y] == unprocessedValue); cur.X++)
{
result.NoteLiquidPoint(cur.X, cur.Y);
tiles[cur.X, cur.Y] = processedValue;
if (cur.Y > bounds.Y)
{
if (IsEmpty(cur.X, cur.Y - 1))
{
result.NoteEscapePoint(cur.X, cur.Y - 1);
}
if ((tiles[cur.X, cur.Y - 1] == unprocessedValue) && !pushedAbove)
{
pushedAbove = true;
toFill.Push(new Point(cur.X, cur.Y - 1));
}
if (tiles[cur.X, cur.Y - 1] != unprocessedValue)
pushedAbove = false;
}
if (cur.Y < bounds.Y + bounds.Height - 1)
{
if (IsEmpty(cur.X, cur.Y + 1))
{
result.NoteEscapePoint(cur.X, cur.Y + 1);
}
if ((tiles[cur.X, cur.Y + 1] == unprocessedValue) && !pushedBelow)
{
pushedBelow = true;
toFill.Push(new Point(cur.X, cur.Y + 1));
}
if (tiles[cur.X, cur.Y + 1] != unprocessedValue)
pushedBelow = false;
}
}
if ((cur.X < bounds.X + bounds.Width) && (IsEmpty(cur.X, cur.Y)))
{
result.NoteEscapePoint(cur.X, cur.Y);
}
} while (toFill.Count > 0);
return result;
}
private void timer1_Tick(object sender, EventArgs e)
{
ProcessTiles();
Invalidate();
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
int x = e.X * cols / ClientSize.Width;
int y = e.Y * rows / ClientSize.Height;
if ((x >= 0) && (x < cols) && (y >= 0) && (y < rows))
tiles[x, y] = 2;
}
}
}
From a fluid dynamics viewpoint, a reasonably popular lattice-based algorithm family is the so-called Lattice Boltzmann method. A simple implementation, ignoring all the fine detail that makes academics happy, should be relatively simple and fast and also get reasonably correct dynamics.

GetPixel,SetPixel and DrawImage does not work well for me

I was trying to create simple program that would perform some trivial operation with given image.
For some reason, it works only for the first time (when the app is launched):
//pseudo code
Bitmap im=Bitmap.FromFile("D:\\x.BMP");
Color [,] ColorArray=new [im.Width,im.Height];
private override voide OnPaint(EventArgs e)
{
for(int X=0;X<im.Width;X++)
{
for(int Y=0;Y<im.Height;Y++)
{
ColorArray[X,Y]=im.GetPixel[X,Y];
}
}
for(int X=0;X<im.Width;X++)
{
for(int Y=0;Y<im.Height;Y++)
{
Color c=ColorArray[X,Y];
...
//some code that adds 100 to R,G,B
im.SetPixel(X,Y,c);
}
}
e.Graphics.DrawImage(im);
}
[EDIT]
I have modified my sample code. With the previous version, it could be hard to see the difference from one iteration to the next (especially with the bmp I was using for testing). This one allows you to change color gradually by pressing 1, 2, or 3 on the Num Pad. As others have mentioned, SetPixel/GetPixel is slow, so each KeyUp event does take some time to run.
This works fine for me.
Create a new Windows Forms project. Drop this code in. Make sure you have "x.bmp" available. Each time you press 1, 2, or 3 on the number pad (you might need turn on Num Lock), the colors of the bitmap change slightly:
public partial class Form1 : Form
{
Bitmap bm;
Color [,] colors;
public Form1()
{
bm = (Bitmap)Bitmap.FromFile("x.bmp");
colors = new Color[bm.Width, bm.Height];
InitializeComponent();
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawImage(bm,new Point(0,0));
}
private void Form1_KeyUp(object sender, KeyEventArgs e)
{
//Change the colors a little bit on each KeyUp.
//On NumPad1, change red.
//On NumPad2, change green.
//On NumPad3, change blue.
//Mod with 256 to ensure a value between 0 and 255.
int rInc = 0;
int gInc = 0;
int bInc = 0;
switch (e.KeyCode)
{
case Keys.NumPad1:
rInc = 20;
break;
case Keys.NumPad2:
gInc = 20;
break;
case Keys.NumPad3:
bInc = 20;
break;
default:
break;
}
for (int x = 0; x < bm.Width; x++)
{
for (int y = 0; y < bm.Height; y++)
{
colors[x, y] = bm.GetPixel(x, y);
}
}
for (int x = 0; x < bm.Width; x++)
{
for (int y = 0; y < bm.Height; y++)
{
Color c = colors[x, y];
int r = (c.R + rInc) % 256;
int g = (c.G + gInc) % 256;
int b = (c.B + bInc) % 256;
c = Color.FromArgb(255, r, g, b);
bm.SetPixel(x, y, c);
}
}
Invalidate();
}
}
It's not very sophisticated, but it does what you asked with real code that closely matches your pseudocode.
You can improve your performance when looping over pixels, arrange the loops to access the pixels in row order (x coordinates) in the inner loop. That best matches the image memory layout so it will improve CPU cache performance
for ( y = 0, y < bm.Height; y++)
{
...
for ( x = 0, x < bm.Width; x++)
{
...
}
}

Categories

Resources