TinyVG / specification

The specification for TinyVG. This is the central authority for the file system
https://tinyvg.tech/
MIT License
239 stars 6 forks source link

[Proposal] Add dashed lines #16

Open neinseg opened 2 years ago

neinseg commented 2 years ago

Dashed (or dotted) lines are a great feature in SVG that I often use. Given that their rendering is reasonably simple to implement, and that emulating them with multiple paths would cause a significant file size increase, I think they would be a good addition to TinyVG.

ikskuh commented 2 years ago

I wonder how i would implement them in my renderer (which uses a signed distance function for lines)

Which line caps would the dashes/dots have?

neinseg commented 2 years ago

Which line caps would the dashes/dots have?

In SVG, per spec dashes are basically just a shorthand for drawing a number of individual paths. The algorithm is described at https://www.w3.org/TR/SVG2/painting.html#StrokeShape This means that according to spec dashes use the stroke's end caps.

I wonder how i would implement them in my renderer (which uses a signed distance function for lines)

They aren't too bad to render. In svg-flatten I take the starting point of the path, then I add segments as long as the resulting partial path is shorter than the dash. The next segment is one overlapping the end of the dash, so I split that where the dash ends. For illustration:

   dashes: ==========          ==========          ==========          ==========
  egments: [1][2][  3  ][    4    ][5][    6   ][     7     ][    8   ][  10  ]
new paths: [1][2][ 3]          [4 ][5][6]          [   7    ]          [  10  ]
discarded:           [3][  4  ]          [  6  ][7]          [    8   ]

Draw the resulting new paths individually, discard the gaps. The only hard thing here is that you need both forward and inverse arc length functions. While trivial for straight lines and easy for circular arcs, this is a bit finicky for cubic beziers. It comes built-in to many graphics libraries, though. This arc length function should be decent, since errors accumulate. If a long path consisting of long or many short cubic beziers is dashed that way using short dashes, errors can build up to a point where the results are visually obvious in a side-by-side comparison since towards the end of the path, dashes can accumulate a significant offset. However I'd say that that kind of rendering artifact is to be expected, and should rarely matter in practice. I have attached an example file that shows this difference, along with renders from Inkscape and Firefox.

Inkscape Firefox dashes-test.svg.tar.gz (because Github doesn't like SVG)

Here's a nice post on the maths: https://tacodewolff.nl/posts/20190525-arc-length/

ikskuh commented 2 years ago

Dashed lines are still under consideration, need to think some more about it. Tempted to accept them though, as they are a really useful feature for technical drawings.

ikskuh commented 2 years ago

I got a really nice idea on encoding right now: The encoding for the dashed lines consists of a single byte pattern as well as a length unit for pattern length.

With this, 256 different line patterns can be encode via the bit sequence:

11110000    ────    ────    ────
11001100    ──  ──  ──  ──  ──  ──
11001111    ──  ──────  ──────  ────
10101010    ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
11100100    ───  ─  ───  ─  ───  ─
11111111    ────────────────────────
10000000    ─       ─       ─
11000000    ──      ──      ──
11100000    ───     ───     ───
11111110    ─────── ─────── ───────
...

This should allow a lot of nice patterns for lines while being encoded reasonable small (only 3 additional bytes + 1 flag bit)

By duplicating all line drawing commans into "draw lines, draw dashed lines" we can save a lot of encoding space