void removeoverlaps(vpsc::Rectangles &rs, bool bothaxes) { double xBorder=0, yBorder=0; static const double EXTRA_GAP=1e-5; unsigned n=rs.size(); try { // The extra gap avoids numerical imprecision problems Rectangle::setXBorder(xBorder+EXTRA_GAP); Rectangle::setYBorder(yBorder+EXTRA_GAP); vpsc::Variables vs(n); unsigned i=0; for(Variables::iterator v=vs.begin();v!=vs.end();++v,++i) { *v=new Variable(i,0,1); } vpsc::Constraints cs; vpsc::generateXConstraints(rs,vs,cs,bothaxes); vpsc::IncSolver vpsc_x(vs,cs); vpsc_x.solve(); vpsc::Rectangles::iterator r=rs.begin(); for(Variables::iterator v=vs.begin();v!=vs.end();++v,++r) { assert((*v)->finalPosition==(*v)->finalPosition); (*r)->moveCentreX((*v)->finalPosition); } assert(r==rs.end()); for_each(cs.begin(),cs.end(),vpsc::delete_object()); cs.clear(); if(bothaxes) { // Removing the extra gap here ensures things that were moved to be adjacent to one another above are not considered overlapping Rectangle::setXBorder(Rectangle::xBorder-EXTRA_GAP); vpsc::generateYConstraints(rs,vs,cs); vpsc::IncSolver vpsc_y(vs,cs); vpsc_y.solve(); r=rs.begin(); for(Variables::iterator v=vs.begin();v!=vs.end();++v,++r) { (*r)->moveCentreY((*v)->finalPosition); } for_each(cs.begin(),cs.end(),vpsc::delete_object()); cs.clear(); Rectangle::setYBorder(Rectangle::yBorder-EXTRA_GAP); vpsc::generateXConstraints(rs,vs,cs,false); vpsc::IncSolver vpsc_x2(vs,cs); vpsc_x2.solve(); r=rs.begin(); for(Variables::iterator v=vs.begin();v!=vs.end();++v,++r) { (*r)->moveCentreX((*v)->finalPosition); } for_each(cs.begin(),cs.end(),vpsc::delete_object()); } for_each(vs.begin(),vs.end(),vpsc::delete_object()); } catch (char *str) { std::cerr<<str<<std::endl; for(vpsc::Rectangles::iterator r=rs.begin();r!=rs.end();++r) { std::cerr << **r <<std::endl; } } Rectangle::setXBorder(xBorder); Rectangle::setYBorder(yBorder); }
/* * Make feasible: * - remove overlaps between rectangular boundaries of nodes/clusters * (respecting structural constraints) * - perform routing (preserve previous topology using rubber banding) */ void makeFeasible(vpsc::Rectangles& rs, vector<cola::Edge>& edges, std::vector<topology::Edge*>& routes, std::vector<topology::Node*>& topologyNodes, double defaultEdgeLength) { printf("Removing overlaps...\n"); removeoverlaps(rs,false); printf("done.\n"); printf("Running libavoid to compute routes...\n"); clock_t libavoidstarttime=clock(); // find feasible routes for edges Avoid::Router *router = new Avoid::Router(Avoid::PolyLineRouting); // Use rotational sweep for point visibility router->UseLeesAlgorithm = true; // Don't use invisibility graph. router->InvisibilityGrph = false; double g=0; // make shape that libavoid sees slightly smaller for(unsigned i=0;i<rs.size();++i) { vpsc::Rectangle* r=rs[i]; double x=r->getMinX()+g; double X=r->getMaxX()-g; double y=r->getMinY()+g; double Y=r->getMaxY()-g; // Create the ShapeRef: Avoid::Polygon shapePoly(4); // AntiClockwise! shapePoly.ps[0] = Avoid::Point(X,y); shapePoly.ps[1] = Avoid::Point(X,Y); shapePoly.ps[2] = Avoid::Point(x,Y); shapePoly.ps[3] = Avoid::Point(x,y); //if(i==4||i==13||i==9) { //printf("rect[%d]:{%f,%f,%f,%f}\n",i,x,y,X,Y); //} unsigned int shapeID = i + 1; Avoid::ShapeRef *shapeRef = new Avoid::ShapeRef(router, shapePoly, shapeID); // ShapeRef constructor makes a copy of polygon so we can free it: //router->addShape(shapeRef); // FIXME } for(unsigned i=0;i<edges.size();++i) { cola::Edge e=edges[i]; Avoid::ConnRef *connRef; unsigned int connID = i + rs.size() + 1; Rectangle* r0=rs[e.first], *r1=rs[e.second]; Avoid::Point srcPt(r0->getCentreX(),r0->getCentreY()); Avoid::Point dstPt(r1->getCentreX(),r1->getCentreY()); connRef = new Avoid::ConnRef(router, srcPt, dstPt, connID); router->processTransaction(); const Avoid::Polygon& route = connRef->route(); vector<topology::EdgePoint*> eps; eps.push_back( new topology::EdgePoint( topologyNodes[e.first], topology::EdgePoint::CENTRE)); for(size_t j=1;j+1<route.size();j++) { const Avoid::Point& p = route.ps[j]; const unsigned nodeID=p.id-1; topology::Node* node=topologyNodes[nodeID]; topology::EdgePoint::RectIntersect ri; switch(p.vn) { case 0: ri=topology::EdgePoint::BR; break; case 1: ri=topology::EdgePoint::TR; break; case 2: ri=topology::EdgePoint::TL; break; case 3: ri=topology::EdgePoint::BL; break; default: ri=topology::EdgePoint::CENTRE; } eps.push_back(new topology::EdgePoint(node,ri)); } eps.push_back(new topology::EdgePoint(topologyNodes[e.second], topology::EdgePoint::CENTRE)); topology::Edge* edgeRoute=new topology::Edge(i,defaultEdgeLength, eps); edgeRoute->assertConvexBends(); routes.push_back(edgeRoute); } writeFile(topologyNodes,routes,"beautify0.svg"); assert(topology::assertNoSegmentRectIntersection(topologyNodes,routes)); double libavoidtime=double(clock()-libavoidstarttime)/double(CLOCKS_PER_SEC); cout << "done. Libavoid ran in " << libavoidtime << " seconds" << endl; delete router; }
void ColaTopologyAddon::makeFeasible(bool generateNonOverlapConstraints, vpsc::Rectangles& boundingBoxes, cola::RootCluster* clusterHierarchy) { if (generateNonOverlapConstraints) { // Set up topologyNodes: unsigned nodesTotal = boundingBoxes.size(); topologyNodes = topology::Nodes(nodesTotal); for (unsigned id = 0; id < nodesTotal; ++id) { topologyNodes[id] = new topology::Node(id, boundingBoxes[id]); } } if (clusterHierarchy) { // create cluster boundaries unsigned clusterCount=0; for (std::vector<cola::Cluster*>::iterator i = clusterHierarchy->clusters.begin(); i != clusterHierarchy->clusters.end(); ++i, ++clusterCount) { (*i)->computeBoundary(boundingBoxes); cola::ConvexCluster* c=dynamic_cast<cola::ConvexCluster*>(*i); if(c!=NULL) { double idealCircumference=2.0*sqrt(M_PI*c->area(boundingBoxes)); std::vector<topology::EdgePoint*> eps; for(unsigned j=0;j<c->hullRIDs.size();++j) { const unsigned id = c->nodes[c->hullRIDs[j]]; const unsigned char corner = c->hullCorners[j]; COLA_ASSERT(id < topologyNodes.size()); //cout << "addToPath(vs[" << id << "],"; topology::Node *node= topologyNodes[id]; topology::EdgePoint::RectIntersect ri; switch(corner) { case 0: ri=topology::EdgePoint::BR; //cout << "EdgePoint::BR);" << endl; break; case 1: ri=topology::EdgePoint::TR; //cout << "EdgePoint::TR);" << endl; break; case 2: ri=topology::EdgePoint::TL; //cout << "EdgePoint::TL);" << endl; break; default: COLA_ASSERT(corner==3); ri=topology::EdgePoint::BL; //cout << "EdgePoint::BL);" << endl; break; } eps.push_back(new topology::EdgePoint(node,ri)); } eps.push_back(eps[0]); //cout << "addToPath(vs[" << eps[0]->node->id << "],(EdgePoint::RectIntersect)"<<eps[0]->rectIntersect<<");" << endl; topology::Edge* e = new topology::Edge(clusterCount,idealCircumference, eps); topologyRoutes.push_back(e); } } } }