Merge pull request #23291 from 3x380V/measurement
Measure: Useability improvements
This commit is contained in:
@@ -3065,7 +3065,7 @@ DocumentObject* Document::addObject(const char* sType,
|
||||
Base::Type::getTypeIfDerivedFrom(sType, DocumentObject::getClassTypeId(), true);
|
||||
if (type.isBad()) {
|
||||
std::stringstream str;
|
||||
str << "'" << sType << "' is not a document object type";
|
||||
str << "Document::addObject: '" << sType << "' is not a document object type";
|
||||
throw Base::TypeError(str.str());
|
||||
}
|
||||
|
||||
|
||||
@@ -723,6 +723,7 @@ MenuItem* StdWorkbench::setupMenuBar() const
|
||||
<< "Separator";
|
||||
#endif
|
||||
*tool << "Std_Measure"
|
||||
<< "Std_QuickMeasure"
|
||||
<< "Std_UnitsCalculator"
|
||||
<< "Separator"
|
||||
<< "Std_ViewLoadImage"
|
||||
@@ -812,7 +813,7 @@ ToolBarItem* StdWorkbench::setupToolBars() const
|
||||
auto view = new ToolBarItem( root );
|
||||
view->setCommand("View");
|
||||
*view << "Std_ViewFitAll" << "Std_ViewFitSelection" << "Std_ViewGroup" << "Std_AlignToSelection"
|
||||
<< "Separator" << "Std_DrawStyle" << "Std_TreeViewActions" << "Std_Measure";
|
||||
<< "Separator" << "Std_DrawStyle" << "Std_TreeViewActions" << "Std_Measure" << "Std_QuickMeasure";
|
||||
|
||||
// Individual views
|
||||
auto individualViews = new ToolBarItem(root, ToolBarItem::DefaultVisibility::Hidden);
|
||||
|
||||
@@ -53,6 +53,15 @@ MeasureArea::MeasureArea()
|
||||
|
||||
MeasureArea::~MeasureArea() = default;
|
||||
|
||||
bool MeasureArea::isSupported(App::MeasureElementType type)
|
||||
{
|
||||
// clang-format off
|
||||
return (type == App::MeasureElementType::PLANE) ||
|
||||
(type == App::MeasureElementType::CYLINDER) ||
|
||||
(type == App::MeasureElementType::SURFACE) ||
|
||||
(type == App::MeasureElementType::VOLUME);
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
bool MeasureArea::isValidSelection(const App::MeasureSelection& selection)
|
||||
{
|
||||
@@ -68,8 +77,7 @@ bool MeasureArea::isValidSelection(const App::MeasureSelection& selection)
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((type != App::MeasureElementType::PLANE && type != App::MeasureElementType::CYLINDER
|
||||
&& type != App::MeasureElementType::SURFACE)) {
|
||||
if (!isSupported(type)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,6 +79,7 @@ public:
|
||||
|
||||
|
||||
private:
|
||||
static bool isSupported(App::MeasureElementType type);
|
||||
void onChanged(const App::Property* prop) override;
|
||||
};
|
||||
|
||||
|
||||
@@ -287,13 +287,11 @@ MeasureType Measurement::getType()
|
||||
TopoDS_Shape
|
||||
Measurement::getShape(App::DocumentObject* obj, const char* subName, TopAbs_ShapeEnum hint) const
|
||||
{
|
||||
TopoShape shape = ShapeFinder::getLocatedTopoShape(*obj, subName);
|
||||
|
||||
if (shape.shapeType() == TopAbs_COMPOUND && hint != TopAbs_COMPOUND
|
||||
&& shape.hasSubShape(hint)) {
|
||||
return shape.getSubTopoShape(hint, true).getShape();
|
||||
}
|
||||
return shape.getShape();
|
||||
return Part::Feature::getShape(obj,
|
||||
Part::ShapeOption::NeedSubElement
|
||||
| Part::ShapeOption::ResolveLink
|
||||
| Part::ShapeOption::Transform,
|
||||
subName);
|
||||
}
|
||||
|
||||
|
||||
@@ -331,6 +329,9 @@ double Measurement::length() const
|
||||
|
||||
// Get the length of one edge
|
||||
TopoDS_Shape shape = getShape(*obj, (*subEl).c_str(), TopAbs_EDGE);
|
||||
if (shape.IsNull() || shape.Infinite()) {
|
||||
continue;
|
||||
}
|
||||
const TopoDS_Edge& edge = TopoDS::Edge(shape);
|
||||
BRepAdaptor_Curve curve(edge);
|
||||
|
||||
@@ -365,8 +366,8 @@ double Measurement::length() const
|
||||
throw Base::RuntimeError(
|
||||
"Measurement - length - Curve type not currently handled");
|
||||
}
|
||||
} // end switch
|
||||
} // end for
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -432,8 +433,6 @@ double Measurement::planePlaneDistance() const
|
||||
const auto& objects = References3D.getValues();
|
||||
const auto& subElements = References3D.getSubValues();
|
||||
|
||||
std::vector<gp_Pln> planes;
|
||||
|
||||
// Get the first plane
|
||||
TopoDS_Shape shape1 = getShape(objects[0], subElements[0].c_str(), TopAbs_FACE);
|
||||
const TopoDS_Face& face1 = TopoDS::Face(shape1);
|
||||
@@ -684,7 +683,11 @@ double Measurement::volume() const
|
||||
|
||||
for (size_t i = 0; i < objects.size(); ++i) {
|
||||
GProp_GProps props = GProp_GProps();
|
||||
BRepGProp::VolumeProperties(getShape(objects[i], subElements[i].c_str()), props);
|
||||
TopoDS_Shape shape = getShape(objects[i], subElements[i].c_str());
|
||||
if (shape.IsNull() || shape.Infinite()) {
|
||||
continue;
|
||||
}
|
||||
BRepGProp::VolumeProperties(shape, props);
|
||||
result += props.Mass();
|
||||
}
|
||||
}
|
||||
@@ -707,7 +710,11 @@ double Measurement::area() const
|
||||
|
||||
for (size_t i = 0; i < objects.size(); ++i) {
|
||||
GProp_GProps props;
|
||||
BRepGProp::SurfaceProperties(getShape(objects[i], subElements[i].c_str()), props);
|
||||
TopoDS_Shape shape = getShape(objects[i], subElements[i].c_str());
|
||||
if (shape.IsNull() || shape.Infinite()) {
|
||||
continue;
|
||||
}
|
||||
BRepGProp::SurfaceProperties(shape, props);
|
||||
result += props.Mass(); // Area is obtained using Mass method for surface properties
|
||||
}
|
||||
}
|
||||
@@ -742,7 +749,11 @@ Base::Vector3d Measurement::massCenter() const
|
||||
// Compute inertia properties
|
||||
|
||||
GProp_GProps props = GProp_GProps();
|
||||
BRepGProp::VolumeProperties(getShape((*obj), ""), props);
|
||||
TopoDS_Shape shape = ShapeFinder::getLocatedShape(*(*obj), "");
|
||||
if (shape.IsNull()) {
|
||||
continue;
|
||||
}
|
||||
BRepGProp::VolumeProperties(shape, props);
|
||||
gprops.Add(props);
|
||||
// Get inertia properties
|
||||
}
|
||||
@@ -818,11 +829,17 @@ bool Measurement::linesAreParallel() const
|
||||
|
||||
// Get the first line
|
||||
TopoDS_Shape shape1 = getShape(objects[0], subElements[0].c_str(), TopAbs_EDGE);
|
||||
if (shape1.IsNull()) {
|
||||
return false;
|
||||
}
|
||||
const TopoDS_Edge& edge1 = TopoDS::Edge(shape1);
|
||||
BRepAdaptor_Curve curve1(edge1);
|
||||
|
||||
// Get the second line
|
||||
TopoDS_Shape shape2 = getShape(objects[1], subElements[1].c_str(), TopAbs_EDGE);
|
||||
if (shape2.IsNull()) {
|
||||
return false;
|
||||
}
|
||||
const TopoDS_Edge& edge2 = TopoDS::Edge(shape2);
|
||||
BRepAdaptor_Curve curve2(edge2);
|
||||
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
#include <Gui/WidgetFactory.h>
|
||||
|
||||
#include "DlgPrefsMeasureAppearanceImp.h"
|
||||
#include "QuickMeasure.h"
|
||||
#include "QuickMeasurePy.h"
|
||||
#include "ViewProviderMeasureAngle.h"
|
||||
#include "ViewProviderMeasureDistance.h"
|
||||
@@ -112,9 +111,5 @@ PyMOD_INIT_FUNC(MeasureGui)
|
||||
|
||||
Base::Interpreter().addType(&MeasureGui::QuickMeasurePy::Type, mod, "QuickMeasure");
|
||||
|
||||
// Create a QuickMeasure instance
|
||||
auto measure = new MeasureGui::QuickMeasure(QApplication::instance());
|
||||
Q_UNUSED(measure)
|
||||
|
||||
PyMOD_Return(mod);
|
||||
}
|
||||
|
||||
@@ -20,8 +20,13 @@
|
||||
**************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
#include <QApplication>
|
||||
#endif
|
||||
|
||||
#include <App/Application.h>
|
||||
#include <App/Document.h>
|
||||
#include <Gui/Action.h>
|
||||
#include <Gui/Application.h>
|
||||
#include <Gui/Command.h>
|
||||
#include <Gui/Control.h>
|
||||
@@ -30,6 +35,7 @@
|
||||
#include <Gui/View3DInventor.h>
|
||||
#include <Gui/View3DInventorViewer.h>
|
||||
|
||||
#include "QuickMeasure.h"
|
||||
#include "TaskMeasure.h"
|
||||
|
||||
|
||||
@@ -56,7 +62,7 @@ void StdCmdMeasure::activated(int iMsg)
|
||||
{
|
||||
Q_UNUSED(iMsg);
|
||||
|
||||
Gui::TaskMeasure* task = new Gui::TaskMeasure();
|
||||
MeasureGui::TaskMeasure* task = new MeasureGui::TaskMeasure();
|
||||
task->setDocumentName(this->getDocument()->getName());
|
||||
Gui::Control().showDialog(task);
|
||||
}
|
||||
@@ -76,6 +82,65 @@ bool StdCmdMeasure::isActive()
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
class StdCmdQuickMeasure: public Gui::Command
|
||||
{
|
||||
public:
|
||||
StdCmdQuickMeasure()
|
||||
: Command("Std_QuickMeasure")
|
||||
{
|
||||
sGroup = "Measure";
|
||||
sMenuText = QT_TR_NOOP("&Quick measure");
|
||||
sToolTipText = QT_TR_NOOP("Toggle quick measure");
|
||||
sWhatsThis = "Std_QuickMeasure";
|
||||
sStatusTip = QT_TR_NOOP("Toggle quick measure");
|
||||
accessParameter();
|
||||
}
|
||||
~StdCmdQuickMeasure() override = default;
|
||||
StdCmdQuickMeasure(const StdCmdQuickMeasure&) = delete;
|
||||
StdCmdQuickMeasure(StdCmdQuickMeasure&&) = delete;
|
||||
StdCmdQuickMeasure& operator=(const StdCmdQuickMeasure&) = delete;
|
||||
StdCmdQuickMeasure& operator=(StdCmdQuickMeasure&&) = delete;
|
||||
|
||||
const char* className() const override
|
||||
{
|
||||
return "StdCmdQuickMeasure";
|
||||
}
|
||||
|
||||
protected:
|
||||
void activated(int iMsg) override
|
||||
{
|
||||
if (parameter.isValid()) {
|
||||
parameter->SetBool("EnableQuickMeasure", iMsg > 0);
|
||||
}
|
||||
|
||||
if (iMsg == 0) {
|
||||
quickMeasure.reset();
|
||||
}
|
||||
else {
|
||||
quickMeasure = std::make_unique<MeasureGui::QuickMeasure>(QApplication::instance());
|
||||
}
|
||||
}
|
||||
Gui::Action* createAction() override
|
||||
{
|
||||
Gui::Action* action = Gui::Command::createAction();
|
||||
action->setCheckable(true);
|
||||
action->setChecked(parameter->GetBool("EnableQuickMeasure", false));
|
||||
return action;
|
||||
}
|
||||
void accessParameter()
|
||||
{
|
||||
// clang-format off
|
||||
parameter = App::GetApplication().GetUserParameter().
|
||||
GetGroup("BaseApp/Preferences/Mod/Measure");
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<MeasureGui::QuickMeasure> quickMeasure;
|
||||
ParameterGrp::handle parameter;
|
||||
};
|
||||
|
||||
void CreateMeasureCommands()
|
||||
{
|
||||
Gui::CommandManager& rcCmdMgr = Gui::Application::Instance->commandManager();
|
||||
@@ -83,4 +148,5 @@ void CreateMeasureCommands()
|
||||
auto cmd = new StdCmdMeasure();
|
||||
cmd->initAction();
|
||||
rcCmdMgr.addCommand(cmd);
|
||||
rcCmdMgr.addCommand(new StdCmdQuickMeasure);
|
||||
}
|
||||
|
||||
@@ -46,9 +46,10 @@
|
||||
#include <QSettings>
|
||||
#include <QAction>
|
||||
#include <QMenu>
|
||||
#include <QShortcut>
|
||||
#include <QToolTip>
|
||||
|
||||
using namespace Gui;
|
||||
using namespace MeasureGui;
|
||||
|
||||
namespace
|
||||
{
|
||||
@@ -62,14 +63,14 @@ using SelectionStyle = Gui::SelectionSingleton::SelectionStyle;
|
||||
|
||||
TaskMeasure::TaskMeasure()
|
||||
{
|
||||
qApp->installEventFilter(this);
|
||||
|
||||
this->setButtonPosition(TaskMeasure::South);
|
||||
auto taskbox = new Gui::TaskView::TaskBox(Gui::BitmapFactory().pixmap("umf-measurement"),
|
||||
tr("Measurement"),
|
||||
true,
|
||||
nullptr);
|
||||
|
||||
setupShortcuts(taskbox);
|
||||
|
||||
QSettings settings;
|
||||
settings.beginGroup(QLatin1String(taskMeasureSettingsGroup));
|
||||
delta = settings.value(QLatin1String(taskMeasureShowDeltaSettingsName), true).toBool();
|
||||
@@ -153,7 +154,7 @@ TaskMeasure::TaskMeasure()
|
||||
auto* settingsLayout = new QHBoxLayout();
|
||||
settingsLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding));
|
||||
settingsLayout->addWidget(mSettings);
|
||||
formLayout->addRow(QStringLiteral(""), settingsLayout);
|
||||
formLayout->addRow(QLatin1String(), settingsLayout);
|
||||
formLayout->addRow(tr("Mode:"), modeSwitch);
|
||||
formLayout->addRow(showDeltaLabel, showDelta);
|
||||
formLayout->addRow(tr("Result:"), valueResult);
|
||||
@@ -177,15 +178,13 @@ TaskMeasure::~TaskMeasure()
|
||||
{
|
||||
Gui::Selection().setSelectionStyle(SelectionStyle::NormalSelection);
|
||||
detachSelection();
|
||||
qApp->removeEventFilter(this);
|
||||
}
|
||||
|
||||
|
||||
void TaskMeasure::modifyStandardButtons(QDialogButtonBox* box)
|
||||
{
|
||||
|
||||
QPushButton* btn = box->button(QDialogButtonBox::Apply);
|
||||
btn->setText(tr("Save"));
|
||||
btn->setText(QCoreApplication::translate("QPlatformTheme", "Save"));
|
||||
btn->setToolTip(tr("Saves the measurement in the active document"));
|
||||
connect(btn, &QPushButton::released, this, qOverload<>(&TaskMeasure::apply));
|
||||
|
||||
@@ -193,7 +192,7 @@ void TaskMeasure::modifyStandardButtons(QDialogButtonBox* box)
|
||||
btn->setEnabled(false);
|
||||
btn = box->button(QDialogButtonBox::Abort);
|
||||
btn->setText(tr("Close"));
|
||||
btn->setToolTip(tr("Closes the measurement task"));
|
||||
btn->setToolTip(tr("Close the measurement task."));
|
||||
|
||||
// Connect reset button
|
||||
btn = box->button(QDialogButtonBox::Reset);
|
||||
@@ -213,11 +212,11 @@ void TaskMeasure::enableAnnotateButton(bool state)
|
||||
}
|
||||
|
||||
|
||||
Measure::MeasureBase* TaskMeasure::createObject(const App::MeasureType* measureType)
|
||||
void TaskMeasure::createObject(const App::MeasureType* measureType)
|
||||
{
|
||||
App::Document* doc = App::GetApplication().getActiveDocument();
|
||||
if (!doc) {
|
||||
return nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (measureType->isPython) {
|
||||
@@ -225,7 +224,9 @@ Measure::MeasureBase* TaskMeasure::createObject(const App::MeasureType* measureT
|
||||
auto pyMeasureClass = measureType->pythonClass;
|
||||
|
||||
// Create a MeasurePython instance
|
||||
// Measure::MeasurePython is an alias so we need to use the string based addObject for now.
|
||||
// Note: writing addObject<Measure::MeasurePython>() is not yet supported because
|
||||
// getClassName() will determine the string 'App::FeaturePythonT<FeatureT>' instead
|
||||
// of 'Measure::MeasurePython'
|
||||
auto featurePython = doc->addObject("Measure::MeasurePython", measureType->label.c_str());
|
||||
_mMeasureObject = dynamic_cast<Measure::MeasureBase*>(featurePython);
|
||||
|
||||
@@ -241,12 +242,19 @@ Measure::MeasureBase* TaskMeasure::createObject(const App::MeasureType* measureT
|
||||
_mMeasureObject = dynamic_cast<Measure::MeasureBase*>(
|
||||
doc->addObject(measureType->measureObject.c_str(), measureType->label.c_str()));
|
||||
}
|
||||
|
||||
return _mMeasureObject;
|
||||
}
|
||||
|
||||
|
||||
void TaskMeasure::update()
|
||||
{
|
||||
try {
|
||||
tryUpdate();
|
||||
}
|
||||
catch (const Base::Exception& e) {
|
||||
e.reportException();
|
||||
}
|
||||
}
|
||||
|
||||
void TaskMeasure::tryUpdate()
|
||||
{
|
||||
App::Document* doc = App::GetApplication().getActiveDocument();
|
||||
|
||||
@@ -274,7 +282,7 @@ void TaskMeasure::update()
|
||||
std::string mode = explicitMode ? modeSwitch->currentText().toStdString() : "";
|
||||
|
||||
App::MeasureSelection selection;
|
||||
for (auto s : Gui::Selection().getSelection(doc->getName(), ResolveMode::NoResolve)) {
|
||||
for (auto s : Gui::Selection().getSelection(doc->getName(), Gui::ResolveMode::NoResolve)) {
|
||||
App::SubObjectT sub(s.pObject, s.SubName);
|
||||
|
||||
App::MeasureSelectionItem item = {sub, Base::Vector3d(s.x, s.y, s.z)};
|
||||
@@ -284,7 +292,7 @@ void TaskMeasure::update()
|
||||
// Get valid measure type
|
||||
App::MeasureType* measureType = nullptr;
|
||||
auto measureTypes = App::MeasureManager::getValidMeasureTypes(selection, mode);
|
||||
if (measureTypes.size() > 0) {
|
||||
if (!measureTypes.empty()) {
|
||||
measureType = measureTypes.front();
|
||||
}
|
||||
|
||||
@@ -320,31 +328,34 @@ void TaskMeasure::update()
|
||||
// we have a valid measure object so we can enable the annotate button
|
||||
enableAnnotateButton(true);
|
||||
|
||||
// Fill measure object's properties from selection
|
||||
_mMeasureObject->parseSelection(selection);
|
||||
if (_mMeasureObject) {
|
||||
// Fill measure object's properties from selection
|
||||
_mMeasureObject->parseSelection(selection);
|
||||
|
||||
// Get result
|
||||
valueResult->setText(_mMeasureObject->getResultString());
|
||||
// Get result
|
||||
valueResult->setText(_mMeasureObject->getResultString());
|
||||
|
||||
// Initialite the measurement's viewprovider
|
||||
initViewObject();
|
||||
|
||||
// Initialite the measurement's viewprovider
|
||||
initViewObject(_mMeasureObject);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TaskMeasure::initViewObject()
|
||||
void TaskMeasure::initViewObject(Measure::MeasureBase* measure)
|
||||
{
|
||||
Gui::Document* guiDoc = Gui::Application::Instance->activeDocument();
|
||||
if (!guiDoc) {
|
||||
return;
|
||||
}
|
||||
|
||||
Gui::ViewProvider* viewObject = guiDoc->getViewProvider(_mMeasureObject);
|
||||
Gui::ViewProvider* viewObject = guiDoc->getViewProvider(measure);
|
||||
if (!viewObject) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Init the position of the annotation
|
||||
dynamic_cast<MeasureGui::ViewProviderMeasureBase*>(viewObject)->positionAnno(_mMeasureObject);
|
||||
dynamic_cast<MeasureGui::ViewProviderMeasureBase*>(viewObject)->positionAnno(measure);
|
||||
|
||||
// Set the ShowDelta Property if it exists on the measurements view object
|
||||
auto* prop = viewObject->getPropertyByName<App::PropertyBool>("ShowDelta");
|
||||
@@ -356,9 +367,9 @@ void TaskMeasure::initViewObject()
|
||||
}
|
||||
|
||||
|
||||
void TaskMeasure::close()
|
||||
void TaskMeasure::closeDialog()
|
||||
{
|
||||
Control().closeDialog();
|
||||
Gui::Control().closeDialog();
|
||||
}
|
||||
|
||||
|
||||
@@ -372,16 +383,13 @@ void TaskMeasure::ensureGroup(Measure::MeasureBase* measurement)
|
||||
}
|
||||
|
||||
App::Document* doc = measurement->getDocument();
|
||||
App::DocumentObject* obj = doc->getObject(measurementGroupName);
|
||||
|
||||
|
||||
if (!obj || !obj->isValid() || !obj->isDerivedFrom<App::DocumentObjectGroup>()) {
|
||||
obj = doc->addObject<App::DocumentObjectGroup>(measurementGroupName,
|
||||
true,
|
||||
"MeasureGui::ViewProviderMeasureGroup");
|
||||
auto group = dynamic_cast<App::DocumentObjectGroup*>(doc->getObject(measurementGroupName));
|
||||
if (!group || !group->isValid()) {
|
||||
group = doc->addObject<App::DocumentObjectGroup>(measurementGroupName,
|
||||
true,
|
||||
"MeasureGui::ViewProviderMeasureGroup");
|
||||
}
|
||||
|
||||
auto group = static_cast<App::DocumentObjectGroup*>(obj);
|
||||
group->addObject(measurement);
|
||||
}
|
||||
|
||||
@@ -414,7 +422,7 @@ bool TaskMeasure::apply(bool reset)
|
||||
bool TaskMeasure::reject()
|
||||
{
|
||||
removeObject();
|
||||
close();
|
||||
closeDialog();
|
||||
|
||||
// Abort transaction
|
||||
App::GetApplication().closeActiveTransaction(true);
|
||||
@@ -460,9 +468,10 @@ void TaskMeasure::clearSelection()
|
||||
void TaskMeasure::onSelectionChanged(const Gui::SelectionChanges& msg)
|
||||
{
|
||||
// Skip non-relevant events
|
||||
if (msg.Type != SelectionChanges::AddSelection && msg.Type != SelectionChanges::RmvSelection
|
||||
&& msg.Type != SelectionChanges::SetSelection
|
||||
&& msg.Type != SelectionChanges::ClrSelection) {
|
||||
if (msg.Type != Gui::SelectionChanges::AddSelection
|
||||
&& msg.Type != Gui::SelectionChanges::RmvSelection
|
||||
&& msg.Type != Gui::SelectionChanges::SetSelection
|
||||
&& msg.Type != Gui::SelectionChanges::ClrSelection) {
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -476,42 +485,45 @@ void TaskMeasure::onSelectionChanged(const Gui::SelectionChanges& msg)
|
||||
const bool shift = (modifier & Qt::ShiftModifier) > 0;
|
||||
// shift inverts the current state temporarily
|
||||
const auto autosave = (mAutoSave && !shift) || (!mAutoSave && shift);
|
||||
if ((!ctrl && Selection().getSelectionStyle() == SelectionStyle::NormalSelection)
|
||||
|| (ctrl && Selection().getSelectionStyle() == SelectionStyle::GreedySelection)) {
|
||||
if (autosave && this->buttonBox->button(QDialogButtonBox::Apply)->isEnabled()) {
|
||||
if ((!ctrl && Gui::Selection().getSelectionStyle() == SelectionStyle::NormalSelection)
|
||||
|| (ctrl && Gui::Selection().getSelectionStyle() == SelectionStyle::GreedySelection)) {
|
||||
if (autosave && buttonBox && buttonBox->button(QDialogButtonBox::Apply)->isEnabled()) {
|
||||
apply(false);
|
||||
}
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
bool TaskMeasure::eventFilter(QObject* obj, QEvent* event)
|
||||
void TaskMeasure::setupShortcuts(QWidget* parent)
|
||||
{
|
||||
auto shortcutSave = new QShortcut(parent);
|
||||
shortcutSave->setKey(QKeySequence(QStringLiteral("Return")));
|
||||
shortcutSave->setContext(Qt::ApplicationShortcut);
|
||||
connect(shortcutSave, &QShortcut::activated, this, &TaskMeasure::saveMeasurement);
|
||||
|
||||
if (event->type() == QEvent::KeyPress) {
|
||||
auto keyEvent = static_cast<QKeyEvent*>(event);
|
||||
auto shortcutQuit = new QShortcut(parent);
|
||||
shortcutQuit->setKey(QKeySequence(QStringLiteral("ESC")));
|
||||
shortcutQuit->setContext(Qt::ApplicationShortcut);
|
||||
connect(shortcutQuit, &QShortcut::activated, this, &TaskMeasure::quitMeasurement);
|
||||
}
|
||||
|
||||
if (keyEvent->key() == Qt::Key_Escape) {
|
||||
|
||||
if (this->hasSelection()) {
|
||||
this->reset();
|
||||
}
|
||||
else {
|
||||
this->reject();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) {
|
||||
// Save object. Indirectly dependent on whether the apply button is enabled
|
||||
// enabled if valid measurement object.
|
||||
this->buttonBox->button(QDialogButtonBox::Apply)->click();
|
||||
return true;
|
||||
}
|
||||
void TaskMeasure::saveMeasurement()
|
||||
{
|
||||
// Save object. Indirectly dependent on whether the apply button is enabled
|
||||
// enabled if valid measurement object.
|
||||
if (buttonBox) {
|
||||
buttonBox->button(QDialogButtonBox::Apply)->click();
|
||||
}
|
||||
}
|
||||
|
||||
return TaskDialog::eventFilter(obj, event);
|
||||
void TaskMeasure::quitMeasurement()
|
||||
{
|
||||
if (this->hasSelection()) {
|
||||
this->reset();
|
||||
}
|
||||
else {
|
||||
this->reject();
|
||||
}
|
||||
}
|
||||
|
||||
void TaskMeasure::setDeltaPossible(bool possible)
|
||||
|
||||
@@ -41,10 +41,10 @@
|
||||
#include <Gui/TaskView/TaskView.h>
|
||||
#include <Gui/Selection/Selection.h>
|
||||
|
||||
namespace Gui
|
||||
namespace MeasureGui
|
||||
{
|
||||
|
||||
class TaskMeasure: public TaskView::TaskDialog, public Gui::SelectionObserver
|
||||
class TaskMeasure: public Gui::TaskView::TaskDialog, public Gui::SelectionObserver
|
||||
{
|
||||
|
||||
public:
|
||||
@@ -59,7 +59,7 @@ public:
|
||||
|
||||
void invoke();
|
||||
void update();
|
||||
void close();
|
||||
void closeDialog();
|
||||
bool apply();
|
||||
bool apply(bool reset);
|
||||
bool reject() override;
|
||||
@@ -67,10 +67,13 @@ public:
|
||||
|
||||
bool hasSelection();
|
||||
void clearSelection();
|
||||
bool eventFilter(QObject* obj, QEvent* event) override;
|
||||
|
||||
private:
|
||||
void setupShortcuts(QWidget* parent);
|
||||
void tryUpdate();
|
||||
void onSelectionChanged(const Gui::SelectionChanges& msg) override;
|
||||
void saveMeasurement();
|
||||
void quitMeasurement();
|
||||
|
||||
Measure::MeasureBase* _mMeasureObject = nullptr;
|
||||
|
||||
@@ -90,10 +93,10 @@ private:
|
||||
void setModeSilent(App::MeasureType* mode);
|
||||
App::MeasureType* getMeasureType();
|
||||
void enableAnnotateButton(bool state);
|
||||
Measure::MeasureBase* createObject(const App::MeasureType* measureType);
|
||||
void createObject(const App::MeasureType* measureType);
|
||||
void ensureGroup(Measure::MeasureBase* measurement);
|
||||
void setDeltaPossible(bool possible);
|
||||
void initViewObject();
|
||||
void initViewObject(Measure::MeasureBase* measure);
|
||||
|
||||
// Stores if the mode is explicitly set by the user or implicitly through the selection
|
||||
bool explicitMode = false;
|
||||
@@ -103,6 +106,6 @@ private:
|
||||
bool mAutoSave = false;
|
||||
};
|
||||
|
||||
} // namespace Gui
|
||||
} // namespace MeasureGui
|
||||
|
||||
#endif // MEASURE_TASKMEASURE_H
|
||||
|
||||
@@ -1377,7 +1377,7 @@ AttachEngine3D::_calculateAttachedPlacement(const std::vector<App::DocumentObjec
|
||||
else {
|
||||
TopLoc_Location loc;
|
||||
Handle(Geom_Surface) surf = BRep_Tool::Surface(face, loc);
|
||||
GeomLib_IsPlanarSurface check(surf);
|
||||
GeomLib_IsPlanarSurface check(surf, precision);
|
||||
if (check.IsPlanar()) {
|
||||
plane = check.Plan();
|
||||
}
|
||||
@@ -2095,11 +2095,17 @@ Base::Placement AttachEnginePlane::_calculateAttachedPlacement(
|
||||
//reuse Attacher3d
|
||||
Base::Placement plm;
|
||||
AttachEngine3D attacher3D;
|
||||
attacher3D.precision = precision;
|
||||
attacher3D.setUp(*this);
|
||||
plm = attacher3D._calculateAttachedPlacement(objs,subs,origPlacement);
|
||||
return plm;
|
||||
}
|
||||
|
||||
double AttachEnginePlane::planarPrecision()
|
||||
{
|
||||
return 2.0e-7; // NOLINT
|
||||
}
|
||||
|
||||
//=================================================================================
|
||||
|
||||
TYPESYSTEM_SOURCE(Attacher::AttachEngineLine, Attacher::AttachEngine)
|
||||
|
||||
@@ -391,6 +391,7 @@ public: //members
|
||||
bool mapReverse = false;
|
||||
double attachParameter = 0.0;
|
||||
double surfU = 0.0, surfV = 0.0;
|
||||
double precision = 1.0e-7;
|
||||
Base::Placement attachmentOffset;
|
||||
|
||||
/**
|
||||
@@ -489,6 +490,7 @@ public:
|
||||
const std::vector<App::DocumentObject*> &objs,
|
||||
const std::vector<std::string> &subs,
|
||||
const Base::Placement &origPlacement) const override;
|
||||
static double planarPrecision();
|
||||
};
|
||||
|
||||
//attacher specialized for datum lines
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#include <ShapeAnalysis_Edge.hxx>
|
||||
#include <gp_Circ.hxx>
|
||||
#include <BRepBuilderAPI_Copy.hxx>
|
||||
#include <GeomLib_IsPlanarSurface.hxx>
|
||||
|
||||
#include <DatumFeature.h>
|
||||
#include <App/Application.h>
|
||||
@@ -56,12 +57,14 @@
|
||||
#include <Base/Rotation.h>
|
||||
#include <Base/Vector3D.h>
|
||||
|
||||
#include "Attacher.h"
|
||||
#include "VectorAdapter.h"
|
||||
#include "PartFeature.h"
|
||||
|
||||
#include "MeasureClient.h"
|
||||
|
||||
using namespace Part;
|
||||
using Attacher::AttachEnginePlane;
|
||||
|
||||
|
||||
// From: https://github.com/Celemation/FreeCAD/blob/joel_selection_summary_demo/src/Gui/Selection/SelectionSummary.cpp
|
||||
@@ -183,12 +186,24 @@ App::MeasureElementType PartMeasureTypeCb(App::DocumentObject* ob, const char* s
|
||||
BRepAdaptor_Surface surface(face);
|
||||
|
||||
switch (surface.GetType()) {
|
||||
case GeomAbs_Cylinder: { return App::MeasureElementType::CYLINDER; }
|
||||
case GeomAbs_Plane: { return App::MeasureElementType::PLANE; }
|
||||
case GeomAbs_Cylinder: {
|
||||
return App::MeasureElementType::CYLINDER;
|
||||
}
|
||||
case GeomAbs_Plane: {
|
||||
return App::MeasureElementType::PLANE;
|
||||
}
|
||||
default: {
|
||||
return App::MeasureElementType::SURFACE; }
|
||||
TopLoc_Location loc;
|
||||
Handle(Geom_Surface) surf = BRep_Tool::Surface(face, loc);
|
||||
GeomLib_IsPlanarSurface check(surf, AttachEnginePlane::planarPrecision());
|
||||
return check.IsPlanar() ? App::MeasureElementType::PLANE
|
||||
: App::MeasureElementType::SURFACE;
|
||||
}
|
||||
}
|
||||
}
|
||||
case TopAbs_SHELL: {
|
||||
return App::MeasureElementType::SURFACE;
|
||||
}
|
||||
case TopAbs_SOLID: {
|
||||
return App::MeasureElementType::VOLUME;
|
||||
}
|
||||
@@ -341,7 +356,7 @@ MeasureAreaInfoPtr MeasureAreaHandler(const App::SubObjectT& subject)
|
||||
}
|
||||
TopAbs_ShapeEnum sType = shape.ShapeType();
|
||||
|
||||
if (sType != TopAbs_FACE) {
|
||||
if (sType != TopAbs_FACE && sType != TopAbs_SHELL && sType != TopAbs_SOLID) {
|
||||
return std::make_shared<MeasureAreaInfo>(false, 0.0, Base::Matrix4D());
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,9 @@ PROPERTY_SOURCE_WITH_EXTENSIONS(Part::Part2DObject, Part::Feature)
|
||||
Part2DObject::Part2DObject()
|
||||
{
|
||||
AttachExtension::initExtension(this);
|
||||
this->setAttacher(new Attacher::AttachEnginePlane);
|
||||
auto engine = new Attacher::AttachEnginePlane;
|
||||
engine->precision = Attacher::AttachEnginePlane::planarPrecision();
|
||||
this->setAttacher(engine);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
|
||||
#include "PrimitiveFeature.h"
|
||||
#include "PartFeature.h"
|
||||
#include "Attacher.h"
|
||||
|
||||
#include <Standard_Type.hxx>
|
||||
#include <Geom_CylindricalSurface.hxx>
|
||||
@@ -40,117 +41,163 @@
|
||||
#include <Geom_Line.hxx>
|
||||
#include <GeomAPI_ProjectPointOnCurve.hxx>
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <GeomLib_IsPlanarSurface.hxx>
|
||||
#include <GeomLProp_SLProps.hxx>
|
||||
|
||||
using Attacher::AttachEnginePlane;
|
||||
|
||||
namespace Part {
|
||||
|
||||
|
||||
VectorAdapter::VectorAdapter() : status(false), vector()
|
||||
VectorAdapter::VectorAdapter()
|
||||
: status(false)
|
||||
{
|
||||
}
|
||||
|
||||
VectorAdapter::VectorAdapter(const TopoDS_Face &faceIn, const gp_Vec &pickedPointIn) :
|
||||
status(false), vector(), origin(pickedPointIn)
|
||||
VectorAdapter::VectorAdapter(const TopoDS_Face &faceIn, const gp_Vec &pickedPointIn)
|
||||
: status(false)
|
||||
, origin(pickedPointIn)
|
||||
{
|
||||
Handle(Geom_Surface) surface = BRep_Tool::Surface(faceIn);
|
||||
if (surface->IsKind(STANDARD_TYPE(Geom_ElementarySurface)))
|
||||
{
|
||||
Handle(Geom_ElementarySurface) eSurface = Handle(Geom_ElementarySurface)::DownCast(surface);
|
||||
gp_Dir direction = eSurface->Axis().Direction();
|
||||
vector = direction;
|
||||
std::vector<std::function<bool(const TopoDS_Face &, const gp_Vec &)>> funcs = {
|
||||
[this](const TopoDS_Face& face, const gp_Vec& vec) {
|
||||
return this->handleElementarySurface(face, vec);
|
||||
},
|
||||
[this](const TopoDS_Face& face, const gp_Vec& vec) {
|
||||
return this->handlePlanarSurface(face, vec);
|
||||
}
|
||||
};
|
||||
for (const auto& it : funcs) {
|
||||
if (it(faceIn, pickedPointIn)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VectorAdapter::VectorAdapter(const TopoDS_Edge &edgeIn, const gp_Vec &pickedPointIn)
|
||||
: status(false)
|
||||
, origin(pickedPointIn)
|
||||
{
|
||||
TopoDS_Vertex firstVertex = TopExp::FirstVertex(edgeIn, Standard_True);
|
||||
TopoDS_Vertex lastVertex = TopExp::LastVertex(edgeIn, Standard_True);
|
||||
vector = convert(lastVertex) - convert(firstVertex);
|
||||
if (vector.Magnitude() < Precision::Confusion()) {
|
||||
return;
|
||||
}
|
||||
vector.Normalize();
|
||||
if (faceIn.Orientation() == TopAbs_REVERSED) {
|
||||
vector.Reverse();
|
||||
}
|
||||
if (surface->IsKind(STANDARD_TYPE(Geom_CylindricalSurface)) ||
|
||||
surface->IsKind(STANDARD_TYPE(Geom_SphericalSurface))
|
||||
)
|
||||
{
|
||||
origin = eSurface->Axis().Location().XYZ();
|
||||
projectOriginOntoVector(pickedPointIn);
|
||||
}
|
||||
else {
|
||||
origin = pickedPointIn + vector;
|
||||
}
|
||||
|
||||
status = true;
|
||||
}
|
||||
projectOriginOntoVector(pickedPointIn);
|
||||
}
|
||||
|
||||
VectorAdapter::VectorAdapter(const TopoDS_Edge &edgeIn, const gp_Vec &pickedPointIn) :
|
||||
status(false), vector(), origin(pickedPointIn)
|
||||
VectorAdapter::VectorAdapter(const TopoDS_Vertex &vertex1In, const TopoDS_Vertex &vertex2In)
|
||||
: status(false)
|
||||
{
|
||||
TopoDS_Vertex firstVertex = TopExp::FirstVertex(edgeIn, Standard_True);
|
||||
TopoDS_Vertex lastVertex = TopExp::LastVertex(edgeIn, Standard_True);
|
||||
vector = convert(lastVertex) - convert(firstVertex);
|
||||
if (vector.Magnitude() < Precision::Confusion()) {
|
||||
return;
|
||||
}
|
||||
vector.Normalize();
|
||||
vector = convert(vertex2In) - convert(vertex1In);
|
||||
vector.Normalize();
|
||||
|
||||
status = true;
|
||||
projectOriginOntoVector(pickedPointIn);
|
||||
//build origin half way.
|
||||
gp_Vec tempVector = (convert(vertex2In) - convert(vertex1In));
|
||||
double mag = tempVector.Magnitude();
|
||||
tempVector.Normalize();
|
||||
tempVector *= (mag / 2.0);
|
||||
origin = tempVector + convert(vertex1In);
|
||||
|
||||
status = true;
|
||||
}
|
||||
|
||||
VectorAdapter::VectorAdapter(const TopoDS_Vertex &vertex1In, const TopoDS_Vertex &vertex2In) :
|
||||
status(false), vector(), origin()
|
||||
VectorAdapter::VectorAdapter(const gp_Vec &vector1, const gp_Vec &vector2)
|
||||
: status(false)
|
||||
{
|
||||
vector = convert(vertex2In) - convert(vertex1In);
|
||||
vector.Normalize();
|
||||
vector = vector2- vector1;
|
||||
vector.Normalize();
|
||||
|
||||
//build origin half way.
|
||||
gp_Vec tempVector = (convert(vertex2In) - convert(vertex1In));
|
||||
double mag = tempVector.Magnitude();
|
||||
tempVector.Normalize();
|
||||
tempVector *= (mag / 2.0);
|
||||
origin = tempVector + convert(vertex1In);
|
||||
//build origin half way.
|
||||
gp_Vec tempVector = vector2 - vector1;
|
||||
double mag = tempVector.Magnitude();
|
||||
tempVector.Normalize();
|
||||
tempVector *= (mag / 2.0);
|
||||
origin = tempVector + vector1;
|
||||
|
||||
status = true;
|
||||
status = true;
|
||||
}
|
||||
|
||||
VectorAdapter::VectorAdapter(const gp_Vec &vector1, const gp_Vec &vector2) :
|
||||
status(false), vector(), origin()
|
||||
bool VectorAdapter::handleElementarySurface(const TopoDS_Face &faceIn, const gp_Vec &pickedPointIn)
|
||||
{
|
||||
vector = vector2- vector1;
|
||||
vector.Normalize();
|
||||
Handle(Geom_Surface) surface = BRep_Tool::Surface(faceIn);
|
||||
if (surface->IsKind(STANDARD_TYPE(Geom_ElementarySurface))) {
|
||||
Handle(Geom_ElementarySurface) eSurface = Handle(Geom_ElementarySurface)::DownCast(surface);
|
||||
gp_Dir direction = eSurface->Axis().Direction();
|
||||
vector = direction;
|
||||
vector.Normalize();
|
||||
if (faceIn.Orientation() == TopAbs_REVERSED) {
|
||||
vector.Reverse();
|
||||
}
|
||||
if (surface->IsKind(STANDARD_TYPE(Geom_CylindricalSurface)) ||
|
||||
surface->IsKind(STANDARD_TYPE(Geom_SphericalSurface))
|
||||
) {
|
||||
origin = eSurface->Axis().Location().XYZ();
|
||||
projectOriginOntoVector(pickedPointIn);
|
||||
}
|
||||
else {
|
||||
origin = pickedPointIn + vector;
|
||||
}
|
||||
status = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
//build origin half way.
|
||||
gp_Vec tempVector = vector2 - vector1;
|
||||
double mag = tempVector.Magnitude();
|
||||
tempVector.Normalize();
|
||||
tempVector *= (mag / 2.0);
|
||||
origin = tempVector + vector1;
|
||||
return false;
|
||||
}
|
||||
|
||||
status = true;
|
||||
bool VectorAdapter::handlePlanarSurface(const TopoDS_Face &faceIn, const gp_Vec &pickedPointIn)
|
||||
{
|
||||
Handle(Geom_Surface) surface = BRep_Tool::Surface(faceIn);
|
||||
GeomLib_IsPlanarSurface check(surface, AttachEnginePlane::planarPrecision());
|
||||
if (check.IsPlanar()) {
|
||||
double u1 {};
|
||||
double u2 {};
|
||||
double v1 {};
|
||||
double v2 {};
|
||||
surface->Bounds(u1, u2, v1, v2);
|
||||
GeomLProp_SLProps prop(surface, u1, v1, 1, Precision::Confusion());
|
||||
if (prop.IsNormalDefined()) {
|
||||
vector = prop.Normal();
|
||||
vector.Normalize();
|
||||
if (faceIn.Orientation() == TopAbs_REVERSED) {
|
||||
vector.Reverse();
|
||||
}
|
||||
origin = pickedPointIn + vector;
|
||||
status = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void VectorAdapter::projectOriginOntoVector(const gp_Vec &pickedPointIn)
|
||||
{
|
||||
Handle(Geom_Curve) heapLine = new Geom_Line(origin.XYZ(), vector.XYZ());
|
||||
gp_Pnt tempPoint(pickedPointIn.XYZ());
|
||||
GeomAPI_ProjectPointOnCurve projection(tempPoint, heapLine);
|
||||
if (projection.NbPoints() < 1) {
|
||||
return;
|
||||
}
|
||||
origin.SetXYZ(projection.Point(1).XYZ());
|
||||
Handle(Geom_Curve) heapLine = new Geom_Line(origin.XYZ(), vector.XYZ());
|
||||
gp_Pnt tempPoint(pickedPointIn.XYZ());
|
||||
GeomAPI_ProjectPointOnCurve projection(tempPoint, heapLine);
|
||||
if (projection.NbPoints() >= 1) {
|
||||
origin.SetXYZ(projection.Point(1).XYZ());
|
||||
}
|
||||
}
|
||||
|
||||
VectorAdapter::operator gp_Lin() const
|
||||
{
|
||||
gp_Pnt tempOrigin;
|
||||
tempOrigin.SetXYZ(origin.XYZ());
|
||||
return gp_Lin(tempOrigin, gp_Dir(vector));
|
||||
gp_Pnt tempOrigin;
|
||||
tempOrigin.SetXYZ(origin.XYZ());
|
||||
return gp_Lin(tempOrigin, gp_Dir(vector));
|
||||
}
|
||||
|
||||
|
||||
/*convert a vertex to vector*/
|
||||
gp_Vec VectorAdapter::convert(const TopoDS_Vertex &vertex)
|
||||
{
|
||||
gp_Pnt point = BRep_Tool::Pnt(vertex);
|
||||
gp_Vec out(point.X(), point.Y(), point.Z());
|
||||
return out;
|
||||
gp_Pnt point = BRep_Tool::Pnt(vertex);
|
||||
gp_Vec out(point.X(), point.Y(), point.Z());
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -43,45 +43,46 @@ namespace Part
|
||||
class VectorAdapter
|
||||
{
|
||||
public:
|
||||
/*!default construction isValid is set to false*/
|
||||
VectorAdapter();
|
||||
/*!Build a vector from a faceIn
|
||||
* @param faceIn vector will be normal to plane and equal to cylindrical axis.
|
||||
* @param pickedPointIn location of pick. straight conversion from sbvec. not accurate.*/
|
||||
VectorAdapter(const TopoDS_Face &faceIn, const gp_Vec &pickedPointIn);
|
||||
/*!Build a vector from an edgeIn
|
||||
* @param edgeIn vector will be lastPoint - firstPoint.
|
||||
* @param pickedPointIn location of pick. straight conversion from sbvec. not accurate.*/
|
||||
VectorAdapter(const TopoDS_Edge &edgeIn, const gp_Vec &pickedPointIn);
|
||||
/*!Build a vector From 2 vertices.
|
||||
*vector will be equal to @param vertex2In - @param vertex1In.*/
|
||||
VectorAdapter(const TopoDS_Vertex &vertex1In, const TopoDS_Vertex &vertex2In);
|
||||
/*!Build a vector From 2 vectors.
|
||||
*vector will be equal to @param vector2 - @param vector1.*/
|
||||
VectorAdapter(const gp_Vec &vector1, const gp_Vec &vector2);
|
||||
/*!default construction isValid is set to false*/
|
||||
VectorAdapter();
|
||||
/*!Build a vector from a faceIn
|
||||
* @param faceIn vector will be normal to plane and equal to cylindrical axis.
|
||||
* @param pickedPointIn location of pick. straight conversion from sbvec. not accurate.*/
|
||||
VectorAdapter(const TopoDS_Face &faceIn, const gp_Vec &pickedPointIn);
|
||||
/*!Build a vector from an edgeIn
|
||||
* @param edgeIn vector will be lastPoint - firstPoint.
|
||||
* @param pickedPointIn location of pick. straight conversion from sbvec. not accurate.*/
|
||||
VectorAdapter(const TopoDS_Edge &edgeIn, const gp_Vec &pickedPointIn);
|
||||
/*!Build a vector From 2 vertices.
|
||||
*vector will be equal to @param vertex2In - @param vertex1In.*/
|
||||
VectorAdapter(const TopoDS_Vertex &vertex1In, const TopoDS_Vertex &vertex2In);
|
||||
/*!Build a vector From 2 vectors.
|
||||
*vector will be equal to @param vector2 - @param vector1.*/
|
||||
VectorAdapter(const gp_Vec &vector1, const gp_Vec &vector2);
|
||||
|
||||
/*!make sure no errors in vector construction.
|
||||
* @return true = vector is good. false = vector is NOT good.*/
|
||||
bool isValid() const {return status;}
|
||||
/*!get the calculated vector.
|
||||
* @return the vector. use isValid to ensure correct results.*/
|
||||
operator gp_Vec() const {return vector;}//explicit bombs
|
||||
/*!build occ line used for extrema calculation*/
|
||||
operator gp_Lin() const;//explicit bombs
|
||||
gp_Vec getPickPoint() const {return origin;}
|
||||
|
||||
operator Base::Vector3d() const {
|
||||
return Base::Vector3d(vector.X(), vector.Y(), vector.Z());
|
||||
}
|
||||
/*!make sure no errors in vector construction.
|
||||
* @return true = vector is good. false = vector is NOT good.*/
|
||||
bool isValid() const {return status;}
|
||||
/*!get the calculated vector.
|
||||
* @return the vector. use isValid to ensure correct results.*/
|
||||
explicit operator gp_Vec() const {return vector;}
|
||||
/*!build occ line used for extrema calculation*/
|
||||
explicit operator gp_Lin() const;
|
||||
gp_Vec getPickPoint() const {return origin;}
|
||||
|
||||
explicit operator Base::Vector3d() const {
|
||||
return Base::Vector3d(vector.X(), vector.Y(), vector.Z());
|
||||
}
|
||||
|
||||
static gp_Vec convert(const TopoDS_Vertex& vertex);
|
||||
|
||||
private:
|
||||
void projectOriginOntoVector(const gp_Vec &pickedPointIn);
|
||||
bool status;
|
||||
gp_Vec vector;
|
||||
gp_Vec origin;
|
||||
private:
|
||||
void projectOriginOntoVector(const gp_Vec &pickedPointIn);
|
||||
bool handleElementarySurface(const TopoDS_Face &faceIn, const gp_Vec &pickedPointIn);
|
||||
bool handlePlanarSurface(const TopoDS_Face &faceIn, const gp_Vec &pickedPointIn);
|
||||
bool status;
|
||||
gp_Vec vector;
|
||||
gp_Vec origin;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -141,7 +141,7 @@ public:
|
||||
throw WrongSupportException();
|
||||
}
|
||||
|
||||
if (!subshape.isPlanar()) {
|
||||
if (!subshape.isPlanar(Attacher::AttachEnginePlane::planarPrecision())) {
|
||||
throw SupportNotPlanarException();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user