I know there are already libraries for drawing a circle in JavaScript but I wanted to know how the actual maths of it works. Unfortunately there is no MathOverflow and I would of thought that with the number of programmers that are active here, someone will know what formula or concepts I need to use.
Actually, there is a 'math overflow': https://math.stackexchange.com/
However, the formula you need to use is along these lines.
x = radius*Math.cos(angle) + centerX;
y = radius*Math.sin(angle) + centerY;
Related
I'm putting together a p5 sketch with little wiggling snakes that move randomly across the screen.
Unfortunately, the tail keeps catching up to the head every time it does a sharpish turn.
Here is the function I'm using to calculate the move, I've tried with a few different ways of calculating the speed, fixed numbers, relative to the snake's length.
It's supposed to work by moving the snakes head (points[3]) in a semi-random direction and then having each body point move towards the one before it by the same amount. This isn't working, and I feel there's something wrong with my algorithm itself. I'm not familiar with these kinds of intermediate random-walks, so I've just been going by guesswork for the most part.
this["moveCurve"] = function() {
let newDir = this["oldDir"] + (random() - 1/2)*PI/6;
let velocity = createVector(1,0);
velocity.setMag(5);
velocity.setHeading(newDir);
this["points"][3].add(velocity);
for (let i = 2; i >= 0; i--) {
this["points"][i].add(p5.Vector.sub(this["points"][i + 1],this["points"][i]).setMag(5));
}
this["oldDir"] = newDir;
}
If you have any idea what I could do to make this work properly, I'd love to hear your advice. Thanks!
This does look like an algorithmic issue / not a bug with how you implemented it.
Here's my go at explaining why the gap between two points must decrease in this algorithm:
Let's consider just a two point snake, with two points Hi (head) and Ti (tail) at an initial locations Hi: (20, 0), and Ti: (0, 0). So, the heading here is 0 radians.
What happens when moveCurve is called? A new heading is chosen (let's use PI/2, a right angle to make it easy to imagine) and using a fixed velocity of 5 we calculate a new position for the head of (20, 5), let's call it Hf. T also moves, but it also moves toward Hf at the same 5 unit velocity, ending up at about (4.85, 1.21). The distance between these two final positions is now 15.62657, which is smaller than the initial distance.
To visualize this, think of the triangle formed between Ti, Hi, and Hf. Ti, and Hi, form the base of this triangle. Ti will move along the hypotenuse to get to Tf, while Hi will move along the other side. The directions they are moving in form an angle which is smaller than PI radians and both points are moving at the same speed so intuitively the points must be getting closer together.
So how to solve this? Well if we consider our tiny snake's movement, the tail moved in a decent direction but too far. One solution might be to scale the velocity vector in order to maintain a fixed distance between points instead of using a fixed velocity. For example instead of stepping 5 units along the hypotenuse from Ti toward Hf in the example, you could step 20 units along the hypotenuse from Hf toward Ti. I'm not sure how this would work out for your snake, just an idea!
Keep slithering!
Fortunately, it turns out p5's documentation itself had the answer for me. By adapting the code from here to use p5 Vectors, I was able to get it all working.
The segLengths property is defined when the object is made, just takes the distances between all the points.
this["moveCurve"] = function() {
let newDir = this["oldDir"] + (random() - 1/2)*PI/6;
let velocity = p5.Vector.fromAngle(newDir).setMag(5);
this["points"][3].add(velocity);
for (let i = 2; i >= 0; i--) {
this["points"][i].set(p5.Vector.sub(this["points"][i+1], p5.Vector.fromAngle(p5.Vector.sub(this["points"][i+1],this["points"][i]).heading()).setMag(this["segLengths"][i])));
}
this["oldDir"] = newDir;
}
I might spend a little time trying to clean up the code a bit, it's a jot messy for my tastes at the moment. But it works.
There has been a lot of questions regarding the coördinate system of svg elements but no one has got me solving my problem.
Look at this fiddle:
https://jsfiddle.net/archemedia/4f54jnm8/
In the startup function, I added connect("A", "B") which connects element A and B with the line.
When I try to connect("A", "D") the line doesn't position correctly, due to the transform attribute of element D.
Could someone provide me with a clear solution?
I don't want to use a svg library, I just want plain javascript code which solves the problem, preferably by adding it to the fiddle.
Many thanks
Your getMid function needs to account for the transform matrix of the rectangles.
function getMid (rect, svg) {
let point = svg.createSVGPoint();
point.x = rect.x.baseVal.value + rect.width.baseVal.value / 2;
point.y = rect.y.baseVal.value + rect.height.baseVal.value / 2;
return point.matrixTransform(svg.getScreenCTM().inverse().multiply(rect.getScreenCTM()));
}
Note the new svg parameter. This is your SVGSVGElement. In the fiddle, you can grab it with document.getElementById('Laag_1').
Normally, I'd cite the relevant pages on MDN, but their SVG documentation is lacking. I had to piece this together from a couple of SO questions. The key was searching "svg get transform matrix" and following the rabbit hole from there.
This is by far the most correct and useful answer and it might server the community. I've searched a lot and got multiple workarounds with regex and custom functions, all of which didn't work. My problem is finally solved.
I updated the fiddle with the answer from AuxTaco and the getCTM() tweak suggested by jcaron. Thanks everyone!
function getMid(rect, svg){
var point = svg.createSVGPoint();
point.x = rect.x.baseVal.value + rect.width.baseVal.value / 2;
point.y = rect.y.baseVal.value + rect.height.baseVal.value / 2;
return point.matrixTransform(svg.getCTM().inverse().multiply(rect.getCTM()));
}
https://jsfiddle.net/archemedia/4f54jnm8/2/
I'm working on a project in paper.js where I need to create new paths based on the intersection, difference and union of two others. I did some digging and found the mathematical function that interpolates a cubic bezier spline, but I was wondering if there were any javascript libraries that did svg-like vector arithmetic. If anything, I'll copy inkscape's and convert it to javascript, but you never know.
Anyway, the mathematical function for interpolating cubic beziers is as follows:
Pointx = (Ax * percent^3) + (Bx * 3 * (percent^2 * (1-percent))) + (Cx * 3 * (percent * (1-percent)^2)) + (Dx * (1-percent)^3)
Pointy = (Ay * percent^3) + (By * 3 * (percent^2 * (1-percent))) + (Cy * 3 * (percent * (1-percent)^2)) + (Dy * (1-percent)^3)
Where A, B, C and D are the points for the curve. A is the start, D is the end, and B and C are the "control points" that manipulate the curvature between A and D. The percent is how far along the curve to calculate on a scale from 0 to 1.
So it would be pretty trivial coming up with an interpolation function that returns a point for a provided bezier and a percentage along the bezier. Finding the inverse - a percentage(s) for a given point (or x value or y value) would be difficult. Or even more difficult, where two beziers intersect (I'm not very good at math). I'm hoping that's what inkscape's functions provide.
Are there any javascript libraries that can do this kind of vector interpolation quickly? If not, I'll post the algorithm I come up with here.
Thank you!
What you are looking for is something called Boolean Operations on Polygons
Paper.js seems to now use fairly nice BoolOps and they deal directly with bezier curves. This should be the first choice if you ask me. Here's a nice example.
In another scenario, you could polygonize the shapes using De-Casteljau algorithm and feed them into Javascript Clipper. If you use high sampling the visual result is identical to true curves, but you lose the curvy nature of the paths.
While I wouldn't go so far as to say this is a duplicate question I believe you will find great insight from the answers to this question as it is quite similar.
I did find one other resource that is not mentioned amongst the answers to that question here:
http://13thparallel.com/archive/bezier-curves/
Other than that the best resource that was mentioned in that question is here:
http://blog.mackerron.com/2011/01/01/javascript-cubic-splines/
Both these resources detail specific functions that will do what you are looking for. While they are not quite "libraries" the code will be easily ported to your project for your purposes.
I have an old friend who is a mathematician. He has his own math to compress his formulas, which are incredibly beautiful.
He works in a program called Mathematica, which transforms the formulas for 3D-shapes.
I wonder if it is possible to obtain these figures using Canvas and JavaScript? See attached formula and figure.
I know little of this myself. But I would be delighted if some one could show me an example.
Since you mention Mathematica I'll use it to provide a few more examples for various values of t. I can't help you with canvas though.
This is the Mathematica code:
With[{a = 3, t = 0.7},
RegionPlot3D[
10^-(t x + y)^10 + 10^-(-t x + y)^10 + 10^-(t y + z)^10 +
10^-(-t y + z)^10 + 10^-(t z + x)^10 + 10^-(-t z + x)^10 >
5/2, {x, -a, a}, {y, -a, a}, {z, -a, a}, PlotPoints -> 50,
Boxed -> False, Axes -> None
]]
t=0.2
t=0.4
t=0.7
t=1
It's definitely possible. You can take a look at the javascript-surface-plot library and the working example at http://www.grvisualisation.50webs.com/javascript_surface_plot.html. It produces a 3D model from a mathematical formula that can be panned and rotated as desired.
If you look at the code for the example, there is a setup function that you would need to update to whatever formula you wanted. Just need to convert your math formula into javascript.
I'm not sure what you want to do with these models once you have one, but this library seems to fit your requirements. Doing a search for html canvas 3d plot brought up additional libraries as well.
I would think WebGL would be ideal for this. It's graphics-accelerated in the newest browsers and can render in full 3D.
Perhaps there are libraries out there that can render from functions out of the box, but it's a new technology so you may have to write much of it yourself.
You are really asking two questions:
Are there any 3D canvas libraries: YES K3D
Are there math libraries for javascript: YES discussed here
If you are doing hard core math equations (which it looks like you are), you're better off doing it in something like MatLab/Maple and dumping it in a file then using a canvas 2D library to render the image. I have a lot of 3D data and I do just that. I run a Python script which calculates the points then appends it to an html file (rememer, web pages can't read data from file, so you have to include the data as a part of your html file). Then I load the html file and display generate the image using EaselJS
I need to draw a circular arc between two given points. I also have the arc's radius. I understand that this can be done using standard canvas APIs but I need to handle the case of elliptical arcs too. This code is a generalized solution. The only problem right now is that it doesn't work!
The mathematical concept behind this code is at https://math.stackexchange.com/questions/53093/how-to-find-the-center-of-an-ellipse.
My JS code is implementation of that. My JS code can be found at http://jsfiddle.net/BkEnz/2/. Ideally both the circles there should pass through the two little pink dots.
I hope somebody can point me towards the right direction. I have been trying to solve this for past few days now!
Fixed this issue. The corrected working code is at http://jsfiddle.net/ZxRBT.
Notice the line
var t = translate(-R1R2x, -R1R2y, IDENTITY_TRANSFORM());
In my previous version of the code this line was
var t = translate(-R1R2x, -R1R2y, sr);
So when I was calculating the value of C1 and C2, using the following code
C1 = compose(vut, [[R1x],[R1y],[1]]);
C2 = compose(vut, [[R2x],[R2y],[1]]);
I was also applying the sr composition over R1x,R1y and R2x,R2y, but these points were already in sr coordinate.
This was a grave mistake which I overlooked for really a long time.