Random enclosing path with dots on path - javascript

I would like to generate a SVG/canvas using JavaScript that contains an enclosing path (a line that starts and ends at the same place) with random number of points that should be equidistant from each other (on the path, not in terms of space).
What library can be used to achieve this effect and if possible, can an example be provided?
Angela

For SVG you can use the Snap library and in particular use the getPointAtLength method to get equidistant points along a path.
http://snapsvg.io/docs/#Snap.path.getPointAtLength
In html Canvas a path can be any combination of line segments and curves (quadratic & cubic Bezier curves). Therefore to plot equidistant points on a path you must mathematically interpolate along each line segment and curve using the appropriate formulae.
For line segments this usually involves calculating the length of the line segment and then "lerping" (Google!) using your specified distance.
For curves this usually involves using the equations for the curve and plotting numerous points along that line. Then connect those points with line segments and again "lerping" along those segments at your specified distance.

Related

How can picture of page be straightened out to look as if it was scanned?

I have seen apps, and wondered how can I programmatically take a picture of image. Define how it needs to be transformed so that it looks parallel to camera and not skewed perspective wise.
Then combine multiple photos to create a pdf file. For example this app does it: https://play.google.com/store/apps/details?id=com.appxy.tinyscan&hl=en
I do not use books for such trivial things so sorry I can not recommend any (especially in English). What you need to do is this:
input image
find main contours
ideally whole grid but even outer contour will suffice (in case no grid is present). You need to divide the contour into horizontal (Red) and vertical (Green) curves (or set of points).
sample contour curves by 4 "equidistant" points
as the image is distorted (not just rotated) then we need to use at least bi-cubic interpolation. For that we need 16 points (Aqua) per patch.
add mirror points to cover whole grid
on the image are mirrored (Yellow) points only for horizontal contours you should do this also for vertical contours (did not fit me in the image and did not want to enlarge resolution just for that) and also for the corner points so you got 6x6 control points. The mirror can be done linearly (like I did).
Now the transformation is done like this:
Process all pixels dst(x0,y0) of target image
Handle x,y as parameter for cubic interpolation
if xs,ys is target image resolution then:
u=(3.0*x)/xs
v=(3.0*y)/ys
Now cubic interpolation is usually done on parameter t=<0.0,1.0) so
if u=<0.0,1.0> use t=u and control points 0,1,2,3.
if u=<1.0,2.0) use t=u-1.0 and control points 1,2,3,4
if u=<2.0,3.0> use t=u-2.0 and control points 2,3,4,5
The same goes for vertical contours and v. Compute xi,yi as bi cubic interpolation of (u,v). And copy pixel:
dst(x,y)=src(xi,yi);
This is just nearest neighbor but you can also use bilinear for this ... As cubic curve I would use this polynomial.
The idea behind bi-cubic interpolation is easy. compute point corresponding to parameter u on 4 horizontal contours. That will give you 4 control points for the final cubic interpolation in vertical direction and v as parameter. Resulting coordinate is your source pixel position.
For more info see:
How can i produce multi point linear interpolation?
Bicubic interpolation
OpenCV Birdseye view without loss of data
In case you do not have a grid use any info that can be used as one. For example lines of text can be considered a contour for this ...

Find tangent of path in d3.js

I'd like to position svg elements (say, ellipses) along a path, for instance a curve generated with a d3.js line generator with B-spline interpolation. While finding the coordinates of points along the path is easy using path.getPointAtLength(), I can't figure out how to find the tangent of any point on the line. If I could get the tangent (or the derivative), I would be able to rotate the elements accordingly to make them look as if they are positioned along the line.
Call path.getPointAtLength() at two points close together. Calculus tells us the difference is the slope/tangent at that point.

How to reduce the number of points in bezier curve paths

I have a large svg path which has quadratice bezier curves.
The path data is used for drawing maps.
How to reduce the number of points of the bezier curve without distorting the overall shape?
You don't say whether you want to do this offline (pre-prepared paths) or online (on the fly). If offline is fine, use a tool like Inkscape.
If you want to calculate the simplified curve yourself, then the typical algorithm used to do this is also the same one that has been used for drawing bezier curves. The algorithm is called "flattening".
Basically the idea is to convert the bezier curves to a series of straight line segments. Because you don't want the the flatness of the line segments to be visible, you have to take into account the scale of the drawing and how curvy the bezier is. If the bezier is very curvy you have to use more line segments than if it is fairly straight.
What you typically do is divide each bezier into two using De Casteljau's algorithm. Then look at each of the two half bezier curves. If a bezier is straight enough to meet a flatness limit you decide on, then stop dividing. Otherwise, divide in half and try again.
At the end of the process you should get a polyline that is indistinguishable from the bezier version. Or if you use a "flatness test" that is a bit courser than that, you will get a rougher approximation of the shape. In your case a map.
If you google bezier flattening you can find a number of papers on the technique. And a few pages which describe how to do it in a more friendly accessible way. For example this one, which is about generating offset curves, but starts out by describing how to flatten a curve:
https://seant23.wordpress.com/2010/11/12/offset-bezier-curves/

Continuously changing bundle coloring in D3 bundle layout

Aloha,
is there any possibility to make the bundles in this visualization:
... look just like the bundles in that visualization
?
I have no idea how to achieve this in d3.
EDIT 1:
Obviously I have to write a custom interpolator. How can I extend the bundle interpolator to additionally interpolate between two colors without changing the d3 library?
Unfortunately, neither SVG or Canvas support stroking a gradient along a path. The way that my dependency tree visualization is implemented is as follows. For each path:
Start with a basis spline (see Hierarchical Edge Bundling).
Convert to a piecewise cubic Bézier curve (see BasisSpline.segments).
Convert to a piecewise linear curve (i.e., polyline; see Path.flatten).
Split into equal-length linear segments (see Path.split).
Once you have these linear segments, you color each segment by computing the appropriate color along the gradient. So, the first segment is drawn green, the last segment is drawn red, and the intermediate segments are drawn with a color somewhere in-between. It might be possible to combine steps 2-4 by sampling the basis spline at equidistant points, but that will require more math.
My dependency tree is implemented in Canvas, but you could achieve the same effect in SVG by creating separate path elements (or line elements) for each segment of constant color. You might get slightly better performance by combining segments of the same color.

Plotting mathematical functions without rendering artefacts

I don't think there's a good answer to this, but I'd like to find out if there's a better way to do this.
I need to plot a mathematical function, which is nearly flat at one end of the display, and nearly vertical at the other end. The bottom left quadrant of a circle would be a good model. I can auto-generate as many points as required.
The problem is, I can't do this without all sorts of artefacts.
I haven't tried Bezier fitting; I don't think this would be even close. My understanding is that Bezier is for one-off manually-constructed pretty graphics, and not for real curve-fitting.
That leaves polylines. There are only 2 things I can do with polylines - I can select the line length (in other words, the number of points I auto-generate), and I can disable anti-aliasing (setAttributeNS(null, "shape-rendering", "crisp-edges").
If I generate lots of points, then I get jaggies everywhere, and the result is unusable. It can also look very much like it's oscillating, which makes it appear that I've incorrectly calculated the function. The anti-aliasing doesn't make any difference, since it doesn't operate across point boundaries.
The only solution I've got is to draw fewer points, so that it's obvious that I'm drawing segments. It's no longer smooth, but at least there are no jaggies or oscillation. I draw this with the default anti-aliasing.
Any ideas?
Edit:
It seems like the only answer to this is actually Bezier curve fitting. You have to preprocess to find the parameters of the required segments, and then plot the results. Google comes up with a number of hits on curve fitting with Beziers.
You have the mathematical function, and can therefore generate as many points as you need.
I assume the problem is that because you do not know the output resolution (SVG is device independent) you do not know how many points to generate. Otherwise you could just create a polyline where each line is approximately 1 pixel long.
Fitting your mathematical function to a bezier curve is (probably) not going to get a perfect match - just like a circle cannot be matched perfectly by a cubic bezier curve. And I think the task of fitting your function to a bezier curve would not be trivial (I've never done this).
Could you rather output your mathematical function to a canvas element? Then you could write some javascript code to plot your mathematical function dependant on the output resolution. Similar to how a graphics system renders a Bezier curve.
Do you know how graphics systems render Bezier curves? They approximate the bezier curve with a polyline, and then measure the error difference between the polyline and the bezier curve. If the difference is greater than a certain tolerance - where the tolerance is determined by the output resolution - the bezier is subdivided and the process repeated for each bezier curve. When the difference between beziers and polylines is below the tolerance, the polylines are drawn. http://en.wikipedia.org/wiki/B%C3%A9zier_curve#Computer_graphics
I suppose you want to draw y=f(x) over a certain interval [a,b]
A classical solution is to take N points uniformly distributed over [a,b], to compute f over these points and draw lines (or polynoms).
It of course doesn't work in your case, since y is nearly vertical in certain area. But why don't you take more points in these areas (and less points where the function is nearly horizontal) ?
You can compute the derivative of your function (or approximate this derivative with (f(x+h)-f(x))/h and h small) and determine the step between two successive points with this derivative

Categories

Resources