# Regarding graphviz's "orthogonal" edge routing

**URL:** <https://forum.graphviz.org/t/regarding-graphvizs-orthogonal-edge-routing/1889>\
**Category:** Help\
**Created:** [November 22, 2023, 3:56pm UTC](https://forum.graphviz.org/t/regarding-graphvizs-orthogonal-edge-routing/1889 "2023-11-22T15:56:13Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![aanastasiou](https://sea2.discourse-cdn.com/graphviz/user_avatar/forum.graphviz.org/aanastasiou/32/1246_2.png) [@aanastasiou](https://forum.graphviz.org/u/aanastasiou)\
**Post date:** [November 22, 2023, 3:56pm UTC](https://forum.graphviz.org/t/regarding-graphvizs-orthogonal-edge-routing/1889/1 "2023-11-22T15:56:13Z")

</div>

This is probably the n^{th} time this question is asked here, but having browsed previous responses, I could not confirm exactly what I am after.

Consider the following simple graph:

```auto
digraph{
    rankdir=TB
    node [shape=box]
    a -> b
    a -> c
    b -> c
    b -> d
    c -> d
    c -> e
    d -> a
}

```

If we pass it through `dot` we get [a very nice depiction](https://dreampuf.github.io/GraphvizOnline/#digraph%7B%0A%20%20%20%20rankdir%3DTB%0A%20%20%20%20node%20%5Bshape%3Dbox%5D%0A%20%20%20%20a%20-%3E%20b%0A%20%20%20%20a%20-%3E%20c%0A%20%20%20%20b%20-%3E%20c%0A%20%20%20%20b%20-%3E%20d%0A%20%20%20%20c%20-%3E%20d%0A%20%20%20%20c%20-%3E%20e%0A%20%20%20%20d%20-%3E%20a%0A%7D) of it.

There are only two “problems” with it:

1. In certain domains, the spline routing is not really attractive (visually).
2. The edges do not depart from the same point on a given node.

Would it be possible to confirm (or -quite happily- refute) that as things stand these two characteristics are _incompatible_?

I can have edges start from the same point on each box [like this](https://dreampuf.github.io/GraphvizOnline/#digraph%7B%0A%20%20%20%20rankdir%3DTB%0A%20%20%20%20node%20%5Bshape%3Dbox%5D%0A%20%20%20%20a%3As%20-%3E%20b%0A%20%20%20%20a%3As%20-%3E%20c%0A%20%20%20%20b%3As%20-%3E%20c%3An%0A%20%20%20%20b%3As%20-%3E%20d%3An%0A%20%20%20%20c%3As%20-%3E%20d%3An%0A%20%20%20%20c%3As%20-%3E%20e%3An%0A%20%20%20%20d%3An%20-%3E%20a%3As%0A%7D)…

…but, when I choose orthogonal edges by `splines="ortho"`, [all hell breaks loose](https://dreampuf.github.io/GraphvizOnline/#digraph%7B%0A%20%20%20%20splines%3D%22ortho%22%0A%20%20%20%20rankdir%3DTB%0A%20%20%20%20node%20%5Bshape%3Dbox%5D%0A%20%20%20%20a%3As%20-%3E%20b%0A%20%20%20%20a%3As%20-%3E%20c%0A%20%20%20%20b%3As%20-%3E%20c%3An%0A%20%20%20%20b%3As%20-%3E%20d%3An%0A%20%20%20%20c%3As%20-%3E%20d%3An%0A%20%20%20%20c%3As%20-%3E%20e%3An%0A%20%20%20%20d%3An%20-%3E%20a%3As%0A%7D) and in a way that seems “irreparable”. That is, neither `splines=false` works (because then the edges are simply straight and go over nodes), neither putting the edges in the `sametail, samehead` group works.

If it is not possible to do orthogonal routing **and** have the edges start and end at a particular port on two given nodes, is it possible to at least have the edges not “invade” the node’s shape?

---

<div class="post-metadata">

**Author:** ![steveroush](https://avatars.discourse-cdn.com/v4/letter/s/a9adbd/32.png) [@steveroush](https://forum.graphviz.org/u/steveroush)\
**Post date:** [November 22, 2023, 6:14pm UTC](https://forum.graphviz.org/t/regarding-graphvizs-orthogonal-edge-routing/1889/2 "2023-11-22T18:14:58Z")

</div>

Yes, **splines=ortho** fails miserably if ports are specified (see  
[spline = ortho produces unexpected output with ports (#1415) · Issues · graphviz / graphviz · GitLab](https://gitlab.com/graphviz/graphviz/-/issues/1415)).  
**splines=ortho** does OK if ports are not specified (see below) - node placement usually works but the port chosen by “ortho” is not always “best” and the edge route is sometimes “suboptimal”.  
Your input without ports:

```auto
digraph{
    splines="ortho"
    rankdir=TB
    node [shape=box]
    a -> b
    a -> c
    b -> c
    b -> d
    c -> d
    c -> e
    d -> a
}

```

Giving:  
 ![alterTest99a](https://global.discourse-cdn.com/graphviz/original/2X/6/6de10c96e2b7b83d942421488e8617c95dc0af85.png)

---

<div class="post-metadata">

**Author:** ![erg](https://sea2.discourse-cdn.com/graphviz/user_avatar/forum.graphviz.org/erg/32/34_2.png) [@erg](https://forum.graphviz.org/u/erg)\
**Post date:** [November 24, 2023, 5:41pm UTC](https://forum.graphviz.org/t/regarding-graphvizs-orthogonal-edge-routing/1889/3 "2023-11-24T17:41:42Z")

</div>

Orthogonal routing works well for vanilla graphs. However, various important features can’t be handled. These include ports, compass points, and edge labels. I spent a lot of time trying to handle these but could never figure out how to tweak the code. Other orthogonal routing algorithms didn’t seem to help either. I view this as a major hole in the Graphviz code base and would love someone to tackle this, even if it involved tossing out the current algorithm entirely.

On a related point, I know there is a bug in the orthogonal code where a count determined analytically seems to undercount. This can be patched by using a gross overcount but it would be nice to figure out why the “provably” correct analytic count gives the wrong answer. Unlike the previous problem, this one can probably be handled by just sitting down and giving it some thought.

---

<div class="post-metadata">

**Author:** ![aanastasiou](https://sea2.discourse-cdn.com/graphviz/user_avatar/forum.graphviz.org/aanastasiou/32/1246_2.png) [@aanastasiou](https://forum.graphviz.org/u/aanastasiou)\
**Post date:** [November 27, 2023, 5:05pm UTC](https://forum.graphviz.org/t/regarding-graphvizs-orthogonal-edge-routing/1889/4 "2023-11-27T17:05:36Z")

</div>

Great, thank you. At least it’s confirmed 🙂

---

<div class="post-metadata">

**Author:** ![aanastasiou](https://sea2.discourse-cdn.com/graphviz/user_avatar/forum.graphviz.org/aanastasiou/32/1246_2.png) [@aanastasiou](https://forum.graphviz.org/u/aanastasiou)\
**Post date:** [November 27, 2023, 5:43pm UTC](https://forum.graphviz.org/t/regarding-graphvizs-orthogonal-edge-routing/1889/5 "2023-11-27T17:43:48Z")

</div>

Hello @erg and thank you for the overview.

I am not familiar with graphviz’s codebase and neither other orthogonal routing algorithms.

All of my experience with routing is from a piece of software I wrote some years ago to visualise the way different digital signal processing blocks get connected in a given “circuit”.

From this limited viewpoint, I feel that fixing the start and stop “conditions” of departure and arrival tend to make the problem easier. Therefore, to me it sounds a bit “strange” that ports, compass points and edge labels are difficult to handle. But again, I may be thinking of low order and size graphs and not all of the details surrounding graphviz.

What I used to do is this:

- The algorithm is given two points A,B that have to be connected with straight lines.

- In my case, almost always, A was a black box’ output port and B was another black box’ input port. My operators always had N inputs but only 1 output and therefore, appeared fixed on the left (inputs) and right (outputs) side of a given black box. But this does not really matter. It is possible to work out compass point directions given the relative positions of A,B. The bottom line is that there is a way by which it is possible to determine the start and stop points of an orthogonal edge.

- Since the routing was “from an output to an input”, my departure was always “from east (on A) to west (on B)”. The lines were drawn with a succession of DrawHorizontal, DrawVertical operations.

- Suppose that we only have two black boxes U,V connected with an edge. U’s output feeds V’s input and U precedes V (in layout). The first DrawHorizontal operation would try to put a line from U.x to V.x and the subsequent DrawVertical operation would try to put a line from the intermediate point that was formed by the preceding DrawHorizontal to V.y.

- If nothing is in the way this results in a very straightforward orthogonal routing between U,V by first trying to “bring” the x point from the one of the output to the one of the input and then do the same “transition” for the y point.

- If after a given DrawHorizontal, DrawVertical a line segment was going though another black box (let’s call it Q), then the line would be drawn to the periphery of Q, stop there and re-trigger an orthogonal connection from that intermediate point to its final destination.

(I am glossing over a couple of constants that the system used. For example, how far the line stops from an intersecting box before it re-triggers a connection but these are details).

For me, this was a simple enough scheme that resulted in reasonable routings. It was even straightforward to “guess” where I should draw a bus based on the proximity of nearby vertical or horizontal edges.

I did not handle node layout because the user could re-position each black box separately on the user interface.

I will post a screenshot once I get the dependencies for that project re-instated.

If this sounds simple enough and potentially useful for someone with enough knowledge of the graphviz codebase to produce an example, then, please, give it a go.

---

<div class="post-metadata">

**Author:** ![aanastasiou](https://sea2.discourse-cdn.com/graphviz/user_avatar/forum.graphviz.org/aanastasiou/32/1246_2.png) [@aanastasiou](https://forum.graphviz.org/u/aanastasiou)\
**Post date:** [November 29, 2023, 5:02pm UTC](https://forum.graphviz.org/t/regarding-graphvizs-orthogonal-edge-routing/1889/6 "2023-11-29T17:02:54Z")

</div>

Hello

Please ignore colours and styling, this is to demonstrate the routing I am outlining above:

A three tap filter:

 ![image](https://global.discourse-cdn.com/graphviz/original/2X/7/7db1c82b380aa69ebc5e9c8841bbf2d060b6c00d.png)

Relative positioning and how it is resolved:

Straightforward:  
 ![image](https://global.discourse-cdn.com/graphviz/original/2X/9/92080cc4539f174a6d9b5cc569015f5b725e5290.png)

At different vertical positions:

![image](https://global.discourse-cdn.com/graphviz/original/2X/b/b6f88fba6c9b321c4382a2baa9e682c46dca3352.png)

![image](https://global.discourse-cdn.com/graphviz/original/2X/6/6414c9b65c86ebb5bbc8124b7ded16719da60bd9.png)

Routing when the element itself is the “obstacle”:

![image](https://global.discourse-cdn.com/graphviz/original/2X/9/976a1c5de009f3a5dd7906b81bf8964d7c349e1b.png)

Routing completely backwards:  
 ![image](https://global.discourse-cdn.com/graphviz/original/2X/4/4f99c466c8ef59b8a7290b06ca74588a346c46ea.png)

Inserting an obstacle on purpose:

Before:  
 ![image](https://global.discourse-cdn.com/graphviz/original/2X/a/a2685a25723adc3a9e5729e58f0f38d993a77183.png)

After:

![image](https://global.discourse-cdn.com/graphviz/original/2X/e/eebab858f5e8d54cf5117ef007f56b3bea32c952.png)

Inserting multiple obstacles on purpose:

Before:

 ![image](https://global.discourse-cdn.com/graphviz/original/2X/0/036267d19fedf369816b1f880d9fca02b0f8a273.png)

Intercepting the “up branch”:

 ![image](https://global.discourse-cdn.com/graphviz/original/2X/1/189d935ba2de9a7622a2b9ac8846d7c54f8cfbd9.png)

(Hit a limit of 10 items as it seems)

…

---

<div class="post-metadata">

**Author:** ![aanastasiou](https://sea2.discourse-cdn.com/graphviz/user_avatar/forum.graphviz.org/aanastasiou/32/1246_2.png) [@aanastasiou](https://forum.graphviz.org/u/aanastasiou)\
**Post date:** [November 29, 2023, 5:03pm UTC](https://forum.graphviz.org/t/regarding-graphvizs-orthogonal-edge-routing/1889/7 "2023-11-29T17:03:34Z")

</div>

…

Intercepting the “right branch”:

 ![image](https://global.discourse-cdn.com/graphviz/original/2X/8/87b4f20c87317d3463f86f8a606b2aa4c3039f07.png)

Intercepting the top branch again:

 ![image](https://global.discourse-cdn.com/graphviz/original/2X/d/dbce3f07414e9454d78e94f9a6a7da6357aeccf9.png)

This is a C++ project and the edge routing can be extracted relatively easily (It is composed of three functions).

All the best
