[CAD] Next steps, a trivia question and discussion of the semantics for what objects a connector should avoid
Hi, I'm moving on refactoring the connectors code. I just changed the toolbar a little bit so every connector type has its own button. During refactoring, two questions arised: 1. What does "Ege" as in "EgeAdjustmentAction" mean? 2. What semantics do we want concerning which objects are to be avoided by a connector?
A little elaboration on the second question: Currently, Inkscape uses libavoid to route object-avoiding connectors. All object which should be avoided by the router are added an "inkscape:connector-avoid" attribute. This does not, e.g., allow an object to be avoided by certain connectors and ignored by others. I can currently see three obvious solutions to that problem: * Avoid objects based on group/layer membership. E.g. avoid any objects on the same top-level layer but ignore others. * Avoid objects based on a "tag". This is not unlike the current approach, but I would really use a class instead of an own attribute for this to be easily interoperable with other implementations of this, especially a potential javascript router as discussed with Doug Schepers from w3c, who is currently working on a SVG connectors spec. Personally, I favor the second solution since I think it is less hacky and more flexible. I think it would be a sane choice to have connectors avoid objects by default and to explicitely mark objects to be ignored while routing. If you wanted a connector ignoring any objects you could just use the non-libavoid routing types I am just adding. * Any combination of the above
If you have any thoughts on this, please share them with me ;)
I'm now moving on to implement (somewhat minimalistic) "points" as described in [0] so I can then head towards renovating connector-context.cpp. My latest commit to launchpad breaks in an assertion when drawing a connector since it needs these changes. The commit before that should work, though.
These "points" will be placed whenever one places a connector's end, except if one places a connector's end on an existing "point". When drawing a connector, all visible points will be rendered as knots. This enables template-based diagram elements which are just are groups that contain a shape and one or more points for the connector to attach.
I will remove any logic from connector-context responsible for handling anything but two endpoints (if you want to draw a connector with multiple "stops", just chain together multiple connectors) and remove the "snap connector end point to connector's intersection with destination shape outline"-logic since I do not think this is too useful.
Best regards, Sebastian
[0] http://dev.w3.org/SVG/modules/connector/SVGConnector.html#PointElement
On Tue, 2013-07-23 at 13:07 +0200, Sebastian Götte wrote:
Hi, I'm moving on refactoring the connectors code. I just changed the toolbar a little bit so every connector type has its own button. During refactoring, two questions arised:
- What does "Ege" as in "EgeAdjustmentAction" mean?
Jon Cruz will need to answer that. It doesn't have any special meaning with regards to Inkscape. I believe that the code comes from some other work Jon was doing.
- What semantics do we want concerning which objects are to be avoided by a connector?
A little elaboration on the second question: Currently, Inkscape uses libavoid to route object-avoiding connectors. All object which should be avoided by the router are added an "inkscape:connector-avoid" attribute. This does not, e.g., allow an object to be avoided by certain connectors and ignored by others. I can currently see three obvious solutions to that problem:
- Avoid objects based on group/layer membership. E.g. avoid any objects on the same top-level layer but ignore others.
- Avoid objects based on a "tag". This is not unlike the current approach, but I would really use a class instead of an own attribute for this to be easily interoperable with other implementations of this, especially a potential javascript router as discussed with Doug Schepers from w3c, who is currently working on a SVG connectors spec.
Personally, I favor the second solution since I think it is less hacky and more flexible. I think it would be a sane choice to have connectors avoid objects by default and to explicitely mark objects to be ignored while routing. If you wanted a connector ignoring any objects you could just use the non-libavoid routing types I am just adding.
- Any combination of the above
I think a default solution of avoiding all objects is reasonable. Using classes also sounds reasonable (and doesn't require using inkscape prefixes). You must be careful, though that you don't overwrite any class attribute that already exists. I don't think that you can directly edit the class attribute in Inkscape. It's not in the Object Properties dialog.
If you have any thoughts on this, please share them with me ;)
I'm now moving on to implement (somewhat minimalistic) "points" as described in [0] so I can then head towards renovating connector-context.cpp. My latest commit to launchpad breaks in an assertion when drawing a connector since it needs these changes. The commit before that should work, though.
Note, points are not part of SVG 1.1. Until they are part of an approved spec, they will need to be have an inkscape preface (e.g. -inkscape-point).
These "points" will be placed whenever one places a connector's end, except if one places a connector's end on an existing "point". When drawing a connector, all visible points will be rendered as knots. This enables template-based diagram elements which are just are groups that contain a shape and one or more points for the connector to attach.
I will remove any logic from connector-context responsible for handling anything but two endpoints (if you want to draw a connector with multiple "stops", just chain together multiple connectors) and remove the "snap connector end point to connector's intersection with destination shape outline"-logic since I do not think this is too useful.
Best regards, Sebastian
[0] http://dev.w3.org/SVG/modules/connector/SVGConnector.html#PointElement
On 23/07/2013, at 9:07 PM, Sebastian Götte <jaseg@...2974...> wrote:
I'm moving on refactoring the connectors code. I just changed the toolbar a little bit so every connector type has its own button. During refactoring, two questions arised:
- What does "Ege" as in "EgeAdjustmentAction" mean?
- What semantics do we want concerning which objects are to be avoided by a connector?
A little elaboration on the second question: Currently, Inkscape uses libavoid to route object-avoiding connectors. All object which should be avoided by the router are added an "inkscape:connector-avoid" attribute. This does not, e.g., allow an object to be avoided by certain connectors and ignored by others. I can currently see three obvious solutions to that problem:
- Avoid objects based on group/layer membership. E.g. avoid any objects on the same top-level layer but ignore others.
- Avoid objects based on a "tag". This is not unlike the current approach, but I would really use a class instead of an own attribute for this to be easily interoperable with other implementations of this, especially a potential javascript router as discussed with Doug Schepers from w3c, who is currently working on a SVG connectors spec.
Personally, I favor the second solution since I think it is less hacky and more flexible. I think it would be a sane choice to have connectors avoid objects by default and to explicitely mark objects to be ignored while routing. If you wanted a connector ignoring any objects you could just use the non-libavoid routing types I am just adding.
- Any combination of the above
Hi Sebastian,
A couple of quick thoughts: - You won't get the behaviour of avoiding specific obstacles with different connectors using libavoid, since it routes connectors using a single visibility graph built from the obstacles for the whole diagram. - I think it would be fine to mark objects as obstacles using something other than a property. - The reason for not avoiding all obstacles by default is that libavoid can be slow -- O(n^2 log n) -- especially if there are a lot of obstacles. You don't want this slowness if you open a file with hundreds or thousands of objects that libavoid tracks as objects by default. That was the reason for the original decision to have the user explicit mark objects as obstacles for routing.
I'm now moving on to implement (somewhat minimalistic) "points" as described in [0] so I can then head towards renovating connector-context.cpp. My latest commit to launchpad breaks in an assertion when drawing a connector since it needs these changes. The commit before that should work, though.
These "points" will be placed whenever one places a connector's end, except if one places a connector's end on an existing "point". When drawing a connector, all visible points will be rendered as knots. This enables template-based diagram elements which are just are groups that contain a shape and one or more points for the connector to attach
FWIW, newer versions of libavoid understand and track "connection pins". These are points specified based on a position on shapes. They move if the parent shape is moved and can be specified as the endpoints for connectors. You might want to make of these.
It could be worth updating the version of libavoid in Inkscape to the latest version found here: https://github.com/mjwybrow/adaptagrams The only real work there would be how you find and track attached objects once using connection pins.
I think there was a previous dev who started doing the connection pin work in Inkscape but I'm not sure what happened to that. It doesn't seem to be on the trunk.
I will remove any logic from connector-context responsible for handling anything but two endpoints (if you want to draw a connector with multiple "stops", just chain together multiple connectors) and remove the "snap connector end point to connector's intersection with destination shape outline"-logic since I do not think this is too useful.
Do you mean the functionality that adjusts the endpoint of a connector to stop at the intersection with the destination shape? If so, the reason for this is that the arrowhead is drawn at the end of the connector and people frequently want this to coincide with the edge of the shape.
Cheers, Michael
----- Dr. Michael Wybrow, Research Fellow Monash Adaptive Visualisation Lab (MArVL) Caulfield School of Information Technology Monash University, Caulfield, Australia Phone: +613 9905 2479 Mobile: +614 2577 2053
Please note I am part-time and do not work on Wednesdays.
On Tue, 2013-07-30 at 09:57 +1000, Michael Wybrow wrote:
On 23/07/2013, at 9:07 PM, Sebastian Götte <jaseg@...2974...> wrote:
I will remove any logic from connector-context responsible for handling anything but two endpoints (if you want to draw a connector with multiple "stops", just chain together multiple connectors) and remove the "snap connector end point to connector's intersection with destination shape outline"-logic since I do not think this is too useful.
Do you mean the functionality that adjusts the endpoint of a connector to stop at the intersection with the destination shape? If so, the reason for this is that the arrowhead is drawn at the end of the connector and people frequently want this to coincide with the edge of the shape.
SVG 2 will have "marker knockouts" which address the issue of allowing arrowheads that end at the same place the path ends without the path sticking out. They are already defined in the SVG 2 draft but there is some disagreement as to how they are currently speced (I, for one, don't like having fixed shapes). See:
http://www.w3.org/TR/SVG2/painting.html#MarkerKnockout
Tav
On 07/30/2013 01:57 AM, Michael Wybrow wrote:
Hi Sebastian,
A couple of quick thoughts:
- You won't get the behaviour of avoiding specific obstacles with different connectors using libavoid, since it routes connectors using a single visibility graph built from the obstacles for the whole diagram.
Ok, I think that's fine. The only use case I can imagine is something like PCB routing where you could want one visibility graph per layer.
- I think it would be fine to mark objects as obstacles using something other than a property.
- The reason for not avoiding all obstacles by default is that libavoid can be slow -- O(n^2 log n) -- especially if there are a lot of obstacles. You don't want this slowness if you open a file with hundreds or thousands of objects that libavoid tracks as objects by default. That was the reason for the original decision to have the user explicit mark objects as obstacles for routing.
Shouldn't this be in O(n log n)?
I'm now moving on to implement (somewhat minimalistic) "points" as described in [0] so I can then head towards renovating connector-context.cpp. My latest commit to launchpad breaks in an assertion when drawing a connector since it needs these changes. The commit before that should work, though.
These "points" will be placed whenever one places a connector's end, except if one places a connector's end on an existing "point". When drawing a connector, all visible points will be rendered as knots. This enables template-based diagram elements which are just are groups that contain a shape and one or more points for the connector to attach
FWIW, newer versions of libavoid understand and track "connection pins". These are points specified based on a position on shapes. They move if the parent shape is moved and can be specified as the endpoints for connectors. You might want to make of these.
Thanks. This behavior can easily be implemented by putting a few SPPoints into a group with some shape. The new connector code just creates these SPPoints as needed, and handling of object centers/corners/nodes etc. should be done by just snapping their locations to these points.
It could be worth updating the version of libavoid in Inkscape to the latest version found here: https://github.com/mjwybrow/adaptagrams The only real work there would be how you find and track attached objects once using connection pins.
By moving to SPPoints this is actually pretty non-problematic since they will just move with the groups containing them.
I think there was a previous dev who started doing the connection pin work in Inkscape but I'm not sure what happened to that. It doesn't seem to be on the trunk.
I will remove any logic from connector-context responsible for handling anything but two endpoints (if you want to draw a connector with multiple "stops", just chain together multiple connectors) and remove the "snap connector end point to connector's intersection with destination shape outline"-logic since I do not think this is too useful.
Do you mean the functionality that adjusts the endpoint of a connector to stop at the intersection with the destination shape? If so, the reason for this is that the arrowhead is drawn at the end of the connector and people frequently want this to coincide with the edge of the shape.
I removed that because it would have been even more work porting and because with the addition of SPPoints it is not really necessary anymore (I am not totally against re-adding it, though).
Best regards, Sebastian
[1] http://dev.w3.org/SVG/modules/connector/SVGConnector.html
On 31/07/2013, at 5:20 AM, Sebastian Götte <jaseg@...2974...> wrote:
- The reason for not avoiding all obstacles by default is that libavoid can be slow -- O(n^2 log n) -- especially if there are a lot of obstacles. You don't want this slowness if you open a file with hundreds or thousands of objects that libavoid tracks as objects by default. That was the reason for the original decision to have the user explicit mark objects as obstacles for routing.
Shouldn't this be in O(n log n)?
Nope. In practice it's fast for small diagrams but parts of it are definitely O(n^2 log n) in the worst case. See the papers.
FWIW, newer versions of libavoid understand and track "connection pins". These are points specified based on a position on shapes. They move if the parent shape is moved and can be specified as the endpoints for connectors. You might want to make of these.
Thanks. This behavior can easily be implemented by putting a few SPPoints into a group with some shape. The new connector code just creates these SPPoints as needed, and handling of object centers/corners/nodes etc. should be done by just snapping their locations to these points.
[...]
By moving to SPPoints this is actually pretty non-problematic since they will just move with the groups containing them.
Fair enough. That sounds fine.
I will remove any logic from connector-context responsible for handling anything but two endpoints (if you want to draw a connector with multiple "stops", just chain together multiple connectors) and remove the "snap connector end point to connector's intersection with destination shape outline"-logic since I do not think this is too useful.
Do you mean the functionality that adjusts the endpoint of a connector to stop at the intersection with the destination shape? If so, the reason for this is that the arrowhead is drawn at the end of the connector and people frequently want this to coincide with the edge of the shape.
I removed that because it would have been even more work porting and because with the addition of SPPoints it is not really necessary anymore (I am not totally against re-adding it, though).
Do you mean that by placing a Point on the boundary at a particular position the arrowhead will be positioned there? If so, my experience is that people often want connectors that appear to be connected to the centre of shapes, but that are drawn just to the edge of the shape. Manually positioning points in the right place to achieve this effect could get very tedious indeed, especially when moving shapes around.
Cheers, Michael
On Mon, 2013-08-05 at 17:46 +1000, Michael Wybrow wrote:
On 31/07/2013, at 5:20 AM, Sebastian Götte <jaseg@...2974...> wrote:
I will remove any logic from connector-context responsible for handling anything but two endpoints (if you want to draw a connector with multiple "stops", just chain together multiple connectors) and remove the "snap connector end point to connector's intersection with destination shape outline"-logic since I do not think this is too useful.
Do you mean the functionality that adjusts the endpoint of a connector to stop at the intersection with the destination shape? If so, the reason for this is that the arrowhead is drawn at the end of the connector and people frequently want this to coincide with the edge of the shape.
I removed that because it would have been even more work porting and because with the addition of SPPoints it is not really necessary anymore (I am not totally against re-adding it, though).
Do you mean that by placing a Point on the boundary at a particular position the arrowhead will be positioned there? If so, my experience is that people often want connectors that appear to be connected to the centre of shapes, but that are drawn just to the edge of the shape. Manually positioning points in the right place to achieve this effect could get very tedious indeed, especially when moving shapes around.
Yes, that is what I mean. You bring up an interesting point. I don't think it has been explicitly considered in the SVG Connector's spec but I don't think it would be hard to add. What has been considered is that an object can have a set of connecting points that belong to the same class. A connector could be directed to attach to the most convenient (e.g. closest) connector point.
Tav
On 08/05/2013 09:46 AM, Michael Wybrow wrote:
I will remove any logic from connector-context responsible for handling anything but two endpoints (if you want to draw a connector with multiple "stops", just chain together multiple connectors) and remove the "snap connector end point to connector's intersection with destination shape outline"-logic since I do not think this is too useful.
Do you mean the functionality that adjusts the endpoint of a connector to stop at the intersection with the destination shape? If so, the reason for this is that the arrowhead is drawn at the end of the connector and people frequently want this to coincide with the edge of the shape.
I removed that because it would have been even more work porting and because with the addition of SPPoints it is not really necessary anymore (I am not totally against re-adding it, though).
Do you mean that by placing a Point on the boundary at a particular position the arrowhead will be positioned there? If so, my experience is that people often want connectors that appear to be connected to the centre of shapes, but that are drawn just to the edge of the shape. Manually positioning points in the right place to achieve this effect could get very tedious indeed, especially when moving shapes around.
Yes. I think the small number of cases where you actually want to connect the connector to the center of the shape instead of a svg:point on the outline does not warrant all the work. The "connect-to-center-snap-to-outline" behavior is probably ok for some simple shapes such as circles or ellipses but for others like plain rectangles I think might not provide aesthetically pleasing results (e.g. in this case I would want it to snap to the middle of one of the sides).
I think it is hard to define a behavior that also works for more complex shapes (spirals, or something banana-shaped, or something with a considerably off-center center of mass).
I do not have a good solution to this yet though.
Sebastian
On 08/05/2013 12:13 PM, Tavmjong Bah wrote:
On Mon, 2013-08-05 at 17:46 +1000, Michael Wybrow wrote:
On 31/07/2013, at 5:20 AM, Sebastian Götte <jaseg@...2974...> wrote:
I will remove any logic from connector-context responsible for handling anything but two endpoints (if you want to draw a connector with multiple "stops", just chain together multiple connectors) and remove the "snap connector end point to connector's intersection with destination shape outline"-logic since I do not think this is too useful.
Do you mean the functionality that adjusts the endpoint of a connector to stop at the intersection with the destination shape? If so, the reason for this is that the arrowhead is drawn at the end of the connector and people frequently want this to coincide with the edge of the shape.
I removed that because it would have been even more work porting and because with the addition of SPPoints it is not really necessary anymore (I am not totally against re-adding it, though).
Do you mean that by placing a Point on the boundary at a particular position the arrowhead will be positioned there? If so, my experience is that people often want connectors that appear to be connected to the centre of shapes, but that are drawn just to the edge of the shape. Manually positioning points in the right place to achieve this effect could get very tedious indeed, especially when moving shapes around.
Yes, that is what I mean. You bring up an interesting point. I don't think it has been explicitly considered in the SVG Connector's spec but I don't think it would be hard to add. What has been considered is that an object can have a set of connecting points that belong to the same class. A connector could be directed to attach to the most convenient (e.g. closest) connector point.
I think this might be too complex. It works fine for e.g. points on a circle, but the distance calculation gets messy as soon as more complex routing (libavoid-style) and concave shapes or even shapes that have holes are involved. I think the problem will be to properly define the behavior in all such fringe cases so another implementation of the routing algorithm in say, javascript running in a browser, may produce consistent results.
A discrete, small set of points also is not sufficient to represent the case where it is in fact irrelevant where the connector attaches (e.g. on a circle).
A complex solution would be to generalize from sets of points to sets of points and curves, but this still does not account for the asethetic factor of the connector's angle to the shape outlines's normal vector. A "more convenient" solution by some simple metric (e.g. euclidean distance) will look bad in some cases. I don't think it is within the scope of an SVG extension to stanardize this. I would prefer an interface that lets the user do all that high-level (aesthetic) reasoning and lets the user to select the best solution for a particular situation.
Sebastian
On Mon, 2013-08-05 at 20:43 +0200, Sebastian Götte wrote:
I do not have a good solution to this yet though.
Connecting to a shape directly (not to a point) should continue to work as it does right now. By connecting to the nearest edge of the shape.
Points though, should go directly.
Martin,
participants (4)
-
Martin Owens
-
Michael Wybrow
-
Sebastian Götte
-
Tavmjong Bah