Files
create/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp
Benjamin Bræstrup Sayoc ee90eb6ebc PartDesign: Use QStringLiteral
2025-02-10 18:34:57 +01:00

414 lines
15 KiB
C++

/***************************************************************************
* Copyright (c) 2013 Jan Rheinlaender *
* <jrheinlaender@users.sourceforge.net> *
* *
* 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 *
* <https://www.gnu.org/licenses/>. *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
# include <Inventor/actions/SoGetBoundingBoxAction.h>
# include <Inventor/details/SoFaceDetail.h>
# include <Inventor/details/SoLineDetail.h>
# include <Inventor/details/SoPointDetail.h>
# include <Inventor/nodes/SoDrawStyle.h>
# include <Inventor/nodes/SoMaterial.h>
# include <Inventor/nodes/SoMaterialBinding.h>
# include <Inventor/nodes/SoPickStyle.h>
# include <Inventor/nodes/SoSeparator.h>
# include <Inventor/nodes/SoShapeHints.h>
# include <Precision.hxx>
# include <QMessageBox>
# include <QAction>
# include <QMenu>
#endif
#include <App/Document.h>
#include <App/DocumentObjectGroup.h>
#include <Gui/Application.h>
#include <Gui/Command.h>
#include <Gui/Control.h>
#include <Gui/View3DInventor.h>
#include <Gui/View3DInventorViewer.h>
#include <Gui/ViewProviderCoordinateSystem.h>
#include <Mod/PartDesign/App/Body.h>
#include <Mod/PartDesign/App/DatumCS.h>
#include <Mod/PartDesign/App/DatumLine.h>
#include <Mod/PartDesign/App/DatumPlane.h>
#include <Mod/PartDesign/App/DatumPoint.h>
#include "ViewProviderDatum.h"
#include "TaskDatumParameters.h"
#include "Utils.h"
#include "ViewProviderBody.h"
using namespace PartDesignGui;
PROPERTY_SOURCE_WITH_EXTENSIONS(PartDesignGui::ViewProviderDatum,Gui::ViewProviderGeometryObject)
// static data
const double ViewProviderDatum::defaultSize = Gui::ViewProviderCoordinateSystem::defaultSize ();
ViewProviderDatum::ViewProviderDatum()
{
PartGui::ViewProviderAttachExtension::initExtension(this);
pShapeSep = new SoSeparator();
pShapeSep->ref();
pPickStyle = new SoPickStyle();
pPickStyle->ref();
DisplayMode.setStatus(App::Property::Hidden, true);
// set default color for datums (golden yellow with 60% transparency)
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath (
"User parameter:BaseApp/Preferences/Mod/PartDesign");
unsigned long shcol = hGrp->GetUnsigned ( "DefaultDatumColor", 0xFFD70099 );
App::Color col ( (uint32_t) shcol );
ShapeAppearance.setDiffuseColor(col);
Transparency.setValue (col.a * 100);
oldWb = "";
oldTip = nullptr;
}
ViewProviderDatum::~ViewProviderDatum()
{
pShapeSep->unref();
pPickStyle->unref();
}
void ViewProviderDatum::attach(App::DocumentObject *obj)
{
if (auto geo = dynamic_cast<App::GeoFeature*>(obj)) {
geo->setMaterialAppearance(ShapeAppearance[0]);
}
ViewProviderGeometryObject::attach ( obj );
// TODO remove this field (2015-09-08, Fat-Zer)
App::DocumentObject* o = getObject();
if (o->is<PartDesign::Plane>()) {
datumType = QStringLiteral("Plane");
datumText = QObject::tr("Plane");
datumMenuText = tr("Datum Plane parameters");
}
else if (o->is<PartDesign::Line>()) {
datumType = QStringLiteral("Line");
datumText = QObject::tr("Line");
datumMenuText = tr("Datum Line parameters");
}
else if (o->is<PartDesign::Point>()) {
datumType = QStringLiteral("Point");
datumText = QObject::tr("Point");
datumMenuText = tr("Datum Point parameters");
}
else if (o->is<PartDesign::CoordinateSystem>()) {
datumType = QStringLiteral("CoordinateSystem");
datumText = QObject::tr("Coordinate System");
datumMenuText = tr("Local Coordinate System parameters");
}
SoShapeHints* hints = new SoShapeHints();
hints->shapeType.setValue(SoShapeHints::UNKNOWN_SHAPE_TYPE);
hints->vertexOrdering.setValue(SoShapeHints::COUNTERCLOCKWISE);
SoDrawStyle* fstyle = new SoDrawStyle();
fstyle->style = SoDrawStyle::FILLED;
fstyle->lineWidth = 3;
fstyle->pointSize = 5;
pPickStyle->style = SoPickStyle::SHAPE;
SoMaterialBinding* matBinding = new SoMaterialBinding;
matBinding->value = SoMaterialBinding::OVERALL;
SoSeparator* sep = new SoSeparator();
sep->addChild(hints);
sep->addChild(fstyle);
sep->addChild(pPickStyle);
sep->addChild(matBinding);
sep->addChild(pcShapeMaterial);
sep->addChild(pShapeSep);
addDisplayMaskMode(sep, "Base");
}
bool ViewProviderDatum::onDelete(const std::vector<std::string> &)
{
// TODO: Ask user what to do about dependent objects, e.g. Sketches that have this feature as their support
// 1. Delete
// 2. Suppress
// 3. Re-route
return true;
}
std::vector<std::string> ViewProviderDatum::getDisplayModes() const
{
return { "Base" };
}
void ViewProviderDatum::setDisplayMode(const char* ModeName)
{
if (strcmp(ModeName, "Base") == 0)
setDisplayMaskMode("Base");
ViewProviderGeometryObject::setDisplayMode(ModeName);
}
std::string ViewProviderDatum::getElement(const SoDetail* detail) const
{
if (detail) {
int element = 1;
if (detail->getTypeId() == SoLineDetail::getClassTypeId()) {
const SoLineDetail* line_detail = static_cast<const SoLineDetail*>(detail);
element = line_detail->getLineIndex();
} else if (detail->getTypeId() == SoFaceDetail::getClassTypeId()) {
const SoFaceDetail* face_detail = static_cast<const SoFaceDetail*>(detail);
element = face_detail->getFaceIndex();
} else if (detail->getTypeId() == SoPointDetail::getClassTypeId()) {
const SoPointDetail* point_detail = static_cast<const SoPointDetail*>(detail);
element = point_detail->getCoordinateIndex();
}
if (element == 0)
return datumType.toStdString();
}
return {};
}
SoDetail* ViewProviderDatum::getDetail(const char* subelement) const
{
QString subelem = QString::fromLatin1(subelement);
if (subelem == QObject::tr("Line")) {
SoLineDetail* detail = new SoLineDetail();
detail->setPartIndex(0);
return detail;
} else if (subelem == QObject::tr("Plane")) {
SoFaceDetail* detail = new SoFaceDetail();
detail->setPartIndex(0);
return detail;
} else if (subelem == QObject::tr("Point")) {
SoPointDetail* detail = new SoPointDetail();
detail->setCoordinateIndex(0);
return detail;
}
return nullptr;
}
bool ViewProviderDatum::isSelectable() const
{
return true;
}
void ViewProviderDatum::setupContextMenu(QMenu* menu, QObject* receiver, const char* member)
{
QAction* act;
act = menu->addAction(QObject::tr("Edit datum"), receiver, member);
act->setData(QVariant((int)ViewProvider::Default));
// Call the extensions
Gui::ViewProvider::setupContextMenu(menu, receiver, member);
}
bool ViewProviderDatum::setEdit(int ModNum)
{
if (!ViewProvider::setEdit(ModNum))
return false;
// TODO Share this code with Features view providers somehow (2015-09-08, Fat-Zer)
if (ModNum == ViewProvider::Default ) {
// When double-clicking on the item for this datum feature the
// object unsets and sets its edit mode without closing
// the task panel
Gui::TaskView::TaskDialog *dlg = Gui::Control().activeDialog();
TaskDlgDatumParameters *datumDlg = qobject_cast<TaskDlgDatumParameters *>(dlg);
if (datumDlg && datumDlg->getViewProvider() != this)
datumDlg = nullptr; // another datum feature left open its task panel
if (dlg && !datumDlg) {
QMessageBox msgBox;
msgBox.setText(QObject::tr("A dialog is already open in the task panel"));
msgBox.setInformativeText(QObject::tr("Do you want to close this dialog?"));
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
msgBox.setDefaultButton(QMessageBox::Yes);
int ret = msgBox.exec();
if (ret == QMessageBox::Yes)
Gui::Control().closeDialog();
else
return false;
}
// clear the selection (convenience)
Gui::Selection().clearSelection();
oldWb = Gui::Command::assureWorkbench("PartDesignWorkbench");
// start the edit dialog
if (datumDlg)
Gui::Control().showDialog(datumDlg);
else
Gui::Control().showDialog(new TaskDlgDatumParameters(this));
return true;
}
else {
return ViewProvider::setEdit(ModNum);
}
}
bool ViewProviderDatum::doubleClicked()
{
auto activeDoc = Gui::Application::Instance->activeDocument();
if(!activeDoc)
activeDoc = getDocument();
auto activeView = activeDoc->getActiveView();
if(!activeView)
return false;
std::string Msg("Edit ");
Msg += this->pcObject->Label.getValue();
Gui::Command::openCommand(Msg.c_str());
Part::Datum* pcDatum = getObject<Part::Datum>();
PartDesign::Body* activeBody = activeView->getActiveObject<PartDesign::Body*>(PDBODYKEY);
auto datumBody = PartDesignGui::getBodyFor(pcDatum, false);
if (datumBody) {
if (datumBody != activeBody) {
Gui::Command::doCommand(Gui::Command::Gui,
"Gui.ActiveDocument.ActiveView.setActiveObject('%s',%s)",
PDBODYKEY, Gui::Command::getObjectCmd(datumBody).c_str());
activeBody = datumBody;
}
}
return PartDesignGui::setEdit(pcObject,activeBody);
}
void ViewProviderDatum::unsetEdit(int ModNum)
{
// return to the WB we were in before editing the PartDesign feature
Gui::Command::assureWorkbench(oldWb.c_str());
if (ModNum == ViewProvider::Default) {
// when pressing ESC make sure to close the dialog
Gui::Control().closeDialog();
}
else {
Gui::ViewProviderGeometryObject::unsetEdit(ModNum);
}
}
void ViewProviderDatum::updateExtents () {
setExtents ( getRelevantBoundBox () );
}
void ViewProviderDatum::setExtents (const SbBox3f &bbox) {
const SbVec3f & min = bbox.getMin ();
const SbVec3f & max = bbox.getMax ();
setExtents ( Base::BoundBox3d ( min.getValue()[0], min.getValue()[1], min.getValue()[2],
max.getValue()[0], max.getValue()[1], max.getValue()[2] ) );
}
SbBox3f ViewProviderDatum::getRelevantBoundBox () const {
std::vector<App::DocumentObject *> objs;
// Probe body first
PartDesign::Body* body = PartDesign::Body::findBodyOf ( this->getObject() );
if (body) {
objs = body->getFullModel ();
} else {
// Probe if we belongs to some group
App::DocumentObject* group = App::DocumentObjectGroup::getGroupOfObject ( this->getObject () );
if(group) {
auto* ext = group->getExtensionByType<App::GroupExtension>();
if(ext)
objs = ext->getObjects ();
} else {
// Fallback to whole document
objs = this->getObject ()->getDocument ()->getObjects ();
}
}
Gui::View3DInventor* view = dynamic_cast<Gui::View3DInventor*>(this->getActiveView());
if(view){
Gui::View3DInventorViewer* viewer = view->getViewer();
SoGetBoundingBoxAction bboxAction(viewer->getSoRenderManager()->getViewportRegion());
SbBox3f bbox = getRelevantBoundBox (bboxAction, objs);
if ( bbox.getVolume () < Precision::Confusion() ) {
bbox.extendBy ( defaultBoundBox () );
}
return bbox;
} else {
return defaultBoundBox();
}
}
SbBox3f ViewProviderDatum::getRelevantBoundBox (
SoGetBoundingBoxAction &bboxAction, const std::vector <App::DocumentObject *> &objs )
{
SbBox3f bbox = defaultBoundBox();
// Adds the bbox of given feature to the output
for (auto obj :objs) {
ViewProvider *vp = Gui::Application::Instance->getViewProvider(obj);
if (!vp) { continue; }
if (!vp->isVisible ()) { continue; }
if (obj->isDerivedFrom (Part::Datum::getClassTypeId() ) ) {
// Treat datums only as their basepoint
// I hope it's ok to take FreeCAD's point here
Base::Vector3d basePoint = static_cast<Part::Datum *> ( obj )->getBasePoint ();
bbox.extendBy (SbVec3f(basePoint.x, basePoint.y, basePoint.z ));
} else {
bboxAction.apply ( vp->getRoot () );
SbBox3f obj_bbox = bboxAction.getBoundingBox ();
if ( obj_bbox.getVolume () < Precision::Infinite () ) {
bbox.extendBy ( obj_bbox );
}
}
}
// TODO: shrink bbox when all other elements are too small
return bbox;
}
SbBox3f ViewProviderDatum::defaultBoundBox () {
return SbBox3f ( -defaultSize, -defaultSize, -defaultSize,
defaultSize, defaultSize, defaultSize );
}
bool ViewProviderDatum::isPickable() {
return bool(pPickStyle->style.getValue() == SoPickStyle::SHAPE);
}
void ViewProviderDatum::setPickable(bool val) {
if(val)
pPickStyle->style = SoPickStyle::SHAPE;
else
pPickStyle->style = SoPickStyle::UNPICKABLE;
}