diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/graphicsscene.cpp | 298 | ||||
| -rw-r--r-- | src/graphicsscene.h | 18 | ||||
| -rw-r--r-- | src/main.cpp | 4 | ||||
| -rw-r--r-- | src/mainwindow.cpp | 265 | ||||
| -rw-r--r-- | src/mainwindow.h | 3 | ||||
| -rw-r--r-- | src/opticaldesign.cpp | 48 | ||||
| -rw-r--r-- | src/opticaldesign.h | 49 |
7 files changed, 621 insertions, 64 deletions
diff --git a/src/graphicsscene.cpp b/src/graphicsscene.cpp index e918ccc..6850c1f 100644 --- a/src/graphicsscene.cpp +++ b/src/graphicsscene.cpp @@ -12,7 +12,55 @@ namespace orphex namespace constants { const QLineF laserPlane{QPointF{-1000, 0}, QPointF{1000, 0}}; + +const auto laserColor = QColor{Qt::red}; +const auto sensorColor = QColor{Qt::red}; } + +/*! + * \brief vFoVDegrees - get "vertical" (YZ projection) Field of View (degrees) + * \param vSensorPlane - sensor plane (YZ projection) + * \param vLaserRange - laser range (YZ projection) + * \return - Field of View angle (degrees) + */ +double vFoVDegrees(const QLineF& vSensorPlane, const QLineF& vLaserRange); + +/*! + * \brief lenseBodyRect - create 2d rectangle representing lense body + * \param diameterMm - body diameter (mm) + * \param lengthMm - body length (mm) + * \return - corresponding 2d body rect + */ +QRectF lenseBodyRect(const double diameterMm, const double lengthMm); + +/*! + * \brief laserBodyRect - create 2d rectangle representing laser body + * \param diameterMm - body diameter (mm) + * \param lengthMm - body length (mm) + * \return - corresponding 2d body rect + */ +QRectF laserBodyRect(const double diameterMm, const double lengthMm); + +/*! + * \brief laserBodyRect - create 2d rectangle representing laser body + * \param diameterMm - body diameter (mm) + * \param lengthMm - body length (mm) + * \return - corresponding 2d body rect + */ + +/*! + * \brief scannerBodyFrontWallRect - create 2d rectangle representing front wall + * of scanner body + * \param thicknessMm - wall thickness (mm) + * \param offsetMm - horizontal offset from lense center (mm) + * \return - corresponding 2d body rect + */ +QRectF scannerBodyFrontWallRect( + const double thicknessMm, + const double offsetMm +); + +QList<QPointF> xzLaserAreaPolygon(const double laserAngle); } // namespace orphex GraphicsScene::GraphicsScene(QObject* parent) @@ -26,11 +74,13 @@ GraphicsScene::GraphicsScene(QObject* parent) ); m_lenseItem->setTransformOriginPoint(m_lenseItem->boundingRect().center()); - m_sensorItem = new QGraphicsLineItem(QLineF{}, m_lenseItem); - m_sensorItem->setPen(QPen{Qt::red, 0}); + m_yzSensorItem = new QGraphicsLineItem{QLineF{}, m_lenseItem}; + m_yzSensorItem->setPen(QPen{orphex::constants::sensorColor, 0}); + + m_xzSensorItem = addRect({}, QPen{orphex::constants::sensorColor, 0}); m_lineOfActionItem = new QGraphicsLineItem{ - QLineF{QPointF{0, -50}, QPointF{0, 50}}, + QLineF{QPointF{0, -1000}, QPointF{0, 1000}}, m_lenseItem }; m_lineOfActionItem->setPen(QPen{Qt::green, 0}); @@ -41,6 +91,31 @@ GraphicsScene::GraphicsScene(QObject* parent) }; m_opticalAxisItem->setPen(QPen{Qt::gray, 0}); + m_lenseVerticalPlaneItem = addLine( + QLineF{QPointF{0, -1000}, QPointF{0, 1000}}, + QPen{Qt::black, 0} + ); + + m_lenseBodyItem = addRect( + QRectF{}, + QPen{m_lenseItem->pen().color(), 0}, + QBrush{m_lenseItem->pen().color(), Qt::DiagCrossPattern} + ); + m_lenseBodyItem->setParentItem(m_lenseItem); + m_lenseBodyItem->setOpacity(0.1); + + m_laserBodyItem = addRect( + QRectF{}, + QPen{Qt::black, 0}, + QBrush{Qt::black, Qt::DiagCrossPattern} + ); + + m_scannerBodyFrontWallItem = addRect( + QRectF{}, + QPen{Qt::lightGray, 0}, + QBrush{Qt::lightGray, Qt::DiagCrossPattern} + ); + using namespace orphex::constants; m_laserPlaneItem = addLine(laserPlane, QPen{Qt::black, 0}); m_laserPlaneItem->stackBefore(m_lenseItem); @@ -55,7 +130,7 @@ GraphicsScene::GraphicsScene(QObject* parent) m_desiredImagePlaneItem = new QGraphicsLineItem(QLineF{}, m_lenseItem); m_desiredImagePlaneItem->setPen(QPen{Qt::yellow, 0.15}); - m_desiredImagePlaneItem->stackBefore(m_sensorItem); + m_desiredImagePlaneItem->stackBefore(m_yzSensorItem); m_desiredRangeAreaItem = new QGraphicsPolygonItem{m_lenseItem}; m_desiredRangeAreaItem->setPen( @@ -71,10 +146,18 @@ GraphicsScene::GraphicsScene(QObject* parent) m_actualRangeItem->setOpacity(0.5); m_actualRangeAreaItem = new QGraphicsPolygonItem{m_lenseItem}; - m_actualRangeAreaItem->setPen(QPen{m_sensorItem->pen().color(), 0}); - m_actualRangeAreaItem->setBrush(QBrush{m_sensorItem->pen().color()}); + m_actualRangeAreaItem->setPen(QPen{m_yzSensorItem->pen().color(), 0}); + m_actualRangeAreaItem->setBrush(QBrush{m_yzSensorItem->pen().color()}); m_actualRangeAreaItem->setOpacity(0.1); + m_xzActualRangeAreaItem = addPolygon( + {}, + m_actualRangeItem->pen(), + m_actualRangeAreaItem->brush() + ); + m_xzActualRangeAreaItem->setOpacity(0.1); + // m_xzActualRangeAreaItem->setParentItem(m_lenseItem); + m_sensorLenseIntersectionItem = new QGraphicsEllipseItem{ QRectF{QPointF{-1, -1}, QPointF{1, 1}}, m_lenseItem @@ -110,6 +193,23 @@ GraphicsScene::GraphicsScene(QObject* parent) lenseLaserTextItem->setDefaultTextColor( m_lenseLaserIntersectionItem->pen().color() ); + + m_xzHardwareLaserPlaneItem = addPolygon( + QPolygonF{}, + // QPen{orphex::constants::laserColor, 0.}, + QPen{Qt::black, 0.}, + // QBrush{orphex::constants::laserColor, Qt::DiagCrossPattern} + QBrush{Qt::black, Qt::DiagCrossPattern} + ); + m_xzHardwareLaserPlaneItem->setOpacity(0.2); + m_xzHardwareLaserPlaneItem->setParentItem(m_laserBodyItem); + m_xzDebugItem = addPolygon( + QPolygonF{}, + QPen{Qt::green, 0.}, + QBrush{Qt::green, Qt::DiagCrossPattern} + ); + m_xzDebugItem->setOpacity(0.1); + m_xzDebugItem->setParentItem(m_laserBodyItem); } void GraphicsScene::update(OpticalDesign* design) @@ -221,17 +321,59 @@ void GraphicsScene::update(OpticalDesign* design) const auto offset = sensorLine.pointAt(1 + offsetRatio) - sensorLine.p2(); sensorLine.setPoints(sensorLine.p1() + offset, sensorLine.p2() + offset); - m_sensorItem->setLine(sensorLine); + m_yzSensorItem->setLine(sensorLine); + + const auto sensorHalfWidth = design->get_sensorWidthMm() / 2.; + const QRectF xzSensorRect{ + QPointF{ + // m_yzSensorItem->mapToScene(sensorLine.p1()).x(), + sensorLine.p1().x(), + sensorHalfWidth + }, + QPointF{ + // m_yzSensorItem->mapToScene(sensorLine.p2()).x(), + sensorLine.p2().x(), + -sensorHalfWidth + } + }; + m_xzSensorItem->setRect(xzSensorRect); + + // const auto yzFoVAngle = QLineF{m_lenseItem->pos(), } + // const auto axisAngleD = design->get_opticalAxisAngleDegrees(); + // const QLineF sceneAxis{ + // m_opticalAxisItem->mapToScene(m_opticalAxisItem->line().p1()), + // m_opticalAxisItem->mapToScene(m_opticalAxisItem->line().p1()) + // }; + // for (auto& p : xzActualRangePolygon) + // { + // // qDebug() << "AZAZA hyp:" << p.x(); + // // p.setX(sceneAxis.x1()); + // // qt_noop(); + // // p.setX(std::sin(qDegreesToRadians(axisAngleD)) * p.x()); + // // p.setX(std::cos(qDegreesToRadians(axisAngleD)) * p.x()); + // // p.setX(p.x() / std::cos(qDegreesToRadians(axisAngleD))); + // // p.setX(m_lenseItem->mapFromScene(p).x()); + // p = QPointF + // } + + // m_xzActualRangeAreaItem->setRotation(180.); + + const auto p1 = xzSensorRect.topLeft(); + const auto p2 = xzSensorRect.bottomRight(); // find laser plane range which corresponds to sensor position m_actualRangeItem->setLine({ - imageToObject(m_sensorItem->line().p1()), - imageToObject(m_sensorItem->line().p2()), + imageToObject(m_yzSensorItem->line().p1()), + imageToObject(m_yzSensorItem->line().p2()), }); - // not that object area has negative coords + // note that object area has negative coords + // const auto tmp = m_actualRangeItem->line(); + // const auto tmp2 = m_actualRangeItem->mapToScene(tmp.p1()); + design->set_actualZBaseMm( - -m_actualRangeItem->mapToScene(m_actualRangeItem->line().p1()).x() + -m_actualRangeItem->mapToScene(m_actualRangeItem->line().p1()).x() /*+ + design->fullBodyOffset()*/ ); design->set_actualZRangeMm(m_actualRangeItem->line().length()); @@ -256,13 +398,17 @@ void GraphicsScene::update(OpticalDesign* design) // fill actual range area m_actualRangeAreaItem->setPolygon( QPolygonF{ - {m_sensorItem->line().p1(), - m_sensorItem->line().p2(), + {m_yzSensorItem->line().p1(), + m_yzSensorItem->line().p2(), m_actualRangeItem->line().p2(), m_actualRangeItem->line().p1()} } ); + design->set_vFoVDegrees( + orphex::vFoVDegrees(m_yzSensorItem->line(), m_actualRangeItem->line()) + ); + design->set_sensorLenseAngleDegrees( m_desiredImagePlaneItem->line().angleTo(m_lineOfActionItem->line()) ); @@ -273,7 +419,7 @@ void GraphicsScene::update(OpticalDesign* design) // TODO: draw lines? QPointF sensorLenseIntersection{}; - if (m_sensorItem->line().intersects( + if (m_yzSensorItem->line().intersects( m_lineOfActionItem->line(), &sensorLenseIntersection ) == QLineF::NoIntersection) @@ -317,7 +463,7 @@ void GraphicsScene::update(OpticalDesign* design) ROI |= m_actualRangeAreaItem->boundingRect(); ROI |= m_desiredRangeAreaItem->boundingRect(); ROI |= m_lenseItem->boundingRect(); - ROI |= m_sensorItem->boundingRect(); + ROI |= m_yzSensorItem->boundingRect(); ROI |= m_sensorLenseIntersectionItem->boundingRect(); ROI |= m_lenseLaserIntersectionItem->boundingRect(); @@ -332,7 +478,7 @@ void GraphicsScene::update(OpticalDesign* design) // calculate distance between sensor and lense on optical axis QPointF sensorAxisIntersection{}; - if (m_sensorItem->line().intersects( + if (m_yzSensorItem->line().intersects( m_opticalAxisItem->line(), &sensorAxisIntersection ) == QLineF::NoIntersection) @@ -425,5 +571,123 @@ void GraphicsScene::update(OpticalDesign* design) design->set_frontSharpDistanceMm(R1Mm); design->set_backSharpDistanceMm(R2Mm); - design->set_depthOfFieldMm((R2Mm - R1Mm)); + const auto depthOfFieldMm = R2Mm - R1Mm; + design->set_depthOfFieldMm(depthOfFieldMm); + + if (qFuzzyIsNull(depthOfFieldMm)) + { + emit design->depthOfFieldMmChanged(); + emit design->depthOfFieldMmChanged(depthOfFieldMm); + } + + m_lenseBodyItem->setRect( + orphex::lenseBodyRect( + design->get_lenseBodyMaxDiameterMm(), + design->get_lenseBodyLengthMm() + ) + ); + + m_laserBodyItem->setRect( + orphex::laserBodyRect( + design->get_laserBodyDiameterMm(), + design->get_laserBodyLengthMm() + ) + ); + + m_scannerBodyFrontWallItem->setRect( + orphex::scannerBodyFrontWallRect( + design->get_scannerBodyWallThicknessMm(), + design->get_scannerBodyFrontWallOffsetMm() + ) + ); + + { + m_xzHardwareLaserPlaneItem->setPolygon( + orphex::xzLaserAreaPolygon(design->get_laserAngleDegrees()) + ); + } + + { + const auto item = m_actualRangeItem; + const auto line = item->line(); + const auto x1 = item->mapToScene(line.p1()).x(); + const auto x2 = item->mapToScene(line.p2()).x(); + QPolygonF xzActualRangePolygon{QList<QPointF>{ + QPointF{x1, imageToObject(m_xzSensorItem->rect().topLeft()).y()}, + QPointF{x1, imageToObject(m_xzSensorItem->rect().bottomLeft()).y()}, + QPointF{ + x2, + imageToObject(m_xzSensorItem->rect().bottomRight()).y() + }, + QPointF{x2, imageToObject(m_xzSensorItem->rect().topRight()).y()}, + }}; + m_xzActualRangeAreaItem->setPolygon(xzActualRangePolygon); + + m_xzDebugItem->setPolygon( + QPolygonF{QList<QPointF>{ + QPointF{0., 0.}, + QPointF{ + x1, + imageToObject(m_xzSensorItem->rect().topLeft()).y() + }, + QPointF{ + x1, + imageToObject(m_xzSensorItem->rect().bottomLeft()).y() + }, + }} + ); + } +} + +double orphex::vFoVDegrees( + const QLineF& vSensorPlane, + const QLineF& vLaserRange +) +{ + const auto sl = vSensorPlane; + const auto arl = vLaserRange; + + const QLineF l0{sl.p1(), arl.p1()}; + const QLineF l1{sl.p2(), arl.p2()}; + + return l1.angleTo(l0); +} + +QRectF orphex::lenseBodyRect(const double diameterMm, const double lengthMm) +{ + return QRectF{ + QPointF{-lengthMm, -diameterMm / 2.}, + QSizeF{lengthMm, diameterMm} + }; +} + +QRectF orphex::laserBodyRect(const double diameterMm, const double lengthMm) +{ + return QRectF{QPointF{0., -diameterMm / 2.}, QSizeF{lengthMm, diameterMm}}; +} + +QRectF orphex::scannerBodyFrontWallRect( + const double thicknessMm, + const double offsetMm +) +{ + return QRectF{ + QPointF{offsetMm - thicknessMm, -1000.}, + QPointF{offsetMm, 1000.} + }; +} + +QList<QPointF> orphex::xzLaserAreaPolygon(const double laserAngle) +{ + QLineF line{QPointF{0., 0.}, QPointF{-1000., 0.}}; + + line.setAngle(180. + laserAngle / 2.); + + QList<QPointF> result{QPointF{0., 0.}, line.p2()}; + + line.setAngle(180. - laserAngle / 2.); + + result << line.p2(); + + return result; } diff --git a/src/graphicsscene.h b/src/graphicsscene.h index 1c50c78..1303eb2 100644 --- a/src/graphicsscene.h +++ b/src/graphicsscene.h @@ -21,17 +21,33 @@ public slots: private: QGraphicsLineItem* m_lineOfActionItem{nullptr}; QGraphicsEllipseItem* m_lenseItem{nullptr}; + QGraphicsRectItem* m_lenseBodyItem{nullptr}; QGraphicsLineItem* m_opticalAxisItem{nullptr}; + QGraphicsLineItem* m_lenseVerticalPlaneItem{nullptr}; + QGraphicsRectItem* m_laserBodyItem{nullptr}; QGraphicsLineItem* m_laserPlaneItem{nullptr}; QGraphicsLineItem* m_desiredLaserPlaneItem{nullptr}; QGraphicsLineItem* m_reverseLaserPlaneItem{nullptr}; QGraphicsLineItem* m_desiredImagePlaneItem{nullptr}; - QGraphicsLineItem* m_sensorItem{nullptr}; + QGraphicsLineItem* m_yzSensorItem{nullptr}; + QGraphicsRectItem* m_xzSensorItem{nullptr}; + QGraphicsLineItem* m_actualRangeItem{nullptr}; QGraphicsPolygonItem* m_desiredRangeAreaItem{nullptr}; QGraphicsPolygonItem* m_actualRangeAreaItem{nullptr}; + QGraphicsPolygonItem* m_xzActualRangeAreaItem{nullptr}; + + QGraphicsRectItem* m_scannerBodyFrontWallItem{nullptr}; + + /*! + * \brief m_xzHardwareLaserPlaneItem - actual laser-illuminated area, + * limited by its angle + */ + QGraphicsPolygonItem* m_xzHardwareLaserPlaneItem{nullptr}; + // debug QGraphicsEllipseItem* m_sensorLenseIntersectionItem{nullptr}; QGraphicsEllipseItem* m_lenseLaserIntersectionItem{nullptr}; + QGraphicsPolygonItem* m_xzDebugItem{nullptr}; }; diff --git a/src/main.cpp b/src/main.cpp index 96ec1e3..dce33fc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,10 +2,14 @@ #include <QApplication> +#include "opticaldesign.h" + int main(int argc, char *argv[]) { QApplication a(argc, argv); + qRegisterMetaType<orphex::LenseAperture>("orphex::LenseAperture"); + a.setApplicationName("OpticalDesign"); a.setApplicationDisplayName("Optical Design"); // TODO: move to cmake diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index e73df5a..464beb4 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -4,11 +4,13 @@ #include <QComboBox> #include <QDoubleSpinBox> #include <QFormLayout> +#include <QGroupBox> #include <QHBoxLayout> #include <QLabel> #include <QOpenGLWidget> #include <QShortcut> #include <QStyle> +#include <QTimer> // optical design #include "graphicsscene.h" @@ -38,8 +40,9 @@ void MainWindow::initUi() const auto mainLayout = new QHBoxLayout{mainWidget}; mainWidget->setLayout(mainLayout); - // addLayout sets parent below - const auto leftLayout = new QFormLayout{}; + + const auto leftPanel = new QWidget{mainWidget}; + const auto leftLayout = new QFormLayout{mainWidget}; leftLayout->setLabelAlignment(Qt::AlignVCenter | Qt::AlignRight); mainLayout->addLayout(leftLayout); @@ -59,6 +62,22 @@ void MainWindow::initUi() using MinValue = double; using MaxValue = double; using SingleStep = double; + + const auto newGroup = [mainWidget, leftLayout](const QString&& title) { + const auto group = new QGroupBox{std::move(title), mainWidget}; + const auto layout = new QFormLayout{group}; + leftLayout->addRow(group); + + return group; + }; + + const auto lenseGroup = newGroup(tr("Lense")); + const auto sensorGroup = newGroup(tr("Sensor")); + const auto rangeGroup = newGroup(tr("Range")); + const auto laserGroup = newGroup(tr("Laser")); + const auto scannerBodyGroup = newGroup(tr("Scanner Body")); + const auto resultsGroup = newGroup(tr("Results")); + auto addFormPair = [this, leftLayout, connectWidgetToProperty]( const QString text, const auto propertySignal, @@ -66,7 +85,8 @@ void MainWindow::initUi() const auto propertySetter, const MinValue minValue, const MaxValue maxValue, - const SingleStep singleStep = 0.1 + const SingleStep singleStep = 0.1, + const QGroupBox* groupBox = nullptr ) { const auto spinBox = new QDoubleSpinBox{centralWidget()}; spinBox->setRange(minValue, maxValue); @@ -87,14 +107,25 @@ void MainWindow::initUi() std::bind(&GraphicsScene::update, m_scene, m_design) ); - leftLayout->addRow(text, spinBox); + if (groupBox) + { + const auto formLayout = + qobject_cast<QFormLayout*>(groupBox->layout()); + Q_ASSERT(formLayout); + formLayout->addRow(text, spinBox); + } + else + { + leftLayout->addRow(text, spinBox); + } }; using Decimals = int; auto addFormLabel = [this, leftLayout]( const QString text, const auto propertySignal, - const Decimals decimals = 2 + const Decimals decimals = 2, + const QGroupBox* groupBox = nullptr ) { const auto label = new QLabel{centralWidget()}; @@ -102,15 +133,28 @@ void MainWindow::initUi() m_design, propertySignal, label, - [label, decimals](const auto value) { + [label, decimals, text](const auto value) { + qDebug() << "AZAZA: changed:" << text << value; label->setText(QString::number(value, 'F', decimals)); } ); - leftLayout->addRow(text, label); + if (groupBox) + { + const auto formLayout = + qobject_cast<QFormLayout*>(groupBox->layout()); + Q_ASSERT(formLayout); + formLayout->addRow(text, label); + } + else + { + leftLayout->addRow(text, label); + } }; - const auto createLenseApertureComboBox = [this, leftLayout]() { + const auto createLenseApertureComboBox = [this](QFormLayout* formLayout) { + Q_ASSERT(formLayout); + const auto comboBox = new QComboBox{centralWidget()}; using namespace orphex; @@ -143,17 +187,20 @@ void MainWindow::initUi() ); // update combobox on property change + const auto onApertureChanged = [this, comboBox](const auto value) { + comboBox->setCurrentIndex( + comboBox->findData(QVariant::fromValue(value)) + ); + }; connect( m_design, qOverload<LenseAperture>(&OpticalDesign::lenseApertureChanged), comboBox, - [comboBox](const auto value) { - comboBox->setCurrentIndex( - comboBox->findData(QVariant::fromValue(value)) - ); - } + onApertureChanged ); + onApertureChanged(m_design->get_lenseAperture()); + connect( m_design, qOverload<>(&OpticalDesign::lenseApertureChanged), @@ -161,7 +208,7 @@ void MainWindow::initUi() std::bind(&GraphicsScene::update, m_scene, m_design) ); - leftLayout->addRow(tr("Lense A&perture:"), comboBox); + formLayout->addRow(tr("A&perture:"), comboBox); }; addFormPair( @@ -170,17 +217,20 @@ void MainWindow::initUi() &OpticalDesign::get_opticalAxisAngleDegrees, &OpticalDesign::set_opticalAxisAngleDegrees, MinValue{10.}, - MaxValue{85.} + MaxValue{85.}, + SingleStep{0.1}, + lenseGroup ); addFormPair( - tr("Lense &Y pos (mm):"), + tr("&Y pos (mm):"), qOverload<double>(&OpticalDesign::lenseYPosMmChanged), &OpticalDesign::get_lenseYPosMm, &OpticalDesign::set_lenseYPosMm, MinValue{10.}, MaxValue{500.}, - SingleStep{1.} + SingleStep{1.}, + lenseGroup ); addFormPair( @@ -189,7 +239,9 @@ void MainWindow::initUi() &OpticalDesign::get_focalDistanceMm, &OpticalDesign::set_focalDistanceMm, MinValue{1.}, - MaxValue{45.} + MaxValue{45.}, + SingleStep{0.1}, + lenseGroup ); addFormPair( tr("&Back Focal Distance (mm):"), @@ -197,55 +249,90 @@ void MainWindow::initUi() &OpticalDesign::get_backFocalDistanceMm, &OpticalDesign::set_backFocalDistanceMm, MinValue{1.}, - MaxValue{45.} + MaxValue{45.}, + SingleStep{0.1}, + lenseGroup + ); + + createLenseApertureComboBox( + qobject_cast<QFormLayout*>(lenseGroup->layout()) + ); + + addFormPair( + tr("Body Max Diameter (mm):"), + qOverload<double>(&OpticalDesign::lenseBodyMaxDiameterMmChanged), + &OpticalDesign::get_lenseBodyMaxDiameterMm, + &OpticalDesign::set_lenseBodyMaxDiameterMm, + MinValue{1.}, + MaxValue{100.}, + SingleStep{1.}, + lenseGroup ); - createLenseApertureComboBox(); + addFormPair( + tr("Body Length (mm):"), + qOverload<double>(&OpticalDesign::lenseBodyLengthMmChanged), + &OpticalDesign::get_lenseBodyLengthMm, + &OpticalDesign::set_lenseBodyLengthMm, + MinValue{1.}, + MaxValue{100.}, + SingleStep{1.}, + lenseGroup + ); addFormPair( - tr("Sensor &Width (mm):"), + tr("&Width (mm):"), qOverload<double>(&OpticalDesign::sensorWidthMmChanged), &OpticalDesign::get_sensorWidthMm, &OpticalDesign::set_sensorWidthMm, MinValue{1.}, - MaxValue{30.} + MaxValue{30.}, + SingleStep{0.1}, + sensorGroup ); addFormPair( - tr("Sensor &Height (mm):"), + tr("&Height (mm):"), qOverload<double>(&OpticalDesign::sensorHeightMmChanged), &OpticalDesign::get_sensorHeightMm, &OpticalDesign::set_sensorHeightMm, MinValue{1.}, - MaxValue{30.} + MaxValue{30.}, + SingleStep{0.1}, + sensorGroup ); addFormPair( - tr("Sensor Cell W&idth (mm):"), + tr("Cell W&idth (µm):"), qOverload<double>(&OpticalDesign::sensorCellWidthUmChanged), &OpticalDesign::get_sensorCellWidthUm, &OpticalDesign::set_sensorCellWidthUm, MinValue{1.}, - MaxValue{30.} + MaxValue{30.}, + SingleStep{0.1}, + sensorGroup ); addFormPair( - tr("Sensor Cell H&eight (mm):"), + tr("Cell H&eight (µm):"), qOverload<double>(&OpticalDesign::sensorCellHeightUmChanged), &OpticalDesign::get_sensorCellHeightUm, &OpticalDesign::set_sensorCellHeightUm, MinValue{1.}, - MaxValue{30.} + MaxValue{30.}, + SingleStep{0.1}, + sensorGroup ); addFormPair( - tr("Sensor Vertical &Offset (mm):"), + tr("Vertical &Offset (mm):"), qOverload<double>(&OpticalDesign::sensorVerticalOffsetMmChanged), &OpticalDesign::get_sensorVerticalOffsetMm, &OpticalDesign::set_sensorVerticalOffsetMm, MinValue{-50.}, MaxValue{50.}, - SingleStep{0.1} + SingleStep{0.1}, + sensorGroup ); addFormPair( @@ -255,7 +342,8 @@ void MainWindow::initUi() &OpticalDesign::set_zBaseMm, MinValue{1.}, MaxValue{10000.}, - SingleStep{1.} + SingleStep{1.}, + rangeGroup ); addFormPair( @@ -265,49 +353,144 @@ void MainWindow::initUi() &OpticalDesign::set_zRangeMm, MinValue{1.}, MaxValue{10000.}, - SingleStep{1.} + SingleStep{1.}, + rangeGroup + ); + + addFormPair( + tr("Body Diameter (mm):"), + qOverload<double>(&OpticalDesign::laserBodyDiameterMmChanged), + &OpticalDesign::get_laserBodyDiameterMm, + &OpticalDesign::set_laserBodyDiameterMm, + MinValue{1.}, + MaxValue{100.}, + SingleStep{1.}, + laserGroup + ); + + addFormPair( + tr("Body Length (mm):"), + qOverload<double>(&OpticalDesign::laserBodyLengthMmChanged), + &OpticalDesign::get_laserBodyLengthMm, + &OpticalDesign::set_laserBodyLengthMm, + MinValue{1.}, + MaxValue{100.}, + SingleStep{1.}, + laserGroup + ); + + addFormPair( + tr("Angle (°):"), + qOverload<double>(&OpticalDesign::laserAngleDegreesChanged), + &OpticalDesign::get_laserAngleDegrees, + &OpticalDesign::set_laserAngleDegrees, + MinValue{1.}, + MaxValue{180.}, + SingleStep{1.}, + laserGroup + ); + addFormPair( + tr("Z Offest (mm):"), + qOverload<double>(&OpticalDesign::laserZOffsetMmChanged), + &OpticalDesign::get_laserZOffsetMm, + &OpticalDesign::set_laserZOffsetMm, + MinValue{-100.}, + MaxValue{100.}, + SingleStep{1.}, + laserGroup + ); + + addFormPair( + tr("Wall Thickness (mm):"), + qOverload<double>(&OpticalDesign::scannerBodyWallThicknessMmChanged), + &OpticalDesign::get_scannerBodyWallThicknessMm, + &OpticalDesign::set_scannerBodyWallThicknessMm, + MinValue{1.}, + MaxValue{30.}, + SingleStep{1.}, + scannerBodyGroup + ); + + addFormPair( + tr("Front Wall Offset (mm):"), + qOverload<double>(&OpticalDesign::scannerBodyFrontWallOffsetMmChanged), + &OpticalDesign::get_scannerBodyFrontWallOffsetMm, + &OpticalDesign::set_scannerBodyFrontWallOffsetMm, + MinValue{-50.}, + MaxValue{50.}, + SingleStep{1.}, + scannerBodyGroup ); addFormLabel( tr("Sensor/Lense Angle (°):"), qOverload<double>(&OpticalDesign::sensorLenseAngleDegreesChanged), - Decimals{3} + Decimals{3}, + resultsGroup ); addFormLabel( - tr("Actual Z Base (mm):"), - qOverload<double>(&OpticalDesign::actualZBaseMmChanged), - Decimals{2} + tr("FoV (YZ, V) (°):"), + qOverload<double>(&OpticalDesign::vFoVDegreesChanged), + Decimals{3}, + resultsGroup ); + // addFormLabel( + // tr("Actual Z Base (mm):"), + // qOverload<double>(&OpticalDesign::actualZBaseMmChanged), + // Decimals{2}, + // resultsGroup + // ); + + { + const auto actualZBaseTextLabel = new QLabel{centralWidget()}; + + connect( + m_design, + &OpticalDesign::actualZBaseTextChanged, + actualZBaseTextLabel, + &QLabel::setText + ); + + auto formLayout = qobject_cast<QFormLayout*>(resultsGroup->layout()); + Q_ASSERT(formLayout); + formLayout->addRow(tr("Actual Z Base (mm):"), actualZBaseTextLabel); + } + addFormLabel( tr("Actual Z Range (mm):"), qOverload<double>(&OpticalDesign::actualZRangeMmChanged), - Decimals{2} + Decimals{2}, + resultsGroup ); addFormLabel( tr("Lense-Sensor Distance (mm):"), qOverload<double>(&OpticalDesign::lenseSensorDistanceMmChanged), - Decimals{2} + Decimals{2}, + resultsGroup ); addFormLabel( tr("Front Sharp Distance (mm):"), qOverload<double>(&OpticalDesign::frontSharpDistanceMmChanged), - Decimals{2} + Decimals{2}, + resultsGroup ); addFormLabel( tr("Back Sharp Distance (mm):"), qOverload<double>(&OpticalDesign::backSharpDistanceMmChanged), - Decimals{2} + Decimals{2}, + resultsGroup ); addFormLabel( tr("Depth Of Field (mm):"), qOverload<double>(&OpticalDesign::depthOfFieldMmChanged), - Decimals{2} + Decimals{2}, + resultsGroup ); // graphics view diff --git a/src/mainwindow.h b/src/mainwindow.h index 3b4922a..a1e613d 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -2,6 +2,7 @@ // qt #include <QMainWindow> +#include <QProperty> // optical design class GraphicsScene; @@ -13,7 +14,7 @@ class MainWindow : public QMainWindow Q_OBJECT public: - MainWindow(QWidget *parent = nullptr); + explicit MainWindow(QWidget* parent = nullptr); ~MainWindow(); private: diff --git a/src/opticaldesign.cpp b/src/opticaldesign.cpp index 01f6050..15d8001 100644 --- a/src/opticaldesign.cpp +++ b/src/opticaldesign.cpp @@ -3,6 +3,32 @@ // qt #include <QSize> +OpticalDesign::OpticalDesign(QObject* parent) + : goodies::G_Object{parent} +{ + const auto emitActualZBaseTextChanged = [this]() { + emit actualZBaseTextChanged(actualZBaseText()); + }; + connect( + this, + qOverload<>(&OpticalDesign::actualZBaseMmChanged), + this, + emitActualZBaseTextChanged + ); + connect( + this, + qOverload<>(&OpticalDesign::scannerBodyFrontWallOffsetMmChanged), + this, + emitActualZBaseTextChanged + ); + connect( + this, + qOverload<>(&OpticalDesign::scannerBodyWallThicknessMmChanged), + this, + emitActualZBaseTextChanged + ); +} + void OpticalDesign::calculate() const { const auto F = get_focalDistanceMm(); @@ -12,3 +38,25 @@ void OpticalDesign::calculate() const const auto hMm = get_sensorHeightMm(); const auto oAngle = get_opticalAxisAngleDegrees(); } + +/* +double OpticalDesign::fullBodyOffset() const +{ + return get_scannerBodyFrontWallOffsetMm() - + get_scannerBodyWallThicknessMm(); +} +*/ + +QString OpticalDesign::actualZBaseText() const +{ + constexpr int decimals{2}; + return QStringLiteral("%1 (%2)") + .arg(get_actualZBaseMm(), 0, 'f', decimals) + .arg( + get_actualZBaseMm() + get_scannerBodyFrontWallOffsetMm() - + get_scannerBodyWallThicknessMm(), + 0, + 'f', + decimals + ); +} diff --git a/src/opticaldesign.h b/src/opticaldesign.h index 5a7ebac..c1ff634 100644 --- a/src/opticaldesign.h +++ b/src/opticaldesign.h @@ -16,6 +16,7 @@ enum class LenseAperture F1_2 = 12, F1_4 = 14, F2_0 = 20, + F2_5 = 25, F2_8 = 28, F4_0 = 40, F5_6 = 56, @@ -34,20 +35,32 @@ enum class LenseAperture Q_ENUM_NS(LenseAperture) } // namespace orphex -// Q_DECLARE_METATYPE(orphex::LenseAperture) - class OpticalDesign : public goodies::G_Object { Q_OBJECT - DEFAULT_CONSTRUCTOR(goodies::G_Object, OpticalDesign) DEFAULT_DESTRUCTOR(OpticalDesign); G_OBJECT(goodies::G_Object, OpticalDesign) +protected: + Q_PROPERTY( + QString actualZBaseText READ actualZBaseText NOTIFY + actualZBaseTextChanged FINAL + ) + +public: + explicit OpticalDesign(QObject* parent = nullptr); + public: void calculate() const; -protected: +public: + /*! + * \brief fullBodyOffset - negative offset of body border from lense center + */ + // double fullBodyOffset() const; + +private: INI_PROPERTY(double, opticalAxisAngleDegrees, 45.); // the Y axis is directed from the laser to the lens INI_PROPERTY(double, lenseYPosMm, 50.); @@ -60,23 +73,51 @@ protected: lenseAperture, orphex::LenseAperture::F1_2 ); + + INI_PROPERTY(double, lenseBodyMaxDiameterMm, 14.); + INI_PROPERTY(double, lenseBodyLengthMm, 17.); + // default values for IMX287 sensor INI_PROPERTY(double, sensorWidthMm, 4.98); INI_PROPERTY(double, sensorHeightMm, 3.74); + INI_PROPERTY(double, sensorCellWidthUm, 6.9); INI_PROPERTY(double, sensorCellHeightUm, 6.9); + // sensor vertical offset along the image plane INI_PROPERTY(double, sensorVerticalOffsetMm, 0.); + INI_PROPERTY(uint16_t, sensorPixelsHeight, 720); INI_PROPERTY(uint16_t, sensorPixelsWidth, 544); + INI_PROPERTY(double, zBaseMm, 90); INI_PROPERTY(double, zRangeMm, 250); + INI_PROPERTY(double, laserBodyDiameterMm, 14.); + INI_PROPERTY(double, laserBodyLengthMm, 45.); + INI_PROPERTY(double, laserAngleDegrees, 45.); + INI_PROPERTY(double, laserZOffsetMm, 0.); + + INI_PROPERTY(double, scannerBodyWallThicknessMm, 3.); + + INI_PROPERTY(double, scannerBodyFrontWallOffsetMm, -20.); + G_PROPERTY_DEFAULT(double, sensorLenseAngleDegrees, 0.); + G_PROPERTY_DEFAULT(double, vFoVDegrees, 0.); + // takes scanner body into account G_PROPERTY_DEFAULT(double, actualZBaseMm, 0.); G_PROPERTY_DEFAULT(double, actualZRangeMm, 0.); G_PROPERTY_DEFAULT(double, lenseSensorDistanceMm, 0.); G_PROPERTY_DEFAULT(double, frontSharpDistanceMm, 0.); G_PROPERTY_DEFAULT(double, backSharpDistanceMm, 0.); G_PROPERTY_DEFAULT(double, depthOfFieldMm, 0.); + + // manual properties +signals: + void actualZBaseTextChanged(QString value); + +public: + QString actualZBaseText() const; }; + +Q_DECLARE_METATYPE(orphex::LenseAperture) |
