Get direction from degrees - javascript

I built a small compass project that is able to calculate the devices heading. SO what I got is a function that returns a value between 0° and 360° for the current heading.
What I like to get is a matching value for the current heading direction from an array like this: (["North", "North-East", "East", "South-East", "South", "South-West", "West", "North-West"])
(keep in mind: North = 0° / 359°)
However I got no idea how to get a result like this & this few lines below are all that I got so far but it doesn't seems working:
var directions = ["North", "North-East", "East", "South-East", "South", "South-West", "West", "North-West"]
function getDirection(heading) {
var index = Math.round((heading/8)/5,625)
return directions[index]
}
Any help would be very appreciated, thanks in advance.

This solution should take all possible scenarios in consideration:
var index = Math.round(((angle %= 360) < 0 ? angle + 360 : angle) / 45) % 8;
function getDirection(angle) {
var directions = ['North', 'North-East', 'East', 'South-East', 'South', 'South-West', 'West', 'North-West'];
var index = Math.round(((angle %= 360) < 0 ? angle + 360 : angle) / 45) % 8;
return directions[index];
}
console.log( getDirection(0) );
console.log( getDirection(45) );
console.log( getDirection(180) );
console.log( getDirection(99) );
console.log( getDirection(275) );
console.log( getDirection(-120) );
console.log( getDirection(587) );

Related

Calculating accuracy of rotation

So I have a variable containing rotation in degrees, and I have an ideal rotation, and what I want is the percentage of accuracy within 20 degrees in either direction.
var actualRotation = 215
var idealRotation = 225
var accuracy = magicFunction(actualRotation, idealRotation)
In this case, the actualRotation is 10 degrees off from idealRotation, so with a 20 degree threshold in either direction, that's a 50% accuracy. So the value of accuracy would be 0.5.
var accuracy = magicFunction(225, 225) // 1.0
var accuracy = magicFunction(225, 210) // 0.25
var accuracy = magicFunction(245, 225) // 0.0
var accuracy = magicFunction(90, 225) // 0.0
How can I achieve this?
var actualRotation = 215
var idealRotation = 225
var diff = abs(actualRotation - idealRotation);
if (diff > 20)
console.log(0);
else{
accuracy = 1 - (diff/ 20);
console.log(accuracy);
}
Try this (just run code snippet):
function magicFunction(actualRotation , idealRotation ) {
var diff = Math.abs(actualRotation - idealRotation);
var accurrancy = 1 - (diff / 20);
accurrancy = accurrancy < 0 ? 0 : accurrancy;
return accurrancy;
}
console.log("225, 225: ", magicFunction(225, 225));
console.log("225, 210: ", magicFunction(225, 210));
console.log("245, 225: ", magicFunction(245, 225));
console.log("90, 225: ", magicFunction(90, 225));
The previous answers were good, but they don't handle the case where the difference crosses the zero-singularity.
E.g. when the angles are 5 and 355, you expect a difference of 10, but a simple subtraction gives 350. To rectify this, subtract the angle from 360 if it is bigger than 180.
For the above to work, you also need the angles to be in the range [0, 360). However this is a simple modulo calculation, as below.
Code:
function normalize(angle) {
if (angle < 0)
return angle - Math.round((angle - 360) / 360) * 360;
else if (angle >= 360)
return angle - Math.round(angle / 360) * 360;
else
return angle;
}
function difference(angle1, angle2) {
var diff = Math.abs(normalize(angle1) - normalize(angle2));
return diff > 180 ? 360 - diff : diff;
}
function magicFunction(actualRotation, idealRotation, limit) {
var diff = difference(actualRotation, idealRotation);
return diff < limit ? 1.0 - (diff / limit) : 0.0;
}
// tests
console.log(difference(10, 255)); // 115 (instead of the incorrect answer 245)
console.log(magicFunction(5, 355, 20)); // 0.5 (instead of 0 as would be returned originally)
EDIT: a graphical illustration of why the previous method would be insufficient:

find position of a point with origin, angle and radius

im stuck with a trigonometry problem in a javascript game im trying to make.
with a origin point(xa,ya) a radius and destination point (ya,yb) I need to find the position of a new point.
//calculate a angle in degree
function angle(xa, ya, xb, yb)
{
var a= Math.atan2(yb - ya, xb - xa);
a*= 180 / Math.PI;
return a;
}
function FindNewPointPosition()
{
//radius origine(xa,xb) destination(ya,yb)
var radius=30;
var a = angle(xa, xb, ya, yb);
newpoint.x = xa + radius * Math.cos(a);
newpoint.y = ya + radius * Math.sin(a);
return newpoint;
}
Imagine a image because I dont have enough reputation to post one :
blue square is the map (5000x5000), black square (500x500) what players see (hud).
Cross(400,400) is the origin and sun(4200,4200) the destination.
The red dot (?,?) indicate to player which direction take to find the sun ..
But sun and cross position can be reverse or in different corner or anywhere !
At the moment the red dot do not do that at all ..
Tks for your help.
Why did you use ATAN2? Change to Math.atan() - you will get angle in var A
Where you have to place your red dot? inside hud?
Corrected code
https://jsfiddle.net/ka9xr07j/embedded/result/
var obj = FindNewPointPosition(400,4200,400,4200); - new position 417. 425
Finally I find a solution without using angle.
function newpointposition(origin, destination)
{
// radius distance between cross and red dot
var r=30;
// calculate a vector
var xDistance = destination.x - origin.x;
var yDistance = destination.y - origin.y;
// normalize vector
var length = Math.sqrt(xDistance * xDistance + yDistance * yDistance);
xDistance /= length;
yDistance /= length;
// add the radius
xDistance = xDistance * r;
yDistance = yDistance * r;
var newpoint = { x: 0, y: 0 };
newpoint.x = origin.x + xDistance;
newpoint.y = origin.y + yDistance;
return newpoint;
}
var radar = newpointposition({
x: 500,
y: 800
}, {
x: 3600,
y: 2850
});
alert(radar.x + ' ' + radar.y);
ty Trike, using jsfiddle really help me.

How to detect if a user has drawn a circle on a touch device using canvas and javascript?

I am creating a Tangram puzzle game using Javascript. And I need to detect when a user has drawn a circle (or circle like shape) with their finger. I have been able to gather hundreds (if not thousands) of x and y points with:
var touchX = event.targetTouches[0].pageX - canvas.offsetLeft;
var touchY = event.targetTouches[0].pageY - canvas.offsetTop;
I then push each x and y coordinate into an array:
touchMoveX.push(touchX);
touchMoveY.push(touchY);
I then loop through each array and create two points:
for(var i = 0; i < touchMoveX.length; i++)
{
for(var l=0; l < touchMoveY.length; l++)
{
var xPosition = touchMoveX[i];
var yPosition = touchMoveY[l];
var v1x = touchMoveX[i];
var v2x = touchMoveX[i + 1];
var v1y = touchMoveY[l];
var v2y = touchMoveY[l + 1];
Then using those two points, I use the following formula to figure out the angle between these two points in degrees:
var v1 = {x: v1x, y: v1y}, v2 = {x: v2x, y: v2y},
angleRad = Math.acos( (v1.x * v2.x + v1.y * v2.y) /
(Math.sqrt(v1.x*v1.x + v1.y*v1.y) * Math.sqrt(v2.x*v2.x + v2.y*v2.y) ) ),
angleDeg = angleRad * 180 / Math.PI;
I then sum up all of the angles and see if they are around 360 degrees.
But the above code I have described isn't working very well. Does someone out there have a better way to do this? Thank you very much.
yeah compute the average of all points (giving you a cheaply approximated center) then check if more than a certain percent of points are within a certain threshold. You can tune those values to adjust the precision until it feels right.
edit: Didn't consider that the circle could have multiple sizes, but you could just add another step computing the average of all distances. Adjusted the example for that.
var totalAmount = touchMoveX.length;
// sum up all coordinates and divide them by total length
// the average is a cheap approximation of the center.
var averageX = touchMoveX.reduce( function ( previous, current) {
return previous + current;
} ) / totalAmount ;
var averageY = touchMoveY.reduce( function ( previous, current) {
return previous + current;
} ) / totalAmount ;
// compute distance to approximated center from each point
var distances = touchMoveX.map ( function ( x, index ) {
var y = touchMoveY[index];
return Math.sqrt( Math.pow(x - averageX, 2) + Math.pow(y - averageY, 2) );
} );
// average of those distance is
var averageDistance = distances.reduce ( function ( previous, current ) {
return previous + current;
} ) / distances.length;
var min = averageDistance * 0.8;
var max = averageDistance * 1.2;
// filter out the ones not inside the min and max boundaries
var inRange = distances.filter ( function ( d ) {
return d > min && d < max;
} ).length;
var minPercentInRange = 80;
var percentInRange = inRange.length / totalAmount * 100;
// by the % of points within those boundaries we can guess if it's circle
if( percentInRange > minPercentInRange ) {
//it's probably a circle
}

Create terrain using longitude latitude in three.js

I would like to create a terrain on top of a cube geometry based on latitude and longitude data. I have an array of objects that contain the latitude, longitude, and amount to deform a specific coordinate.
var geo = new THREE.CubeGeometry( 10, 20, 40, 40, worldWidth, worldDepth);
var worldWidth = 100, worldDepth = 100;
for ( var i = 0; i < worldWidth; i++ ) {
for ( var j = 0; j < worldDepth; j++ ){
for (var k = 0; k < locations.length; k++ ) {
var index = j * worldWidth + i;
var x = worldWidth * (locations[k].lng + 180) / (2 * 180);
var y = worldDepth * (locations[k].lat + 180) / (2 * 180);
var dx = i - x;
var dy = j - y;
var dist = Math.sqrt( dx*dx + dy*dy );
if ( dist < .5 ) {
geo.vertices[index].x += locations[k].count * .05;
}
}
}
}
Right now, this code just pushes up each individual coordinate that is closest to the latitude and longitude. Is there a way I can smooth the area around each locatiuon coordinate so that it looks like a terrain rather than spikes?
Good day, it sounds to me like your looking to Subdivide the mesh, thereby "smoothing" out the peak to valley effect. This can be done with a Modifier as seen in this Three.js example:
http://threejs.org/examples/#webgl_geometry_subdivision
Now the basic principles here are:
1) use the latest revision of Three.js
2) pull down the SubdivisionModifier.js file and link it in:
<script src="js/modifiers/SubdivisionModifier.js"></script>
3) create the modifier during initializaion (play with the value, I tried 3):
var modifier = new THREE.SubdivisionModifier( 3 );
4) then after your vertices manipulation and before adding your geometry to a mesh to render apply the modifier like so:
geometry.mergeVertices();
geometry.computeCentroids();
geometry.computeFaceNormals();
geometry.computeVertexNormals();
modifier.modify( geometry );
Give that a try and let us know how it's working out, I'd be super keen to find out myself.

Selecting individual letters in .print with Raphael 2.1

I tried to do what this Raphael tutorial [ http://www.html5rocks.com/en/tutorials/raphael/intro/ ] does and select individual letters from a string printed with .print, but no joy
I have generated the font with cufon, and replaced Cufon.registerFont with Raphael.registerFont
var paper = Raphael( '#div', 500, 500 ),
label = paper.print( xCenter, yCenter, 'blah', paper.getFont("CelliniProMedium"), 54 );
label[1].attr( 'fill', 'red');
causes an error because label is just a path not an array of paths.
What gives?
thanks in advance
Yeah, this is definitely a change in behavior between 1.4 and 2.0 -- and it's a bit of functionality that came in handy in more than one situation.
On the other hand, replicating the array result functionality is easy to do by extending Raphael 2.0...
Raphael.fn.printArray = function printArray( x, y, string, font, size, letter_spacing, line_height )
{
var result = [];
var cx = x, cy = y;
size = size || 16;
letter_spacing = letter_spacing || 0.2;
line_height = line_height || 1.5;
for ( var i = 0; i < string.length; i++ )
{
if ( string[i] == " " )
{
cx += size;
continue;
}
else if ( string[i] == "\n" )
{
cx = x;
cy += size * line_height;
continue;
}
var glyph = this.print( 0, 0, string[i], font, size ).attr( { opacity: 0 } );
var glyphBox = glyph.getBBox();
glyph.attr( { transform: "T" + cx + "," + cy, opacity: 1 } );
cx += glyphBox.width + ( size * letter_spacing );
result.push( glyph );
}
return result;
}
This isn't perfect code, but with a little refinement it could easily fill the gap.
so it looks like it's either a bug or a feature with 2.1 - I got 1.4 from GitHub and it works as expected. Leaving question open for a short while in case anyone can shed any more lights on this, as I think it may be useful to others.

Categories

Resources