TaskImage: rework interactive scaling tool.

This commit is contained in:
Paddle
2023-04-09 08:10:59 +02:00
parent 9172157d40
commit 0acbb881cb
3 changed files with 135 additions and 126 deletions

View File

@@ -25,14 +25,18 @@
#ifndef _PreComp_
# include <QDialog>
# include <QPushButton>
# include <QAction>
# include <map>
# include <Inventor/SoPickedPoint.h>
# include <Inventor/events/SoLocation2Event.h>
# include <Inventor/events/SoMouseButtonEvent.h>
# include <Inventor/sensors/SoNodeSensor.h>
# include <Inventor/nodes/SoOrthographicCamera.h>
# include <Inventor/nodes/SoBaseColor.h>
# include <Inventor/nodes/SoCoordinate3.h>
# include <Inventor/nodes/SoLineSet.h>
# include <Inventor/nodes/SoAnnotation.h>
# include <Inventor/nodes/SoTransform.h>
#endif
#include <Base/Console.h>
@@ -71,6 +75,11 @@ TaskImage::TaskImage(Image::ImagePlane* obj, QWidget* parent)
aspectRatio = obj->XSize.getValue() / obj->YSize.getValue();
QAction* action = new QAction(tr("Allow points outside the image"), this);
action->setCheckable(true);
action->setChecked(false);
ui->pushButtonScale->addAction(action);
connectSignals();
}
@@ -184,20 +193,6 @@ View3DInventorViewer* TaskImage::getViewer() const
return nullptr;
}
void TaskImage::selectedPoints(size_t num)
{
if (num == 1) {
ui->labelInstruction->setText(tr("Select second point"));
}
else if (num == 2) {
ui->labelInstruction->setText(tr("Enter desired distance between the points"));
ui->pushButtonScale->setEnabled(true);
ui->quantitySpinBox->setEnabled(true);
ui->quantitySpinBox->setValue(scale->getDistance());
ui->quantitySpinBox->setFocus();
}
}
void TaskImage::scaleImage(double factor)
{
if (!feature.expired()) {
@@ -213,35 +208,22 @@ void TaskImage::scaleImage(double factor)
void TaskImage::startScale()
{
scale->activate(ui->checkBoxOutside->isChecked());
if (ui->checkBoxOutside->isChecked()) {
ui->labelInstruction->setText(tr("Select two points in the 3d view"));
}
else {
ui->labelInstruction->setText(tr("Select two points on the image"));
}
ui->checkBoxOutside->setEnabled(false);
ui->pushButtonScale->setEnabled(false);
ui->pushButtonScale->setText(tr("Accept"));
scale->activate(qAsConst(ui->pushButtonScale)->actions()[0]->isChecked());
ui->pushButtonScale->hide();
ui->pushButtonCancel->show();
ui->quantitySpinBox->setEnabled(false);
}
void TaskImage::acceptScale()
void TaskImage::acceptScale(double val)
{
scaleImage(ui->quantitySpinBox->value().getValue() / scale->getDistance());
scaleImage(val / scale->getDistance());
rejectScale();
}
void TaskImage::rejectScale()
{
scale->deactivate();
ui->labelInstruction->clear();
ui->pushButtonScale->setEnabled(true);
ui->pushButtonScale->setText(tr("Interactive"));
ui->pushButtonScale->show();
ui->pushButtonCancel->hide();
ui->quantitySpinBox->setEnabled(false);
ui->checkBoxOutside->setEnabled(true);
}
void TaskImage::onInteractiveScale()
@@ -250,20 +232,14 @@ void TaskImage::onInteractiveScale()
View3DInventorViewer* viewer = getViewer();
if (viewer) {
auto vp = Application::Instance->getViewProvider(feature.get());
scale = new InteractiveScale(viewer, vp, getNorm());
connect(scale, &InteractiveScale::selectedPoints,
this, &TaskImage::selectedPoints);
Base::Placement placement = feature->Placement.getValue();
scale = new InteractiveScale(viewer, vp, placement);
connect(scale, &InteractiveScale::scaleRequired,
this, &TaskImage::acceptScale);
}
}
if (scale) {
if (scale->isActive()) {
acceptScale();
}
else {
startScale();
}
}
startScale();
}
void TaskImage::open()
@@ -381,6 +357,8 @@ void TaskImage::updatePlacement()
if (!feature.expired()) {
feature->Placement.setValue(Pos);
if(scale)
scale->setPlacement(Pos);
}
}
@@ -403,30 +381,20 @@ void TaskImage::updateIcon()
ui->previewLabel->size()));
}
SbVec3f TaskImage::getNorm()
{
if (feature.expired())
return SbVec3f(0., 0., 1.);
// Get imagePlane normal
Base::Vector3d RN(0, 0, 1);
// move to position of Sketch
Base::Placement Plz = feature->Placement.getValue();
Base::Rotation tmp(Plz.getRotation());
tmp.multVec(RN, RN);
Plz.setRotation(tmp);
return SbVec3f(RN.x, RN.y, RN.z);
}
// ----------------------------------------------------------------------------
InteractiveScale::InteractiveScale(View3DInventorViewer* view, ViewProvider* vp, SbVec3f normal)
struct NodeData {
InteractiveScale* scale;
};
InteractiveScale::InteractiveScale(View3DInventorViewer* view, ViewProvider* vp, Base::Placement plc)
: active{false}
, allowOutsideImage{false}
, placement{plc}
, viewer{view}
, viewProv{vp}
, norm{normal}
, midPoint{SbVec3f(0,0,0)}
{
root = new SoAnnotation;
root->ref();
@@ -434,7 +402,6 @@ InteractiveScale::InteractiveScale(View3DInventorViewer* view, ViewProvider* vp,
measureLabel = new SoDatumLabel();
measureLabel->ref();
measureLabel->norm.setValue(norm);
measureLabel->string = "";
measureLabel->textColor = SbColor(1.0f, 0.149f, 0.0f);
measureLabel->size.setValue(17);
@@ -442,12 +409,39 @@ InteractiveScale::InteractiveScale(View3DInventorViewer* view, ViewProvider* vp,
measureLabel->useAntialiasing = false;
measureLabel->param1 = 0.;
measureLabel->param2 = 0.;
transform = new SoTransform();
root->addChild(transform);
setPlacement(placement);
Gui::MDIView* mdi = Gui::Application::Instance->activeDocument()->getActiveView();
distanceBox = new QuantitySpinBox(mdi);
distanceBox->setUnit(Base::Unit::Length);
distanceBox->setMinimum(0.0);
distanceBox->setMaximum(INT_MAX);
distanceBox->setButtonSymbols(QAbstractSpinBox::NoButtons);
distanceBox->setToolTip(tr("Enter desired distance between the points"));
distanceBox->setKeyboardTracking(false);
// Pressing enter will validate the tool.
connect(distanceBox, qOverload<double>(& QuantitySpinBox::valueChanged),
this, &InteractiveScale::distanceEntered);
//track camera movements to update spinbox position.
NodeData* info = new NodeData{ this };
cameraSensor = new SoNodeSensor([](void* data, SoSensor* sensor) {
NodeData* info = static_cast<NodeData*>(data);
info->scale->positionWidget();
}, info);
cameraSensor->attach(viewer->getCamera());
}
InteractiveScale::~InteractiveScale()
{
root->unref();
measureLabel->unref();
distanceBox->deleteLater();
cameraSensor->detach();
}
void InteractiveScale::activate(bool allowOutside)
@@ -467,6 +461,7 @@ void InteractiveScale::activate(bool allowOutside)
void InteractiveScale::deactivate()
{
if (viewer) {
distanceBox->hide();
points.clear();
root->removeChild(measureLabel);
static_cast<SoSeparator*>(viewer->getSceneGraph())->removeChild(root);
@@ -539,13 +534,30 @@ void InteractiveScale::collectPoint(const SbVec3f& pos3d)
double distance = getDistance(pos3d);
if (distance > Base::Precision::Confusion()) {
points.push_back(pos3d);
midPoint = points[0] + (points[1] - points[0]) / 2;
measureLabel->string = "";
positionWidget();
QSignalBlocker block(distanceBox);
distanceBox->setValue((points[1] - points[0]).length());
distanceBox->show();
distanceBox->selectNumber();
distanceBox->setFocus();
}
else {
Base::Console().Warning(std::string("Image scale"), "The second point is too close. Retry!\n");
}
}
}
Q_EMIT selectedPoints(points.size());
void InteractiveScale::positionWidget()
{
QSize wSize = distanceBox->size();
QPoint pxCoord = viewer->toQPoint(viewer->getPointOnViewport(midPoint));
pxCoord.setX(std::max(pxCoord.x() - wSize.width() / 2, 0));
pxCoord.setY(std::max(pxCoord.y() - wSize.height() / 2, 0));
distanceBox->move(pxCoord);
}
void InteractiveScale::getMouseClick(void * ud, SoEventCallback * ecb)
@@ -592,17 +604,48 @@ void InteractiveScale::getMousePosition(void * ud, SoEventCallback * ecb)
valueStr = quantity.getUserString(factor, unitStr);
scale->measureLabel->string = SbString(valueStr.toUtf8().constData());
//Update the points.
//Update the SoDatumLabel. It needs 2D points!
scale->measureLabel->pnts.setNum(2);
SbVec3f* verts = scale->measureLabel->pnts.startEditing();
verts[0] = scale->points[0];
verts[1] = pos3d;
verts[0] = scale->getCoordsOnImagePlane(scale->points[0]);
verts[1] = scale->getCoordsOnImagePlane(pos3d);
scale->measureLabel->pnts.finishEditing();
}
}
void InteractiveScale::distanceEntered(double val)
{
Q_EMIT scaleRequired(val);
}
void InteractiveScale::setPlacement(Base::Placement plc)
{
placement = plc;
double x, y, z, w;
placement.getRotation().getValue(x, y, z, w);
transform->rotation.setValue(x, y, z, w);
Base::Vector3d RN(0, 0, 1);
RN = placement.getRotation().multVec(RN);
measureLabel->norm.setValue(SbVec3f(RN.x, RN.y, RN.z));
}
SbVec3f InteractiveScale::getCoordsOnImagePlane(const SbVec3f& point)
{
// Plane form
Base::Vector3d R0(0, 0, 0), RX(1, 0, 0), RY(0, 1, 0);
// move to position of Sketch
Base::Rotation tmp(placement.getRotation());
RX = tmp.multVec(RX);
RY = tmp.multVec(RY);
Base::Vector3d S(point[0], point[1], point[2]);
S.TransformToCoordinateSystem(R0, RX, RY);
return SbVec3f(S.x, S.y, 0.);
}
// ----------------------------------------------------------------------------
TaskImageDialog::TaskImageDialog(Image::ImagePlane* obj)

View File

@@ -26,6 +26,7 @@
#include <QPointer>
#include <Gui/TaskView/TaskDialog.h>
#include <Gui/QuantitySpinBox.h>
#include <App/DocumentObserver.h>
#include <App/ImagePlane.h>
#include <memory>
@@ -35,6 +36,8 @@ class SbVec3f;
class SoEventCallback;
class SoSeparator;
class SoDatumLabel;
class SoNodeSensor;
class SoTransform;
namespace Gui {
@@ -45,7 +48,7 @@ class InteractiveScale : public QObject
Q_OBJECT
public:
explicit InteractiveScale(View3DInventorViewer* view, ViewProvider* vp, SbVec3f normal);
explicit InteractiveScale(View3DInventorViewer* view, ViewProvider* vp, Base::Placement plc);
~InteractiveScale();
void activate(bool allowOutside);
void deactivate();
@@ -54,6 +57,7 @@ public:
}
double getDistance() const;
double getDistance(const SbVec3f&) const;
void setPlacement(Base::Placement plc);
private:
static void getMouseClick(void * ud, SoEventCallback * ecb);
@@ -62,19 +66,30 @@ private:
void findPointOnImagePlane(SoEventCallback * ecb);
void findPointOnFocalPlane(SoEventCallback * ecb);
void collectPoint(const SbVec3f&);
void positionWidget();
/// give the coordinates of a line on the image plane in imagePlane (2D) coordinates
SbVec3f getCoordsOnImagePlane(const SbVec3f& point);
Q_SIGNALS:
void selectedPoints(size_t);
void scaleRequired(double);
protected Q_SLOTS:
void distanceEntered(double);
private:
bool active;
bool allowOutsideImage;
Base::Placement placement;
SoSeparator* root;
SoDatumLabel* measureLabel;
SoTransform* transform;
QPointer<Gui::View3DInventorViewer> viewer;
ViewProvider* viewProv;
std::vector<SbVec3f> points;
SbVec3f norm;
SbVec3f midPoint;
QuantitySpinBox* distanceBox;
SoNodeSensor* cameraSensor;
};
class Ui_TaskImage;
@@ -96,12 +111,10 @@ private:
void onInteractiveScale();
View3DInventorViewer* getViewer() const;
void selectedPoints(size_t num);
void scaleImage(double);
void startScale();
void acceptScale();
void acceptScale(double val);
void rejectScale();
SbVec3f getNorm();
void restore(const Base::Placement&);
void onPreview();

View File

@@ -245,25 +245,19 @@
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="8" column="0" colspan="2">
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string/>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<item row="2" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="pushButtonScale">
<widget class="QToolButton" name="pushButtonScale">
<property name="toolTip">
<string>Interactively scale the image</string>
</property>
<property name="text">
<string>Interactive</string>
</property>
<property name="popupMode">
<enum>QToolButton::MenuButtonPopup</enum>
</property>
</widget>
</item>
<item>
@@ -286,49 +280,8 @@
</property>
</spacer>
</item>
<item>
<widget class="QCheckBox" name="checkBoxOutside">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Allow points outside the image</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="labelDistance">
<property name="text">
<string>Desired distance:</string>
</property>
</widget>
</item>
<item>
<widget class="Gui::QuantitySpinBox" name="quantitySpinBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="unit" stdset="0">
<string notr="true">mm</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0">
<widget class="QLabel" name="labelInstruction">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</widget>
</item>