Documented libavoid code example

libavoid is a C++ library. Its code is all within the Avoid:: namespace.

First, you must create an instance of the router.

Avoid::Router *router = new Avoid::Router(Avoid::PolyLineRouting);

To add a shape (obstacle) to the router, you first create a ShapeRef by giving the bounding box of the obstacle.

// Create the ShapeRef:
Avoid::Rectangle rectangle(Avoid::Point(20.0, 35.0), Avoid::Point(40.0, 12.0));
Avoid::ShapeRef *shapeRef = new Avoid::ShapeRef(router, rectangle);

or

Avoid::Polygon shapePoly(3);
shapePoly.ps[0] = Avoid::Point(1.0, 1.0);
shapePoly.ps[1] = Avoid::Point(2.5, 1.5);
shapePoly.ps[2] = Avoid::Point(1.5, 2.5);
Avoid::ShapeRef *shapeRef = new Avoid::ShapeRef(router, shapePoly);

The relevant prototypes (all in the Avoid namespace) are as follows. If a shape ID is specified, it should be non-zero and unique among all shapes and connectors.

Avoid::Rectangle(const Avoid::Point& topLeft, const Avoid::Point& bottomRight);
Avoid::Rectangle(const Avoid::Point& centre, const double width, const double height);
Avoid::ShapeRef(Avoid::Router *router, const Avoid::Polygon& polygon, unsigned int id = 0);

To actually add the shape to the router (and cause rerouting of connectors it intersects) you do the following:

router->addShape(shapeRef);

Conversely, to delete a shape from the router (and reroute connectors that then have a better path) you do the following.

router->removeShape(shapeRef);

To move or resize a shape already in the router, you do the following:

router->moveShape(shapeRef, newPolygon);

or

double xmove = 20, ymove = 15;
router->moveShape(shapeRef, xmove, ymove);

In its default mode the router will queue multiple shape movements and perform the changes to the visibility graph in an optimised order. Thus you make several calls to router->moveShape() for different shapes and then tell the router to process the moves. This tend to be useful in interactive applications where the user may move multiple shapes at once.

router->moveShape(shapeRef1, newPolygon1);
router->moveShape(shapeRef2, newPolygon2);
router->processTransaction();

To add a new connector to the router, you do the following:

Avoid::ConnEnd srcPt(Avoid::Point(1.2, 0.5));
Avoid::ConnEnd dstPt(Avoid::Point(3.0, 4.0));
Avoid::ConnRef *connRef = new Avoid::ConnRef(router, srcPt, dstPt);

To remove a connector from the router:

delete connRef;

You can set a function to be called when the connector needs to be redrawn. When called, this function will be passed the pointer given as a second argument to setCallback:

void connCallback(void *ptr)
{
    Avoid::ConnRef *connRef = (Avoid::ConnRef *) ptr;
    printf("Connector %u needs rerouting!\n", connRef->id());
}
connRef->setCallback(connCallback, connRef);

The callback will be triggered by movement, addition and deletion of shapes, as well as by adjustment of the connector endpoints, or by procressing a transaction that includes any of these events. You can check if a connector path has changed, and hence the object requires repainting (say because a better path is available due to a shape being deleted):

if (connRef->needsRepaint()) ...

If you want to trigger the callback for a connector after moving its endpoints (or when it is first created you can do this via:

connRef->processTransaction();

You can then get the new path as follows:

const Avoid::PolyLine route = connRef->dispayRoute();
for (size_t i = 0; i < route.size(); ++i) 
{
    Avoid::Point point = route.at(i);
    printf("%f, %f\n", point.x, point.y);
}

Obviously the alternative to using the callback mechanism is to iterate through all connectors and check their needsRepaint() value after having called processTransaction().

You can update the endpoints of a connector with:

Avoid::ConnEnd newSrcPt(Avoid::Point(6, 3));
Avoid::ConnEnd newDstPt(Avoid::Point(12, 67));
connRef->setEndpoints(newSrcPt, newDstPt);

or

Avoid::ConnEnd newSrcPt(Avoid::Point(6, 3));
connRef->setSourceEndpoint(newSrcPt);
Avoid::ConnEnd newDstPt(Avoid::Point(6, 3));
connRef->setDestEndpoint(newDstPt);

(Then ConnEnd type exists to allow connector ports later on!)

See also a short example: example.cpp in the libavoid/tests directory