|
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
|
|
|
|
| #ifndef SKETCHERGUI_DrawSketchDefaultHandler_H
|
| #define SKETCHERGUI_DrawSketchDefaultHandler_H
|
|
|
| #include <Inventor/events/SoKeyboardEvent.h>
|
|
|
| #include <Base/Exception.h>
|
| #include <Base/Console.h>
|
| #include <Gui/Command.h>
|
|
|
| #include <Mod/Sketcher/App/GeoEnum.h>
|
| #include <Mod/Sketcher/App/GeometryFacade.h>
|
| #include <Mod/Sketcher/App/PythonConverter.h>
|
| #include <Mod/Sketcher/App/SketchObject.h>
|
| #include <Mod/Sketcher/App/SolverGeometryExtension.h>
|
|
|
| #include "AutoConstraint.h"
|
| #include "DrawSketchHandler.h"
|
| #include "ViewProviderSketch.h"
|
| #include "SnapManager.h"
|
|
|
| #include "Utils.h"
|
|
|
| namespace SketcherGui
|
| {
|
|
|
|
|
|
|
|
|
|
|
|
|
| namespace StateMachines
|
| {
|
|
|
| enum class OneSeekEnd
|
| {
|
| SeekFirst,
|
| End
|
| };
|
|
|
| enum class TwoSeekEnd
|
| {
|
| SeekFirst,
|
| SeekSecond,
|
| End
|
| };
|
|
|
| enum class ThreeSeekEnd
|
| {
|
| SeekFirst,
|
| SeekSecond,
|
| SeekThird,
|
| End
|
| };
|
|
|
| enum class FourSeekEnd
|
| {
|
| SeekFirst,
|
| SeekSecond,
|
| SeekThird,
|
| SeekFourth,
|
| End
|
| };
|
|
|
| enum class FiveSeekEnd
|
| {
|
| SeekFirst,
|
| SeekSecond,
|
| SeekThird,
|
| SeekFourth,
|
| SeekFifth,
|
| End
|
| };
|
|
|
| enum class TwoSeekDoEnd
|
| {
|
| SeekFirst,
|
| SeekSecond,
|
| Do,
|
| End
|
| };
|
|
|
| }
|
|
|
|
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| template<typename SelectModeT>
|
| class StateMachine
|
| {
|
| public:
|
| StateMachine()
|
| : Mode(static_cast<SelectModeT>(0))
|
| {}
|
| virtual ~StateMachine()
|
| {}
|
|
|
| protected:
|
| void setState(SelectModeT mode)
|
| {
|
| Mode = mode;
|
| onModeChanged();
|
| }
|
|
|
| void ensureState(SelectModeT mode)
|
| {
|
| if (Mode != mode) {
|
| Mode = mode;
|
| onModeChanged();
|
| }
|
| }
|
|
|
| |
| |
| |
| |
| |
| |
|
|
| void ensureStateIfEarlier(SelectModeT mode)
|
| {
|
| if (Mode != mode) {
|
| if (mode < Mode) {
|
| Mode = mode;
|
| onModeChanged();
|
| }
|
| }
|
| }
|
|
|
| SelectModeT state() const
|
| {
|
| return Mode;
|
| }
|
|
|
| bool isState(SelectModeT state) const
|
| {
|
| return Mode == state;
|
| }
|
|
|
| void setNextState(std::optional<SelectModeT> nextState)
|
| {
|
| nextMode = nextState;
|
| }
|
|
|
| std::optional<SelectModeT> getNextState()
|
| {
|
| return nextMode;
|
| }
|
|
|
| void applyNextState()
|
| {
|
| if (nextMode) {
|
| auto next = std::move(*nextMode);
|
| nextMode = std::nullopt;
|
| setState(next);
|
| }
|
| }
|
|
|
| bool isFirstState() const
|
| {
|
| return Mode == (static_cast<SelectModeT>(0));
|
| }
|
|
|
| bool isLastState() const
|
| {
|
| return Mode == SelectModeT::End;
|
| }
|
|
|
| constexpr SelectModeT getFirstState() const
|
| {
|
| return static_cast<SelectModeT>(0);
|
| }
|
|
|
| SelectModeT computeNextMode() const
|
| {
|
| auto modeint = static_cast<int>(state());
|
|
|
| if (modeint < maxMode) {
|
| auto newmode = static_cast<SelectModeT>(modeint + 1);
|
| return newmode;
|
| }
|
| else {
|
| return SelectModeT::End;
|
| }
|
| }
|
|
|
| void moveToNextMode()
|
| {
|
| setState(computeNextMode());
|
| }
|
|
|
| void reset()
|
| {
|
| nextMode = std::nullopt;
|
| if (Mode != static_cast<SelectModeT>(0)) {
|
| setState(static_cast<SelectModeT>(0));
|
| }
|
| }
|
|
|
| virtual bool onModeChanged()
|
| {
|
| return true;
|
| };
|
|
|
| private:
|
| SelectModeT Mode;
|
| std::optional<SelectModeT> nextMode;
|
| static const constexpr int maxMode = static_cast<int>(SelectModeT::End);
|
| };
|
|
|
|
|
| namespace ConstructionMethods
|
| {
|
|
|
| enum class DefaultConstructionMethod
|
| {
|
| End
|
| };
|
|
|
| }
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| template<typename ConstructionMethodT>
|
| class ConstructionMethodMachine
|
| {
|
| public:
|
| ConstructionMethodMachine(
|
| ConstructionMethodT constructionmethod = static_cast<ConstructionMethodT>(0)
|
| )
|
| : ConstructionMode(constructionmethod)
|
| {}
|
| virtual ~ConstructionMethodMachine()
|
| {}
|
|
|
| protected:
|
| void setConstructionMethod(ConstructionMethodT mode)
|
| {
|
| ConstructionMode = mode;
|
| onConstructionMethodChanged();
|
| }
|
|
|
| ConstructionMethodT constructionMethod() const
|
| {
|
| return ConstructionMode;
|
| }
|
|
|
| bool isConstructionMethod(ConstructionMethodT state) const
|
| {
|
| return ConstructionMode == state;
|
| }
|
|
|
| void resetConstructionMode()
|
| {
|
| ConstructionMode = static_cast<ConstructionMethodT>(0);
|
| }
|
|
|
| void initConstructionMethod(ConstructionMethodT mode)
|
| {
|
| ConstructionMode = mode;
|
| }
|
|
|
|
|
| ConstructionMethodT getNextMethod() const
|
| {
|
| auto modeint = static_cast<int>(ConstructionMode);
|
|
|
|
|
| if (modeint < (maxMode - 1)) {
|
| auto newmode = static_cast<ConstructionMethodT>(modeint + 1);
|
| return newmode;
|
| }
|
| else {
|
| return static_cast<ConstructionMethodT>(0);
|
| }
|
| }
|
|
|
| void iterateToNextConstructionMethod()
|
| {
|
| if (ConstructionMethodsCount() > 1) {
|
| setConstructionMethod(getNextMethod());
|
| }
|
| }
|
|
|
| virtual void onConstructionMethodChanged() {};
|
|
|
| static constexpr int ConstructionMethodsCount()
|
| {
|
| return maxMode;
|
| }
|
|
|
| private:
|
| ConstructionMethodT ConstructionMode;
|
| static const constexpr int maxMode = static_cast<int>(ConstructionMethodT::End);
|
| };
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| template<
|
| typename HandlerT,
|
| typename SelectModeT,
|
| int PInitAutoConstraintSize,
|
| typename ConstructionMethodT = ConstructionMethods::DefaultConstructionMethod>
|
| class DrawSketchDefaultHandler: public DrawSketchHandler,
|
| public StateMachine<SelectModeT>,
|
| public ConstructionMethodMachine<ConstructionMethodT>
|
| {
|
| public:
|
| DrawSketchDefaultHandler(
|
| ConstructionMethodT constructionmethod = static_cast<ConstructionMethodT>(0)
|
| )
|
| : ConstructionMethodMachine<ConstructionMethodT>(constructionmethod)
|
| , sugConstraints(PInitAutoConstraintSize)
|
| , avoidRedundants(true)
|
| , continuousMode(true)
|
| {
|
| applyCursor();
|
| }
|
|
|
| ~DrawSketchDefaultHandler() override
|
| {}
|
|
|
| |
| |
| |
|
|
|
|
| void mouseMove(SnapManager::SnapHandle snapHandle) override
|
| {
|
| updateDataAndDrawToPosition(snapHandle.compute());
|
| }
|
|
|
| bool pressButton(Base::Vector2d onSketchPos) override
|
| {
|
|
|
| onButtonPressed(onSketchPos);
|
| return true;
|
| }
|
|
|
| bool releaseButton(Base::Vector2d onSketchPos) override
|
| {
|
| Q_UNUSED(onSketchPos);
|
| finish();
|
| return true;
|
| }
|
|
|
| void registerPressedKey(bool pressed, int key) override
|
| {
|
| if (key == SoKeyboardEvent::M && pressed && !this->isLastState()) {
|
| this->iterateToNextConstructionMethod();
|
| }
|
| else if (key == SoKeyboardEvent::ESCAPE && pressed) {
|
| rightButtonOrEsc();
|
| }
|
| }
|
|
|
| void pressRightButton(Base::Vector2d onSketchPos) override
|
| {
|
| Q_UNUSED(onSketchPos);
|
| rightButtonOrEsc();
|
| }
|
|
|
| virtual void rightButtonOrEsc()
|
| {
|
| if (this->isFirstState()) {
|
| quit();
|
| }
|
| else {
|
| handleContinuousMode();
|
| }
|
| }
|
|
|
|
|
|
|
|
|
| protected:
|
| using SelectMode = SelectModeT;
|
| using ModeStateMachine = StateMachine<SelectModeT>;
|
| using ConstructionMethod = ConstructionMethodT;
|
| using ConstructionMachine = ConstructionMethodMachine<ConstructionMethodT>;
|
|
|
| |
| |
| |
| |
| |
|
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| bool finish()
|
| {
|
| if (this->isState(SelectMode::End)) {
|
| unsetCursor();
|
| resetPositionText();
|
|
|
| try {
|
| executeCommands();
|
|
|
| if (sugConstraints.size() > 0) {
|
| beforeCreateAutoConstraints();
|
|
|
| generateAutoConstraints();
|
|
|
| createAutoConstraints();
|
| }
|
| }
|
| catch (const Base::RuntimeError& e) {
|
|
|
|
|
|
|
| Base::Console().error(e.what());
|
| }
|
|
|
|
|
|
|
| try {
|
| tryAutoRecomputeIfNotSolve(sketchgui->getSketchObject());
|
| }
|
| catch (const Base::RuntimeError& e) {
|
|
|
|
|
|
|
| Base::Console().error(e.what());
|
| }
|
| return handleContinuousMode();
|
| }
|
| return false;
|
| }
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| void reset()
|
| {
|
| clearEdit();
|
|
|
| for (auto& ac : sugConstraints) {
|
| ac.clear();
|
| }
|
|
|
| AutoConstraints.clear();
|
| ShapeGeometry.clear();
|
| ShapeConstraints.clear();
|
|
|
| onReset();
|
|
|
| ModeStateMachine::reset();
|
|
|
| applyCursor();
|
| }
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| bool handleContinuousMode()
|
| {
|
| if (continuousMode) {
|
|
|
| reset();
|
|
|
|
|
| return false;
|
| }
|
| else {
|
| sketchgui->purgeHandler();
|
| return true;
|
| }
|
| }
|
|
|
|
|
| private:
|
| |
|
|
|
|
| virtual void onReset()
|
| {}
|
| virtual void executeCommands()
|
| {}
|
| virtual void generateAutoConstraints()
|
| {}
|
| virtual void beforeCreateAutoConstraints()
|
| {}
|
| virtual void createAutoConstraints()
|
| {}
|
|
|
| void onConstructionMethodChanged() override {};
|
|
|
| virtual void updateDataAndDrawToPosition(Base::Vector2d onSketchPos)
|
| {
|
| Q_UNUSED(onSketchPos)
|
| };
|
|
|
| virtual void angleSnappingControl()
|
| {}
|
|
|
|
|
| virtual void createShape(bool onlyeditoutline)
|
| {
|
| Q_UNUSED(onlyeditoutline)
|
| }
|
|
|
| protected:
|
| |
|
|
|
|
|
|
| void activated() override
|
| {
|
| avoidRedundants = sketchgui->AvoidRedundant.getValue()
|
| && sketchgui->Autoconstraints.getValue();
|
|
|
| ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath(
|
| "User parameter:BaseApp/Preferences/Mod/Sketcher"
|
| );
|
|
|
| continuousMode = hGrp->GetBool("ContinuousCreationMode", true);
|
| }
|
|
|
| |
| |
| |
|
|
| virtual void onButtonPressed(Base::Vector2d onSketchPos)
|
| {
|
| this->updateDataAndDrawToPosition(onSketchPos);
|
| if (canGoToNextMode()) {
|
| this->moveToNextMode();
|
| }
|
| }
|
|
|
| virtual bool canGoToNextMode()
|
| {
|
| return true;
|
| }
|
|
|
| |
|
|
| bool onModeChanged() override
|
| {
|
| angleSnappingControl();
|
|
|
| return !finish();
|
| };
|
|
|
|
|
| |
|
|
|
|
|
|
|
|
| bool generateOneAutoConstraintFromSuggestion(
|
| const AutoConstraint& ac,
|
| int geoId1,
|
| Sketcher::PointPos posId1
|
| )
|
| {
|
| int geoId2 = ac.GeoId;
|
| Sketcher::PointPos posId2 = ac.PosId;
|
|
|
| static const auto isStartOrEnd = [](const Sketcher::PointPos posId) {
|
| return posId == Sketcher::PointPos::start || posId == Sketcher::PointPos::end;
|
| };
|
|
|
|
|
| switch (ac.Type) {
|
| case Sketcher::Coincident: {
|
| if (posId1 == Sketcher::PointPos::none) {
|
| return true;
|
| }
|
|
|
|
|
| auto itOfTangentConstraint = AutoConstraints.end();
|
| if (isStartOrEnd(posId1) && isStartOrEnd(posId2)) {
|
| itOfTangentConstraint = std::ranges::find(
|
| AutoConstraints,
|
| std::tuple {Sketcher::Tangent, geoId1, geoId2},
|
| [](const auto& ace) {
|
| return std::tuple {ace->Type, ace->First, ace->Second};
|
| }
|
| );
|
| }
|
|
|
| if (itOfTangentConstraint != AutoConstraints.end()) {
|
|
|
| (*itOfTangentConstraint)->FirstPos = posId1;
|
| (*itOfTangentConstraint)->SecondPos = posId2;
|
| }
|
| else {
|
| auto c = std::make_unique<Sketcher::Constraint>();
|
| c->Type = Sketcher::Coincident;
|
| c->First = geoId1;
|
| c->FirstPos = posId1;
|
| c->Second = geoId2;
|
| c->SecondPos = posId2;
|
| AutoConstraints.push_back(std::move(c));
|
| }
|
| } break;
|
| case Sketcher::PointOnObject: {
|
| if (posId1 == Sketcher::PointPos::none) {
|
|
|
| std::swap(geoId1, geoId2);
|
| std::swap(posId1, posId2);
|
| }
|
|
|
| auto itOfTangentConstraint = AutoConstraints.end();
|
| if (isStartOrEnd(posId1)) {
|
| itOfTangentConstraint = std::ranges::find_if(AutoConstraints, [&](const auto& ace) {
|
| return ace->Type == Sketcher::Tangent && ace->involvesGeoId(geoId1)
|
| && ace->involvesGeoId(geoId2);
|
| });
|
| }
|
|
|
|
|
| if (itOfTangentConstraint != AutoConstraints.end()) {
|
| if ((*itOfTangentConstraint)->First != geoId1) {
|
| std::swap((*itOfTangentConstraint)->Second, (*itOfTangentConstraint)->First);
|
| }
|
|
|
| (*itOfTangentConstraint)->FirstPos = posId1;
|
| }
|
| else {
|
| auto c = std::make_unique<Sketcher::Constraint>();
|
| c->Type = Sketcher::PointOnObject;
|
| c->First = geoId1;
|
| c->FirstPos = posId1;
|
| c->Second = geoId2;
|
| AutoConstraints.push_back(std::move(c));
|
| }
|
| } break;
|
| case Sketcher::Symmetric: {
|
| auto c = std::make_unique<Sketcher::Constraint>();
|
| c->Type = Sketcher::Symmetric;
|
| c->First = geoId2;
|
| c->FirstPos = Sketcher::PointPos::start;
|
| c->Second = geoId2;
|
| c->SecondPos = Sketcher::PointPos::end;
|
| c->Third = geoId1;
|
| c->ThirdPos = posId1;
|
| AutoConstraints.push_back(std::move(c));
|
| } break;
|
|
|
|
|
|
|
|
|
|
|
| case Sketcher::Horizontal:
|
| case Sketcher::Vertical: {
|
| auto c = std::make_unique<Sketcher::Constraint>();
|
| c->Type = ac.Type;
|
| c->First = (geoId2 != Sketcher::GeoEnum::GeoUndef ? geoId2 : geoId1);
|
| AutoConstraints.push_back(std::move(c));
|
| } break;
|
| case Sketcher::Tangent: {
|
| Sketcher::SketchObject* Obj = sketchgui->getObject<Sketcher::SketchObject>();
|
|
|
| const Part::Geometry* geom1 = Obj->getGeometry(geoId1);
|
| const Part::Geometry* geom2 = Obj->getGeometry(geoId2);
|
|
|
|
|
| if (geom1 && geom2
|
| && (geom1->is<Part::GeomEllipse>() || geom2->is<Part::GeomEllipse>())) {
|
| if (!geom1->is<Part::GeomEllipse>()) {
|
| std::swap(geoId1, geoId2);
|
| }
|
|
|
|
|
| geom1 = Obj->getGeometry(geoId1);
|
| geom2 = Obj->getGeometry(geoId2);
|
|
|
| if (geom2->is<Part::GeomEllipse>() || geom2->is<Part::GeomArcOfEllipse>()
|
| || geom2->is<Part::GeomCircle>() || geom2->is<Part::GeomArcOfCircle>()) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| return false;
|
| }
|
| }
|
|
|
|
|
| if (geom1 && geom2
|
| && (geom1->is<Part::GeomArcOfEllipse>() || geom2->is<Part::GeomArcOfEllipse>())) {
|
| if (!geom1->is<Part::GeomArcOfEllipse>()) {
|
| std::swap(geoId1, geoId2);
|
| }
|
|
|
|
|
| geom1 = Obj->getGeometry(geoId1);
|
| geom2 = Obj->getGeometry(geoId2);
|
|
|
| if (geom2->is<Part::GeomArcOfEllipse>() || geom2->is<Part::GeomCircle>()
|
| || geom2->is<Part::GeomArcOfCircle>()) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| return false;
|
| }
|
| }
|
|
|
| auto resultCoincident = std::ranges::find_if(AutoConstraints, [&](const auto& ace) {
|
| return ace->Type == Sketcher::Coincident && ace->First == geoId1
|
| && ace->Second == geoId2;
|
| });
|
|
|
| auto resultPointOnObject = std::ranges::find_if(AutoConstraints, [&](const auto& ace) {
|
| return ace->Type == Sketcher::PointOnObject && ace->involvesGeoId(geoId1)
|
| && ace->involvesGeoId(geoId2);
|
| });
|
|
|
| if (resultCoincident != AutoConstraints.end()
|
| && isStartOrEnd((*resultCoincident)->FirstPos)
|
| && isStartOrEnd((*resultCoincident)->SecondPos)) {
|
|
|
| (*resultCoincident)->Type = Sketcher::Tangent;
|
| }
|
| else if (resultPointOnObject != AutoConstraints.end()
|
| && isStartOrEnd((*resultPointOnObject)->FirstPos)) {
|
|
|
| (*resultPointOnObject)->Type = Sketcher::Tangent;
|
| }
|
| else if (resultCoincident != AutoConstraints.end()
|
| && (*resultCoincident)->FirstPos == Sketcher::PointPos::mid
|
| && (*resultCoincident)->SecondPos == Sketcher::PointPos::mid && geom1 && geom2
|
| && (geom1->is<Part::GeomCircle>() || geom1->is<Part::GeomArcOfCircle>())
|
| && (geom2->is<Part::GeomCircle>() || geom2->is<Part::GeomArcOfCircle>())) {
|
|
|
| auto c = std::make_unique<Sketcher::Constraint>();
|
| c->Type = Sketcher::Equal;
|
| c->First = geoId1;
|
| c->Second = geoId2;
|
| AutoConstraints.push_back(std::move(c));
|
| }
|
| else {
|
| auto c = std::make_unique<Sketcher::Constraint>();
|
| c->Type = Sketcher::Tangent;
|
| c->First = geoId1;
|
| c->Second = geoId2;
|
| AutoConstraints.push_back(std::move(c));
|
| }
|
| } break;
|
| default:
|
| break;
|
| }
|
|
|
| return true;
|
| }
|
|
|
| |
| |
| |
| |
|
|
| void generateAutoConstraintsOnElement(
|
| const std::vector<AutoConstraint>& autoConstrs,
|
| int geoId1,
|
| Sketcher::PointPos posId1
|
| )
|
| {
|
| if (!sketchgui->Autoconstraints.getValue()) {
|
| return;
|
| }
|
|
|
| for (auto& ac : autoConstrs) {
|
| if (!generateOneAutoConstraintFromSuggestion(ac, geoId1, posId1)) {
|
| return;
|
| }
|
| }
|
| }
|
|
|
| |
|
|
| void createGeneratedAutoConstraints(bool owncommand)
|
| {
|
| try {
|
|
|
| if (owncommand) {
|
| Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Add Auto-Constraints"));
|
| }
|
|
|
| tryAddAutoConstraints();
|
|
|
| if (owncommand) {
|
| Gui::Command::commitCommand();
|
| }
|
| }
|
| catch (const Base::PyException&) {
|
| if (owncommand) {
|
| Gui::Command::abortCommand();
|
| }
|
| }
|
| }
|
|
|
| |
|
|
| void tryAddAutoConstraints()
|
| {
|
| auto autoConstraints = toPointerVector(AutoConstraints);
|
|
|
| Gui::Command::doCommand(
|
| Gui::Command::Doc,
|
| Sketcher::PythonConverter::convert(
|
| Gui::Command::getObjectCmd(sketchgui->getObject()),
|
| autoConstraints
|
| )
|
| .c_str()
|
| );
|
| }
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| void removeRedundantAutoConstraints()
|
| {
|
|
|
| if (AutoConstraints.empty()) {
|
| return;
|
| }
|
|
|
| auto sketchobject = getSketchObject();
|
|
|
| auto autoConstraints = toPointerVector(AutoConstraints);
|
|
|
|
|
|
|
| sketchobject->diagnoseAdditionalConstraints(autoConstraints);
|
|
|
| if (sketchobject->getLastHasRedundancies()) {
|
| Base::Console().warning(
|
| QT_TRANSLATE_NOOP("Notifications", "Autoconstraints cause redundancy. Removing them") "\n"
|
| );
|
|
|
| auto lastsketchconstraintindex = sketchobject->Constraints.getSize() - 1;
|
|
|
| auto redundants = sketchobject->getLastRedundant();
|
|
|
| for (int index = redundants.size() - 1; index >= 0; index--) {
|
| int redundantconstraintindex = redundants[index] - 1;
|
| if (redundantconstraintindex > lastsketchconstraintindex) {
|
| int removeindex = redundantconstraintindex - lastsketchconstraintindex - 1;
|
| AutoConstraints.erase(std::next(AutoConstraints.begin(), removeindex));
|
| }
|
| else {
|
|
|
|
|
|
|
|
|
| THROWM(
|
| Base::RuntimeError,
|
| QT_TRANSLATE_NOOP(
|
| "Notifications",
|
| "Redundant constraint is not an autoconstraint. No autoconstraints "
|
| "or additional constraints were added. Please report!"
|
| ) "\n"
|
| );
|
| }
|
| }
|
|
|
|
|
|
|
| }
|
|
|
|
|
|
|
| if (sketchobject->getLastHasConflicts()) {
|
| auto lastsketchconstraintindex = sketchobject->Constraints.getSize() - 1;
|
|
|
| auto conflicting = sketchobject->getLastConflicting();
|
|
|
| for (int index = conflicting.size() - 1; index >= 0; index--) {
|
| int conflictingIndex = conflicting[index] - 1;
|
| if (conflictingIndex > lastsketchconstraintindex) {
|
| int removeindex = conflictingIndex - lastsketchconstraintindex - 1;
|
| AutoConstraints.erase(std::next(AutoConstraints.begin(), removeindex));
|
| }
|
| }
|
| }
|
| }
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| void diagnoseWithAutoConstraints()
|
| {
|
| auto sketchobject = getSketchObject();
|
|
|
| auto autoConstraints = toPointerVector(AutoConstraints);
|
|
|
| sketchobject->diagnoseAdditionalConstraints(autoConstraints);
|
|
|
| if (sketchobject->getLastHasRedundancies() || sketchobject->getLastHasConflicts()) {
|
| THROWM(
|
| Base::RuntimeError,
|
| QT_TRANSLATE_NOOP(
|
| "Notifications",
|
| "Unexpected Redundancy/Conflicting constraint. Check the "
|
| "constraints and autoconstraints of this operation."
|
| ) "\n"
|
| );
|
| }
|
| }
|
|
|
|
|
| Sketcher::SolverGeometryExtension::PointParameterStatus getPointInfo(
|
| const Sketcher::GeoElementId& element
|
| )
|
| {
|
| if (element.isCurve()) {
|
| THROWM(Base::TypeError, "getPointInfo: Provided geometry element is not a point!")
|
| }
|
|
|
| auto sketchobject = getSketchObject();
|
|
|
|
|
| const auto& solvedsketch = sketchobject->getSolvedSketch();
|
|
|
| auto solvext = solvedsketch.getSolverExtension(element.GeoId);
|
|
|
| if (solvext) {
|
| auto pointinfo = solvext->getPoint(element.Pos);
|
|
|
| return pointinfo;
|
| }
|
|
|
| THROWM(
|
| Base::ValueError,
|
| "Geometry element does not have solver information (possibly when trying to apply "
|
| "widget constraints)!"
|
| )
|
| }
|
|
|
|
|
| int getLineDoFs(int geoid)
|
| {
|
| auto startpointinfo = getPointInfo(Sketcher::GeoElementId(geoid, Sketcher::PointPos::start));
|
|
|
| auto endpointinfo = getPointInfo(Sketcher::GeoElementId(geoid, Sketcher::PointPos::end));
|
|
|
| int DoFs = startpointinfo.getDoFs();
|
| DoFs += endpointinfo.getDoFs();
|
|
|
| return DoFs;
|
| }
|
|
|
|
|
| Sketcher::SolverGeometryExtension::EdgeParameterStatus getEdgeInfo(int geoid)
|
| {
|
|
|
| auto sketchobject = getSketchObject();
|
|
|
|
|
| const auto& solvedsketch = sketchobject->getSolvedSketch();
|
|
|
| auto solvext = solvedsketch.getSolverExtension(geoid);
|
|
|
| if (solvext) {
|
| Sketcher::SolverGeometryExtension::EdgeParameterStatus edgeinfo
|
| = solvext->getEdgeParameters();
|
|
|
| return edgeinfo;
|
| }
|
|
|
| THROWM(
|
| Base::ValueError,
|
| "Geometry does not have solver extension when trying to apply widget constraints!"
|
| )
|
| }
|
|
|
| |
| |
| |
| |
| |
| |
|
|
| auto addToShapeConstraints(
|
| Sketcher::ConstraintType type,
|
| int first,
|
| Sketcher::PointPos firstPos = Sketcher::PointPos::none,
|
| int second = Sketcher::GeoEnum::GeoUndef,
|
| Sketcher::PointPos secondPos = Sketcher::PointPos::none,
|
| int third = Sketcher::GeoEnum::GeoUndef,
|
| Sketcher::PointPos thirdPos = Sketcher::PointPos::none
|
| )
|
| {
|
| auto constr = std::make_unique<Sketcher::Constraint>();
|
| constr->Type = type;
|
| constr->First = first;
|
| constr->FirstPos = firstPos;
|
| constr->Second = second;
|
| constr->SecondPos = secondPos;
|
| constr->Third = third;
|
| constr->ThirdPos = thirdPos;
|
| return ShapeConstraints.emplace_back(std::move(constr)).get();
|
| }
|
|
|
|
|
| auto addLineToShapeGeometry(Base::Vector3d p1, Base::Vector3d p2, bool constructionMode)
|
| {
|
| auto line = std::make_unique<Part::GeomLineSegment>();
|
| line->setPoints(p1, p2);
|
| Sketcher::GeometryFacade::setConstruction(line.get(), constructionMode);
|
| return static_cast<Part::GeomLineSegment*>(ShapeGeometry.emplace_back(std::move(line)).get());
|
| }
|
|
|
|
|
| auto addArcToShapeGeometry(Base::Vector3d p1, double start, double end, double radius, bool constructionMode)
|
| {
|
| auto arc = std::make_unique<Part::GeomArcOfCircle>();
|
| arc->setCenter(p1);
|
| arc->setRange(start, end, true);
|
| arc->setRadius(radius);
|
| Sketcher::GeometryFacade::setConstruction(arc.get(), constructionMode);
|
| return static_cast<Part::GeomArcOfCircle*>(ShapeGeometry.emplace_back(std::move(arc)).get());
|
| }
|
|
|
|
|
| auto addPointToShapeGeometry(Base::Vector3d p1, bool constructionMode)
|
| {
|
| auto point = std::make_unique<Part::GeomPoint>();
|
| point->setPoint(p1);
|
| Sketcher::GeometryFacade::setConstruction(point.get(), constructionMode);
|
| return static_cast<Part::GeomPoint*>(ShapeGeometry.emplace_back(std::move(point)).get());
|
| }
|
|
|
|
|
| auto addEllipseToShapeGeometry(
|
| Base::Vector3d centerPoint,
|
| Base::Vector3d majorAxisDirection,
|
| double majorRadius,
|
| double minorRadius,
|
| bool constructionMode
|
| )
|
| {
|
| auto ellipse = std::make_unique<Part::GeomEllipse>();
|
| ellipse->setMajorRadius(majorRadius);
|
| ellipse->setMinorRadius(minorRadius);
|
| ellipse->setMajorAxisDir(majorAxisDirection);
|
| ellipse->setCenter(centerPoint);
|
| Sketcher::GeometryFacade::setConstruction(ellipse.get(), constructionMode);
|
| return static_cast<Part::GeomEllipse*>(ShapeGeometry.emplace_back(std::move(ellipse)).get());
|
| }
|
|
|
|
|
| auto addCircleToShapeGeometry(Base::Vector3d centerPoint, double radius, bool constructionMode)
|
| {
|
| auto circle = std::make_unique<Part::GeomCircle>();
|
| circle->setRadius(radius);
|
| circle->setCenter(centerPoint);
|
| Sketcher::GeometryFacade::setConstruction(circle.get(), constructionMode);
|
| return static_cast<Part::GeomCircle*>(ShapeGeometry.emplace_back(std::move(circle)).get());
|
| }
|
|
|
| |
|
|
| void commandAddShapeGeometryAndConstraints()
|
| {
|
| auto shapeGeometry = toPointerVector(ShapeGeometry);
|
| std::string sketchObj = Gui::Command::getObjectCmd(sketchgui->getObject());
|
| Gui::Command::doCommand(Gui::Command::Doc, "ActiveSketch = %s\n", sketchObj.c_str());
|
| Gui::Command::doCommand(
|
| Gui::Command::Doc,
|
| Sketcher::PythonConverter::convert(
|
| sketchObj,
|
| shapeGeometry,
|
| Sketcher::PythonConverter::Mode::OmitInternalGeometry
|
| )
|
| .c_str()
|
| );
|
|
|
| size_t initialConstraintCount = sketchgui->getSketchObject()->Constraints.getSize();
|
| auto shapeConstraints = toPointerVector(ShapeConstraints);
|
| Gui::Command::doCommand(
|
| Gui::Command::Doc,
|
| Sketcher::PythonConverter::convert(sketchObj, shapeConstraints).c_str()
|
| );
|
|
|
| reassignVirtualSpace(initialConstraintCount);
|
| }
|
|
|
|
|
| void DrawShapeGeometry()
|
| {
|
| drawEdit(toPointerVector(ShapeGeometry));
|
| }
|
|
|
|
|
| void CreateAndDrawShapeGeometry()
|
| {
|
| createShape(true);
|
| drawEdit(toPointerVector(ShapeGeometry));
|
| }
|
|
|
|
|
|
|
| private:
|
|
|
| void reassignVirtualSpace(size_t startIndex)
|
| {
|
| if (ShapeConstraints.empty()) {
|
| return;
|
| }
|
|
|
| std::stringstream stream;
|
| bool hasConstraintsInVirtualSpace = false;
|
| for (size_t i = 0; i < ShapeConstraints.size(); ++i) {
|
| if (ShapeConstraints[i]->isInVirtualSpace) {
|
| if (hasConstraintsInVirtualSpace) {
|
| stream << ",";
|
| }
|
| stream << i + startIndex;
|
| hasConstraintsInVirtualSpace = true;
|
| }
|
| }
|
| if (!hasConstraintsInVirtualSpace) {
|
| return;
|
| }
|
|
|
| try {
|
| Gui::cmdAppObjectArgs(
|
| sketchgui->getObject(),
|
| "setVirtualSpace([%s], True)",
|
| stream.str().c_str()
|
| );
|
| }
|
| catch (const Base::Exception& e) {
|
| Base::Console().error("%s\n", e.what());
|
| }
|
| }
|
|
|
| protected:
|
| std::vector<std::vector<AutoConstraint>> sugConstraints;
|
|
|
| std::vector<std::unique_ptr<Part::Geometry>> ShapeGeometry;
|
| std::vector<std::unique_ptr<Sketcher::Constraint>> ShapeConstraints;
|
| std::vector<std::unique_ptr<Sketcher::Constraint>> AutoConstraints;
|
|
|
| bool avoidRedundants;
|
| bool continuousMode;
|
| };
|
|
|
| }
|
|
|
|
|
| #endif
|
|
|