@@ -1316,32 +1316,131 @@ void DbNetDescriptor::findPath(NodeMap& graph,
13161316 }
13171317}
13181318
1319- std::set<odb::Line> DbNetDescriptor::convertGuidesToLines (odb::dbNet* net) const
1319+ void DbNetDescriptor::findPath (PointMap& graph,
1320+ const odb::Point& source,
1321+ const odb::Point& sink,
1322+ std::vector<odb::Point>& path) const
1323+ {
1324+ // find path from source to sink using A*
1325+ // https://en.wikipedia.org/w/index.php?title=A*_search_algorithm&oldid=1050302256
1326+
1327+ auto distance = [](const odb::Point& node0, const odb::Point& node1) -> int {
1328+ return odb::Point::manhattanDistance (node0, node1);
1329+ };
1330+
1331+ std::map<odb::Point, odb::Point> came_from;
1332+ std::map<odb::Point, int > g_score;
1333+ std::map<odb::Point, int > f_score;
1334+
1335+ struct DistNode
1336+ {
1337+ odb::Point node;
1338+ int dist;
1339+
1340+ public:
1341+ // used for priority queue
1342+ bool operator <(const DistNode& other) const { return dist > other.dist ; }
1343+ };
1344+ std::priority_queue<DistNode> open_set;
1345+ std::set<odb::Point> open_set_nodes;
1346+ const int source_sink_dist = distance (source, sink);
1347+ open_set.push ({source, source_sink_dist});
1348+ open_set_nodes.insert (source);
1349+
1350+ for (const auto & [node, nodes] : graph) {
1351+ g_score[node] = std::numeric_limits<int >::max ();
1352+ f_score[node] = std::numeric_limits<int >::max ();
1353+ }
1354+ g_score[source] = 0 ;
1355+ f_score[source] = source_sink_dist;
1356+
1357+ while (!open_set.empty ()) {
1358+ auto current = open_set.top ().node ;
1359+
1360+ open_set.pop ();
1361+ open_set_nodes.erase (current);
1362+
1363+ if (current == sink) {
1364+ // build path
1365+ while (current != source) {
1366+ path.emplace_back (current);
1367+ current = came_from[current];
1368+ }
1369+ path.emplace_back (current);
1370+ return ;
1371+ }
1372+
1373+ const int current_g_score = g_score[current];
1374+ for (const auto & neighbor : graph[current]) {
1375+ const int possible_g_score
1376+ = current_g_score + distance (current, neighbor);
1377+ if (possible_g_score < g_score[neighbor]) {
1378+ const int new_f_score = possible_g_score + distance (neighbor, sink);
1379+ came_from[neighbor] = current;
1380+ g_score[neighbor] = possible_g_score;
1381+ f_score[neighbor] = new_f_score;
1382+
1383+ if (open_set_nodes.find (neighbor) == open_set_nodes.end ()) {
1384+ open_set.push ({neighbor, new_f_score});
1385+ open_set_nodes.insert (neighbor);
1386+ }
1387+ }
1388+ }
1389+ }
1390+ }
1391+
1392+ std::set<odb::Line> DbNetDescriptor::convertGuidesToLines (
1393+ odb::dbNet* net,
1394+ DbTargets& sources,
1395+ DbTargets& sinks) const
13201396{
1397+ sources.clear ();
1398+ sinks.clear ();
1399+
13211400 auto guides = net->getGuides ();
13221401 if (guides.empty ()) {
13231402 return {};
13241403 }
13251404
13261405 std::set<odb::Line> lines;
13271406
1407+ struct DbIO
1408+ {
1409+ bool is_sink;
1410+ bool is_source;
1411+ };
1412+ std::map<odb::dbObject*, DbIO> io_map;
1413+
13281414 std::map<odb::dbTechLayer*, std::map<odb::dbObject*, std::set<odb::Rect>>>
13291415 terms;
13301416 for (odb::dbITerm* term : net->getITerms ()) {
13311417 if (!term->getInst ()->isPlaced ()) {
13321418 continue ;
13331419 }
1420+ const auto iotype = term->getIoType ();
1421+ const bool is_sink
1422+ = iotype == odb::dbIoType::INPUT || iotype == odb::dbIoType::INOUT;
1423+ const bool is_source
1424+ = iotype == odb::dbIoType::OUTPUT || iotype == odb::dbIoType::INOUT;
1425+ io_map[term] = {is_sink, is_source};
13341426 for (const auto & [layer, itermbox] : term->getGeometries ()) {
13351427 terms[layer][term].insert (itermbox);
13361428 }
13371429 }
13381430 for (odb::dbBTerm* term : net->getBTerms ()) {
1431+ const auto iotype = term->getIoType ();
1432+ const bool is_sink
1433+ = iotype == odb::dbIoType::OUTPUT || iotype == odb::dbIoType::INOUT;
1434+ const bool is_source
1435+ = iotype == odb::dbIoType::INPUT || iotype == odb::dbIoType::INOUT;
1436+ io_map[term] = {is_sink, is_source};
1437+
13391438 for (odb::dbBPin* pin : term->getBPins ()) {
13401439 if (!pin->getPlacementStatus ().isPlaced ()) {
13411440 continue ;
13421441 }
13431442 for (odb::dbBox* box : pin->getBoxes ()) {
1344- terms[box->getTechLayer ()][pin ].insert (box->getBox ());
1443+ terms[box->getTechLayer ()][term ].insert (box->getBox ());
13451444 }
13461445 }
13471446 }
@@ -1374,7 +1473,9 @@ std::set<odb::Line> DbNetDescriptor::convertGuidesToLines(odb::dbNet* net) const
13741473 if (guide->isConnectedToTerm ()) {
13751474 std::vector<odb::Point> anchors = {p0, center, p1};
13761475
1377- auto draw_term_connection = [&anchors, &lines](const odb::Point& term) {
1476+ auto find_term_connection = [&anchors, &lines, &io_map, &sources, &sinks](
1477+ odb::dbObject* dbterm,
1478+ const odb::Point& term) {
13781479 // draw shortest flywire
13791480 std::stable_sort (anchors.begin (),
13801481 anchors.end (),
@@ -1383,6 +1484,12 @@ std::set<odb::Line> DbNetDescriptor::convertGuidesToLines(odb::dbNet* net) const
13831484 < odb::Point::manhattanDistance (term, pt1);
13841485 });
13851486 lines.emplace (term, anchors[0 ]);
1487+ if (io_map[dbterm].is_sink ) {
1488+ sinks[dbterm].insert (term);
1489+ }
1490+ if (io_map[dbterm].is_source ) {
1491+ sources[dbterm].insert (term);
1492+ }
13861493 };
13871494
13881495 for (const auto & [obj, objbox] : terms[guide->getLayer ()]) {
@@ -1392,16 +1499,16 @@ std::set<odb::Line> DbNetDescriptor::convertGuidesToLines(odb::dbNet* net) const
13921499 candidates.push_back (&termbox);
13931500 }
13941501 }
1395- bool drawn = false ;
1502+ bool found = false ;
13961503 for (const auto * termbox : candidates) {
13971504 if (termbox->overlaps (box)) {
1398- draw_term_connection ( termbox->center ());
1399- drawn = true ;
1505+ find_term_connection (obj, termbox->center ());
1506+ found = true ;
14001507 break ;
14011508 }
14021509 }
1403- if (!drawn && !candidates.empty ()) {
1404- draw_term_connection ( candidates[0 ]->center ());
1510+ if (!found && !candidates.empty ()) {
1511+ find_term_connection (obj, candidates[0 ]->center ());
14051512 }
14061513 }
14071514 }
@@ -1410,6 +1517,44 @@ std::set<odb::Line> DbNetDescriptor::convertGuidesToLines(odb::dbNet* net) const
14101517 return lines;
14111518}
14121519
1520+ void DbNetDescriptor::drawPathSegmentWithGuides (
1521+ const std::set<odb::Line>& lines,
1522+ DbTargets& sources,
1523+ DbTargets& sinks,
1524+ const odb::dbObject* sink,
1525+ Painter& painter) const
1526+ {
1527+ PointMap pointmap;
1528+ for (const auto & line : lines) {
1529+ pointmap[line.pt0 ()].insert (line.pt1 ());
1530+ pointmap[line.pt1 ()].insert (line.pt0 ());
1531+ }
1532+
1533+ for (const auto & [obj, srcs] : sources) {
1534+ for (const auto & src_pt : srcs) {
1535+ for (const auto & dst_pt : sinks[sink]) {
1536+ std::vector<odb::Point> path;
1537+ findPath (pointmap, src_pt, dst_pt, path);
1538+
1539+ if (!path.empty ()) {
1540+ odb::Point prev_pt = path[0 ];
1541+ for (const auto & pt : path) {
1542+ if (pt == prev_pt) {
1543+ continue ;
1544+ }
1545+
1546+ painter.drawLine (prev_pt, pt);
1547+ prev_pt = pt;
1548+ }
1549+ } else {
1550+ // unable to find path so just draw a fly-wire
1551+ painter.drawLine (src_pt, dst_pt);
1552+ }
1553+ }
1554+ }
1555+ }
1556+ }
1557+
14131558// additional_data is used define the related sink for this net
14141559// this will limit the fly-wires to just those related to that sink
14151560// if nullptr, all flywires will be drawn
@@ -1514,8 +1659,13 @@ void DbNetDescriptor::highlight(std::any object, Painter& painter) const
15141659 highlight_color.a = 255 ;
15151660 painter.setPen (highlight_color, true , 4 );
15161661
1517- std::set<odb::Line> lines = convertGuidesToLines (net);
1662+ DbTargets sources;
1663+ DbTargets sinks;
1664+ std::set<odb::Line> lines = convertGuidesToLines (net, sources, sinks);
1665+
15181666 if (sink_object != nullptr ) {
1667+ drawPathSegmentWithGuides (
1668+ lines, sources, sinks, sink_object, painter);
15191669 } else {
15201670 for (const auto & line : lines) {
15211671 painter.drawLine (line);
0 commit comments