Sketcher: Added support for expressions.

This commit is contained in:
Eivind Kvedalen
2015-07-21 00:16:24 +02:00
committed by wmayer
parent bb78126184
commit cacf7bdaf1
16 changed files with 957 additions and 338 deletions

View File

@@ -46,6 +46,9 @@
# include <vector>
#endif // #ifndef _PreComp_
#include <boost/bind.hpp>
#include <App/Document.h>
#include <Base/Writer.h>
#include <Base/Reader.h>
#include <Base/Tools.h>
@@ -93,6 +96,11 @@ SketchObject::SketchObject()
solverNeedsUpdate=false;
noRecomputes=false;
ExpressionEngine.setValidator(boost::bind(&Sketcher::SketchObject::validateExpression, this, _1, _2));
constraintsRemovedConn = Constraints.signalConstraintsRemoved.connect(boost::bind(&Sketcher::SketchObject::constraintsRemoved, this, _1));
constraintsRenamedConn = Constraints.signalConstraintsRenamed.connect(boost::bind(&Sketcher::SketchObject::constraintsRenamed, this, _1));
}
SketchObject::~SketchObject()
@@ -247,7 +255,7 @@ int SketchObject::setDatum(int ConstrId, double Datum)
std::vector<Constraint *> newVals(vals);
// clone the changed Constraint
Constraint *constNew = vals[ConstrId]->clone();
constNew->Value = Datum;
constNew->setValue(Datum);
newVals[ConstrId] = constNew;
this->Constraints.setValues(newVals);
delete constNew;
@@ -286,6 +294,8 @@ int SketchObject::setDriving(int ConstrId, bool isdriving)
constNew->isDriving = isdriving;
newVals[ConstrId] = constNew;
this->Constraints.setValues(newVals);
if (isdriving)
setExpression(Constraints.createPath(ConstrId), boost::shared_ptr<App::Expression>());
delete constNew;
if(noRecomputes) // if we do not have a recompute, the sketch must be solved to update the DoF of the solver
@@ -342,6 +352,8 @@ int SketchObject::toggleDriving(int ConstrId)
constNew->isDriving = !constNew->isDriving;
newVals[ConstrId] = constNew;
this->Constraints.setValues(newVals);
if (constNew->isDriving)
setExpression(Constraints.createPath(ConstrId), boost::shared_ptr<App::Expression>());
delete constNew;
if(noRecomputes) // if we do not have a recompute, the sketch must be solved to update the DoF of the solver
@@ -2268,7 +2280,7 @@ int SketchObject::addCopy(const std::vector<int> &geoIdList, const Base::Vector3
constNew->Type = Sketcher::Distance;
constNew->First = rowrefgeoid;
constNew->FirstPos = Sketcher::none;
constNew->Value = perpendicularDisplacement.Length();
constNew->setValue(perpendicularDisplacement.Length());
newconstrVals.push_back(constNew);
}
@@ -2329,14 +2341,14 @@ int SketchObject::addCopy(const std::vector<int> &geoIdList, const Base::Vector3
constNew->Type = Sketcher::Distance;
constNew->First = colrefgeoid;
constNew->FirstPos = Sketcher::none;
constNew->Value = displacement.Length();
constNew->setValue(displacement.Length());
newconstrVals.push_back(constNew);
constNew = new Constraint();
constNew->Type = Sketcher::Angle;
constNew->First = colrefgeoid;
constNew->FirstPos = Sketcher::none;
constNew->Value = atan2(displacement.y,displacement.x);
constNew->setValue(atan2(displacement.y,displacement.x));
newconstrVals.push_back(constNew);
}
else { // any other element
@@ -3499,6 +3511,38 @@ void SketchObject::validateConstraints()
}
}
std::string SketchObject::validateExpression(const App::ObjectIdentifier &path, boost::shared_ptr<const App::Expression> expr)
{
const App::Property * prop = path.getProperty();
assert(expr != 0);
if (!prop)
return "Property not found";
if (prop == &Constraints) {
const Constraint * constraint = Constraints.getConstraint(path);
if (!constraint->isDriving)
return "Reference constraints cannot be set!";
}
std::set<App::ObjectIdentifier> deps;
expr->getDeps(deps);
for (std::set<App::ObjectIdentifier>::const_iterator i = deps.begin(); i != deps.end(); ++i) {
const App::Property * prop = (*i).getProperty();
if (prop == &Constraints) {
const Constraint * constraint = Constraints.getConstraint(*i);
if (!constraint->isDriving)
return "Reference constraint from this sketch cannot be used in this expression.";
}
}
return "";
}
//This function is necessary for precalculation of an angle when adding
// an angle constraint. It is also used here, in SketchObject, to
// lock down the type of tangency/perpendicularity.
@@ -3546,6 +3590,23 @@ double SketchObject::calculateAngleViaPoint(int GeoId1, int GeoId2, double px, d
*/
}
void SketchObject::constraintsRenamed(const std::map<App::ObjectIdentifier, App::ObjectIdentifier> &renamed)
{
ExpressionEngine.renameExpressions(renamed);
getDocument()->renameObjectIdentifiers(renamed);
}
void SketchObject::constraintsRemoved(const std::set<App::ObjectIdentifier> &removed)
{
std::set<App::ObjectIdentifier>::const_iterator i = removed.begin();
while (i != removed.end()) {
ExpressionEngine.setValue(*i, boost::shared_ptr<App::Expression>(), 0);
++i;
}
}
//Tests if the provided point lies exactly in a curve (satisfies
// point-on-object constraint). It is used to decide whether it is nesessary to
// constrain a point onto curves when 3-element selection tangent-via-point-like
@@ -3841,10 +3902,10 @@ bool SketchObject::AutoLockTangencyAndPerpty(Constraint *cstr, bool bForce, bool
{
try{
//assert ( cstr->Type == Tangent || cstr->Type == Perpendicular);
if(cstr->Value != 0.0 && ! bForce) /*tangency type already set. If not bForce - don't touch.*/
if(cstr->getValue() != 0.0 && ! bForce) /*tangency type already set. If not bForce - don't touch.*/
return true;
if(!bLock){
cstr->Value=0.0;//reset
cstr->setValue(0.0);//reset
} else {
//decide on tangency type. Write the angle value into the datum field of the constraint.
int geoId1, geoId2, geoIdPt;
@@ -3880,7 +3941,7 @@ bool SketchObject::AutoLockTangencyAndPerpty(Constraint *cstr, bool bForce, bool
if(fabs(angleErr) > M_PI/2 )
angleDesire += M_PI;
cstr->Value = angleDesire + angleOffset; //external tangency. The angle stored is offset by Pi/2 so that a value of 0.0 is invalid and threated as "undecided".
cstr->setValue(angleDesire + angleOffset); //external tangency. The angle stored is offset by Pi/2 so that a value of 0.0 is invalid and threated as "undecided".
}
}
} catch (Base::Exception& e){
@@ -3891,6 +3952,15 @@ bool SketchObject::AutoLockTangencyAndPerpty(Constraint *cstr, bool bForce, bool
return true;
}
void SketchObject::setExpression(const App::ObjectIdentifier &path, boost::shared_ptr<App::Expression> expr, const char * comment)
{
DocumentObject::setExpression(path, expr, comment);
if(noRecomputes) // if we do not have a recompute, the sketch must be solved to update the DoF of the solver, constraints and UI
solve();
}
// Python Sketcher feature ---------------------------------------------------------
namespace App {