I'm working on a project that requires me to accurately control the number of pixels that are used to draw (roughly) circular stimuli, and although Bresenham's algorithms are great, they don't draw circles of an arbitrary area (to my knowledge). I've tried scripts that interrupt Bresenham's algorithm when the desired area has been plotted, but the results are decidedly hit-or-miss. Does anyone know of a way to plot the "best" circle (somewhat subjective, I know) using a given number of pixels? Many thanks!
A rough way of doing it, for example:
The radius of a circle of area 1000 sq px is sqrt(1000/pi) = 17.8... That circle should then fit in a 35x35 matrix. If you make "indices" for that matrix where the central pixel is (0,0), you can check easily if the pixel falls in the circle or not by substitution into the equation of a circle x^2 + y^2 = r^2. Or you can use the alternative equation for a circle centered at (a,b). If it evaluates to TRUE, it does, if not, it's outside the circle.
As a pseudocode/example, in Python I would do an optimized version of:
import numpy, math
target_area = 1000.0
r = (target_area / math.pi) ** 0.5
m = numpy.zeros((2*r+2,2*r+2))
a, b = r, r
for row in range(0, m.shape[0]):
for col in range(0, m.shape[1]):
if (col-a)**2 + (row-b)**2 <= r**2:
m[row,col] = 1
numpy.sum(m)
#>>> 999
Here is the result when the target area is 100,000 pixels (the actual circle generated is 99988.0):
You could also write a routine to find which areas can be matched more closely than others with this algorithm, and select those values to ensure conformity.
The area of a circle is A=Pi*r2. You're starting from the area and (apparently) want the radius, so we divide both sides by Pi to get: r2=A/pi. Taking the square root of both sides then gives us: r=sqrt(A/pi). Once you have the radius, drawing with most of the normal algorithms should be straightforward.
A simple (but somewhat naive approach) would be to simply count the number of pixels drawn by Bresenham's algorithm for a given radius, and then use binary search to find the radius that produces the desired number of pixels.
My first thought is to use an algorithm with sub-pixel precision. Consider what happens if you're center has irrational coordinates and you gradually increase the radius. This would fill seemingly random pixels around the perimeter as they became included in the circle. You want to avoid symmetry that causes the 4 quadrants of the circle adding pixels at the same time so you get closer to single pixels getting added. How something like this could be implemented I haven't a clue.
I had to solve a single instance of the 3d version once. I needed to a set of lattice points inside a sphere to be less-than or equal to 255. IIRC if r*r = 15 there are 240 points inside the sphere. I was not concerned with getting 255 exactly though.
Supposedly you have 2000 pixels in total that should make up your complete circle. By complete I mean there should be no breakage in pixels and must be connected to each other. Since 2Pi*R = circumference, the running length of diameter of the circle, this is the total amount of pixels you have. Now simply write R = 2000/2*Pi and this will give you the radius. Now you should be able to draw a circle the comprised of 2000 pixels. I hope this is what you wanted.
Let's forget about pixels for a second and let's work through the basic math/geometry.
We all know that
Area of a Circle = Pi * Radius ^2
which is the same as saying
Area of a Circle = Pi * (Diameter / 2) ^2
We all know that
Area of the Square Enclosing the Circle (i.e. each side of the square is tangent to the circle) = Diameter * Diameter
Thus
Ratio of the Circle Area to the Square Area = Circle Area / Square Area = (Pi * (Diameter / 2) ^2) / (Diameter * Diameter) = Pi / 4
Now let's assume that we have a circle and square with a pixel count large enough so that we don't have to worry about the troublesome edge cases around the border of the circle. In fact let's assume for a second that we have a very large diameter (maybe 10,000 or maybe even infinite). With this assumption the following holds:
Number of Pixels in the Circle = (Number of Pixels in the Square) * (Ratio of the Circle Area to the Square Area)
In other words for a sufficiently large number of pixels, the ratio of the areas of a perfectly drawn circle to a perfectly drawn square will approximate the ratio of the number of pixels in a pixelated circle to the number of pixels in the enclosing pixelated square.
Now in a pixelated square, the number of pixels in that square is the number of pixels across times the number of pixels high. Or in other words it is the square's diameter (in pixels) squared. Let's call the square's pixel diameter d. So substituting with the formulas above we have:
Number of Pixels in the Circle = (d * d) * (Pi /4)
So now let's solve for d
d = Sqrt(4 * (Num of Pixels in the Circle) / Pi)
Well we said earlier that d was the diameter of the square. Well it also happens to be the diameter of the circle. So when you want to draw a circle with a certain number of pixels, you draw a circle with the diameter being:
Diameter of Circle = Sqrt(4 * (Desired Number of Pixels in Circle Area) / Pi)
Now obviously you have to make some choices about rounding and so forth (there is no such thing as a fractional pixel), but you get the point. Also, this formula is more accurate as the desired number of pixels for the area of the circle goes up. For small amounts of pixels the roundoff error may not give you exactly the right number of pixels.
Related
I have some area X by Y pixels and I need to fill it up pixel by pixel. The problem is that at any given moment the drawn shape should be as round as possible.
I think that this algorithm is subset of Ordered Dithering, when converting grayscale images to one-bit, but I could not find any references nor could I figure it out myself.
I am aware of Bresenham's Circle, but it is used to draw circle of certain radius not area.
I created animation of all filling percents for 10 by 10 pixel grid. As full area is 10x10=100px, then each frame is exactly 1% inc.
A filled disk has the equation
(X - Xc)² + (Y - Yc)² ≤ C.
When you increase C, the number of points that satisfies the equation increases, but because of symmetry it increases in bursts.
To obtain the desired filling effect, you can compute (X - Xc)² + (Y - Yc)² for every pixel, sort on this value, and let the pixels appear one by one (or in a single go if you know the desired number of pixels).
You can break ties in different ways:
keep the original order as when you computed the pixels, by using a stable sort;
shuffle the runs of equal values;
slightly alter the center coordinates so that there are no ties.
Filling with the de-centering trick.
Values:
Order:
I'm trying to plot XY graph in real time using Java. Functions that only rely on X are easy. Just iterate over x0...xn, get value and draw lines between the points. There are a lot of guides on it and it's intuitive.
But there is literally no guide on plotting graphs with x AND y being a variable.
Consider this equation: sin(x^3 * y^2) = cos(x^2 * y^3)
Using online Graph plotter I get this:
While my best result plotting the same function is this:
I just iterate over every pixel on screen and pass pixel positions as parameters to the function. If function's output is close to 0, I color the pixel. As you can see it's bad. It also takes huge amount of processing power. It only redraws once every couple of seconds. And if I try to increase precision, all lines just become thicker. Especially around intersections.
My question is how can I make my program faster and make it produce better looking graphs. Maybe there are some algorithms for that purpose?
The challenge is to chose the correct threshold. Pixels where abs(f(x,y)) is below the threshold should be colored. Pixels above the threshold should be white.
The problem is that if the threshold is too low, gaps appear in places where no pixel is exactly on the line. On the other hand, if the threshold is too high, the lines widen in places where the function is near zero, and the function is changing slowly.
So what's the correct threshold? The answer is the magnitude of the gradient, multiplied by the radius of a pixel. In other words, the pixel should be colored when
abs(f(x,y)) < |g(x,y)| * pixelRadius
The reason is that the magnitude of the gradient is equal to the maximum slope of the surface (at a given point). So a zero crossing occurs within a pixel if the slope is large enough to reduce the function to zero, inside the pixel.
That of course is only rough approximation. It assumes that the gradient doesn't change significantly within the area bounded by the pixel. The function in the question conforms to that assumption reasonably well, except in the upper right corner. Notice that in the graph below, there are Moiré patterns in the upper right. I believe that those are due to the failure in my antialiasing calculation: I don't compensate for a rapidly changing gradient.
In the graph below, pixels are white if
abs(f(x,y)) > |g(x,y)| * pixelRadius
Otherwise the pixel intensity is a number from 0 to 1, with 0 being black and 1 being white:
intensity = abs(f(x,y)) / (|g(x,y)| * pixelRadius)
I don't how exactly the online plotter did, but here are some suggestions.
Simplify your equation, as to this specific one, you can easily have x^2 * y^2 * (x ± y) = (2 * n + 1 / 2) * pi where n for any integer. It's much clearer than the original one.
Draw lines rather than points. Every n here stands for 4 curves, you can now loop over x and figure out y and draw a line between adjacent points.
Hope it helps!
I am building a road editor where one can drag predefined road segments together and combine them to a connected road. One of those segments is a right curve.
The curve is drawn as SVG (using D3 arc path function) and has two handles to change the radius and the length directly within the SVG (small black circle changes length and small black square changes the radius). I use a d3 drag handler on the handles.
To calculate the new central angle I do as follows:
get YOffset from center point of the arc
flip YOffset (to match screen y and math)
get corresponding x value with Pythagoras (x = Math.sqrt(r^2 - YOffset^2))
get the respective central angle (Math.PI / 2 - Math.atan2(YOffset, x);
This will only work if the arc starts at PI/2 like in the figure. If I add further arcs with arbitrary start angles (see next figure, red arc), my solution wont work.
I'm looking for a general solution so it will work for any arc regardless of its start angle.
To me it seems this is not much of a programming problem, but of math. What I understand is: given a start point (x₁, y₁), an end pont(x₂, y₂) and a radius r, what is the angle α?
You can compute the distance d between the two points. Half its length is the far leg of a right triangle with r as its hypothenuse. d/2r is the sinus of the near angle; double that and you have the angle between the end points.
(And, having α expressed in radians, the path length is simply α * r.)
I've just implemented collision detection using SAT and this article as reference to my implementation. The detection is working as expected but I need to know where both rectangles are colliding.
I need to find the center of the intersection, the black point on the image above (but I don't have the intersection area neither). I've found some articles about this but they all involve avoiding the overlap or some kind of velocity, I don't need this.
The information I've about the rectangles are the four points that represents them, the upper right, upper left, lower right and lower left coordinates. I'm trying to find an algorithm that can give me the intersection of these points.
I just need to put a image on top of it. Like two cars crashed so I put an image on top of the collision center. Any ideas?
There is another way of doing this: finding the center of mass of the collision area by sampling points.
Create the following function:
bool IsPointInsideRectangle(Rectangle r, Point p);
Define a search rectangle as:
TopLeft = (MIN(x), MAX(y))
TopRight = (MAX(x), MAX(y))
LowerLeft = (MIN(x), MIN(y))
LowerRight = (MAX(x), MIN(y))
Where x and y are the coordinates of both rectangles.
You will now define a step for dividing the search area like a mesh. I suggest you use AVG(W,H)/2 where W and H are the width and height of the search area.
Then, you iterate on the mesh points finding for each one if it is inside the collition area:
IsPointInsideRectangle(rectangle1, point) AND IsPointInsideRectangle(rectangle2, point)
Define:
Xi : the ith partition of the mesh in X axis.
CXi: the count of mesh points that are inside the collision area for Xi.
Then:
And you can do the same thing with Y off course. Here is an ilustrative example of this approach:
You need to do the intersection of the boundaries of the boxes using the line to line intersection equation/algorithm.
http://en.wikipedia.org/wiki/Line-line_intersection
Once you have the points that cross you might be ok with the average of those points or the center given a particular direction possibly. The middle is a little vague in the question.
Edit: also in addition to this you need to work out if any of the corners of either of the two rectangles are inside the other (this should be easy enough to work out, even from the intersections). This should be added in with the intersections when calculating the "average" center point.
This one's tricky because irregular polygons have no defined center. Since your polygons are (in the case of rectangles) guaranteed to be convex, you can probably find the corners of the polygon that comprises the collision (which can include corners of the original shapes or intersections of the edges) and average them to get ... something. It will probably be vaguely close to where you would expect the "center" to be, and for regular polygons it would probably match exactly, but whether it would mean anything mathematically is a bit of a different story.
I've been fiddling mathematically and come up with the following, which solves the smoothness problem when points appear and disappear (as can happen when the movement of a hitbox causes a rectangle to become a triangle or vice versa). Without this bit of extra, adding and removing corners will cause the centroid to jump.
Here, take this fooplot.
The plot illustrates 2 rectangles, R and B (for Red and Blue). The intersection sweeps out an area G (for Green). The Unweighted and Weighted Centers (both Purple) are calculated via the following methods:
(0.225, -0.45): Average of corners of G
(0.2077, -0.473): Average of weighted corners of G
A weighted corner of a polygon is defined as the coordinates of the corner, weighted by the sin of the angle of the corner.
This polygon has two 90 degree angles, one 59.03 degree angle, and one 120.96 degree angle. (Both of the non-right angles have the same sine, sin(Ɵ) = 0.8574929...
The coordinates of the weighted center are thus:
( (sin(Ɵ) * (0.3 + 0.6) + 1 - 1) / (2 + 2 * sin(Ɵ)), // x
(sin(Ɵ) * (1.3 - 1.6) + 0 - 1.5) / (2 + 2 * sin(Ɵ)) ) // y
= (0.2077, -0.473)
With the provided example, the difference isn't very noticeable, but if the 4gon were much closer to a 3gon, there would be a significant deviation.
If you don't need to know the actual coordinates of the region, you could make two CALayers whose frames are the rectangles, and use one to mask the other. Then, if you set an image in the one being masked, it will only show up in the area where they overlap.
I am writing a function to draw an approximate circle on a square array (in Matlab, but the problem is mainly algorithmic).
The goal is to produce a mask for integrating light that falls on a portion of a CCD sensor from a diffraction-limited point source (whose diameter corresponds to a few pixels on the CCD array). In summary, the CCD sensor sees a pattern with revolution-symmetry, that has of course no obligation to be centered on one particular pixel of the CCD (see example image below).
Here is the algorithm that I currently use to produce my discretized circular mask, and which works partially (Matlab/Octave code):
xt = linspace(-xmax, xmax, npixels_cam); % in physical coordinates (meters)
[X Y] = meshgrid(xt-center(1), xt-center(2)); % shifted coordinate matrices
[Theta R] = cart2pol(X,Y);
R = R'; % cart2pol uses a different convention for lines/columns
mask = (R<=radius);
As you can see, my algorithm selects (sets to 1) all the pixels whose physical distance (in meters) is smaller or equal to a radius, which doesn't need to be an integer.
I feel like my algorithm may not be the best solution to this problem. In particular, I would like it to include the pixel in which the center is present, even when the radius is very small.
Any ideas ?
(See http://i.stack.imgur.com/3mZ5X.png for an example image of a diffraction-limited spot on a CCD camera).
if you like to select pixels if and only if they contain any part of the circle C:
in each pixel place a small circle A with the radius = halv size of the pixel, and another one around it with R=sqrt(2)*half size of the circle (a circumscribed circle)
To test if two circles touch each other you just calculate the center to center distances and subtract the sum of the two radii.
If the test circle C is within A then you select the pixel. If it's within B but not C you need to test all four pixel sides for overlap like this Circle line-segment collision detection algorithm?
A brute force approximate method is to make a much finer grid within each pixel and test each center point in that grid.
This is a well-studied problem. Several levels of optimization are possible:
You can brute-force check if every pixel is inside the circle. (r^2 >= (x-x0)^2 + (y-y0)^2)
You can brute-force check if every pixel in a square bounding the circle is inside the circle. (r^2 >= (x-x0)^2 + (y-y0)^2 where |x-x0| < r and |y-y0| < r)
You can go line-by-line (where |y-y0| < r) and calculate the starting x ending x and fill all the lines in between. (Although square roots aren't cheap.)
There's an infinite possibility of more sophisticated algorithms. Here's a common one: http://en.wikipedia.org/wiki/Midpoint_circle_algorithm (filling in the circle is left as an exercise)
It really depends on how sophisticated you want to be based on how imperative good performance is.