Skip to content

Commit b7e58f8

Browse files
authored
Merge pull request #7852 from gadfort/gui-guide-flywires
gui: use guides for net highlighting when available
2 parents 6f12721 + 0e7a5d9 commit b7e58f8

File tree

5 files changed

+354
-8
lines changed

5 files changed

+354
-8
lines changed

src/gui/include/gui/gui.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ class Painter
216216

217217
// Draw a line with coordinates in DBU with the current pen
218218
virtual void drawLine(const odb::Point& p1, const odb::Point& p2) = 0;
219+
void drawLine(const odb::Line& line) { drawLine(line.pt0(), line.pt1()); }
219220

220221
// Draw a circle with coordinates in DBU with the current pen
221222
virtual void drawCircle(int x, int y, int r) = 0;

src/gui/src/dbDescriptors.cpp

Lines changed: 281 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -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

src/gui/src/dbDescriptors.h

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -178,11 +178,23 @@ class DbNetDescriptor : public BaseDbDescriptor<odb::dbNet>
178178
using Node = odb::dbWireGraph::Node;
179179
using NodeList = std::set<const Node*>;
180180
using NodeMap = std::map<const Node*, NodeList>;
181+
using PointList = std::set<odb::Point>;
182+
using PointMap = std::map<odb::Point, PointList>;
181183
using GraphTarget = std::pair<const odb::Rect, const odb::dbTechLayer*>;
182-
183-
void drawPathSegment(odb::dbNet* net,
184-
const odb::dbObject* sink,
185-
Painter& painter) const;
184+
using DbTargets = std::map<const odb::dbObject*, std::set<odb::Point>>;
185+
186+
std::set<odb::Line> convertGuidesToLines(odb::dbNet* net,
187+
DbTargets& sources,
188+
DbTargets& sinks) const;
189+
190+
void drawPathSegmentWithGraph(odb::dbNet* net,
191+
const odb::dbObject* sink,
192+
Painter& painter) const;
193+
void drawPathSegmentWithGuides(const std::set<odb::Line>& lines,
194+
DbTargets& sources,
195+
DbTargets& sinks,
196+
const odb::dbObject* sink,
197+
Painter& painter) const;
186198
void findSourcesAndSinksInGraph(odb::dbNet* net,
187199
const odb::dbObject* sink,
188200
odb::dbWireGraph* graph,
@@ -196,6 +208,10 @@ class DbNetDescriptor : public BaseDbDescriptor<odb::dbNet>
196208
const Node* source,
197209
const Node* sink,
198210
std::vector<odb::Point>& path) const;
211+
void findPath(PointMap& graph,
212+
const odb::Point& source,
213+
const odb::Point& sink,
214+
std::vector<odb::Point>& path) const;
199215

200216
void buildNodeMap(odb::dbWireGraph* graph, NodeMap& node_map) const;
201217

src/odb/include/odb/geom.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,11 @@ class Polygon
327327
// returns a corrected Polygon with a closed form and counter-clockwise points
328328
Polygon bloat(int margin) const;
329329

330+
// Merge a collection of shapes
331+
static std::vector<Polygon> merge(const std::vector<Polygon>& polys);
332+
static std::vector<Polygon> merge(const std::vector<Rect>& rects);
333+
static std::vector<Polygon> merge(const std::vector<Oct>& octs);
334+
330335
// Returns the geometric difference between this polygon "a" and polygon "b"
331336
// results in a vector of polygons.
332337
std::vector<Polygon> difference(Polygon b) const;

0 commit comments

Comments
 (0)