I am generating rectangles with given random numbers in this class.
class Rect
{
double x;
double y;
public Rect(double _x, double _y)
{
x = _x;
y = _y;
}
public void Draw()
{
Gl.glBegin(Gl.GL_QUADS);
Gl.glVertex2d(x + (-0.05d), y + (-0.05d));
Gl.glVertex2d(x + (-0.05d), y + (0.05d));
Gl.glVertex2d(x + (0.05d), y + (0.05d));
Gl.glVertex2d(x + (0.05d), y + (-0.05d));
Gl.glEnd();
}
}
I call it in Paint function.
private void simpleOpenGlControl1_Paint(object sender, PaintEventArgs e)
{
Gl.glClearColor(0, 1, 0, 0);
Gl.glClear(Gl.GL_COLOR_BUFFER_BIT);
for (int i = 0; i < 4; i++)
{
rand = new Random();
double x = 2 * rand.NextDouble() - 1;
double y = 2 * rand.NextDouble() - 1;
rect= new Rect(x,y);
rect.Draw();
}
}
Everything looks fine but there is something wrong. I cant see the all rectangles. Some of them are missing. But if I toggle breakpoint somewhere or put the MessageBox.Show(x+" "+y); code works fine and shows me the number of rectangles what i want. I think my code is true but something wrong about OpenGL. I am using Tao Framework.
My guess is the problem is with this bit of code:
for (int i = 0; i < 4; i++)
{
rand = new Random();
double x = 2 * rand.NextDouble() - 1;
double y = 2 * rand.NextDouble() - 1;
rect= new Rect(x,y);
rect.Draw();
}
You are creating a new Random instance in every iteration of your loop and then use that instance to generate two random values. The sequence of values generated by Random depends on the seed that was used to initialize the Random. According to the documentation of the constructor used here:
The default seed value is derived from the system clock and has finite
resolution.
That is, if your loop runs fast enough, the different instances of Random in your loop will be initialized with the same seed, causing them to generate the same x and y values: the rectangles then overlap and appear to be missing. This also explains why your code is working if you interrupt it using breakpoints or messages boxes.
Edit: the best solution to this problem is to create a single Random instance outside of your loop, by initializing rand before your for statement or (as a class member) in the constructor of your class for example.
Related
I am currently developing a test program that makes sure that holes on a motherboard aren't too close to each other or that they aren't overlapping.
In order to do this, I am keeping all of the holes' X, Y coordinates and radii in objects called holeInfo's and the objects inside the list holeInfoList.
I am currently using a nested for loop to go through all of the holes and a basic mathematical formula to check the distance between the holes.
Here is the function I use:
public void checkHoleConditions()
{
for (int i = 0; i < holeInfoList.Count - 1; i++)
{
errorType = new List<string>();
for (int j = i + 1; j < holeInfoList.Count; j++)
{
holeMinSpaceFailed = false;
if (failsHoleConditions(holeInfoList[i], holeInfoList[j]))
{
if (holeMinSpaceFailed)
{
errorType.Add("X: " + holeInfoList[j].holeXCoordinate + " Y: " + holeInfoList[j].holeYCoordinate + "R: " + holeInfoList[j].holeDiameter + " too close.");
}
else
{
errorType.Add("X: " + holeInfoList[j].holeXCoordinate + " Y: " + holeInfoList[j].holeYCoordinate + "R: " + holeInfoList[j].holeDiameter + " overlap.");
}
invalidHole = new InvalidHole(holeInfoList[i], errorType);
invalidHoleList.Add(invalidHole);
Console.WriteLine("Hole Error Detected");
}
else
{
Console.WriteLine("Hole Check Successful");
}
}
}
}
public bool failsHoleConditions(HoleInfo holeOne, HoleInfo holeTwo)
{
float holeOneXCoordinate = holeOne.holeXCoordinate;
float holeOneYCoordinate = holeOne.holeYCoordinate;
float holeOneRadius = holeOne.holeDiameter / 2;
float holeTwoXCoordinate = holeTwo.holeXCoordinate;
float holeTwoYCoordinate = holeTwo.holeYCoordinate;
float holeTwoRadius = holeTwo.holeDiameter / 2;
float holeXDifferenceSquared = (float)Math.Pow((holeOneXCoordinate - holeTwoXCoordinate), 2);
float holeYDifferenceSquared = (float)Math.Pow((holeOneYCoordinate - holeTwoYCoordinate), 2);
float distanceBetweenCenters = (float)Math.Sqrt(holeXDifferenceSquared + holeYDifferenceSquared);
float distanceBetweenHoles = distanceBetweenCenters - (holeOneRadius + holeTwoRadius);
if (distanceBetweenHoles <= 0)
{
return true;
}
else if (distanceBetweenHoles <= minimumSpace)
{
holeMinSpaceFailed = true;
return true;
}
return false;
}
Currently, my program does the test in about 2.5 minutes for 254 list objects. Considering that this is a test program, 2.5 minutes for only 254 holes is a long time.
What are some of the algorithms that I can implement to make the test run faster?
An inspiration for this solution is physics engines, and the optimizations there that take care of collision detection.
I don't claim to know entirely how it works, and for better solutions you should try researching ODE or Bullet Dynamics for this.
Basically the solution is to separate objects (holes) into islands, and only compare each object's position to objects in the same island. If you can't come up with a way to properly separate islands, you could just do this:
Suppose we have 125 objects on a square field, 5 by 5. You can divide it into 25 primary square islands, and then 8 intersection islands (long islands, along the edges of the primary islands. The smallest side of these islands should be the minimum distance you want to compute). Islands can overlap. You have to parse the whole list once to make this split. Which means that so far we loop through 125 items total - O(n).
Next, for each island (33 total, O(n^(2/3)), find objects that are closer than they have to be, by using those same nested loops. Total complexity of each island is O((n / n^(2/3))^2) = O(n^(2/3)). Times the number of islands, we get total complexity for this algorithm = O(n^(4/3)), which is smaller than O(n^2) that was originally presented.
Hope this makes sense. I can write a Python demo if you want. It's just that it would be quite a lot of code.
Edit:
Or you could just use a 2D physics engine and plot the objects as circles with a diameter equal to the minimum distance between holes and then let it detect the collisions. Or take the relevant code from there (if license permits), since the entire physics engine is a bit overkill for the task.
https://github.com/VelcroPhysics/VelcroPhysics
Edit 2:
254 list objects
I thought you were parsing 254 different boards. This solution I highlighted would make sense only in huge computational loads.
holeMinSpaceFailed will never be true if failsHoleConditions is true
don't pass around logic like that
x * x is faster then Math.Pow
No need to take Sqrt - just square minimumSpace
Something like this. Runs 1 million 300 milliseconds. Something is wrong for your code to take minutes.
static byte HoleTooClose(HoleInfo x, HoleInfo y, float minDistance)
{
float holeSize = (x.Diameter + y.Diameter) / 2;
float deltaX = y.X - x.X;
float deltaY = y.Y - x.Y;
float distanceSquared = deltaX * deltaX + deltaY * deltaY - holeSize * holeSize;
if (distanceSquared <= 0)
{
return 0;
}
float minDistanceSquared = minDistance * minDistance;
if (distanceSquared <= minDistanceSquared)
{
return 1;
}
return 2;
}
internal struct HoleInfo
{
public float Diameter { get; internal set; }
public float X { get; internal set; }
public float Y { get; internal set; }
public HoleInfo (float x, float y, float diameter)
{
X = x;
Y = y;
Diameter = diameter;
}
}
static bool DistanceTooClose(System.Windows.Point x, System.Windows.Point y, Double minDistance)
{
double deltaX = Math.Abs(y.X - x.X);
double deltaY = Math.Abs(y.Y - x.Y);
double distanceSquared = deltaX * deltaX + deltaY * deltaY;
//double distance = Math.Sqrt(distanceSquared);
Double minDistanceSquared = minDistance * minDistance;
return (distanceSquared <= minDistanceSquared);
}
If you need to test all against all, one optimization can be to put them in a nxn matrix, instead of a list. Then, execute the validation on parallel. The bigger the matrix and the more cores you have the better. The parallel can also be executed on the list, but I'm not 100% sure if .Net will determine to wait for each thread to end, as the algorithm is sequential.
If your method uses euclidean distance, you can try to order the list first, based on this distance. sqr(x)+sqr(y) with respect to 0 can be a score to sort first. I think .Net can handle this sorting easily. Later, just run your algorithm till the first allowed circuit. Then, you know the rest must be accepted, so you will only execute on the first elements of the list
While using a self-written graphing control I noticed that the painting of the graph was much slower while displaying noisy data than when it displayed clean data.
I dug further into and narrowed the problem down to its bare minimum difference: Drawing the same amount of lines with varying Y values versus drawing lines with the same Y value.
So for example I put together the following tests. I generate lists of points, one with random Y values, one with the same Y, and one with a Zig-Zag Y pattern.
private List<PointF> GenerateRandom(int n, int width, int height)
{
//Generate random pattern
Random rnd = new Random();
float stepwidth = Convert.ToSingle(width / n);
float mid = Convert.ToSingle(height / 2);
float lastx = 0;
float lasty = mid;
List<PointF> res = new List<PointF>();
res.Add(new PointF(lastx, lasty));
for (int i = 1; i <= n; i++)
{
var x = stepwidth * i;
var y = Convert.ToSingle(height * rnd.NextDouble());
res.Add(new PointF(x, y));
}
return res;
}
private List<PointF> GenerateUnity(int n, int width, int height)
{
//Generate points along a simple line
float stepwidth = Convert.ToSingle(width / n);
float mid = Convert.ToSingle(height / 2);
float lastx = 0;
float lasty = mid;
List<PointF> res = new List<PointF>();
res.Add(new PointF(lastx, lasty));
for (int i = 1; i <= n; i++)
{
var x = stepwidth * i;
var y = mid;
res.Add(new PointF(x, y));
}
return res;
}
private List<PointF> GenerateZigZag(int n, int width, int height)
{
//Generate an Up/Down List
float stepwidth = Convert.ToSingle(width / n);
float mid = Convert.ToSingle(height / 2);
float lastx = 0;
float lasty = mid;
List<PointF> res = new List<PointF>();
res.Add(new PointF(lastx, lasty));
var state = false;
for (int i = 1; i <= n; i++)
{
var x = stepwidth * i;
var y = mid - (state ? 50 : -50);
res.Add(new PointF(x, y));
state = !state;
}
return res;
}
I now draw each list of points a few times and compare how long it takes:
private void DoTheTest()
{
Bitmap bmp = new Bitmap(970, 512);
var random = GenerateRandom(2500, bmp.Width, bmp.Height).ToArray();
var unity = GenerateUnity(2500, bmp.Width, bmp.Height).ToArray();
var ZigZag = GenerateZigZag(2500, bmp.Width, bmp.Height).ToArray();
using (Graphics g = Graphics.FromImage(bmp))
{
var tUnity = BenchmarkDraw(g, 200, unity);
var tRandom = BenchmarkDraw(g, 200, random);
var tZigZag = BenchmarkDraw(g, 200, ZigZag);
MessageBox.Show(tUnity.ToString() + "\r\n" + tRandom.ToString() + "\r\n" + tZigZag.ToString());
}
}
private double BenchmarkDraw(Graphics g, int n, PointF[] Points)
{
var Times = new List<double>();
for (int i = 1; i <= n; i++)
{
g.Clear(Color.White);
System.DateTime d3 = DateTime.Now;
DrawLines(g, Points);
System.DateTime d4 = DateTime.Now;
Times.Add((d4 - d3).TotalMilliseconds);
}
return Times.Average();
}
private void DrawLines(Graphics g, PointF[] Points)
{
g.DrawLines(Pens.Black, Points);
}
I come up with the following durations per draw:
Straight Line: 0.095 ms
Zig-Zag Pattern: 3.24 ms
Random Pattern: 5.47 ms
So it seems to get progressively worse, the more change there is in the lines to be drawn, and that is also a real world effect I encountered in the control painting I mentioned in the beginning.
My questions are thus the following:
Why does it make a such a brutal difference, which lines are to be drawn?
How can I improve the drawing speed for the noisy data?
Three reasons come to mind:
Line Length : Depending on the actual numbers sloped lines may be longer by just a few pixels or a lot or even by some substantial factor. Looking at your code I suspect the latter..
Algorithm : Drawing sloped lines does take some algorithm to find the next pixels. Even fast drawing routines need to do some computations as opposed to vertical or horizontal lines, which run straight through the pixel arrays.
Anti-Aliasing : Unless you turn off anti-aliasing completely (with all the ugly consequences) the number of pixels to paint will also be around 2-3 times more as all those anti-aliasing pixels above and below the center lines must also be calculated and drawn. Not to forget calculating their colors!
The remedy for the latter part is obviously to turn off anti-aliasing, but the other problems are simply the way things are. So best don't worry and be happy about the speedy straight lines :-)
If you really have a lot of lines or your lines could be very long (a few time the size of the screen), or if you have a lot of almost 0 pixel line, you have to wrote code to reduce useless drawing of lines.
Well, here are some ideas:
If you write many lines at the same x, then you could replace those by a single line between min and max y at that x.
If your line goes way beyond the screen boundary, you should clip them.
If a line is completly outside of the visible area, you should skip it.
If a line have a 0 length, you should not write it.
If a line has a single pixel length, you should write only that pixel.
Obviously, the benefit depends a lot on how many lines you draw... And also the alternative might not give the exact same result...
In practice, it you draw a chart on a screen, then if you display only useful information, it should be pretty fast on modern hardware.
Well if you use style or colors, it might not be as trivial to optimize the displaying of the data.
Alternatively, they are some charting component that are optimized for display large data... The good one are generally expensive but it might still worth it. Often trials are available so you can get a good idea on how much you might increase the performance and then decide what to do.
Right now, I'm working on a little Jump'n'Run game in XNA. I decided to load textures from a tileset,
and designed a method for getting the source rectangles of a bigger rectangle. Within the method, the calculated rectangles are being added to a list, and the list is returned at the end of the method. However, the method doesn't seem to work properly. When trying to get a rectangle from a given index out of the list, I'm getting a index out of range exception. I tried this with several numbers, it still wont work. here is my method for getting the rectangles:
public static List<Rectangle> getSourceRectangles(Rectangle original, int partWidth, int partHeight)
{
List<Rectangle> rlist = new List<Rectangle>();
int ix, iy;
ix = original.Width / partWidth;
iy = original.Height / partHeight;
for (int x = 0; x < ix; x++)
{
for (int y = 0; y < iy; y++)
{
Rectangle r = new Rectangle(x * partWidth, y * partHeight, partWidth, partHeight);
rlist.Add(r);
}
}
return rlist;
}
I save the return value in a global Container class.
this is were I get the error: (ist just the constructor of the NormalTile class!)
public NormalTile(int _TextureIndex,Rectangle _rect)
{
this.rect = _rect;
this.TileTextureIndex = _TextureIndex - 1;
this.tex_rect = Global.TileTextures[TileTextureIndex];//HERE
}
Why is this even Happening?
I have created a somewhat complete application which allows me to create a map (.txt file with information about all the points of the map), load it and draw it.
My solution for this was, inside the windows forms application, to put a panel (since I need to be able to move on map) and inside that panel pictureboxes(since I want to put a background image and image on them) that represent points of map in size 50x50 pixels. The problem I am facing now is increased load time for my application, since I am loading pictures into the pictureboxes...
Does anyone have any alternative suggestion to what I have been attempting?
Visual representation might help:
The code, as requested: (well, some of it)
private void Load_Map()
{
for (int i = Y - 12; i < Y + 12; i++)
{
if ((i >= 0) & (i < Int32.Parse(MP.Mheight)))
{
string Line = xline[i];
for (int j = X - 12; j < X + 12; j++)
{
if ((j >= 0) & (j < Int32.Parse(MP.Mwidth)))
{
int X = i * Int32.Parse(MP.Mwidth) + j;
int Z = Int32.Parse(Line[j].ToString());
Map_Location[X] = Z;
Color H = new Color();
Map_Point(j, i, Map_Height(Z, H), 50);
}
}
}
}
}
Creating points:
private void Map_Point(int X, int Y, Color H, int Point_Size)
{
PictureBox MP = new PictureBox();
MP.Name = Map_Coordinates(X, Y);
MP.Size = new Size(Point_Size, Point_Size);
MP.Location = new Point(Y * (Point_Size + 1) + 4, X * (Point_Size + 1) + 4);
MP.BackColor = H;
Control MW = this.Controls["WorldMap"];
MW.Controls.Add(MP);
}
You'll be better off creating a custom control by deriving from System.Windows.Forms.Control and overriding the OnPaint method and doing your own drawing and handling click events yourself.
Using a large number of WinForms controls the way you're doing is an exercise in pain, as WinForms will create a hWnd object for each control, and WinForms doesn't scale too well, unfortunately.
You should be using System.Drawing.Graphics
Here are the MSDN Tutorials for it.
It has a method called DrawImage , which you can use instead of a picture box. For the grid you should be drawing it as a rectangle with a color for the background and vertical/horizontal lines to make the grid.
I'm trying to draw the Mandelbrot fractal, using the following method that I wrote:
public void Mendelbrot(int MAX_Iterations)
{
int iterations = 0;
for (float x = -2; x <= 2; x += 0.001f)
{
for (float y = -2; y <= 2; y += 0.001f)
{
Graphics gpr = panel.CreateGraphics();
//System.Numerics
Complex C = new Complex(x, y);
Complex Z = new Complex(0, 0);
for (iterations = 0; iterations < MAX_Iterations && Complex.Abs(Z) < 2; Iterations++)
Z = Complex.Pow(Z, 2) + C;
//ARGB color based on Iterations
int r = (iterations % 32) * 7;
int g = (iterations % 16) * 14;
int b = (iterations % 128) * 2;
int a = 255;
Color c = Color.FromArgb(a,r,g,b);
Pen p = new Pen(c);
//Tranform the coordinates x(real number) and y(immaginary number)
//of the Gauss graph in x and y of the Cartesian graph
float X = (panel.Width * (x + 2)) / 4;
float Y = (panel.Height * (y + 2)) / 4;
//Draw a single pixel using a Rectangle
gpr.DrawRectangle(p, X, Y, 1, 1);
}
}
}
It works, but it's slow, because I need to add the possibility of zooming. Using this method of drawing it isn't possible, so I need something fast. I tried to use a FastBitmap, but it isn't enough, the SetPixel of the FastBitmap doesn't increase the speed of drawing. So I'm searching for something very fast, I know that C# isn't like C and ASM, but it would be interesting do this in C# and Winforms.
Suggestions are welcome.
EDIT: Mendelbrot Set Zoom Animation
I assume it would be significantly more efficient to first populate your RGB values into a byte array in memory, then write them in bulk into a Bitmap using LockBits and Marshal.Copy (follow the link for an example), and finally draw the bitmap using Graphics.DrawImage.
You need to understand some essential concepts, such as stride and image formats, before you can get this to work.
As comment said put out CreateGraphics() out of the double loop, and this is already a good imrovement.
But also
Enable double buffering
For zooming use MatrixTransformation functions like:
ScaleTransform
RotateTransform
TranslateTransform
An interesting article on CodeProject can be found here. It goes a little bit further than just function calls, by explaining actually Matrix calculus ( a simple way, don't worry), which is good and not difficult to understand, in order to know what is going on behind the scenes.