From bae8050fac84684e915832fcfaec5e0b2e834b0b Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Tue, 17 May 2022 12:00:52 +0200 Subject: [PATCH] Sketcher-Utils: Refactor common code up --- src/Mod/Sketcher/Gui/AutoConstraint.h | 47 +++++++ src/Mod/Sketcher/Gui/CMakeLists.txt | 1 + src/Mod/Sketcher/Gui/CommandConstraints.cpp | 4 - src/Mod/Sketcher/Gui/CommandCreateGeo.cpp | 138 -------------------- src/Mod/Sketcher/Gui/DrawSketchHandler.h | 16 +-- src/Mod/Sketcher/Gui/Utils.cpp | 138 ++++++++++++++++++++ src/Mod/Sketcher/Gui/Utils.h | 33 +++++ 7 files changed, 221 insertions(+), 156 deletions(-) create mode 100644 src/Mod/Sketcher/Gui/AutoConstraint.h diff --git a/src/Mod/Sketcher/Gui/AutoConstraint.h b/src/Mod/Sketcher/Gui/AutoConstraint.h new file mode 100644 index 0000000000..46de42f78b --- /dev/null +++ b/src/Mod/Sketcher/Gui/AutoConstraint.h @@ -0,0 +1,47 @@ +/*************************************************************************** + * Copyright (c) 2022 Abdullah Tahiri * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library 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 Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#ifndef SKETCHERGUI_AutoConstraint_H +#define SKETCHERGUI_AutoConstraint_H + +namespace SketcherGui { + +// A Simple data type to hold basic information for suggested constraints +struct AutoConstraint +{ + enum TargetType + { + VERTEX, + CURVE, + VERTEX_NO_TANGENCY + }; + Sketcher::ConstraintType Type; + int GeoId; + Sketcher::PointPos PosId; +}; + +} // namespace SketcherGui + + +#endif // SKETCHERGUI_AutoConstraint_H + diff --git a/src/Mod/Sketcher/Gui/CMakeLists.txt b/src/Mod/Sketcher/Gui/CMakeLists.txt index 9c0820afe1..b45f6bed37 100644 --- a/src/Mod/Sketcher/Gui/CMakeLists.txt +++ b/src/Mod/Sketcher/Gui/CMakeLists.txt @@ -61,6 +61,7 @@ SET(SketcherGui_SRCS AppSketcherGui.cpp GeometryCreationMode.h Command.cpp + AutoConstraint.h Utils.h Utils.cpp CommandCreateGeo.cpp diff --git a/src/Mod/Sketcher/Gui/CommandConstraints.cpp b/src/Mod/Sketcher/Gui/CommandConstraints.cpp index 239b42ba5f..b0a2a1edfe 100644 --- a/src/Mod/Sketcher/Gui/CommandConstraints.cpp +++ b/src/Mod/Sketcher/Gui/CommandConstraints.cpp @@ -72,10 +72,6 @@ namespace SketcherGui ConstraintCreationMode constraintCreationMode = Driving; -void ActivateHandler(Gui::Document *doc, DrawSketchHandler *handler); - -bool isCreateGeoActive(Gui::Document *doc); - bool isCreateConstraintActive(Gui::Document *doc) { if (doc) { diff --git a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp index 3d82c1e40a..45d4347541 100644 --- a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp +++ b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp @@ -77,144 +77,6 @@ namespace SketcherGui { GeometryCreationMode geometryCreationMode=Normal; } -/* helper functions ======================================================*/ - -// Return counter-clockwise angle from horizontal out of p1 to p2 in radians. -double GetPointAngle (const Base::Vector2d &p1, const Base::Vector2d &p2) -{ - double dX = p2.x - p1.x; - double dY = p2.y - p1.y; - return dY >= 0 ? atan2(dY, dX) : atan2(dY, dX) + 2*M_PI; -} - -void ActivateHandler(Gui::Document *doc, DrawSketchHandler *handler) -{ - std::unique_ptr ptr(handler); - if (doc) { - if (doc->getInEdit() && doc->getInEdit()->isDerivedFrom(SketcherGui::ViewProviderSketch::getClassTypeId())) { - SketcherGui::ViewProviderSketch* vp = static_cast (doc->getInEdit()); - vp->purgeHandler(); - vp->activateHandler(ptr.release()); - } - } -} - -bool isCreateGeoActive(Gui::Document *doc) -{ - if (doc) { - // checks if a Sketch Viewprovider is in Edit and is in no special mode - if (doc->getInEdit() && doc->getInEdit()->isDerivedFrom - (SketcherGui::ViewProviderSketch::getClassTypeId())) { - /*if (dynamic_cast(doc->getInEdit())-> - getSketchMode() == ViewProviderSketch::STATUS_NONE)*/ - return true; - } - } - return false; -} - -SketcherGui::ViewProviderSketch* getSketchViewprovider(Gui::Document *doc) -{ - if (doc) { - if (doc->getInEdit() && doc->getInEdit()->isDerivedFrom - (SketcherGui::ViewProviderSketch::getClassTypeId()) ) - return dynamic_cast(doc->getInEdit()); - } - return nullptr; -} - -void removeRedundantHorizontalVertical(Sketcher::SketchObject* psketch, - std::vector &sug1, - std::vector &sug2) -{ - if(!sug1.empty() && !sug2.empty()) { - - bool rmvhorvert = false; - - // we look for: - // 1. Coincident to external on both endpoints - // 2. Coincident in one endpoint to origin and pointonobject/tangent to an axis on the other - auto detectredundant = [psketch](std::vector &sug, bool &ext, bool &orig, bool &axis) { - - ext = false; - orig = false; - axis = false; - - for(std::vector::const_iterator it = sug.begin(); it!=sug.end(); ++it) { - if( (*it).Type == Sketcher::Coincident && !ext) { - const std::map coincidents = psketch->getAllCoincidentPoints((*it).GeoId, (*it).PosId); - - if(!coincidents.empty()) { - // the keys are ordered, so if the first is negative, it is coincident with external - ext = coincidents.begin()->first < 0; - - std::map::const_iterator geoId1iterator; - - geoId1iterator = coincidents.find(-1); - - if( geoId1iterator != coincidents.end()) { - if( (*geoId1iterator).second == Sketcher::PointPos::start ) - orig = true; - } - } - else { // it may be that there is no constraint at all, but there is external geometry - ext = (*it).GeoId < 0; - orig = ((*it).GeoId == -1 && (*it).PosId == Sketcher::PointPos::start); - } - } - else if( (*it).Type == Sketcher::PointOnObject && !axis) { - axis = (((*it).GeoId == -1 && (*it).PosId == Sketcher::PointPos::none) || ((*it).GeoId == -2 && (*it).PosId == Sketcher::PointPos::none)); - } - - } - }; - - bool firstext = false, secondext = false, firstorig = false, secondorig = false, firstaxis = false, secondaxis = false; - - detectredundant(sug1, firstext, firstorig, firstaxis); - detectredundant(sug2, secondext, secondorig, secondaxis); - - - rmvhorvert = ((firstext && secondext) || // coincident with external on both endpoints - (firstorig && secondaxis) || // coincident origin and point on object on other - (secondorig && firstaxis)); - - if(rmvhorvert) { - for(std::vector::reverse_iterator it = sug2.rbegin(); it!=sug2.rend(); ++it) { - if( (*it).Type == Sketcher::Horizontal || (*it).Type == Sketcher::Vertical) { - sug2.erase(std::next(it).base()); - it = sug2.rbegin(); // erase invalidates the iterator - } - } - } - } -} - -void ConstraintToAttachment(Sketcher::GeoElementId element, Sketcher::GeoElementId attachment, double distance, App::DocumentObject* obj) { - if (distance == 0.) { - - if(attachment.isCurve()) { - Gui::cmdAppObjectArgs(obj, "addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ", - element.GeoId, element.posIdAsInt(), attachment.GeoId); - - } - else { - Gui::cmdAppObjectArgs(obj, "addConstraint(Sketcher.Constraint('Coincident',%d,%d,%d,%d)) ", - element.GeoId, element.posIdAsInt(), attachment.GeoId, attachment.posIdAsInt()); - } - } - else { - if(attachment == Sketcher::GeoElementId::VAxis) { - Gui::cmdAppObjectArgs(obj, "addConstraint(Sketcher.Constraint('DistanceX',%d,%d,%f)) ", - element.GeoId, element.posIdAsInt(), distance); - } - else if(attachment == Sketcher::GeoElementId::HAxis) { - Gui::cmdAppObjectArgs(obj, "addConstraint(Sketcher.Constraint('DistanceY',%d,%d,%f)) ", - element.GeoId, element.posIdAsInt(), distance); - } - } -} - /* Sketch commands =======================================================*/ class DrawSketchHandlerLine: public DrawSketchHandler diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandler.h b/src/Mod/Sketcher/Gui/DrawSketchHandler.h index 8830555356..3bbc0f19c9 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandler.h +++ b/src/Mod/Sketcher/Gui/DrawSketchHandler.h @@ -28,6 +28,8 @@ #include #include +#include "AutoConstraint.h" + class QPixmap; namespace Sketcher { @@ -89,20 +91,6 @@ private: friend class DrawSketchHandler; }; -// A Simple data type to hold basic information for suggested constraints -struct AutoConstraint -{ - enum TargetType - { - VERTEX, - CURVE, - VERTEX_NO_TANGENCY - }; - Sketcher::ConstraintType Type; - int GeoId; - Sketcher::PointPos PosId; -}; - /** Handler to create new sketch geometry * This class has to be reimplemented to create geometry in the * sketcher while its in editing. diff --git a/src/Mod/Sketcher/Gui/Utils.cpp b/src/Mod/Sketcher/Gui/Utils.cpp index 6a630692f3..5b8df91037 100644 --- a/src/Mod/Sketcher/Gui/Utils.cpp +++ b/src/Mod/Sketcher/Gui/Utils.cpp @@ -279,3 +279,141 @@ bool SketcherGui::checkConstraint(const std::vector< Sketcher::Constraint * > &v return false; } + +/* helper functions ======================================================*/ + +// Return counter-clockwise angle from horizontal out of p1 to p2 in radians. +double SketcherGui::GetPointAngle (const Base::Vector2d &p1, const Base::Vector2d &p2) +{ + double dX = p2.x - p1.x; + double dY = p2.y - p1.y; + return dY >= 0 ? atan2(dY, dX) : atan2(dY, dX) + 2*M_PI; +} + +void SketcherGui::ActivateHandler(Gui::Document *doc, DrawSketchHandler *handler) +{ + std::unique_ptr ptr(handler); + if (doc) { + if (doc->getInEdit() && doc->getInEdit()->isDerivedFrom(SketcherGui::ViewProviderSketch::getClassTypeId())) { + SketcherGui::ViewProviderSketch* vp = static_cast (doc->getInEdit()); + vp->purgeHandler(); + vp->activateHandler(ptr.release()); + } + } +} + +bool SketcherGui::isCreateGeoActive(Gui::Document *doc) +{ + if (doc) { + // checks if a Sketch Viewprovider is in Edit and is in no special mode + if (doc->getInEdit() && doc->getInEdit()->isDerivedFrom + (SketcherGui::ViewProviderSketch::getClassTypeId())) { + /*if (dynamic_cast(doc->getInEdit())-> + getSketchMode() == ViewProviderSketch::STATUS_NONE)*/ + return true; + } + } + return false; +} + +SketcherGui::ViewProviderSketch* SketcherGui::getSketchViewprovider(Gui::Document *doc) +{ + if (doc) { + if (doc->getInEdit() && doc->getInEdit()->isDerivedFrom + (SketcherGui::ViewProviderSketch::getClassTypeId()) ) + return dynamic_cast(doc->getInEdit()); + } + return nullptr; +} + +void SketcherGui::removeRedundantHorizontalVertical(Sketcher::SketchObject* psketch, + std::vector &sug1, + std::vector &sug2) +{ + if(!sug1.empty() && !sug2.empty()) { + + bool rmvhorvert = false; + + // we look for: + // 1. Coincident to external on both endpoints + // 2. Coincident in one endpoint to origin and pointonobject/tangent to an axis on the other + auto detectredundant = [psketch](std::vector &sug, bool &ext, bool &orig, bool &axis) { + + ext = false; + orig = false; + axis = false; + + for(std::vector::const_iterator it = sug.begin(); it!=sug.end(); ++it) { + if( (*it).Type == Sketcher::Coincident && ext == false) { + const std::map coincidents = psketch->getAllCoincidentPoints((*it).GeoId, (*it).PosId); + + if(!coincidents.empty()) { + // the keys are ordered, so if the first is negative, it is coincident with external + ext = coincidents.begin()->first < 0; + + std::map::const_iterator geoId1iterator; + + geoId1iterator = coincidents.find(-1); + + if( geoId1iterator != coincidents.end()) { + if( (*geoId1iterator).second == Sketcher::PointPos::start ) + orig = true; + } + } + else { // it may be that there is no constraint at all, but there is external geometry + ext = (*it).GeoId < 0; + orig = ((*it).GeoId == -1 && (*it).PosId == Sketcher::PointPos::start); + } + } + else if( (*it).Type == Sketcher::PointOnObject && axis == false) { + axis = (((*it).GeoId == -1 && (*it).PosId == Sketcher::PointPos::none) || ((*it).GeoId == -2 && (*it).PosId == Sketcher::PointPos::none)); + } + + } + }; + + bool firstext = false, secondext = false, firstorig = false, secondorig = false, firstaxis = false, secondaxis = false; + + detectredundant(sug1, firstext, firstorig, firstaxis); + detectredundant(sug2, secondext, secondorig, secondaxis); + + + rmvhorvert = ((firstext && secondext) || // coincident with external on both endpoints + (firstorig && secondaxis) || // coincident origin and point on object on other + (secondorig && firstaxis)); + + if(rmvhorvert) { + for(std::vector::reverse_iterator it = sug2.rbegin(); it!=sug2.rend(); ++it) { + if( (*it).Type == Sketcher::Horizontal || (*it).Type == Sketcher::Vertical) { + sug2.erase(std::next(it).base()); + it = sug2.rbegin(); // erase invalidates the iterator + } + } + } + } +} + +void SketcherGui::ConstraintToAttachment(Sketcher::GeoElementId element, Sketcher::GeoElementId attachment, double distance, App::DocumentObject* obj) { + if (distance == 0.) { + + if(attachment.isCurve()) { + Gui::cmdAppObjectArgs(obj, "addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ", + element.GeoId, element.posIdAsInt(), attachment.GeoId); + + } + else { + Gui::cmdAppObjectArgs(obj, "addConstraint(Sketcher.Constraint('Coincident',%d,%d,%d,%d)) ", + element.GeoId, element.posIdAsInt(), attachment.GeoId, attachment.posIdAsInt()); + } + } + else { + if(attachment == Sketcher::GeoElementId::VAxis) { + Gui::cmdAppObjectArgs(obj, "addConstraint(Sketcher.Constraint('DistanceX',%d,%d,%f)) ", + element.GeoId, element.posIdAsInt(), distance); + } + else if(attachment == Sketcher::GeoElementId::HAxis) { + Gui::cmdAppObjectArgs(obj, "addConstraint(Sketcher.Constraint('DistanceY',%d,%d,%f)) ", + element.GeoId, element.posIdAsInt(), distance); + } + } +} diff --git a/src/Mod/Sketcher/Gui/Utils.h b/src/Mod/Sketcher/Gui/Utils.h index 502ee2c80c..5224521975 100644 --- a/src/Mod/Sketcher/Gui/Utils.h +++ b/src/Mod/Sketcher/Gui/Utils.h @@ -24,12 +24,26 @@ #ifndef SKETCHERGUI_Recompute_H #define SKETCHERGUI_Recompute_H +#include +#include +#include "AutoConstraint.h" + +namespace App { + class DocumentObject; +} + +namespace Gui { + class DocumentObject; +} + namespace Sketcher { enum class PointPos : int; class SketchObject; } namespace SketcherGui { + class DrawSketchHandler; + class ViewProviderSketch; /// This function tries to auto-recompute the active document if the option /// is set in the user parameter. If the option is not set nothing will be done @@ -90,6 +104,25 @@ inline bool isEdge(int GeoId, Sketcher::PointPos PosId) return (GeoId != Sketcher::GeoEnum::GeoUndef && PosId == Sketcher::PointPos::none); } + +/* helper functions ======================================================*/ + +// Return counter-clockwise angle from horizontal out of p1 to p2 in radians. +double GetPointAngle (const Base::Vector2d &p1, const Base::Vector2d &p2); + +void ActivateHandler(Gui::Document *doc, DrawSketchHandler *handler); + +bool isCreateGeoActive(Gui::Document *doc); + +SketcherGui::ViewProviderSketch* getSketchViewprovider(Gui::Document *doc); + + +void removeRedundantHorizontalVertical(Sketcher::SketchObject* psketch, + std::vector &sug1, + std::vector &sug2); + +void ConstraintToAttachment(Sketcher::GeoElementId element, Sketcher::GeoElementId attachment, double distance, App::DocumentObject* obj); + } #endif // SKETCHERGUI_Recompute_H