@@ -1114,9 +1114,9 @@ void DbNetDescriptor::findSourcesAndSinksInGraph(
11141114 sink_nodes.insert (sinks_nodes.begin (), sinks_nodes.end ());
11151115}
11161116
1117- void DbNetDescriptor::drawPathSegment (odb::dbNet* net,
1118- const odb::dbObject* sink,
1119- Painter& painter) const
1117+ void DbNetDescriptor::drawPathSegmentWithGraph (odb::dbNet* net,
1118+ const odb::dbObject* sink,
1119+ Painter& painter) const
11201120{
11211121 odb::dbWireGraph graph;
11221122 graph.decode (net->getWire ());
@@ -1316,6 +1316,245 @@ void DbNetDescriptor::findPath(NodeMap& graph,
13161316 }
13171317}
13181318
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
1396+ {
1397+ sources.clear ();
1398+ sinks.clear ();
1399+
1400+ auto guides = net->getGuides ();
1401+ if (guides.empty ()) {
1402+ return {};
1403+ }
1404+
1405+ std::set<odb::Line> lines;
1406+
1407+ struct DbIO
1408+ {
1409+ bool is_sink;
1410+ bool is_source;
1411+ };
1412+ std::map<odb::dbObject*, DbIO> io_map;
1413+
1414+ std::map<odb::dbTechLayer*, std::map<odb::dbObject*, std::set<odb::Rect>>>
1415+ terms;
1416+ for (odb::dbITerm* term : net->getITerms ()) {
1417+ if (!term->getInst ()->isPlaced ()) {
1418+ continue ;
1419+ }
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};
1426+ for (const auto & [layer, itermbox] : term->getGeometries ()) {
1427+ terms[layer][term].insert (itermbox);
1428+ }
1429+ }
1430+ 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+
1438+ for (odb::dbBPin* pin : term->getBPins ()) {
1439+ if (!pin->getPlacementStatus ().isPlaced ()) {
1440+ continue ;
1441+ }
1442+ for (odb::dbBox* box : pin->getBoxes ()) {
1443+ terms[box->getTechLayer ()][term].insert (box->getBox ());
1444+ }
1445+ }
1446+ }
1447+
1448+ for (const auto * guide : guides) {
1449+ const auto & box = guide->getBox ();
1450+ const auto center = box.center ();
1451+ const int width_half = box.minDXDY () / 2 ;
1452+ odb::Point p0, p1;
1453+ switch (box.getDir ()) {
1454+ case 0 : {
1455+ // DX < DY
1456+ p0 = odb::Point (center.x (), box.yMin () + width_half);
1457+ p1 = odb::Point (center.x (), box.yMax () - width_half);
1458+ break ;
1459+ }
1460+ case 1 : {
1461+ p0 = odb::Point (box.xMin () + width_half, center.y ());
1462+ p1 = odb::Point (box.xMax () - width_half, center.y ());
1463+ break ;
1464+ }
1465+ default : {
1466+ p0 = center;
1467+ p1 = center;
1468+ break ;
1469+ }
1470+ }
1471+ lines.emplace (p0, p1);
1472+
1473+ if (guide->isConnectedToTerm ()) {
1474+ std::vector<odb::Point> anchors = {p0, center, p1};
1475+
1476+ auto find_term_connection = [&anchors, &lines, &io_map, &sources, &sinks](
1477+ odb::dbObject* dbterm,
1478+ const odb::Point& term) {
1479+ // draw shortest flywire
1480+ std::stable_sort (anchors.begin (),
1481+ anchors.end (),
1482+ [&term](const odb::Point& pt0, const odb::Point& pt1) {
1483+ return odb::Point::manhattanDistance (term, pt0)
1484+ < odb::Point::manhattanDistance (term, pt1);
1485+ });
1486+ 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+ }
1493+ };
1494+
1495+ for (const auto & [obj, objbox] : terms[guide->getLayer ()]) {
1496+ std::vector<const odb::Rect*> candidates;
1497+ for (const auto & termbox : objbox) {
1498+ if (termbox.intersects (box)) {
1499+ candidates.push_back (&termbox);
1500+ }
1501+ }
1502+ bool found = false ;
1503+ for (const auto * termbox : candidates) {
1504+ if (termbox->overlaps (box)) {
1505+ find_term_connection (obj, termbox->center ());
1506+ found = true ;
1507+ break ;
1508+ }
1509+ }
1510+ if (!found && !candidates.empty ()) {
1511+ find_term_connection (obj, candidates[0 ]->center ());
1512+ }
1513+ }
1514+ }
1515+ }
1516+
1517+ return lines;
1518+ }
1519+
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+
13191558// additional_data is used define the related sink for this net
13201559// this will limit the fly-wires to just those related to that sink
13211560// if nullptr, all flywires will be drawn
@@ -1388,7 +1627,7 @@ void DbNetDescriptor::highlight(std::any object, Painter& painter) const
13881627 if (wire) {
13891628 draw_flywires = false ;
13901629 if (sink_object != nullptr ) {
1391- drawPathSegment (net, sink_object, painter);
1630+ drawPathSegmentWithGraph (net, sink_object, painter);
13921631 }
13931632
13941633 odb::dbWireShapeItr it;
@@ -1397,6 +1636,44 @@ void DbNetDescriptor::highlight(std::any object, Painter& painter) const
13971636 while (it.next (shape)) {
13981637 painter.drawRect (shape.getBox ());
13991638 }
1639+ } else {
1640+ auto guides = net->getGuides ();
1641+ if (!guides.empty ()) {
1642+ draw_flywires = false ;
1643+
1644+ // draw outlines of guides
1645+ std::vector<odb::Rect> guide_rects;
1646+ guide_rects.reserve (guides.size ());
1647+ for (const auto * guide : guides) {
1648+ guide_rects.push_back (guide->getBox ());
1649+ }
1650+ painter.saveState ();
1651+ painter.setBrush (painter.getPenColor (), gui::Painter::Brush::kNone );
1652+ for (const odb::Polygon& outline : odb::Polygon::merge (guide_rects)) {
1653+ painter.drawPolygon (outline);
1654+ }
1655+ painter.restoreState ();
1656+
1657+ painter.saveState ();
1658+ Painter::Color highlight_color = painter.getPenColor ();
1659+ highlight_color.a = 255 ;
1660+ painter.setPen (highlight_color, true , 2 );
1661+
1662+ DbTargets sources;
1663+ DbTargets sinks;
1664+ std::set<odb::Line> lines = convertGuidesToLines (net, sources, sinks);
1665+
1666+ if (sink_object != nullptr ) {
1667+ drawPathSegmentWithGuides (
1668+ lines, sources, sinks, sink_object, painter);
1669+ } else {
1670+ for (const auto & line : lines) {
1671+ painter.drawLine (line);
1672+ }
1673+ }
1674+
1675+ painter.restoreState ();
1676+ }
14001677 }
14011678 }
14021679
0 commit comments