mjwybrow / adaptagrams

Libraries for constraint-based layout and connector routing for diagrams.
http://www.adaptagrams.org/
264 stars 81 forks source link

[question][libavoid] Help needed for configuring edge routing. #74

Open haxscramper opened 3 months ago

haxscramper commented 3 months ago

How to force libavoid edges to not overlap with the node body and to have some offset from rectangle nodes?

I have a small graph with several nodes and constraints, and I want to route the edges so they would not cross each other and overlap with the rectangles themselves.

Code from outputInstanceToSVG is under details, generated SVG image is:

adaptagrams_debug

When setting orthogonal routing for edge references and the router itself, I expected something closer to the image below (red lines show preferrable edge positions), but it looks like I'm missing some of the options but cannot figure out which ones exactly.

image

Specifically, I would really appreciate it if someone could point to

  1. Why setRoutingType(Avoid::ConnType::ConnType_Orthogonal) in the Avoid::ConnRef class does not force all edges to consist only of vertical/horizontal lines?
  2. How to force the edges to be attached to the border of the rectangles rather than to the center?
  3. If the edge is attached to the edge of the rectangle, it how to make it have some offset distance from the rectangle so it would not run perfectly parallel? Using ATTACH_POS_BOTTOM for the lower edge moves it around, but it is not clear how to make it have a [-shape. image
```cpp #include "libavoid/libavoid.h" using namespace Avoid; int main(void) { Router *router = new Router(PolyLineRouting | OrthogonalRouting); router->setRoutingParameter((RoutingParameter)0, 50); router->setRoutingParameter((RoutingParameter)1, 0); router->setRoutingParameter((RoutingParameter)2, 0); router->setRoutingParameter((RoutingParameter)3, 4000); router->setRoutingParameter((RoutingParameter)4, 110); router->setRoutingParameter((RoutingParameter)5, 0); router->setRoutingParameter((RoutingParameter)6, 0); router->setRoutingParameter((RoutingParameter)7, 4); router->setRoutingParameter((RoutingParameter)8, 0); router->setRoutingOption((RoutingOption)0, true); router->setRoutingOption((RoutingOption)1, true); router->setRoutingOption((RoutingOption)2, false); router->setRoutingOption((RoutingOption)3, false); router->setRoutingOption((RoutingOption)4, true); router->setRoutingOption((RoutingOption)5, false); router->setRoutingOption((RoutingOption)6, true); Polygon polygon; ConnRef *connRef = nullptr; ConnEnd srcPt; ConnEnd dstPt; ConnEnd heConnPt; PolyLine newRoute; ShapeConnectionPin *connPin = nullptr; // shapeRef14 polygon = Polygon(4); polygon.ps[0] = Point(-306.143, -223.138); polygon.ps[1] = Point(-206.143, -223.138); polygon.ps[2] = Point(-206.143, -323.138); polygon.ps[3] = Point(-306.143, -323.138); ShapeRef *shapeRef14 = new ShapeRef(router, polygon, 14); connPin = new ShapeConnectionPin(shapeRef14, 2, 0.5, 0.5, true, 0, (ConnDirFlags)0); // shapeRef15 polygon = Polygon(4); polygon.ps[0] = Point(-306.143, 70.7384); polygon.ps[1] = Point(-206.143, 70.7384); polygon.ps[2] = Point(-206.143, -29.2616); polygon.ps[3] = Point(-306.143, -29.2616); ShapeRef *shapeRef15 = new ShapeRef(router, polygon, 15); connPin = new ShapeConnectionPin(shapeRef15, 2, 0.5, 0.5, true, 0, (ConnDirFlags)0); connPin = new ShapeConnectionPin(shapeRef15, 3, 0.5, 0.5, true, 0, (ConnDirFlags)0); // shapeRef16 polygon = Polygon(4); polygon.ps[0] = Point(78.4782, -20.6001); polygon.ps[1] = Point(178.478, -20.6001); polygon.ps[2] = Point(178.478, -120.6); polygon.ps[3] = Point(78.4782, -120.6); ShapeRef *shapeRef16 = new ShapeRef(router, polygon, 16); connPin = new ShapeConnectionPin(shapeRef16, 3, 0.5, 0.5, true, 0, (ConnDirFlags)0); connPin = new ShapeConnectionPin(shapeRef16, 4, 0.5, 0.5, true, 0, (ConnDirFlags)0); // shapeRef17 polygon = Polygon(4); polygon.ps[0] = Point(78.4782, 315.454); polygon.ps[1] = Point(178.478, 315.454); polygon.ps[2] = Point(178.478, 215.454); polygon.ps[3] = Point(78.4782, 215.454); ShapeRef *shapeRef17 = new ShapeRef(router, polygon, 17); connPin = new ShapeConnectionPin(shapeRef17, 4, 0.5, 0.5, true, 0, (ConnDirFlags)0); connPin = new ShapeConnectionPin(shapeRef17, 5, 0.5, 0.5, true, 0, (ConnDirFlags)0); // shapeRef18 polygon = Polygon(4); polygon.ps[0] = Point(-30.856, 315.454); polygon.ps[1] = Point(69.144, 315.454); polygon.ps[2] = Point(69.144, 215.454); polygon.ps[3] = Point(-30.856, 215.454); ShapeRef *shapeRef18 = new ShapeRef(router, polygon, 18); connPin = new ShapeConnectionPin(shapeRef18, 5, 0.5, 0.5, true, 0, (ConnDirFlags)0); connPin = new ShapeConnectionPin(shapeRef18, 6, 0.5, 0.5, true, 0, (ConnDirFlags)0); // shapeRef19 polygon = Polygon(4); polygon.ps[0] = Point(336.413, 315.454); polygon.ps[1] = Point(436.413, 315.454); polygon.ps[2] = Point(436.413, 215.454); polygon.ps[3] = Point(336.413, 215.454); ShapeRef *shapeRef19 = new ShapeRef(router, polygon, 19); connPin = new ShapeConnectionPin(shapeRef19, 6, 0.5, 0.5, true, 0, (ConnDirFlags)0); // connRef7 connRef = new ConnRef(router, 7); srcPt = ConnEnd(shapeRef14, 2); connRef->setSourceEndpoint(srcPt); dstPt = ConnEnd(shapeRef15, 2); connRef->setDestEndpoint(dstPt); connRef->setRoutingType((ConnType)2); // connRef8 connRef = new ConnRef(router, 8); srcPt = ConnEnd(shapeRef15, 3); connRef->setSourceEndpoint(srcPt); dstPt = ConnEnd(shapeRef16, 3); connRef->setDestEndpoint(dstPt); connRef->setRoutingType((ConnType)2); // connRef9 connRef = new ConnRef(router, 9); srcPt = ConnEnd(shapeRef16, 4); connRef->setSourceEndpoint(srcPt); dstPt = ConnEnd(shapeRef17, 4); connRef->setDestEndpoint(dstPt); connRef->setRoutingType((ConnType)2); // connRef10 connRef = new ConnRef(router, 10); srcPt = ConnEnd(shapeRef17, 5); connRef->setSourceEndpoint(srcPt); dstPt = ConnEnd(shapeRef18, 5); connRef->setDestEndpoint(dstPt); connRef->setRoutingType((ConnType)2); // connRef11 connRef = new ConnRef(router, 11); srcPt = ConnEnd(shapeRef18, 6); connRef->setSourceEndpoint(srcPt); dstPt = ConnEnd(shapeRef19, 6); connRef->setDestEndpoint(dstPt); connRef->setRoutingType((ConnType)2); router->processTransaction(); router->outputInstanceToSVG("orthogonalOpt2"); delete router; return 0; }; ```
Aksem commented 1 week ago

In shape connection pin intsantiation you have new ShapeConnectionPin(shapeRef14, 2, 0.5, 0.5, true, 0, (ConnDirFlags)0); third and fourth values are X and Y position of your pin. And fifth means relative or absolute. 0.5, 0.5, true, means relative position 0.5 of shape width from left, 0.5 of shape height from the top.

One possible solution would be to create a pin on each side of shape with positions (0.5, 0, true), (1, 0.5, true), (0.5, 1, true), (0, 0.5, true). Or if shape sides, where pins should be, are known in advance, keep only those pins.

Feel free to ask further questions in my actively maintained fork of adaptagrams: https://github.com/Aksem/adaptagrams/issues even if you use original adaptagrams version.