My goal - move sprite, left and right arrows keys must set directions of moving.I struggle with rotation geometry few days, and it beat me.
My code below
void rotate_point(float cx, float cy, float angle, int *px,int *py) {
*px = cos(angle) * (*px - cx) - sin(angle) * (*py - cy) + cx;
*py = sin(angle) * (*px - cx) + cos(angle) * (*py - cy) + cy;
}
https://pastebin.com/vUvnNkKb
How you can see, moves of red line on rotations mismatched with X,Y of sprite rect.Many thanks to everyone who can helps.
Note that in the second line you are using px that has been changed in the first line.
Remember old value and use it for correct rotation like this:
void rotate_point(float cx, float cy, float angle, int *px,int *py) {
float tmp = *px;
*px = cos(angle) * (tmp - cx) - sin(angle) * (*py - cy) + cx;
*py = sin(angle) * (tmp - cx) + cos(angle) * (*py - cy) + cy;
}
Related
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)
Now, I know similar questions have been asked. But none of the answers has helped me to find the result I need.
Following situation:
We have a line with a point-of-origin (PO), given as lx, ly. We also have an angle for the line in that it exits PO, where 0° means horizontally to the right, positive degrees mean clockwise. The angle is in [0;360[. Additionally we have the length of the line, since it is not infinitely long, as len.
There is also a circle with the given center-point (CP), given as cx, cy. The radius is given as cr.
I now need a function that takes these numbers as parameters and returns the distance of the closest intersection between line and circle to the PO, or -1 if no intersection occures.
My current approach is a follows:
float getDistance(float lx, float ly, float angle, float len, float cx, float cy, float cr) {
float nlx = lx - cx;
float nly = ly - cy;
float m = tan(angle);
float b = (-lx) * m;
// a = m^2 + 1
// b = 2 * m * b
// c = b^2 - cr^2
float[] x_12 = quadraticFormula(sq(m) + 1, 2*m*b, sq(b) - sq(cr));
// if no intersections
if (Float.isNaN(x_12[0]) && Float.isNaN(x_12[1]))
return -1;
float distance;
if (Float.isNaN(x_12[0])) {
distance = (x_12[1] - nlx) / cos(angle);
} else {
distance = (x_12[0] - nlx) / cos(angle);
}
if (distance <= len) {
return distance;
}
return -1;
}
// solves for x
float[] quadraticFormula(float a, float b, float c) {
float[] results = new float[2];
results[0] = (-b + sqrt(sq(b) - 4 * a * c)) / (2*a);
results[1] = (-b - sqrt(sq(b) - 4 * a * c)) / (2*a);
return results;
}
But the result is not as wished. Sometimes I do get a distance returned, but that is rarely correct, there often isn't even an intersection occuring. Most of the time no intersection is returned though, although there should be one.
Any help would be much appreciated.
EDIT:
I managed to find the solution thanks to MBo's answer. Here is the content of my finished getDistance(...)-function - maybe somebody can be helped by it:
float nlx = lx - cx;
float nly = ly - cy;
float dx = cos(angle);
float dy = sin(angle);
float[] results = quadraticFormula(1, 2*(nlx*dx + nly*dy), sq(nlx)+sq(nly)-sq(cr));
float dist = -1;
if (results[0] >= 0 && results[0] <= len)
dist = results[0];
if (results[1] >= 0 && results[1] <= len && results[1] < results[0])
dist = results[1];
return dist;
Using your nlx, nly, we can build parametric equation of line segment
dx = Cos(angle)
dy = Sin(Angle)
x = nlx + t * dx
y = nly + t * dy
Condition of intersection with circumference:
(nlx + t * dx)^2 + (nly + t * dy)^2 = cr^2
t^2 * (dx^2 + dy^2) + t * (2*nlx*dx + 2*nly*dy) + nlx^2+nly^2-cr^2 = 0
so we have quadratic equation for unknown parameter t with
a = 1
b = 2*(nlx*dx + nly*dy)
c = nlx^2+nly^2-cr^2
solve quadratic equation, find whether t lies in range 0..len.
// https://openprocessing.org/sketch/8009#
// by https://openprocessing.org/user/54?view=sketches
float circleX = 200;
float circleY = 200;
float circleRadius = 100;
float lineX1 = 350;
float lineY1 = 350;
float lineX2, lineY2;
void setup() {
size(400, 400);
ellipseMode(RADIUS);
smooth();
}
void draw() {
background(204);
lineX2 = mouseX;
lineY2 = mouseY;
if (circleLineIntersect(lineX1, lineY1, lineX2, lineY2, circleX, circleY, circleRadius) == true) {
noFill();
}
else {
fill(255);
}
ellipse(circleX, circleY, circleRadius, circleRadius);
line(lineX1, lineY1, lineX2, lineY2);
}
// Code adapted from Paul Bourke:
// http://local.wasp.uwa.edu.au/~pbourke/geometry/sphereline/raysphere.c
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;
//println(bb4ac);
if (bb4ac < 0) { // Not intersecting
return false;
}
else {
float mu = (-b + sqrt( b*b - 4*a*c )) / (2*a);
float ix1 = x1 + mu*(dx);
float iy1 = y1 + mu*(dy);
mu = (-b - sqrt(b*b - 4*a*c )) / (2*a);
float ix2 = x1 + mu*(dx);
float iy2 = y1 + mu*(dy);
// The intersection points
ellipse(ix1, iy1, 10, 10);
ellipse(ix2, iy2, 10, 10);
float testX;
float testY;
// Figure out which point is closer to the circle
if (dist(x1, y1, cx, cy) < dist(x2, y2, cx, cy)) {
testX = x2;
testY = y2;
} else {
testX = x1;
testY = y1;
}
if (dist(testX, testY, ix1, iy1) < dist(x1, y1, x2, y2) || dist(testX, testY, ix2, iy2) < dist(x1, y1, x2, y2)) {
return true;
} else {
return false;
}
}
}
I am writing a simple ray shader and I am trying to prodcue a dice with a cube and a number of spheres representing the dots. The spheres are correct, but the sides of the cube are on the x, y and z axes. The cube is centred around 0, 0, 0.
I have checked that the coordinate of the vertices are correct. I am assuming that my ray calculation is correct as the spheres are in the correct positions.
Here is the code for the ray calculation
Ray Image::RayThruPixel(float i, float j)
{
float alpha = m_tanFOVx * ((j - m_halfWidth) / m_halfWidth);
float beta = m_tanFOVy * ((m_halfHeight - i) / m_halfHeight);
vec3 *coordFrame = m_camera.CoordFrame();
vec3 p1 = (coordFrame[U_VEC] * alpha) + (coordFrame[V_VEC] * beta) - coordFrame[W_VEC];
return Ray(m_camera.Eye(), p1);
}
where m_tanFOVx is tan(FOVx / 2) and m_tanFOVy is tan(FOVy / 2) FOVx and FOVy are in radians.
To find the intersection of the ray and triangle my code is as follows:
bool Triangle::Intersection(Ray ray, float &fDistance)
{
static float epsilon = 0.000001;
bool bHit = false;
float fMinDist(10000000);
float divisor = glm::dot(ray.p1, normal);
// if divisor == 0 then the ray is parallel with the triangle
if(divisor > -epsilon && divisor < epsilon)
{
bHit = false;
}
else
{
float t = (glm::dot(v0, normal) - glm::dot(ray.p0, normal)) / divisor;
if(t > 0)
{
vec3 P = ray.p0 + (ray.p1 * t);
vec3 v2 = P - m_vertexA;
v0 = m_vertexB - m_vertexA;
v1 = m_vertexC - m_vertexA;
normal = glm::normalize(glm::cross(v0, v1));
d00 = glm::dot(v0, v0);
d01 = glm::dot(v0, v1);
d11 = glm::dot(v1, v1);
denom = d00 * d11 - d01 * d01;
float d20 = glm::dot(v2, v0);
float d21 = glm::dot(v2, v1);
float alpha = (d11 * d20 - d01 * d21) / denom;
float beta = (d00 * d21 - d01 * d20) / denom;
float gamma = 1.0 - alpha - beta;
vec3 testP = alpha * m_vertexA + beta * m_vertexB + gamma * m_vertexC;
if((alpha >= 0 ) &&
(beta >= 0) &&
(alpha + beta <= 1))
{
bHit = true;
fDistance = t;
}
}
}
return bHit;
}
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).
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