Circle Rasterization Algorithm - center between pixels - graphics

I have a problem where I have to select all squares (think pixels) that are partially within a circle (even if the circle only cuts through a small corner of the square, but not if it goes through one of the corner vertices). The radius is an integer multiple of the pixel size.
The problem is that the center of the circle is between pixels, i.e. on the corner vertices of four pixels.
I want to visit each pixel only once.
For example, I would like to select all white pixels in the following images:
R = 8 px
R = 10 px
For a circle with the center in the center of a pixel, this wouldn't be a problem, and I could use the usual form of the Bresenham algorithm:
public void checkCircle(int x0, int y0, int radius) {
int x = radius;
int y = 0;
int err = -x;
while (x > 0) {
while (err <= 0) {
y++;
err += 2 * y + 1;
}
checkVLine(x0 + x, y0 - y, y0 + y);
checkVLine(x0 - x, y0 - y, y0 + y);
x--;
err -= 2 * x + 1;
}
checkVLine(x0, y0 - radius, y0 + radius);
}
public void checkVLine(int x, int y0, int y1) {
assert(y0 <= y1);
for (int y = y0; y <= y1; y++)
checkPixel(x, y);
}
Sadly, I don't see how to adapt it to support inter-pixel circles.

For the first quadrant - cell should be marked if its left bottom corner lies inside circle, so you can rasterize with simple loops
for dy = 0 to R-1
dx = 0
sq = R * R - dy * dy
while dx * dx < sq
mark (dx, dy)
mark (dx, -dy-1)
mark (-dx-1, dy)
mark (-dx-1, -dy-1)
To fill whole horizontal lines, you can calculate max value for dx
for dy = 0 to R-1
mdx = Floor(Sqrt(R * R - dy * dy))
fill line (-mdx-1,dy)-(mdx,dy)
fill line (-mdx-1,-dy-1)-(mdx,-dy-1)

Related

How to draw a line on really low resolution

I am currently working on a project on arduino which involves drawing a line on a 8x8 rgb led display, given 2 random coordinates, how do I determine which pixels between them should be painted?
Any help is apprecieated
Here is a simple implementation of the line drawing algorithm mentioned above.
Note that this example will only work if x1 is less than x2.
void drawLine(int x1, int y1, int x2, int y2) {
int dx = x2 - x1;
int dy = y2 - y1;
for (int x = x1; x < x2; x++){
int y = y1 + dy * (x - x1) / dx;
plot(x, y);
}
}
void plot(int x, int y) {
// Draw each pixel
}

Is there a better way to generate points on a circle than trying out points in the equation x^2 + y^2 = r^2?

I have seen many apps which draw circles e.g pygame for python, p5.js for javascript. But I cannot find a method to find out points on a circle efficiently. My current solution to the problem involves trying out all the numbers in the square in which the circle can be inscribed.
This can't be the most efficient method to do it. What is the method used at the industry level? Does it involve optimization or is it a whole new method?
A Midpoint Circle Algorithm could be used.
And an implementation e.g. in C from rosettacode.org:
#define plot(x, y) put_pixel_clip(img, x, y, r, g, b)
void raster_circle(
image img,
unsigned int x0,
unsigned int y0,
unsigned int radius,
color_component r,
color_component g,
color_component b )
{
int f = 1 - radius;
int ddF_x = 0;
int ddF_y = -2 * radius;
int x = 0;
int y = radius;
plot(x0, y0 + radius);
plot(x0, y0 - radius);
plot(x0 + radius, y0);
plot(x0 - radius, y0);
while(x < y)
{
if(f >= 0)
{
y--;
ddF_y += 2;
f += ddF_y;
}
x++;
ddF_x += 2;
f += ddF_x + 1;
plot(x0 + x, y0 + y);
plot(x0 - x, y0 + y);
plot(x0 + x, y0 - y);
plot(x0 - x, y0 - y);
plot(x0 + y, y0 + x);
plot(x0 - y, y0 + x);
plot(x0 + y, y0 - x);
plot(x0 - y, y0 - x);
}
}

How to draw this circle instead of Bresenham's Circle Algorithm

int main()
{
const auto console = ::GetConsoleWindow();
const auto context = ::GetDC(console);
constexpr auto red = RGB(255, 0, 0);
constexpr auto yellow = RGB(255, 255, 0);
RECT rectClient, rectWindow;
GetClientRect(console, &rectClient);
GetWindowRect(console, &rectWindow);
int posx, posy;
posx = GetSystemMetrics(SM_CXSCREEN) / 2 - (rectWindow.right - rectWindow.left) / 2;
posy = GetSystemMetrics(SM_CYSCREEN) / 2 - (rectWindow.bottom - rectWindow.top) / 2;
const int radius = 150;
for (int y = -radius; y <= radius; y++)
for (int x = -radius; x <= radius; x++)
if (x * x + y * y <= radius * radius)
SetPixel(context, posx + x, posy + y, red);
}
It gives me this result img
it looks good but i saw this weird pixels at sides (up, down, right, left)
img
and this is what I want (I added some pixels at the top so it looks better)
enter image description here
Your "what I want" looks anti-aliased. So draw anti-aliased.
If the original condition is not met, but x*x + y*y <= (radius+1)*(radius+1) is met then you need a partially-shaded pixel.
Another way to do anti-aliasing is to test not the center of each pixel but the four corners (x \plusminus 0.5, y \plusminus 0.5). If more than zero but fewer than four corners are inside the circle, you need a partially-shaded pixel.

How to calculate width, height and position of bezier curve

I have a bezier curve defined by start point, end point and 2 control points (parameters of this: http://www.w3schools.com/tags/canvas_beziercurveto.asp).
First, I need to calculate width and height of this curve. If I make rectangle around a curve, its width and height is what I need.
Then I need to start point (x,y of left top corner) of this rectangle.
How can I calculate that ? Thanks.
For true bounds, you need to compute the extremities of the curve's component functions, then plug those into the bezier function for the (x,y) coordinates for each extremity. I cover this over at http://pomax.github.io/bezierinfo/#extremities, which also explains how to do most of the steps required to get there in the text leading up to the extremities section. paragraphs 11 and 12/13 then cover bounding boxes (plain, which you're probably interested in, and tight, respectively)
I found approximate solution in some other topic (I don't remember which one) but here is simple JS function to calculate it:
function getCurveBoundary(ax, ay, bx, by, cx, cy, dx, dy) {
var tobx = bx - ax;
var toby = by - ay;
var tocx = cx - bx;
var tocy = cy - by;
var todx = dx - cx;
var tody = dy - cy;
var step = 1 / 40; // precission
var d, px, py, qx, qy, rx, ry, tx, ty, sx, sy, x, y, i, minx, miny, maxx, maxy;
function min(num1, num2) {
if (num1 > num2)
return num2;
if (num1 < num2)
return num1;
return num1;
}
function max(num1, num2) {
if (num1 > num2)
return num1;
if (num1 < num2)
return num2;
return num1;
}
for (var i = 0; i < 41; i++)
{
d = i * step;
px = ax + d * tobx;
py = ay + d * toby;
qx = bx + d * tocx;
qy = by + d * tocy;
rx = cx + d * todx;
ry = cy + d * tody;
toqx = qx - px;
toqy = qy - py;
torx = rx - qx;
tory = ry - qy;
sx = px + d * toqx;
sy = py + d * toqy;
tx = qx + d * torx;
ty = qy + d * tory;
totx = tx - sx;
toty = ty - sy;
x = sx + d * totx;
y = sy + d * toty;
if (i == 0)
{
minx = x;
miny = y;
maxx = x;
maxy = y;
}
else
{
minx = min(minx, x);
miny = min(miny, y);
maxx = max(maxx, x);
maxy = max(maxy, y);
}
}
return {x: Math.round(minx), y: Math.round(miny), width: Math.round(maxx - minx), height: Math.round(maxy - miny)};
}
If you're looking for an approximate solution, it's pretty easy to compute a solution that's always big enough to cover the curve, but might be too big.
Beziers satisfy the 'convex hull property' which means that you can take a bounding box of your control points and that will bound the curve itself.
If you're looking for something more accurate, then the simplest way is to evaluate a bunch of different points on the curve and take the bounding box of those points on the curve. You can vary the number of points you test in order to change the quality/speed tradeoff.
If you're looking for something that directly computes the exact answer then what you need is a root finder to look for extrema of the functions x(t) and y(t).

Line Segment Circle Intersection

I am trying to determine the point at which a line segment intersect a circle. For example, given any point between P0 and P3 (And also assuming that you know the radius), what is the easiest method to determine P3?
Generally,
find the angle between P0 and P1
draw a line at that angle from P0 at a distance r, which will give you P3
In pseudocode,
theta = atan2(P1.y-P0.y, P1.x-P0.x)
P3.x = P0.x + r * cos(theta)
P3.y = P0.y + r * sin(theta)
From the center of the circle and the radius you can write the equation describing the circle.
From the two points P0 and P1 you can write the equation describing the line.
So you have 2 equations in 2 unknowns, which you can solved through substitution.
Let (x0,y0) = coordinates of the point P0
And (x1,y1) = coordinates of the point P1
And r = the radius of the circle.
The equation for the circle is:
(x-x0)^2 + (y-y0)^2 = r^2
The equation for the line is:
(y-y0) = M(x-x0) // where M = (y1-y0)/(x1-x0)
Plugging the 2nd equation into the first gives:
(x-x0)^2*(1 + M^2) = r^2
x - x0 = r/sqrt(1+M^2)
Similarly you can find that
y - y0 = r/sqrt(1+1/M^2)
The point (x,y) is the intersection point between the line and the circle, (x,y) is your answer.
P3 = (x0 + r/sqrt(1+M^2), y0 + r/sqrt(1+1/M^2))
Go for this code..its save the time
private boolean circleLineIntersect(float x1, float y1, float x2, float y2, float cx, float cy, float cr ) {
float dx = x2 - x1;
float dy = y2 - y1;
float a = dx * dx + dy * dy;
float b = 2 * (dx * (x1 - cx) + dy * (y1 - cy));
float c = cx * cx + cy * cy;
c += x1 * x1 + y1 * y1;
c -= 2 * (cx * x1 + cy * y1);
c -= cr * cr;
float bb4ac = b * b - 4 * a * c;
// return false No collision
// return true Collision
return bb4ac >= 0;
}
You have a system of equations. The circle is defined by: x^2 + y^2 = r^2. The line is defined by y = y0 + [(y1 - y0) / (x1 - x0)]·(x - x0). Substitute the second into the first, you get x^2 + (y0 + [(y1 - y0) / (x1 - x0)]·(x - x0))^2 = r^2. Solve this and you'll get 0-2 values for x. Plug them back into either equation to get your values for y.
MATLAB CODE
function [ flag] = circleLineSegmentIntersection2(Ax, Ay, Bx, By, Cx, Cy, R)
% A and B are two end points of a line segment and C is the center of
the circle, % R is the radius of the circle. THis function compute
the closest point fron C to the segment % If the distance to the
closest point > R return 0 else 1
Dx = Bx-Ax;
Dy = By-Ay;
LAB = (Dx^2 + Dy^2);
t = ((Cx - Ax) * Dx + (Cy - Ay) * Dy) / LAB;
if t > 1
t=1;
elseif t<0
t=0;
end;
nearestX = Ax + t * Dx;
nearestY = Ay + t * Dy;
dist = sqrt( (nearestX-Cx)^2 + (nearestY-Cy)^2 );
if (dist > R )
flag=0;
else
flag=1;
end
end

Resources