svg-cg / projects

Discussion of project proposals & report publication requests for the SVG community group
2 stars 0 forks source link

Add Polar coordinate syntaxe to path data #2

Open JeremiePat opened 5 years ago

JeremiePat commented 5 years ago

Hi Community group,

Along my recent use of SVG, I feel more en more uncomfortable with SVG not having a polar coordinate system in addition to the current Cartesian coordinate system. Polar coordinates are amazingly useful to create regular shapes like euclidean polygons, organic shapes like flowers/trees or when handling some cartography use-cases such as polar maps.

It is pretty straight forward (not to said trivial) to convert from one system to the other and many libs exist to handle that (some examples: JS, Rust…)

I would suggest to extend the syntax of path to support polar coordinates. As both 2D Cartesian and polar coordinates are tuples of 2 numbers ([x/y] for Cartesian, [theta/distance] for polar with theta express in degrees) I would love to have a simple modifier to the current syntax of path command. My personal preference would be to add the support for parenthesis inside path syntax to identify tuple of coordinates that are polar coordinates (as an easy short cut for developer, parentheses could also be allowed to wrap several tuple at the same time).

For example:

Cartesian Polar
M10,10 M(45,14.14)
M10,10 0,10 m(45,14.14 90,10) same as m(45,14.14) (90,10)
m10,10 10,10 m(45,14.14 45,14.14) same as m(45,14.14) (45,14.14)
A5,5 0,0,0 10,10 A(5,5 0,0,0 45,14.14) same as A5,5 0,0,0 (45,14.14)

Also mixed tuples should be okay: m10,10 10,10= m10,10 (45,14.14) = m(45,14.14) 10,10 = m(45,14.14 45,14.14) = m(45,14.14) (45,14.14)

Okay, what about syntax error. I would be in favor of having some fallback rules rather than just discarding all or part of the path in case of error with the parenthesis (either matching issues or misplacement)

Here are some possible fallback rules in case of error or ambiguous syntax

Wrong Various suggested fix at parsing (my own preference in bold)
1 M(45,14.14 l10,10 l10,10 M(45,14.14) l10,10 l10,10 or M(45,14.14) l(10,10) l(10,10)
2 M45,14.14 l10,10) l10,10 M45,14.14 l(10,10) l10,10 or M(45,14.14) l(10,10) l10,10
3 M(45,14.14 l10,10 l10,10) M(45,14.14) l10,10 l(10,10) or M(45,14.14) l(10,10) l(10,10)
4 M45(14.14) l10,10 l10,10 M45 14.14 l10,10 l10,10 (Not a valid tuple, just ignore the parenthesis)
5 M45 (14.14 10) 10 M45 14.14 10 10 (Still not a valid tuple, just ignore the parenthesis)
6 M45 (14.14 10 10) M45 14.14 10 10 or M45 14.14 (10 10)

Such syntax error can be handled either at a global level or at tuple/command level. My own preference is to handle that at the tuple/command level. I think it should ease parsing if it's handle at that level (but I'm far from a parser expert). However from my point of view it's more an author concern as it's clearer at which level things operate when they handle path either "by hand" or programmatically.

Let me know it is worth of interest and/or if you have other ideas on how to add Polar coordinates to SVG :)

BigBadaboom commented 5 years ago

There is a proposal for a "Bearing" (B) command in the path syntax. Have you seen that?

https://svgwg.org/specs/paths/#PathDataBearingCommands

Would that suit your use cases?

JeremiePat commented 5 years ago

The "Bearing" command is very interesting and it allows to somewhat mimic polar coordinates, which allows to covers some of the use cases I mentioned.

But it is significantly different than a true polar coordinates system. Polar coordinates are meant to define individual point coordinates in the 2D plan where Bearing is a way to rotate the whole subsequent coordinates system of a path definition. The former is a single vector operation where the latter is a global transformation that impact all subsequent vector operations.

Because of that different behavior, B command isn't sharp enough for some cases. For example, when dealing with Bézier curve command it can be handy to mix both Cartesian and polar coordinates, especially in their relative form: c(45,10) (30,20) 30,0 (polar for control point, Cartesian for end point… okay the 2nd control point is still hard to figure, but less hard than with Cartesian coordinates)

That say, mixing both B command and polar coordinates could be a nice easy way to draw spirals (which is currently unbearable with SVG): polar coordinates are easier to define the starting point of a spiral arc based on a center points where B commands are easier to draw relative subsequent segments of such arc (I'm thinking out loud here and it would worth deeper investigation)

derrickoswald commented 4 years ago

Rather than parenthesis, would it satisfy the use-cases to use an @ or < character in place of the comma to separate a distance and an angle instead of x and y? So assuming degrees as the angular unit, M 3,4 would become M 5@53.13010235 M 2,2 would become M 2.828427125<45

For the relative commands, it would be relative to the current point, rather than absolute position.

I'm not sure what the specification says about a missing second number (after a comma), but if no angle was supplied, it could imply tangent to last segment or curve, so M 2,2 2@ would draw a line 4.828427125 long at 45°

BigBadaboom commented 4 years ago

M 2,2 2@ would draw a line 4.828427125 long at 45°

Why 45deg? Are you assuming a previous point of 0,0? An M at the start of a path establishes the first "current point". So I would think that a missing angle there would either be invalid, or would have to default to something like 0deg.

Also, the 2 in "2@" would be a length, going by your previous examples, correct? So it wouldn't be a line "2 long"?