I have a function that is meant to take a give angle and rotate the coordinates of a triangle by that angle. However, it pauses slightly then jumps to a new position rather than running smoothly.
The function works by translating the original coordinates to the origin, rotating them by the angle that has already been moved plus the specified angle. Then it translates the coordinates back to the unmodified positions before translating them to where the image currenty is.
void rotateTriangle(double angle_){
int ang = angle_ + angle;
triCoords[0]=((triCoords_[0] - triPos_[0])*cos(ang) - (triCoords_[1] - triPos_[1])*sin(ang)) + triPos_[0] + triPos[0];
triCoords[1]=((triCoords_[1] - triPos_[1])*cos(ang) + (triCoords_[0] - triPos_[0])*sin(ang)) + triPos_[1] + triPos[1];
triCoords[2]=((triCoords_[2] - triPos_[0])*cos(ang) - (triCoords_[3] - triPos_[1])*sin(ang)) + triPos_[0] + triPos[0];
triCoords[3]=((triCoords_[3] - triPos_[1])*cos(ang) + (triCoords_[2] - triPos_[0])*sin(ang)) + triPos_[1] + triPos[1];
triCoords[4]=((triCoords_[4] - triPos_[0])*cos(ang) - (triCoords_[5] - triPos_[1])*sin(ang)) + triPos_[0] + triPos[0];
triCoords[5]=((triCoords_[5] - triPos_[1])*cos(ang) + (triCoords_[4] - triPos_[0])*sin(ang)) + triPos_[1] + triPos[1];
}
Well, this:
int ang = angle_ + angle;
will of course truncate the floating-point angle to an integer. Since sin() and cos() work with radians, that doesn't work out too well.
You should have:
const double ang = angle_ + angle;
It's not clear what angle is here (angle_ is the function's argument, but the two names are confusingly similiar), I guess it's a global variable.
If this is is for on-screen rendering, you might consider limiting yourself to float precision and use sinf() and cosf() instead.
Related
I'm actually using the algorithme of Toto Briac from Raycaster, searching for more effective floor/ceiling raycast
When using it, the floor casting is working well for east and west side, but for north and south it just does weird things (just look image).
double pixelsToBottom;
double pixelsToMid;
double directDistFloor;
double realDistance;
double y;
t_point f_p;
pixelsToBottom = (double)data->s_height - wall[1].y;
pixelsToMid = (double)data->s_height / 2 - pixelsToBottom;
for (int i = pixelsToMid; i < data->s_height / 2; i += 1)
{
directDistFloor = (data->dist_proj * (double)(data->s_height / 2)) / i;
realDistance = directDistFloor / fabs(cos(angle));
f_p.x = data->player.pos.x + cos(angle) * (realDistance) / (data->dist_proj / (64.0));
f_p.y = data->player.pos.y + sin(angle) * (realDistance) / (data->dist_proj / (64.0));
y = (wall->x + (i + data->s_height / 2) * data->s_width) / data->s_width;
pixel_put(&data->obj, wall->x, y, f_pixel(data, f_p));
}
But i'm facing an issu, when i'm facing north and south side it's all ok, but when the ray is going into east or west side, the texture just do a weird thing like that :
I know that it refer to : realDistance = directDistFloor / fabs(cos(angle));
if i replace the cos(angle) by sin(angle) in this line, it just invert things. I didn't find a way to change the calcule in right moment. I you have any idea I will take it ! Thank you !!
It's okay I found the answer, for the people who are interest, in the line realDistance = directDistFloor / fabs(cos(angle)); I was using the angle of the ray in the world, I changed it by the angle relative to my player dir (so 0° if it's the player dir ray) and it work properly ! Thank's #ZwergofPhoenix for the time you took !
I have written a C script to implement the inverse Vincenty's formula to calculate the distance between two sets of GPS coordinates based on the equations shown at https://en.wikipedia.org/wiki/Vincenty%27s_formulae
However, my results are different to the results given by this online calculator https://www.cqsrg.org/tools/GCDistance/ and Google maps. My results are consistently around 1.18 times the result of the online calculator.
My function is below, any tips on where I could be going wrong would be very much appreciated!
double get_distance(double lat1, double lon1, double lat2, double lon2)
{
double rad_eq = 6378137.0; //Radius at equator
double flattening = 1 / 298.257223563; //flattenig of earth
double rad_pol = (1 - flattening) * rad_eq; //Radius at poles
double U1,U2,L,lambda,old_lambda,sigma,sin_sig,cos_sig,alpha,cos2sigmam,A,B,C,u_sq,delta_s,dis;
//Convert to radians
lat1=M_PI*lat1/180.0;
lat2=M_PI*lat2/180.0;
lon1=M_PI*lon1/180.0;
lon2=M_PI*lon2/180.0;
//Calculate U1 and U2
U1=atan((1-flattening)*tan(lat1));
U2=atan((1-flattening)*tan(lat2));
L=lon2-lon1;
lambda=L;
double tolerance=pow(10.,-12.);//iteration tollerance should give 0.6mm
double diff=1.;
while (abs(diff)>tolerance)
{
sin_sig=sqrt(pow(cos(U2)*sin(lambda),2.)+pow(cos(U1)*sin(U2)-(sin(U1)*cos(U2)*cos(lambda)),2.));
cos_sig=sin(U1)*cos(U2)+cos(U1)*cos(U2)*cos(lambda);
sigma=atan(sin_sig/cos_sig);
alpha=asin((cos(U1)*cos(U2)*sin(lambda))/(sin_sig));
cos2sigmam=cos(sigma)-(2*sin(U1)*sin(U2))/((pow(cos(alpha),2.)));
C=(flattening/16)*pow(cos(alpha),2.)*(4+(flattening*(4-(3*pow(cos(alpha),2.)))));
old_lambda=lambda;
lambda=L+(1-C)*flattening*sin(alpha)*(sigma+C*sin_sig*(cos2sigmam+C*cos_sig*(-1+2*pow(cos2sigmam,2.))));
diff=abs(old_lambda-lambda);
}
u_sq=pow(cos(alpha),2.)*((pow(rad_eq,2.)-pow(rad_pol,2.))/(pow(rad_pol,2.)));
A=1+(u_sq/16384)*(4096+(u_sq*(-768+(u_sq*(320-(175*u_sq))))));
B=(u_sq/1024)*(256+(u_sq*(-128+(u_sq*(74-(47*u_sq))))));
delta_s=B*sin_sig*(cos2sigmam+(B/4)*(cos_sig*(-1+(2*pow(cos2sigmam,2.)))-(B/6)*cos2sigmam*(-3+(4*pow(sin_sig,2.)))*(-3+(4*pow(cos2sigmam,2.)))));
dis=rad_pol*A*(sigma-delta_s);
//Returns distance in metres
return dis;
}
This formula is not symmetric:
cos_sig = sin(U1)*cos(U2)
+ cos(U1)*cos(U2) * cos(lambda);
And turns out to be wrong, a sin is missing.
Another style of formatting (one including some whitespace) could also help.
Besides the fabs for abs and one sin for that cos I also changed the loop; there were two abs()-calls and diff had to be preset with the while-loop.
I inserted a printf to see how the value progresses.
Some parentheses can be left out. These formulas are really difficult to realize. Some more helper variables could be useful in this jungle of nested math operations.
do {
sin_sig = sqrt(pow( cos(U2) * sin(lambda), 2)
+ pow(cos(U1)*sin(U2)
- (sin(U1)*cos(U2) * cos(lambda))
, 2)
);
cos_sig = sin(U1) * sin(U2)
+ cos(U1) * cos(U2) * cos(lambda);
sigma = atan2(sin_sig, cos_sig);
alpha = asin(cos(U1) * cos(U2) * sin(lambda)
/ sin_sig
);
double cos2alpha = cos(alpha)*cos(alpha); // helper var.
cos2sigmam = cos(sigma) - 2*sin(U1)*sin(U2) / cos2alpha;
C = (flat/16) * cos2alpha * (4 + flat * (4 - 3*cos2alpha));
old_lambda = lambda;
lambda = L + (1-C) * flat * sin(alpha)
*(sigma + C*sin_sig
*(cos2sigmam + C*cos_sig
*(2 * pow(cos2sigmam, 2) - 1)
)
);
diff = fabs(old_lambda - lambda);
printf("%.12f\n", diff);
} while (diff > tolerance);
For 80,80, 0,0 the output is (in km):
0.000885870048
0.000000221352
0.000000000055
0.000000000000
9809.479224
which corresponds to the millimeter with WGS-84.
Given theta angles in radians, width and height of the rotated image, how do I calculate the new width and height of the outer rectangle that contains the rotated image?
In other words how do I calculate the new bonding box width/height?
Note that the image could actually be circle and have transparent pixels on the edges.
That would be: x1, y1.
I am actually rotating a pixbuf with the origin at center using cairo_rotate() and I need to know the newly allocated area. What I tried is this:
double geo_rotated_rectangle_get_width (double a, double b, double theta)
{
return abs(a*cos(theta)) + abs(b*sin(theta));
}
And it will work in the sense of always returning sufficient space to contain the rotated image, but it also always returns higher values than it should, when image is not rotated in a multiple of 90o and is a fully opaque image (a square).
EDIT:
This is the image I am rotating:
Interestingly enough, I just tried with a fully opaque image with the same size and it was OK. I use gdk_pixbuf_get_width() to get width and it returns the same value for both regardless. So I assume the formula is correct and the problem is that the transparency is not accounted for. When rotated with a diagonal orientation there are edges from the rectangle of the rotated image that are transparent.
I'll leave the above so that it is helpful to others :)
Now the question becomes how to account for transparent pixels on the edges
To determine the bbox of the rotated rectangle, you can compute the coordinates of the 4 vertices and take the bbox of these 4 points.
a is the width of the unrotated rectangle and b its height ;
let diag = sqrt(a * a + b * b) / 2 the distance from the center to the top right corner of this rectangle. You can use diag = hypot(a, b) / 2 for better precision ;
first compute the angle theta0 of the first diagonal for theta=0: theta0 = atan(b / a) or better theta0 = atan2(b, a) ;
the 4 vertices are:
{ diag * cos(theta0 + theta), diag * sin(theta0 + theta) }
{ diag * cos(pi - theta0 + theta), diag * sin(pi - theta0 + theta) }
{ diag * cos(pi + theta0 + theta), diag * sin(pi + theta0 + theta) }
{ diag * cos(-theta0 + theta), diag * sin(-theta0 + theta) }
which can be simplified as:
{ diag * cos(theta + theta0), diag * sin(theta + theta0) }
{ -diag * cos(theta - theta0), -diag * sin(theta - theta0) }
{ -diag * cos(theta + theta0), -diag * sin(theta + theta0) }
{ diag * cos(theta - theta0), diag * sin(theta - theta0) }
which gives x1 and y1:
x1 = diag * fmax(fabs(cos(theta + theta0)), fabs(cos(theta - theta0))
y1 = diag * fmax(fabs(sin(theta + theta0)), fabs(sin(theta - theta0))
and the width and height of the rotated rectangle follow:
width = 2 * diag * fmax(fabs(cos(theta + theta0)), fabs(cos(theta - theta0))
height = 2 * diag * fmax(fabs(sin(theta + theta0)), fabs(sin(theta - theta0))
This is the geometric solution, but you must take into account the rounding performed by the graphics primitive, so it is much preferable to use the graphics API and retrieve the pixbuf dimensions with gdk_pixbuf_get_width() and gdk_pixbuf_get_height(), which will allow for precise placement.
I'd say "let cairo compute those coordinates". If you have access to a cairo_t*, you can do something like the following (untested!):
double x1, y1, x2, y2;
cairo_save(cr);
cairo_rotate(cr, theta); // You can also do cairo_translate() and whatever your heart desires
cairo_new_path(cr);
cairo_rectangle(cr, x, y, width, height);
cairo_restore(cr); // Note: This preserved the path!
cairo_fill_extents(cr, &x1, &y1, &x2, &y2);
cairo_new_path(cr); // Clean up after ourselves
printf("Rectangle is inside of (%g,%g) to (%g,%g) (size %g,%g)\n",
x1, y1, x2, y2, x2 - x1, y2 - y1);
The above code applies some transformation, then constructs a path. This makes cairo apply the transformation to the given coordinates. Afterwards, the transformation is "thrown away" with cairo_restore(). Next, we ask cairo for the area covered by the current path, which it provides in the current coordinate system, i.e. without the transformation.
I'm still a beginner in programming. I was writing some code (C on Linux) to calculate the page rank of some example webpages. I'm using the google formula, which is here: http link
Here is the code I wrote:
#include <stdio.h>
double iResA, iResB, iResC, iResD, resA, resB, resC, resD;
int outLinksA = 2, outLinksB = 1, outLinksC = 2;
int main(){
// get initial results for all PR
iResA = 0.05 + (0.85 * ((0.33/outLinksB) + (0.33/outLinksC)));
iResB = 0.05 + (0.85 * ((0.33/outLinksA) + (0.33/outLinksC)));
iResC = 0.05 + (0.85 * (0.33/outLinksA));
printf("initial values for all PR:\nA: %.8lf\nB: %.8lf\nC: %.8lf\n\n", iResA, iResB, iResC);
resA = 0.05 + (0.85 * ((iResB/outLinksB) + (iResC/outLinksC)));
resB = 0.05 + (0.85 * ((iResA/outLinksA) + (iResC/outLinksC)));
resC = 0.05 + (0.85 * ((iResA/outLinksA)));
printf("new values for all PR:\nA: %.8lf\nB: %.8lf\nC: %.8lf\n\n", resA, resB, resC);
for (int i = 0; i < 10; i++) {
resA = 0.05 + (0.85 * ((resB/outLinksB) + (resC/outLinksC)));
resB = 0.05 + (0.85 * ((resA/outLinksA) + (resC/outLinksC)));
resC = 0.05 + (0.85 * ((resA/outLinksA)));
printf("Iteration: %d\nnew values for all PR:\nA: %.8lf\nB: %.8lf\nC: %.8lf\n\n", i + 1, resA, resB, resC);
}
return 0;
}
I have to find initial results to work with, I have set the damping factor (d) to 0.05 ((1-0.85)/3 was used to calculate that, I'm dividing by 3 because that's how many imaginary web pages I'm working with).
The problem is that I will have to create a new variable for every iteration, so this means whatever's inside the "for" loop is technically wrong. resA will be given a new value with each iteration, and that new value will be used to calculate resB, which is not good. I want to be able to use the old value of resA to calculate resB, when the iteration is finished, only then do I want the new value to be used, and that value must remain constant until the next iteration.
Perhaps there is a much easier method, and I am just over-complicating things. I'm sorry if this is really easy and I'm just not seeing a way to create a good implementation. What new things must I learn to make my life easier trying to implement this?
Allocate new variables
Store the result to the new variables during calculation
Store results to the original variables from the new variables after calculation
for (int i = 0; i < 10; i++) {
double new_resA = 0.05 + (0.85 * ((resB/outLinksB) + (resC/outLinksC)));
double new_resB = 0.05 + (0.85 * ((resA/outLinksA) + (resC/outLinksC)));
double new_resC = 0.05 + (0.85 * ((resA/outLinksA)));
resA = new_resA;
resB = new_resB;
resC = new_resC;
printf("Iteration: %d\nnew values for all PR:\nA: %.8lf\nB: %.8lf\nC: %.8lf\n\n", i + 1, resA, resB, resC);
}
I'm working on a RayTracer and I can't figure out what I'm doing wrong when I try to calculate an intersection with a cone. I have my ray vector and the position of the cone with its axis. I know that compute a cone along a simple axis is easy but I want to do it with an arbitrary axis.
I'm using this link http://mrl.nyu.edu/~dzorin/rend05/lecture2.pdf for the cone equation (page 7-8) and here is my code :
alpha = cone->angle * (PI / 180);
axe.x = 0;
axe.y = 1;
axe.z = 0;
delt_p = vectorize(cone->position, ray.origin);
tmp1.x = ray.vector.x - (dot_product(ray.vector, axe) * axe.x);
tmp1.y = ray.vector.y - (dot_product(ray.vector, axe) * axe.y);
tmp1.z = ray.vector.z - (dot_product(ray.vector, axe) * axe.z);
tmp2.x = (delt_p.x) - (dot_product(delt_p, axe) * axe.x);
tmp2.y = (delt_p.y) - (dot_product(delt_p, axe) * axe.y);
tmp2.z = (delt_p.z) - (dot_product(delt_p, axe) * axe.z);
a = (pow(cos(alpha), 2) * dot_product(tmp1, tmp1)) - (pow(sin(alpha), 2) * dot_product(ray.vector, axe));
b = 2 * ((pow(cos(alpha), 2) * dot_product(tmp1, tmp2)) - (pow(sin(alpha), 2) * dot_product(ray.vector, axe) * dot_product(delt_p, axe)));
c = (pow(cos(alpha), 2) * dot_product(tmp2, tmp2)) - (pow(sin(alpha), 2) * dot_product(delt_p, axe));
delta = pow(b, 2) - (4 * a * c);
if (delta >= 0)
{
t1 = (((-1) * b) + sqrt(delta)) / (2 * a);
t2 = (((-1) * b) - sqrt(delta)) / (2 * a);
t = (t1 < t2 ? t1 : t2);
return (t);
}
I initialised my axis with the y axis so I can rotate it.
Here is what I get : http://i.imgur.com/l3kaavc.png
Instead of a cone, I have that paraboloid red shape on the right, and I know that it's almost the same equation as a cone.
You probably need to implement arbitrary transformations on primitives using homogenous matrices, rather than support arbitrary orientation for each primitive.
For example, it's not uncommon for ray tracers to only support cones that have their base on the origin, and that point along the vertical axis. You would then use affine transformations to move the cone to the right place and orientation.
My own ray tracer (which thus far only supports planes, boxes and spheres) has the same problem, and implementation transformation matrices is my next task.