If we take Wikipedia article on Marching square into account, we see that case#5 and case#10 are said to be ambiguous cases.
I have implemented Marching Square as follows and I am not understanding how an ambiguous case can arise:
public class LinesRectangle
{
public Graphics Graphics { get; set; }
public Color Color { get; set; }
public Pen Pen { get; set; }
public int Thickness { get; set; }
public LinesRectangle()
{
Color = Color.Blue;
Thickness = 2;
Pen = new Pen(Color, Thickness);
}
public void DrawLines(int x, int y, int width, int code)
{
int height = width;
Graphics.DrawRectangle(Pen, new System.Drawing.Rectangle(x, y, width, height));
int x1 = 0, y1 = 0;
int x2 = 0, y2 = 0;
switch (code)
{
case 0:
case 15:
break;
case 1:
case 14:
x1 = x; y1 = y + height/2;
x2 = x + width/2; y2 = y + height;
Graphics.DrawLine(Pen, x1, y1, x2, y2);
break;
case 2:
case 13:
x1 = x + width/2; y1 = y + height;
x2 = x + width; y2 = y + height/2;
Graphics.DrawLine(Pen, x1, y1, x2, y2);
break;
case 3:
case 12:
x1 = x; y1 = y + height / 2;
x2 = x + width; y2 = y + height / 2;
Graphics.DrawLine(Pen, x1, y1, x2, y2);
break;
case 4:
case 11:
x1 = x+width/2; y1 = y;
x2 = x + width; y2 = y + height / 2;
Graphics.DrawLine(Pen, x1, y1, x2, y2);
break;
case 5:
x1 = x ; y1 = y + height/2;
x2 = x + width/2; y2 = y;
Graphics.DrawLine(Pen, x1, y1, x2, y2);
x1 = x + width / 2; y1 = y + height;
x2 = x + width; y2 = y + height / 2;
Graphics.DrawLine(Pen, x1, y1, x2, y2);
break;
case 6:
case 9:
x1 = x + width / 2; y1 = y;
x2 = x + width/2; y2 = y + height;
Graphics.DrawLine(Pen, x1, y1, x2, y2);
break;
case 7:
case 8:
x1 = x; y1 = y + height / 2;
x2 = x + width / 2; y2 = y;
Graphics.DrawLine(Pen, x1, y1, x2, y2);
break;
case 10:
x1 = x + width / 2; y1 = y;
x2 = x + width; y2 = y + height / 2;
Graphics.DrawLine(Pen, x1, y1, x2, y2);
x1 = x; y1 = y + height / 2;
x2 = x + width / 2; y2 = y + height;
Graphics.DrawLine(Pen, x1, y1, x2, y2);
break;
}
}
}
You can see here each of the cases are taken care of individually.
Output:
Can anyone tell me what I am missing?
Driver Program:
public enum What
{
lines, surface, both
}
public partial class DrawingForm : System.Windows.Forms.Form
{
public int [,] Data { get; set; }
public void Print(int[,] data, int xn, int yn)
{
for (int j = 0; j < yn; j++)
{
for (int i = 0; i < xn; i++)
{
Console.Write(data[i, j] + ", ");
}
Console.WriteLine();
}
}
public int[,] normalize(int[,] data, int xn, int yn)
{
for (int j = 0; j < yn; j++)
{
for (int i = 0; i < xn; i++)
{
if (data[i, j] > 1)
{
data[i, j] = 0;
}
else
{
data[i, j] = 1;
}
}
}
return data;
}
public int[,] marching_square(int x, int y, int[,] data, int isovalue, What what)
{
int xn = x;
int yn = y;
data = normalize(data, xn, yn);
int[,] bitMask = new int[xn - 1, yn - 1];
for (int j = 0; j < yn - 1; j++)
{
for (int i = 0; i < xn - 1; i++)
{
StringBuilder sb = new StringBuilder();
sb.Append(data[i, j]);
sb.Append(data[i + 1, j]);
sb.Append(data[i + 1, j + 1]);
sb.Append(data[i, j + 1]);
bitMask[i, j] = Convert.ToInt32(sb.ToString(), 2);
}
}
return bitMask;
}
public DrawingForm()
{
InitializeComponent();
}
private void MainForm_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
int[,] data = new int[,] {
{ 1,1,1,1,1 },
{ 1,2,3,2,1 },
{ 1,3,1,3,1 },
{ 1,2,3,2,1 },
{ 1,1,1,1,1 }
};
int[,] bitMask = marching_square(5, 5, data, 0, What.lines);
Graphics g = this.CreateGraphics();
LinesRectangle rect = new LinesRectangle();
rect.Graphics = g;
for (int j = 0; j < 4; j++)
{
for (int i = 0; i < 4; i++)
{
rect.DrawLines(i*50, j*50, 50, bitMask[i,j]);
}
}
}
}
Edit: In case of the following data (as pointed out by #JeremyLakeman):
{ 2,1,2,1,2 },
{ 1,2,1,2,1 },
{ 2,1,2,1,2 },
{ 1,2,1,2,1 },
{ 2,1,2,1,2 }
my program produced the following output:
Your example doesn't include any ambiguous cases. What output would you expect with the following input;
{ 2,1,2,1,2 },
{ 1,2,1,2,1 },
{ 2,1,2,1,2 },
{ 1,2,1,2,1 },
{ 2,1,2,1,2 }
Circles around the 1's? Circles around the 2's? Diagonal lines?
Edit;
From your code;
case 5:
x1 = x ; y1 = y + height/2;
x2 = x + width/2; y2 = y;
Graphics.DrawLine(Pen, x1, y1, x2, y2);
x1 = x + width / 2; y1 = y + height;
x2 = x + width; y2 = y + height / 2;
Graphics.DrawLine(Pen, x1, y1, x2, y2);
break;
case 10:
x1 = x + width / 2; y1 = y;
x2 = x + width; y2 = y + height / 2;
Graphics.DrawLine(Pen, x1, y1, x2, y2);
x1 = x; y1 = y + height / 2;
x2 = x + width / 2; y2 = y + height;
Graphics.DrawLine(Pen, x1, y1, x2, y2);
break;
You could swap those case labels. You could pick one, delete the other, and merge the cases. You could look at more surrounding pixels to pick one. You could roll a random number to pick which way to draw it.
But you didn't. You arbitrarily decided that you would always draw those cases this way.
Oh man, I understand you. Surprisingly thats a good question!
Ambiguity is seen clearly in a moment when you decide if "value above the isovalue" is black or white and opposite for the "value below the isovalue".
Let me explain what I mean.
If you do algorithm by hand you can get following results. The only choice you do while following algorithm described on wiki - is to decide what color to use when painting nodes.
{ 1, 1, 1 },
{ 1, 2, 1 },
{ 1, 1, 1 }
has no ambiguous cases so the choice does not matter - resulting image will be the same no matter if '1' is a "black dot" or a "white dot".
BUT lets see example with ambiguous cases:
{ 1, 2, 1 },
{ 2, 1, 2 },
{ 1, 2, 1 }
algorith would provide a circle around the middle point if '1's are white, and same algorithm would provide 4 arcs near the middle points if '1's are chosen to be black.
I think moment of choice is in normalize function at
if (data[i, j] > 1)
If you change ">" to "<" you will get change of image for ambigous cases. And it would change nothing for non-ambigous cases. Ambiguity is easier to understand if you look at methods idea not algorithm. Look at saddle point - there is ambiguity in drawing contour because from the one hand saddle point is a minimum and from the other its a maximum - depends on direction of measurements.
Hope that helps to clear the confusion.
Edit: I elaborated in comments but for visibility I'm duplicating it here
I have a line C# code with drawing graphichpath, how to get all value every line pixel. not just point (x1,y1) and (x2,y2) point but I want all pixel from (x1,y1) to (x2,y2)
Here's an algorithm that should give you an estimation of the pixels between your two Points. Note it will not match what is on screen perfectly (which looks antialiased).
public static IEnumerable<Tuple<int,int>> EnumerateLineNoDiagonalSteps(int x0, int y0, int x1, int y1)
{
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;
while(true)
{
yield return Tuple.Create(x0, y0);
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;
}
}
}
Replace the Tuple with Point.
For more information, see:
http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
or
http://en.wikipedia.org/wiki/Xiaolin_Wu%27s_line_algorithm
It only works when slope is between 0 and 1. i'm not sure where to go from here. thanks for your help! This method reads in two points and draws the line between them using bresenhams algo. I don't know where to go to optimize it for all lines. thanks for your help.
void Bresenhams(int x1, int y1, int xk, int yk)
{
int deltaX = xk - x1;
int deltaY = yk - y1;
int error = 0;
int y = y1;
int x = x1;
int doubleDeltaX = 2 * deltaX;
bool steep = Math.Abs(yk - y1) > Math.Abs(xk - x1);
canvas.SetPixel(x1, y1, Color.Black);
if (!steep)
{
for (int i = x1 + 1; i <= xk; i++)
{
if (x1 > xk)
{
int temp = x1;
x1 = xk;
xk = temp;
temp = y1;
y1 = yk;
yk = temp;
}
error = error + deltaY;
if (error > deltaX)
{
y++;
error -= doubleDeltaX;
}
canvas.SetPixel(i, y, Color.Black);
}
}
else
{
for (int i = y1 + 1; i <= yk; i++)
{
if (y1 > yk)
{
int temp = x1;
x1 = xk;
xk = temp;
temp = y1;
y1 = yk;
yk = temp;
}
error = error + deltaY;
if (error > deltaY)
{
y++;
error -= doubleDeltaX;
}
canvas.SetPixel(x, i, Color.Black);
}
}
pictureBox1.Image = canvas;
}
Divide a circle into 8 parts. You can run Bresenham over one octant and draw all 8 at the same time. For center at 0,0:
0-45 x,y
45-90 y,x
90-135 -y,x
135-180 -x,y
180-225 -x,-y
225-270 -y,-x
270-315 y,-x
315-360 x,-y
I have the following:
bool AreNear(Point Old, Point Current)
{
int x1 = Convert.ToInt32(Old.X);
int x2 = Convert.ToInt32(Current.X);
int y1 = Convert.ToInt32(Old.Y);
int y2 = Convert.ToInt32(Current.Y);
if (x1 == x2) {
if (y1 == y2) {
return true;
}
}
return false;
}
I want to return true in the function if the current point is in 25 pixels radius of the old point. Can anyone tell me how to do that?
You can use the Pythagorean formula to calculate the distance between two points. In C#:
var d = Math.Sqrt(Math.Pow(x1 - x2, 2) + Math.Pow(y1 - y2, 2))
Why does this work? Have a look at the following diagram and remember that a^2 + b^2 = c^2 holds for right triangles:
Just calculate the square of the distance using Pythagoras' theorem, and compare to the square of the radius:
bool ComparePoints(Point Old, Point Current)
{
int x1 = Convert.ToInt32(Old.X);
int x2 = Convert.ToInt32(Current.X);
int y1 = Convert.ToInt32(Old.Y);
int y2 = Convert.ToInt32(Current.Y);
int dx = x1 - x2;
int dy = y1 - y2;
return (dx*dx + dy*dy) < 25*25;
}
You can use Math.Abs to get the distance:
public static bool InDistance(Point Old, Point Current, int distance)
{
int diffX = Math.Abs(Old.X - Current.X);
int diffY = Math.Abs(Old.Y - Current.Y);
return diffX <= distance && diffY <= distance;
}
use it:
bool arePointsInDistance = InDistance(new Point(100, 120), new Point(120, 99), 25);
Try using the distance formula http://www.purplemath.com/modules/distform.htm and compare the distance <=25
Below is a function that detects if two circles intersect. I want to change it to only detect if the periferi of the circles intersect. Hence, if circle A is completely inside circle B, there is no collision!
How?
private bool IsCircleCollision(
int x1, int y1, int radius1,
int x2, int y2, int radius2)
{
int dx = x2 - x1;
int dy = y2 - y1;
int distance = (dx * dx) + (dy * dy);
int radii = radius1 + radius2;
if (distance < radii * radii)
{
return true;
}
else
{
return false;
}
}
You work this out by calculating the distance between the two centres, D say. There is an intersection if
abs(R1-R2) < D < R1+R2
where R1 and R2 are the radii of the two circles.
The first test, abs(R1-R2) < D handles the case when one circle's centre is inside the other's. And the second test, D < R1+R2, handles the case when neither circle contains the other's centre.
So, adapting your code we have:
private bool IsCircleCollision(
int x1, int y1, int radius1,
int x2, int y2, int radius2)
{
int dx = x2 - x1;
int dy = y2 - y1;
double D = Math.Sqrt(dx*dx + dy*dy);
return Math.Abs(radius1-radius2)<D && D<radius1+radius2;
}
If performance is important here, you can do without the call to Math.Sqrt like this:
private bool IsCircleCollision(
int x1, int y1, int radius1,
int x2, int y2, int radius2)
{
int dx = x2 - x1;
int dy = y2 - y1;
int Dsqr = dx*dx + dy*dy;
int rdiff = Math.Abs(radius1-radius2);
int rsum = radius1+radius2
return rdiff*rdiff<Dsqr && D<rsum*rsum;
}
The perimeters will be intersecting if and only if the distance between the two centers is less than or equal to the sum of the two radii but greater than or equal to their absolute difference. With this fact, it shouldn't be hard to re-write the function.
You could add a check to see if the distance + radius1 is less than radius2 or distance + radius2 is less than radius1, but then you'll need distance to be the actual distance rather than its square.
else if (Math.Sqrt(dx * dx + dy * dy) < Math.Abs(radius1 - radius2))