diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt index 6255b96070..fd7adbde1b 100644 --- a/src/Gui/CMakeLists.txt +++ b/src/Gui/CMakeLists.txt @@ -342,8 +342,8 @@ SET(Gui_UIC_SRCS Placement.ui TextureMapping.ui TaskView/TaskAppearance.ui - TaskView/TaskImageScale.ui TaskView/TaskOrientation.ui + TaskView/TaskImage.ui TaskView/TaskSelectLinkProperty.ui TaskElementColors.ui DlgObjectSelection.ui @@ -720,12 +720,12 @@ SET(Task_View_SRCS TaskView/TaskAppearance.cpp TaskView/TaskAppearance.h TaskView/TaskAppearance.ui - TaskView/TaskImageScale.cpp - TaskView/TaskImageScale.h - TaskView/TaskImageScale.ui TaskView/TaskOrientation.cpp TaskView/TaskOrientation.h TaskView/TaskOrientation.ui + TaskView/TaskImage.cpp + TaskView/TaskImage.h + TaskView/TaskImage.ui TaskView/TaskSelectLinkProperty.cpp TaskView/TaskSelectLinkProperty.h TaskView/TaskSelectLinkProperty.ui @@ -968,6 +968,7 @@ SET(Inventor_CPP_SRCS SoNavigationDragger.cpp SoAxisCrossKit.cpp SoTextLabel.cpp + SoDatumLabel.cpp SoTouchEvents.cpp SoMouseWheelEvent.cpp SoFCCSysDragger.cpp @@ -995,6 +996,7 @@ SET(Inventor_SRCS SoNavigationDragger.h SoAxisCrossKit.h SoTextLabel.h + SoDatumLabel.h SoTouchEvents.h SoMouseWheelEvent.h SoFCCSysDragger.h @@ -1235,8 +1237,8 @@ if(MSVC) propertyeditor/PropertyItemDelegate.cpp propertyeditor/PropertyModel.cpp TaskView/TaskAppearance.cpp - TaskView/TaskImageScale.cpp TaskView/TaskOrientation.cpp + TaskView/TaskImage.cpp TaskView/TaskSelectLinkProperty.cpp TaskView/TaskEditControl.cpp TaskView/TaskView.cpp diff --git a/src/Mod/Sketcher/Gui/SoDatumLabel.cpp b/src/Gui/SoDatumLabel.cpp similarity index 99% rename from src/Mod/Sketcher/Gui/SoDatumLabel.cpp rename to src/Gui/SoDatumLabel.cpp index 1c5c4add8d..a2cde08acd 100644 --- a/src/Mod/Sketcher/Gui/SoDatumLabel.cpp +++ b/src/Gui/SoDatumLabel.cpp @@ -55,7 +55,7 @@ #define ZCONSTR 0.006f -using namespace SketcherGui; +using namespace Gui; // ------------------------------------------------------ @@ -615,11 +615,13 @@ void SoDatumLabel::GLRender(SoGLRenderAction * action) } // Perp Lines glBegin(GL_LINES); + if (length != 0.) { glVertex2f(p1[0], p1[1]); glVertex2f(perp1[0], perp1[1]); glVertex2f(p2[0], p2[1]); glVertex2f(perp2[0], perp2[1]); + } glVertex2f(par1[0], par1[1]); glVertex2f(par2[0], par2[1]); @@ -1019,3 +1021,12 @@ void SoDatumLabel::GLRender(SoGLRenderAction * action) glPopAttrib(); state->pop(); } + +void SoDatumLabel::setPoints(SbVec3f p1, SbVec3f p2) +{ + pnts.setNum(2); + SbVec3f* verts = pnts.startEditing(); + verts[0] = p1; + verts[1] = p2; + pnts.finishEditing(); +} \ No newline at end of file diff --git a/src/Mod/Sketcher/Gui/SoDatumLabel.h b/src/Gui/SoDatumLabel.h similarity index 89% rename from src/Mod/Sketcher/Gui/SoDatumLabel.h rename to src/Gui/SoDatumLabel.h index 766979d1e3..183076ec0d 100644 --- a/src/Mod/Sketcher/Gui/SoDatumLabel.h +++ b/src/Gui/SoDatumLabel.h @@ -20,8 +20,8 @@ * * ***************************************************************************/ -#ifndef SKETCHERGUI_SODATUMLABEL_H -#define SKETCHERGUI_SODATUMLABEL_H +#ifndef GUI_SODATUMLABEL_H +#define GUI_SODATUMLABEL_H #include #include @@ -35,12 +35,12 @@ #include #include -#include +#include -namespace SketcherGui { +namespace Gui { -class SketcherGuiExport SoDatumLabel : public SoShape { +class GuiExport SoDatumLabel : public SoShape { using inherited = SoShape; SO_NODE_HEADER(SoDatumLabel); @@ -60,6 +60,10 @@ public: static void initClass(); SoDatumLabel(); + /*The points have to be on XY plane, ie they need to be 2D points. + To draw on other planes, you need to attach a SoTransform to the SoDatumLabel (or parent).*/ + void setPoints(SbVec3f p1, SbVec3f p2); + SoMFString string; SoSFColor textColor; SoSFEnum datumtype; @@ -99,4 +103,4 @@ private: } -#endif // SKETCHERGUI_SODATUMLABEL_H +#endif // GUI_SODATUMLABEL_H diff --git a/src/Gui/SoFCDB.cpp b/src/Gui/SoFCDB.cpp index 1fb8002705..08598a269b 100644 --- a/src/Gui/SoFCDB.cpp +++ b/src/Gui/SoFCDB.cpp @@ -69,6 +69,7 @@ #include "SoMouseWheelEvent.h" #include "SoNavigationDragger.h" #include "SoTextLabel.h" +#include "SoDatumLabel.h" #include "Inventor/MarkerBitmaps.h" #include "Inventor/SmSwitchboard.h" #include "Inventor/SoAutoZoomTranslation.h" @@ -124,6 +125,7 @@ void Gui::SoFCDB::init() SoVRMLAction ::initClass(); SoSkipBoundingGroup ::initClass(); SoTextLabel ::initClass(); + SoDatumLabel ::initClass(); SoColorBarLabel ::initClass(); SoStringLabel ::initClass(); SoFrameLabel ::initClass(); diff --git a/src/Gui/TaskView/TaskImage.cpp b/src/Gui/TaskView/TaskImage.cpp new file mode 100644 index 0000000000..e99972864e --- /dev/null +++ b/src/Gui/TaskView/TaskImage.cpp @@ -0,0 +1,688 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later + +/*************************************************************************** + * Copyright (c) 2023 Werner Mayer * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + **************************************************************************/ + +#include "PreCompiled.h" +#ifndef _PreComp_ +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "TaskImage.h" +#include "ui_TaskImage.h" + + +using namespace Gui; + +/* TRANSLATOR Gui::TaskImage */ + +TaskImage::TaskImage(Image::ImagePlane* obj, QWidget* parent) + : QWidget(parent) + , ui(new Ui_TaskImage) + , feature(obj) + , aspectRatio(1.0) +{ + ui->setupUi(this); + ui->groupBoxCalibration->hide(); + + initialiseTransparency(); + + aspectRatio = obj->XSize.getValue() / obj->YSize.getValue(); + + connectSignals(); +} + +TaskImage::~TaskImage() +{ + if (!feature.expired() && scale) { + if (scale->isActive()) { + scale->deactivate(); + } + scale->deleteLater(); + } +} + +void TaskImage::connectSignals() +{ + connect(ui->Reverse_checkBox, &QCheckBox::clicked, + this, &TaskImage::onPreview); + connect(ui->XY_radioButton, &QRadioButton::clicked, + this, &TaskImage::onPreview); + connect(ui->XZ_radioButton, &QRadioButton::clicked, + this, &TaskImage::onPreview); + connect(ui->YZ_radioButton, &QRadioButton::clicked, + this, &TaskImage::onPreview); + connect(ui->spinBoxZ, qOverload(&QuantitySpinBox::valueChanged), + this, &TaskImage::onPreview); + connect(ui->spinBoxX, qOverload(&QuantitySpinBox::valueChanged), + this, &TaskImage::onPreview); + connect(ui->spinBoxY, qOverload(&QuantitySpinBox::valueChanged), + this, &TaskImage::onPreview); + connect(ui->spinBoxRotation, qOverload(&QuantitySpinBox::valueChanged), + this, &TaskImage::onPreview); + connect(ui->spinBoxTransparency, qOverload(&QSpinBox::valueChanged), + this, &TaskImage::changeTransparency); + connect(ui->sliderTransparency, qOverload(&QSlider::valueChanged), + this, &TaskImage::changeTransparency); + + connect(ui->spinBoxWidth, qOverload(&QuantitySpinBox::valueChanged), + this, &TaskImage::changeWidth); + connect(ui->spinBoxHeight, qOverload(&QuantitySpinBox::valueChanged), + this, &TaskImage::changeHeight); + connect(ui->pushButtonScale, &QPushButton::clicked, + this, &TaskImage::onInteractiveScale); + connect(ui->pushButtonApply, &QPushButton::clicked, + this, &TaskImage::acceptScale); + connect(ui->pushButtonCancel, &QPushButton::clicked, + this, &TaskImage::rejectScale); +} + +void TaskImage::initialiseTransparency() +{ + auto vp = Application::Instance->getViewProvider(feature.get()); + App::Property* prop = vp->getPropertyByName("Transparency"); + if (prop && prop->getTypeId().isDerivedFrom(App::PropertyInteger::getClassTypeId())) { + auto Transparency = static_cast(prop); + ui->spinBoxTransparency->setValue(Transparency->getValue()); + ui->sliderTransparency->setValue(Transparency->getValue()); + } +} + +void TaskImage::changeTransparency(int val) +{ + if (feature.expired()) + return; + + auto vp = Application::Instance->getViewProvider(feature.get()); + App::Property* prop = vp->getPropertyByName("Transparency"); + if (prop && prop->getTypeId().isDerivedFrom(App::PropertyInteger::getClassTypeId())) { + auto Transparency = static_cast(prop); + Transparency->setValue(val); + + QSignalBlocker block(ui->spinBoxTransparency); + QSignalBlocker blocks(ui->sliderTransparency); + ui->spinBoxTransparency->setValue(val); + ui->sliderTransparency->setValue(val); + } +} + +void TaskImage::changeWidth(double val) +{ + if (!feature.expired()) { + feature->XSize.setValue(val); + + if (ui->checkBoxRatio->isChecked()) { + QSignalBlocker block(ui->spinBoxWidth); + ui->spinBoxHeight->setValue(val / aspectRatio); + } + } +} + +void TaskImage::changeHeight(double val) +{ + if (!feature.expired()) { + feature->YSize.setValue(val); + + if (ui->checkBoxRatio->isChecked()) { + QSignalBlocker block(ui->spinBoxHeight); + ui->spinBoxWidth->setValue(val * aspectRatio); + } + } +} + +View3DInventorViewer* TaskImage::getViewer() const +{ + if (!feature.expired()) { + auto vp = Application::Instance->getViewProvider(feature.get()); + auto doc = static_cast(vp)->getDocument(); + auto view = dynamic_cast(doc->getViewOfViewProvider(vp)); + if (view) { + return view->getViewer(); + } + } + + return nullptr; +} + +void TaskImage::scaleImage(double factor) +{ + if (!feature.expired()) { + feature->XSize.setValue(feature->XSize.getValue() * factor); + feature->YSize.setValue(feature->YSize.getValue() * factor); + + QSignalBlocker blockW(ui->spinBoxWidth); + ui->spinBoxWidth->setValue(feature->XSize.getValue()); + QSignalBlocker blockH(ui->spinBoxHeight); + ui->spinBoxHeight->setValue(feature->YSize.getValue()); + } +} + +void TaskImage::startScale() +{ + scale->activate(); + ui->pushButtonScale->hide(); + ui->groupBoxCalibration->show(); + ui->pushButtonApply->setEnabled(false); +} + +void TaskImage::acceptScale() +{ + scaleImage(scale->getScaleFactor()); + rejectScale(); +} + +void TaskImage::enableApplyBtn() +{ + ui->pushButtonApply->setEnabled(true); +} + +void TaskImage::rejectScale() +{ + scale->deactivate(); + ui->pushButtonScale->show(); + ui->groupBoxCalibration->hide(); +} + +void TaskImage::onInteractiveScale() +{ + if (!feature.expired() && !scale) { + View3DInventorViewer* viewer = getViewer(); + if (viewer) { + auto vp = Application::Instance->getViewProvider(feature.get()); + scale = new InteractiveScale(viewer, vp, feature->globalPlacement()); + connect(scale, &InteractiveScale::scaleRequired, + this, &TaskImage::acceptScale); + connect(scale, &InteractiveScale::scaleCanceled, + this, &TaskImage::rejectScale); + connect(scale, &InteractiveScale::enableApplyBtn, + this, &TaskImage::enableApplyBtn); + } + } + + startScale(); +} + +void TaskImage::open() +{ + if (!feature.expired()) { + App::Document* doc = feature->getDocument(); + doc->openTransaction(QT_TRANSLATE_NOOP("Command", "Edit image")); + restore(feature->Placement.getValue()); + } +} + +void TaskImage::accept() +{ + if (!feature.expired()) { + App::Document* doc = feature->getDocument(); + doc->commitTransaction(); + doc->recompute(); + } +} + +void TaskImage::reject() +{ + if (!feature.expired()) { + App::Document* doc = feature->getDocument(); + doc->abortTransaction(); + feature->purgeTouched(); + } +} + +void TaskImage::onPreview() +{ + updateIcon(); + updatePlacement(); +} + +void TaskImage::restore(const Base::Placement& plm) +{ + if (feature.expired()) + return; + + QSignalBlocker blockW(ui->spinBoxWidth); + QSignalBlocker blockH(ui->spinBoxHeight); + ui->spinBoxWidth->setValue(feature->XSize.getValue()); + ui->spinBoxHeight->setValue(feature->YSize.getValue()); + + Base::Rotation rot = plm.getRotation(); + Base::Vector3d pos = plm.getPosition(); + + double yaw, pitch, roll; + rot.getYawPitchRoll(yaw, pitch, roll); + + double tol = 1.0e-5; + bool reverse = false; + if (fabs(pitch) < tol && (fabs(roll) < tol || fabs(roll - 180.) < tol)) { + if (fabs(roll - 180.) < tol) + reverse = true; + int inv = reverse ? -1 : 1; + ui->XY_radioButton->setChecked(true); + ui->spinBoxRotation->setValue(yaw * inv); + } + else if (fabs(roll - 90.) < tol && (fabs(yaw) < tol || fabs(yaw - 180.) < tol)) { + if (fabs(yaw - 180.) < tol) + reverse = true; + int inv = reverse ? -1 : 1; + ui->XZ_radioButton->setChecked(true); + ui->spinBoxRotation->setValue(- pitch); + } + else if (fabs(roll - 90.) < tol && (fabs(yaw - 90.) < tol || fabs(yaw + 90.) < tol)) { + if (fabs(yaw + 90.) < tol) + reverse = true; + int inv = reverse ? -1 : 1; + ui->YZ_radioButton->setChecked(true); + ui->spinBoxRotation->setValue(-pitch); + } + ui->Reverse_checkBox->setChecked(reverse); + + Base::Vector3d R0(0, 0, 0), RX(1, 0, 0), RY(0, 1, 0); + + RX = rot.multVec(RX); + RY = rot.multVec(RY); + pos.TransformToCoordinateSystem(R0, RX, RY); + ui->spinBoxX->setValue(pos.x); + ui->spinBoxY->setValue(pos.y); + ui->spinBoxZ->setValue(pos.z); + + onPreview(); +} + +void TaskImage::updatePlacement() +{ + double angle = ui->spinBoxRotation->value().getValue(); + bool reverse = ui->Reverse_checkBox->isChecked(); + + Base::Placement Pos; + Base::Rotation rot; + double dir = reverse ? 180. : 0.; + int inv = reverse ? -1 : 1; + + if (ui->XY_radioButton->isChecked()) { + rot.setYawPitchRoll(inv * angle, 0., dir); + } + else if (ui->XZ_radioButton->isChecked()) { + rot.setYawPitchRoll(dir, -angle, 90.); + } + else if (ui->YZ_radioButton->isChecked()) { + rot.setYawPitchRoll(90. - dir, -angle, 90.); + } + + Base::Vector3d offset = Base::Vector3d(ui->spinBoxX->value().getValue(), ui->spinBoxY->value().getValue(), ui->spinBoxZ->value().getValue()); + offset = rot.multVec(offset); + Pos = Base::Placement(offset, rot); + + if (!feature.expired()) { + feature->Placement.setValue(Pos); + if(scale) + scale->setPlacement(feature->globalPlacement()); + } +} + +void TaskImage::updateIcon() +{ + std::string icon; + bool reverse = ui->Reverse_checkBox->isChecked(); + if (ui->XY_radioButton->isChecked()) { + icon = reverse ? "view-bottom" : "view-top"; + } + else if (ui->XZ_radioButton->isChecked()) { + icon = reverse ? "view-rear" : "view-front"; + } + else if (ui->YZ_radioButton->isChecked()) { + icon = reverse ? "view-left" : "view-right"; + } + + ui->previewLabel->setPixmap( + Gui::BitmapFactory().pixmapFromSvg(icon.c_str(), + ui->previewLabel->size())); +} + +// ---------------------------------------------------------------------------- + + +struct NodeData { + InteractiveScale* scale; +}; + +InteractiveScale::InteractiveScale(View3DInventorViewer* view, ViewProvider* vp, Base::Placement plc) + : active(false) + , placement(plc) + , viewer(view) + , viewProv(vp) + , midPoint(SbVec3f(0,0,0)) +{ + root = new SoAnnotation; + root->ref(); + root->renderCaching = SoSeparator::OFF; + + measureLabel = new SoDatumLabel(); + measureLabel->ref(); + measureLabel->string = ""; + measureLabel->textColor = SbColor(1.0f, 0.149f, 0.0f); + measureLabel->size.setValue(17); + measureLabel->lineWidth = 2.0; + 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); + distanceBox->installEventFilter(this); + + //track camera movements to update spinbox position. + NodeData* info = new NodeData{ this }; + cameraSensor = new SoNodeSensor([](void* data, SoSensor* sensor) { + NodeData* info = static_cast(data); + info->scale->positionWidget(); + }, info); + cameraSensor->attach(viewer->getCamera()); +} + +InteractiveScale::~InteractiveScale() +{ + root->unref(); + measureLabel->unref(); + distanceBox->deleteLater(); + cameraSensor->detach(); +} + +void InteractiveScale::activate() +{ + if (viewer) { + static_cast(viewer->getSceneGraph())->addChild(root); + viewer->setEditing(true); + viewer->addEventCallback(SoLocation2Event::getClassTypeId(), InteractiveScale::getMousePosition, this); + viewer->addEventCallback(SoButtonEvent::getClassTypeId(), InteractiveScale::soEventFilter, this); + viewer->setSelectionEnabled(false); + viewer->getWidget()->setCursor(QCursor(Qt::CrossCursor)); + active = true; + } +} + +void InteractiveScale::deactivate() +{ + if (viewer) { + distanceBox->hide(); + points.clear(); + root->removeChild(measureLabel); + static_cast(viewer->getSceneGraph())->removeChild(root); + viewer->setEditing(false); + viewer->removeEventCallback(SoLocation2Event::getClassTypeId(), InteractiveScale::getMousePosition, this); + viewer->removeEventCallback(SoButtonEvent::getClassTypeId(), InteractiveScale::soEventFilter, this); + viewer->setSelectionEnabled(true); + viewer->getWidget()->setCursor(QCursor(Qt::ArrowCursor)); + active = false; + } +} + +double InteractiveScale::getScaleFactor() const +{ + if ((points[0] - points[1]).length() == 0.) + return 1.0; + + return distanceBox->value().getValue() / (points[0] - points[1]).length(); +} + +double InteractiveScale::getDistance(const SbVec3f& pt) const +{ + if (points.empty()) + return 0.0; + + return (points[0] - pt).length(); +} + +void InteractiveScale::findPointOnImagePlane(SoEventCallback * ecb) +{ + const SoMouseButtonEvent * mbe = static_cast(ecb->getEvent()); + Gui::View3DInventorViewer* view = static_cast(ecb->getUserData()); + std::unique_ptr pp(view->getPointOnRay(mbe->getPosition(), viewProv)); + if (pp.get()) { + auto pos3d = pp->getPoint(); + + collectPoint(pos3d); + } +} + +void InteractiveScale::collectPoint(const SbVec3f& pos3d) +{ + if (points.empty()) { + points.push_back(pos3d); + + measureLabel->setPoints(getCoordsOnImagePlane(pos3d), getCoordsOnImagePlane(pos3d)); + root->addChild(measureLabel); + } + else if (points.size() == 1) { + double distance = getDistance(pos3d); + if (distance > Base::Precision::Confusion()) { + points.push_back(pos3d); + + midPoint = points[0] + (points[1] - points[0]) / 2; + + measureLabel->string = ""; + distanceBox->show(); + QSignalBlocker block(distanceBox); + distanceBox->setValue((points[1] - points[0]).length()); + distanceBox->adjustSize(); + positionWidget(); + distanceBox->selectNumber(); + distanceBox->setFocus(); + + Q_EMIT enableApplyBtn(); + } + else { + Base::Console().Warning(std::string("Image scale"), "The second point is too close. Retry!\n"); + } + } +} + +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::getMousePosition(void * ud, SoEventCallback * ecb) +{ + InteractiveScale* scale = static_cast(ud); + const SoLocation2Event * l2e = static_cast(ecb->getEvent()); + Gui::View3DInventorViewer* view = static_cast(ecb->getUserData()); + + if (scale->points.size() == 1) { + ecb->setHandled(); + SbVec3f pos3d; + + std::unique_ptr pp(view->getPointOnRay(l2e->getPosition(), scale->viewProv)); + if (pp.get()) { + pos3d = pp->getPoint(); + } + else { + return; + } + + Base::Quantity quantity; + quantity.setValue((pos3d - scale->points[0]).length()); + quantity.setUnit(Base::Unit::Length); + + //Update the displayed distance + double factor; + QString unitStr, valueStr; + valueStr = quantity.getUserString(factor, unitStr); + scale->measureLabel->string = SbString(valueStr.toUtf8().constData()); + + scale->measureLabel->setPoints(scale->getCoordsOnImagePlane(scale->points[0]), scale->getCoordsOnImagePlane(pos3d)); + } +} + +void InteractiveScale::soEventFilter(void* ud, SoEventCallback* ecb) +{ + InteractiveScale* scale = static_cast(ud); + + const SoEvent* soEvent = ecb->getEvent(); + if (soEvent->isOfType(SoKeyboardEvent::getClassTypeId())) { + /* If user press escape, then we cancel the tool.*/ + const auto kbe = static_cast(soEvent); + + if (kbe->getKey() == SoKeyboardEvent::ESCAPE && kbe->getState() == SoButtonEvent::UP) { + ecb->setHandled(); + ecb->getAction()->setHandled(); + Q_EMIT scale->scaleCanceled(); + } + } + else if (soEvent->isOfType(SoMouseButtonEvent::getClassTypeId())) { + const auto mbe = static_cast(soEvent); + + if (mbe->getButton() == SoMouseButtonEvent::BUTTON1 && mbe->getState() == SoButtonEvent::DOWN) + { + ecb->setHandled(); + scale->findPointOnImagePlane(ecb); + } + if (mbe->getButton() == SoMouseButtonEvent::BUTTON2 && mbe->getState() == SoButtonEvent::DOWN) + { + ecb->setHandled(); + Q_EMIT scale->scaleCanceled(); + } + } +} + +bool InteractiveScale::eventFilter(QObject* object, QEvent* event) +{ + if (event->type() == QEvent::KeyRelease) { + QKeyEvent* keyEvent = static_cast(event); + + /* If user press enter in the spinbox, then we validate the tool.*/ + if (keyEvent->key() == Qt::Key_Enter && dynamic_cast(object)) { + Q_EMIT scaleRequired(); + } + + /* If user press escape, then we cancel the tool. Required here as well for when checkbox has focus.*/ + if (keyEvent->key() == Qt::Key_Escape) { + Q_EMIT scaleCanceled(); + } + } + return false; +} + +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 pos = placement.getPosition(); + transform->translation.setValue(pos.x, pos.y, pos.z); + + 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 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 pos = placement.getPosition(); + + //we use pos as the Base because in setPlacement we set transform->translation using placement.getPosition() to fix the Zoffset. But this applies the X & Y translation too. + Base::Vector3d S(point[0], point[1], point[2]); + S.TransformToCoordinateSystem(pos, RX, RY); + + return SbVec3f(S.x, S.y, 0.); +} + +// ---------------------------------------------------------------------------- + +TaskImageDialog::TaskImageDialog(Image::ImagePlane* obj) +{ + widget = new TaskImage(obj); + Gui::TaskView::TaskBox* taskbox = new Gui::TaskView::TaskBox( + Gui::BitmapFactory().pixmap("image-plane"), widget->windowTitle(), true, nullptr); + taskbox->groupLayout()->addWidget(widget); + Content.push_back(taskbox); +} + +void TaskImageDialog::open() +{ + widget->open(); +} + +bool TaskImageDialog::accept() +{ + widget->accept(); + return true; +} + +bool TaskImageDialog::reject() +{ + widget->reject(); + return true; +} + +#include "moc_TaskImage.cpp" diff --git a/src/Gui/TaskView/TaskImageScale.h b/src/Gui/TaskView/TaskImage.h similarity index 60% rename from src/Gui/TaskView/TaskImageScale.h rename to src/Gui/TaskView/TaskImage.h index 4327abee4c..5d2d0e5bed 100644 --- a/src/Gui/TaskView/TaskImageScale.h +++ b/src/Gui/TaskView/TaskImage.h @@ -21,11 +21,12 @@ * * **************************************************************************/ -#ifndef GUI_TASKIMAGESCALE_H -#define GUI_TASKIMAGESCALE_H +#ifndef GUI_TASKIMAGE_H +#define GUI_TASKIMAGE_H #include #include +#include #include #include #include @@ -33,9 +34,10 @@ class SbVec3f; class SoEventCallback; -class SoCoordinate3; class SoSeparator; -class SoLineSet; +class SoDatumLabel; +class SoNodeSensor; +class SoTransform; namespace Gui { @@ -46,65 +48,110 @@ class InteractiveScale : public QObject Q_OBJECT public: - explicit InteractiveScale(View3DInventorViewer* view, ViewProvider* vp); + explicit InteractiveScale(View3DInventorViewer* view, ViewProvider* vp, Base::Placement plc); ~InteractiveScale(); - void activate(bool allowOutside); + + bool eventFilter(QObject* object, QEvent* event); + void activate(); void deactivate(); bool isActive() const { return active; } - double getDistance() const; + double getScaleFactor() const; double getDistance(const SbVec3f&) const; - void clearPoints(); + void setPlacement(Base::Placement plc); private: - static void getMouseClick(void * ud, SoEventCallback * ecb); + static void soEventFilter(void * ud, SoEventCallback * ecb); static void getMousePosition(void * ud, SoEventCallback * ecb); - void findPointOnPlane(SoEventCallback * ecb); 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(); + void scaleCanceled(); + void enableApplyBtn(); private: bool active; - bool allowOutsideImage; - SoCoordinate3* coords; + Base::Placement placement; SoSeparator* root; + SoDatumLabel* measureLabel; + SoTransform* transform; QPointer viewer; ViewProvider* viewProv; std::vector points; + SbVec3f midPoint; + QuantitySpinBox* distanceBox; + SoNodeSensor* cameraSensor; }; -class Ui_TaskImageScale; -class TaskImageScale : public QWidget +class Ui_TaskImage; +class TaskImage : public QWidget { Q_OBJECT public: - explicit TaskImageScale(Image::ImagePlane* obj, QWidget* parent = nullptr); - ~TaskImageScale() override; + explicit TaskImage(Image::ImagePlane* obj, QWidget* parent = nullptr); + ~TaskImage() override; + + void open(); + void accept(); + void reject(); private: - void changeWidth(); - void changeHeight(); + void initialiseTransparency(); + void connectSignals(); + void onInteractiveScale(); View3DInventorViewer* getViewer() const; - void selectedPoints(size_t num); void scaleImage(double); void startScale(); void acceptScale(); void rejectScale(); + void enableApplyBtn(); + + void restore(const Base::Placement&); + void onPreview(); + void updateIcon(); + void updatePlacement(); + +private Q_SLOTS: + void changeTransparency(int val); + void changeWidth(double val); + void changeHeight(double val); private: - std::unique_ptr ui; + std::unique_ptr ui; QPointer scale; App::WeakPtrT feature; double aspectRatio; }; +class TaskImageDialog : public Gui::TaskView::TaskDialog +{ + Q_OBJECT + +public: + explicit TaskImageDialog(Image::ImagePlane* obj); + +public: + void open() override; + bool accept() override; + bool reject() override; + + QDialogButtonBox::StandardButtons getStandardButtons() const override { + return QDialogButtonBox::Ok | QDialogButtonBox::Cancel; + } + +private: + TaskImage* widget; +}; + } -#endif // GUI_TASKIMAGESCALE_H +#endif // GUI_TASKIMAGE_H diff --git a/src/Gui/TaskView/TaskImage.ui b/src/Gui/TaskView/TaskImage.ui new file mode 100644 index 0000000000..589d949f81 --- /dev/null +++ b/src/Gui/TaskView/TaskImage.ui @@ -0,0 +1,291 @@ + + + Gui::TaskImage + + + + 0 + 0 + 421 + 267 + + + + Image plane settings + + + + + + + + Planes + + + + + + XY-Plane + + + true + + + + + + + XZ-Plane + + + + + + + YZ-Plane + + + + + + + + + + + 48 + 48 + + + + + 48 + 48 + + + + Preview + + + + + + + + + Reverse direction + + + + + + + Offset: + + + + + + + mm + + + -999999999.000000000000000 + + + 999999999.000000000000000 + + + + + + + X distance: + + + + + + + mm + + + -999999999.000000000000000 + + + 999999999.000000000000000 + + + + + + + Y distance: + + + + + + + mm + + + -999999999.000000000000000 + + + 999999999.000000000000000 + + + + + + + Rotation : + + + + + + + deg + + + + + + + + + Transparency : + + + + + + + 100 + + + Qt::Horizontal + + + + + + + 0 + + + 0 + + + 100 + + + + + + + + + Image size + + + + + + Width: + + + + + + + mm + + + 0.00000001 + + + 999999999.000000000000000 + + + + + + + Height: + + + + + + + mm + + + 0.00000001 + + + 999999999.000000000000000 + + + + + + + Keep aspect ratio + + + true + + + + + + + Interactively scale the image by setting a length between two points of the image. + + + Calibrate + + + + + + + Calibration + + + + + + Apply + + + + + + + Cancel + + + + + + + + + + + + + + Gui::QuantitySpinBox + QWidget +
Gui/QuantitySpinBox.h
+
+
+ + +
diff --git a/src/Gui/TaskView/TaskImageScale.cpp b/src/Gui/TaskView/TaskImageScale.cpp deleted file mode 100644 index a09e3c7573..0000000000 --- a/src/Gui/TaskView/TaskImageScale.cpp +++ /dev/null @@ -1,369 +0,0 @@ -// SPDX-License-Identifier: LGPL-2.1-or-later - -/*************************************************************************** - * Copyright (c) 2023 Werner Mayer * - * * - * This file is part of FreeCAD. * - * * - * FreeCAD is free software: you can redistribute it and/or modify it * - * under the terms of the GNU Lesser General Public License as * - * published by the Free Software Foundation, either version 2.1 of the * - * License, or (at your option) any later version. * - * * - * FreeCAD is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with FreeCAD. If not, see * - * . * - * * - **************************************************************************/ - -#include "PreCompiled.h" -#ifndef _PreComp_ -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "TaskImageScale.h" -#include "ui_TaskImageScale.h" - - -using namespace Gui; - -/* TRANSLATOR Gui::TaskImageScale */ - -TaskImageScale::TaskImageScale(Image::ImagePlane* obj, QWidget* parent) - : QWidget(parent) - , ui(new Ui_TaskImageScale) - , feature(obj) - , aspectRatio{1.0} -{ - ui->setupUi(this); - ui->pushButtonCancel->hide(); - ui->spinBoxWidth->setValue(obj->getXSizeInPixel()); - ui->spinBoxHeight->setValue(obj->getYSizeInPixel()); - - aspectRatio = obj->XSize.getValue() / obj->YSize.getValue(); - - connect(ui->spinBoxWidth, qOverload(&QSpinBox::valueChanged), - this, &TaskImageScale::changeWidth); - connect(ui->spinBoxHeight, qOverload(&QSpinBox::valueChanged), - this, &TaskImageScale::changeHeight); - connect(ui->pushButtonScale, &QPushButton::clicked, - this, &TaskImageScale::onInteractiveScale); - connect(ui->pushButtonCancel, &QPushButton::clicked, - this, &TaskImageScale::rejectScale); -} - -TaskImageScale::~TaskImageScale() -{ - if (scale) { - if (scale->isActive()) { - scale->deactivate(); - } - scale->deleteLater(); - } -} - -void TaskImageScale::changeWidth() -{ - if (!feature.expired()) { - int value = ui->spinBoxWidth->value(); - feature->setXSizeInPixel(value); - - if (ui->checkBoxRatio->isChecked()) { - QSignalBlocker block(ui->spinBoxWidth); - ui->spinBoxHeight->setValue(int(double(value) / aspectRatio)); - } - } -} - -void TaskImageScale::changeHeight() -{ - if (!feature.expired()) { - int value = ui->spinBoxHeight->value(); - feature->setYSizeInPixel(value); - - if (ui->checkBoxRatio->isChecked()) { - QSignalBlocker block(ui->spinBoxHeight); - ui->spinBoxWidth->setValue(int(double(value) * aspectRatio)); - } - } -} - -View3DInventorViewer* TaskImageScale::getViewer() const -{ - if (!feature.expired()) { - auto vp = Application::Instance->getViewProvider(feature.get()); - auto doc = static_cast(vp)->getDocument(); - auto view = dynamic_cast(doc->getViewOfViewProvider(vp)); - if (view) { - return view->getViewer(); - } - } - - return nullptr; -} - -void TaskImageScale::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()); - } -} - -void TaskImageScale::scaleImage(double factor) -{ - if (!feature.expired()) { - feature->XSize.setValue(feature->XSize.getValue() * factor); - feature->YSize.setValue(feature->YSize.getValue() * factor); - - QSignalBlocker blockW(ui->spinBoxWidth); - ui->spinBoxWidth->setValue(feature->getXSizeInPixel()); - QSignalBlocker blockH(ui->spinBoxHeight); - ui->spinBoxHeight->setValue(feature->getYSizeInPixel()); - } -} - -void TaskImageScale::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")); - ui->pushButtonCancel->show(); - ui->quantitySpinBox->setEnabled(false); -} - -void TaskImageScale::acceptScale() -{ - scaleImage(ui->quantitySpinBox->value().getValue() / scale->getDistance()); - rejectScale(); -} - -void TaskImageScale::rejectScale() -{ - scale->deactivate(); - ui->labelInstruction->clear(); - ui->pushButtonScale->setEnabled(true); - ui->pushButtonScale->setText(tr("Interactive")); - ui->pushButtonCancel->hide(); - ui->quantitySpinBox->setEnabled(false); - ui->checkBoxOutside->setEnabled(true); - - scale->clearPoints(); -} - -void TaskImageScale::onInteractiveScale() -{ - if (!feature.expired() && !scale) { - View3DInventorViewer* viewer = getViewer(); - if (viewer) { - auto vp = Application::Instance->getViewProvider(feature.get()); - scale = new InteractiveScale(viewer, vp); - connect(scale, &InteractiveScale::selectedPoints, - this, &TaskImageScale::selectedPoints); - } - } - - if (scale) { - if (scale->isActive()) { - acceptScale(); - } - else { - startScale(); - } - } -} - -// ---------------------------------------------------------------------------- - -InteractiveScale::InteractiveScale(View3DInventorViewer* view, ViewProvider* vp) - : active{false} - , allowOutsideImage{false} - , viewer{view} - , viewProv{vp} -{ - coords = new SoCoordinate3; - coords->ref(); - root = new SoAnnotation; - root->ref(); - - root->addChild(coords); - - SoBaseColor* color = new SoBaseColor; - color->rgb.setValue(1.0F, 0.0F, 0.0F); - root->addChild(color); - root->addChild(new SoLineSet); -} - -InteractiveScale::~InteractiveScale() -{ - coords->unref(); - root->unref(); -} - -void InteractiveScale::activate(bool allowOutside) -{ - if (viewer) { - static_cast(viewer->getSceneGraph())->addChild(root); - viewer->setEditing(true); - viewer->addEventCallback(SoLocation2Event::getClassTypeId(), InteractiveScale::getMousePosition, this); - viewer->addEventCallback(SoMouseButtonEvent::getClassTypeId(), InteractiveScale::getMouseClick, this); - viewer->setSelectionEnabled(false); - viewer->getWidget()->setCursor(QCursor(Qt::CrossCursor)); - active = true; - allowOutsideImage = allowOutside; - } -} - -void InteractiveScale::deactivate() -{ - if (viewer) { - static_cast(viewer->getSceneGraph())->removeChild(root); - viewer->setEditing(false); - viewer->removeEventCallback(SoLocation2Event::getClassTypeId(), InteractiveScale::getMousePosition, this); - viewer->removeEventCallback(SoMouseButtonEvent::getClassTypeId(), InteractiveScale::getMouseClick, this); - viewer->setSelectionEnabled(true); - viewer->getWidget()->setCursor(QCursor(Qt::ArrowCursor)); - active = false; - } -} - -double InteractiveScale::getDistance() const -{ - if (points.size() < 2) - return 0.0; - - return (points[0] - points[1]).length(); -} - -double InteractiveScale::getDistance(const SbVec3f& pt) const -{ - if (points.empty()) - return 0.0; - - return (points[0] - pt).length(); -} - -void InteractiveScale::clearPoints() -{ - points.clear(); - coords->point.setNum(0); -} - -void InteractiveScale::findPointOnPlane(SoEventCallback * ecb) -{ - if (allowOutsideImage) { - findPointOnFocalPlane(ecb); - } - else { - findPointOnImagePlane(ecb); - } -} - -void InteractiveScale::findPointOnImagePlane(SoEventCallback * ecb) -{ - const SoMouseButtonEvent * mbe = static_cast(ecb->getEvent()); - Gui::View3DInventorViewer* view = static_cast(ecb->getUserData()); - std::unique_ptr pp(view->getPointOnRay(mbe->getPosition(), viewProv)); - if (pp.get()) { - auto pos3d = pp->getPoint(); - - collectPoint(pos3d); - } -} - -void InteractiveScale::findPointOnFocalPlane(SoEventCallback * ecb) -{ - const SoMouseButtonEvent * mbe = static_cast(ecb->getEvent()); - Gui::View3DInventorViewer* view = static_cast(ecb->getUserData()); - - auto pos2d = mbe->getPosition(); - auto pos3d = view->getPointOnFocalPlane(pos2d); - - collectPoint(pos3d); -} - -void InteractiveScale::collectPoint(const SbVec3f& pos3d) -{ - if (points.empty()) { - points.push_back(pos3d); - coords->point.set1Value(0, pos3d); - } - else if (points.size() == 1) { - double distance = getDistance(pos3d); - if (distance > Base::Precision::Confusion()) { - points.push_back(pos3d); - coords->point.set1Value(1, pos3d); - } - else { - Base::Console().Warning(std::string("Image scale"), "The second point is too close. Retry!\n"); - } - } - - Q_EMIT selectedPoints(points.size()); -} - -void InteractiveScale::getMouseClick(void * ud, SoEventCallback * ecb) -{ - InteractiveScale* scale = static_cast(ud); - const SoMouseButtonEvent * mbe = static_cast(ecb->getEvent()); - - if (mbe->getButton() == SoMouseButtonEvent::BUTTON1 && mbe->getState() == SoButtonEvent::DOWN) { - ecb->setHandled(); - scale->findPointOnPlane(ecb); - } -} - -void InteractiveScale::getMousePosition(void * ud, SoEventCallback * ecb) -{ - InteractiveScale* scale = static_cast(ud); - const SoLocation2Event * l2e = static_cast(ecb->getEvent()); - Gui::View3DInventorViewer* view = static_cast(ecb->getUserData()); - - if (scale->points.size() == 1) { - ecb->setHandled(); - auto pos2d = l2e->getPosition(); - auto pos3d = view->getPointOnFocalPlane(pos2d); - scale->coords->point.set1Value(1, pos3d); - } -} - -#include "moc_TaskImageScale.cpp" diff --git a/src/Gui/TaskView/TaskImageScale.ui b/src/Gui/TaskView/TaskImageScale.ui deleted file mode 100644 index bc51452a36..0000000000 --- a/src/Gui/TaskView/TaskImageScale.ui +++ /dev/null @@ -1,184 +0,0 @@ - - - Gui::TaskImageScale - - - - 0 - 0 - 421 - 267 - - - - Scale image - - - - - - Image size - - - - - - - - Width: - - - - - - - px - - - 1 - - - 100000000 - - - - - - - Height: - - - - - - - px - - - 1 - - - 100000000 - - - - - - - - - Keep aspect ratio - - - true - - - - - - - - - - - - - - - - - - Interactively scale the image - - - Interactive - - - - - - - Cancel - - - - - - - Qt::Horizontal - - - - 136 - 20 - - - - - - - - - 0 - 0 - - - - Allow points outside the image - - - - - - - - - - - Desired distance: - - - - - - - false - - - mm - - - - - - - - - - - - - - - - - - - - Gui::QuantitySpinBox - QWidget -
Gui/QuantitySpinBox.h
-
-
- - spinBoxWidth - spinBoxHeight - checkBoxRatio - pushButtonScale - pushButtonCancel - checkBoxOutside - quantitySpinBox - - - -
diff --git a/src/Gui/ViewProviderImagePlane.cpp b/src/Gui/ViewProviderImagePlane.cpp index 267c9fc99d..0f16a3afc2 100644 --- a/src/Gui/ViewProviderImagePlane.cpp +++ b/src/Gui/ViewProviderImagePlane.cpp @@ -41,8 +41,7 @@ #include #include #include -#include -#include +#include #include #include "ViewProviderImagePlane.h" @@ -159,12 +158,9 @@ bool ViewProviderImagePlane::doubleClicked() void ViewProviderImagePlane::manipulateImage() { - auto dialog = new TaskOrientationDialog( - dynamic_cast(getObject()) - ); - dialog->addTaskBox(new TaskImageScale( + auto dialog = new TaskImageDialog( dynamic_cast(getObject()) - )); + ); Gui::Control().showDialog(dialog); } diff --git a/src/Mod/Sketcher/Gui/AppSketcherGui.cpp b/src/Mod/Sketcher/Gui/AppSketcherGui.cpp index 5400376a45..37d62d793c 100644 --- a/src/Mod/Sketcher/Gui/AppSketcherGui.cpp +++ b/src/Mod/Sketcher/Gui/AppSketcherGui.cpp @@ -32,7 +32,6 @@ #include "PropertyConstraintListItem.h" #include "SketcherSettings.h" -#include "SoDatumLabel.h" #include "SoZoomTranslation.h" #include "ViewProviderPython.h" #include "ViewProviderSketch.h" @@ -125,7 +124,6 @@ PyMOD_INIT_FUNC(SketcherGui) SketcherGui::ViewProviderPython ::init(); SketcherGui::ViewProviderCustom ::init(); SketcherGui::ViewProviderCustomPython ::init(); - SketcherGui::SoDatumLabel ::initClass(); SketcherGui::SoZoomTranslation ::initClass(); SketcherGui::PropertyConstraintListItem ::init(); SketcherGui::ViewProviderSketchGeometryExtension ::init(); diff --git a/src/Mod/Sketcher/Gui/CMakeLists.txt b/src/Mod/Sketcher/Gui/CMakeLists.txt index 74f4fdedbf..bf24df36fc 100644 --- a/src/Mod/Sketcher/Gui/CMakeLists.txt +++ b/src/Mod/Sketcher/Gui/CMakeLists.txt @@ -87,8 +87,6 @@ SET(SketcherGui_SRCS PreCompiled.h SoZoomTranslation.cpp SoZoomTranslation.h - SoDatumLabel.cpp - SoDatumLabel.h PropertyConstraintListItem.h PropertyConstraintListItem.cpp TaskSketcherConstraints.ui diff --git a/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.cpp b/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.cpp index ffeb8283ee..3f62f61884 100644 --- a/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.cpp +++ b/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.cpp @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -58,13 +59,13 @@ #include #include "EditModeConstraintCoinManager.h" -#include "SoDatumLabel.h" #include "SoZoomTranslation.h" #include "ViewProviderSketch.h" #include "ViewProviderSketchCoinAttorney.h" #include "Utils.h" +using namespace Gui; using namespace SketcherGui; using namespace Sketcher;