Skip to content

Commit

Permalink
Sketcher: Unit independent pole weight for B-Splines (Weight constraint)
Browse files Browse the repository at this point in the history
========================================================================

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.
  • Loading branch information
abdullahtahiriyo committed Dec 10, 2020
1 parent 8080e8d commit 95c1a26
Show file tree
Hide file tree
Showing 11 changed files with 444 additions and 85 deletions.
1 change: 1 addition & 0 deletions src/Mod/Sketcher/App/Constraint.cpp
Expand Up @@ -126,6 +126,7 @@ Quantity Constraint::getPresentationValue() const
quantity.setUnit(Unit::Angle);
break;
case SnellsLaw:
case Weight:
quantity.setValue(Value);
break;
default:
Expand Down
3 changes: 2 additions & 1 deletion src/Mod/Sketcher/App/Constraint.h
Expand Up @@ -57,6 +57,7 @@ enum ConstraintType {
SnellsLaw = 16,
Block = 17,
Diameter = 18,
Weight = 19,
NumConstraintTypes // must be the last item!
};

Expand Down Expand Up @@ -117,7 +118,7 @@ class SketcherExport Constraint : public Base::Persistence

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;
Expand Down
9 changes: 9 additions & 0 deletions src/Mod/Sketcher/App/ConstraintPyImp.cpp
Expand Up @@ -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);
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand Down
13 changes: 13 additions & 0 deletions src/Mod/Sketcher/App/Sketch.cpp
Expand Up @@ -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;
Expand Down
56 changes: 40 additions & 16 deletions src/Mod/Sketcher/App/SketchObject.cpp
Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -3839,6 +3842,7 @@ int SketchObject::addSymmetric(const std::vector<int> &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();
Expand Down Expand Up @@ -4133,9 +4137,10 @@ int SketchObject::addCopy(const std::vector<int> &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();
Expand Down Expand Up @@ -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 ;
}
}
}

Expand Down Expand Up @@ -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)++;
}
}
Expand Down Expand Up @@ -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 ||
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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<const Part::GeomBSplineCurve*>(getGeometry(bsplinegeoid));

std::vector<double> 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]);

}
}
}
}
}
}
}
Expand Down Expand Up @@ -7912,9 +7939,6 @@ int SketchObject::getGeometryId(int GeoId, long &id) const
return 0;
}




// Python Sketcher feature ---------------------------------------------------------

namespace App {
Expand Down

0 comments on commit 95c1a26

Please sign in to comment.