I am working on a simple Random Walker program that should draw a 10p long line, then choose a random cardinal direction to draw another line (also 10p long) until a certain number of lines have been reached.
I am using four coordinates to draw the line (two coordinates for X and two for Y). The Y coordinates are pushed into a Stack after every line is drawn and they are popped out as the X coordinates. This should ensure that the starting point of every second line is the end-point of the previous line.
The program draws on a Windows Form after pushing a Button controller. As of now, the output is something like this:
This here is my event handler code block for the button:
// Graphics and Pen classes instantiated
Graphics graphics;
graphics = this.CreateGraphics();
Pen pen = new Pen(Color.Black);
pen.Width = 1;
// lineLength is 10 pixels
// gridLength and gridWidth are needed to keep the Random Path inside a 600×600 field (this is not yet implemented in the code)
// lineCount is for maximizing the number of lines to be drawn and to control the loop
int lineLength = 10;
int gridWidth = 600;
int gridLength = 600;
int lineCount = 0;
// Starting line drawn with the following coordinates:
int x1 = 20;
int x2 = 20;
int y1 = 20;
int y2 = 30;
graphics.DrawLine(pen, x1, y1, x2, y2);
lineCount++;
// Stack initialized to store "y" coordinates
// "y" coordinates should be passed on as "x" coordinates for every consecutive lines
// so that the ending point's coordinate of a line
Stack<int> stackY = new Stack<int>();
stackY.Push(y2);
stackY.Push(y1);
for (lineCount = 1; lineCount <= 64; lineCount++)
{
// X pops current Y coordinates from stack
x1 = stackY.Pop();
x2 = stackY.Pop();
// Initializing the random number (between 1 and 4) generator to choose from the cardinal directions
Random rnd = new Random();
int dir = rnd.Next(1, 5);
switch (dir)
{
// up
case 1:
y1 = y1 + lineLength; // y1 plus lineLength
graphics.DrawLine(pen, x1, y1, x2, y2); //drawing the line
stackY.Push(y2); // pushing the current y coordinates into the stack
stackY.Push(y1);
break;
// right
case 2:
y1 = y2 + lineLength; // y2 plus lineLength
graphics.DrawLine(pen, x1, y1, x2, y2);
stackY.Push(y2);
stackY.Push(y1);
break;
// down
case 3:
y1 = y1 - lineLength; // y1 minus lineLength
graphics.DrawLine(pen, x1, y1, x2, y2);
stackY.Push(y2);
stackY.Push(y1);
break;
// left
case 4:
y2 = y2 - lineLength; // y2 minus lineLength
graphics.DrawLine(pen, x1, y1, x2, y2);
stackY.Push(y2);
stackY.Push(y1);
break;
} //switch
} //for
} //event handler
I am not really sure what went wrong - I appreciate any heads-up and advices! Thank you!
You are making this far more complicated than you need to. Also you are mixing the x and y coordinates in a way that doesn't make sense.
You don't need a stack, just store the most recent points. Something like this.
int x = 20, y = 20;
int new_x = x, new_y = y;
Random rnd = new Random();
for (int i = 0; i < numLines; i++)
{
int dir = rnd.Next(1, 5);
if (dir == 1) new_x += lineLength;
if (dir == 2) new_x -= lineLength;
if (dir == 3) new_y += lineLength;
if (dir == 4) new_y -= lineLength;
graphics.DrawLine(pen, x, y, new_x, new_y);
x = new_x;
y = new_y;
}
Also you don't need to redeclare the Random object every time, just once before the loop.
Related
I want to multiple cut one picture in c# code.the following image is my c # forum and I can select an area and cut it.
I want to multiple cut one picture in c# code
I want to repeat this process
private void btnKes_Click(object sender, EventArgs e)
{
int tiklanma = 0;
if (true)
{
tiklanma++;
}
pictureBox2.Refresh();
pictureBox2.Refresh();
Bitmap sourceBitmap = new Bitmap(pictureBox1.Image, pictureBox1.Width, pictureBox1.Height);
Graphics g = pictureBox2.CreateGraphics();
int x1, x2, y1, y2;
Int32.TryParse(txtX1.Text, out x1);
Int32.TryParse(txtX2.Text, out x2);
Int32.TryParse(txtY1.Text, out y1);
Int32.TryParse(txtY2.Text, out y2);
if ((x1 < x2 && y1 < y2))
{
rectCropArea = new Rectangle(x1, y1, x2 - x1, y2 - y1);
}
else if (x2 < x1 && y2 > y1)
{
rectCropArea = new Rectangle(x2, y1, x1 - x2, y2 - y1);
}
else if (x2 > x1 && y2 < y1)
{
rectCropArea = new Rectangle(x1, y2, x2 - x1, y1 - y2);
}
else
{
rectCropArea = new Rectangle(x2, y2, x1 - x2, y1 - y2);
}
pictureBox1.Refresh(); // This repositions the dashed box to new location as per coordinates entered.
int sayac = 40;
for (int i = 0; i < tiklanma; i++)
{
PictureBox pcBx = new PictureBox();
Size size = new Size(100, 100);
pcBx.Location();
pcBx.Size = size;
g.DrawImage(sourceBitmap, new Rectangle(0, 0, rectCropArea.Width, rectCropArea.Height), rectCropArea, GraphicsUnit.Pixel);
}
sourceBitmap.Dispose();
}
I want to select the fields more than once in the second picture and save the fields. How can I do this?
Use a FlowLayoutPanel, and every time you draw a new segment on the main image add a new PictureBox control to the layout panel.
Eventually you'll want to do other things with these picture segments, and so I also recommend immediately going a for a custom/user control here that includes a PictureBox as one part. That will make it much easier later to use buttons or context with each picture.
The specifics for all of this are out of scope for this type of question. We'd need to see more of your code to be able to use appropriate context with our answer, and the results are more than can fit well in the simple Q&A format. So go, try what you can, and then come back and ask new questions when you run into more specific problems.
In System.Drawing there is a command called DrawLines.
https://msdn.microsoft.com/en-us/library/83k7w0zx(v=vs.110).aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-2
I need arrays X and Y to be plotted as a PointF in "Single Format" but with a "F" at the end of each X and Y point.
protected void Page_Load(object sender, EventArgs e)
{
double[] X = new double[]{10,15,20,25,30};
double[] Y = new double[]{100,150,200,250,300};
using (Bitmap xPanel = new Bitmap(500, 500))
{
using (Graphics objGraphicPanel = Graphics.FromImage(xPanel))
{
for (int nn = 2; nn <= 5; nn++)
{
float x1 = Convert.ToSingle(X[nn - 1]);
float y1 = Convert.ToSingle(Y[nn - 1]);
float x2 = Convert.ToSingle(X[nn]);
float y2 = Convert.ToSingle(Y[nn]);
PointF[] ptf =
{
new PointF(x1, y1),
new PointF(x2, y2)
};
objGraphicPanel.DrawLines(colorPen, ptf);
xPanel.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
}
string Imgbase64 = Convert.ToBase64String(ms.ToArray());
MyImage.Src = "data:image/png;base64," + Imgbase64;
objGraphicPanel.Dispose();
}
xPanel.Dispose();
This does not work because it must be in the format:
PointF[] ptf =
{
new PointF(10.56F, 25.78654F),
new PointF(500.123456F, 234.567F)
};
PointF requires the "float single" format but I also need the "F" at the end of each array point to get the PointF and DrawLines to work.
How do I get that "F" after or the code equivalent?
This is only an example my arrays are much larger.
The place
PointF[] ptf =
{
new PointF(x1, y1),
new PointF(x2, y2)
};
is not a problem. PointF accepts only float arguments. When you put 'F' in the end of the number you just tell the compiller that your number is float (not double). In your code values x1, x2, y1, y2 are already float, because you define them as
float x1 = ...
float y1 = ...
The problem is, that you iterate your array from 2 to 5. In C# numeration in arrays is from 0 to N-1 (N is length of the array). So you should write
for (int nn = 1; nn < 5; nn++)
or, and this is better
for (int nn = 1; nn < X.Length; nn++)
Also you save your image at each iteration. I think
xPanel.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
should be outside the cycle for.
Also when you write
using (...)
{
...
}
you don't need to dispose the item you create inside the brackets ( and ). The dispose is called automatically in the end of the using operator.
So the lines
objGraphicPanel.Dispose();
and
xPanel.Dispose();
are redundant.
Also, it is not necessary to create array ptf for drawing a single line. You can use DrawLine method:
objGraphicPanel.DrawLine(colorPen, x1, y1, x2, y2);
So, the folowing code shoud work fine
protected void Page_Load(object sender, EventArgs e)
{
double[] X = new double[]{10,15,20,25,30};
double[] Y = new double[]{100,150,200,250,300};
using (Bitmap xPanel = new Bitmap(500, 500))
{
using (Graphics objGraphicPanel = Graphics.FromImage(xPanel))
{
for (int nn = 1; nn < X.Length; nn++)
{
float x1 = Convert.ToSingle(X[nn - 1]);
float y1 = Convert.ToSingle(Y[nn - 1]);
float x2 = Convert.ToSingle(X[nn]);
float y2 = Convert.ToSingle(Y[nn]);
objGraphicPanel.DrawLine(colorPen, x1, y1, x2, y2);
}
}
xPanel.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
}
I am drawing a line onto the canvas, by giving it a starting and ending point. Now I want to get the X and Y location of each point of that line. how can I do that?
Line line = new Line();
line.Visibility = System.Windows.Visibility.Visible;
line.StrokeThickness =1;
line.X1 = x[1];
line.X2 = y[1];
line.Y1 = x[i-1]/4;
line.Y2 = y[i - 1] / 4;
MyIP.Children.Add(line);
This is simple math. You know the starting and ending point of the line, meaning you can calculate any point you want on that line, by using the equation of the line. The way to get the equation is
y = y1 + [(y2 - y1) / (x2 - x1)] * (x - x1)
You know 2 points: (x1, y1) and (x2, y2)
In the end you'll get something in the form of
y = Ax + B
Meaning that for every x, you can calculate y, as A & B are constants.
So you could simply loop through all the x values, and increment by whatever granularity you want or need, to get the appropriate y values, and you'll end up with a set of (x, y) values
for (double i = x1; i <= x2; i+=0.2)
{
var x = i;
var y = (A*x)+B;
// now you have one pair of x, y
}
I'm creating and drawing a triangle mesh in wpf c# using GeometryModel3D. I've been trying to figure out how to create a smooth shading over the triangles, like the classic openGL smooth shaded triangle.
I would like to define a colour for each vertex, and then having the colours interpolated over the face, like this, assuming the three colour where red, green and blue.
I assumed I would need to use a brush, but I haven't been able to figure out how.
So any help would be appreciated, or any pointer to a guide that shows me how to achieve this.
EDIT:
I've looked at Triangular Gradient in WPF3D, which seems to answer the question partly, just using xaml.
Unfortunatly it seems like it need equilateral triangles.
2nd EDIT
The answer above, uses the RadialGradientBrush. Is the RadiusXand RadiusY used to make it elliptic instead of circular?
3rd EDIT
Okay, I'm fairly sure I can use the RadialGradientBrush. What I think I can do is, find the center of the circumcircle of the triangles, and create a RadialGradientBrush with RadiusX and RadiusY equal to the radius if the circumcircle. I would then move the focal point of the RadialGradientBrush to the vertices with GradientOrigin.
GradientOrigin takes two doubles X,Y as the center, with both of them being in the interval [0,1]. From what I can read is X = 0.0 is the left side and X = 1.0 is the right side and Y = 0.0 is the top and Y = 1.0 is the bottom. What I can't figure out, is this mapping [0,1]x[0,1] to a circle, or is it a square? The mapping from the vertices of the triangle to [0,1]x[0,1], depends on what shape this interval represents.
Have you heard of Helix 3D Toolkit for WPF ?
I didn't go as far as you'd like but I guess it is possible by looking at the Surface Demo example :
There are surely libraries for that, but to give some simple way, searching through some google,http://www.geeksforgeeks.org/check-whether-a-given-point-lies-inside-a-triangle-or-not/
computing the distance from corners, gives info about the smooth color. Checking if point is in triangle.
float area(int x1, int y1, int x2, int y2, int x3, int y3)
{
return (float)Math.Abs((x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2)) / 2.0);
}
bool isInside(int x1, int y1, int x2, int y2, int x3, int y3, int x, int y)
{
/* Calculate area of triangle ABC */
float A = area(x1, y1, x2, y2, x3, y3);
/* Calculate area of triangle PBC */
float A1 = area(x, y, x2, y2, x3, y3);
/* Calculate area of triangle PAC */
float A2 = area(x1, y1, x, y, x3, y3);
/* Calculate area of triangle PAB */
float A3 = area(x1, y1, x2, y2, x, y);
/* Check if sum of A1, A2 and A3 is same as A */
return (A == A1 + A2 + A3);
}
for (int ii = 5; ii < 100; ii++)
{
for (int jj = 5; jj < 100; jj++)
{
int distanceRed =0, distanceGreen =0,distanceBlue =0;
if (isInside(30, 50, 30, 90, 20, 70, ii, jj))
{
distanceRed = (int)Math.Sqrt(((ii - 30) * (ii - 30) + (jj - 50) * (jj - 50)));
distanceGreen = (int)Math.Sqrt(((ii - 30) * (ii - 30) + (jj - 90) * (jj - 90)));
distanceBlue = (int)Math.Sqrt(((ii - 20) * (ii - 20) + (jj - 70) * (jj - 70)));
}
else
{
distanceRed = 0; distanceGreen = 0; distanceBlue = 0;
}
ptr[(((int)jj) * 3) + ((int)ii) * stride] = (byte)(distanceRed % 256);
ptr[(((int)jj) * 3) + ((int)ii) * stride + 1] = (byte)(distanceGreen % 256);
ptr[(((int)jj) * 3) + ((int)ii) * stride + 2] = (byte)(distanceBlue % 256);
}
}
gives the result:
Couldnt fit the red. Maybe the modulo is wrong here.
Also the sqrt is inefficient.
Basically, I want to use a line algo to determine which cells to check for collisions for my raycaster.
Bresenham isn't great for this as it uses a unified-thickness approach, meaning that it ignores cells that aren't at least half-covering the line. Not great at all, because it means that some segments of my line aren't being checked for intersections with the cells, leading to errors.
I can't seem to find any "thick-line" algorithms, can anyone help me find one?
Green: What I would like.
Red: What I currently have and don't want.
I had exactly the same problem as you and found an very simple solution. Usually, Bresenham has two consecutive if's to determine whether it should increase the coordinate for the two dimensions:
public void drawLine(int x0, int y0, int x1, int y1, char ch) {
int dx = Math.abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
int dy = -Math.abs(y1 - y0), sy = y0 < y1 ? 1 : -1;
int err = dx + dy, e2; // error value e_xy
for (;;) {
put(x0, y0, ch);
if (x0 == x1 && y0 == y1) break;
e2 = 2 * err;
// horizontal step?
if (e2 > dy) {
err += dy;
x0 += sx;
}
// vertical step?
if (e2 < dx) {
err += dx;
y0 += sy;
}
}
}
Now all you have to do is to insert an else before the second if:
public void drawLineNoDiagonalSteps(int x0, int y0, int x1, int y1, char ch) {
int dx = Math.abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
int dy = -Math.abs(y1 - y0), sy = y0 < y1 ? 1 : -1;
int err = dx + dy, e2;
for (;;) {
put(x0, y0, ch);
if (x0 == x1 && y0 == y1) break;
e2 = 2 * err;
// EITHER horizontal OR vertical step (but not both!)
if (e2 > dy) {
err += dy;
x0 += sx;
} else if (e2 < dx) { // <--- this "else" makes the difference
err += dx;
y0 += sy;
}
}
}
Now the algorithm doesn't change both coordinates at once anymore.
I haven't thoroughly tested this but it seems to work pretty well.
This thread old, but I thought it'd be worth putting this on the Internet:
// This prints the pixels from (x, y), increasing by dx and dy.
// Based on the DDA algorithm (uses floating point calculations).
void pixelsAfter(int x, int y, int dx, int dy)
{
// Do not count pixels |dx|==|dy| diagonals twice:
int steps = Math.abs(dx) == Math.abs(dy)
? Math.abs(dx) : Math.abs(dx) + Math.abs(dy);
double xPos = x;
double yPos = y;
double incX = (dx + 0.0d) / steps;
double incY = (dy + 0.0d) / steps;
System.out.println(String.format("The pixels after (%d,%d) are:", x, y));
for(int k = 0; k < steps; k++)
{
xPos += incX;
yPos += incY;
System.out.println(String.format("A pixel (%d) after is (%d, %d)",
k + 1, (int)Math.floor(xPos), (int)Math.floor(yPos)));
}
}
Without loss of generality, assume x2 >= x1, then
int x = floor(x1);
int y = floor(y1);
double slope = (x2 - x1) / (y2 - y1);
if (y2 >= y1) {
while (y < y2) {
int r = floor(slope * (y - y1) + x1);
do {
usepixel(x, y);
++x;
} while (x < r);
usepixel(x, y);
++y;
}
}
else {
while (y > y2) {
int r = floor(slope * (y - y1) + x1);
do {
usepixel(x, y);
++x;
} while (x < r);
usepixel(x, y);
--y;
}
}
The floor calls can probably be written just as a cast-to-integer.
There is an interesting article available in GPU Gems, maybe it can help you: Chapter 22. Fast Prefiltered Lines
What about Bresenham with an additional constraint that no diagonal moves are allowed: Generate the points with the traditional algorithm, then as a post-processing step insert extra steps needed to make only orthogonal movements.
You could find all the intersections your ray has with the horizontal grid lines, and then mark all the cells on a row that either have an intersection point on one side, or are between the two cells with the intersections on the row.
Finding the intersections can be done by starting from the origin, advancing the point to the first intersection (and marking the cells in the process), finding out the vector that takes you from an intersection to the next (both these operations are basic similar triangles (or trig)) and then advancing column by column until you've gone far enough. Advancing column by column involves one vector addition per column, and a small loop to fill in the cells between the ones with intersections. Replace "mark" with "process" if you're processing the cells on the fly - this algorithm is guaranteed to mark each cell only once.
The same could be done with the vertical lines, but grids are generally stored in horizontal slices so I chose that. If you're using trig, you'll need to handle straight horizontal lines with a special case.
By the way, as far as I know, this is how old grid-based raycaster "3D" games (like Wolfenstein 3D) were done. I first read about this algorithm from this book, eons ago.