#include "mainwindow.h" // qt #include #include #include #include #include #include #include #include // optical design #include "graphicsscene.h" #include "graphicsview.h" #include "opticaldesign.h" MainWindow::MainWindow(QWidget* parent) : QMainWindow{parent} , m_scene{new GraphicsScene{this}} , m_view{new GraphicsView{m_scene, this}} , m_design{new OpticalDesign{this}} { initUi(); initShortcuts(); } MainWindow::~MainWindow() {} void MainWindow::initUi() { setMinimumSize({640, 480}); qDebug() << "global settings path:" << GlobalSettings::instance()->fileName(); const auto mainWidget = new QWidget{this}; const auto mainLayout = new QHBoxLayout{mainWidget}; mainWidget->setLayout(mainLayout); // addLayout sets parent below const auto leftLayout = new QFormLayout{}; leftLayout->setLabelAlignment(Qt::AlignVCenter | Qt::AlignRight); mainLayout->addLayout(leftLayout); // left panel const auto connectWidgetToProperty = [this]( const auto widget, const auto widgetSignal, const auto widgetSetter, const auto propertyObject, const auto propertySignal, const auto propertySetter ) { connect(widget, widgetSignal, propertyObject, propertySetter); connect(propertyObject, propertySignal, widget, widgetSetter); }; using MinValue = double; using MaxValue = double; using SingleStep = double; auto addFormPair = [this, leftLayout, connectWidgetToProperty]( const QString text, const auto propertySignal, const auto propertyGetter, const auto propertySetter, const MinValue minValue, const MaxValue maxValue, const SingleStep singleStep = 0.1 ) { const auto spinBox = new QDoubleSpinBox{centralWidget()}; spinBox->setRange(minValue, maxValue); spinBox->setSingleStep(singleStep); spinBox->setValue(std::bind(propertyGetter, m_design)()); connect( spinBox, &QDoubleSpinBox::valueChanged, m_design, propertySetter ); connect(m_design, propertySignal, spinBox, &QDoubleSpinBox::setValue); connect( m_design, propertySignal, m_scene, std::bind(&GraphicsScene::update, m_scene, m_design) ); leftLayout->addRow(text, spinBox); }; using Decimals = int; auto addFormLabel = [this, leftLayout]( const QString text, const auto propertySignal, const Decimals decimals = 2 ) { const auto label = new QLabel{centralWidget()}; connect( m_design, propertySignal, label, [label, decimals](const auto value) { label->setText(QString::number(value, 'F', decimals)); } ); leftLayout->addRow(text, label); }; const auto createLenseApertureComboBox = [this, leftLayout]() { const auto comboBox = new QComboBox{centralWidget()}; using namespace orphex; const auto metaEnum = QMetaEnum::fromType(); for (int i{0}; i < metaEnum.keyCount(); ++i) { const auto key = metaEnum.key(i); const auto value = metaEnum.value(i); const auto text = QString{key} .replace(QStringLiteral("F"), QStringLiteral("1/")) .replace(QChar{'_'}, QChar{'.'}); comboBox->addItem(text, value); } // update property on combobox change connect( comboBox, &QComboBox::currentIndexChanged, m_design, [this, metaEnum, comboBox](const auto index) { m_design->set_lenseAperture( comboBox->currentData().value() ); qDebug() << m_design->get_lenseAperture(); } ); // update combobox on property change connect( m_design, qOverload(&OpticalDesign::lenseApertureChanged), comboBox, [comboBox](const auto value) { comboBox->setCurrentIndex( comboBox->findData(QVariant::fromValue(value)) ); } ); connect( m_design, qOverload<>(&OpticalDesign::lenseApertureChanged), m_scene, std::bind(&GraphicsScene::update, m_scene, m_design) ); leftLayout->addRow(tr("Lense A&perture:"), comboBox); }; addFormPair( tr("&Axis Angle (°):"), qOverload(&OpticalDesign::opticalAxisAngleDegreesChanged), &OpticalDesign::get_opticalAxisAngleDegrees, &OpticalDesign::set_opticalAxisAngleDegrees, MinValue{10.}, MaxValue{85.} ); addFormPair( tr("Lense &Y pos (mm):"), qOverload(&OpticalDesign::lenseYPosMmChanged), &OpticalDesign::get_lenseYPosMm, &OpticalDesign::set_lenseYPosMm, MinValue{10.}, MaxValue{500.}, SingleStep{1.} ); addFormPair( tr("&Focal Distance (mm):"), qOverload(&OpticalDesign::focalDistanceMmChanged), &OpticalDesign::get_focalDistanceMm, &OpticalDesign::set_focalDistanceMm, MinValue{1.}, MaxValue{45.} ); addFormPair( tr("&Back Focal Distance (mm):"), qOverload(&OpticalDesign::backFocalDistanceMmChanged), &OpticalDesign::get_backFocalDistanceMm, &OpticalDesign::set_backFocalDistanceMm, MinValue{1.}, MaxValue{45.} ); createLenseApertureComboBox(); addFormPair( tr("Sensor &Width (mm):"), qOverload(&OpticalDesign::sensorWidthMmChanged), &OpticalDesign::get_sensorWidthMm, &OpticalDesign::set_sensorWidthMm, MinValue{1.}, MaxValue{30.} ); addFormPair( tr("Sensor &Height (mm):"), qOverload(&OpticalDesign::sensorHeightMmChanged), &OpticalDesign::get_sensorHeightMm, &OpticalDesign::set_sensorHeightMm, MinValue{1.}, MaxValue{30.} ); addFormPair( tr("Sensor Cell W&idth (mm):"), qOverload(&OpticalDesign::sensorCellWidthUmChanged), &OpticalDesign::get_sensorCellWidthUm, &OpticalDesign::set_sensorCellWidthUm, MinValue{1.}, MaxValue{30.} ); addFormPair( tr("Sensor Cell H&eight (mm):"), qOverload(&OpticalDesign::sensorCellHeightUmChanged), &OpticalDesign::get_sensorCellHeightUm, &OpticalDesign::set_sensorCellHeightUm, MinValue{1.}, MaxValue{30.} ); addFormPair( tr("Sensor Vertical &Offset (mm):"), qOverload(&OpticalDesign::sensorVerticalOffsetMmChanged), &OpticalDesign::get_sensorVerticalOffsetMm, &OpticalDesign::set_sensorVerticalOffsetMm, MinValue{-50.}, MaxValue{50.}, SingleStep{0.1} ); addFormPair( tr("Z &Base (mm):"), qOverload(&OpticalDesign::zBaseMmChanged), &OpticalDesign::get_zBaseMm, &OpticalDesign::set_zBaseMm, MinValue{1.}, MaxValue{10000.}, SingleStep{1.} ); addFormPair( tr("Z &Range (mm):"), qOverload(&OpticalDesign::zRangeMmChanged), &OpticalDesign::get_zRangeMm, &OpticalDesign::set_zRangeMm, MinValue{1.}, MaxValue{10000.}, SingleStep{1.} ); addFormLabel( tr("Sensor/Lense Angle (°):"), qOverload(&OpticalDesign::sensorLenseAngleDegreesChanged), Decimals{3} ); addFormLabel( tr("Actual Z Base (mm):"), qOverload(&OpticalDesign::actualZBaseMmChanged), Decimals{2} ); addFormLabel( tr("Actual Z Range (mm):"), qOverload(&OpticalDesign::actualZRangeMmChanged), Decimals{2} ); addFormLabel( tr("Lense-Sensor Distance (mm):"), qOverload(&OpticalDesign::lenseSensorDistanceMmChanged), Decimals{2} ); addFormLabel( tr("Front Sharp Distance (mm):"), qOverload(&OpticalDesign::frontSharpDistanceMmChanged), Decimals{2} ); addFormLabel( tr("Back Sharp Distance (mm):"), qOverload(&OpticalDesign::backSharpDistanceMmChanged), Decimals{2} ); addFormLabel( tr("Depth Of Field (mm):"), qOverload(&OpticalDesign::depthOfFieldMmChanged), Decimals{2} ); // graphics view const auto openGlWidget = new QOpenGLWidget{centralWidget()}; QSurfaceFormat surfaceFormat{}; surfaceFormat.setSamples(4); openGlWidget->setFormat(surfaceFormat); m_view->setViewport(openGlWidget); // m_view->centerOn({0, 0}); // m_view->ensureVisible(QRectF{m_scene->sceneRect()}); mainLayout->addWidget(m_view); setCentralWidget(mainWidget); connect( m_design, qOverload(&OpticalDesign::opticalAxisAngleDegreesChanged), this, [](const auto value) { qDebug() << "angle changed:" << value; } ); m_view->setTransformationAnchor(GraphicsView::AnchorViewCenter); m_view->scale(5, 5); m_view->setTransformationAnchor(GraphicsView::AnchorUnderMouse); m_view->centerOn({0, -m_design->get_lenseYPosMm()}); m_scene->update(m_design); } void MainWindow::initShortcuts() { new QShortcut{Qt::CTRL | Qt::Key_Q, this, this, &MainWindow::close}; }