Floating point number precision or algorithmic error in JavaScript - javascript

I tried to implement in JavaScript rotation around point, using rotation matrix, but for some reason I got some unexpected results - instead of moving around a point, my figure was moving along a line. Here I provide completely reproducible example, which demonstrates that after rotation distance between a rotating point and the center changes. Here it is:
var alpha = 0.10146071845187077;
var cos_ = Math.cos(alpha);
var sin_ = Math.sin(alpha);
var center = [4861165.687852355,7606554.432771027];
var pointBefore = [4847712.770874163, 7610682.032298427];
var dist1, dist2, x1, y1, x2, y2, pointAfter = [];
// 1. substract + 2. rotate + 3. get back
// 1.
x1 = pointBefore[0] - center[0];
y1 = pointBefore[1] - center[1];
// 2.
x2 = cos_ * x1 - sin_ * y1;
y2 = sin_ * x1 + cos_ * y1;
// 3.
pointAfter[0] = x2 + center[0];
pointAfter[1] = y2 + center[1];
// Check distances
dist1 = Math.sqrt(Math.pow(x1, 2) + Math.pow(y1, 2));
dist2 = Math.sqrt(Math.pow(pointAfter[0] - center[0], 2) +
Math.pow(pointAfter[1] - center[1], 2));
console.log(JSON.stringify({dist1: dist1, dist2: dist2}));
// -> {"dist1":14071.888753138577,"dist2":14071.88875313881}
I hope, I made some errors in math, but I cannot see them.

Inaccuracy is due to the fact how floating point numbers are stored:
Is floating point math broken?
Basically, it's impossible to store irrational numbers and high precision real numbers in the fixed space of 64bits so there will be rounding errors which become significant after many operations. Think of the number 2/3, you cannot represent it accurately no matter the precision.
A possible solution is to either calculate with whole numbers only when possible or round the results after each operation.

Related

Draw a perpendicular line through middle of two long/lat points

Hello i'm currently trying to draw a line through two long/lat lines to create a triangle. So far i have manged to draw a line through but the line is not perpendicular and looks skewed. Here is my code:
startPosition = [-0.17640, 51.426700];
endPosition = [0.17640, 51.796700];
triangleSizeY = (endPosition [1] - startPosition[1]) / 6;
/*subtract
end from start to work out direction and also use this divided by 6 to
get distance*/
triangleSize *= -1;
triangleSizeX = (endPosition [0] - startPosition[0]) / 6;
/*subtract
end from start to work out direction and also use this divided by 6 to
get distance*/
triangleSize *= -1;
var cx = (startPosition[0] + endPosition[0]) / 2;
var cy = (startPosition[1] + endPosition[1]) / 2;
var dx = (endPosition[0] - startPosition[0]) / 2;
var dy = (endPosition[1] - startPosition[1]) / 2;
positions[0] = [midPoint[0] + triangleSizeX, midPoint[1] +
triangleSizeY];
positions[1] = [cx - dy, cy + dx];
positions[2] = [cx + dy, cy - dx];
This is what it looks like:
First, lat/lon are angular so you can not do linear type distances. The steps you need to take to solve this:
Compute the distance between the 2 lat/lon pairs you want a perpendicular line from.
Take half the distance computed from the above step to get you the midpoint range.
Calculate the bearing between the 2 lat/lon pairs. (see reference below on computing a bearing from 2 lat/lon's)
With the half distance and bearing, you can compute the lat/lon of the midpoint. This is called computing a lat/lon based on a range and bearing. (See the reference below.)
Now you can go perpendicular from the midpoint by adding/subtracting 90 degrees from the bearing in step 3. Decide on a range you want to compute the new lat/lon from a range/bearing like in step 4.
This site (https://www.movable-type.co.uk/scripts/latlong.html) has the calculations you need to do this. Also, since the distance is relatively small, you can use the Equirectangular approximation over Haversine for distance calculation.

Get coords of the intersection of the line in the plane

I have a canvas with this params:
width = 400, height = 400
and have a line passing through the point cursor[x1,y1] at an angle Q (in degree)
I need get all coords of the intersection of the line in the plane and write it to array. Now i use this equation: y - y1 = k * (x - x1)
to check all point I use this code:
var rad = Q * Math.PI/180;
for (ctrY = 0; ctrY < 400; ctrY += 1) {
for (ctrX = 0; ctrX < 400; ctrX += 1) {
if ( (ctrY - cursor.y) ===
~~(Math.tan(rad) * (ctrX - cursor.x)) ) {
z.push([ctrX, ctrY]);
}
}
}
For example when 0 < Q < 90 and cursor[x1,y1] = [200,200] z.length = 0 and it's not correct.
Where i'm wrong? Maybe there is a more convenient algorithm?
P.S. Sorry for my english
Seems you need line rastering algorithm. Consider Bresenham algorithm.
You can also look at DDA algorithm
I imagine an algorithm like this. (I only consider the case when 0 < Q < 90). First I will want to calculate the points where the line will intersect the Ox and Oy axes, considering the origin (0,0) point the upper left corner and if we imagine that the negative x and y values are respectively to the left and to the top of this point. Let x2 and y2 be the values where the line will intersect Ox and Oy. We want to calculate these values. We now have a system with 2 unknown variables (x2 and y2): Math.tan(rad) = (y1 -y2)/x1 and Math.tan(rad) = y1/(x1-x2). We can deduct these equations by drawing the line on the coordinate system and analyzing a bit. If we solve the system of equations we find something like: x2 = (x1*y1 -x1 * x1 * Math.tan(rad)/(2 * y1-x1)) and y2= y1- x1 * Math.tan(rad) (These need to be verified, I haven't double checked my calculus). A linear equation can be defined by the formula y = a*x + b and in our case a = x2 and b = y2. We can then calculate the points like this:
for (xIdx = 0; xIdx < 400; xIdx += 1) {
var ctrX = xIdx;
var ctrY = x2 * ctrX + y2 //todo: replace with the respective calculated variables x2 and y2(we could also define two functions in js) and proper rounding
z.push([ctrX, ctrY]);
}
I'm not sure if I'm 100% accurate but I hope you understand my idea.

Spherical Distance in JavaScript

I need to find the Spherical Distance of two coordinates using Javascript. I am using Wolfram a lot for this project and found this formula d=cos^(-1)(P·Q) [reference: http://mathworld.wolfram.com/SphericalDistance.html]. So I know that P·Q is the dot product of the two coordinates in question. This leads to finding the dot product which I found as DotProduct = (x1*x2 + y1*y2 + z1*z2) [reference: http://en.wikipedia.org/wiki/Dot_product]. So I put together the following method and get NaN (Not a Number) every time.
function ThreeDimensionalDistance(x1,y1,z1,x2,y2,z2){
return Math.acos(x1*x2 + y1*y2 + z1*z2);
}
Here are two sets of sample data I use and I can't figure out why I get NaN. Am I missing something small, do I need to convert my numbers to something for them to work with arc cos? Thank you in advance for any help.
Sample 1
X:-1.7769265970284516,Y:-5.129885707200497,Z:-2.554761143401265
X:-0.8336414256732807,Y:-1.9876462173033347,Z:5.599491449072957
Distance: NaN
Sample 2
X:-0.8336414256732807,Y:-1.9876462173033347,Z:5.599491449072957
X:0.8447772905770565,Y:4.252407300473133,Z:4.147696165367961
Distance: NaN
I've done some math, so try the following out:
function threeDimensionalDistance(x1, y1, z1, x2, y2, z2) {
// Assume that the points are on the same sphere
var radius = Math.sqrt(x1 * x1 + y1 * y1 + z1 * z1);
// Calculate normalized spherical distance
var dotProduct = x1 * x2 + y1 * y2 + z1 * z2;
var normalizedDistance = Math.acos(dotProduct / (radius * radius));
// Calculate actual distance
var distance = normalizedDistance * radius;
return distance;
}
One minor change that I made was renaming your method to begin with a lowercase letter, to follow standard JavaScript style guidelines.

Javascript: Find point on perpendicular line always the same distance away

I'm trying to find a point that is equal distance away from the middle of a perpendicular line. I want to use this point to create a Bézier curve using the start and end points, and this other point I'm trying to find.
I've calculated the perpendicular line, and I can plot points on that line, but the problem is that depending on the angle of the line, the points get further away or closer to the original line, and I want to be able to calculate it so it's always X units away.
Take a look at this JSFiddle which shows the original line, with some points plotted along the perpendicular line:
http://jsfiddle.net/eLxcB/1/.
If you change the start and end points, you can see these plotted points getting closer together or further away.
How do I get them to be uniformly the same distance apart from each other no matter what the angle is?
Code snippit below:
// Start and end points
var startX = 120
var startY = 150
var endX = 180
var endY = 130
// Calculate how far above or below the control point should be
var centrePointX = ((startX + endX) / 2);
var centrePointY = ((startY + endY) / 2);
// Calculate slopes and Y intersects
var lineSlope = (endY - startY) / (endX - startX);
var perpendicularSlope = -1 / lineSlope;
var yIntersect = centrePointY - (centrePointX * perpendicularSlope);
// Draw a line between the two original points
R.path('M '+startX+' '+startY+', L '+endX+' '+endY);
Generally you can get the coordinates of a normal of a line like this:
P1 = {r * cos(a) + Cx, -r * sin(a) + Cy},
P2 = {-r * cos(a) + Cx, r * sin(a) + Cy}.
A demo applying this to your case at jsFiddle.

Canvas, drawing a line segment

My trigonometry is more than weak, and therefore I do not know how to draw a line segment shorter than full lines start point and end point.
http://jsfiddle.net/psycketom/TUyJb/
What I have tried, is, subtract from start point a fraction of target point, but it results in a wrong line.
/*
* this is an excerpt from fiddle, that shows
* the actual calculation functions I have implemented
*/
var target = {
x : width / 2 + 60,
y : 20
};
var start = {
x : width / 2,
y : height
};
var current = {
x : 0,
y : 0
};
var growth = 0.5;
current.x = start.x - (target.x * growth);
current.y = start.y - (target.y * growth);
My bet is that I have to use sin / cos or something else from the trigonometry branch to get it right. But, since my trigonometry is not even rusty, but weak in general, I'm stuck.
How do I draw a proper line to target?
If I understand you correctly, then this should give you what you're looking for:
current.x = start.x + (target.x - start.x) * growth;
current.y = start.y + (target.y - start.y) * growth;
The equation is a linear interpolate, its the same as linear easing. You take the delta of the start and end (min and max), multiply it by a percent (the normal) of how far along delta you are and then you add it back to the start value. Incredibly essential algorithm :)

Categories

Resources