diff options
Diffstat (limited to 'libs/cassowary/ClFDBinaryOneWayConstraint.cc')
-rw-r--r-- | libs/cassowary/ClFDBinaryOneWayConstraint.cc | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/libs/cassowary/ClFDBinaryOneWayConstraint.cc b/libs/cassowary/ClFDBinaryOneWayConstraint.cc new file mode 100644 index 0000000000..e7bf7f1089 --- /dev/null +++ b/libs/cassowary/ClFDBinaryOneWayConstraint.cc @@ -0,0 +1,140 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClFDBinaryOneWayConstraint.cc + + +#ifdef HAVE_CONFIG_H +#include <config.h> +#define CONFIG_H_INCLUDED +#endif + +#include <cassowary/ClFDBinaryOneWayConstraint.h> +#include <cassowary/ClLinearConstraint.h> +#include <cassowary/ClTypedefs.h> +#include <cassowary/ClLinearExpression.h> + + +void +ClFDBinaryOneWayConstraint::EnsurePreconditionsForCn(const ClConstraint &cn) +{ + ClVarSet setRO = cn.ReadOnlyVars(); + if (setRO.size() > 1) + throw ExCLTooDifficultSpecial("Only 0 or 1 read only variables are allowed"); + const ClLinearExpression &expr = cn.Expression(); + const ClVarToNumberMap &terms = expr.Terms(); + if (terms.size() > 2) + throw ExCLTooDifficultSpecial("Cannot have more than 2 variables"); + if (terms.size() == 0) + throw ExCLTooDifficultSpecial("Must have at least 1 variable"); + if (terms.size() == 2 && setRO.size() == 0) + throw ExCLTooDifficultSpecial("Both variables cannot be read-write, one must be read-only"); + if (terms.size() == 1 && setRO.size() == 1) + throw ExCLTooDifficultSpecial("Single read-only variable in LinearConstraint -- must not be read-only."); + ClVariable clv = (*terms.begin()).first; + /* GJB:FIXME:: iterate over all the variables */ + if (!clv->IsFDVariable()) { + throw ExCLTooDifficultSpecial("FD constraint contains non-FD variables"); + } +} + +bool +ClFDBinaryOneWayConstraint::FCanConvertCn(const ClConstraint &cn) +{ + try { + EnsurePreconditionsForCn(cn); + return true; + } catch (...) { + return false; + } +} + + +ClFDBinaryOneWayConstraint::ClFDBinaryOneWayConstraint(const ClConstraint &cn) + :ClFDConstraint(cn.strength(), cn.weight()) +{ + EnsurePreconditionsForCn(cn); + list<FDNumber> l; + /* GJB:FIXME:: varargs inteface, with sentinel as first arg? */ + l.push_back(9); + l.push_back(10); + l.push_back(12); + l.push_back(14); + l.push_back(20); + + ClVarSet setRO = cn.ReadOnlyVars(); + + ClVariable clvRO = clvNil; + ClVariable clvROLinear = clvNil; + Number coeffRO = 0; + + ClVariable clvRW = clvNil; + Number coeffRW = 0; + + if (setRO.size() == 1) { + const ClVariable &clv = *(setRO.begin()); + if (clv->IsFDVariable()) + clvRO = clv; + else + clvRO = new ClFDVariable(clv.Name(),clv.IntValue(),l); + clvROLinear = clv; + } + const ClLinearExpression &expr = cn.Expression(); + const ClVarToNumberMap &terms = expr.Terms(); + + for (ClVarToNumberMap::const_iterator it = terms.begin(); + it != terms.end(); + ++it) { + ClVariable clv = (*it).first; + if (clv == clvROLinear) { + coeffRO = (*it).second; + } else { + if (clv->IsFDVariable()) + clvRW = clv; + else + clvRW = new ClFDVariable(clv.Name(),clv.Value(),l); + coeffRW = (*it).second; + } + } + assert(!clvRW.IsNil()); + if (coeffRW == 0) { + throw ExCLTooDifficultSpecial("RW variable's coefficient must be non-zero"); + } + + bool fInequality = cn.IsInequality(); + bool fStrictInequality = cn.IsStrictInequality(); + double rhs_constant = expr.Constant(); + + // now we have: + // coeffRW * clvRW + coeffRO * clvRO <REL> rhs_constant + // where <REL> is >= if fInequality, or = if !fInequality + // + // need: + // clvRW <REL> coefficient * clvRO + constant + // + // so: + // coefficient = -coeffRO/coeffRW + // constant = rhs_constant/coeffRW + + if (fStrictInequality) + _rel = cnGT; + else if (fInequality) + _rel = cnGEQ; + else + _rel = cnEQ; + + if (coeffRW < 0) + _rel = ReverseInequality(_rel); + + _coefficient = -coeffRO/coeffRW; + _constant = -rhs_constant/coeffRW; + _vRW = clvRW; + _vRO = clvRO; + return; +} |