Converting between -180-180 to 0-360 - javascript

I have a function that returns an angle from -180 to 180 and I need it to be 0 to 360. What is the formula to convert the angle?
Here's what I want:
0/360
270 90
180
Here's what I have:
-90
-180/180 0
90
Any help is greatly appreciated, working on an html/javascript game.

There are a number of ways this can be done while preserving the equivalent angle, with certain assumptions about the values.
If you are sure the values are actually in the range [-180,180), then you can use something like the following:
var x = Math.random()*360-180; // Generate random angle in range [-180, 180)
var y = x < 0 ? x+360 : x; // Normalize to be in the range [0, 360)
If you're doing this a lot, the branch operation may result in poor behavior (though maybe not in Javascript ... you'd need to profile it). So, it's sometimes better to do this without a branching operation. You can do this using the modulus (%) operator.
var x = Math.random()*360-180; // Generate random angle in range [-180, 180)
var y = (x + 360) % 360; // Normalize to be in the range [0, 360)
If you cannot guarantee the original value is in the range [-180, 180) you can essentially divide out the number of turns. This would look like
var x = getAngle(); // Some angle, potentially outside [-180, 180)
var y = x - 360 * Math.floor(x/360); // Normalizes to be in range [0, 360)
Some care will need to be taken for large absolute values of x due to the way floating point numbers are represented (which as I understand it is what Javascript uses, even when integer values would work well)
Edit: I just noticed you are also changing where you consider the 0 angle to be (above rather than to the right). In that case, you need to also add 90 degrees to rotate the 0 into the correct position. In this case, the first code segment becomes:
var x = Math.random()*360-180; // Generate random angle in range [-180, 180)
var y = x < -90 ? x+450 : x+90; // Normalize to be in the range [0, 360)
The next one becomes as Amadan indicated.
var x = Math.random()*360-180; // Generate random angle in range [-180, 180)
var y = (x + 450) % 360; // Normalize to be in the range [0, 360)
and the last one becomes
var x = getAngle(); // Some angle, potentially outside [-180, 180)
var y = (x+90) - 360 * Math.floor((x+90)/360); // Normalizes to be in range [0, 360)

Here is code as suggested by #Amadan
function convert(deg) {
return ((deg + 450) % 360);
}
window.console.log(convert(-180));
window.console.log(convert(-90));
window.console.log(convert(0));
window.console.log(convert(90));
window.console.log(convert(180));

Related

Converting an equirectangular depth map into 3d point cloud

I have a 2D equirectangular depth map that is a 1024 x 512 array of floats, each ranging between 0 to 1. Here example (truncated to grayscale):
I want to convert it to a set of 3D points but I am having trouble finding the right formula to do so - it's sort of close - pseudocode here (using a vec3() library):
for(var y = 0; y < array_height; ++y) {
var lat = (y / array_height) * 180.0 - 90.0;
var rho = Math.cos(lat * Math.PI / 180.0);
for(var x = 0; x < array_width; ++x) {
var lng = (x / array_width) * 360.0 - 180.0;
var pos = new vec3();
pos.x = (r * Math.cos(lng * Math.PI / 180.0));
pos.y = (Math.sin(lat * Math.PI / 180.0));
pos.z = (r * Math.sin(lng * Math.PI / 180.0));
pos.norm();
var depth = parseFloat(depth[(y * array_width) + x] / 255);
pos.multiply(depth);
// at this point I can plot pos as an X, Y, Z point
}
}
What I end up with isn't quite right and I can't tell why not. I am certain the data is correct. Can anyone suggest what I am doing wrong.
Thank you.
Molly.
Well looks like the texture is half-sphere in spherical coordinates:
x axis is longitude angle a <0,180> [deg]
y axis is latitude angle b <-45,+45> [deg]
intensity is radius r <0,1> [-]
So for each pixel simply:
linearly convert x,y to a,b
in degrees:
a = x*180 / (width -1)
b = -45 + ( y* 90 / (height-1) )
or in radians:
a = x*M_PI / (width -1)
b = -0.25*M_PI + ( 0.5*y*M_PI / (height-1) )
apply spherical to cartesian conversion
x=r*cos(a)*cos(b);
y=r*sin(a)*cos(b);
z=r* sin(b);
Looks like you have wrongly coded this conversion as latitude angle should be in all x,y,z not just y !!! Also you should not normalize the resulting position that would corrupt the shape !!!
store point into point cloud.
When I put all together in VCL/C++ (sorry do not code in javascript):
List<double> pnt; // 3D point list x0,y0,z0,x1,y1,z1,...
void compute()
{
int x,y,xs,ys; // texture positiona and size
double a,b,r,da,db; // spherical positiona and angle steps
double xx,yy,zz; // 3D point
DWORD *p; // texture pixel access
// load and prepare BMP texture
Graphics::TBitmap *bmp=new Graphics::TBitmap;
bmp->LoadFromFile("map.bmp");
bmp->HandleType=bmDIB;
bmp->PixelFormat=pf32bit;
xs=bmp->Width;
ys=bmp->Height;
/*
// 360x180 deg
da=2.0*M_PI/double(xs-1);
db=1.0*M_PI/double(ys-1);
b=-0.5*M_PI;
*/
// 180x90 deg
da=1.0*M_PI/double(xs-1);
db=0.5*M_PI/double(ys-1);
b=-0.25*M_PI;
// proces all its pixels
pnt.num=0;
for ( y=0; y<ys; y++,b+=db)
for (p=(DWORD*)bmp->ScanLine[y],a=0.0,x=0; x<xs; x++,a+=da)
{
// pixel access
r=DWORD(p[x]&255); // obtain intensity from texture <0..255>
r/=255.0; // normalize to <0..1>
// convert to 3D
xx=r*cos(a)*cos(b);
yy=r*sin(a)*cos(b);
zz=r* sin(b);
// store to pointcloud
pnt.add(xx);
pnt.add(yy);
pnt.add(zz);
}
// clean up
delete bmp;
}
Here preview for 180x90 deg:
and preview for 360x180 deg:
Not sure which one is correct (as I do not have any context to your map) but the first option looks more correct to me ...
In case its the second just use different numbers (doubled) for the interpolation in bullet #1
Also if you want to remove the background just ignore r==1 pixels:
simply by testing the intensity to max value (before normalization) in my case by adding this line:
if (r==255) continue;
after this one
r=DWORD(p[x]&255);
In your case (you have <0..1> already) you should test r>=0.9999 or something like that instead.

Angle and its inverse using Math.atan2

var vTheta = Math.atan2(v.vy,v.vx);
var obsAngle = Math.atan2(-v.vy,-v.vx);
This is the original code I used to find a vector angle and its inverse. They are used for some different calculations later in the code. I wanted to remove the second Math.atan2 function and replace it to help optimize the code with the following:
var vTheta = Math.atan2(v.vy,v.vx);
var obsAngle = 0;
if (vTheta >= 0) obsAngle = Math.PI - vTheta;
else if (vTheta < 0) obsAngle = Math.PI + vTheta;
When I print the results of obsAngle for both versions, the obsAngle is the same (or close enough), however the program does not behave the same. In both cases the obsAngle is between -pi and pi.
What would the difference be in these two versions that could cause a problem?
atan2 will return a value in the range [−π,π]. If θ ≥ 0, i.e. θ ∈ [0,π] then π − θ ∈ [0,π]. Likewise, if θ < 0, i.e. θ ∈ [−π,0) then π + θ ∈ [0,π). So your second computation will never result in negative values.
The first computation results in angles which relate by vTheta - obsAngle = ±π. To mimic that, you'd have to write
if (vTheta >= 0) obsAngle = vTheta - Math.PI;
else obsAngle = vTheta + Math.PI;

How to generate coordinates to represent a circle in 3D programming?

Lets say I have 10 objects. The first object is placed at x75, y0, z0. Now lets say I wanted to orient the objects so they form a circle with x0, y0, z0 at it's center. And each object is an equal distance from each other. Is there a formula I can use to generate the coordinates? I should mention the number of objects wont always be 10. It's a variable so some times it might be 15 or 20 or any other number.
You can use some formula like:
x = x0 + r * cos(theta * pi / 180);
y = y0 + r * sin(theta * pi / 180);
so x0 = 0 and y0 = 0.
For theta, it will be the degree, which depends on the number of objects. So if you have 10 objects, theta will be a multiple of 36. So basically it is a multiple of 360/num of objects.
r is the radius of the circle, so if the first one is at (75, 0, 0), then r = 75.

How to rotate an image clockwise or counterclockwise, whichever is shorter?

I'm making a web page that includes a clock with an arrow in the center. When the user clicks on an hour, the arrow rotates to point to what he/she has clicked.
I'm using a jQuery image rotate plugin (jQueryRotate) to rotate the arrow.
Here is the current code to compute the number of degrees to rotate:
var numTiles = $("ul li").size(); // Number of tiles is however many are listed in the UL, which is 12
var sel = 0; // Default hour selection
var rot = 0; // Default rotation is at the top (0 degrees)
var gap = 360 / numTiles; // Degrees between each tile
function rotateArrow(num) {
rot = num * gap;
$("#arrow").rotateAnimation(rot);
sel = num;
}
When the user clicks one of the hours, it passes num as a value of 1 through 12.
It works fine, but the problem is that if the arrow is pointing to 1 o'clock, and the user clicks 11 o'clock, the arrow rotates clockwise 300 degrees, when it would make more sense to rotate 60 degrees counterclockwise.
So, how can I write an equation to take the current hour (num) and the hour clicked (sel), and output a value as a positive or negative number, which equals the number of degrees to rotate that is most efficient, rather than just rotate only in one direction?
Any advice is appreciated. Let me know if you have any questions. Thanks!
Basically the closest rotation will always be less than 180 degrees, so if your angle is greater than 180, just subtract 360 from it to get the negative angle. Taking your own example, if you end up with 300 degrees, subtract 360 to get -60 degrees.
So to add to your current line of code:
rot = num * gap;
all you need is:
if (rot > 180)
rot -= 360;
This does the rather boring job:
function diff(x, y) {
var a = (x * Math.PI / 180) - Math.PI;
var b = (y * Math.PI / 180) - Math.PI;
return Math.atan2(Math.sin(b - a), Math.cos(b - a)) * (180 / Math.PI);
}
It returns -180 to 180, depending on which rotation will be the shortest.
diff(360, 20)
> 19.999999999999993
diff(20, 360)
> -19.999999999999993
diff(0, 160)
> 160
diff(0, 190)
> -170

Javascript function for trilinear interpolation

All,
I THINK that I'm looking for a function for Trilinear interpolation.
Here's the details:
I have a three dimensional dataset:
Dimension 1 varies from 0 to 100 in increments of 5
Dimension 2 varies from 0 to 100 in increments of 5
Dimension 3 varies from 0 to 1 in increments of 0.1
So, I have 4851 total values (21 x 21 x 11).
If I need to find the value for (10, 25, 0.3) - that's easy - I can just look it up in the 3-dimensional array.
But, I need to be able to come up with the best approximation, given dimensional values of (17,48,0.73), for example.
So, I think that what I'm looking for is a trilinear interpolation (although I'd definitely appreciate any suggestions for a better method, or a hint that I'm on the wrong topic altogether...)
A quick google search turns up this formula:
Vxyz =
V000(1-x)(1-y)(1-z) +
V100x(1-y)(1-z) +
V010(1-x)y(1-z) +
V001(1-x)(1-y)z +
V101x(1-y)z +
V011(1-x)yz +
V110xy(1-z) +
V111xyz
Which looks like what I'm looking for, but I'm not sure what x, y, and z represent. If I had to guess, x is a ratio - the distance of my "target" first dimension value from the nearest two values I have, y is the ratio for the second dimension, and z is the ratio for the third dimension.
Of course, since I don't really know what I'm talking about, I wouldn't know if this is right or wrong.
So, ideally, I'd like a bit of Javascript or pseudo-code that shows exactly how to accomplish this.
Many thanks in advance!
The code you are looking at is trying to do a weighted average of the 8 points of the cube with vertices that are in your dataset, and which encloses the point you are trying to find a value for.
For a point p
// Find the x, y and z values of the
// 8 vertices of the cube that surrounds the point
x0 = Math.floor(p.x / 5);
x1 = Math.floor(p.x / 5) + 1;
y0 = Math.floor(p.y / 5);
y1 = Math.floor(p.y / 5) + 1;
z0 = Math.floor(p.z / .1);
z1 = Math.floor(p.z / .1) + 1;
// Look up the values of the 8 points surrounding the cube
p000 = dataset[x0][y0][z0];
p001 = dataset[x0][y0][z1];
// ...
// Find the weights for each dimension
x = (x - x0) / 5;
y = (y - y0) / 5;
z = (z - z0) / .1;
// Compute the guess using the method you found
// ...

Categories

Resources