Calculate distance on the basis of Angle and Maximum Range - javascript

I am working on javascript code where I need to find out distance on the basis of Angle, Initial Height, Velocity, Maximum Range.
Example: If an object shoots from the ground (where height = 0) at the angle 45 degree and with the velocity of 3000. The Object drops at distance 1500 meter far from the point where it was thrown.
What will be the distance from the shooting point to dropping point on the ground, if the object shoots from same height and velocity but at the angle of 60 degree.
Initial Height => h = 0
Angle => a = 45 degree
Velocity => v = 3000
Max Range => m = 1500 meter
var h = 0;
var a = 45;
var v = 3000;
var m = 1500;
var d = null; //need to calculate this
// Range calculation formula is: d = V₀² * sin(2 * α) / g
d = v * v * Math.sin(2 * a) / 9.8;
I am getting Range from above formula but that's not on the basis of given maximum range.

The function Math.sin expects that the angle is given in radian. Given an angle α in degree, you can compute the angle in radian by α * (π/180). Thus, your computation needs to be performed as follows.
d = v * v * Math.sin(2 * a * Math.PI / 180) / 9.8;
Note, your maximum range is actually ≈920000 m. Your initial velocity is 10800 km/h (or 6710 mph), which is 10 times as fast as a commercial air plane.

Related

With HTML5 canvas, how to calculate the final point coordinates with an offset?

On a HTML5 canvas object, I have to subtract a distance from a destination point, to give the final destination on the same line.
So, first I have calculated the distance between the source and target points, with the Pythagorean theorem, but my memories of Thales's theorem are too faulty to find the final point (on same line), with the right x and y attributes.
function getDistance (from, to){
return Math.hypot(to.x - from.x, to.y - from.y);
}
function getFinalTo (from, to, distanceToSubstract){
//with Pythagore we obtain the distance between the 2 points
var originalDistance = getDistance(from, to);
var finalDistance = originalDistance - distanceToSubstract;
//Now, I was thinking about Thales but all my tries are wrong
//Here some of ones, I need to get finalTo properties to draw an arrow to a node without
var finalTo = new Object;
finalTo.x = ((1 - finalDistance) * from.x) + (finalDistance * to.x);
finalTo.y = ((1 - finalDistance) * from.y) + (finalDistance * to.y);
return finalTo;
}
Indeed, the arrowhead be hidden by the round node that can be about 100 pixels of radius, so I try to get the final point.
Thanks a lot.
Regards,
Will depend on the line cap. For "butt" there is no change, for "round" and "square" you the line extends by half the width at each end
The following function shortens the line to fit depending on the line cap.
drawLine(x1,y1,x2,y2){
// get vector from start to end
var x = x2-x1;
var y = y2-y1;
// get length
const len = Math.hypot(x,y) * 2; // *2 because we want half the width
// normalise vector
x /= len;
y /= len;
if(ctx.lineCap !== "butt"){
// shorten both ends to fit the length
const lw = ctx.lineWidth;
x1 += x * lw;
y1 += y * lw;
x2 -= x * lw;
y2 -= y * lw;
}
ctx.beginPath()
ctx.lineTo(x1,y1);
ctx.lineTo(x2,y2);
ctx.stroke();
}
For miter joins the following answer will help https://stackoverflow.com/a/41184052/3877726
You can use simple proportion by distance ratio:
(I did not account for round cap)
ratio = finalDistance / originalDistance
finalTo.x = from.x + (to.x - from.x) * ratio;
finalTo.y = from.y + (to.y - from.y) * ratio;
Your approach was attempt to use linear interpolation, but you erroneously mixed distances (in pixels, meters etc) with ratios (dimensionless - is this term right?)
ratio = finalDistance / originalDistance
finalTo.x = ((1 - ratio) * from.x) + (ratio * to.x);
finalTo.y = ((1 - ratio) * from.y) + (ratio * to.y);
Note that both approaches is really the same formula.

Calculate the position of an orbiting object

I'm creating a solar system animation using canvas and have a problem calculating an object's position (x,y) values.
Earth is orbiting around the Sun, and I need to calculate and update the Earth's position at each frame. And using Earth's position, I'll orbit the Moon around the Earth.
The related function is this:
orbitAround : function (master) {
master.makeOrbitCenter();
this.increaseOrbitAngle();
context.rotate(this.orbit.angle * Math.PI/180);
context.translate(this.orbit.distance, 0);
// calculate and update the X and Y position of the earth
// so that luna can orbit around earth
// these are the initial values of earth
this.position.x = master.position.x + this.orbit.distance;
this.position.y = master.position.y;
},
Fiddle demo
To make it simpler, I've drawn this picture
Let's say the blue disc is the Earth, and is located at (300,200). The Sun is at (200,200) and the distance between them is 100. After the Earth makes a 45 degree rotation around the Sun, what would its position be? How can I calculate it using the given values?
It looks like you've got something working there, but here's a breakdown:
Math.cos and Math.sin return a theoretical x and y position along an axis. They need to be given the angle in radians.
So, in order to get the position of a 45 degree angle, you essentially need to calculate the radian equivalent of degrees first.
var degrees = 45;
var radians = degrees * (Math.PI / 180);
The result here is 0.785398163. You can then get the x and y coordinate of the orbiting object using this:
var x = Math.cos(0.785398163) * distance;
var y = Math.sin(0.785398163) * distance;
The whole process for a single frame would look like this:
var distance = 100; // from the centre of orbit
var degrees = 45; // around a 360 degree orbit
var radians = degrees * (Math.PI / 180);
var x = Math.cos(radians) * distance;
var y = Math.sin(radians) * distance;
Here's a very basic fiddle with square planets and everything.
I would do something like this:
distance = 100; //distance between earth and sun.
getXPosition = function(angle){
return distance*(Math.cos(Math.PI * (angle/180)));
};
getYPosition = function(angle){
return distance*(Math.sin(Math.PI * (angle/180)));
};
var x = getXPosition(45); //70.71 from the sun
var y = getYPosition(45); //70.71 from the sun
And to get the final position just do this:
x += 200; //200 = sun position
y -= 200; //200 = sun position

Problems With Vector Reflection with Particle Collisions

I was wondering whether I made a math mistake in my particle collision simulation found here.
The particles don't seem to separate properly during collision resolution. Here is a code snippet from the function which separates particles and changes their velocities:
//particle 1
var pi = particles[i];
//particle 2
var pj = particles[j];
//particle 1 to particle 2
var pimpj = pi.mesh.position.clone().sub(pj.mesh.position);
//particle 2 to particle 1
var pjmpi = pj.mesh.position.clone().sub(pi.mesh.position);
//if colliding (radius is 20)
if(pimpj.length() < 20 && pimpj.length() != 0)
{
//reflect velocity off of 1->2
pi.velocity = pi.velocity.reflect(pimpj.clone().normalize()).multiplyScalar(restitution);
//reflect velocity off of 2->1
pj.velocity = pj.velocity.reflect(pjmpi.clone().normalize()).multiplyScalar(restitution);
//move particle 1 to appropiate location based off of distance in between
var pip = pi.velocity.clone().normalize().multiplyScalar(20-pimpj.length());
//move particle 2
var pjp = pj.velocity.clone().normalize().multiplyScalar(20-pimpj.length());
pi.mesh.position.add(pip);
pj.mesh.position.add(pjp);
}
I have tried reversing pimpj with pjmpi while changing pi.velocity, but to no effect.
note: I am using three.js
Firstly, the particle collisions you seem to be looking for are Elastic collisions, for which there is maths covering the calculation of the velocities after a collision.
The collision is simplest in the centre of momentum frame, so if you first calculate that frame V = (m1v1 + m2v2)/(m1+m2), then you can subtract it from both particles, do a simple symmetric collision and add the frame velocity back on afterwards.
From there, calculate the velocities using the formulae in the 2 & 3d section of that page.
Specific points on your code:
pimpj = -pjmpi, so you don't need both
A collision occurs when the paths between the last frame and this frame got too close; if you only check the distance at each frame you will have problems where particles fly through each other at high speed, and that you have to keep shifting their positions because they are already overlapping when you detect the collision.
Ideally calculate the positions on impact and use those to redirect them.
For speed, only calculate pimpj.clone().normalize() once, and store it - you're not changing this direction unit vector later, so you don't need to keep recalculating it, or calculating pjmpi-derived equivalents (see #1)
I think part of the problem is that your model of collision is overly simplistic. The basic rules for collision are conservation of momentum and conservation of energy. Looking at the 1D case. If both particles have the same mass m and u1 and u2 are you velocities beforehand and v1, v2 are the velocities after then
m u1 + m2 u2 = m v1 + m v2
conservation of energy for a perfect collision gives
1/2 m u1.u1 + 1/2 m u2.u2 = 1/2 m v1.v1 + 1/2 m v2.v2.
These two equations have the solution v1 = u2, v2 = u1. That is the velocities switch. In particular if one velocity is zero before collision then after collision the other velocity becomes zero after the collision. You can see this happen when using a newton's cradle.
In 2D we can resolve in a coordinate system with 1 direction along to the plane of contact and one direction perpendicular to it. The force only occurs in the perpendicular direction, this means the velocities along the pane don't change but the perpendicular velocities switch.
var u = pjmpi.clone().normalize();
var v = new THREE.Vector3(u.y,-u.x,0);
// resolve in two directions
var piu = pi.velocity.dot(u);
var piv = pi.velocity.dot(v);
pi.velocity = new THREE.Vector3(
pju * u.x + piv * v.x,
pju * u.y + piv * v.y,
0);
pj.velocity = new THREE.Vector3(
piu * u.x + pjv * v.x,
piu * u.y + pjv * v.y,
0);
That works for a perfectly elastic collision. See Wikipedia elastic collision which has an nice illustration. The formula at the end simplifies a bit if you take the masses equal.
For an partially inelastic collision with restitution R we can look at the end of http://www.plasmaphysics.org.uk/collision2d.htm. Now take the velocity of the center of mass w. This will not change after the collision because the total momentum is conserved. So w=(u1+u2)/2 = (v1+v2)/2. Take the velocities relative to this center of mass
v1' = v1-w, v2' = v2-w, apply the restitution v1'' = R (v1'-w), v2'' = R(v2'-w) and add the velocity of the center of mass.
v1''' = R(v1-v2)/2 + (v1+v2)/2
v2''' = R(v1-v2)/2 + (v1+v2)/2
Also see wikipedia Inelastic collision which has the same formula in 1D.
This translate to code as
var u = pjmpi.clone().normalize();
var v = new THREE.Vector3(u.y,-u.x,0);
// resolve in two directions
var piu = pi.velocity.dot(u);
var piv = pi.velocity.dot(v);
var pju = pj.velocity.dot(u);
var pjv = pj.velocity.dot(v);
// velocities after collision
var v1x = pju * u.x + piv * v.x;
var v1y = pju * u.y + piv * v.y;
var v2x = piu * u.x + pjv * v.x;
var v2y = piu * u.y + pjv * v.y;
// vel center of mass
var wx = (v1x+v2x)/2;
var wy = (v1y+v2y)/2;
// difference
var dx = (v1x-v2x)/2;
var dy = (v1y-v2y)/2;
// final velocities
pi.velocity = new THREE.Vector3(
wx + restitution * dx,
wy + restitution * dy,
0);
pj.velocity = new THREE.Vector3(
wx - restitution * dx,
wy - restitution * dy,
0);
// We can print the KE and momentum before and after to check
console.log("KE before ",
pi.velocity.lengthSq()+pj.velocity.lengthSq());
console.log("M before ",
pi.velocity.x+pj.velocity.x ,
pi.velocity.y+pj.velocity.y);
console.log("KE after",v1x*v1x+v1y*v1y + v2x*v2x + v2y*v2y);
console.log("M after ", v1x+v2x, v1y+v2y);
console.log("KE rest",
pi.velocity.lengthSq()+pj.velocity.lengthSq());
console.log("M rest ",
pi.velocity.x+pj.velocity.x ,
pi.velocity.y+pj.velocity.y);
This can simplify nicely. Start by taking the mean and half the difference of the two particles. Reflect the difference and apply the restitution
var len = pjmpi.length();
// unit vector normal to plane of collision
var nx = pjmpi.x / len;
var ny = pjmpi.y / len;
// unit vector tangent to plane of collision
var tx = -ny;
var ty = nx;
// center of mass
var wx = (pi.velocity.x+pj.velocity.x)/2;
var wy = (pi.velocity.y+pj.velocity.y)/2;
// half difference
var dx = (pi.velocity.x-pj.velocity.x)/2;
var dy = (pi.velocity.y-pj.velocity.y)/2;
// resolve in two directions
var a = dx * nx + dy * ny;
var b = dx * tx + dy * ty;
// reflect difference in normal
var cx = -a * nx + b * tx;
var cy = -a * ny + b * ty;
// apply restitution and add back center of mass
pi.velocity.set(
wx + restitution * cx,
wy + restitution * cy,
0);
pj.velocity.set(
wx - restitution * cx,
wy - restitution * cy,
0);
I've used THREE as little as possible to avoid creating too many objects.
I've saved this as a fiddle at http://jsfiddle.net/SalixAlba/8axnL59k/. I've reduced number of points, and removed gravity to make things a bit simpler to see.
Besides the very good points in the other answers, you only want to do the velocity changes if the particles move towards each other. This is the case of the derivative of the distance is negative, which can be transformed to the scalar product of pi-pj and vi-vj being negative.
Without that you may enter an infinite loop where the velocities get reflected back and forth while the distance stays below the critical radius.

Haversine Formula still not working

I used harversine formula to calculate if points are inside/outside of circle, but still it response that points are inside of the circle, it must be outside the circle. Take a look at my code.
var xp = 7.070562277980709; // point_lat
var yp = 125.60755640475463; // point_long
var radius = 63.942490126300555; // radius
var xc = 7.070479805752504; // circle_lat
var yc = 125.60851603754577; // circle_lon
var r = radius / 1000; // convert meter to kilometer
var dlat = (xp - xc) * (Math.PI / 180);
var dlng = (yp - yc) * (Math.PI / 180);
var a = ((Math.sin(dlat / 2)) * (Math.sin(dlat / 2)));
var b = ((Math.cos(xp * (Math.PI / 180))) * (Math.cos(xc * (Math.PI / 180))));
var c = ((Math.sin(dlng / 2)) * (Math.sin(dlng / 2)));
var d = a + (b * c);
var e = 2 * Math.atan2(Math.sqrt(d), Math.sqrt(1 - d));
var f = r * e;
if (f < r) {
alert('INSIDE');
} else if(f > r) {
alert('OUTSIDE');
}
this function should alert me "OUTSIDE". Whats wrong with this code?? Thanks for your help.
All points are given by google map. And the default unit of radius of google map is meter, thats why I converted it to kilometer.
In the formula you are using, the radius is the Earth's radius. The formula gives the great circle (i.e. shortest) distance between two points on the Earth's surface.
Using 63.942490126300555 for the radius, then dividing it by 1,000 gives an f of 0.0000010667905687961212 km or 0.001 m or 1 mm.
Substituting a more appropriate value for r (e.g. 6,371) gives an f of 0.10629117978319975 km, or 106.291 metres.
Calculating it another way, since the coordinates are close to the equator, you can work out the distances as fractions of the Earth's circumference and use plain trigonometry.
Using a circumference of 40,000 km, the difference in latitude is 0.0000824722282057877 degrees, which is:
dLat = 40,000 km * 0.0000824722282057877 / 360
or
dLat = 0.009163580911754189 km
= 9.164 m
and for longitude:
dLong = 0.0009596327911367553;
dist = 40000 * 0.0009596327911367553 / 360;
= 0.10662586568186169 km
= 106.626 m
And a bit of basic trig:
dist = sqrt(9.164^2 + 106.626^2)
= 0.10629117978319975 km
= 106.291 m
which is pretty close to the other result. You can use that method quite successfully for small distances, just multiply the distance derived from the difference in longitude by the cosine of the latitude (since angular distances get shorter as you get closer to the pole).
My comment was just a dig at your spelling of "metre". :-)
Edit
Here's a function to return the great circle distance based on the Haversine formula at Movable Type Scripts:
// Return the great circle distance between two points on
// the Earth's surface given their latitude and longitude in
// decimal degrees. Only approximate.
function greatCircleDistance(lat0, lon0, lat1, lon1) {
// Approximate Earth radius
var earthRadius = 6.371e3; // 6,371,000 m
// Convert args to radians
for (var i=arguments.length; i; ) {
arguments[--i] = arguments[i] * Math.PI/180;
}
// Do calculation
var dLat = lat1 - lat0;
var dLon = lon1 - lon0;
var a = Math.pow(Math.sin(dLat/2),2) +
Math.cos(lat0) * Math.cos(lat1) *
Math.pow(Math.sin(dLon/2),2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return earthRadius * c;
}
var xp = 7.070562277980709; // point_lat
var yp = 125.60755640475463; // point_long
var xc = 7.070479805752504; // circle_lat
var yc = 125.60851603754577; // circle_lon
console.log(greatCircleDistance(xp, yp, xc, yc)); // 0.10629117978188952
So you can do:
if ( greatCircleDistance(xp, yp, xc, yc) > 63) {
console.log('outside');
} else {
console.log('inside');
}
It is obvious that your Harversine calculation is correct and it is equal to the result returned by google map api static method computeDistanceBetween. Here is a fiddle.
However your logic implies that both the radius of sphere and radius within which you want to check if a point exists, are same.
To get the expected output you must model your problem space as below
R : radius of sphere
p1, p2... : points(lat,long co-ordinates) on the surface of sphere
r: to check whether p2 lies within distance 'r' of p1 where r & R in the same unit
Based on above you need to implement below logic
var e = calculate haversine of the central angle for point p1 and p2
var d = e * R;//where R is the radius of sphere, and the d would be great circle distance
if( d < r){// check whether p1 exists within r distance of p2
//point is inside
}
else{
//point is outside
}
Note that Haversine formula is not only for earth distance, rather it is for spherical body. However the correctness may differ based on size and position of the points under consideration.

Use X,Y coordinates to plot points inside a circle

Is there a way in javascript to plot x,y coordinates so they fall into a circle rather than a square?
For example if I have the following code:
circleRadius = 100;
context.drawImage(img_elem, dx, dy, dw, dh);
I need to figure out a combination of x,y values that would fall inside a 100 pixel circle.
Thanks!
choose an x at random between -100 and 100
a circle is defined by x^2 + y^2 = r^2, which in your case equals 100^2 = 10000
From this equation you can get that y^2 = 10000 - x^2 , therefore the points with a chosen x and y = +/-sqrt(10000 - x^2) will lye on the circle.
choose an y at random between the two coordinates found at point 3
You're set!
EDIT:
In JS:
var radius = 100;
x = Math.random() * 2 * radius - radius;
ylim = Math.sqrt(radius * radius - x * x);
y = Math.random() * 2 * ylim - ylim;
Another edit: a jsFiddle Example
If you want equidistributed coordinates you better go for
var radius = 100
var center_x = 0
var center_y = 0
// ensure that p(r) ~ r instead of p(r) ~ constant
var r = radius*Math.sqrt(Math.random(1))
var angle = Math.sqrt(2*Math.PI)
// compute desired coordinates
var x = center_x + r*Math.cos(angle);
var y = center_y + r*Math.sin(angle);
If you want more points close to the middle then use
var r = radius*Math.random(1)
instead.
not sure what you mean for javascript but
x = R*cos(theta) and y = R*sin(theta) are the Cartesian points for a circle. R is the radius of course and theta is the angle which goes from 0 to 2*Pi.
I'm posting this as a solution because this question was the only relevant result in google.
My question/problem was how to add cartesian coordinates inside a circle where x and y would not exceed r.
Examples:
plot: (45,75) inside a circle with a radius of 100 (this would normally fall inside the circle, but not the correct position)
plot: (100,100) inside a circle with a radius of 100 (this would normally fall outside the circle
Solution
// The scale of the graph to determine position of plot
// I.E. If the graph visually uses 300px but the values only goto 100
var scale = 100;
// The actual px radius of the circle / width of the graph
var radiusGraph = 300;
// Plot the values on a cartesian plane / graph image
var xCart = xVal * radiusGraph;
var yCart = yVal * radiusGraph;
// Get the absolute values for comparison
var xCartAbs = Math.abs( xCart );
var yCartAbs = Math.abs( yCart );
// Get the radius of the cartesian plot
var radiusCart = Math.sqrt( xCart * xCart + yCart * yCart );
// Compare to decide which value is closer to the limit
// Once we know, calculate the largest possible radius with the graphs limit.
// r^2 = x^2 + y^2
if ( xCartAbs > yCartAbs ) { // Less than 45°
diff = scale / xCartAbs;
radiusMaximum = Math.sqrt( radiusGraph * radiusGraph + Math.pow( yCartAbs * diff, 2) );
} else if ( yCartAbs > xCartAbs ) { // Greater than 45°
diff = scale / yCartAbs;
radiusMaximum = Math.sqrt( radiusGraph * radiusGraph + Math.pow( xCartAbs * diff, 2) );
} else { // 45°
radiusMaximum = Math.sqrt( 2 * ( radiusGraph * radiusGraph ) );
}
// Get the percent of the maximum radius that the cartesian plot is at
var radiusDiff = radiusCart / radiusMaximum;
var radiusAdjusted = radiusGraph * radiusDiff;
// Calculate the angle of the cartesian plot
var theta = Math.atan2( yCart, xCart );
// Get the new x,y plot inside the circle using the adjust radius from above
var xCoord = radiusAdjusted * Math.cos( theta );
var yCoord = radiusAdjusted * Math.sin( theta );
Not sure if this is correct JavaScript code, but something like this:
for (x = -r; x < r; x++) {
for (y = -r; x < r; y++) {
if ((x * x + y * y) < (r * r)) {
// This x/y coordinate is inside the circle.
// Use <= if you want to count points _on_ the circle, too.
}
}
}

Categories