Open huangwenjunlovedy opened 5 months ago
您好,通过使用gdsdk和gdstk解析1.gds文件发现,其lib中包含两个Cell,其中NCH33_CDNS_657593343090的Cell包含多个polygon,是具体的图形,Cell'2'只包含一个指向Cell'NCH33_CDNS_657593343090'的引用。因此通过gdstk的get_polygons接口,获取所有的多边形,会将Cell'NCH33_CDNS_657593343090'的多边形返回,并将Cell'2'按偏移之后计算得到其多边形返回,因此,使用gdstk会得到两部分图形。
KLayout在版图显示时会有一定的优化选择。当同时存在cell和指向cell的引用时,KLayout会隐藏被指向的cell。
换句话说,KLayout将按照层级树来组织引用和Cell,并显示层级树顶层的cell。gdstk的get_polygons则将层级树展开扁平化,不再有层级关系。 如下所示: KLayout:Cell'2' ----> Cell'NCH33_CDNS_657593343090',只显示顶层的Cell'2' gdstk.get_polygons:返回Cell'2'和Cell'NCH33_CDNS_657593343090'的所有polygon
如果想要实现和KLayout完全相同的显示功能,从gdstk中获取Cell和引用之间的关系,需要使用自己建立层级树关系,(gdstk的引用和Cell本身具有一定的层级树关系)。然后只显示lib下第一层级的Cell和引用。
十分感谢您的回答,我大概明白了。我会去尝试建立层级树关系来显示cell
我尝试了写一个获取gds文件cells引用关系的代码,但是lib.cell_array中本身存储了引用cell和被引用的cell。导致我递归解析也出现多余的层级关系。不知道如何解决。想请问您能帮忙解决吗,十分感谢!另外就算解析出了正确的cells间层级树关系,我在for(int i = 0; i < lib.cell_array.count; i++)中画出图形时,又应该怎样做判断呢?期待您的解答! (1)这是.h头文件 `
QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE
class MainWindow : public QMainWindow { Q_OBJECT
public: MainWindow(QWidget *parent = nullptr); ~MainWindow();
void printReferences(gdstk::Cell &cell,
int cell_level,
QString indent,
QStandardItem *parentItem);
private: Ui::MainWindow ui; QStandardItemModel model; QTreeView *treeView; };
(2)这是.cpp源文件
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this);
gdstk::ErrorCode error_code;
gdstk::Set<gdstk::Tag> tags = {0};
auto lib = gdstk::read_gds(QString("D://xxx.gds").toLocal8Bit().data(),
0,
1e-2,
NULL,
&error_code);
QStandardItemModel *model = new QStandardItemModel;
QStandardItem *rootItem = model->invisibleRootItem();
for (size_t i = 0; i < lib.cell_array.count; i++) {
gdstk::Cell *cell = lib.cell_array[i];
printReferences(*cell, 0, "-", rootItem);
}
QTreeView *treeView = new QTreeView;
treeView->setModel(model);
setCentralWidget(treeView);
}
MainWindow::~MainWindow() { delete ui; }
void MainWindow::printReferences(gdstk::Cell &cell, int cell_level, QString indent, QStandardItem parentItem) { QString name = QString::number(cell_level) + " " + cell.name; QStandardItem item = new QStandardItem(name); parentItem->appendRow(item); qDebug() << indent << cell_level << cell.name; for (int i = 0; i < cell.reference_array.count; i++) { gdstk::Cell cur_cel = cell.reference_array[i]->cell; printReferences(cur_cel, cell_level + 1, "-" + indent, item); } } `
解析three_level_structure.gds的结果: three_level_structure.zip
(3)我解析的错误的
(4)klayout解析正确的
我已经解决了问题并能正确展示了,十分感谢您!
不好意思回复晚了,晚上我也尝试写了个简单的恢复层级树方法,时间比较赶,写得比较粗糙,请见谅
#include <algorithm>
#include <gdstk.hpp>
#include <iostream>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <vector>
class TreeNode {
public:
TreeNode(gdstk::Cell* c) : self(c){};
~TreeNode() = default;
std::string toString(uint64_t level = 0) const {
std::string content(level * 2, ' ');
content += self->name;
content += "\n";
for (auto&& i : children) {
content += i->toString(level + 1);
}
return content;
}
gdstk::Cell* self;
//
std::set<std::shared_ptr<TreeNode>> children;
};
class TreeLib {
public:
TreeLib() = default;
~TreeLib() = default;
std::string toString() const {
std::string content = "Root:\n";
for (auto&& i : tree) {
content += i->toString(1);
}
return content;
}
std::vector<std::shared_ptr<TreeNode>> tree;
};
void buildTreeNodeRefer(gdstk::Cell* cell,
std::map<gdstk::Cell*, std::shared_ptr<TreeNode>>& map,
std::set<gdstk::Cell*>& mark) {
for (size_t i = 0; i < cell->reference_array.count; i++) {
auto ref = cell->reference_array[i];
gdstk::ReferenceType& ref_type = ref->type;
switch (ref_type) {
case gdstk::ReferenceType::Cell: {
auto refed_cell = ref->cell;
buildTreeNodeRefer(refed_cell, map, mark);
// 标记被引用Cell
mark.insert(refed_cell);
// 建立TreeNode之间的引用关系
auto cur_node = map[cell];
auto refered_node = map[refed_cell];
cur_node->children.insert(refered_node);
break;
}
case gdstk::ReferenceType::Name: {
auto refed_cell_iter = std::find_if(
map.begin(), map.end(),
[&](const std::pair<gdstk::Cell* const, std::shared_ptr<TreeNode>>&
pair) { return strcmp(pair.first->name, ref->name); });
if (refed_cell_iter != map.end()) {
auto refed_cell = refed_cell_iter->first;
buildTreeNodeRefer(refed_cell, map, mark);
// 标记被引用Cell
mark.insert(refed_cell);
// 建立TreeNode之间的引用关系
auto cur_node = map[cell];
auto refered_node = map[refed_cell];
cur_node->children.insert(refered_node);
} else {
throw std::runtime_error("Refered Cell canot be find in lib");
}
break;
}
default:
throw std::runtime_error("RawCell not be processed");
break;
}
}
}
int main(int argc, char const* argv[]) {
gdstk::Set<gdstk::Tag> tag = {};
gdstk::ErrorCode error_code = gdstk::ErrorCode::NoError;
auto lib = gdstk::read_gds(argv[1], 0, 0, &tag, &error_code);
// 1.step 将所有Cell转换为TreeNode,并使用容器用于后续标记哪些cell被引用
std::set<gdstk::Cell*> refered_mark;
std::map<gdstk::Cell*, std::shared_ptr<TreeNode>> cell_map_to_node;
for (size_t i = 0; i < lib.cell_array.count; i++) {
auto c = lib.cell_array[i];
// unrefered_mark[c] = TreeNode(c);
cell_map_to_node[c] = std::make_shared<TreeNode>(c);
}
// 2.step 遍历所有TreeNode,建立引用层级树
// 需要注意,代码不能处理循环引用的情况,例如CellA-->CellB-->CellA,这种情况将无限递归
for (auto it = cell_map_to_node.begin(); it != cell_map_to_node.end(); it++) {
buildTreeNodeRefer(it->first, cell_map_to_node, refered_mark);
}
// 3.step 从cell_map_to_node中找到从未被引用的Cell作为顶层
TreeLib tree_lib;
for (auto&& i : cell_map_to_node) {
if (refered_mark.count(i.first)) {
continue;
} else {
tree_lib.tree.push_back(i.second);
}
}
std::cout << tree_lib.toString() << std::endl;
}
读入three_level_structure并打印层级树如下:
Root:
toplevel
device_level_1
device_level_2_1
device_level_2
device_level_3
请注意,这只是简单的演示才使用层级树结构,真实的复杂引用关系会形成DAG(有向无环图),最好使用DAG来描述Cell间引用关系
十分感谢您的回答。我分别使用了python和qt来实现cell 层级树功能。我试了下解析不同的gds文件(包括复杂的)和klayout结果是一样的,但我并不了解DAG(有向无环图),我采用了递归的方式来获取cell 层级树可能有BUG。如果允许的话您可以给出潜藏的BUG建议吗?
(1)cell 层级树功能的python代码如下: cell_tree.zip
运行结果(和klayout对比) 我的:
klayout的:
(2)cell 层级树功能和版图展示的C++代码如下: 在画gds版图展示的时候,我是从Library.top_level()函数里获取到顶层的top Cells,并通过cell->get_polygons(true, true, -1, false, 0, polygons)函数,其中depth参数设置为-1 以此递归获取到所有的多边形包括引用的。这样画出的的gds版图效果就和klayout是一样了(我试了不同的gds文件展示结果是一样的)。也同样想请问您这样做有潜在的BUG吗? gds_show.zip
画出的效果:
klayout画出的效果:
最后再次感谢和期待您的回答!
如果可以的话,也希望能加您的WX沟通请教,我的微信q785941939
(1)我打开了一个1.gds文件,下图是用Klayou打开时正确的样式:
(2)我用 gds_viewer打开该1.gds文件,效果如下:会把没有计算偏移量的模块也多画出来
(3)我模仿您的 gds_viewer 自己创立了一个新的qt工程项目,按您的方法展示时是同样结果,不知道怎么解决。我展示的代码逻辑与您一样。但我研究了一段时间没能解决这个问题,所以请教您看能不能帮忙解决。十分感谢!(附件是我的1.gds文件) 1.gds.zip
我的展示代码如下: ` // 读取GDS文件 Library lib = gdstk::read_gds(filePath.toLocal8Bit().data(), 0, 1e-2, NULL, &error_code);