Get SVG path part (or split path) - svg

Input:
SVG path, may consist of Lines and Curves.
percentage length of this path (say 50% of the path)
Output:
svg path that is part of this path from beginning to a given point at length.
There is a nice method on path getPointAtLength and also getPathSegAtLength so we can get the segment at the given length, but still not clear how to "split" this segment and the path that is needed.
I wonder is there some unified solution for the problem.

As you have discovered, the SVGPathElement has methods to step through the segments of a path. You just need to step through them until you get to the one that you have to subdivide. Just be aware that those APIs are in the middle of changing. So you may need to use a polyfill for some browsers - depending on whether you choose to use the new or the old API
The only path segment type that is at all tricky to subdivide are the quadratic and cubic bezier curves. But those are actually pretty easy also, using De Casteljau's algorithm.
See: Divide bezier curve into two equal halves
That answer explains dividing a cubic bezier. However the quadratic version is very similar.

Related

How to calculate a DXF's used area in Python 3 with ezdxf or dxfgrabber?

I would like to calculate the minimum size of an rectangle that contains all elements of an DXF file, but apparently neither ezdxf or dxfgrabber have a function to do that.
Is iterating through all entities and calculating the points the only way to do it? If the drawing used only lines and boxes that would be easy, but with splines, arcs and circles the process become tiring.
I know that the context of my answer does not relate to the libraries you refer. But if you look here it mentions:
Extmin and Extmax - Returns the extents of Model space.
Pextmin and Pextmax - Returns the extents of the current Paper space layout.
Are you able to access these variables using your libraries? If not, then you most likely have to do it the manual way.

Calculating average curvature of a polygonal chain with non-uniform segment length

I'm using a polygonal chain to approximate a curve. I want to approximate the average of a function of curvature of all points that lie on the curve. One function of curvature that I need is, for example, the square of curvature.
I can get near that by choosing some points on the chain, calculating the curvature in those points, applying the function on it (for example squaring it), and then averaging the calculated values.
I need both accuracy and speed. I appreciate both — fast, but approximate; as well as accurate, but slow solutions. I'm working in Java, but the answer doesn't need to be written in Java — it doesn't even need to contain any code at all.
Polygonal chain with uniform segment length
If the polygonal chain's segments all have equal length, I can just calculate the curvature in the vertices and then average that. I see two ways to get the curvature in a vertex.
One way is to get the circle that goes through the selected vertex, the vertex before it, and the one after it. The curvature is then 1/radius of the circle.
The other way is to calculate the external angle (in radians) of the two segments connected at the selected vertex and then divide its absolute value by the length of a segment. In the following image, φ marks the external angle:
I am not sure if this method is correct, as I haven't mathematically derived it, but I've noticed through experimentation that it gives similar results to the above method.
Polygonal chain with non-uniform segment length
Unfortunately, though, there's no guarantee that the segments have uniform length.
If I try using the first of the above methods, vertices connected to longer segments give lower curvatures, even if they are visibly sharper. I tried substituting previous and next vertices with a point x units before the selected vertex and a point x units after it. I don't know what to set the x constant to, to get accurate results. All the values I've tried seemed to give inaccurate results.
If I try using the second method, I don't know what length to divide the angle by. If I don't divide by anything at all, I actually get pretty good results for comparing two curves and determining which one is curvier, but I need to be able to determine the actual curvature in a point.
With both of these methods there's also the problem that parts with shorter segments (where points are denser) will affect the average more.
Another possible solution would be to ignore the vertices and instead use an array of points on the chain that are evenly spaced, treat them as a new polygonal chain (connect the points with straight lines), and then calculate curvatures on this new chain instead, using one of the methods I mentioned under the header titled "Polygonal chain with uniform segment length".
Finding such an array of points is not trivial, though, because I have to choose a segment length, and only after producing the points, I can see if the length of the resulting chain is divisible by the chosen segment length.
If you aren't short on space, the last solution you mentioned would be the best, because the "sphere" approximation, as you've perhaps realized, would give awful results in more extreme cases, especially if the curvature is large or changes sign quickly.
There are many ways to do interpolations, the simplest being quadratic and cubic splines. However if you have more pre-processing time, Lagrange polynomials produce very good results: https://en.wikipedia.org/wiki/Lagrange_polynomial.
Side note on your angle division method, consider this diagram:
(From simple geometry the inside angle there is also theta)
For a << l. So the curvature:
So your approximation is in fact correct for small curvatures.
An alternative is to use a local parabola approximation to estimate the curvature. Basically, to estimate the curvature at point P(i), you take P(i-1), P(i) and P(i+1) and construct a parabola from these 3 points. Then, you compute the curvature at P(i) from the parabola. Remember to use chord-length (or centripetal) parametrization when constructing the parabola.

Breaking a path into 100 pixel lines

I have a path drawn in Illustrator, and I need to break the path into section of 100 px. I can't figure out the logic. A line consist of 2 points x1,y1 and x2, y2. And this is for a straight line. My line may have angles/curve, so what do I need to do, to figure out the distance between 2 pixels.Here is a graphic illustration of my line and the sections, which I need to select/extract:
From the shape above, I need to break it into section of lines(note these are not straight lines).
Try referencing the Bug Algorithm. It's a very simple intuitive approach to path planning. I've uploaded an example written in LabVIEW here, but I know there are plenty of others available.
The Bug Algorithm generates a continuous line; a lot of data points; however you can keep a running average of the general diretion it's heading in and detect sharp changes in angles as an important node in the path. This allows you to segment paths from possibly thousands of data points into just a handful.
There are two aspects in your question:
how do I break a path at some point,
how do I find points spaced by a certain distance.
To answer the first, the type of primitives that define the path matters. Assuming a sequence of Bezier cubics, you will resort to the de Casteljau's algorithm: it allows you to construct the control points that correspond to a desired section of a given Bezier arc, from the original control points. Then, a section of a path will be obtained as a starting section of an initial Bezier, then (possibly) a sequence of whole Bezier arcs, and finally the ending section of a last Bezier arc.
To answer the second, assuming that you need an accurate answer, you will need to resort to numerical integration of the arc length along the path. Refer to this post: https://math.stackexchange.com/a/1171564/65203.
For a simple approximation, you can flatten the curve (approximate it as a polyline) and compute the accumulated segment lengths (or even count the pixels if your curve renderer gives you access to this information).
This process is not trivial.

SVG Path and morphing

I have a bit of a theoretical questions.
Lets say i have 2 paths in svg. Each with a different number of points. One has 4 Bézier curves and the other 3.
What i want to do is morph one into the other.
Now, i know they have to have the same exact structure and same number of points to do so.
So, the question is, can i add "virtual points" into their paths to get the same structure and number of points, without changing the shape of the objects?
For example, taking one point in one of the paths and just adding the same point after it to increase the number of points. Or creating a Bézier curve in both paths that would actually pretend to be a line instead of a curve. Would that change the object? And if i have points on x=1 y=1 and x=4 y=4, would using this form make Bézier curve a line? (M1 1C1 1 4 4 4 4)
Figured it out. Using control points anywhere on the same line as the coordiantes transforms the Bézier into a line, also if you use the same point as both the control points, start and end coordinate you can make the curve into a point. Adding more of these points into path doesnt change the look of the object, just adds more data into the path.
http://www.petercollingridge.co.uk/book/export/html/560
Down at the cubic curves you can align the points in the described manner to get the desired result
I have a simple to use d3 plugin to animate svg path which supports different number of points, also it animates only the parts of the path which differs from original path, not the whole path.
7kb minified: https://pratyushcrd.github.io/d3-path-morphing/

How to get the outline of a stroke? [duplicate]

This question already has answers here:
svg: generate 'outline path'
(2 answers)
Closed 5 years ago.
I want to convert a stroked path to a filled object. (Programmatically, in JavaScript.)
The line is just a simple curved line, a sequence of coordinates. I can render this line as a path, and give it a stroke of a certain thickness... but I'm trying to get a filled shape rather than a stroked line, so that I can do further modifications on it, such as warping it, so the resulting 'stroke' might vary in thickness or have custom bits cut out of it (neither of these things are possible with a real SVG stroke, as far as I can tell).
So I'm trying to manually 'thicken' a line into a solid shape. I can't find any function that does this – I've looked through the docs of D3.js and Raphaël, but no luck. Does anyone know of a library/function that would do this?
Or, even better: if someone could explain to me the geometry theory about how I would do this task manually, by taking the list of line coordinates I have and working out a new path that effectively 'strokes' it, that would be amazing. To put it another way, what does the browser do when you tell it to stroke a path – how does it work out what shape the stroke should be?
There has been a similar question recently:
svg: generate 'outline path'
All in all, this is a non-trivial task. As mentioned in my answer to the linked question, PostScript has a command for generating paths that produce basically the same output as a stroke, called strokepath. If you look at what Ghostscript spits out when you run the code I posted at the linked question, it's pretty ugly. And even Inkscape doesn't really do a good job. I just tried Path => Outline stroke in Inkscape (I think that's what the English captions should say), and what came out didn't really look the same as the stroked path.
The "simplest" case would be if you only have non-self-intersecting polylines, polygons or paths that don't contain curves because in general, you can't draw exact "parallel" Bézier curves to the right and the left of a non-trivial Bézier curve that would delimit the stroked area - it's mathematically non-existent. So you would have to approximate it one way or the other. For straight line segments, the exact solution can be found comparatively easily.
The classic way of rendering vector paths with curves/arcs in them is to approximate everything with a polyline that is sufficiently smooth. De Casteljau's Algorithm is typically used for turning Bézier curves into line segments. (That's also basically what comes out when you use the strokepath command in Ghostscript.) You can then find delimiting parallel line segments, but have to join them correctly, using the appropriate linejoin and miterlimit rules. Of course, don't forget the linecaps.
I thought that self-intersecting paths might be tricky because you might get hollow areas inside the path, i.e. the "crossing area" of a black path might become white. This might not be an issue for open paths when using nonzero winding rule, but I'd be cautious about this. For closed paths, you probably need the two "delimiting" paths to run in opposite orientation. But I'm not sure right now whether this really covers all the potential pitfalls.
Sorry if I cause a lot of confusion with this and maybe am not of much help.
This page has a fairly good tutorial on bezier curves in general with a nice section on offset curves.
http://pomax.github.io/bezierinfo/
A less precise but possibly faster method can be found here.
http://seant23.wordpress.com/2010/11/12/offset-bezier-curves/
There is no mathematical answer, because the curve parallel to a bezier curve is not generally a bezier curve. Most methods have degenerate cases, especially when dealing with a series of curves.
Think of a simple curve as one with no trouble spots. No cusps, no loops, no inflections, and ideally a strictly increasing curvature. Chop up all the starting curves into these simple curves. Find all the offset curves of these simple curves. Put all the offset curves back together dealing with gaps and intersections. Quadratic curves are much more tractable if you have the option to work with them.
I think most browsers do something similar to processingjs, as they have degenerate cases even with quadratic curves. For example, look at the curve 200,300 719,301 500,300 with a thickness of 100 or more.
The standard method is the Tiller-Hanson algorithm (Offsets of Two-Dimensional Profiles, 1984, which irritatingly is not on line for free) which creates a good approximation. The idea is that because the control points of each Bezier curve lie on lines tangent to the start and end of the curve, a parallel curve will have the same property. So we offset the start and the end of the curve, then find new control points using these intersections. However, that gives very bad results for sharp curves, so the first step is to bisect the original curve, which is very easy to do to Bezier curves, until it turns through a sufficiently small angle.
Other refinements are needed to deal with (i) intersections between the parallels, on the inside of each vertex; (ii) inserting an arc of a circle to fill the gap on the outside of each vertex; and (iii) adding end-caps - square, butt or circular.
Tiller-Hanson is difficult to implement, but there's a good open-source implementation in the FreeType library, in ftstroke.c (http://git.savannah.gnu.org/cgit/freetype/freetype2.git/tree/src/base/ftstroke.c).
I'm sorry to say that it can be quite difficult to integrate this code, but I have used it successfully, and it works well.

Resources