I am trying to get the coordinates from one point on this but it does only give me the x and y coordinates and the zoom data too. Even though i am trying to figure out how to convert x and y to lat and long. the data that appear in this map are confusing me too much. this map gives me:
http://gis.nyc.gov/doitt/nycitymap/
Height: (static value)
width: (static value)
minX
maxX
minY
maxY
zoom
those are the data this maps gives me for 1 specific building or place and i don't know how to convert it in lat and long. can someone help me out on this please?
Thank you so much for reading this post.
This perhaps can help
public double xCoordinateToLongitude(int x, int z) {
return x / Math.pow(2.0, z) * 360.0 - 180;
}
public double yCoordinateToLatitude(int y, int z) {
double n = Math.PI - (2.0 * Math.PI * y) / Math.pow(2.0, z);
return (Math.toDegrees(Math.atan(Math.sinh(n))) * -1) * 1000000 / 1000000;
}
(* 1000000 / 1000000 ) is for decimal approach
Related
Programming Language: C
I'm currently in the process of implementing a 3D wireframe model represented through isometric projection.
My current understanding of the project is to:
parse a text map containing the x,y,z coordinates of the wireframe model
Transforming the 3D coordinates to 2D using isometric projection
Drawing the line using the Bresenham Line Algo and a few functions out of my graphic library of choice.
I'm done with Step 1 however I've been stuck on Step 2 for the last few days.
I understand that isometric projection is the process of projecting a 2D plane in a angle that it looks like it's 3D even though we are only working with x,y when drawing the lines. That is def. not the best way of describing it and if I'm incorrect please correct me.
Example of a text map:
0 0 0
0 5 0
0 0 0
My data structure of choice (implemented as array of structs)
typedef struct point
{
float x;
float y;
float z;
bool is_last;
int color; // Implemented after mandatory part
} t_point;
I pretty much just read out the rows, column and values of the text map and store them in x,y,z values respectively.
Now that I have to transform them I've tried the following formulas:
const double angle = 30 * M_PI / 180.0;
void isometric(t_dot *dot, double angle)
{
dot->x = (dot->x - dot->y) * cos(angle);
dot->y = (dot->x + dot->y) * sin(angle) - dot->z;
}
static void iso(int x, int y, int z)
{
int previous_x;
int previous_y;
previous_x = x;
previous_y = y;
x = (previous_x - previous_y) * cos(0.523599);
y = -z + (previous_x + previous_y) * sin(0.523599);
}
t_point *calc_isometric(t_point *pts, int max_pts)
{
float x;
float y;
float z;
const double angle = 30 * M_PI / 180.0;
int num_pts;
num_pts = 0;
while (num_pts < max_pts)
{
x = pts[num_pts].x;
y = pts[num_pts].y;
z = pts[num_pts].z;
printf("x: %f y: %f z: %f\n", x, y, z);
pts[num_pts].x = (x - y) * cos(angle);
pts[num_pts].y = (x + y) * sin(angle) - z;
printf("x_iso %f\ty_iso %f\n\n", pts[num_pts].x, pts[num_pts].y);
num_pts++;
}
return (pts);
}
It spits out various things which makes no sense to me. I could just go one and try to implement the Line Algo. from here and hope for the best but I would like to understand what I'm actually doing here.
Next to that I learned through me research that I need to set up my camera in a certain way to create the projection.
All in all I'm just very lost and my question boils down to this.
Please help me understand the concept of isometric projection.
How to transform 3D coordinates (x,y,z) into coordinates using isometric projection.
I see it like this:
// constants:
float deg = M_PI/180.0;
float ax = 30*deg;
float ay =150*deg;
vec2 X = vec2(cos(ax),-sin(ax)); // x axis
vec2 Y = vec2(cos(ay),-sin(ay)); // y axis
vec2 Z = vec2( 0.0,- 1.0); // z axis
vec2 O = vec2(0,0); // position of point (0,0,0) on screen
// conversion:
vec3 p=vec3(?,?,?); // input point
vec2 q=O+(p.x*X)+(p.y*Y)+(p.z*Y); // output point
the coordinatewise version:
float Xx = cos(ax);
float Xy = -sin(ax);
float Yx = cos(ay);
float Yy = -sin(ay);
float Zx = 0.0;
float Zy = - 1.0;
float Ox = 0;
float Oy = 0;
// conversion:
float px=?,py=?,pz=?; // input point
float qx=Ox+(px*Xx)+(py*Yx)+(pz*Yx); // output point
float qy=Oy+(px*Xy)+(py*Yy)+(pz*Yy); // output point
Asuming x axis going to right and y axis going down ... the O is usually set to center of screen instead of (0,0) unless you add pan capabilities of your isometric world.
In case you want to add arbitrary rotations within the "3D" XY plane see this:
How can I warp a shader matrix to match isometric perspective in a 3d scene?
So you just compute the X,Y vectors on the ellipse (beware they will not be unit anymore!!!) So if I see it right it would be:
float ax=?,ay=ax+90*deg;
float Xx = cos(ax) ;
float Xy = -sin(ax)*0.5;
float Yx = cos(ay) ;
float Yy = -sin(ay)*0.5;
where ax is the rotation angle...
I am replacing my project's use of glRotatef because I need to be able to transform double matrices. glRotated is not an option because OpenGL does not guarantee the stored matrices or any operations performed to be double precision. However, my new implementation only rotates around the global axes, and does not give the same result as glRotatef.
I have looked at some implementations of glRotatef (like OpenGl rotate custom implementation) and don't see how they account for the initial transformation matrix's local axes when calculating the rotation matrix.
I have a generic rotate function, taken (with some changes) from https://community.khronos.org/t/implementing-rotation-function-like-glrotate/68603:
typedef double double_matrix_t[16];
void rotate_double_matrix(const double_matrix_t in, double angle, double x, double y, double z,
double_matrix_t out)
{
double sinAngle, cosAngle;
double mag = sqrt(x * x + y * y + z * z);
sinAngle = sin ( angle * M_PI / 180.0 );
cosAngle = cos ( angle * M_PI / 180.0 );
if ( mag > 0.0f )
{
double xx, yy, zz, xy, yz, zx, xs, ys, zs;
double oneMinusCos;
double_matrix_t rotMat;
x /= mag;
y /= mag;
z /= mag;
xx = x * x;
yy = y * y;
zz = z * z;
xy = x * y;
yz = y * z;
zx = z * x;
xs = x * sinAngle;
ys = y * sinAngle;
zs = z * sinAngle;
oneMinusCos = 1.0f - cosAngle;
rotMat[0] = (oneMinusCos * xx) + cosAngle;
rotMat[4] = (oneMinusCos * xy) - zs;
rotMat[8] = (oneMinusCos * zx) + ys;
rotMat[12] = 0.0F;
rotMat[1] = (oneMinusCos * xy) + zs;
rotMat[5] = (oneMinusCos * yy) + cosAngle;
rotMat[9] = (oneMinusCos * yz) - xs;
rotMat[13] = 0.0F;
rotMat[2] = (oneMinusCos * zx) - ys;
rotMat[6] = (oneMinusCos * yz) + xs;
rotMat[10] = (oneMinusCos * zz) + cosAngle;
rotMat[14] = 0.0F;
rotMat[3] = 0.0F;
rotMat[7] = 0.0F;
rotMat[11] = 0.0F;
rotMat[15] = 1.0F;
multiply_double_matrices(in, rotMat, out); // Generic matrix multiplication function.
}
}
I call this function with the same rotations I used to call glRotatef with and in the same order, but the result is different. All rotations are done around the global axes, while glRotatef would rotate around the local axis of in.
For example, I have a plane:
and I pitch up 90 degrees (this gives the expected result with both glRotatef and my rotation function) and persist the transformation:
If I bank 90 degrees with glRotatef (glRotatef(90, 0.0f, 0.0f, 1.0f)), the plane rotates around the transformation's local Z axis pointing out of the plane's nose, which is what I want:
But if I bank 90 degrees with my code (rotate_double_matrix(in, 90.0f, 0.0, 0.0, 1.0, out)), I get this:
The plane is still rotating around the global Z axis.
Similar issues happen if I change the order of rotations - the first rotation gives the expected result, but subsequent rotations still happen around the global axes.
How does glRotatef rotate around a matrix's local axes? What do I need to change in my code to get the same result? I assume rotate_double_matrix needs to modify the x, y, z values passed in based on the in matrix somehow, but I'm not sure.
You're probably multiplying the matrices in the wrong order. Try changing
multiply_double_matrices(in, rotMat, out);
to
multiply_double_matrices(rotMat, in, out);
I can never remember which way is right, and there's a reasonable chance multiply_double_matrices is backwards anyway (at least if I'd written it :)
The order you multiply matrices in matters. Since rotMat holds your rotation, and in holds the combination of all other matrices applied so far, i.e. "everything else", multiplying in the wrong order means that rotMat gets applied after everything else instead of before everything else. (And I didn't get that part backwards! If you want rotMat to be the "top of stack" transformation, that means you actually want it to be the first when your vertex coordinates are processed)
Another possibility is that you mixed up rows with columns. OpenGL matrices go down, then across, i.e.
matrix[0] matrix[4] matrix[8] matrix[12]
matrix[1] matrix[5] matrix[9] matrix[13]
matrix[2] matrix[6] matrix[10] matrix[14]
matrix[3] matrix[7] matrix[11] matrix[15]
even though 2D arrays are traditionally stored across, then down:
matrix[0] matrix[1] matrix[2] matrix[3]
matrix[4] matrix[5] matrix[6] matrix[7]
matrix[8] matrix[9] matrix[10] matrix[11]
matrix[12] matrix[13] matrix[14] matrix[15]
Getting this wrong can cause similar-looking, but mathematically different, issues
I'm trying to write the C code for an algorithm that approximates pi. It's supposed to get the volume of a cube and the volume of a sphere inside that cube (the sphere's radius is 1/2 of the cube's side). Then I am supposed to divide the cube's volume by the sphere's and multiply by 6 to get pi.
It's working but it's doing something weird in the part that is supposed to get the volumes. I figure it's something to do the with delta I chose for the approximations.
With a cube of side 4 instead of giving me a volume of 64 it's giving me 6400. With the sphere instead of 33 it's giving me 3334. something.
Can someone figure it out? Here is the code (I commented the relevant parts):
#include <stdio.h>
int in_esfera(double x, double y, double z, double r_esfera){
double dist = (x-r_esfera)*(x-r_esfera) + (y-r_esfera)*(y-r_esfera) + (z-r_esfera)*(z-r_esfera);
return dist <= (r_esfera)*(r_esfera) ? 1 : 0;
}
double get_pi(double l_cubo){
double r_esfera = l_cubo/2;
double total = 0;
double esfera = 0;
//this is delta, for the precision. If I set it to 1E anything less than -1 the program continues endlessly. Is this normal?
double delta = (1E-1);
for(double x = 0; x < l_cubo; x+=delta){
printf("x => %f; delta => %.6f\n",x,delta);
for(double y = 0; y <l_cubo; y+=delta){
printf("y => %f; delta => %.6f\n",y,delta);
for(double z = 0; z < l_cubo; z+=delta){
printf("z => %f; delta => %.6f\n",z,delta);
total+=delta;
if(in_esfera(x,y,z,r_esfera))
esfera+=delta;
}
}
}
//attempt at fixing this
//esfera/=delta;
//total/=delta;
//
//This printf displays the volumes. Notice how the place of the point is off. If delta isn't a power of 10 the values are completely wrong.
printf("v_sphere = %.8f; v_cube = %.8f\n",esfera,total);
return (esfera)/(total)*6;
}
void teste_pi(){
double l_cubo = 4;
double pi = get_pi(l_cubo);
printf("%.8f\n",pi);
}
int main(){
teste_pi();
}
total+=delta;
if(in_esfera(x,y,z,r_esfera))
esfera+=delta;
total and esfera are three-dimensional volumes whereas delta is a one-dimensional length. If you were tracking units you'd have m3 on the left and m on the right. The units are incompatible.
To fix it, cube delta so that you're conceptually accumulating tiny cubes instead of tiny lines.
total+=delta*delta*delta;
if(in_esfera(x,y,z,r_esfera))
esfera+=delta*delta*delta;
Doing that fixes the output, and also works for any value of delta:
v_sphere = 33.37400000; v_cube = 64.00000000
3.12881250
Note that this algorithm "works" for arbitrary delta values, but it has severe accuracy issues. It's incredibly prone to rounding problems. It works best when delta is a power of two: 1/64.0 is better than 1/100.0, for example:
v_sphere = 33.50365448; v_cube = 64.00000000
3.14096761
Also, if you want your program to run faster get rid of all those printouts! Or at least the ones in the inner loops...
The thing is that multiplication over integers like a * b * c is the same as adding 1 + 1 + 1 + 1 + ... + 1 a * b * c times, right?
You're adding delta + delta + ... (x / delta) * (y / delta) * (z / delta) times. Or, in other words, (x * y * z) / (delta ** 3) times.
Now, that sum of deltas is the same as this:
delta * (1 + 1 + 1 + 1 + ...)
^^^^^^^^^^^^^^^^^^^^ (x * y * z) / (delta**3) times
So, if delta is a power of 10, (x * y * z) / (delta**3) will be an integer, and it'll be equal to the sum of 1's in parentheses (because it's the same as the product x * y * (z / (delta**3)), where the last term is an integer - see the very first sentence of this answer). Thus, your result will be the following:
delta * ( (x * y * z) / (delta ** 3) ) == (x * y * z) / (delta**2)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the sum of ones
That's how you ended up calculating the product divided by delta squared.
To solve this, multiply all volumes by delta * delta.
However, I don't think it's possible to use this logic for deltas that aren't a power of 10. And indeed, the code will go all kinds of haywire for delta == 0.21 and l_cubo == 2, for example: you'll get 9.261000000000061 instead of 8.
I'm trying to do parallel projection in C.
My function:
void parallel_projection(int x, int y, int z, float angle);
It is necessary to pass 3D coordinates to 2D using the parallel projection with the parameters of the function.
What is the formula to use to find x and y? (Using cos, sin and tangent)
Parallel Projection - Wikipedia
In your image, x and wx is the same axis, and angle is in yoz plane. So wx = x.
projected y:
when y = 0,
wy = z * cos(pi/2 - α) = z * sin(α)
when y > 0 and z < 0,
wy = sqrt(y^2 + z^2) * cos(α + arctan(z / y) + pi)
otherwise,
wy = sqrt(y^2 + z^2) * cos(α + arctan(z / y))
Note that angle is given in degree, while in C, trigonometric functions accept radian.
I'm trying to convert X and Y screen coordinates to a float range of -1.0, to 1.0.
(-1,-1 being 0,0 and if the resolution was 640x480, 1,1 would be 640,480. 0,0 would be 320,240... the center.)
How would I approach this? I made several futile attempts, and I'm not exactly mathematically inclined.
Here is some C code
void convert(int X, int Y)
{
float newx = 2*(X-320.0f)/640.0f;
float newy = 2*(Y-240.0f)/480.0f;
printf("New x = %f, New y = %f", newx, newy);
}
EDIT: Added the f suffix to ensure we do not do integer math !
In the X direction:
Screen coordinate 0 corresponds to -1.0.
Screen coordinate 640 corresponds to 1.0.
You can convert that to an equation:
Given fX in floating point coordinates, the screen coordinate sX is:
sX = 640*(fX + 1.0)/2.0
or
sX = 320*(fX + 1.0)
Similarly, given fY in floating point coordinates, the screen coordinate sY is:
sY = 480*(fY + 1.0)/2.0
or
sY = 240*(fY + 1.0)
The inverse of that:
Given sX in screen coordinates, fX in real coordinates is:
fX = (sX/320 - 1.0)
Given sY in screen coordinates, fY in real coordinates is:
fY = (sY/240 - 1.0)
When you convert that to code, make sure the last two equations have a 1.0. Otherwise, you'll lose accuracy due to integer division.
fX = (1.0*sX/320 - 1.0)
fY = (1.0*sY/240 - 1.0)