I have randomly generated some points on a JavaScript canvas I was wondering what the most efficient method would be to draw triangles connecting the points in a uniform fashion. The goal is to have the triangles fill the entire canvas without overlapping.
For a visual representation, here is an image of the points I have randomly generated across a canvas. As you can see I may have to modify the way I randomly place the points on the canvas.
And this is how I wish to draw the triangles.
Thanks to #Phorgz & #GabeRogan for pointing me in the right direction. Delaunay Triangulation was definitely the way to go and it ended up being very fast, even when updating the canvas as an animation.
I did end up using the npm package faster-delaunay which uses the divide and conquer algorithm to triangulate the randomly generated points.
Here is a result of what I have drawn on the canvas that updates as the points move around the plane:
Related
I'm trying to learn more about programmatically drawing and animating shapes using javascript. I'm trying to recreate something like this:
The base shape is a circle which I want to add series of jagged peaks and valleys of various sizes (distortion/zigzags). I also want to add some sliders with dat.GUI where I can control:
Points (number of vertices added between existing vertices in the circle. The density of jagged edges.)
Size (maximum length for segment paths.)
The speed of the animation.
It similar to how Wiggle Path in after effects works.
What is the best practice to recreate an animation like in the gif above?
Is using requestAnimationFrame and drawing on canvas a good solution because it's an "live" animation (not looping)?
Or is using a library like two.js to draw SVGs a better solution in this case?
Keep in mind that I want the animation randomly generated over time, and its a learning process where I'm looking for a starting point.
There isn't any code included in the question to address, so here's a general run-through:
The wiggle path in After Effects works by splitting each line segment into several points using interpolation.
p = p1 + (p2 - p1) * t; // t = [0, 1]
// t is a result of length / points, then each segment length / length.
Each point is assigned one or several oscillators (the more oscillators the more complex the movement, or put differently: more variations) that starts at a random angle moving the point perpendicularly to the line it sits on. For circles you can see the circle as a single line where interpolation is based on angle instead of distance.
Rotate each oscillator based on temporal phase (speed) and their radius based on spacial phase. Here Math.sin() can be used for the y-position of the point along the perpendicular line. For increased complexity you simply add more sin() together each at a different frequency. If you want to normalize the output is up to you.
Connect the points using lines, or to make it smooth like in the example gif, use for example cardinal splines which goes through the points and takes n points (disclaimer: the linked solution is MIT, author here).
If you need the shape to start as the same shape each time (like in AE) you will need to implement a custom random function so you can control the seed value at the beginning of the animation.
An alternative to use oscillators is to use Perlin / Simplex noise, but this require you to calculate much more data to obtain the same result.
If you use SVG, canvas or something else doesn't really matter as long as you understand how it works and why you're using it.
I'm looking for a way to create a svg like path from a binary image (only black and white pixels). The image itself will be a blob with irregular shape that could have holes in it.
Without holes I only need a bounding path the recreates the border of the blob. When there are holes in the blob, I'm fine with additional paths (as one path alone wont be able to recreate this, I guess). At the end I just need to know which path is the outer one and which are the holes.
I already found these:
How to add stroke/outline to transparent PNG image in JavaScript canvas
Creating a path from the edge of an image
How can I find hole in a 2D matrix?
Additionally I need the detection of holes. It doesn't really matter to me if the result is a polygon or a path. I just need the points with high enough accuracy that curves keep being curvy :)
It would be great if someone has an idea or even some further sources.
PS: I'm working with canvas and javascript (fabricJS) if this makes any difference.
Finally I successfully went with the other option as markE described (although it's a bit modified). I'm using the Marching Squares Algorithm (MSA) and the Floodfill Algorithm (FFA) to achieve this. Simplifying the resulting points is done via Douglas-Peucker Algorithm (DPA).
MAA: https://stackoverflow.com/a/25875512/2577116
FFA: http://www.williammalone.com/articles/html5-canvas-javascript-paint-bucket-tool/
DPA: https://stackoverflow.com/a/22516982/2577116
(Smoothing: https://stackoverflow.com/a/7058606/2577116)
I put everything together in this jsFiddle.
Steps:
get path object after user finished free drawing
create image from path via base64 dataURL
convert to binary image (only 0 and 255 pixel, no transparency)
apply FFA on position 0,0 with random color, save color
go to next pixel
if pixel has known floodfill color or path color (black), move on to next
otherwise floodfill with new random color, save color
move over all pixels, repeating 5.-7.
remove saved color on index 1 (it's the color surrounding the path contour (padding), so it's neither the path nor a hole)
for all other colors apply MSA and simplify resulting points (with DPA)
Either create polygons from simplified points OR ...
... smooth points and create path
add to canvas, remove input path
DONE :)
For simpler code my random color at the moment only creates shades of grey. R=G=B and A=255 allows for simpler checks. On the other hand this solution limits the contour to have max. 254 holes (256 shades of grey - path color (0) - padding color (no hole)). If one needs more it's no problem to extend the code to create random values for R, G, B and even A. Don't forget to adopt the color checks accordingly ;)
The whole algorithm may not be optimized for performance but honestly I see no need to do so at the moment. It's fast enough for my use-case. Anyway, if someone has a hint regarding optimization I'm glad to hear/read about :)
Best Option
If you drew the Blobs with your code, then the simplest & best way is to decompose each blob (and sub-blob) into it's component Bezier curves. FabricJS is open source so you can see how they create the curves -- and therefore how you can decompose the curves. The result will be a dozen or so Bezier curves that are easy to redraw or navigate. If you need help navigating Bezier Curves, see this tutorial covering Navigating along a Path.
Other Option
You will need to get the pixel information, so you will need to context.drawImage your Fabric Blob onto a native canvas and use context.getImagedata to fetch the pixel information.
Assuming:
All pixels are either white or black.
The blob is black: rgba(0,0,0,255)
Outside the blob is white: rgba(255,255,255,255)
The holes in the blob are white: rgba(255,255,255,255)
A plan to find the blob & hole paths:
Load the imageData: context.getImageData(0,0,canvas.width,canvas.height)
Find a white pixel on the perimeter of the image.
Use a FloodFill Algorithm (FFA) to replace the outer white with transparency.
Use the Marching Squares Algorithm (MSA) find the outermost blob perimeter and save that blob path.
Use a Floodfill Algorithm to fill the blob you've discovered in #4 with transparency. This makes the outer blob "invisible" to the next round of MSA. At this point you only have white holes -- everything else is transparent.
Use the Marching Squares Algorithm (MSA) find the perimeter of the next white hole and save that hole path.
Use a Floodfill algorithm to fill the white hole in #6 with transparency. This makes this hole invisible to the next round of MSA.
Repeat #6 & #7 to find each remaining white hole.
If MSA reports no pixels you're done.
For efficiency, you can repeatedly use the imageData from Step#1 in the subsequent steps. You can abandon the imageData when you have completed all the steps.
Since blobs are curves, you will find your blob paths contain many points. You might use a path point reduction algorithm to simplify those many points into fewer points.
Let's say I have a simple 2d x-y graph. I want to draw a really complicate shape centered at (5,5), (3,4) ,(-1,9), etc.
I know where the vertices of the shape will be relative to a center (n,m). Is it possible to calculate all the vertices on the GPU instead of in javascript? I would just need to upload the relationship of the vertices to the center once and then after that just the individual points.
For example if the shape was a square, the relationship would be:
At the point (n,m), there are vertices (n-1, m-1), (n+1, m-1), (n+1,m-1), (n+1, m+1).
That way I could just upload (5,5), (3,4) ,(-1,9) to the GPU instead of calculating 12 vertices and uploading.
Questions:
Is this possible?
Would this be faster than calculating the vertices in javascript?
These are some solutions for OPENGL, WebGL does not support apparently.
http://www.opengl.org/wiki/Vertex_Rendering
http://www.opengl.org/wiki/GLAPI/glDrawArraysInstanced
edit: Apparently WebGL doesn't have drawArraysInstanced
I am searching for a 2D physics engine to simulate gravity using images, preferably PNG images with transparency. So the engine will know how to calculate the collision base on the opaque parts of the image. I have only found Javascript engines that works with primitive shapes and basic HTML elements, but not with images.
I don't know any way to do what you desire, but you can try drawing your shapes in HTML5 Canvas and use Box2D.js for working with shape collision.
One think you could do is compute the convex hull of your image (you can have a look here) and then use those hulls to compute collisions and so on (using GJK for example, you can find some great explanations here or here)
As noted by micnic, I guess you can indeed use Box2D.js and feed a b2PolygonShape why the non transparent pixels of your images (or you can compute their contours and use contours as input for the b2PolygonShape)
I am still working on my "javascript 3d engine" (link inside stackoverflow).
at First, all my polygons were faces of cubes, so sorting them by average Z was working fine.
but now I've "evolved" and I want to draw my polygons (which may contain more than 4 vertices)
in the right order, namely, those who are close to the camera will be drawn last.
basically,
I know how to rotate them and "perspective"-ize them into 2D,
but don't know how to draw them in the right order.
just to clarify:
//my 3d shape = array of polygons
//polygon = array of vertices
//vertex = point with x,y,z
//rotation is around (0,0,0) and my view point is (0,0,something) I guess.
can anyone help?
p.s: some "catch phrases" I came up with, looking for the solution: z-buffering, ray casting (?!), plane equations, view vector, and so on - guess I need a simple to understand answer so that's why I asked this one. thanks.
p.s2: i don't mind too much about overlapping or intersecting polygons... so maybe the painter's algorthm indeed might be good. but: what is it exactly? how do I decide the distance of a polygon?? a polygon has many points.
The approach of sorting polygons and then drawing them bottom-to-top is called the "Painter's algorithm". Unfortunately the sorting step is in general an unsolvable problem, because it's possible for 3 polygons to overlap each other:
Thus there is not necessarily any polygon that is "on top". Alternate approaches such as using a Z buffer or BSP tree (which involves splitting polygons) don't suffer from this problem.
how do I decide the distance of a polygon?? a polygon has many points.
Painter's algorithm is the simplest to implement, but it works only in very simple cases because it assumes that there is only a single "distance" or z-value for each polygon (which you could approximate to be the average of z-values of all points in the polygon). Of course, this will produce wrong results if two polygons intersect each other.
In reality, there isn't a single distance value for a polygon -- each point on the surface of a polygon can be at a different distance from the viewer, so each point has its own "distance" or depth.
You already mentioned Z-buffering, and that is one way of doing this. I don't think you can implement this efficiently on a HTML canvas, but here's the general idea:
You need to maintain an additional canvas, the "z-buffer", where each pixel's colour represents the z-depth of the corresponding pixel on the main canvas.
To draw a polygon, you go through each point on its surface and draw only those points which are closer to the viewer than any previous objects, as indicated by the z-buffer.
I think you will have some ideas by investigating BSP tree ( binary spaces partition tree ), even if the algo will require to split some of your polygon in two.
Some example could be find here http://www.devmaster.net/articles/bsp-trees/ or by google for BSP tree. Posting some code as a reply is, in my opinion, not serious since is a complex topic.