Re: [Inkscape-devel] [Lib2geom-devel] Geom::Path and boost::ptr_vector
Krzysztof Kosiński wrote:
... BTW I want to make 2 additional changes:
- When the ends of normal path data coincide, no closing segment is added.
To clarify: you're talking about a path which is NOT closed? Then it sounds logical (although I wonder why Inkscape would add a closing segment).
If you're talking about having a closed path and then not adding the closing segment, please reconsider. Inkscape used to do this in the past and it caused some very nasty bugs (having to do with round-tripping for one), apart from simply being incorrect (at least in SVG).
-----Original Message----- From: Jasper van de Gronde [mailto:th.v.d.gronde@...528...] Sent: Wednesday, February 10, 2010 19:15 To: Inkscape Devel List; Krzysztof Kosiński Subject: Re: [Inkscape-devel] [Lib2geom-devel] Geom::Path andboost::ptr_vector
Krzysztof Kosiński wrote:
... BTW I want to make 2 additional changes:
- When the ends of normal path data coincide, no closing
segment is added.
To clarify: you're talking about a path which is NOT closed? Then it sounds logical (although I wonder why Inkscape would add a closing segment).
If you're talking about having a closed path and then not adding the closing segment, please reconsider. Inkscape used to do this in the past and it caused some very nasty bugs (having to do with round-tripping for one), apart from simply being incorrect (at least in SVG).
This one scared me too a bit. We have to investigate *very* carefully what the implications of this change are.
Ciao, Johan
W dniu 10 lutego 2010 19:14 użytkownik Jasper van de Gronde <th.v.d.gronde@...528...> napisał:
If you're talking about having a closed path and then not adding the closing segment, please reconsider. Inkscape used to do this in the past and it caused some very nasty bugs (having to do with round-tripping for one), apart from simply being incorrect (at least in SVG).
Some background: currently paths always store a "closing segment" that is not part of the "normal" user supplied path data, but can be iterated over using end_closed. The intent is to have a well defined way to stroke and fill a path. This segment is stored even if it is degenerate (zero length), for example when the path is closed and has only Bezier curves.
After the proposed change the closing segment will not be added if the final point of the last segment of the "normal" path data is exactly equal to the initial point of the first segment. Closedness will still be stored in a flag, like before, and affect what is returned from the iterators. This will simplify the code in the node tool, because the path won't have a zero-length segment at the end that has to be intelligently skipped. By itself it probably won't fix the bug I mentioned, but it will simplify a quirk when dealing with closed paths.
Alternatively, the iterators might be modified so that iterating over the closed path doesn't return the extra zero-length segment, but then I see no need to store it in the first place. If there is some specific need to have this zero-length segment in the path, I will reconsider this.
Jasper: I see that you've wrote the PathString class that writes SVG path strings in Inkscape (in svg/path-string.cpp). Can you modify it so that if the last segment of a path is not linear, it is always written in absolute coordinates regardless of the preference settings? Otherwise we sometimes suffer from a loss of precision when writing the transformed path, which (I believe) causes the "rotate adds node" bug.
Regards, Krzysztof
Krzysztof Kosiński wrote:
W dniu 10 lutego 2010 19:14 użytkownik Jasper van de Gronde <th.v.d.gronde@...528...> napisał:
If you're talking about having a closed path and then not adding the closing segment, please reconsider. Inkscape used to do this in the past and it caused some very nasty bugs (having to do with round-tripping for one), apart from simply being incorrect (at least in SVG).
Some background: currently paths always store a "closing segment" that is not part of the "normal" user supplied path data, but can be iterated over using end_closed. The intent is to have a well defined way to stroke and fill a path. This segment is stored even if it is degenerate (zero length), for example when the path is closed and has only Bezier curves.
So the closing segment is also present if that path is not actually closed? Possibly this is a case of a way too overloaded term :) In any case, I'm talking about the following paths all being definitely different (and Inkscape should at least be able to round-trip their structure, even after transformations):
M 0,0 L 1,1 M 0,0 L 1,1 z M 0,0 L 1,1 L 0,0 z M 0,0 L 1,1 L 0,0
... This will simplify the code in the node tool, because the path won't have a zero-length segment at the end that has to be intelligently skipped. By itself it probably won't fix the bug I mentioned, but it will simplify a quirk when dealing with closed paths.
Why would it simplify this? If it is present without the path being closed this makes sense (you'd indeed have to skip it), but for closed paths the segment is definitely there (even if zero length). Remember that in general a zero-length segment is simply valid SVG and the close-path command is defined as drawing a straight segment between the current point and the beginning of the subpath (whether this segment is zero-length or not).
Alternatively, the iterators might be modified so that iterating over the closed path doesn't return the extra zero-length segment, but then I see no need to store it in the first place. If there is some specific need to have this zero-length segment in the path, I will reconsider this.
See the above, specifically you may want to have a very, very close look at all the details of marker and stroke rendering, as well as the path implementation notes: http://www.w3.org/TR/SVG11/implnote.html#PathElementImplementationNotes
It is possible that what you're trying to do is okay, but you need to be VERY careful here.
Jasper: I see that you've wrote the PathString class that writes SVG path strings in Inkscape (in svg/path-string.cpp). Can you modify it so that if the last segment of a path is not linear, it is always written in absolute coordinates regardless of the preference settings? Otherwise we sometimes suffer from a loss of precision when writing the transformed path, which (I believe) causes the "rotate adds node" bug.
This sounds suspect. No loss of precision should ever add (or remove) a node. If it does there is something wrong (the number of nodes is completely unrelated to the position of the nodes).
Obviously any loss of precision with relative coordinates is an issue itself (and I'll try to have a look over the weekend), but it should (as in: if it isn't Inkscape has a more serious bug) be completely separate from any problems with node duplication.
(Resending, I think it didn't reach the list previously.)
Krzysztof Kosiński wrote:
W dniu 10 lutego 2010 19:14 użytkownik Jasper van de Gronde <th.v.d.gronde@...528...> napisał:
If you're talking about having a closed path and then not adding the closing segment, please reconsider. Inkscape used to do this in the past and it caused some very nasty bugs (having to do with round-tripping for one), apart from simply being incorrect (at least in SVG).
Some background: currently paths always store a "closing segment" that is not part of the "normal" user supplied path data, but can be iterated over using end_closed. The intent is to have a well defined way to stroke and fill a path. This segment is stored even if it is degenerate (zero length), for example when the path is closed and has only Bezier curves.
So the closing segment is also present if that path is not actually closed? Possibly this is a case of a way too overloaded term :) In any case, I'm talking about the following paths all being definitely different (and Inkscape should at least be able to round-trip their structure, even after transformations):
M 0,0 L 1,1 M 0,0 L 1,1 z M 0,0 L 1,1 L 0,0 z M 0,0 L 1,1 L 0,0
... This will simplify the code in the node tool, because the path won't have a zero-length segment at the end that has to be intelligently skipped. By itself it probably won't fix the bug I mentioned, but it will simplify a quirk when dealing with closed paths.
Why would it simplify this? If it is present without the path being closed this makes sense (you'd indeed have to skip it), but for closed paths the segment is definitely there (even if zero length). Remember that in general a zero-length segment is simply valid SVG and the close-path command is defined as drawing a straight segment between the current point and the beginning of the subpath (whether this segment is zero-length or not).
Alternatively, the iterators might be modified so that iterating over the closed path doesn't return the extra zero-length segment, but then I see no need to store it in the first place. If there is some specific need to have this zero-length segment in the path, I will reconsider this.
See the above, specifically you may want to have a very, very close look at all the details of marker and stroke rendering, as well as the path implementation notes: http://www.w3.org/TR/SVG11/implnote.html#PathElementImplementationNotes
It is possible that what you're trying to do is okay, but you need to be VERY careful here.
Jasper: I see that you've wrote the PathString class that writes SVG path strings in Inkscape (in svg/path-string.cpp). Can you modify it so that if the last segment of a path is not linear, it is always written in absolute coordinates regardless of the preference settings? Otherwise we sometimes suffer from a loss of precision when writing the transformed path, which (I believe) causes the "rotate adds node" bug.
This sounds suspect. No loss of precision should ever add (or remove) a node. If it does there is something wrong (the number of nodes is completely unrelated to the position of the nodes).
Obviously any loss of precision with relative coordinates is an issue itself (and I'll try to have a look over the weekend), but it should (as in: if it isn't Inkscape has a more serious bug) be completely separate from any problems with node duplication.
(Sending yet again because there might be something wrong with the SMTP server I was using and I don't see the message appearing on the list...)
Krzysztof Kosiński wrote:
W dniu 10 lutego 2010 19:14 użytkownik Jasper van de Gronde <th.v.d.gronde@...528...> napisał:
If you're talking about having a closed path and then not adding the closing segment, please reconsider. Inkscape used to do this in the past and it caused some very nasty bugs (having to do with round-tripping for one), apart from simply being incorrect (at least in SVG).
Some background: currently paths always store a "closing segment" that is not part of the "normal" user supplied path data, but can be iterated over using end_closed. The intent is to have a well defined way to stroke and fill a path. This segment is stored even if it is degenerate (zero length), for example when the path is closed and has only Bezier curves.
So the closing segment is also present if that path is not actually closed? Possibly this is a case of a way too overloaded term :) In any case, I'm talking about the following paths all being definitely different (and Inkscape should at least be able to round-trip their structure, even after transformations):
M 0,0 L 1,1 M 0,0 L 1,1 z M 0,0 L 1,1 L 0,0 z M 0,0 L 1,1 L 0,0
... This will simplify the code in the node tool, because the path won't have a zero-length segment at the end that has to be intelligently skipped. By itself it probably won't fix the bug I mentioned, but it will simplify a quirk when dealing with closed paths.
Why would it simplify this? If it is present without the path being closed this makes sense (you'd indeed have to skip it), but for closed paths the segment is definitely there (even if zero length). Remember that in general a zero-length segment is simply valid SVG and the close-path command is defined as drawing a straight segment between the current point and the beginning of the subpath (whether this segment is zero-length or not).
Alternatively, the iterators might be modified so that iterating over the closed path doesn't return the extra zero-length segment, but then I see no need to store it in the first place. If there is some specific need to have this zero-length segment in the path, I will reconsider this.
See the above, specifically you may want to have a very, very close look at all the details of marker and stroke rendering, as well as the path implementation notes: http://www.w3.org/TR/SVG11/implnote.html#PathElementImplementationNotes
It is possible that what you're trying to do is okay, but you need to be VERY careful here.
Jasper: I see that you've wrote the PathString class that writes SVG path strings in Inkscape (in svg/path-string.cpp). Can you modify it so that if the last segment of a path is not linear, it is always written in absolute coordinates regardless of the preference settings? Otherwise we sometimes suffer from a loss of precision when writing the transformed path, which (I believe) causes the "rotate adds node" bug.
This sounds suspect. No loss of precision should ever add (or remove) a node. If it does there is something wrong (the number of nodes is completely unrelated to the position of the nodes).
Obviously any loss of precision with relative coordinates is an issue itself (and I'll try to have a look over the weekend), but it should (as in: if it isn't Inkscape has a more serious bug) be completely separate from any problems with node duplication.
W dniu 11 lutego 2010 18:08 użytkownik Jasper van de Gronde <th.v.d.gronde@...528...> napisał:
Why would it simplify this? If it is present without the path being closed this makes sense (you'd indeed have to skip it), but for closed paths the segment is definitely there (even if zero length). Remember that in general a zero-length segment is simply valid SVG and the close-path command is defined as drawing a straight segment between the current point and the beginning of the subpath (whether this segment is zero-length or not).
The issue is not that this segment exists in open paths. It's a problem when the path's last "real" segment is a bezier, or an explicit line segment (l rather than z). When there's a zero-length closing segment in a closed path, I need to ignore it and only show one node for the join between the last segment and first segment, and the segment introduced by "z" has to be ignored.
Jasper: I see that you've wrote the PathString class that writes SVG path strings in Inkscape (in svg/path-string.cpp). Can you modify it so that if the last segment of a path is not linear, it is always written in absolute coordinates regardless of the preference settings? Otherwise we sometimes suffer from a loss of precision when writing the transformed path, which (I believe) causes the "rotate adds node" bug.
This sounds suspect. No loss of precision should ever add (or remove) a node. If it does there is something wrong (the number of nodes is completely unrelated to the position of the nodes).
For nodes in the middle of the path this is true, but not in the special case of the node that joins the beginning and end of the path. Whether we show one or two nodes between the first and last "real" segment directly depends on whether the closing segment introduced by "z" is zero-length or not. When a transformation makes the zero length closing segment non-zero, because the errors in relative coordinates add up differently, the node tool treats it as a real segment and no longer ignores it by showing only one node. So two nodes appear for both ends of the closing segment, while there should be only one. The loss of precision is a direct cause of the extra node bug. See the "7nodes" spreadsheet that was posted as the 2nd comment to the bug. https://bugs.launchpad.net/inkscape/+bug/515237
Regards, Krzysztof
Krzysztof Kosiński wrote:
W dniu 11 lutego 2010 18:08 użytkownik Jasper van de Gronde <th.v.d.gronde@...528...> napisał:
Why would it simplify this? If it is present without the path being closed this makes sense (you'd indeed have to skip it), but for closed paths the segment is definitely there (even if zero length). Remember that in general a zero-length segment is simply valid SVG and the close-path command is defined as drawing a straight segment between the current point and the beginning of the subpath (whether this segment is zero-length or not).
The issue is not that this segment exists in open paths. It's a problem when the path's last "real" segment is a bezier, or an explicit line segment (l rather than z). When there's a zero-length closing segment in a closed path, I need to ignore it and only show one node for the join between the last segment and first segment, and the segment introduced by "z" has to be ignored.
The path "M 0,0 L 1,1 z" has two nodes and "M 0,0 L 1,1 L 0,0 z" has three. Inkscape definitely SHOULD distinguish the two. (The most obvious reason being that the first path should only have one mid marker and the second two.)
I understand this is stranger when the segments involved are curves, but that doesn't make it untrue. SVG simply does not have any way of specifying a closed path with only curved segments.
Relying on the numerical precision of Inkscape (and/or other applications) to give extra meaning to a zero-length segment connecting two (curved) segments if it happens to be the last segment in the current subpath is risky at best and could lead to very subtle and weird issues (as well as no round-tripping).
As for the correct fix, that's another story. The best fix would obviously have been to handle closed paths differently in SVG. More realistically we may want to make a special nodetype (as in sodipodi:nodetypes) that indicates that a node is intended to close the curve (whether or not the endpoint indeed coincides with the first node of the subpath). For example, we could use the capital version of the nodetype for this purpose.
W dniu 11 lutego 2010 20:09 użytkownik Jasper van de Gronde <th.v.d.gronde@...528...> napisał:
The path "M 0,0 L 1,1 z" has two nodes and "M 0,0 L 1,1 L 0,0 z" has three. Inkscape definitely SHOULD distinguish the two. (The most obvious reason being that the first path should only have one mid marker and the second two.)
It is not possible to create the second path in the node tool at the moment - it will be automatically converted to the first one. I think it's good. Are there any actual use cases for closed paths where the last "z" is treated as a real segment?
Relying on the numerical precision of Inkscape (and/or other applications) to give extra meaning to a zero-length segment connecting two (curved) segments if it happens to be the last segment in the current subpath is risky at best and could lead to very subtle and weird issues (as well as no round-tripping).
I don't know what "round-tripping" means in this context. There is a subtle and weird issue already (the bug I mentioned).
Only the "z" has to sometimes be treated as a linear segment and sometimes as nothing. There is no "happens to be the last segment" because "z" is by definition the last segment. Are you suggesting we should always treat "z" as a real segment? This is very wrong: - Curve dragging would work on everything except this segment, or (alternatively) curve-dragging it would introduce an extra node. - All closed Bezier-only paths would have an ugly double node that couldn't be removed.
As for the correct fix, that's another story. The best fix would obviously have been to handle closed paths differently in SVG. More realistically we may want to make a special nodetype (as in sodipodi:nodetypes) that indicates that a node is intended to close the curve (whether or not the endpoint indeed coincides with the first node of the subpath). For example, we could use the capital version of the nodetype for this purpose.
This is a good idea, I considered doing something like this. We could actually use the first letter of the nodetype string since in 0.47 and earlier it is ignored for closed paths. However, paths created using the Bezier tool or converted from shapes do not contain nodetype information - transforming them will still lead to the node adding bug.
The only ways to fix this that I can think of at the moment is to always store the last segment before "z" using absolute coordinates, or adding nodetype information to all paths whenever they are created. The second solution requires many more changes.
Regards, Krzysztof
A quick mail to hopefully clarify some things.
1. Inkscape cannot generate all possible valid SVG paths; so we are not looking at what Inkscape can and should generate, but instead are looking at what is valid SVG and which should be representable in 2Geom. Probably it is a good thing that Inkscape cannot generate weird SVG paths, but 2geom should not care about Inkscape's desires in this case. (the two are unrelated)
2. Round tripping means: reading SVG, converting it to a 2Geom path, and converting it back to SVG. The result should be identical to the original SVG.
Cheers, Johan
-----Original Message----- From: Krzysztof Kosinski [mailto:tweenk.pl@...400...] Sent: Sat 13/02/2010 3:27 To: Jasper van de Gronde Cc: Inkscape Devel List Subject: Re: [Inkscape-devel] [Lib2geom-devel] Geom::Path andboost::ptr_vector
W dniu 11 lutego 2010 20:09 uzytkownik Jasper van de Gronde <th.v.d.gronde@...528...> napisal:
The path "M 0,0 L 1,1 z" has two nodes and "M 0,0 L 1,1 L 0,0 z" has three. Inkscape definitely SHOULD distinguish the two. (The most obvious reason being that the first path should only have one mid marker and the second two.)
It is not possible to create the second path in the node tool at the moment - it will be automatically converted to the first one. I think it's good. Are there any actual use cases for closed paths where the last "z" is treated as a real segment?
Relying on the numerical precision of Inkscape (and/or other applications) to give extra meaning to a zero-length segment connecting two (curved) segments if it happens to be the last segment in the current subpath is risky at best and could lead to very subtle and weird issues (as well as no round-tripping).
I don't know what "round-tripping" means in this context. There is a subtle and weird issue already (the bug I mentioned).
Only the "z" has to sometimes be treated as a linear segment and sometimes as nothing. There is no "happens to be the last segment" because "z" is by definition the last segment. Are you suggesting we should always treat "z" as a real segment? This is very wrong: - Curve dragging would work on everything except this segment, or (alternatively) curve-dragging it would introduce an extra node. - All closed Bezier-only paths would have an ugly double node that couldn't be removed.
As for the correct fix, that's another story. The best fix would obviously have been to handle closed paths differently in SVG. More realistically we may want to make a special nodetype (as in sodipodi:nodetypes) that indicates that a node is intended to close the curve (whether or not the endpoint indeed coincides with the first node of the subpath). For example, we could use the capital version of the nodetype for this purpose.
This is a good idea, I considered doing something like this. We could actually use the first letter of the nodetype string since in 0.47 and earlier it is ignored for closed paths. However, paths created using the Bezier tool or converted from shapes do not contain nodetype information - transforming them will still lead to the node adding bug.
The only ways to fix this that I can think of at the moment is to always store the last segment before "z" using absolute coordinates, or adding nodetype information to all paths whenever they are created. The second solution requires many more changes.
Regards, Krzysztof
------------------------------------------------------------------------------ SOLARIS 10 is the OS for Data Centers - provides features such as DTrace, Predictive Self Healing and Award Winning ZFS. Get Solaris 10 NOW http://p.sf.net/sfu/solaris-dev2dev _______________________________________________ Inkscape-devel mailing list Inkscape-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/inkscape-devel
Krzysztof Kosiński wrote:
Only the "z" has to sometimes be treated as a linear segment and sometimes as nothing. There is no "happens to be the last segment" because "z" is by definition the last segment. Are you suggesting we should always treat "z" as a real segment? This is very wrong:
- Curve dragging would work on everything except this segment, or
(alternatively) curve-dragging it would introduce an extra node.
- All closed Bezier-only paths would have an ugly double node that
couldn't be removed.
This is a valid point, but I think Johan also has a good point in his post about distinguishing between what lib2geom can represent and what Inkscape exposes to the user.
Perhaps an explicit wrapper may provide you with the convenience you're looking for, while making it easy to provide consistent and correct behaviour across the board. The mapping could be something like this (where Lz and Cz are the "closing" variants of L and C):
M 0,0 L 1,1 z <-> M 0,0 L 1,1 Lz M 0,0 L 1,1 L 0,0 z <-> M 0,0 L 1,1 L 0,0 Lz M 0,0 C p1 p2 1,1 z <-> M 0,0 C p1 p2 1,1 Lz M 0,0 C p1 p2 1,1 C p3 p4 0,0 z <-> M 0,0 C p1 p2 1,1 Cz p3 p4
In other words, we only add the "manual" closing segment when needed and there is a 1-on-1 correspondence between "Inkscape paths" and "SVG paths" (something which was lacking in a previous version). Please note that there is no 1-on-1 correspondence if we also transform the second path into "M 0,0 L 1,1 Lz".
Alternatively we could consider altering lib2geom's representation of paths to deal with closing segments in a different way and do the mapping only when reading from/writing to SVG path strings. But I
Now, if we indeed do the above and introduce the notion of an "Inkscape path" (or UI path, or whatever you want to call it), then it indeed becomes of paramount importance to be able to detect if the last specified node in the subpath is equal to the first. So yes, then I'd love to make sure that relative paths do not mess things up in this department.
Note that this would cause some inconsistency w.r.t. markers, but at least people would have full control of their paths. And sacrificing 1-on-1 correspondence does seem a bit high a price to pay just for partially(!) solving a cosmetic problem that would only come up when people create closed paths with mid markers (and that they could solve themselves by explicitly creating a duplicate node).
participants (3)
-
unknown@example.com
-
Jasper van de Gronde
-
Krzysztof Kosiński