diff --git a/src/Mod/Sketcher/App/SketchGeometryExtension.h b/src/Mod/Sketcher/App/SketchGeometryExtension.h index 51571d5813..3ad0893c1f 100644 --- a/src/Mod/Sketcher/App/SketchGeometryExtension.h +++ b/src/Mod/Sketcher/App/SketchGeometryExtension.h @@ -63,9 +63,11 @@ public: virtual long getId() const = 0; virtual void setId(long id) = 0; + // Internal Alignment Geometry Type virtual InternalType::InternalType getInternalType() const = 0; virtual void setInternalType(InternalType::InternalType type) = 0; + // Geometry functional mode virtual bool testGeometryMode(int flag) const = 0; virtual void setGeometryMode(int flag, bool v=true) = 0; }; diff --git a/src/Mod/Sketcher/Gui/AppSketcherGui.cpp b/src/Mod/Sketcher/Gui/AppSketcherGui.cpp index 9f19709a9d..c0e2931128 100644 --- a/src/Mod/Sketcher/Gui/AppSketcherGui.cpp +++ b/src/Mod/Sketcher/Gui/AppSketcherGui.cpp @@ -42,6 +42,7 @@ #include "SoZoomTranslation.h" #include "SketcherSettings.h" #include "PropertyConstraintListItem.h" +#include "ViewProviderSketchGeometryExtension.h" // create the commands @@ -122,13 +123,14 @@ PyMOD_INIT_FUNC(SketcherGui) SketcherGui::Workbench::init(); // init objects - SketcherGui::ViewProviderSketch ::init(); - SketcherGui::ViewProviderPython ::init(); - SketcherGui::ViewProviderCustom ::init(); - SketcherGui::ViewProviderCustomPython ::init(); - SketcherGui::SoDatumLabel ::initClass(); - SketcherGui::SoZoomTranslation ::initClass(); - SketcherGui::PropertyConstraintListItem ::init(); + SketcherGui::ViewProviderSketch ::init(); + SketcherGui::ViewProviderPython ::init(); + SketcherGui::ViewProviderCustom ::init(); + SketcherGui::ViewProviderCustomPython ::init(); + SketcherGui::SoDatumLabel ::initClass(); + SketcherGui::SoZoomTranslation ::initClass(); + SketcherGui::PropertyConstraintListItem ::init(); + SketcherGui::ViewProviderSketchGeometryExtension ::init(); (void)new Gui::PrefPageProducer ( QT_TRANSLATE_NOOP("QObject","Sketcher") ); (void)new Gui::PrefPageProducer ( QT_TRANSLATE_NOOP("QObject","Sketcher") ); diff --git a/src/Mod/Sketcher/Gui/CMakeLists.txt b/src/Mod/Sketcher/Gui/CMakeLists.txt index d7ba36057f..2a16b77d0e 100644 --- a/src/Mod/Sketcher/Gui/CMakeLists.txt +++ b/src/Mod/Sketcher/Gui/CMakeLists.txt @@ -140,6 +140,8 @@ SET(SketcherGui_SRCS TaskDlgEditSketch.h ViewProviderPython.cpp ViewProviderPython.h + ViewProviderSketchGeometryExtension.h + ViewProviderSketchGeometryExtension.cpp ) if(FREECAD_USE_PCH) diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp index 89a910b53c..51a3e15bc6 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp @@ -120,6 +120,7 @@ #include "TaskDlgEditSketch.h" #include "TaskSketcherValidation.h" #include "CommandConstraints.h" +#include "ViewProviderSketchGeometryExtension.h" FC_LOG_LEVEL_INIT("Sketch",true,true) @@ -849,9 +850,8 @@ bool ViewProviderSketch::mouseButtonPressed(int Button, bool pressed, const SbVe Base::Vector3d vec(x-xInit,y-yInit,0); // BSpline weights have a radius corresponding to the weight value - // However, in order for them to have a visual size irrespective of the - // zoom, the scenograph has a size getScaleFactor() times the weight - // + // However, in order for them proportional to the B-Spline size, + // the scenograph has a size scalefactor times the weight // This code normalizes the information sent to the solver. if(gf->getInternalType() == InternalType::BSplineControlPoint) { auto circle = static_cast(geo); @@ -859,7 +859,17 @@ bool ViewProviderSketch::mouseButtonPressed(int Button, bool pressed, const SbVe Base::Vector3d dir = vec - center; - vec = center - dir / getScaleFactor(); + double scalefactor = 1.0; + + if(circle->hasExtension(SketcherGui::ViewProviderSketchGeometryExtension::getClassTypeId())) + { + auto vpext = std::static_pointer_cast( + circle->getExtension(SketcherGui::ViewProviderSketchGeometryExtension::getClassTypeId()).lock()); + + scalefactor = vpext->getRepresentationFactor(); + } + + vec = center + dir / scalefactor; } try { @@ -1150,8 +1160,34 @@ bool ViewProviderSketch::mouseMove(const SbVec2s &cursorPos, Gui::View3DInventor edit->PreselectCurve != -1 && edit->DragCurve != edit->PreselectCurve) { Mode = STATUS_SKETCH_DragCurve; edit->DragCurve = edit->PreselectCurve; - getSketchObject()->getSolvedSketch().initMove(edit->DragCurve, Sketcher::none, false); const Part::Geometry *geo = getSketchObject()->getGeometry(edit->DragCurve); + + // BSpline Control points are edge draggable only if their radius is movable + // This is because dragging gives unwanted cosmetic results due to the scale ratio. + // This is an heuristic as it does not check all indirect routes. + if(GeometryFacade::isInternalType(geo, InternalType::BSplineControlPoint)) { + bool weight = false; + bool weight_driven = false; + bool equal = false; + bool block = false; + + for(auto c : getSketchObject()->Constraints.getValues()) { + weight = weight || (c->Type == Sketcher::Weight && c->First == edit->DragCurve); + weight_driven = weight_driven || (c->Type == Sketcher::Weight && !c->isDriving && c->First == edit->DragCurve); + equal = equal || (c->Type == Sketcher::Equal && (c->First == edit->DragCurve || c->Second == edit->DragCurve)); + block = block || (c->Type == Sketcher::Block && c->First == edit->DragCurve); + } + + if( (weight && !weight_driven) || + (equal && !weight_driven) || + block) { + Mode = STATUS_NONE; + return false; + } + } + + getSketchObject()->getSolvedSketch().initMove(edit->DragCurve, Sketcher::none, false); + if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId() || geo->getTypeId() == Part::GeomBSplineCurve::getClassTypeId()) { relative = true; @@ -1211,9 +1247,8 @@ bool ViewProviderSketch::mouseMove(const SbVec2s &cursorPos, Gui::View3DInventor Base::Vector3d vec(x-xInit,y-yInit,0); // BSpline weights have a radius corresponding to the weight value - // However, in order for them to have a visual size irrespective of the - // zoom, the scenograph has a size getScaleFactor() times the weight - // + // However, in order for them proportional to the B-Spline size, + // the scenograph has a size scalefactor times the weight // This code normalizes the information sent to the solver. if(gf->getInternalType() == InternalType::BSplineControlPoint) { auto circle = static_cast(geo); @@ -1221,7 +1256,17 @@ bool ViewProviderSketch::mouseMove(const SbVec2s &cursorPos, Gui::View3DInventor Base::Vector3d dir = vec - center; - vec = center - dir / getScaleFactor(); + double scalefactor = 1.0; + + if(circle->hasExtension(SketcherGui::ViewProviderSketchGeometryExtension::getClassTypeId())) + { + auto vpext = std::static_pointer_cast( + circle->getExtension(SketcherGui::ViewProviderSketchGeometryExtension::getClassTypeId()).lock()); + + scalefactor = vpext->getRepresentationFactor(); + } + + vec = center + dir / scalefactor; } if (getSketchObject()->getSolvedSketch().movePoint(edit->DragCurve, Sketcher::none, vec, relative) == 0) { @@ -3666,10 +3711,10 @@ void ViewProviderSketch::draw(bool temp /*=false*/, bool rebuildinformationlayer Base::Vector3d center = circle->getCenter(); // BSpline weights have a radius corresponding to the weight value - // However, in order for them to have a visual size irrespective of the - // zoom, the scenograph has a size getScaleFactor() times the weight + // However, in order for them proportional to the B-Spline size, + // the scenograph has a size scalefactor times the weight // - // This code draws the scaled up version of the geometry for the scenograph + // This code produces the scaled up version of the geometry for the scenograph if(gf->getInternalType() == InternalType::BSplineControlPoint) { for( auto c : getSketchObject()->Constraints.getValues()) { if( c->Type == InternalAlignment && c->AlignmentType == BSplineControlPoint && c->First == GeoId) { @@ -3685,8 +3730,8 @@ void ViewProviderSketch::draw(bool temp /*=false*/, bool rebuildinformationlayer // tentative scaling factor: // proportional to the length of the bspline // inversely proportional to the number of poles - //double scalefactor = bspline->length(bspline->getFirstParameter(), bspline->getLastParameter())/10.0/weights.size(); - double scalefactor = getScaleFactor(); + double scalefactor = bspline->length(bspline->getFirstParameter(), bspline->getLastParameter())/10.0/weights.size(); + //double scalefactor = getScaleFactor(); double vradius = weight*scalefactor; // virtual circle or radius vradius @@ -3705,6 +3750,21 @@ void ViewProviderSketch::draw(bool temp /*=false*/, bool rebuildinformationlayer mcurve(0,x,y); Coords.emplace_back(x, y, 0); + + // save scale factor for any prospective dragging operation + if(!circle->hasExtension(SketcherGui::ViewProviderSketchGeometryExtension::getClassTypeId())) + { + // It is ok to add this kind of extension to a const geometry because: + // 1. It does not modify the object in a way that affects property state, just ViewProvider representation + // 2. If it is lost (for example upon undo), redrawing will reinstate it with the correct value + const_cast(circle)->setExtension(std::make_unique()); + } + + auto vpext = std::const_pointer_cast( + std::static_pointer_cast( + circle->getExtension(SketcherGui::ViewProviderSketchGeometryExtension::getClassTypeId()).lock())); + + vpext->setRepresentationFactor(scalefactor); } break; } @@ -5462,10 +5522,22 @@ Restart: double radius; - if(Constr->Type == Weight) - radius = circle->getRadius()*getScaleFactor(); - else + if(Constr->Type == Weight) { + double scalefactor = 1.0; + + if(circle->hasExtension(SketcherGui::ViewProviderSketchGeometryExtension::getClassTypeId())) + { + auto vpext = std::static_pointer_cast( + circle->getExtension(SketcherGui::ViewProviderSketchGeometryExtension::getClassTypeId()).lock()); + + scalefactor = vpext->getRepresentationFactor(); + } + + radius = circle->getRadius()*scalefactor; + } + else { radius = circle->getRadius(); + } double angle = (double) Constr->LabelPosition; if (angle == 10) { diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketchGeometryExtension.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketchGeometryExtension.cpp new file mode 100644 index 0000000000..e11c4db0a5 --- /dev/null +++ b/src/Mod/Sketcher/Gui/ViewProviderSketchGeometryExtension.cpp @@ -0,0 +1,79 @@ +/*************************************************************************** + * Copyright (c) 2019 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 * + * * + ***************************************************************************/ + +#include "PreCompiled.h" + +#include +#include +#include + +#include "ViewProviderSketchGeometryExtension.h" + +using namespace SketcherGui; + +//---------- Geometry Extension +TYPESYSTEM_SOURCE(SketcherGui::ViewProviderSketchGeometryExtension,Part::GeometryExtension) + + +ViewProviderSketchGeometryExtension::ViewProviderSketchGeometryExtension():RepresentationFactor(1.0) +{ + +} + + +// Persistence implementer +unsigned int ViewProviderSketchGeometryExtension::getMemSize (void) const +{ + return sizeof(double); +} + +void ViewProviderSketchGeometryExtension::Save(Base::Writer &writer) const +{ + (void) writer; + // So far only intended for runtime +} + +void ViewProviderSketchGeometryExtension::Restore(Base::XMLReader &reader) +{ + (void) reader; + // So far only intended for runtime +} + +std::unique_ptr ViewProviderSketchGeometryExtension::copy(void) const +{ + auto cpy = std::make_unique(); + + cpy->RepresentationFactor = this->RepresentationFactor; + + cpy->setName(this->getName()); // Base Class + +#if defined (__GNUC__) && (__GNUC__ <=4) + return std::move(cpy); +#else + return cpy; +#endif +} + +PyObject * ViewProviderSketchGeometryExtension::getPyObject(void) +{ + THROWM(Base::NotImplementedError, "ViewProviderSketchGeometryExtension does not have a Python counterpart"); +} diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketchGeometryExtension.h b/src/Mod/Sketcher/Gui/ViewProviderSketchGeometryExtension.h new file mode 100644 index 0000000000..21e91a7fd7 --- /dev/null +++ b/src/Mod/Sketcher/Gui/ViewProviderSketchGeometryExtension.h @@ -0,0 +1,68 @@ +/*************************************************************************** + * Copyright (c) 2020 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 SKETCHER_VIEWPROVIDERSKETCHGEOMETRYEXTENSION_H +#define SKETCHER_VIEWPROVIDERSKETCHGEOMETRYEXTENSION_H + +#include + +namespace SketcherGui { + +class SketcherGuiExport ViewProviderSketchGeometryExtension : public Part::GeometryExtension +{ + TYPESYSTEM_HEADER_WITH_OVERRIDE(); +public: + + ViewProviderSketchGeometryExtension(); + virtual ~ViewProviderSketchGeometryExtension() override = default; + + // Persistence implementer --------------------- + virtual unsigned int getMemSize(void) const override; + virtual void Save(Base::Writer &/*writer*/) const override; + virtual void Restore(Base::XMLReader &/*reader*/) override; + + virtual std::unique_ptr copy(void) const override; + + virtual PyObject *getPyObject(void) override; + + // Data Members + + // Representation factor + // Provides a mechanism to store a factor associated with the representation of a geometry + // This is only useful when a geometry must be scaled only for representation, while keeping its value + // Applicability: General abstract concepts embodied in a geometry, in practice B-Spline poles. + // Why not in SketchGeometryExtension? Because it is merely representation related. It has no place in + // a console application. + virtual double getRepresentationFactor() const {return RepresentationFactor;} + virtual void setRepresentationFactor(double representationFactor) {RepresentationFactor = representationFactor;} + +private: + ViewProviderSketchGeometryExtension(const ViewProviderSketchGeometryExtension&) = default; + +private: + double RepresentationFactor; +}; + +} //namespace SketcherGui + + +#endif // SKETCHER_VIEWPROVIDERSKETCHGEOMETRYEXTENSION_H