#include "main_window.h" #include #include #include #include #include #include #include #include #include #include MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { setWindowTitle("Sistema de Inspección y Medición de Soldaduras (Línea Única)"); resize(1200, 800); createUI(); } void MainWindow::createUI() { QWidget *centralWidget = new QWidget(this); setCentralWidget(centralWidget); QHBoxLayout *mainLayout = new QHBoxLayout(centralWidget); mainLayout->setContentsMargins(8, 8, 8, 8); mainLayout->setSpacing(8); // Left sidebar panel QWidget *panel = new QWidget(centralWidget); panel->setFixedWidth(320); QVBoxLayout *panelLayout = new QVBoxLayout(panel); panelLayout->setContentsMargins(4, 4, 4, 4); // Image loading section QGroupBox *grpFile = new QGroupBox("1. Imagen de Inspección", panel); QVBoxLayout *fileLayout = new QVBoxLayout(grpFile); QPushButton *btnOpen = new QPushButton("Cargar Imagen...", grpFile); btnOpen->setIcon(style()->standardIcon(QStyle::SP_DialogOpenButton)); btnOpen->setFixedHeight(36); fileLayout->addWidget(btnOpen); panelLayout->addWidget(grpFile); // Calibration setup section QGroupBox *grpCalib = new QGroupBox("2. Calibración", panel); QVBoxLayout *calibLayout = new QVBoxLayout(grpCalib); QFormLayout *formGrid = new QFormLayout(); m_spinSquareSize = new QDoubleSpinBox(grpCalib); m_spinSquareSize->setRange(0.1, 1000.0); m_spinSquareSize->setValue(30.0); m_spinSquareSize->setSuffix(" mm"); m_spinSquareSize->setDecimals(1); formGrid->addRow("Lado Cuadrado (Ajedrez):", m_spinSquareSize); calibLayout->addLayout(formGrid); QPushButton *btnCalibChessboard = new QPushButton("Autocalibrar Ajedrez", grpCalib); btnCalibChessboard->setFixedHeight(30); btnCalibChessboard->setStyleSheet("font-weight: bold; background-color: #b71c1c; color: white; border-radius: 4px;"); calibLayout->addWidget(btnCalibChessboard); panelLayout->addWidget(grpCalib); // Measurement readout section QGroupBox *grpMeas = new QGroupBox("3. Medición en Vivo", panel); QVBoxLayout *measLayout = new QVBoxLayout(grpMeas); m_lblMeasurement = new QLabel("Medida: -\nDistancia: - px", grpMeas); m_lblMeasurement->setStyleSheet("font-size: 14px; font-weight: bold; color: #ff5555; background: #1e1e24; padding: 10px; border-radius: 4px;"); measLayout->addWidget(m_lblMeasurement); panelLayout->addWidget(grpMeas); panelLayout->addStretch(); // OpenGL Central Viewport Widget m_glWidget = new MeasurementWidget(centralWidget); mainLayout->addWidget(panel); mainLayout->addWidget(m_glWidget, 1); // Connect signals & slots connect(btnOpen, &QPushButton::clicked, this, &MainWindow::openImage); connect(m_glWidget, &MeasurementWidget::measurementUpdated, this, &MainWindow::updateMeasurementInfo); // Connect progress signal to dynamically update the gradient color of the button! connect(m_glWidget, &MeasurementWidget::calibrationProgress, this, [btnCalibChessboard](int percent) { double ratio = percent / 100.0; btnCalibChessboard->setStyleSheet(QString( "font-weight: bold; color: white; border-radius: 4px;" "background: qlineargradient(x1:0, y1:0, x2:1, y2:0, stop:0 #2e7d32, stop:%1 #2e7d32, stop:%2 #b71c1c, stop:1 #b71c1c);" ).arg(ratio).arg(qMin(1.0, ratio + 0.001))); }); // Autocalibrate using chessboard connect(btnCalibChessboard, &QPushButton::clicked, this, [this, btnCalibChessboard, btnOpen]() { btnCalibChessboard->setEnabled(false); btnOpen->setEnabled(false); int gx = 0; // Pass 0 to auto-detect int gy = 0; // Pass 0 to auto-detect double sqSize = m_spinSquareSize->value(); bool success = m_glWidget->calibrateWithChessboard(gx, gy, sqSize); if (success) { // Keep green when calibrated successfully btnCalibChessboard->setStyleSheet("font-weight: bold; background-color: #2e7d32; color: white; border-radius: 4px;"); } else { // Return to red if calibration failed btnCalibChessboard->setStyleSheet("font-weight: bold; background-color: #b71c1c; color: white; border-radius: 4px;"); } btnCalibChessboard->setEnabled(true); btnOpen->setEnabled(true); if (success) { int squaresX = gx + 1; int squaresY = gy + 1; QMessageBox::information(this, "Calibración Exitosa", QString("Se detectó automáticamente un tablero de ajedrez.\n\n" "Dimensiones identificadas:\n" "- Intersecciones internas: %1 x %2\n" "- Cuadrados totales: %3 x %4\n" "- Medida del lado: %5 mm\n\n" "La distorsión del lente y la perspectiva han sido calibradas con éxito.") .arg(gx).arg(gy).arg(squaresX).arg(squaresY).arg(sqSize, 0, 'f', 1)); } else { QMessageBox::warning(this, "Error de Calibración", QString("No se pudo detectar automáticamente ningún tablero de ajedrez en la imagen.\n\n" "Por favor verifica:\n" "1. Que el tablero esté bien iluminado y plano.\n" "2. Que el tablero esté completamente visible en la foto.")); } }); // Reset calibration button color to red when a new image is loaded connect(m_glWidget, &MeasurementWidget::imageLoaded, this, [btnCalibChessboard]() { btnCalibChessboard->setStyleSheet("font-weight: bold; background-color: #b71c1c; color: white; border-radius: 4px;"); }); } void MainWindow::openImage() { QString fileName = QFileDialog::getOpenFileName(this, "Abrir Imagen de Inspección", "", "Imágenes (*.png *.jpg *.jpeg *.bmp *.tif *.tiff)"); if (!fileName.isEmpty()) { if (!m_glWidget->loadImage(fileName)) { QMessageBox::warning(this, "Error", "No se pudo cargar la imagen seleccionada."); } } } void MainWindow::updateMeasurementInfo(double px, double mm) { Q_UNUSED(px); if (m_glWidget->isCalibrated()) { m_lblMeasurement->setText(QString("Medida: %1 mm").arg(mm, 0, 'f', 2)); } else { m_lblMeasurement->setText("Medida: Sin Calibrar"); } }