From 95c1a262b71887084e520ea1f4475e1f649dea6a Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Wed, 25 Nov 2020 14:27:27 +0100 Subject: [PATCH] Sketcher: Unit independent pole weight for B-Splines (Weight constraint) ======================================================================== Until now BSpline poles were circles relying on physical length units. This lead to several problems: - While the BSpline weight follows the circle size, weights do not have length units, but are adimensinal - As representation of the BSpline depends on the physical size of the circle, the numerical value to be set to a pole circle differs from the numerical value of the weight. The present commit: 1. Separates pole circle representation (physical size), from the numerical value used in the radius constraint, so that the value in the constraint is the weight, the value representation is a factor of the weight value (in this commit is getScaleFactor(), but this will change in the next commit). Dragging accounts for this scale factor too. 2. While Radius constraint button is used to constraint a B-Spline weight as before, this creates a Weight constraint, which is a new type of constraint. This is done so that the value is truly adimensional and is so presented in all kind of editors that rely on the units indicated by the constraint. It is obviously also shown as adimensional (thus without units), in the 3D view and in the datum dialogs. 3. Because the circle of the pole of a B-Spline is not a geometric circle, but a graphical representation of the pole and how it affects the corresponding B-Spline, constraint creation commands are limited so that no point on object, tangent, perpendicular or SnellLaw constraints can be created on a B-Spline weight circle. This is also the case for the Diameter constraint, which won't accept the circle. Equality constraints work either on only circles or only weights, but not on a mixture of them. Bonus: This commit fixes a bug in master, that using the select equality constraint then click in two geometric elements mode, you could make a circle equal to an ellipse resulting in malformed solver constraints. --- src/Mod/Sketcher/App/Constraint.cpp | 1 + src/Mod/Sketcher/App/Constraint.h | 3 +- src/Mod/Sketcher/App/ConstraintPyImp.cpp | 9 + src/Mod/Sketcher/App/Sketch.cpp | 13 + src/Mod/Sketcher/App/SketchObject.cpp | 56 ++-- src/Mod/Sketcher/Gui/CommandConstraints.cpp | 270 ++++++++++++++++-- src/Mod/Sketcher/Gui/CommandConstraints.h | 4 + src/Mod/Sketcher/Gui/CommandCreateGeo.cpp | 25 +- src/Mod/Sketcher/Gui/EditDatumDialog.cpp | 14 +- .../Sketcher/Gui/TaskSketcherConstrains.cpp | 4 + src/Mod/Sketcher/Gui/ViewProviderSketch.cpp | 130 ++++++++- 11 files changed, 444 insertions(+), 85 deletions(-) diff --git a/src/Mod/Sketcher/App/Constraint.cpp b/src/Mod/Sketcher/App/Constraint.cpp index 20c1b28dca..1b00d25061 100644 --- a/src/Mod/Sketcher/App/Constraint.cpp +++ b/src/Mod/Sketcher/App/Constraint.cpp @@ -126,6 +126,7 @@ Quantity Constraint::getPresentationValue() const quantity.setUnit(Unit::Angle); break; case SnellsLaw: + case Weight: quantity.setValue(Value); break; default: diff --git a/src/Mod/Sketcher/App/Constraint.h b/src/Mod/Sketcher/App/Constraint.h index b8ee2a2ac3..7a3316b08a 100644 --- a/src/Mod/Sketcher/App/Constraint.h +++ b/src/Mod/Sketcher/App/Constraint.h @@ -57,6 +57,7 @@ enum ConstraintType { SnellsLaw = 16, Block = 17, Diameter = 18, + Weight = 19, NumConstraintTypes // must be the last item! }; @@ -117,7 +118,7 @@ public: inline bool isDimensional() const { return Type == Distance || Type == DistanceX || Type == DistanceY || - Type == Radius || Type == Diameter || Type == Angle || Type == SnellsLaw; + Type == Radius || Type == Diameter || Type == Angle || Type == SnellsLaw || Type == Weight; } friend class PropertyConstraintList; diff --git a/src/Mod/Sketcher/App/ConstraintPyImp.cpp b/src/Mod/Sketcher/App/ConstraintPyImp.cpp index 03204f4aca..cafa0019e0 100644 --- a/src/Mod/Sketcher/App/ConstraintPyImp.cpp +++ b/src/Mod/Sketcher/App/ConstraintPyImp.cpp @@ -169,6 +169,13 @@ int ConstraintPy::PyInit(PyObject* args, PyObject* /*kwd*/) this->getConstraintPtr()->LabelPosition = 10; valid = true; } + else if (strcmp("Weight",ConstraintType) == 0) { + this->getConstraintPtr()->Type = Weight; + // set a value that is out of range of result of atan2 + // this value is handled in ViewProviderSketch + this->getConstraintPtr()->LabelPosition = 10; + valid = true; + } if (valid) { this->getConstraintPtr()->First = FirstIndex; this->getConstraintPtr()->setValue(Value); @@ -503,6 +510,7 @@ std::string ConstraintPy::representation(void) const case Block : result << "'Block' (" << getConstraintPtr()->First << ")>";break; case Radius : result << "'Radius'>";break; case Diameter : result << "'Diameter'>";break; + case Weight : result << "'Weight'>";break; case Parallel : result << "'Parallel'>";break; case Tangent : if (this->getConstraintPtr()->Third == Constraint::GeoUndef) @@ -554,6 +562,7 @@ Py::String ConstraintPy::getType(void) const case Block : return Py::String("Block");break; case Radius : return Py::String("Radius");break; case Diameter : return Py::String("Diameter");break; + case Weight : return Py::String("Weight");break; case Parallel : return Py::String("Parallel");break; case Tangent : return Py::String("Tangent");break; case Perpendicular : return Py::String("Perpendicular");break; diff --git a/src/Mod/Sketcher/App/Sketch.cpp b/src/Mod/Sketcher/App/Sketch.cpp index cb22c78d9e..bb5b7d18a4 100644 --- a/src/Mod/Sketcher/App/Sketch.cpp +++ b/src/Mod/Sketcher/App/Sketch.cpp @@ -1406,6 +1406,19 @@ int Sketch::addConstraint(const Constraint *constraint) rtn = addDiameterConstraint(constraint->First, c.value,c.driving); break; } + case Weight: + { + c.value = new double(constraint->getValue()); + if(c.driving) + FixParameters.push_back(c.value); + else { + Parameters.push_back(c.value); + DrivenParameters.push_back(c.value); + } + + rtn = addRadiusConstraint(constraint->First, c.value,c.driving); + break; + } case Equal: rtn = addEqualConstraint(constraint->First,constraint->Second); break; diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index 448e618b76..33e18229ac 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -327,7 +327,7 @@ int SketchObject::setDatum(int ConstrId, double Datum) type != Perpendicular) return -1; - if ((type == Distance || type == Radius || type == Diameter) && Datum <= 0) + if ((type == Distance || type == Radius || type == Diameter || type == Weight) && Datum <= 0) return (Datum == 0) ? -5 : -4; // copy the list @@ -1243,6 +1243,9 @@ void SketchObject::addGeometryState(const Constraint* cstr) const { auto gf = GeometryFacade::getFacade(vals[cstr->First]); gf->setInternalType(InternalType::BSplineControlPoint); + + // handle constraint as adimensional + break; } case BSplineKnotPoint: @@ -3839,6 +3842,7 @@ int SketchObject::addSymmetric(const std::vector &geoIdList, int refGeoId, (*it)->Type == Sketcher::Equal || (*it)->Type == Sketcher::Radius || (*it)->Type == Sketcher::Diameter || + (*it)->Type == Sketcher::Weight || (*it)->Type == Sketcher::Angle || (*it)->Type == Sketcher::PointOnObject ){ Constraint *constNew = (*it)->copy(); @@ -4133,9 +4137,10 @@ int SketchObject::addCopy(const std::vector &geoIdList, const Base::Vector3 if( ((*it)->Type != Sketcher::DistanceX && (*it)->Type != Sketcher::DistanceY ) || (*it)->FirstPos == Sketcher::none ) { // if it is not a point locking DistanceX/Y if (((*it)->Type == Sketcher::DistanceX || - (*it)->Type == Sketcher::DistanceY || - (*it)->Type == Sketcher::Distance || - (*it)->Type == Sketcher::Diameter || + (*it)->Type == Sketcher::DistanceY || + (*it)->Type == Sketcher::Distance || + (*it)->Type == Sketcher::Diameter || + (*it)->Type == Sketcher::Weight || (*it)->Type == Sketcher::Radius ) && clone ) { // Distances on a single Element are mapped to equality constraints in clone mode Constraint *constNew = (*it)->copy(); @@ -4831,12 +4836,9 @@ int SketchObject::exposeInternalGeometry(int GeoId) // search for first pole weight constraint for (std::vector< Sketcher::Constraint * >::const_iterator it= vals.begin(); it != vals.end(); ++it) { - if((*it)->Type == Sketcher::Radius && (*it)->First == controlpointgeoids[0]) { + if((*it)->Type == Sketcher::Weight && (*it)->First == controlpointgeoids[0]) { isfirstweightconstrained = true ; } - else if((*it)->Type == Sketcher::Diameter && (*it)->First == controlpointgeoids[0]) { - isfirstweightconstrained = true ; - } } } @@ -5218,8 +5220,8 @@ int SketchObject::deleteUnusedInternalGeometry(int GeoId, bool delgeoid) } } - // ignore radii and diameters - else if (((*itc)->Type!=Sketcher::Radius && (*itc)->Type!=Sketcher::Diameter) && ( (*itc)->Second == (*it) || (*itc)->First == (*it) || (*itc)->Third == (*it)) ) { + // ignore weight constraints + else if (((*itc)->Type!=Sketcher::Weight) && ( (*itc)->Second == (*it) || (*itc)->First == (*it) || (*itc)->Third == (*it)) ) { (*ita)++; } } @@ -5756,6 +5758,7 @@ int SketchObject::carbonCopy(App::DocumentObject * pObj, bool construction) if ((*it)->Type == Sketcher::Distance || (*it)->Type == Sketcher::Radius || (*it)->Type == Sketcher::Diameter || + (*it)->Type == Sketcher::Weight || (*it)->Type == Sketcher::Angle || (*it)->Type == Sketcher::SnellsLaw || (*it)->Type == Sketcher::DistanceX || @@ -7067,6 +7070,7 @@ bool SketchObject::evaluateConstraint(const Constraint *constraint) const switch (constraint->Type) { case Radius: case Diameter: + case Weight: case Horizontal: case Vertical: case Distance: @@ -7487,16 +7491,39 @@ void SketchObject::restoreFinished() void SketchObject::migrateSketch(void) { - bool updateGeoState = false; + bool noextensions = false; for( const auto & g : getInternalGeometry() ) if(!g->hasExtension(SketchGeometryExtension::getClassTypeId())) // no extension - legacy file - updateGeoState = true; + noextensions = true; - if(updateGeoState) { + if(noextensions) { for( auto c : Constraints.getValues()) { addGeometryState(c); + + // Convert B-Spline controlpoints radius/diameter constraints to Weight cosntraints + if(c->Type == InternalAlignment && c->AlignmentType == BSplineControlPoint) { + int circlegeoid = c->First; + int bsplinegeoid = c->Second; + + auto bsp = static_cast(getGeometry(bsplinegeoid)); + + std::vector weights = bsp->getWeights(); + + for( auto ccp : Constraints.getValues()) { + + if( (ccp->Type == Radius || ccp->Type == Diameter ) && + ccp->First == circlegeoid ) { + + if(c->InternalAlignmentIndex < int(weights.size())) { + ccp->Type = Weight; + ccp->setValue(weights[c->InternalAlignmentIndex]); + + } + } + } + } } } } @@ -7912,9 +7939,6 @@ int SketchObject::getGeometryId(int GeoId, long &id) const return 0; } - - - // Python Sketcher feature --------------------------------------------------------- namespace App { diff --git a/src/Mod/Sketcher/Gui/CommandConstraints.cpp b/src/Mod/Sketcher/Gui/CommandConstraints.cpp index 2dab96b05b..202b1d6068 100644 --- a/src/Mod/Sketcher/Gui/CommandConstraints.cpp +++ b/src/Mod/Sketcher/Gui/CommandConstraints.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #include "ViewProviderSketch.h" #include "DrawSketchHandler.h" @@ -255,6 +256,20 @@ bool SketcherGui::IsPointAlreadyOnCurve(int GeoIdCurve, int GeoIdPoint, Sketcher return Obj->isPointOnCurve(GeoIdCurve, p.x, p.y); } +bool SketcherGui::isBsplinePole(const Part::Geometry * geo) +{ + auto gf = GeometryFacade::getFacade(geo); + + return gf->getInternalType() == InternalType::BSplineControlPoint; +} + +bool SketcherGui::isBsplinePole(const Sketcher::SketchObject* Obj, int GeoId) +{ + auto geom = Obj->getGeometry(GeoId); + + return isBsplinePole(geom); +} + bool SketcherGui::ReleaseHandler(Gui::Document* doc) { if (doc) { if (doc->getInEdit() && doc->getInEdit()->isDerivedFrom(SketcherGui::ViewProviderSketch::getClassTypeId())) { @@ -2655,6 +2670,14 @@ void CmdSketcherConstrainPointOnObject::activated(int iMsg) continue; } + if( geom && isBsplinePole(geom)) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select an edge that is not a B-spline weight")); + abortCommand(); + + continue; + } + cnt++; Gui::cmdAppObjectArgs(selection[0].getObject(),"addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ", points[iPnt].GeoId, points[iPnt].PosId, curves[iCrv].GeoId); @@ -2668,9 +2691,10 @@ void CmdSketcherConstrainPointOnObject::activated(int iMsg) QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("None of the selected points were constrained " "onto the respective curves, " - "either because they are parts " + "because they are parts " "of the same element, " - "or because they are both external geometry.")); + "because they are both external geometry, " + "or because the edge is not eligible.")); } return; } @@ -2730,6 +2754,14 @@ void CmdSketcherConstrainPointOnObject::applyConstraint(std::vector & return; } + if( geom && isBsplinePole(geom)) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select an edge that is not a B-spline weight")); + abortCommand(); + + return; + } + if (allOK) { Gui::cmdAppObjectArgs(sketchgui->getObject(), "addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ", GeoIdVt, PosIdVt, GeoIdCrv); @@ -3508,6 +3540,12 @@ void CmdSketcherConstrainPerpendicular::activated(int iMsg) if (isEdge(GeoId1, PosId1) && isEdge(GeoId2, PosId2) && isVertex(GeoId3, PosId3)) { + if(isBsplinePole(Obj, GeoId1) || isBsplinePole(Obj, GeoId2)) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select an edge that is not a B-spline weight")); + return; + } + openCommand(QT_TRANSLATE_NOOP("Command", "Add perpendicular constraint")); try{ @@ -3607,6 +3645,12 @@ void CmdSketcherConstrainPerpendicular::activated(int iMsg) return; } + if(isBsplinePole(geom2)) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select an edge that is not a B-spline weight")); + return; + } + openCommand(QT_TRANSLATE_NOOP("Command", "Add perpendicularity constraint")); Gui::cmdAppObjectArgs(selection[0].getObject(), "addConstraint(Sketcher.Constraint('Perpendicular',%d,%d,%d)) ", GeoId1,PosId1,GeoId2); @@ -3643,6 +3687,12 @@ void CmdSketcherConstrainPerpendicular::activated(int iMsg) if (geo1->getTypeId() == Part::GeomLineSegment::getClassTypeId()) std::swap(GeoId1,GeoId2); + if(isBsplinePole(Obj, GeoId1)) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select an edge that is not a B-spline weight")); + return; + } + // GeoId2 is the line geo1 = Obj->getGeometry(GeoId1); geo2 = Obj->getGeometry(GeoId2); @@ -3818,6 +3868,12 @@ void CmdSketcherConstrainPerpendicular::applyConstraint(std::vector & if (geo1->getTypeId() == Part::GeomLineSegment::getClassTypeId()) std::swap(GeoId1,GeoId2); + if(isBsplinePole(Obj, GeoId1)) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select an edge that is not a B-spline weight")); + return; + } + // GeoId2 is the line geo1 = Obj->getGeometry(GeoId1); geo2 = Obj->getGeometry(GeoId2); @@ -3963,6 +4019,12 @@ void CmdSketcherConstrainPerpendicular::applyConstraint(std::vector & if (isEdge(GeoId1, PosId1) && isEdge(GeoId2, PosId2) && isVertex(GeoId3, PosId3)) { + if(isBsplinePole(Obj, GeoId1) || isBsplinePole(Obj, GeoId2)) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select an edge that is not a B-spline weight")); + return; + } + openCommand(QT_TRANSLATE_NOOP("Command", "Add perpendicular constraint")); try{ @@ -4112,6 +4174,12 @@ void CmdSketcherConstrainTangent::activated(int iMsg) if (isEdge(GeoId1, PosId1) && isEdge(GeoId2, PosId2) && isVertex(GeoId3, PosId3)) { + if(isBsplinePole(Obj, GeoId1) || isBsplinePole(Obj, GeoId2)) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select an edge that is not a B-spline weight")); + return; + } + openCommand(QT_TRANSLATE_NOOP("Command", "Add tangent constraint")); try{ @@ -4194,6 +4262,12 @@ void CmdSketcherConstrainTangent::activated(int iMsg) return; } + if(isBsplinePole(geom2)) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select an edge that is not a B-spline weight")); + return; + } + openCommand(QT_TRANSLATE_NOOP("Command", "Add tangent constraint")); Gui::cmdAppObjectArgs(selection[0].getObject(), "addConstraint(Sketcher.Constraint('Tangent',%d,%d,%d)) ", GeoId1,PosId1,GeoId2); @@ -4218,6 +4292,11 @@ void CmdSketcherConstrainTangent::activated(int iMsg) return; } + if(isBsplinePole(geom1) || isBsplinePole(geom2)) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select an edge that is not a B-spline weight")); + return; + } // check if there is a coincidence constraint on GeoId1, GeoId2 const std::vector< Constraint * > &cvals = Obj->Constraints.getValues(); @@ -4437,6 +4516,12 @@ void CmdSketcherConstrainTangent::applyConstraint(std::vector &selSeq return; } + if(isBsplinePole(geom1) || isBsplinePole(geom2)) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select an edge that is not a B-spline weight")); + return; + } + if( geom1 && geom2 && ( geom1->getTypeId() == Part::GeomEllipse::getClassTypeId() || @@ -4606,6 +4691,12 @@ void CmdSketcherConstrainTangent::applyConstraint(std::vector &selSeq if (isEdge(GeoId1, PosId1) && isEdge(GeoId2, PosId2) && isVertex(GeoId3, PosId3)) { + if(isBsplinePole(Obj, GeoId1) || isBsplinePole(Obj, GeoId2)) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select an edge that is not a B-spline weight")); + return; + } + openCommand(QT_TRANSLATE_NOOP("Command", "Add tangent constraint")); try{ @@ -4667,8 +4758,8 @@ CmdSketcherConstrainRadius::CmdSketcherConstrainRadius() { sAppModule = "Sketcher"; sGroup = QT_TR_NOOP("Sketcher"); - sMenuText = QT_TR_NOOP("Constrain radius"); - sToolTipText = QT_TR_NOOP("Fix the radius of a circle or an arc"); + sMenuText = QT_TR_NOOP("Constrain radius or weight"); + sToolTipText = QT_TR_NOOP("Fix the radius of a circle or an arc or fix the weight of a pole of a B-Spline"); sWhatsThis = "Sketcher_ConstrainRadius"; sStatusTip = sToolTipText; sPixmap = "Constraint_Radius"; @@ -4715,6 +4806,9 @@ void CmdSketcherConstrainRadius::activated(int iMsg) std::vector< std::pair > geoIdRadiusMap; std::vector< std::pair > externalGeoIdRadiusMap; + bool poles = false; + bool nonpoles = false; + for (std::vector::const_iterator it = SubNames.begin(); it != SubNames.end(); ++it) { bool issegmentfixed = false; int GeoId; @@ -4742,6 +4836,8 @@ void CmdSketcherConstrainRadius::activated(int iMsg) else { geoIdRadiusMap.push_back(std::make_pair(GeoId, radius)); } + + nonpoles = true; } else if (geom && geom->getTypeId() == Part::GeomCircle::getClassTypeId()) { const Part::GeomCircle *circle = static_cast(geom); @@ -4753,6 +4849,11 @@ void CmdSketcherConstrainRadius::activated(int iMsg) else { geoIdRadiusMap.push_back(std::make_pair(GeoId, radius)); } + + if(isBsplinePole(geom)) + poles = true; + else + nonpoles = true; } } @@ -4761,6 +4862,12 @@ void CmdSketcherConstrainRadius::activated(int iMsg) QObject::tr("Select one or more arcs or circles from the sketch.")); } + if(poles && nonpoles) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select either only one or more B-Spline poles or only one or more arcs or circles from the sketch, but not mixed.")); + return; + } + bool commitNeeded=false; bool updateNeeded=false; bool commandopened=false; @@ -4772,8 +4879,13 @@ void CmdSketcherConstrainRadius::activated(int iMsg) unsigned int constrSize = 0; for (std::vector< std::pair >::iterator it = externalGeoIdRadiusMap.begin(); it != externalGeoIdRadiusMap.end(); ++it) { - Gui::cmdAppObjectArgs(selection[0].getObject(),"addConstraint(Sketcher.Constraint('Radius',%d,%f)) ", - it->first,it->second); + + if(nonpoles) + Gui::cmdAppObjectArgs(selection[0].getObject(),"addConstraint(Sketcher.Constraint('Radius',%d,%f)) ", + it->first,it->second); + else + Gui::cmdAppObjectArgs(selection[0].getObject(),"addConstraint(Sketcher.Constraint('Weight',%d,%f)) ", + it->first,it->second); const std::vector &ConStr = Obj->Constraints.getValues(); @@ -4829,8 +4941,12 @@ void CmdSketcherConstrainRadius::activated(int iMsg) if(!commandopened) openCommand(QT_TRANSLATE_NOOP("Command", "Add radius constraint")); - Gui::cmdAppObjectArgs(selection[0].getObject(), "addConstraint(Sketcher.Constraint('Radius',%d,%f)) ", - refGeoId,radius); + if(nonpoles) + Gui::cmdAppObjectArgs(selection[0].getObject(), "addConstraint(Sketcher.Constraint('Radius',%d,%f)) ", + refGeoId,radius); + else + Gui::cmdAppObjectArgs(selection[0].getObject(), "addConstraint(Sketcher.Constraint('Weight',%d,%f)) ", + refGeoId,radius); // Add the equality constraints for (std::vector< std::pair >::iterator it = geoIdRadiusMap.begin()+1; it != geoIdRadiusMap.end(); ++it) { @@ -4844,8 +4960,12 @@ void CmdSketcherConstrainRadius::activated(int iMsg) if(!commandopened) openCommand(QT_TRANSLATE_NOOP("Command", "Add radius constraint")); for (std::vector< std::pair >::iterator it = geoIdRadiusMap.begin(); it != geoIdRadiusMap.end(); ++it) { - Gui::cmdAppObjectArgs(selection[0].getObject(), "addConstraint(Sketcher.Constraint('Radius',%d,%f)) ", - it->first,it->second); + if(nonpoles) + Gui::cmdAppObjectArgs(selection[0].getObject(), "addConstraint(Sketcher.Constraint('Radius',%d,%f)) ", + it->first,it->second); + else + Gui::cmdAppObjectArgs(selection[0].getObject(), "addConstraint(Sketcher.Constraint('Weight',%d,%f)) ", + it->first,it->second); if (constraintCreationMode==Reference) { const std::vector &ConStr = Obj->Constraints.getValues(); @@ -4878,12 +4998,20 @@ void CmdSketcherConstrainRadius::activated(int iMsg) QDialog dlg(Gui::getMainWindow()); Ui::InsertDatum ui_Datum; ui_Datum.setupUi(&dlg); - dlg.setWindowTitle(EditDatumDialog::tr("Change radius")); - ui_Datum.label->setText(EditDatumDialog::tr("Radius:")); Base::Quantity init_val; - init_val.setUnit(Base::Unit::Length); init_val.setValue(geoIdRadiusMap.front().second); + if(poles) { + dlg.setWindowTitle(EditDatumDialog::tr("Change weight")); + ui_Datum.label->setText(EditDatumDialog::tr("Weight:")); + + } + else{ + dlg.setWindowTitle(EditDatumDialog::tr("Change radius")); + ui_Datum.label->setText(EditDatumDialog::tr("Radius:")); + init_val.setUnit(Base::Unit::Length); + } + ui_Datum.labelEdit->setValue(init_val); ui_Datum.labelEdit->selectNumber(); if (constrainEqual || geoIdRadiusMap.size() == 1) @@ -4989,7 +5117,14 @@ void CmdSketcherConstrainRadius::applyConstraint(std::vector &selSeq, // Create the radius constraint now openCommand(QT_TRANSLATE_NOOP("Command", "Add radius constraint")); - Gui::cmdAppObjectArgs(Obj, "addConstraint(Sketcher.Constraint('Radius',%d,%f)) ", + + bool ispole = isBsplinePole(geom); + + if(ispole) + Gui::cmdAppObjectArgs(Obj, "addConstraint(Sketcher.Constraint('Weight',%d,%f)) ", + GeoId, radius); + else + Gui::cmdAppObjectArgs(Obj, "addConstraint(Sketcher.Constraint('Radius',%d,%f)) ", GeoId, radius); const std::vector &ConStr = Obj->Constraints.getValues(); @@ -5022,10 +5157,19 @@ void CmdSketcherConstrainRadius::applyConstraint(std::vector &selSeq, QDialog dlg(Gui::getMainWindow()); Ui::InsertDatum ui_Datum; ui_Datum.setupUi(&dlg); - dlg.setWindowTitle(EditDatumDialog::tr("Change radius")); - ui_Datum.label->setText(EditDatumDialog::tr("Radius:")); Base::Quantity init_val; - init_val.setUnit(Base::Unit::Length); + + if(ispole) { + dlg.setWindowTitle(EditDatumDialog::tr("Change weight")); + ui_Datum.label->setText(EditDatumDialog::tr("Weight:")); + + } + else{ + dlg.setWindowTitle(EditDatumDialog::tr("Change radius")); + ui_Datum.label->setText(EditDatumDialog::tr("Radius:")); + init_val.setUnit(Base::Unit::Length); + } + init_val.setValue(radius); ui_Datum.labelEdit->setValue(init_val); @@ -5205,6 +5349,12 @@ void CmdSketcherConstrainDiameter::activated(int iMsg) const Part::GeomCircle *circle = static_cast(geom); double radius = circle->getRadius(); + if(isBsplinePole(geom)) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select an edge that is not a B-spline weight")); + continue; + } + if(issegmentfixed) { externalGeoIdDiameterMap.push_back(std::make_pair(GeoId, 2*radius)); } @@ -5444,6 +5594,12 @@ void CmdSketcherConstrainDiameter::applyConstraint(std::vector &selSe return; } + if(isBsplinePole(geom)) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select an edge that is not a B-spline weight")); + return; + } + // Create the diameter constraint now openCommand(QT_TRANSLATE_NOOP("Command", "Add diameter constraint")); Gui::cmdAppObjectArgs(Obj, "addConstraint(Sketcher.Constraint('Diameter',%d,%f)) ", @@ -5768,6 +5924,13 @@ void CmdSketcherConstrainAngle::activated(int iMsg) bool bothexternal=areBothPointsOrSegmentsFixed(Obj, GeoId1, GeoId2); if (isEdge(GeoId1, PosId1) && isEdge(GeoId2, PosId2) && isVertex(GeoId3, PosId3)) { + + if(isBsplinePole(Obj, GeoId1) || isBsplinePole(Obj, GeoId2)) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select an edge that is not a B-spline weight")); + return; + } + double ActAngle = 0.0; openCommand(QT_TRANSLATE_NOOP("Command", "Add angle constraint")); @@ -5824,6 +5987,12 @@ void CmdSketcherConstrainAngle::activated(int iMsg) std::swap(PosId1,PosId2); } + if(isBsplinePole(Obj, GeoId1) || isBsplinePole(Obj, GeoId2)) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select an edge that is not a B-spline weight")); + return; + } + if (isEdge(GeoId2,PosId2)) { // line to line angle const Part::Geometry *geom1 = Obj->getGeometry(GeoId1); @@ -6109,6 +6278,13 @@ void CmdSketcherConstrainAngle::applyConstraint(std::vector &selSeq, bool bothexternal=areBothPointsOrSegmentsFixed(Obj,GeoId1, GeoId2); if (isEdge(GeoId1, PosId1) && isEdge(GeoId2, PosId2) && isVertex(GeoId3, PosId3)) { + + if(isBsplinePole(Obj, GeoId1) || isBsplinePole(Obj, GeoId2)) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select an edge that is not a B-spline weight")); + return; + } + double ActAngle = 0.0; openCommand(QT_TRANSLATE_NOOP("Command", "Add angle constraint")); @@ -6241,7 +6417,7 @@ void CmdSketcherConstrainEqual::activated(int iMsg) std::vector ids; bool lineSel = false, arcSel = false, circSel = false, ellipsSel = false, arcEllipsSel=false, hasAlreadyExternal = false; - bool hyperbSel = false, parabSel=false; + bool hyperbSel = false, parabSel=false, weightSel=false; for (std::vector::const_iterator it=SubNames.begin(); it != SubNames.end(); ++it) { @@ -6279,20 +6455,30 @@ void CmdSketcherConstrainEqual::activated(int iMsg) return; } - if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) + if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { lineSel = true; - else if (geo->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) + } + else if (geo->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) { arcSel = true; - else if (geo->getTypeId() == Part::GeomCircle::getClassTypeId()) - circSel = true; - else if (geo->getTypeId() == Part::GeomEllipse::getClassTypeId()) + } + else if (geo->getTypeId() == Part::GeomCircle::getClassTypeId()) { + if(isBsplinePole(geo)) + weightSel = true; + else + circSel = true; + } + else if (geo->getTypeId() == Part::GeomEllipse::getClassTypeId()) { ellipsSel = true; - else if (geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) + } + else if (geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) { arcEllipsSel = true; - else if (geo->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId()) + } + else if (geo->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId()) { hyperbSel = true; - else if (geo->getTypeId() == Part::GeomArcOfParabola::getClassTypeId()) + } + else if (geo->getTypeId() == Part::GeomArcOfParabola::getClassTypeId()) { parabSel = true; + } else { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("Select two or more edges of similar type")); @@ -6303,10 +6489,11 @@ void CmdSketcherConstrainEqual::activated(int iMsg) } // Check for heterogeneous groups in selection - if ( (lineSel && ((arcSel || circSel) || (ellipsSel || arcEllipsSel) || hyperbSel || parabSel) ) || - ((arcSel || circSel) && ((ellipsSel || arcEllipsSel) || hyperbSel || parabSel)) || - ((ellipsSel || arcEllipsSel) && (hyperbSel || parabSel)) || - (hyperbSel && parabSel) ) { + if ( (lineSel && ((arcSel || circSel) || (ellipsSel || arcEllipsSel) || hyperbSel || parabSel || weightSel) ) || + ((arcSel || circSel) && ((ellipsSel || arcEllipsSel) || hyperbSel || parabSel || weightSel)) || + ((ellipsSel || arcEllipsSel) && (hyperbSel || parabSel || weightSel)) || + ( hyperbSel && (parabSel || weightSel)) || + ( parabSel && weightSel)) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("Select two or more edges of similar type")); @@ -6348,6 +6535,23 @@ void CmdSketcherConstrainEqual::applyConstraint(std::vector &selSeq, return; } + const Part::Geometry *geo1 = Obj->getGeometry(GeoId1); + const Part::Geometry *geo2 = Obj->getGeometry(GeoId2); + + if ( (geo1->getTypeId() == Part::GeomLineSegment::getClassTypeId() && geo2->getTypeId() != Part::GeomLineSegment::getClassTypeId()) || + (geo1->getTypeId() == Part::GeomHyperbola::getClassTypeId() && geo2->getTypeId() != Part::GeomHyperbola::getClassTypeId()) || + (geo1->getTypeId() == Part::GeomParabola::getClassTypeId() && geo2->getTypeId() != Part::GeomParabola::getClassTypeId()) || + (isBsplinePole(geo1) && !isBsplinePole(geo1)) || + ( (geo1->getTypeId() == Part::GeomCircle::getClassTypeId() || geo1->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) && + (geo2->getTypeId() != Part::GeomCircle::getClassTypeId() || geo2->getTypeId() != Part::GeomArcOfCircle::getClassTypeId())) || + ( (geo1->getTypeId() == Part::GeomEllipse::getClassTypeId() || geo1->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) && + (geo2->getTypeId() != Part::GeomEllipse::getClassTypeId() || geo2->getTypeId() != Part::GeomArcOfEllipse::getClassTypeId())) ){ + + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select two or more edges of similar type")); + return; + } + // undo command open openCommand(QT_TRANSLATE_NOOP("Command", "Add equality constraint")); Gui::cmdAppObjectArgs(Obj, "addConstraint(Sketcher.Constraint('Equal',%d,%d)) ", @@ -6745,6 +6949,12 @@ void CmdSketcherConstrainSnellsLaw::activated(int iMsg) return; } + if(isBsplinePole(geo)) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select an edge that is not a B-spline weight")); + return; + } + double n2divn1=0; //the essence. diff --git a/src/Mod/Sketcher/Gui/CommandConstraints.h b/src/Mod/Sketcher/Gui/CommandConstraints.h index 281872feac..f6a08d3632 100644 --- a/src/Mod/Sketcher/Gui/CommandConstraints.h +++ b/src/Mod/Sketcher/Gui/CommandConstraints.h @@ -51,6 +51,10 @@ bool isConstructionPoint(const Sketcher::SketchObject* Obj, int GeoId); bool IsPointAlreadyOnCurve(int GeoIdCurve, int GeoIdPoint, Sketcher::PointPos PosIdPoint, Sketcher::SketchObject* Obj); +bool isBsplinePole(const Part::Geometry * geo); + +bool isBsplinePole(const Sketcher::SketchObject* Obj, int GeoId); + /// Release any currently-active handler for the document. /// Returns true if a handler was released, and false if not bool ReleaseHandler(Gui::Document* doc); diff --git a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp index 35de045ee8..0a2939e7d8 100644 --- a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp +++ b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp @@ -4134,33 +4134,12 @@ public: //Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Add Pole circle")); //Add pole - double guess = (EditCurve[1]-EditCurve[0]).Length()/6; - - auto normalize = [](double guess) { - double units=1.0; - - while (guess >= 10.0) { - guess /= 10.0; - units*=10.0; - } - - while (guess < 1.0) { - guess *= 10.0; - units/=10.0; - } - - return round(guess)*units; - - }; - - guess = normalize(guess); - Gui::cmdAppObjectArgs(sketchgui->getObject(), "addGeometry(Part.Circle(App.Vector(%f,%f,0),App.Vector(0,0,1),10),True)", EditCurve[EditCurve.size()-1].x,EditCurve[EditCurve.size()-1].y); if(EditCurve.size() == 2) { - Gui::cmdAppObjectArgs(sketchgui->getObject(), "addConstraint(Sketcher.Constraint('Radius',%d,%f)) ", - FirstPoleGeoId, guess ); + Gui::cmdAppObjectArgs(sketchgui->getObject(), "addConstraint(Sketcher.Constraint('Weight',%d,%f)) ", + FirstPoleGeoId, 1.0 ); // First pole defaults to 1.0 weight } Gui::cmdAppObjectArgs(sketchgui->getObject(), "addConstraint(Sketcher.Constraint('Equal',%d,%d)) ", diff --git a/src/Mod/Sketcher/Gui/EditDatumDialog.cpp b/src/Mod/Sketcher/Gui/EditDatumDialog.cpp index 89a54d5e15..21ba1729bf 100644 --- a/src/Mod/Sketcher/Gui/EditDatumDialog.cpp +++ b/src/Mod/Sketcher/Gui/EditDatumDialog.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include "ViewProviderSketch.h" #include "ui_InsertDatum.h" @@ -81,13 +82,14 @@ void EditDatumDialog::exec(bool atCursor) return; } + Base::Quantity init_val; + QDialog dlg(Gui::getMainWindow()); if (ui_ins_datum == nullptr) { ui_ins_datum.reset(new Ui_InsertDatum); ui_ins_datum->setupUi(&dlg); } double datum = Constr->getValue(); - Base::Quantity init_val; if (Constr->Type == Sketcher::Angle) { datum = Base::toDegrees(datum); @@ -108,6 +110,11 @@ void EditDatumDialog::exec(bool atCursor) ui_ins_datum->label->setText(tr("Diameter:")); ui_ins_datum->labelEdit->setParamGrpPath(QByteArray("User parameter:BaseApp/History/SketcherLength")); } + else if (Constr->Type == Sketcher::Weight) { + dlg.setWindowTitle(tr("Insert weight")); + ui_ins_datum->label->setText(tr("Weight:")); + ui_ins_datum->labelEdit->setParamGrpPath(QByteArray("User parameter:BaseApp/History/SketcherWeight")); + } else if (Constr->Type == Sketcher::SnellsLaw) { dlg.setWindowTitle(tr("Refractive index ratio", "Constraint_SnellsLaw")); ui_ins_datum->label->setText(tr("Ratio n2/n1:", "Constraint_SnellsLaw")); @@ -155,7 +162,10 @@ void EditDatumDialog::exec(bool atCursor) void EditDatumDialog::accepted() { Base::Quantity newQuant = ui_ins_datum->labelEdit->value(); - if (newQuant.isQuantity() || (Constr->Type == Sketcher::SnellsLaw && newQuant.isDimensionless())) { + if( newQuant.isQuantity() || + (Constr->Type == Sketcher::SnellsLaw && newQuant.isDimensionless()) || + (Constr->Type == Sketcher::Weight && newQuant.isDimensionless())) { + // save the value for the history ui_ins_datum->labelEdit->pushToHistory(); diff --git a/src/Mod/Sketcher/Gui/TaskSketcherConstrains.cpp b/src/Mod/Sketcher/Gui/TaskSketcherConstrains.cpp index 1e5098366c..72378330df 100644 --- a/src/Mod/Sketcher/Gui/TaskSketcherConstrains.cpp +++ b/src/Mod/Sketcher/Gui/TaskSketcherConstrains.cpp @@ -138,6 +138,7 @@ public: case Sketcher::DistanceX: case Sketcher::DistanceY: case Sketcher::Radius: + case Sketcher::Weight: case Sketcher::Diameter: case Sketcher::Angle: name = QString::fromLatin1("%1 (%2)").arg(name).arg(constraint->getPresentationValue().getUserString()); @@ -257,6 +258,7 @@ public: case Sketcher::DistanceY: return selicon(constraint,vdist,vdist_driven); case Sketcher::Radius: + case Sketcher::Weight: return selicon(constraint,radi,radi_driven); case Sketcher::Diameter: return selicon(constraint,dia,dia_driven); @@ -326,6 +328,7 @@ public: case Sketcher::DistanceY: case Sketcher::Radius: case Sketcher::Diameter: + case Sketcher::Weight: case Sketcher::Angle: case Sketcher::SnellsLaw: return ( constraint->First >= 0 || constraint->Second >= 0 || constraint->Third >= 0 ); @@ -945,6 +948,7 @@ void TaskSketcherConstrains::slotConstraintsChanged(void) case Sketcher::DistanceX: case Sketcher::DistanceY: case Sketcher::Radius: + case Sketcher::Weight: case Sketcher::Diameter: case Sketcher::Angle: case Sketcher::SnellsLaw: diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp index 178cfb0452..89a910b53c 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp @@ -842,9 +842,29 @@ bool ViewProviderSketch::mouseButtonPressed(int Button, bool pressed, const SbVe geo->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId()|| geo->getTypeId() == Part::GeomBSplineCurve::getClassTypeId()) { getDocument()->openCommand(QT_TRANSLATE_NOOP("Command", "Drag Curve")); + + auto geo = getSketchObject()->getGeometry(edit->DragCurve); + auto gf = GeometryFacade::getFacade(geo); + + 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 + // + // This code normalizes the information sent to the solver. + if(gf->getInternalType() == InternalType::BSplineControlPoint) { + auto circle = static_cast(geo); + Base::Vector3d center = circle->getCenter(); + + Base::Vector3d dir = vec - center; + + vec = center - dir / getScaleFactor(); + } + try { Gui::cmdAppObjectArgs(getObject(), "movePoint(%i,%i,App.Vector(%f,%f,0),%i)" - ,edit->DragCurve, Sketcher::none, x-xInit, y-yInit, relative ? 1 : 0); + ,edit->DragCurve, Sketcher::none, vec.x, vec.y, relative ? 1 : 0); getDocument()->commitCommand(); tryAutoRecomputeIfNotSolve(getSketchObject()); @@ -1133,7 +1153,7 @@ bool ViewProviderSketch::mouseMove(const SbVec2s &cursorPos, Gui::View3DInventor getSketchObject()->getSolvedSketch().initMove(edit->DragCurve, Sketcher::none, false); const Part::Geometry *geo = getSketchObject()->getGeometry(edit->DragCurve); if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId() || - geo->getTypeId() == Part::GeomBSplineCurve::getClassTypeId() ) { + geo->getTypeId() == Part::GeomBSplineCurve::getClassTypeId()) { relative = true; //xInit = x; //yInit = y; @@ -1185,7 +1205,25 @@ bool ViewProviderSketch::mouseMove(const SbVec2s &cursorPos, Gui::View3DInventor return true; case STATUS_SKETCH_DragCurve: if (edit->DragCurve != -1) { + auto geo = getSketchObject()->getGeometry(edit->DragCurve); + auto gf = GeometryFacade::getFacade(geo); + 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 + // + // This code normalizes the information sent to the solver. + if(gf->getInternalType() == InternalType::BSplineControlPoint) { + auto circle = static_cast(geo); + Base::Vector3d center = circle->getCenter(); + + Base::Vector3d dir = vec - center; + + vec = center - dir / getScaleFactor(); + } + if (getSketchObject()->getSolvedSketch().movePoint(edit->DragCurve, Sketcher::none, vec, relative) == 0) { setPositionText(Base::Vector2d(x,y)); draw(true,false); @@ -1261,7 +1299,7 @@ void ViewProviderSketch::moveConstraint(int constNum, const Base::Vector2d &toPo #endif if (Constr->Type == Distance || Constr->Type == DistanceX || Constr->Type == DistanceY || - Constr->Type == Radius || Constr->Type == Diameter) { + Constr->Type == Radius || Constr->Type == Diameter || Constr-> Type == Weight) { Base::Vector3d p1(0.,0.,0.), p2(0.,0.,0.); if (Constr->SecondPos != Sketcher::none) { // point to point distance @@ -1331,14 +1369,14 @@ void ViewProviderSketch::moveConstraint(int constNum, const Base::Vector2d &toPo Base::Vector3d vec = Base::Vector3d(toPos.x, toPos.y, 0) - p2; Base::Vector3d dir; - if (Constr->Type == Distance || Constr->Type == Radius || Constr->Type == Diameter) + if (Constr->Type == Distance || Constr->Type == Radius || Constr->Type == Diameter || Constr->Type == Weight) dir = (p2-p1).Normalize(); else if (Constr->Type == DistanceX) dir = Base::Vector3d( (p2.x - p1.x >= FLT_EPSILON) ? 1 : -1, 0, 0); else if (Constr->Type == DistanceY) dir = Base::Vector3d(0, (p2.y - p1.y >= FLT_EPSILON) ? 1 : -1, 0); - if (Constr->Type == Radius || Constr->Type == Diameter) { + if (Constr->Type == Radius || Constr->Type == Diameter || Constr->Type == Weight) { Constr->LabelDistance = vec.x * dir.x + vec.y * dir.y; Constr->LabelPosition = atan2(dir.y, dir.x); } else { @@ -2804,6 +2842,7 @@ void ViewProviderSketch::updateColor(void) bool hasDatumLabel = (type == Sketcher::Angle || type == Sketcher::Radius || type == Sketcher::Diameter || + type == Sketcher::Weight || type == Sketcher::Symmetric || type == Sketcher::Distance || type == Sketcher::DistanceX || @@ -3621,18 +3660,69 @@ void ViewProviderSketch::draw(bool temp /*=false*/, bool rebuildinformationlayer else if ((*it)->getTypeId() == Part::GeomCircle::getClassTypeId()) { // add a circle const Part::GeomCircle *circle = static_cast(*it); Handle(Geom_Circle) curve = Handle(Geom_Circle)::DownCast(circle->handle()); + auto gf = GeometryFacade::getFacade(circle); int countSegments = stdcountsegments; Base::Vector3d center = circle->getCenter(); - double segment = (2 * M_PI) / countSegments; - for (int i=0; i < countSegments; i++) { - gp_Pnt pnt = curve->Value(i*segment); + + // 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 + // + // This code draws 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) { + auto bspline = dynamic_cast((*geomlist)[c->Second]); + + if(bspline){ + auto weights = bspline->getWeights(); + + double weight = 1.0; + if(c->InternalAlignmentIndex < int(weights.size())) + weight = weights[c->InternalAlignmentIndex]; + + // 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 vradius = weight*scalefactor; + + // virtual circle or radius vradius + auto mcurve = [¢er, vradius](double param, double &x, double &y) { + x = center.x + vradius*cos(param); + y = center.y + vradius*sin(param); + }; + + double x; + double y; + for (int i=0; i < countSegments; i++) { + double param = 2*M_PI*i/countSegments; + mcurve(param,x,y); + Coords.emplace_back(x, y, 0); + } + + mcurve(0,x,y); + Coords.emplace_back(x, y, 0); + } + break; + } + } + } + else { + + double segment = (2 * M_PI) / countSegments; + + for (int i=0; i < countSegments; i++) { + gp_Pnt pnt = curve->Value(i*segment); + Coords.emplace_back(pnt.X(), pnt.Y(), pnt.Z()); + } + + gp_Pnt pnt = curve->Value(0); Coords.emplace_back(pnt.X(), pnt.Y(), pnt.Z()); } - gp_Pnt pnt = curve->Value(0); - Coords.emplace_back(pnt.X(), pnt.Y(), pnt.Z()); - Index.push_back(countSegments+1); edit->CurvIdToGeoId.push_back(GeoId); Points.push_back(center); @@ -5344,11 +5434,13 @@ Restart: asciiText->pnts.finishEditing(); } break; + case Weight: case Radius: { assert(Constr->First >= -extGeoCount && Constr->First < intGeoCount); Base::Vector3d pnt1(0.,0.,0.), pnt2(0.,0.,0.); + if (Constr->First != Constraint::GeoUndef) { const Part::Geometry *geo = GeoById(*geomlist, Constr->First); @@ -5366,7 +5458,15 @@ Restart: } else if (geo->getTypeId() == Part::GeomCircle::getClassTypeId()) { const Part::GeomCircle *circle = static_cast(geo); - double radius = circle->getRadius(); + auto gf = GeometryFacade::getFacade(geo); + + double radius; + + if(Constr->Type == Weight) + radius = circle->getRadius()*getScaleFactor(); + else + radius = circle->getRadius(); + double angle = (double) Constr->LabelPosition; if (angle == 10) { angle = 0; @@ -5385,7 +5485,10 @@ Restart: SoDatumLabel *asciiText = static_cast(sep->getChild(CONSTRAINT_SEPARATOR_INDEX_MATERIAL_OR_DATUMLABEL)); // Get display string with units hidden if so requested - asciiText->string = SbString( getPresentationString(Constr).toUtf8().constData() ); + if(Constr->Type == Weight) + asciiText->string = SbString( QString::number(Constr->getValue()).toStdString().c_str()); + else + asciiText->string = SbString( getPresentationString(Constr).toUtf8().constData() ); asciiText->datumtype = SoDatumLabel::RADIUS; asciiText->param1 = Constr->LabelDistance; @@ -5475,6 +5578,7 @@ void ViewProviderSketch::rebuildConstraintsVisual(void) case DistanceY: case Radius: case Diameter: + case Weight: case Angle: { SoDatumLabel *text = new SoDatumLabel();