I was trying to make something that told you the intersection points of two circles. Where I put in the centers of the circles and the radius. (I got the intersection function from stackoverflow: here). I am trying to add the user input but when ever I change the static number inside the code to a user input (either through prompt or html input), the function breaks and the alert sends me an unfinished answer and an Nan.
Here is the coding so far (without user input):
<html>
<button onclick="button()">Test</button>
<script>
var x0 = 3;
var y0 = 0;
var r0 = 3;
var x1 = -1;
var y1 = 0;
var r1 = 2;
function button() {
intersection(x0, y0, r0, x1, y1, r1)
function intersection(x0, y0, r0, x1, y1, r1) {
var a, dx, dy, d, h, rx, ry;
var x2, y2;
/* dx and dy are the vertical and horizontal distances between
* the circle centers.
*/
dx = x1 - x0;
dy = y1 - y0;
/* Determine the straight-line distance between the centers. */
d = Math.sqrt((dy*dy) + (dx*dx));
/* Check for solvability. */
if (d > (r0 + r1)) {
/* no solution. circles do not intersect. */
return false;
}
if (d < Math.abs(r0 - r1)) {
/* no solution. one circle is contained in the other */
return false;
}
/* 'point 2' is the point where the line through the circle
* intersection points crosses the line between the circle
* centers.
*/
/* Determine the distance from point 0 to point 2. */
a = ((r0*r0) - (r1*r1) + (d*d)) / (2.0 * d) ;
/* Determine the coordinates of point 2. */
x2 = x0 + (dx * a/d);
y2 = y0 + (dy * a/d);
/* Determine the distance from point 2 to either of the
* intersection points.
*/
h = Math.sqrt((r0*r0) - (a*a));
/* Now determine the offsets of the intersection points from
* point 2.
*/
rx = -dy * (h/d);
ry = dx * (h/d);
/* Determine the absolute intersection points. */
var xi = x2 + rx;
var xi_prime = x2 - rx;
var yi = y2 + ry;
var yi_prime = y2 - ry;
var list = "(" + xi + ", " + yi + ")" + "(" + xi_prime + ", " +
yi_prime + ")"
alert(list);
}
}
</script>
</html>
When I change anyone of the variables that apart of the circle into user input like:
var x0 = prompt("X cord of circle 1");
The alert comes up as: (3-2.6250, -1.4523687548277813)(NaN, 1.4523687548277813)
and without the user input (shown in the large code block) it comes out as: (0.375, -1.4523687548277813)(0.375, 1.4523687548277813). Which is the correct answer.
Can anyone tell me what I am doing wrong or what is going on?
Prompt will take the user input as a string. To convert it to an integer for math jazz, use parseInt.
var x0String = prompt("X cord of circle 1");
var x0 = parseInt(x0String);
JavaScript should "convert" numeric string to integer if you perform calculations on it since JS is weakly typed, but it is good practice and you can avoid some pitfalls by parsing the integer value from a string yourself.
Your prompt returns a string, but you can't do math on a string. Try converting it to a number:
var x0 = Number(prompt("X cord of circle 1"));
As Daniel pointed out it's always better to change the string to a number if you need it as a number. It seemed really confusing, why the program was not working, until I found that x0 is used twice.
The reason the program was returning NaN is because when using the + operator, the number is converted into a string not a number.
That happens here: x0 + (dx * a/d);
What happens then is that a negative number is added to the string creating something like: 2-2
As you might expect the value can no longer be converted into a number, thus returning NaN, when we try to minus it later.
Related
I'm creating a raycasting engine on javascript using p5js and there is an issue with the line to line (raycast to wall) intersection.
I found a lot of line to line collision algorithms, including p5 collide library, but the problem appears on every one of them.
this.intersects = function (raycastStart, raycastEnd) {
var x1 = this.startPoint.x; //Start point is the first point of a line.
var y1 = this.startPoint.y;
var x2 = this.endPoint.x; //End point is the second point of a line.
var y2 = this.endPoint.y;
var x3 = raycastStart.x;
var y3 = raycastStart.y;
var x4 = raycastEnd.x;
var y4 = raycastEnd.y;
var a_dx = x2 - x1;
var a_dy = y2 - y1;
var b_dx = x4 - x3;
var b_dy = y4 - y3;
var s = (-a_dy * (x1 - x3) + a_dx * (y1 - y3)) / (-b_dx * a_dy + a_dx * b_dy);
var t = (+b_dx * (y1 - y3) - b_dy * (x1 - x3)) / (-b_dx * a_dy + a_dx * b_dy);
//Vector2 is simply class with two fields: x and y.
return (s >= 0 && s <= 1 && t >= 0 && t <= 1) ? new Vector2(x1 + t * a_dx, y1 + t * a_dy) : null;
}
The line to line collision works on one side properly, but on the other, it works incorrect, according to my y position.
this is my map.
on one side it works perfectly
but on the other, it checks collision for line segments, that are lower than my Y position
(I would comment, but don't have enough reputation to do so...)
It appears that your line collision algorithm is working. But what appears to be missing is a check to determine which raycaster-to-line intersection is closer. That is, in your working example the raycast never casts across two line segments, so there is no question about which line segment constrains your raycast. But in your non-working example, the raycaster hits 2 of your 4 segments, so you now need to determine which of the 2 intersection points is closer to the raycast start, in order to determine which line segment is closer.
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.
I want to calculate the rotation of a specific point (top and left). It's a bit complicated. I know the original top and left. Then a scaling is added and then the rotation is calculated.
At the moment i do this. (orginal left:-350, orginal top: -10, f1_scale: 0.544444, rotation angle:-30deg)
function sin(x) {
return Math.sin(x / 180 * Math.PI);
}
function cos(x) {
return Math.cos(x / 180 * Math.PI);
}
function rotate(x, y, a) {
var x2 = cos(a) * x - sin(a) * y;
var y2 = sin(a) * x - cos(a) * y;
return [x2, y2];
}
var scaledLeft = -350 * f1_scale;
var scaledTop = -10 * f1_scale;
var rotateOut = rotate(scaledLeft, scaledTop,-30);
This works for the left (x) coordinate, but the y coordinate is way off.
Can someone see what i did wrong or did someone already tried this?
Thank you.
You need to understand math behind it. First, look at this image http://prntscr.com/amd2it where:
(x0, y0) are coordinates of starting point
(x1, y1) are coordinates after rotation
(p, q) are coordinates of point of rotation
In order to find (x1, y1), you need to know value of (p, q), as well as (x0, y0) and angle a. If we apply elementary geometry, we get this:
sin(a)( q - y0 ) = q - y1
y1 = q - sin(a)( q - y0 )
and
cos(a)( p - x0 ) = p - x1
x1 = p - cos(a)( p - x0 )
or you can use Pythagoras' theorem for second value.
When we understand this, I don't think it will be problem to translate it to code.
I have a function which gets the mouse position in world space, then checks to see if the mouse is over or near to the circle's line.
The added complication how ever is the circle is transformed at an angle so it's more of an ellipse. I can't see to get the code to detect that the mouse is near the border of circle and am unsure where I am going wrong.
This is my code:
function check(evt){
var x = (evt.offsetX - element.width/2) + camera.x; // world space
var y = (evt.offsetY - element.height/2) + camera.y; // world space
var threshold = 20/scale; //margin to edge of circle
for(var i = 0; i < obj.length;i++){
// var mainAngle is related to the transform
var x1 = Math.pow((x - obj[i].originX), 2) / Math.pow((obj[i].radius + threshold) * 1,2);
var y1 = Math.pow((y - obj[i].originY),2) / Math.pow((obj[i].radius + threshold) * mainAngle,2);
var x0 = Math.pow((x - obj[i].originX),2) / Math.pow((obj[i].radius - threshold) * 1, 2);
var y0 = Math.pow((y - obj[i].originY),2) / Math.pow((obj[i].radius - threshold) * mainAngle, 2);
if(x1 + y1 <= 1 && x0 + y0 >= 1){
output.innerHTML += '<br/>Over';
return false;
}
}
output.innerHTML += '<br/>out';
}
To understand it better, I have a fiddle here: http://jsfiddle.net/nczbmbxm/ you can move the mouse over the circle, it should say "Over" when you are within the threshold of being near the circle's perimeter. Currently it does not seem to work. And I can't work out what the maths needs to be check for this.
There is a typo on line 34 with orignX
var x1 = Math.pow((x - obj[i].orignX), 2) / Math.pow((obj[i].radius + threshold) * 1,2);
should be
var x1 = Math.pow((x - obj[i].originX), 2) / Math.pow((obj[i].radius + threshold) * 1,2);
now you're good to go!
EDIT: In regards to the scaling of the image and further rotation of the circle, I would set up variables for rotation about the x-axis and y-axis, such as
var xAngle;
var yAngle;
then as an ellipse can be written in the form
x^2 / a^2 + y^2 / b^2 = 1
such as in Euclidean Geometry,
then the semi-major and semi-minor axes would be determined by the rotation angles. If radius is the circles actual radius. then
var semiMajor = radius * cos( xAngle );
var semiMinor = radius;
or
var semiMajor = radius;
var semiMinor = radius * cos( yAngle );
you would still need to do some more transformations if you wanted an x and y angle.
so if (xMouseC, yMouseC) are the mouse coordinates relative to the circles centre, all you must do is check if that point satisfies the equation of the ellipse to within a certain tolerance, i.e. plug in
a = semiMajor;
b = semiMinor;
x = xMouseC;
y = yMouseC;
and see if it is sufficiently close to 1.
Hope that helps!
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.