Bond.cpp 15 KB

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