C# drawing houses that become 20% smaller than house on left - c#

I want to draw a street with a panel but it wont work. I want to have it with a loop but i cant get it done. The wall and roof must become 20% smaller than the house on the left.
My code:
private void button1_Click(object sender, EventArgs e)
{
for (int i = 0; i < 5; i++)
{
HuisTekenen();
}
}
private void HuisTekenen()
{
gebouw();
dak();
}
private void gebouw()
{
Graphics paper;
paper = panel1.CreateGraphics();
Pen pennetje = new Pen(Color.Green);
int b = 100;
int aantal = 0;
for (int i = 10; aantal <= 5; i += 120)
{
paper.DrawRectangle(pennetje, i, 100, b, 150);
aantal++;
i = i / 100 * 80;
b = b / 100 * 80;
}
}
private void dak()
{
Graphics paper;
paper = panel1.CreateGraphics();
Pen pennetje = new Pen(Color.Red);
int b = 100;
int aantal = 0;
for (int i = 10; aantal <= 5; i+=120)
{
paper.DrawLine(pennetje, i, 10 / 100 * 80, i, b);
paper.DrawLine(pennetje, i, 10 / 100 * 80, i + 100, b);
aantal++;
i = i / 100 * 80;
b = 100 / 100 * 80;
}
}
The result i want to get:
Result i get:
Can you help me?
Thanks!

Here's a way to get started with the box. Youll have to finish your homework on your own.
float size = 50;
float xpos = 0;
float ypos = 0;
for(int i=0;i<5;i++) //whatever you do, this must be what your loop looks like. anything else is going way off in the wrong direction
{
paper.DrawRectangle(pennetje, xpos, ypos, size, size);
xpos += size + 20;
size *= .8f;
}

First a remark: your for-statements are odd, usually the three parts will use the same variable. It can work this way, but doing it like this is certainly not recommended.
A different kind of issue will be this statement:
i = i / 100 * 80;
With variable i being an int, and / performing integer division, the first part i / 100 will produce 0 because that is the int value closest to the real/float result. And of course multiplying 0 by 80 will not do anything.
I suggest you now try again :-)

Related

Plasma effect in WinForms, how to create continous loop

I'm trying to create some simple graphics ("plasma" effect) with C# and Winforms.
I have two classes in my code, (main)Form1 and Plasmadraw.
In Plasmadraw I have following setup:
class Plasmadraw
{
int y;
int x;
double i;
double pii = 3.1415;
public void Draw(Graphics gfx, int addition)
{
for (int i = 0; i < 23040; i++)
{
x = x + 10;
if (x == 1920)
{
x = 0;
y = y + 10;
}
if (y == 1200)
{
y = 0;
}
double v = Math.Sin((x * 0.5) + i * 0.001 * addition);
double c = v * pii;
double d = c + (2 * pii / 3);
double f = c + (6 * pii / 3);
double r = 255 * Math.Abs(Math.Sin(c));
double g = 255 * Math.Abs(Math.Sin(d));
double b = 255 * Math.Abs(Math.Sin(f));
int r1 = (int)r;
int g1 = (int)g;
int b1 = (int)b;
Color e = Color.FromArgb(r1, g1, b1);
SolidBrush brush = new SolidBrush(e);
Rectangle rect = new Rectangle(x, y, 10, 10);
gfx.FillRectangle(brush, rect);
}
}
}
and then in Form1 I have Paint event:
private void Form1_Paint(object sender, PaintEventArgs e)
{
Plasmadraw plasmaeffect = new Plasmadraw();
for (int a = 0; a < 30; a++)
{
plasmaeffect.Draw(e.Graphics, a);
Invalidate();
}
Is this somehow completely wrong way to build the logic ? I've managed to create some graphics effects (moving sprites etc.) by creating a list and then running through the list with Foreach in Paint event (& Invalidate()). However, I'd like to learn some new way to do things, rather than copying the old way.

Bitmap high memory usage

I have an issue with my WinForms project. I need to display image of created maze and i use bitmap. But empty bitmap(9990, 9990) takes 400MB+. Is there way to decrease this memory consumption or i need to change bitmap to anything else?
Bitmap bm = new Bitmap(9990, 9990);
Thank you for your help.
The cell and wall have one size 10x10 px.
https://i.stack.imgur.com/yj9CA.png
I decreased the memory usage by using a custom PixelFormat;
It reduced memory consumption by 2-4 times.
var format = System.Drawing.Imaging.PixelFormat.Format16bppRgb565;
inBm = new Bitmap(
CellWid * (maze.finish.X + 2),
CellHgt * (maze.finish.Y + 2), format);
Is there a way to decrease memory consumption? As long as you do not need the whole maze rendered at once there is. You use 10*10*4 = 400B to store information about one cell. Chances are, you only need to know if the cell is a wall or not. That is 1 bit. You can reduce 400MB to 125kB to store information about the whole maze. And render only the part you actually need. Here is some code to play with, this draws 999x999 cells "maze" you can move by mouse
BitArray maze = null;
int mazeWidth = 999;
int mazeHeight = 999;
int xPos = 0;
int yPos = 0;
int cellSize = 10;
private void Form1_Load(object sender, EventArgs e)
{
maze = new BitArray(mazeWidth * mazeHeight);
Random rnd = new Random();
for (int i = 0; i < maze.Length; ++i)
{
maze[i] = rnd.Next(4) == 0;
}
xPos = -Width / 2;
yPos = -Height / 2;
DoubleBuffered = true;
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
for (int y = Math.Max(0, yPos / cellSize); y < mazeHeight; ++y)
{
int yDraw = y * cellSize - yPos;
if (yDraw > Height) { return; }
for (int x = Math.Max(0, xPos / cellSize); x < mazeWidth; ++x)
{
if (maze[x + y * mazeWidth])
{
int xDraw = x * cellSize - xPos;
if (xDraw > Width) { break; }
e.Graphics.FillRectangle(
Brushes.Black,
xDraw,
yDraw,
cellSize,
cellSize
);
}
}
}
}
public static int Clamp(int value, int min, int max)
{
if (value < min) { return min; }
if (value > max) { return max; }
return value;
}
int fromX;
int fromY;
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
fromX = e.X;
fromY = e.Y;
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
int w2 = Width / 2;
int h2 = Height / 2;
xPos = Clamp(xPos + fromX - e.X, -w2, mazeWidth * cellSize - w2);
yPos = Clamp(yPos + fromY - e.Y, -h2, mazeHeight * cellSize - h2);
fromX = e.X;
fromY = e.Y;
Invalidate();
}
}

Drawing circles with increasing radius in C#

I am using the below code to draw the circles(reading centres from a csv file) with increasing radius. The increase in radius is 5 units per circle.
namespace MATLAB_file
{
public partial class Form1 : Form
{
string[] read;
float th;
int c = 0;
int r;
public List<PointF> circleCoordinates = new List<PointF>();
int rl;
public Form1()
{
InitializeComponent();
}
protected override void OnPaint(PaintEventArgs e)
{
Pen linePen = new Pen(System.Drawing.Color.CornflowerBlue);
Graphics grphx = this.CreateGraphics();
grphx.Clear(this.BackColor);
foreach (PointF point in this.circleCoordinates)
{
Pen redPen1 = new Pen(Color.Red, 100);
e.Graphics.DrawArc(Pens.Red, point.X, point.Y, 1, 1, 0, 120F);
}
linePen.Dispose();
base.OnPaint(e);
}
private void Form1_Load(object sender, EventArgs e)
{
double xx, yy;
int i;
int n = 0;
float[] centre1 = new float[1000];
System.IO.StreamReader sr;
sr = new System.IO.StreamReader("centers.txt", true);
char[] seperators = { ',' };
string data = sr.ReadLine();
read = data.Split(new Char[] { ',' });
rl = read.Length;
int a1 = rl / 2;
for (c = 0; c < rl; c++)
{
centre1[c] = float.Parse(read[c]);
}
while (r < 200)
{
for (i = 0; i < a1; i++)
{
while (th < 360)
{
xx = r * Math.Cos(th) + centre1[2 * i] + 100;
xx1 = (float)xx;
yy = r * Math.Sin(th) + centre1[2 * i + 1] + 100;
yy1 = (float)yy;
this.circleCoordinates.Add(new PointF(xx1, yy1));
this.Invalidate();
th = th + .360F;
}
th = 0;
}
r = r + 5;
}
}
}
}
The above code is displaying all the circles but I do not want all circles to be displayed on canvas, rather only one circle should show with gradual increase in radius
Please suggest how to delete the previous drawn circle on drawing new one. Is there any other way to do it, if my later use includes removal of certain section of circles based on "th" values?
If you move the Clear call within the foreach you will see only the last drawn circle, though this could be achieved with drawing only the Last circleCoordinates too.
foreach (PointF point in this.circleCoordinates)
{
grphx.Clear(this.BackColor);
Pen redPen1 = new Pen(Color.Red, 100);
e.Graphics.DrawArc(Pens.Red, point.X, point.Y, 1, 1, 0, 120F);
}
An alternative interpretation:
You want animation, which generates the onPaint events (by timer ticks or on user input) and you increase a counter to select the circle to draw.
For that, you will need a new member in your program, like int Index; and you could select the circle based on this, using something the following code snippet (assuming you always have at least 1 circleCoordinates, animation restarts after it finished):
PointF point = this.circleCoordinates[Index % circleCoordinates.Length];
or (last circle remain on the screen after the animation)
PointF point = this.circleCoordinates[Math.Min(Index, circleCoordinates.Length - 1)];

How can I report progress based on multiple variables in a nested loop (for a progress bar)?

I have a BackgroundWorker and a single ProgressBar. When working, the BackgroundWorker runs through a triple for-loop and reports progress to the ProgressBar.
Currently, the progress that is being reported is only that of the outter-most loop (xProgress), which works, but does not run smoothly. The goal is for the ProgressBar to also account for the progress percentages of the inner loops, so that the ProgressBar updates more smoothly and more accurately.
The DoWork method:
private void bgw_DoWork(object sender, DoWorkEventArgs e)
{
int xMax, yMax, zMax;
xMax = 10;
for (int x = 1; x <= xMax; x++)
{
yMax = 5;
for (int y = 1; y <= yMax; y++)
{
zMax = new Random().Next(50, 100);
for (int z = 1; z <= zMax; z++)
{
Thread.Sleep(5); /// The process
double xProgress = (double)x / (double)xMax;
double yProgress = (double)y / (double)yMax;
double zProgress = (double)z / (double)zMax;
/// The progress calculation:
double progressCalc = xProgress;
int progress = (int)(progressCalc * pgb.Maximum);
bgw.ReportProgress(progress);
}
}
}
}
This works even if you don't know your best/worst case in advance.
Any of the max's could be randomized in the same fashion of zMax.
static void F()
{
var r = new Random();
int xMax = 10;
int yMax = 5;
int zMax;
for (int x = 0; x < xMax; x++)
{
double xProg = (double)x / xMax;
for (int y = 0; y < yMax; y++)
{
double yProg = (double)y / (yMax * xMax);
zMax = r.Next(50, 100);
for (int z = 0; z < zMax; z++)
{
double zProg = (double)z / (zMax * yMax * xMax);
var prog = xProg + yProg + zProg;
Console.WriteLine(prog.ToString("P"));
// bgw.ReportProgress((int)(prog * pgb.Maximum));
}
}
}
Console.WriteLine(1.ToString("P")); // Make sure to report the final 100%
// bgw.ReportProgress((int)pgb.Maximum);
}
Btw, I'd replace the pgb.Maximum's with 1 and in the OnProgressHandler multiply the progress by it. That way the threaded method does not touch UI elements at all.
It's true that you can't know exactly how many iterations your loops will do, but you certainly can smooth your progress indicator.
Let's assume your total iterations in the worst case is xMax * yMax * worstZMax.
worstZMax = 99 because the upper bound is exclusive in Random.Next(minValue:int, maxValue:int)
Hence the total iterations in worst case scenario will be 5 * 10 * 99 = 4950.
Now we could start with that total and adjust it as required when we loose iterations after generating zMax for each y loop and we'll effectively smooth the progress calculation and reporting.
This is how I'd do it:
private void bgw_DoWork(object sender, DoWorkEventArgs e)
{
const int xMax = 10;
const int yMax = 5;
const int worstZMax = 99; //because upper is exclusive in Random.Next(lower, upper)
var iteration = 0;
var total = xMax * yMax * worstZMax; //total number of iterations (worst case)
for (var x = 1; x <= xMax; x++)
{
for (var y = 1; y <= yMax; y++)
{
var zMax = new Random().Next(50, 100);
//get how many iterations did we miss, and adjust the total iterations
total -= worstZMax - zMax;
for (var z = 1; z <= zMax; z++)
{
iteration++; //count this iteration
Thread.Sleep(5); // The process
// The progress calculation
var progress = (double)iteration / total * pgb.Maximum;
bgw.ReportProgress((int)progress);
}
}
}
}
Hope this helps!
Updated Answer:
Since inner loop has unknown number of iterations you could decide how many steps it should advance. for example 10.
Then you could do something like this:
progressbarMaximum = xMax * yMax * 10
right before z-loop you get the zModulo by dividing zMax with 10.
in your z-loop check if
zMax % zModulo == 0
then increment progressbar.
Old answer:
If you multiply xMax, yMax and zMax you get the total number of iterations of the innermost loop.
Set progressbar maximum to that value.
On each iteration of the inner loop increment progressbar.
You can't make it exact. Think of it this way - what if the first randoms were all 50 and you have already done half of the 2 outer loops - if the rest of the randoms will be 50 - you've done 50%. If the rest of the randoms will be 100 - you will only have done 33%. So you don't know how far the progress bar should be.
(Of course random results won't usually be like that. It's just to illustrate the point.)

Correctly executing bicubic resampling

I've been experimenting with the image bicubic resampling algorithm present in the AForge framework with the idea of introducing something similar into my image processing solution. See the original algorithm here and interpolation kernel here
Unfortunately I've hit a wall. It looks to me like somehow I am calculating the sample destination position incorrectly, probably due to the algorithm being designed for Format24bppRgb images where as I am using a Format32bppPArgb format.
Here's my code:
public Bitmap Resize(Bitmap source, int width, int height)
{
int sourceWidth = source.Width;
int sourceHeight = source.Height;
Bitmap destination = new Bitmap(width, height, PixelFormat.Format32bppPArgb);
destination.SetResolution(source.HorizontalResolution, source.VerticalResolution);
using (FastBitmap sourceBitmap = new FastBitmap(source))
{
using (FastBitmap destinationBitmap = new FastBitmap(destination))
{
double heightFactor = sourceWidth / (double)width;
double widthFactor = sourceHeight / (double)height;
// Coordinates of source points
double ox, oy, dx, dy, k1, k2;
int ox1, oy1, ox2, oy2;
// Width and height decreased by 1
int maxHeight = height - 1;
int maxWidth = width - 1;
for (int y = 0; y < height; y++)
{
// Y coordinates
oy = (y * widthFactor) - 0.5;
oy1 = (int)oy;
dy = oy - oy1;
for (int x = 0; x < width; x++)
{
// X coordinates
ox = (x * heightFactor) - 0.5f;
ox1 = (int)ox;
dx = ox - ox1;
// Destination color components
double r = 0;
double g = 0;
double b = 0;
double a = 0;
for (int n = -1; n < 3; n++)
{
// Get Y cooefficient
k1 = Interpolation.BiCubicKernel(dy - n);
oy2 = oy1 + n;
if (oy2 < 0)
{
oy2 = 0;
}
if (oy2 > maxHeight)
{
oy2 = maxHeight;
}
for (int m = -1; m < 3; m++)
{
// Get X cooefficient
k2 = k1 * Interpolation.BiCubicKernel(m - dx);
ox2 = ox1 + m;
if (ox2 < 0)
{
ox2 = 0;
}
if (ox2 > maxWidth)
{
ox2 = maxWidth;
}
Color color = sourceBitmap.GetPixel(ox2, oy2);
r += k2 * color.R;
g += k2 * color.G;
b += k2 * color.B;
a += k2 * color.A;
}
}
destinationBitmap.SetPixel(
x,
y,
Color.FromArgb(a.ToByte(), r.ToByte(), g.ToByte(), b.ToByte()));
}
}
}
}
source.Dispose();
return destination;
}
And the kernel which should represent the given equation on Wikipedia
public static double BiCubicKernel(double x)
{
if (x < 0)
{
x = -x;
}
double bicubicCoef = 0;
if (x <= 1)
{
bicubicCoef = (1.5 * x - 2.5) * x * x + 1;
}
else if (x < 2)
{
bicubicCoef = ((-0.5 * x + 2.5) * x - 4) * x + 2;
}
return bicubicCoef;
}
Here's the original image at 500px x 667px.
And the image resized to 400px x 543px.
Visually it appears that the image is over reduced and then the same pixels are repeatedly applied once we hit a particular point.
Can anyone give me some pointers here to solve this?
Note FastBitmap is a wrapper for Bitmap that uses LockBits to manipulate pixels in memory. It works well with everything else I apply it to.
Edit
As per request here's the methods involved in ToByte
public static byte ToByte(this double value)
{
return Convert.ToByte(ImageMaths.Clamp(value, 0, 255));
}
public static T Clamp<T>(T value, T min, T max) where T : IComparable<T>
{
if (value.CompareTo(min) < 0)
{
return min;
}
if (value.CompareTo(max) > 0)
{
return max;
}
return value;
}
You are limiting your ox2 and oy2 to destination image dimensions, instead of source dimensions.
Change this:
// Width and height decreased by 1
int maxHeight = height - 1;
int maxWidth = width - 1;
to this:
// Width and height decreased by 1
int maxHeight = sourceHeight - 1;
int maxWidth = sourceWidth - 1;
Well, I've met a very strange thing, which might be or might be not a souce of the problem.
I've started to try implementing convolution matrix by myself and encountered strange behaviour. I was testing code on a small image 4x4 pixels. The code is following:
var source = Bitmap.FromFile(#"C:\Users\Public\Pictures\Sample Pictures\Безымянный.png");
using (FastBitmap sourceBitmap = new FastBitmap(source))
{
for (int TY = 0; TY < 4; TY++)
{
for (int TX = 0; TX < 4; TX++)
{
Color color = sourceBitmap.GetPixel(TX, TY);
Console.Write(color.B.ToString().PadLeft(5));
}
Console.WriteLine();
}
}
Althought I'm printing out only blue channel value, it's still clearly incorrect.
On the other hand, your solution partitially works, what makes the thing I've found kind of irrelevant. One more guess I have: what is your system's DPI?
From what I have found helpfull, here are some links:
C++ implementation of bicubic interpolation on
matrix
C# implemetation of bicubic interpolation, lacking the part about rescaling
Thread on gamedev.net which has almost working solution
That's my answer so far, but I will try further.

Categories

Resources