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