I'm well acquainted with basic math and know the equations, but when I try to implement them in canvas they fail.
Here's the relevant code:
function distance(one,two){
var a, b
if(one[0] > one[1]){
a = one[1] - one[0]
}else{
a = one[0] - one[1]
}
if(two[0] > two[1]){
b = two[1] - two[0]
}else{
b = two[0] - two[1]
}
var c = a^2 + b^2;
return Math.sqrt(c);
}
radius = distance([centerX,e.clientX], [centerY,e.clientY])
context.fillCircle(centerX, centerY, radius, "white");
Here's the code in action
As you can see, the circle is far too short and I don't know why... when I remove the sqrt, it becomes out of whack very quickly.
^ does not do what you think it does.
js> 8^2
10
js> Math.pow(8,2)
64
Related
I reached out for help recently on math.stackexchange.com with a question about 2 dimensional algebra. The answer was promptly provided but it's in mathematical notation unfamiliar to me and the person giving the answer has stopped responding to my questions. While I am extremely grateful to BStar for providing this information, he/she has stopped replying both on the site and the chat, and doesn't seem interested in helping me understand it to the point that I could write programming code to calculate the desired point P. I respect that, but it leaves me stuck for now. Could someone help me convert this sequence of steps into a programming language such as Javascript? (I am actually working in PHP, but Javascript would be more convenient to represent in a runnable Snippet on stackoverflow .. I'm happy with any current language that I can translate into PHP).
The post is at https://math.stackexchange.com/questions/4110517/trig-101-calculate-coords-of-point-p-such-that-it-is-distance-n-from-line-ab-an/4110550?noredirect=1#comment8504010_4110550
The answer given is in Latex but here's a screenshot of it:
The latest description of the process by the author BStar: "Here is the process: First calculate cos B and use arccos to get B. Second calculate tanθ to get θ with arctan by using |BP| is the same from two triangles. Knowing these, we can get vectors BA’ and B’P, thus vectors OA and OP. We get θ to grt vector BA’ in this case, not the other way around. "
I can follow up until step (5) where the comma notation comes in, i.e. k = (-xb, -yb)(xc - xb, yc - yb) / ac. This seems to make k a two dimensional vector but I don't think I ever worked with this notation. Later, k is used in step (6) and (6a) to calculate theta, appearing both in the numerator and denominator of a fraction. I have no idea how to expand this to get an actual value for theta.
(Edit Note: The author BStar assumed point A is at the origin, so (xa, ya) = (0, 0) but I cannot make that assumption in the real world. Thus the vector BA in Step 1 is actually (xa - xb, ya - yb) and his formula for k shown above is actually k = (xa - xb, ya - yb)(xc - xb, yc - yb) / ac. This expansion needs to be carried through the calculation but it's not a major change.)
If we were to frame this in Javascript, I could lay out a framework of what is known at the beginning of the calculation. It's not productive to represent every single step of the mathematical proof given by BStar, but I'm not sure exactly what steps can be left as processes in the mathematical proof and what steps need expounding in code.
/* Known points - A, B, C */
var xa = 10, ya = 10;
var xb = 100, yb = 500;
var xc = 700, yc = 400;
/* Known lengths m and n (distance perpendicularly from AB and AC) */
var m = 30;
var n = 50;
/* Point we want to calculate, P */
var px = 0, py = 0;
/* Calculation goes here - some Javascript notes:
* var a = Math.sin(angInRadians);
* var b = Math.asin(opposite / hypotenuse);
* var c = Math.pow(number, 2); // square a number
* var d = Math.sqrt(number);
*/
/* Print the result */
console.log('Result: P (' + px + ', ' + py + ')');
How would one express the maths from the diagram in the programming snippet above?
I think I can get you to the angle of B but I'm not very good with math and get lost with all those variables. If you are stuck at figuring out the angle try this and see if it does what you want. It seems to do what step 5 is asking but double check my work.
let pointA = {x: 100, y: 0};
let pointB = {x: 20, y: 20};
let pointC = {x: 0, y: 100};
let distBA_x = pointB.x - pointA.x;
let distBA_y = pointB.y - pointA.y;
//let BA_a = Math.sqrt(distBA_x*distBA_x + distBA_y*distBA_y);
let distBC_x = pointB.x - pointC.x;
let distBC_y = pointB.y - pointC.y;
//let BC_c = Math.sqrt(distBC_x*distBC_x + distBC_y*distBC_y);
var angle = Math.atan2(distBA_x * distBC_y - distBA_y * distBC_x, distBA_x * distBC_x + distBA_y * distBC_y);
if(angle < 0) {angle = angle * -1;}
var degree_angle = angle * (180 / Math.PI);
console.log(degree_angle)
I've laid it out on a canvas so you can see it visually and change the parameters. Hope it helps. Here's the Codepen https://codepen.io/jfirestorm44/pen/RwKdpRw
BA • BC is a "dot product" between two vectors. The result is a single number: It's the sum of the products of vector components. If the vectors are (x1,y1) and (x2,y2) the dot product is x1x2+y1y2.
Assuming you don't have a library for vector calculations and don't want to create one, the code for computing k would be:
k = (-xb*(xc - xb)-yb*(yc - yb)) / ac
Im creating an object that randomly moves in a natural way using noise like this (works as intended):
The objects encounter a collision and their trajectory is manipulated, the movement path now changes to straight line (words as intended)
thisRabbit.x = _world.width * (noise(thisRabbit.t));
thisRabbit.y = _world.height * (noise(thisRabbit.t+5));
thisRabbit.t += 0.001;
The problem is after this movement , i want the object to start moving in a random direction again as it was initially. If i use the same function, the object jumps to the last location before the trajectory was modified.
let vx = this.acquiredFood[0] - this.x;
let vy = this.acquiredFood[1] - this.y;
let f = (this.genes.speed + 10) / Math.sqrt(vx*vx+vy*vy);
vx = vx * f;
vy = vy * f;
let newX = this.x + vx;
let newY = this.y + vy;
So how do i get the object to move as before, given a starting position
edit: snippet here: https://editor.p5js.org/vince.chinner/sketches/HPFKR8eIw
Your problem is that you used a factor from 0 to 1 generated with noise and an incremented seed to generate the position by multiplying directly the world dimentions. When reaching food, you cannot increment the seed as to be in the exact position where the movement to get your food led you (I found no inverse function for noise to get the seed from the return value).
What you need to do instead is use the noise to increment or decrement the coordinates, so that no matter where the seed is, you don't loose your current position.
Here are the different corrections I applied to the code, as there were also syntax errors, I can't really paste the whole stuff here for copyright reasons (you didn't share the whole code here and the sketch belongs to you)
MAIN CORRECTION:
used a var found because returning from the forEach callback doesn't make you leave the findFood function, but the callback one. And the forEach loop doesn't stop. Using this var prevents the further forEach tests to be made and allows you to return from findFood so that no further move is made after seeing food.
noise is now applied to a value of 4 and I subtract 2, so that x and y now change with a range of -2 to 2 each. Of course, with this method, you need to check against world dimentions or else the rabbit could leave the world. The seed increment has been changed too or else it would vary too slowly (adapt values as you wish)
findFood(){
var thisRabbit = this, found = false;
_world.food.forEach(f => {
if(!found){
let d = int(dist(f[0], f[1], thisRabbit.x, thisRabbit.y));
if(d < (thisRabbit.genes.vision / 2)+3){
thisRabbit.state = "foundFood";
this.acquiredFood = f;
found = true;
}
}
});
if(found){ return; }
thisRabbit.x += (noise(thisRabbit.t) * 4) - 2;
if(thisRabbit.x < 0){ thisRabbit.x = 0; }
if(thisRabbit.x > _world.width){ thisRabbit.x = _world.width; }
thisRabbit.y += (noise(thisRabbit.t + 5) * 4) - 2;
if(thisRabbit.y < 0){ thisRabbit.y = 0; }
if(thisRabbit.y > _world.height){ thisRabbit.y = _world.height; }
thisRabbit.t += 0.01;
}
SYNTAX ERRORS:
lines 23 / 24: assignment should be with a value (null or false)
this.genes = null;
this.acquiredFood = null;
lines 129 to 133: end you instructions with a ; instead of a ,
this.width = w;
this.height = h;
this.foodDensity = foodDensity;
this.food = [];
this.rabits = [];
line 156 to 160: there should be no space between rabbit and .t. Additionnally, because the coordinates are not directly linked to t, I would prefer to use random for starting position:
let x = this.width * random();
let y = this.height * random();
let _rabbit = new rabbit(x, y);
_rabbit.genes = genes;
_rabbit.t = t;
I've gotten pretty far but something just doesn't seem to work.
A = 50.88259382849774,6.003988087177277
B = 50.88269282423443,6.0036662220954895
C = 50.882530369581545,6.003847271203995
The C coordinate is a little off from the 90 degree line (x) and this function I made should position C on the closest way to the x line.
this.snapCoords = function(a, b, c){
var result = (b.x-a.x)*(c.x-b.x)+(b.y-a.y)*(c.y-b.y);
var negative = false;
if(result < 0){
result = result*-1;
negative = true;
}
result = Math.sqrt(result);
result = result/2;
if(negative === false){
var d = {x: c.x+result, y: c.y-result};
}
else{
var d = {x: c.x-result, y: c.y+result};
}
console.log(d); // returns : 50.88246729610898,6.003910344676565
}
It does get the the 90 degree (x) line but not the closest way. Something must still be wrong in my function but I can't figure it out.
EDIT:
So this is my problem
My function puts the third coordinate on C which is 90 degrees but not where it should be (the red spot) it somehow extends to a further point.
I think the OP is trying to project the point C onto the line passing thru point B and is perpendicular to line AB. If this is the case, the math for the projection is not correct. You can find the projected point D as
D= C - dot(vec(BC), vec(AB)) * vec(AB)/|vec(AB)|^2
By this calculation, the projected point D will be (50.8825952820492, 6.00363622113846).
The following is a picture for points A, B, C and D :
The problem is currently solved. In case some one wants to see the colored fractal, the code is here.
Here is the previous problem:
Nonetheless the algorithm is straight forward, I seems to have a small error (some fractals are drawing correctly and some are not). You can quickly check it in jsFiddle that c = -1, 1/4 the fractal is drawing correctly but if I will take c = i; the image is totally wrong.
Here is implementation.
HTML
<canvas id="a" width="400" height="400"></canvas>
JS
function point(pos, canvas){
canvas.fillRect(pos[0], pos[1], 1, 1); // there is no drawpoint in JS, so I simulate it
}
function conversion(x, y, width, R){ // transformation from canvas coordinates to XY plane
var m = R / width;
var x1 = m * (2 * x - width);
var y2 = m * (width - 2 * y);
return [x1, y2];
}
function f(z, c){ // calculate the value of the function with complex arguments.
return [z[0]*z[0] - z[1] * z[1] + c[0], 2 * z[0] * z[1] + c[1]];
}
function abs(z){ // absolute value of a complex number
return Math.sqrt(z[0]*z[0] + z[1]*z[1]);
}
function init(){
var length = 400,
width = 400,
c = [-1, 0], // all complex number are in the form of [x, y] which means x + i*y
maxIterate = 100,
R = (1 + Math.sqrt(1+4*abs(c))) / 2,
z;
var canvas = document.getElementById('a').getContext("2d");
var flag;
for (var x = 0; x < width; x++){
for (var y = 0; y < length; y++){ // for every point in the canvas plane
flag = true;
z = conversion(x, y, width, R); // convert it to XY plane
for (var i = 0; i < maxIterate; i++){ // I know I can change it to while and remove this flag.
z = f(z, c);
if (abs(z) > R){ // if during every one of the iterations we have value bigger then R, do not draw this point.
flag = false;
break;
}
}
// if the
if (flag) point([x, y], canvas);
}
}
}
Also it took me few minutes to write it, I spent much more time trying to find why does not it work for all the cases. Any idea where I screwed up?
Good news! (or bad news)
You're implementation is completely. correct. Unfortunately, with c = [0, 1], the Julia set has very few points. I believe it is measure zero (unlike say, the Mandelbrot set). So the probability of a random point being in that Julia set is 0.
If you reduce your iterations to 15 (JSFiddle), you can see the fractal. One hundred iterations is more "accurate", but as the number of iterations increase, the chance that a point on your 400 x 400 grid will be included in your fractal approximation decreases to zero.
Often, you will see the Julia fractal will multiple colors, where the color indicates how quickly it diverges (or does not diverge at all), like in this Flash demonstration. This allows the Julia fractal to be somewhat visible even in cases like c = i.
Your choices are
(1) Reduce your # of iterations, possibly depending on c.
(2) Increase the size of your sampling (and your canvas), possibly depending on c.
(3) Color the points of your canvas according to the iteration # at which R was exceeded.
The last option will give you the most robust result.
I am having trouble understanding a function hopefully someone can help me out here. I am trying to find the pitch diameter of a sprocket the function for this in JavaScript is:
function sprocket_diam(dataform,pitch,teeth)
{
var a,b,c,d,e;
a = pitch / 2;
b = teeth * 2;
c = 360 / b;
d = Math.sin ((c * Math.PI) / 180);
e = (a / d) * 2
dataform.diam.value = e;
}
The above function works just as intended but I am trying to do this by hand on a calculator. I think the problem I am having comes in the d variable. For example lets say I have a 15 tooth sprocket with a pitch of .5". Using the above formula the numbers for the variables I get are:
a=0.25,b=30,c=12, and for d I take (12*3.14)/180 which gives me 0.2093 so e=(0.25/.2093)*2 which ends up being 2.388915432 but is the incorrect answer it should be 2.404867172372066 Can someone point out what I am doing wrong? I have always struggled with math.
You didn't compute the sinus. (Math.sin)
Your error is that you do as if Math.PI would be 3.14.
If you use the precise value of Math.PI, you get 12*Math.PI/180 == 0.20943951023931953 instead of the 0.2093 you use and at the end you find 2.404867172372066