Skip to content

Commit

Permalink
PropertyExpressionEngine: support binding of output property
Browse files Browse the repository at this point in the history
PropertyExpressionEngine::execute() can be divided to two steps, to
compute non-output properties before object execute(), and then compute
only output propertyies afterwards.

Fixes realthunder/FreeCAD_assembly3#52
  • Loading branch information
realthunder committed Sep 24, 2018
1 parent 4a3a0e1 commit 32df9f6
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 43 deletions.
26 changes: 10 additions & 16 deletions src/App/Document.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3048,18 +3048,12 @@ bool Document::_recomputeFeature(DocumentObject* Feat)

DocumentObjectExecReturn *returnCode = 0;
try {
returnCode = Feat->ExpressionEngine.execute();
if (returnCode != DocumentObject::StdReturn) {
returnCode->Which = Feat;
_RecomputeLog.push_back(returnCode);
#ifdef FC_DEBUG
Base::Console().Error("%s\n",returnCode->Why.c_str());
#endif
Feat->setError();
return true;
returnCode = Feat->ExpressionEngine.execute(0);
if (returnCode == DocumentObject::StdReturn) {
returnCode = Feat->recompute();
if(returnCode == DocumentObject::StdReturn)
returnCode = Feat->ExpressionEngine.execute(1);
}

returnCode = Feat->recompute();
}
catch(Base::AbortException &e){
e.ReportException();
Expand Down Expand Up @@ -3094,15 +3088,15 @@ bool Document::_recomputeFeature(DocumentObject* Feat)
}
#endif

// error code
if (returnCode == DocumentObject::StdReturn) {
if(returnCode == DocumentObject::StdReturn) {
Feat->resetError();
}
else {
}else{
returnCode->Which = Feat;
_RecomputeLog.push_back(returnCode);
#ifdef FC_DEBUG
Base::Console().Error("%s\n",returnCode->Why.c_str());
FC_ERR("Failed to recompute " << Feat->getExportName(true) << ": " << returnCode->Why);
#else
FC_LOG("Failed to recompute " << Feat->getExportName(true) << ": " << returnCode->Why);
#endif
Feat->setError();
return true;
Expand Down
39 changes: 15 additions & 24 deletions src/App/PropertyExpressionEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -509,14 +509,23 @@ struct cycle_detector : public boost::dfs_visitor<> {
*/

void PropertyExpressionEngine::buildGraph(const ExpressionMap & exprs,
boost::unordered_map<int, ObjectIdentifier> & revNodes, DiGraph & g) const
boost::unordered_map<int, ObjectIdentifier> & revNodes, DiGraph & g, int output) const
{
boost::unordered_map<ObjectIdentifier, int> nodes;
std::vector<Edge> edges;

// Build data structure for graph
for (ExpressionMap::const_iterator it = exprs.begin(); it != exprs.end(); ++it)
for (ExpressionMap::const_iterator it = exprs.begin(); it != exprs.end(); ++it) {
if(output>=0) {
auto prop = it->first.getProperty();
if(!prop)
throw Base::RuntimeError("Path does not resolve to a property.");
bool is_output = prop->testStatus(App::Property::Output)||(prop->getType()&App::Prop_Output);
if(is_output != (output>0))
continue;
}
buildGraphStructures(it->first, it->second.expression, nodes, revNodes, edges);
}

// Create graph
g = DiGraph(revNodes.size());
Expand Down Expand Up @@ -544,13 +553,13 @@ void PropertyExpressionEngine::buildGraph(const ExpressionMap & exprs,
* order, in case properties depends on each other.
*/

std::vector<App::ObjectIdentifier> PropertyExpressionEngine::computeEvaluationOrder()
std::vector<App::ObjectIdentifier> PropertyExpressionEngine::computeEvaluationOrder(int output)
{
std::vector<App::ObjectIdentifier> evaluationOrder;
boost::unordered_map<int, ObjectIdentifier> revNodes;
DiGraph g;

buildGraph(expressions, revNodes, g);
buildGraph(expressions, revNodes, g, output);

/* Compute evaluation order for expressions */
std::vector<int> c;
Expand All @@ -569,7 +578,7 @@ std::vector<App::ObjectIdentifier> PropertyExpressionEngine::computeEvaluationOr
* @return StdReturn on success.
*/

DocumentObjectExecReturn *App::PropertyExpressionEngine::execute()
DocumentObjectExecReturn *App::PropertyExpressionEngine::execute(int output)
{
DocumentObject * docObj = freecad_dynamic_cast<DocumentObject>(getContainer());

Expand All @@ -595,7 +604,7 @@ DocumentObjectExecReturn *App::PropertyExpressionEngine::execute()
resetter r(running);

// Compute evaluation order
std::vector<App::ObjectIdentifier> evaluationOrder = computeEvaluationOrder();
std::vector<App::ObjectIdentifier> evaluationOrder = computeEvaluationOrder(output);
std::vector<ObjectIdentifier>::const_iterator it = evaluationOrder.begin();

#ifdef FC_PROPERTYEXPRESSIONENGINE_LOG
Expand All @@ -620,24 +629,6 @@ DocumentObjectExecReturn *App::PropertyExpressionEngine::execute()
// Evaluate expression
std::unique_ptr<Expression> e(expressions[*it].expression->eval());

#ifdef FC_PROPERTYEXPRESSIONENGINE_LOG
{
Base::Quantity q;
boost::any value = e->getValueAsAny();

if (value.type() == typeid(Base::Quantity))
q = boost::any_cast<Base::Quantity>(value);
else if (value.type() == typeid(double))
q = boost::any_cast<double>(value);
else {
std::clog << "Unknown return value for expression.";
q = 0;
}

std::clog << "Assigning value " << q.getValue() << " to " << (*it).toString().c_str() << " (" << prop->getName() << ")" << std::endl;
}
#endif

/* Set value of property */
prop->setPathValue(*it, e->getValueAsAny());

Expand Down
11 changes: 8 additions & 3 deletions src/App/PropertyExpressionEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,12 @@ class AppExport PropertyExpressionEngine : public App::Property, private App::At

const boost::any getPathValue(const App::ObjectIdentifier & path) const;

DocumentObjectExecReturn * execute();
/** Evaluate the expressions
*
* @param output: 0 indicates to compute all non-output property bindings.
* 1 indicates to compute only output properties. -1 means compute all.
*/
DocumentObjectExecReturn * execute(int output=-1);

void getDocumentObjectDeps(std::vector<DocumentObject*> & docObjs) const;

Expand Down Expand Up @@ -141,14 +146,14 @@ class AppExport PropertyExpressionEngine : public App::Property, private App::At
typedef std::pair<int, int> Edge;
typedef boost::unordered_map<const App::ObjectIdentifier, ExpressionInfo> ExpressionMap;

std::vector<App::ObjectIdentifier> computeEvaluationOrder();
std::vector<App::ObjectIdentifier> computeEvaluationOrder(int output);

void buildGraphStructures(const App::ObjectIdentifier &path,
const boost::shared_ptr<Expression> expression, boost::unordered_map<App::ObjectIdentifier, int> &nodes,
boost::unordered_map<int, App::ObjectIdentifier> &revNodes, std::vector<Edge> &edges) const;

void buildGraph(const ExpressionMap &exprs,
boost::unordered_map<int, App::ObjectIdentifier> &revNodes, DiGraph &g) const;
boost::unordered_map<int, App::ObjectIdentifier> &revNodes, DiGraph &g, int output=-1) const;

bool running; /**< Boolean used to avoid loops */

Expand Down

0 comments on commit 32df9f6

Please sign in to comment.