微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Graphviz点,不同形状的自指箭头

如何解决Graphviz点,不同形状的自指箭头

我正在尝试制造一个具有某些环回某些节点的最终状态机。

digraph g{
      rankdir=TB;
      forcelabels=true;
      ranksep=1.5;
      pad=0.5;
      nodesep=2;
    
      node[shape=circle];
    
      A[label="Wait for call\n0 from above"];
      B[label="Wait for\nACK 0 || ACK 1"];
      E[label="Wait for call\n1 from above"];
      F[label="Wait for\nACk 2 || ACK 3"];
    
      C[label="Wait for ACK 0"];
      D[label="Wait for ACK 1"];
      G[label="Wait for ACK 2"];
      H[label="Wait for ACk 3"];
    
      A -> B[label=" rdt_send(data)  \n  sndpkt=make_pkt(0,data,checksum)  \n  udt_send(sndpkt)  \n  start_timer 1 and 2  \n"];
     
      B -> D[xlabel="  rdt_rcv(rcvpkt) && \n notcorrupt(rcvpkt) \n && isAck(rcvpkt,0)  \n  stop_timer 1"];
      B -> C[xlabel="  rdt_rcv(rcvpkt) && \n notcorrupt(rcvpkt) \n && isAck(rcvpkt,1)  \n  stop_timer 2"];
      C -> E[xlabel="  rdt_rcv(rcvpkt) && \n notcorrupt(rcvpkt) \n && isAck(rcvpkt,0)  \n  stop_timer 2"];
      D -> E[label= "  rdt_rcv(rcvpkt) && \n notcorrupt(rcvpkt) \n && isAck(rcvpkt,1)  \n  stop_timer 1"];
    
      C:nw -> C:nw[constraint=none,xlabel="PLACEHOLDER"];
      C:sw -> C:sw[constraint=none,xlabel="PLACEHOLDER"];
    
      D:ne -> D:ne[constraint=none,xlabel="PLACEHOLDER"];
      D:se -> D:se[constraint=none,xlabel="PLACEHOLDER"];
    
      E -> F[constraint=none,xlabel="  \n  rdt_send(data)  \n  sndpkt=make_pkt(1,checksum)  \n  udt_send(sndpkt)\n  start_timer "];
     
      F -> G[xlabel="  rdt_rcv(rcvpkt) \n  && notcorrupt(rcvpkt)  \n  && isAck(rcvpkt,3)  \n  stop_timer "];
      F -> H[xlabel="  rdt_rcv(rcvpkt) \n  && notcorrupt(rcvpkt)  \n  && isAck(rcvpkt,2)  \n  stop_timer "];
      G -> A[xlabel="  rdt_rcv(rcvpkt) \n  && notcorrupt(rcvpkt)  \n  && isAck(rcvpkt,3)  \n  stop_timer "];
      H -> A[xlabel="  rdt_rcv(rcvpkt) \n  && notcorrupt(rcvpkt)  \n  && isAck(rcvpkt,2)  \n  stop_timer "];
    
      G:sw -> G:sw[constraint=none,xlabel="PLACEHOLDER"];
      G:nw -> G:nw[constraint=none,xlabel="PLACEHOLDER"];
    
      H:se -> H:se[constraint=none,xlabel="PLACEHOLDER"];
      H:ne -> H:ne[constraint=none,xlabel="PLACEHOLDER"];
    
      A:w -> A:w[label="  rdt_rcv(rcvpkt)  \n  ᐱ"];
    
      B:n -> B:n[label="  rdt_rcv(rcvpkt)  \n  && corrupt(rcvpkt)  \n  ||  isAck(rcvpkt,1)  \n  ᐱ "];
      B:e -> B:e[label="  timeout  \n  udt_send(sndpkt)  \n  start_timer  \n "];
    
      E:e -> E:e[label="  rdt_rcv(rcvpkt)\nᐱ "];
    
      F:s -> F:s[label="  rdt_rcv(rcvpkt)  \n  && corrupt(rcvpkt)  \n  || isAck(rcvpkt,0)  \n  ᐱ "]; 
      F:w -> F:w[label="  timeout  \n  udt_send(sndpkt)  \n  start_timer "];
    
      {rank=same;A;B}
      {rank=same;C,D,G,H}
      {rank=same;E;F}
}

然后我使用命令

dot -Tsvg in.dot -o out.svg

这将生成以下图形

Graph

请注意四个中间节点上不同的环回边缘及其标签位置。即使我增加了nodesep属性,边缘也似乎被拉伸了。我如何有效地解决这个问题?

解决方法

令人惊讶的是,增加 nodesep 也会增加循环大小。
以下内容减少了 nodesep ,添加了一个不可见的节点(和2个边缘),并为(一些)边缘标签添加了一些空格。

digraph g{
  rankdir=TB;
  forcelabels=true;
  ranksep=1.5;
  pad=0.5;
  nodesep=1;  // was 2

  node[shape=circle];

  A[label="Wait for call\n0 from above"];
  B[label="Wait for\nACK 0 || ACK 1"];
  E[label="Wait for call\n1 from above"];
  F[label="Wait for\nACk 2 || ACK 3"];

  C[label="Wait for ACK 0"];
  D[label="Wait for ACK 1"];
  G[label="Wait for ACK 2"];
  H[label="Wait for ACk 3"];

  A -> B[label=" rdt_send(data)  \n  sndpkt=make_pkt(0,data,checksum)  \n  udt_send(sndpkt)  \n  start_timer 1 and 2  \n"];
 
  B -> D[xlabel="  rdt_rcv(rcvpkt) && \n notcorrupt(rcvpkt) \n && isAck(rcvpkt,0)  \n  stop_timer 1"];
  B -> C[xlabel="  rdt_rcv(rcvpkt) && \n notcorrupt(rcvpkt) \n && isAck(rcvpkt,1)  \n  stop_timer 2"];
  C -> E[xlabel="  rdt_rcv(rcvpkt) && \n notcorrupt(rcvpkt) \n && isAck(rcvpkt,0)  \n  stop_timer 2"];
  D -> E[label= "  rdt_rcv(rcvpkt) && \n notcorrupt(rcvpkt) \n && isAck(rcvpkt,1)  \n  stop_timer 1"];

  C:nw -> C:nw[constraint=none,xlabel="1PLACEHOLDER"];
  C:sw -> C:sw[constraint=none,xlabel="2PLACEHOLDER       "];  // spaces

  D:ne -> D:ne[constraint=none,xlabel="    3PLACEHOLDER"];     // spaces
  D:se -> D:se[constraint=none,xlabel="4PLACEHOLDER"];

  E -> F[constraint=none,xlabel="  \n  rdt_send(data)  \n  sndpkt=make_pkt(1,checksum)  \n  udt_send(sndpkt)\n  start_timer "];
 
  F -> G[xlabel="  rdt_rcv(rcvpkt) \n  && notcorrupt(rcvpkt)  \n  && isAck(rcvpkt,3)  \n  stop_timer "];
  F -> H[xlabel="  rdt_rcv(rcvpkt) \n  && notcorrupt(rcvpkt)  \n  && isAck(rcvpkt,2)  \n  stop_timer "];
  G -> A[xlabel="  rdt_rcv(rcvpkt) \n  && notcorrupt(rcvpkt)  \n  && isAck(rcvpkt,3)  \n  stop_timer "];
  H -> A[xlabel="  rdt_rcv(rcvpkt) \n  && notcorrupt(rcvpkt)  \n  && isAck(rcvpkt,2)  \n  stop_timer "];

  G:sw -> G:sw[constraint=none,xlabel="5PLACEHOLDER"];
  G:nw -> G:nw[constraint=none,xlabel="6PLACEHOLDER"];

  H:se -> H:se[constraint=none,xlabel="     7PLACEHOLDER"]; // spaces
  H:ne -> H:ne[constraint=none,xlabel="8PLACEHOLDER"];

  A:w -> A:w[label="  rdt_rcv(rcvpkt)  \n  ᐱ"];

  B:n -> B:n[label="  rdt_rcv(rcvpkt)  \n  && corrupt(rcvpkt)  \n  ||  isAck(rcvpkt,1)  \n  ᐱ "];
  B:e -> B:e[label="  timeout  \n  udt_send(sndpkt)  \n  start_timer  \n "];

  E:e -> E:e[label="  rdt_rcv(rcvpkt)\nᐱ "];

  F:s -> F:s[label="  rdt_rcv(rcvpkt)  \n  && corrupt(rcvpkt)  \n  || isAck(rcvpkt,0)  \n  ᐱ "]; 
  F:w -> F:w[label="  timeout  \n  udt_send(sndpkt)  \n  start_timer "];

  {rank=same;A;B}
  {rank=same;C,D,G,H   BOGUS[style=invis]}
  {rank=same;E;F}
  edge [style=invis]
  H -> BOGUS -> C

}

为此: enter image description here

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。