SVG path with a blank command - svg

SVG's path defines several commands (M, m, L, l, z, etc). However I sometime see missing/blank commands, e.g.
m 0,0 20,0 0,20 -20,0 z
It would appear that no command is a line command but I can't find this documented anywhere. Is this the case?

This is documented at several places in the SVG specification
https://www.w3.org/TR/SVG11/single-page.html#paths-PathData
The command letter can be eliminated on subsequent commands if the same command is used multiple times in a row (e.g., you can drop the second "L" in "M 100 200 L 200 100 L -100 -200" and use "M 100 200 L 200 100 -100 -200" instead).
and also under the explanation of the M command:
If a moveto is followed by multiple pairs of coordinates, the subsequent pairs are treated as implicit lineto commands.

Related

What is the difference of "z" and "Z" when closing an SVG path?

When creating an SVG path, typically the capital letters (M, L...) in the d attribute refer to absolute coordinates and the lower case letters (m, l...) refer to relative coordinates to the last point.
Here's an example that draws a small right triangle in absolute coordinates:
<path style="stroke:black;fill:none;" d="M100,100 L150,100 V50 Z" />
This draws the same triangle in relative coordinates:
<path style="stroke:black;fill:none;" d="m100,100 l50,0 v-50 z" />
I can use a capital or lowercase M and Z in either case and visually, nothing is changed. Regarding M, I assume that since it is the first point, it is absolute or relative to (0, 0), but please correct me if that is wrong. What is the difference of z and Z?
In all cases:
An upper-case command specifies absolute coordinates, while a lower-case command specifies coordinates relative to the current position. path_commands
But in the case of z/Z, there is no difference (ClosePath). There is no absolute or relative coordinate associated with the z/Z, so it will just create a straight line between the last point and the starting point.
Both z and Z define the Path Command: ClosePath
Path commands are instructions that define a path to be drawn. Each command is composed of a command letter and numbers that represent the command parameters.
SVG defines 6 types of path commands, for a total of 20 commands:
MoveTo: M, m
LineTo: L, l, H, h, V, v
Cubic Bézier Curve: C, c, S, s
Quadratic Bézier Curve: Q, q, T, t
Elliptical Arc Curve: A, a
ClosePath: Z, z

SVG : Confusion about relative path coordinates

I'm trying to cut up a long SVG path generated by inkscape into several smaller paths. Specifically, I am cutting up this path:
"m 42.333333,13.895833 c 0,21.166668 21.166666,19.843751 21.166666,19.843751 h 9.260417 c 0,0 19.84375,-11.906251 13.229166,7.9375 -6.614583,19.84375 -13.229166,31.75 -33.072916,21.166667 C 33.072916,52.260417 31.75,13.895833 31.75,13.895833"
The output I generate at the moment are the following paths:
"M 42.333333,13.895833 c 0,21.166668 21.166666,19.843751 21.166666,19.843751"
"M 63.499999,33.739584 l 9.260417,0"
"M 72.760416,33.739584 c 0,0 19.84375,-11.906251 13.229166,7.9375 -6.614583,19.84375 -13.229166,31.75 -33.072916,21.166667"
"M 39.6875,54.906251 c -6.61458400000001,-2.645834 -7.93750000000001,-41.010418 -7.93750000000001,-41.010418"
This is not correct. You can see the difference between input and output here.
As you can see, almost all points are correct, except that the fourth path of the output does not start at the same point that the corresponding part of the original path does. This is probably caused by some error in my understanding of how SVG path coordinates exactly work.
I arrived at the starting point (39.6875,54.906251) for the fourth path as follows:
We start at (42.33333,13.895833). We then curve to relative position (21.166666,19.843751), so that gives us absolute position (42.33333+21.166666,13.895833+19.843751) = (63.499996,33.739584).
The path is then extended with a horizontal line with relative x coordinate 9.260417. So that gives new absolute position (63.499996 + 9.260417, 33.739584 + 0 ) = (72.760413,33.739584). We then curve to relative position (-33.072916,21.166667). Giving the start position for the fourth path as (72.760413-33.072916,33.739584+21.166667) = (39.6875,54.906251) (with some rounding).
Why is this wrong?
I figured it out myself.
The problem was caused due to the third curve actually being a polybezier consisting of 2 cubic curves. The coordinates of that second cubic bezier should be relative to its starting point, rather than the starting point of the complete polybezier.

SVG Move Command: Relative Path

I'm trying to understand the SVG Path commands. However I am confused by the statement made regarding the Move command in the SVG Path reference
The SVG path reference states the following for Move command
M (uppercase) indicates that absolute coordinates will follow;
So if the current point is say (100, 100), then the command M 200 200 would move the current point to (200, 200).
m (lowercase) indicates that relative coordinates will follow.
So if the current point is say (100, 100), then the command m 200 200 would move the current point to (300, 300).
If a moveto is followed by multiple pairs of coordinates, the subsequent pairs are treated as implicit lineto commands. Hence, implicit lineto commands will be relative if the moveto is relative, and absolute if the moveto is absolute.
So if the current point is (100, 100), then the command M 200 200 300 300 400 300 will first move the current point to (200,200) then draw a line to (300,300) followed by line to 400, 400.
Whereas if the current point is (100, 100), then the command m 200 200 300 300 400 400 will first move the current point to (300,300) then draw a line to (600,600) followed by line to 1000, 1000.
Now here comes the confusing part
"If a relative moveto (m) appears as the first element of the path, then it is treated as a pair of absolute coordinates. In this case, subsequent pairs of coordinates are treated as relative even though the initial moveto is interpreted as an absolute moveto."
Based on the above statement, in the previous scenario where the current point is (100, 100) then the command m 200 200 300 300 400 400 should have moved the current point to (200,200) then draw a line to (500,500) followed by line to 900, 900.
Is my understanding correct? What does the last statement really indicate?
Based on the above statement, in the previous scenario where the
current point is (100, 100) then the command m 200 200 300 300 400
400 should have moved the current point to (200,200) then draw a line
to (500,500) followed by line to 900, 900.
Is my understanding correct? What does the last statement really
indicate?
No. The current point cannot be 100,100 to invoke that. It's a bit confusing from how it's described but when that contingency comes about the current point is 0,0 the origin. Where both absolute and relative points have the same effect.
If you initialize x and y at first to be 0,0 then everything else will work itself out.

Confused by this SVG path data

The svg path for a file created in Inkscape is the following --
d="m 1.2499932,903.60456 0,146.50004 197.7500068,0 0,-146.50004 -197.7500068,0 z m 166.9375068,29.0625 0.75,88.62504 -3.53125,3.5312 -82.312507,0.25 -3.28125,-2.75 0.25,-82.09374 -12.625,0 -2.28125,5.8125 -43.9375,-0.25 c -4.90662,-3.46937 -0.70544,-8.07521 5.03125,-12.875 l 141.937507,-0.25 z"
I usually see an L, H, V, C, S, Q, T, or A command following the x,y position after the initial m command. In this case there are 5 x,y positions following the m command before the next command. This breaks my parsing code. I don't understand the role of the extra four positions.
All pairs of co-ordinates after the initial pair are treated as implicit lineto commands i.e. as if they were preceded by an l (or an L if the inital command was an M).

How to create a gerund from an array in J?

In J, we can use "_ to produce a constant function:
k100 =. 100"_
k200 =. 200"_
These can be used in a gerund with other verbs:
(+:`k100`k200`-:)`:0 [ 256
512 100 200 128
How can I create a gerund directly from an array?
That is, I want to define k so that it produces a gerund of constant verbs, like so:
gk =: k 100 200 NB. (or '100 200 k' if it needs to be an adverb.)
gk#.(0)''
100
gk#.(1)''
200
I agree with #eelvex that this smells like an XY Problem. Using your example, can you give us a use-case for why you'd prefer to write
gk =: k 100 200 300
gk#.0''
100
gk#.1''
200
instead of
GK =: 100 200 300
0 { GK
100
1 { GK
200
or even
100*1+ 0
100
100*1+ 1
200
etc?
In general, using a conjunction (#.) instead of a verb ({) limits your run-time flexibility as well as increases code complexity, so typically you'd prefer the latter to the former, if you can get it.
Conjunctions are really only required if you want to produce non-noun results (i.e. verbs or other conjunctions or adverbs) or if you need their higher binding power, but in your case, since you're taking a noun as input and simply generating its elements as output, I don't see the need for the conjunction, or a reason to pay the complexity tax. Taking a noun (array) and producing a noun result is the raison d'etre of verbs and single most common construction in J code.
With all that said, it's not difficult to write k.
k=:[^:(__-:])L:_ 0" _1 0&({. __"_`'')
Here, we take a sample gerund (noun form of constant verb) as a template, then replace the blank (the __) with the value we want our constant function to produce. Basically, we make one copy of __"_ for each item of our array, and replace the __ with that item. So 100 200 300 becomes (100"_)`(200"_)`(300"_):
gk=:k 100 200 300
gk#.0 ''
100
gk#.1 ''
200
But again, I would not recommend this approach unless either the problem you're facing can't be solved with a simple verb, such as {&100 200 300 or (100 * 1 + ]), or the gains of using the gerund approach more than offset the costs in terms of flexibility, complexity, and clarity.
If you describe your specific problem in more detail, we can help you weigh these choices.
Something like this might work (build the string and ". it):
k =: [: ". [: ([,'`',])/('(' , '"_)' ,~ ":)"0
gk =: k 100 200 300
gk #. (2)''
300
k is actually (". f/g"0 y), where f/g"0 y just builds the string (num1"_)`(num2"_)`...from y =: num1, num2, ....
There will be other ways too.

Resources