Convert lat, long to x, y on Mollweide - c++

I have tried to follow the instructions here but I get wild results compared to this site.
Here is my code.
#include <cmath>
double solveNR(double latitude, double epsilon) {
if (abs(latitude) == M_PI / 2) {
return latitude;
}
double theta = latitude;
while (true) {
double nextTheta = theta - (2 * theta * std::sin(2 * theta) - M_PI * std::sin(latitude)) / (2 + 2 * std::cos(2 * theta));
if (abs(theta - nextTheta) < epsilon) {
break;
}
theta = nextTheta;
}
return theta;
}
void convertToXY(double radius, double latitude, double longitude, double* x, double* y) {
latitude = latitude * M_PI / 180;
longitude = longitude * M_PI / 180;
double longitudeZero = 0 * M_PI / 180;
double theta = solveNR(latitude, 1);
*x = radius * 2 * sqrt(2) * (longitude - longitudeZero) * std::cos(theta) / M_PI;
*y = radius * sqrt(2) * std::sin(theta);
}
For instance,
180 longitude = 21
90 latitude = 8.1209e+06
assuming a radius of 5742340.81
I found this resource which seems to calculate the right answer. But I cannot parse how it is different.

In your solveNR() function why do you use
double nextTheta = theta - (2 * theta * std::sin(2 * theta) - PI *
std::sin(latitude)) / (2 + 2 * std::cos(2 * theta));
instead
double nextTheta = theta - (2 * theta + std::sin(2 * theta) - PI *
std::sin(latitude)) / (2 + 2 * std::cos(2 * theta));
Seems like you should use "+" instead "*" (after 2 * theta in the numerator), to accord with wiki-instructions.

Related

What did i wrong in my image turn algoritm?

I just want to turn image #1 and write it in memory #2 (#1 Body #2 TurnBody) (rotation around the center of the image)
KI and KJ its just (i-radius) and (j-radius) for usage. SIN and COS its just sin and cos of turn angle.
radius - just half of image side (my image is square)
6.28 = pi*2
example i need to turn
example i have:
(i turn not all image, just a small square in center and add it to big screen image)
TurnAngle - just my global value (shows what angle the image is now rotated)
void Turn(double angle, int radius, COLORREF* Body, COLORREF* TurnBody)
{
if (abs(TurnAngle += angle) > 6.28)
{
TurnAngle = 0;
}
int i, ki, j, kj;
const double SIN = sin(TurnAngle), COS = cos(TurnAngle);
for (i = 0, ki = -radius; i < 2 * radius; i++, ki++)
{
for (j = 0, kj = -radius; j < 2 * radius; j++, kj++)
{
if (Body[i * 2 * radius + j]) // if Pixel not black
{
TurnBody[static_cast<int>(kj * COS - ki * SIN + radius + (ki * COS + kj * SIN + radius) * 2 * radius)] = Body[i * 2 * radius + j];
}
}
}
}
this work, smth was wrong with ( ) or double values i rly dont know... Thank you guys
this->TurnBody[(int)(kj * COS - ki * SIN) + this->radius + ((int)(ki * COS + kj * SIN) + this->radius) * 2 * this->radius] = this->Body[i * 2 * this->radius + j];
I think this is wrong:
TurnBody[static_cast<int>(kj * COS - ki * SIN + radius + (ki * COS + kj * SIN + radius) * 2 * radius)] = Body[i * 2 * radius + j];
I think it should be more like this:
TurnBody[(int)(kj * COS) + radius + ((int)(kj * SIN) + radius) * 2*radius] = Body[i * 2 * radius + j];

How does this lighting calculation work?

I have that piece of code that is responsible for lighting a pyramid.
float Geometric3D::calculateLight(int vert1, int vert2, int vert3) {
float ax = tabX[vert2] - tabX[vert1];
float ay = tabY[vert2] - tabY[vert1];
float az = tabZ[vert2] - tabZ[vert1];
float bx = tabX[vert3] - tabX[vert1];
float by = tabY[vert3] - tabY[vert1];
float bz = tabZ[vert3] - tabZ[vert1];
float Nx = (ay * bz) - (az * by);
float Ny = (az * bx) - (ax * bz);;
float Nz = (ax * by) - (ay * bx);;
float Lx = -300.0f;
float Ly = -300.0f;
float Lz = -1000.0f;
float lenN = sqrtf((Nx * Nx) + (Ny * Ny) + (Nz * Nz));
float lenL = sqrtf((Lx * Lx) + (Ly * Ly) + (Lz * Lz));
float res = ((Nx * Lx) + (Ny * Ly) + (Nz * Lz)) / (lenN * lenL);
if (res < 0.0f)
res = -res;
return res;
}
I cannot understand calculations at the end. Can someone explain me the maths that is behind them? I know that firstly program calculates two vectors of a plane to compute the normal of it (which goes for vector N). Vector L stand for lighting but what happens next? Why do we calculate length of normal and light then multiply it and divide by their sizes?

C++ Angles between a vector and a point

I got 2 points own=(x, y, z) and en=(x, y, z) which represents my own position in the world and some other player position. the other player also got pitch (from 90 degrees to -90) and yaw (0 to 360). I want to calculate the angles between the other player look and my own position.
In 2D, alpha is what I'm trying to calculate:
int main()
{
float own_x = 1, own_y = 1, own_z = 1;
float en_x = 10, en_y = 1, en_z = 10;
float pi = 3.14159265;
float pitch = 0.f * (pi / 180), yaw = 45.f * (pi / 180);
float x = sin(yaw) * cos(pitch);
float y = sin(pitch);
float z = cos(pitch) * cos(yaw);
float vec_length = sqrt(pow(en_x - own_x, 2) + pow(en_y - own_y, 2) + pow(en_y - own_y, 2));
x /= vec_length;
y /= vec_length;
z /= vec_length;
float cos_t = ((en_x - own_x)*x + (en_y - own_y)*y + (en_z - own_z)*z) / sqrt(pow(en_x - own_x, 2) + pow(en_y - own_y, 2) + pow(en_y - own_y, 2));
float arc = acos(cos_t) * (180 / pi);
return 0;
}
you divide twice with the length of en-own: You should remove
vec_length, and xyz /= vec_length.
your division at cos_t is buggy, you use _y twice in the
expression instead of _y and _z
Note: instead of pow(x, 2), use x*x, it is faster usually (compilers may not optimize pow(x, 2) to x*x).

Half of my ellipse drawn in the wrong place

Here is the code for an oval drawing method I am working on. I am applying the Bresenham method to plot its co-ordinates, and taking advantage of the ellipse's symmetrical properties to draw the same pixel in four different places.
void cRenderClass::plotEllipse(int xCentre, int yCentre, int width, int height, float angle, float xScale, float yScale)
{
if ((height == width) && (abs(xScale - yScale) < 0.005))
plotCircle(xCentre, yCentre, width, xScale);
std::vector<std::vector <float>> rotate;
if (angle > 360.0f)
{
angle -= 180.0f;
}
rotate = maths.rotateMatrix(angle, 'z');
//rotate[0][0] = cos(angle)
//rotate[0][1] = sin(angle)
float theta = atan2(-height*rotate[0][1], width*rotate[0][0]);
if (angle > 90.0f && angle < 180.0f)
{
theta += PI;
}
//add scalation in at a later date
float xShear = (width * (cos(theta) * rotate[0][0])) - (height * (sin(theta) * rotate[0][1]));
float yShear = (width * (cos(theta) * rotate[0][1])) + (height * (sin(theta) * rotate[0][0]));
float widthAxis = abs(sqrt(((rotate[0][0] * width) * (rotate[0][0] * width)) + ((rotate[0][1] * height) * (rotate[0][1] * height))));
float heightAxis = (width * height) / widthAxis;
int aSquared = widthAxis * widthAxis;
int fourASquared = 4*aSquared;
int bSquared = heightAxis * heightAxis;
int fourBSquared = 4*bSquared;
x0 = 0;
y0 = heightAxis;
int sigma = (bSquared * 2) + (aSquared * (1 - (2 * heightAxis)));
while ((bSquared * x0) <= (aSquared * y0))
{
drawPixel(xCentre + x0, yCentre + ((floor((x0 * yShear) / xShear)) + y0));
drawPixel(xCentre - x0, yCentre + ((floor((x0 * yShear) / xShear)) + y0));
drawPixel(xCentre + x0, yCentre + ((floor((x0 * yShear) / xShear)) - y0));
drawPixel(xCentre - x0, yCentre + ((floor((x0 * yShear) / xShear)) - y0));
if (sigma >= 0)
{
sigma += (fourASquared * (1 - y0));
y0--;
}
sigma += (bSquared * ((4 * x0) + 6));
x0++;
}
x0 = widthAxis;
y0 = 0;
sigma = (aSquared * 2) + (bSquared * (1 - (2 * widthAxis)));
while ((aSquared * y0) <= (bSquared * x0))
{
drawPixel(xCentre + x0, yCentre + ((floor((x0 * yShear) / xShear)) + y0));
drawPixel(xCentre - x0, yCentre + ((floor((x0 * yShear) / xShear)) + y0));
drawPixel(xCentre + x0, yCentre + ((floor((x0 * yShear) / xShear)) - y0));
drawPixel(xCentre - x0, yCentre + ((floor((x0 * yShear) / xShear)) - y0));
if (sigma >= 0)
{
sigma += (fourBSquared * (1 - x0));
x0--;
}
sigma += (aSquared * (4 * y0) + 6);
y0++;
}
//the above algorithm hasn't been quite completed
//there are still a few things I want to enquire Andy about
//before I move on
//this other algorithm definitely works
//however
//it is computationally expensive
//and the line drawing isn't as refined as the first one
//only use this as a last resort
/* std::vector<std::vector <float>> rotate;
rotate = maths.rotateMatrix(angle, 'z');
float s = rotate[0][1];
float c = rotate[0][0];
float ratio = (float)height / (float)width;
float px, py, xNew, yNew;
for (int theta = 0; theta <= 360; theta++)
{
px = (xCentre + (cos(maths.degToRad(theta)) * (width / 2))) - xCentre;
py = (yCentre - (ratio * (sin(maths.degToRad(theta)) * (width / 2)))) - yCentre;
x0 = (px * c) - (py * s);
y0 = (px * s) + (py * c);
drawPixel(x0 + xCentre, y0 + yCentre);
}*/
}
Here's the problem. When testing the rotation matrix on my oval drawing function, I expect it to draw an ellipse at a slant from its original horizontal position as signified by 'angle'. Instead, it makes a heart shape. This is sweet, but not the result I want.
I have managed to get the other algorithm (as seen in the bottom part of that code sample) working successfully, but it takes more time to compute, and doesn't draw lines quite as nicely. I only plan to use that if I can't get this Bresenham one working.
Can anyone help?

What is the correct way to map a texture on a sphere?

I'm having problems with the correct mapping of a sphere. I used a world-map to show where it goes wrong. North America appears on the front from top to bottom, while South America is on the other side upside down and continents like Asia are not even on the map.
(source: troll.ws)
The code below is the sphere-object
class Shape {
public void drawSphere(double radius, int slices, int stacks) {
gl.glEnable(GL_TEXTURE_2D);
head.bind(gl); //Method that binds the world-map (for testing) texture.
gl.glBegin(GL_QUADS);
double stack = (2 * PI) / stacks;
double slice = (2 * PI) / slices;
for (double theta = 0; theta < 2 * PI; theta += stack) {
for (double phi = 0; phi < 2 * PI; phi += slice) {
Vector p1 = getPoints(phi, theta, radius);
Vector p2 = getPoints(phi + slice, theta, radius);
Vector p3 = getPoints(phi + slice, theta + stack, radius);
Vector p4 = getPoints(phi, theta + stack, radius);
double s0 = theta / (2 * PI);
double s1 = (theta + stack) / (2 * PI);
double t0 = phi / (2 * PI);
double t1 = (phi + slice) / (2 * PI);
vectorToNormal(norm(p1));
gl.glTexCoord2d(s0, t0);
vectorToVertex(p1);
vectorToNormal(norm(p2));
gl.glTexCoord2d(s0, t1);
vectorToVertex(p2);
vectorToNormal(norm(p3));
gl.glTexCoord2d(s1, t1 );
vectorToVertex(p3);
vectorToNormal(norm(p4));
gl.glTexCoord2d(s1, t0);
vectorToVertex(p4);
}
}
gl.glEnd();
gl.glDisable(GL_TEXTURE_2D);
}
Vector getPoints(double phi, double theta, double radius) {
double x = radius * cos(theta) * sin(phi);
double y = radius * sin(theta) * sin(phi);
double z = radius * cos(phi);
return new Vector(x, y, z);
}
How can I fix it? I tried swapping some coordinates and other things, but that made it even messier for me.
Also, there seem to be some artifacts when on the spere when I bind the texture to it. Is that fixable?
Both your loops are going from 0 to 2*PI. One of them should only be a half circle. You've doubled up the sphere, resulting in the dodgy mapping and the strange artefacts.
Thanks to JasonD, this fixed it.
for (double theta = 0; theta < 2 * PI; theta += stack) {
for (double phi = 0; phi < 1 * PI; phi += slice) {
Vector p1 = getPoints(phi, theta, radius);
Vector p2 = getPoints(phi + slice, theta, radius);
Vector p3 = getPoints(phi + slice, theta + stack, radius);
Vector p4 = getPoints(phi, theta + stack, radius);
double s0 = theta / (2 * PI);
double s1 = (theta + stack) / (2 * PI);
double t0 = phi / (1 * PI);
double t1 = (phi + slice) / (1 * PI);