Number: 1921
Title: edge misses top of node with invtriangle shape
Submitter: chris korda
Date: Tue Apr 6 03:56:42 2010
Subsys: Dot
Version: 2.24
System: x86-Windows-XP
Severity: cosmetic
Problem:
If the inverted triangle node shape (invtriangle) is used, and connections are made to the flat top of the triangle via the northern ports, the resulting edges miss the flat top of the triangle by a significant amount. The result suggests that in this case the edge-positioning code ignores the invtriangle attribute and substitutes a default shape (ellipse?).

dot command:
  dot -Tjpg -omytest.jpg mytest.txt

Input file: b1921.dot
Output file: b1921.jpg
Comments:
[ellson] This problem is related to the port code. See modified example: input and output.

[ellson] Thanks for the report. I've applied a fix for this particular case which should be in tomorrow's snapshot.

We still need more cleanup of compassPort placement code. I think e,w ports on assymetric shapes will still fail at the moment.

[chris] Thanks for the update. I enclose another related but distinct case which might be interesting. It also uses invtriangle but with all three north ports connected. In this case NW and NE intersect the top of the node, but N does not. Note that this example fails with other node shapes besides invtriangle, e.g. try it with house or invhouse.

I can submit this via the bug reports form if you prefer.

I'm curious about the nature of the problem. Do shapes have some data that defines where their ports are? And if so, do the inverted shapes have their own data, or are they handled by flipping the ports around the origin?

In other words, would it be helpful to try all the nodes shapes against these two cases of mine? I will volunteer to do this if it's helpful.

The problem was affecting N,S,E,W but not NE,NW, SE,SW which were slightly better coded.

[ellson] The problem only affects asymmetric shapes: N,S, if the shape is asymmetric vertically, and E,W if the shape is asymmetric horizontally

I've put in a partial fix for N,S, but haven't fixed E,W yet. The code really needs to be recoded to accept a port at any angle; instead of the case statement in which the same code is repeated multiple times, or not if it didn't seem too important ;-)

If you're interested, the code that needs rewriting is in lib/common/shapes.c in the compassPort() function. I think a better coding would be to convert the compass request to an angle, find the intersection of that angle from the node center to the node bounding box, then use the edge clipping code to work back to the intersecion with the polygon. Basically we shouldn't be using a case statement at all.

The fix I've applied works for your other example. See attached. You can see my fix so far with:


      cvs diff -u -r1.140 -r1.141 lib/common/shapes.c

The fix I've applied works for your other example. See attached.

[chris'] Thanks, and yes it sounds convoluted and in need of a rewrite. It does tend to happen in older systems, I deal with it all the time. Regarding "code ... repeated multiple times", at my work we call these "paste bombs", because they're made with the paste key, and they cause big problems later when some of them get modified but others not.

I do have one question though. Is there an easier way to do what I'm trying to do? All I want is to ensure that for each node, its inputs (edge heads) connect on the top, and its outputs (edge tails) connect on the bottom. Maybe there's already some dot feature I missed that adds this constraint? Compass ports are overly constraining: I don't want to have specify east/west, dot should keep that degree of freedom. Also compass ports won't work if there are more than three edges connecting to the node top or bottom.

If there's no such feature, perhaps I should propose it? The syntax is easy, an edge could specify an orientation (TBLR) instead of a compass point, e.g.

edge1:B->edge2:T

or in a LR graph,

edge1:L->edge2:R

[erg] I'm unclear as to what is being proposed. Is edge1 the name of a node, and B is short-hand for sw/s/se, whatever works? Or is this a new keyword, and edge1:B specifies the previous constraint for all out-edges?

The original grammar did contain a specification for the angle an edge entered a node but, as with ports, it was never implemented. Presumably one might also want a fuzzy angle.

If the code can be simplified, great, but using ports affects mincross, positioning and edge routing, and everything has to work correctly under the transformations used for rankdir.

[ellson] My interpretation would be "foonode:T -> ..." means any that an outedge of foonode is constained to originate at any convenient angle from ne to nw. Convenient to the edge layouter."

Or, perhaps alternatively, that the edge induces a virtual port anywhere arout the node periphery between ne and nw.


>
> The original grammar did contain a specification for the angle an edge entered a node but, as with ports, it was never
> implemented.  Presumably one might also want a fuzzy angle.

Yes, I think we are talking about fuzzy angles, or floating ports, with contrained flexibility left to the edge layouter.

[erg] So

foo:B -> bar:T

means that particular edge from foo to bar goes from the bottom of foo to the top of bar?

Note that we do have the port _ tells the router to use some reasonable port exposed to the outside of the node, so we already have a notion of fuzziness.

The nice thing about having non-fuzzy ports is that this aids crossing reduction.

[chris] Yes, exactly. For example in this case:


alpha:B -> foo:T
bravo:B -> foo:T
charlie:B -> foo:T
delta:B -> foo:T

all four edges would emanate from the bottom of their respective nodes, and would terminate at the top of node foo. Ideally the edge heads would be spaced evenly along the top of foo, and would appear in the same order that they would have appeared if 'B' had not been specified.

L and R would exhibit the same behavior but horizontally, which would be especially useful in a LR graph.

The fuzziness has advantages: the user avoids having to explicitly order the edges, avoids special cases for different numbers of edges, and isn't limited to three edges.
Owner: *
Status: *