(Login — Register) |
Thread Rating:
Drawing primitives tutorial (lines, circles, ellipses, etc) |
01-01-2011, 10:36 PM,
|
|||
|
|||
Drawing primitives tutorial (lines, circles, ellipses, etc)
Introduction:
From primary school, we all know that a perfect line is series of an infinite number of points sorted together in space. Each point has an infinitely accurate position on space meaning that the coordinates of each point is a floating point number with an infinite amount of numbers behind itâs point. Unfortunately, our computer is far from perfect, and cannot calculate infinite values. Thatâs why a computer always draws a line as near as possible to the real thing. Any beginner programmer quickly realizes that screen shows images using pixels, whose coordinates can only be determined using integer numbers. How does he then draw those beautiful circles, etc..? Letâs get right down to business: Lines: Iâve seen and heard of many methods to draw these simple objects and they all seemed exaggerated to me. I mean, how much can you optimize this simple piece of code?? However, it is understandable, because lines are usually used to draw many other primitives, like squares and triangles. I will, anyway, use a simple technique, which will determine the position of each pixel to be lit, and then use a simple putpixel routine. (I program in C++ using Allegro, but these examples will be so easy that you should have no problem rewriting them to anything else; I also recommend everybody to check the source code of any graphics library (like the document âgfx.câ in Allegroâs source) for it is an excellent âsourceâ of information): hline() and vline() [horizontal and vertical] is the simplest of all lines. The method is to go from one end of the line to the other putting pixels all the way. Something like this: Code: void hline(int x1, int x2, int y) //x1 is the beginning x coord.; x2 is the end one; y is the y coord. vline() is pretty much the same, just that coordinates are switched: Code: void vline(int x, int y1, int y2) We want to get something like this: Imagine that the little squares are actually pixels, the two red dots are virtual beginning and end of the line, and the thin black line connecting the two dots is a virtually perfect line, or something we want to get as close to as we can. The gray colored pixels would be more or less something we see on the screen. There are two algorithms we can use, each for its own type of situation: 1. First would go something like this: we follow the âxâ coordinate one-by-one, and calculate the âyâ as the same percentage âxâ made on its length. This sounds a bit inaccurate, but basically we want to achieve that âxâ and âyâ meet at the end. Look at the code first: Code: void line(int x1,int y1,int x2,int y2) 2. The other algorithm is the same as the first one, but this time we move one-by-one on the y coordinate: Code: void line(int x1,int y1,int x2,int y2) BAD
GOOD
Note: you could optimize this code by throwing the things that can be precalculated, before the loop:Code: void line(int x1,int y1,int x2,int y2) Code: if(x2 Circle: I will describe two methods of drawing circles: one will be using a simple property of all circles, and the other will be a bit more complex and will help us to later draw spirals. 1. Each circle has a simple property that each of his points is in the exact same distance from the center. That distance is called radius: dx = abs(rx-x) and dy=abs(ry-y) // [abs()-absolute value] So from simple mathematics we can say that: dx^2 + dy^2 = r^2 for every point of the circle⦠The procedure practically checks each point in a square 2r*2r and if one of them fits the condition then we putpixel() there: Code: void circle(int rx, int ry, int r) If you run this program you may notice that the circle is broken. Thatâs because, again, the screen isnât perfect so heâll hardly get that x^2 + y^2 equals âexactlyâ r^2. To fix this little inconvenience one has to ease up this âtightâ condition: Code: void circle(int rx, int ry, int r, int f) To make a filled circle: Code: void circle(int rx, int ry, int r) Just to show you how cool this method can be, take a look at this simple fractal (Itâs called Sierpinskiâs triangle): Code: void Sierpinski() To make a long story short, I finally conducted this explanation: -if we start from the top of the circle and watch the X coordinate of each pixel we weâll see that they increase to a certain point, then decrease for the same amount, then decrease once more and finally increase to return to the same point it started. Does that remind you of something? Letâs put it on paper and then make it a bit smoother: Yes, itâs a sine! For you that still donât get it: X coordinates in a circle move exactly the same as the numbers in the sine function, that means they can now easily be calculated. Y coordinate is very similar only itâs shifted 90 degrees (or PI/2) to right. On the drawing above, red sinusoid is for the X coordinate and blue for Y. So, we will calculate each point as the distance of the coordinate from the center of the circle by a value calculated from a sinusoidal function. But, how do we control the radius? As we all know sine returns values from -1 to 1 and our X coordinate (and Y for that matter) takes values from -R to R, so it turns out we only have to multiply the value of sine with R and we get our circle: Code: #include Weâre just one step from creating spirals so letâs get going. Spirals: Spirals can be made in different ways. Iâve heard of people that create spirals off of arcs, but I wanted to do it better. Spirals and circles are actually pretty similar. The only differences is that spirals donât end after 2*pi (360 degrees) and that their radius increases (starting from zero). What we want to do is modify the existing circle algorithm to finish after, letâs say, 8*pi (which makes 4 full turns) and make r increase: Code: void spiral(int rx, int ry) Now we only have to alter the algorithm: Code: void spiral(int rx, int ry) Code: void spiral(int rx, int ry) |
|||
« Next Oldest | Next Newest »
|
Users browsing this thread: 1 Guest(s)