Bond.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. #include "Bond.h"
  2. #include <QDebug>
  3. #include <QPair>
  4. #include <QSet>
  5. #include <QMap>
  6. #include <cmath>
  7. Bond::Bond(QWidget* parent) : QWidget(parent) {
  8. generateTestData();
  9. }
  10. void Bond::generateTestData() {
  11. // 生成测试数据:2x2 PCB,每个PCB 2x2 PT矩阵,每个PT矩阵 2x3固晶点
  12. int pcbIndex = 0;
  13. int dieIndex = 0;
  14. std::srand(std::time(nullptr));
  15. for (int pcbRow = 0; pcbRow < 2; ++pcbRow) {
  16. for (int pcbCol = 0; pcbCol < 2; ++pcbCol) {
  17. int iPcbMatId = ++pcbIndex;
  18. pcbDimensions[iPcbMatId] = qMakePair(2, 2); // PCB包含2x2 PT矩阵
  19. int ptIndex = 0;
  20. for (int ptRow = 0; ptRow < 2; ++ptRow) {
  21. for (int ptCol = 0; ptCol < 2; ++ptCol) {
  22. int iPtMatId = ++ptIndex;
  23. ptDimensions[iPcbMatId][iPtMatId] = qMakePair(2, 3); // PT矩阵包含2x3固晶点
  24. for (int dieRow = 0; dieRow < 2; ++dieRow) {
  25. for (int dieCol = 0; dieCol < 3; ++dieCol) {
  26. ns_mat::POINT_INFO_STRUCT point;
  27. point.stIndex.iPcbMatId = iPcbMatId;
  28. point.stIndex.iPtMatId = iPtMatId;
  29. point.stIndex.iPcbRow = pcbRow;
  30. point.stIndex.iPcbCol = pcbCol;
  31. point.stIndex.iPtRow = dieRow;
  32. point.stIndex.iPtCol = dieCol;
  33. point.stIndex.iIndex = ++dieIndex;
  34. point.stBondStatus.bDieStatus = static_cast<ns_mat::DIE_STATUS>(std::rand() % 7);
  35. bondData.append(point);
  36. }
  37. }
  38. }
  39. }
  40. }
  41. }
  42. }
  43. void Bond::initFrom(QWidget* parent) {
  44. scene = new QGraphicsScene(parent);
  45. view = new BondGraphicsView(scene);
  46. int width = parent->width();
  47. int height = parent->height();
  48. // Step 1: 收集PCB全局布局信息
  49. QMap<QPair<int, int>, int> pcbPosMap;
  50. QSet<int> uniquePcbIds;
  51. foreach(const ns_mat::POINT_INFO_STRUCT & point, bondData) {
  52. QPair<int, int> pos(point.stIndex.iPcbRow, point.stIndex.iPcbCol);
  53. if (!pcbPosMap.contains(pos)) {
  54. pcbPosMap[pos] = point.stIndex.iPcbMatId;
  55. }
  56. uniquePcbIds.insert(point.stIndex.iPcbMatId);
  57. }
  58. // 计算PCB全局行列数
  59. int maxPcbRow = 0, maxPcbCol = 0;
  60. for (const QPair<int, int>& pos : pcbPosMap.keys()) {
  61. maxPcbRow = qMax(maxPcbRow, pos.first);
  62. maxPcbCol = qMax(maxPcbCol, pos.second);
  63. }
  64. int pcbRows = maxPcbRow + 1;
  65. int pcbCols = maxPcbCol + 1;
  66. // Step 2: 计算PCB布局参数
  67. qreal margin = width / maxPcbCol * 0.05;
  68. qreal pcbSpacing = margin;
  69. int fontSize = qMax(static_cast<int>(margin), 1);
  70. QFont font;
  71. font.setPointSize(fontSize);
  72. qreal totalWidth = width - 2 * margin;
  73. qreal totalHeight = height - 2 * margin;
  74. qreal pcbWidth = (totalWidth - (pcbCols - 1) * pcbSpacing) / pcbCols;
  75. qreal pcbHeight = (totalHeight - (pcbRows - 1) * pcbSpacing) / pcbRows;
  76. // Step 3: 预处理数据分组
  77. QMap<int, QMap<int, QList<ns_mat::POINT_INFO_STRUCT>>> groupedData;
  78. foreach(const ns_mat::POINT_INFO_STRUCT & point, bondData) {
  79. groupedData[point.stIndex.iPcbMatId][point.stIndex.iPtMatId].append(point);
  80. }
  81. // 绘制PCB并记录位置
  82. QMap<int, QRectF> pcbRects;
  83. for (int row = 0; row < pcbRows; ++row) {
  84. for (int col = 0; col < pcbCols; ++col) {
  85. QPair<int, int> pos(row, col);
  86. if (pcbPosMap.contains(pos)) {
  87. int pcbId = pcbPosMap[pos];
  88. QRectF rect(
  89. margin + col * (pcbWidth + pcbSpacing),
  90. margin + row * (pcbHeight + pcbSpacing),
  91. pcbWidth,
  92. pcbHeight
  93. );
  94. pcbRects[pcbId] = rect;
  95. // 绘制PCB背景
  96. QGraphicsRectItem* pcbItem = new QGraphicsRectItem(rect);
  97. pcbItem->setBrush(QColor("#e1d4e6"));
  98. scene->addItem(pcbItem);
  99. // 添加PCB标签
  100. QGraphicsTextItem* text = new QGraphicsTextItem(QString("PCB%1").arg(pcbId));
  101. text->setFont(font);
  102. qreal fixedHeight = qMin(pcbWidth / std::ceil(static_cast<qreal>(groupedData[pcbId].keys().size()) / std::ceil(std::sqrt(groupedData[pcbId].keys().size()))) * 0.1
  103. , pcbHeight / std::ceil(std::sqrt(groupedData[pcbId].keys().size())) * 0.1);
  104. qreal actualHeight = text->boundingRect().height();
  105. if (actualHeight > 0) {
  106. qreal scaleFactor = fixedHeight / actualHeight;
  107. text->setScale(scaleFactor);
  108. }
  109. text->setPos(rect.x(), rect.y());
  110. scene->addItem(text);
  111. }
  112. }
  113. }
  114. // Step 4: 绘制PT矩阵和固晶点
  115. foreach(int pcbId, uniquePcbIds) {
  116. QRectF pcbRect = pcbRects.value(pcbId);
  117. if (!pcbRect.isValid()) continue;
  118. // 获取当前PCB的所有PT矩阵
  119. QList<int> ptMatIds = groupedData[pcbId].keys();
  120. int ptMatCount = ptMatIds.size();
  121. if (ptMatCount == 0) continue;
  122. // 计算PT矩阵布局行列数(方形布局)
  123. int ptRows = std::ceil(std::sqrt(ptMatCount));
  124. int ptCols = std::ceil(static_cast<qreal>(ptMatCount) / ptRows);
  125. while (ptRows * ptCols < ptMatCount) ptCols++;
  126. qreal ptMargin = qMin(pcbWidth / ptCols * 0.1, pcbHeight / ptRows * 0.1);
  127. int fontSize_1 = qMax(static_cast<int>(ptMargin), 1);
  128. QFont font_1;
  129. font_1.setPointSize(fontSize_1);
  130. // 计算PT矩阵尺寸
  131. qreal ptWidth = (pcbRect.width() - (ptCols + 1) * ptMargin) / ptCols;
  132. qreal ptHeight = (pcbRect.height() - (ptRows + 1) * ptMargin) / ptRows;
  133. // 绘制每个PT矩阵
  134. for (int i = 0; i < ptMatIds.size(); ++i) {
  135. int ptId = ptMatIds[i];
  136. int row = i / ptCols;
  137. int col = i % ptCols;
  138. QRectF ptRect(
  139. pcbRect.x() + col * (ptWidth + ptMargin) + ptMargin,
  140. pcbRect.y() + row * (ptHeight + ptMargin) + ptMargin,
  141. ptWidth,
  142. ptHeight
  143. );
  144. // 绘制PT矩阵背景
  145. QGraphicsRectItem* ptItem = new QGraphicsRectItem(ptRect);
  146. ptItem->setBrush(QColor("#d5e4f8"));
  147. scene->addItem(ptItem);
  148. // 添加PT矩阵标签
  149. QGraphicsTextItem* ptText = new QGraphicsTextItem(QString("PT矩阵%1").arg(ptId));
  150. ptText->setFont(font_1);
  151. qreal fixedHeight_1 = qMin(ptWidth / ptDimensions[pcbId][ptId].second * 0.3, ptHeight / ptDimensions[pcbId][ptId].first * 0.3);
  152. qreal actualHeight_1 = ptText->boundingRect().height();
  153. if (actualHeight_1 > 0) {
  154. qreal scaleFactor_1 = fixedHeight_1 / actualHeight_1;
  155. ptText->setScale(scaleFactor_1);
  156. }
  157. ptText->setPos(ptRect.x(), ptRect.y());
  158. scene->addItem(ptText);
  159. // Step 5: 绘制固晶点
  160. QList<ns_mat::POINT_INFO_STRUCT> points = groupedData[pcbId][ptId];
  161. if (points.isEmpty()) continue;
  162. // 获取固晶点矩阵尺寸
  163. QPair<int, int> dieDims = ptDimensions[pcbId][ptId];
  164. int dieRows = dieDims.first;
  165. int dieCols = dieDims.second;
  166. qreal dieMargin = qMin(ptWidth / dieCols * 0.3, ptHeight / dieRows * 0.3);
  167. // 计算固晶点尺寸
  168. qreal dieWidth = (ptRect.width() - (dieCols + 1) * dieMargin) / dieCols;
  169. qreal dieHeight = (ptRect.height() - (dieRows + 1) * dieMargin) / dieRows;
  170. int fontSize_2 = qMax(static_cast<int>(qMin(dieWidth, dieHeight) * 0.2), 1);
  171. QFont font_2;
  172. font_2.setPointSize(fontSize_2);
  173. foreach(const ns_mat::POINT_INFO_STRUCT & point, points) {
  174. // 计算固晶点位置
  175. QRectF dieRect(
  176. ptRect.x() + point.stIndex.iPtCol * (dieWidth + dieMargin) + dieMargin,
  177. ptRect.y() + point.stIndex.iPtRow * (dieHeight + dieMargin) + dieMargin,
  178. dieWidth,
  179. dieHeight
  180. );
  181. // 绘制固晶点
  182. BondItem* dieItem = new BondItem(point);
  183. dieItem->setRect(dieRect);
  184. scene->addItem(dieItem);
  185. // 添加固晶点编号
  186. QGraphicsTextItem* dieText = new QGraphicsTextItem(dieItem);
  187. dieText->setPlainText("PT" + QString::number(point.stIndex.iIndex));
  188. dieText->setFont(font_2);
  189. dieText->setPos(dieRect.center() - QPointF(dieText->boundingRect().width() / 2,
  190. dieText->boundingRect().height() / 2));
  191. }
  192. }
  193. }
  194. view->setScene(scene);
  195. view->resize(width, height);
  196. }
  197. void Bond::paintInitFrom(QWidget* parent) {
  198. int width = parent->width();
  199. int height = parent->height();
  200. globalPixmap = QPixmap(width, height);
  201. globalPixmap.fill(Qt::white);
  202. QPainter painter(&globalPixmap);
  203. painter.setRenderHint(QPainter::Antialiasing);
  204. QFont baseFont = painter.font();
  205. // Step 1: 收集PCB全局布局信息
  206. QMap<QPair<int, int>, int> pcbPosMap;
  207. QSet<int> uniquePcbIds;
  208. foreach(const ns_mat::POINT_INFO_STRUCT & point, bondData) {
  209. QPair<int, int> pos(point.stIndex.iPcbRow, point.stIndex.iPcbCol);
  210. if (!pcbPosMap.contains(pos)) {
  211. pcbPosMap[pos] = point.stIndex.iPcbMatId;
  212. }
  213. uniquePcbIds.insert(point.stIndex.iPcbMatId);
  214. }
  215. // 计算PCB全局行列数
  216. int maxPcbRow = 0, maxPcbCol = 0;
  217. for (const QPair<int, int>& pos : pcbPosMap.keys()) {
  218. maxPcbRow = qMax(maxPcbRow, pos.first);
  219. maxPcbCol = qMax(maxPcbCol, pos.second);
  220. }
  221. int pcbRows = maxPcbRow + 1;
  222. int pcbCols = maxPcbCol + 1;
  223. // Step 2: 计算PCB布局参数
  224. qreal margin = width / maxPcbCol * 0.05;
  225. qreal pcbSpacing = margin;
  226. qreal totalWidth = width - 2 * margin;
  227. qreal totalHeight = height - 2 * margin;
  228. qreal pcbWidth = (totalWidth - (pcbCols - 1) * pcbSpacing) / pcbCols;
  229. qreal pcbHeight = (totalHeight - (pcbRows - 1) * pcbSpacing) / pcbRows;
  230. // Step 3: 预处理数据分组
  231. QMap<int, QMap<int, QList<ns_mat::POINT_INFO_STRUCT>>> groupedData;
  232. foreach(const ns_mat::POINT_INFO_STRUCT & point, bondData) {
  233. groupedData[point.stIndex.iPcbMatId][point.stIndex.iPtMatId].append(point);
  234. }
  235. // 绘制PCB并记录位置
  236. QMap<int, QRectF> pcbRects;
  237. for (int row = 0; row < pcbRows; ++row) {
  238. for (int col = 0; col < pcbCols; ++col) {
  239. QPair<int, int> pos(row, col);
  240. if (pcbPosMap.contains(pos)) {
  241. int pcbId = pcbPosMap[pos];
  242. QRectF rect(
  243. margin + col * (pcbWidth + pcbSpacing),
  244. margin + row * (pcbHeight + pcbSpacing),
  245. pcbWidth,
  246. pcbHeight
  247. );
  248. pcbRects[pcbId] = rect;
  249. // 绘制PCB背景
  250. painter.setPen(Qt::NoPen);
  251. painter.setBrush(QColor("#e1d4e6"));
  252. painter.drawRect(rect);
  253. }
  254. }
  255. }
  256. // Step 4: 绘制PT矩阵和固晶点
  257. foreach(int pcbId, uniquePcbIds) {
  258. QRectF pcbRect = pcbRects.value(pcbId);
  259. if (!pcbRect.isValid()) continue;
  260. // 获取当前PCB的所有PT矩阵
  261. QList<int> ptMatIds = groupedData[pcbId].keys();
  262. int ptMatCount = ptMatIds.size();
  263. if (ptMatCount == 0) continue;
  264. // 计算PT矩阵布局行列数(方形布局)
  265. int ptRows = std::ceil(std::sqrt(ptMatCount));
  266. int ptCols = std::ceil(static_cast<qreal>(ptMatCount) / ptRows);
  267. while (ptRows * ptCols < ptMatCount) ptCols++;
  268. qreal ptMargin = qMin(pcbWidth / ptCols * 0.1, pcbHeight / ptRows * 0.1);
  269. // 计算PT矩阵尺寸
  270. qreal ptWidth = (pcbRect.width() - (ptCols + 1) * ptMargin) / ptCols;
  271. qreal ptHeight = (pcbRect.height() - (ptRows + 1) * ptMargin) / ptRows;
  272. // 绘制每个PT矩阵
  273. for (int i = 0; i < ptMatIds.size(); ++i) {
  274. int ptId = ptMatIds[i];
  275. int row = i / ptCols;
  276. int col = i % ptCols;
  277. QRectF ptRect(
  278. pcbRect.x() + col * (ptWidth + ptMargin) + ptMargin,
  279. pcbRect.y() + row * (ptHeight + ptMargin) + ptMargin,
  280. ptWidth,
  281. ptHeight
  282. );
  283. // 绘制PT矩阵背景
  284. painter.setPen(Qt::NoPen);
  285. painter.setBrush(QColor("#d5e4f8"));
  286. painter.drawRect(ptRect);
  287. // Step 5: 绘制固晶点
  288. QList<ns_mat::POINT_INFO_STRUCT> points = groupedData[pcbId][ptId];
  289. if (points.isEmpty()) continue;
  290. // 获取固晶点矩阵尺寸
  291. QPair<int, int> dieDims = ptDimensions[pcbId][ptId];
  292. int dieRows = dieDims.first;
  293. int dieCols = dieDims.second;
  294. qreal dieMargin = qMin(ptWidth / dieCols * 0.3, ptHeight / dieRows * 0.3);
  295. // 计算固晶点尺寸
  296. qreal dieWidth = (ptRect.width() - (dieCols + 1) * dieMargin) / dieCols;
  297. qreal dieHeight = (ptRect.height() - (dieRows + 1) * dieMargin) / dieRows;
  298. foreach(const ns_mat::POINT_INFO_STRUCT & point, points) {
  299. // 计算固晶点位置
  300. QRectF dieRect(
  301. ptRect.x() + point.stIndex.iPtCol * (dieWidth + dieMargin) + dieMargin,
  302. ptRect.y() + point.stIndex.iPtRow * (dieHeight + dieMargin) + dieMargin,
  303. dieWidth,
  304. dieHeight
  305. );
  306. // 绘制固晶点
  307. painter.setPen(Qt::NoPen);
  308. painter.setBrush(getColorByStatus(point.stBondStatus.bDieStatus));
  309. painter.drawRect(dieRect);
  310. }
  311. }
  312. }
  313. painter.end();
  314. }
  315. QColor Bond::getColorByStatus(ns_mat::DIE_STATUS status) {
  316. switch (status) {
  317. //case ns_mat::DIE_STATUS::NO_PICK: return QColor(200, 200, 200);
  318. //case ns_mat::DIE_STATUS::WAF_PICK_DONE: return QColor(100, 200, 230);
  319. //case ns_mat::DIE_STATUS::TRANSFER_BOND_DONE: return QColor(255, 255, 0);
  320. case ns_mat::DIE_STATUS::TRANSFER_PICK_DONE: return QColor(255, 165, 0);
  321. case ns_mat::DIE_STATUS::LOOKUP_CALIB_DONE: return QColor(0, 150, 255);
  322. case ns_mat::DIE_STATUS::BOND_DONE: return QColor(144, 238, 144);
  323. case ns_mat::DIE_STATUS::BOND_DEL: return QColor(255, 50, 50);
  324. default: return Qt::gray;
  325. }
  326. }
  327. QPixmap Bond::getGlobalPixmap() const {
  328. return globalPixmap;
  329. }