Fixed issue #2877: Added hypot() and catet() functions to expression framework.
This commit is contained in:
@@ -678,7 +678,12 @@ FunctionExpression::FunctionExpression(const DocumentObject *_owner, Function _f
|
||||
case ATAN2:
|
||||
case POW:
|
||||
if (args.size() != 2)
|
||||
throw ExpressionError("Invalid number of arguments: eaxctly two required.");
|
||||
throw ExpressionError("Invalid number of arguments: exactly two required.");
|
||||
break;
|
||||
case HYPOT:
|
||||
case CATH:
|
||||
if (args.size() < 2 || args.size() > 3)
|
||||
throw ExpressionError("Invalid number of arguments: exactly two, or three required.");
|
||||
break;
|
||||
case STDDEV:
|
||||
case SUM:
|
||||
@@ -922,8 +927,10 @@ Expression * FunctionExpression::eval() const
|
||||
|
||||
std::unique_ptr<Expression> e1(args[0]->eval());
|
||||
std::unique_ptr<Expression> e2(args.size() > 1 ? args[1]->eval() : 0);
|
||||
std::unique_ptr<Expression> e3(args.size() > 2 ? args[2]->eval() : 0);
|
||||
NumberExpression * v1 = freecad_dynamic_cast<NumberExpression>(e1.get());
|
||||
NumberExpression * v2 = freecad_dynamic_cast<NumberExpression>(e2.get());
|
||||
NumberExpression * v3 = freecad_dynamic_cast<NumberExpression>(e3.get());
|
||||
double output;
|
||||
Unit unit;
|
||||
double scaler = 1;
|
||||
@@ -1026,6 +1033,16 @@ Expression * FunctionExpression::eval() const
|
||||
}
|
||||
break;
|
||||
}
|
||||
case HYPOT:
|
||||
case CATH:
|
||||
if (v1->getUnit() != v2->getUnit())
|
||||
throw ExpressionError("Units must be equal");
|
||||
if (args.size() > 2) {
|
||||
if (v2->getUnit() != v3->getUnit())
|
||||
throw ExpressionError("Units must be equal");
|
||||
}
|
||||
unit = v1->getUnit();
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
@@ -1086,6 +1103,14 @@ Expression * FunctionExpression::eval() const
|
||||
output = pow(value, v2->getValue());
|
||||
break;
|
||||
}
|
||||
case HYPOT: {
|
||||
output = sqrt(pow(v1->getValue(), 2) + pow(v2->getValue(), 2) + (v3 ? pow(v3->getValue(), 2) : 0));
|
||||
break;
|
||||
}
|
||||
case CATH: {
|
||||
output = sqrt(pow(v1->getValue(), 2) - pow(v2->getValue(), 2) - (v3 ? pow(v3->getValue(), 2) : 0));
|
||||
break;
|
||||
}
|
||||
case ROUND:
|
||||
output = boost::math::round(value);
|
||||
break;
|
||||
@@ -1190,6 +1215,10 @@ std::string FunctionExpression::toString() const
|
||||
return "atan2(" + ss.str() + ")";
|
||||
case POW:
|
||||
return "pow(" + ss.str() + ")";
|
||||
case HYPOT:
|
||||
return "hypot(" + ss.str() + ")";
|
||||
case CATH:
|
||||
return "cath(" + ss.str() + ")";
|
||||
case ROUND:
|
||||
return "round(" + ss.str() + ")";
|
||||
case TRUNC:
|
||||
@@ -1792,6 +1821,8 @@ static void initParser(const App::DocumentObject *owner)
|
||||
registered_functions["trunc"] = FunctionExpression::TRUNC;
|
||||
registered_functions["ceil"] = FunctionExpression::CEIL;
|
||||
registered_functions["floor"] = FunctionExpression::FLOOR;
|
||||
registered_functions["hypot"] = FunctionExpression::HYPOT;
|
||||
registered_functions["cath"] = FunctionExpression::CATH;
|
||||
|
||||
// Aggregates
|
||||
registered_functions["sum"] = FunctionExpression::SUM;
|
||||
|
||||
@@ -328,6 +328,8 @@ public:
|
||||
TRUNC,
|
||||
CEIL,
|
||||
FLOOR,
|
||||
HYPOT,
|
||||
CATH,
|
||||
|
||||
// Aggregates
|
||||
AGGREGATES,
|
||||
|
||||
@@ -229,6 +229,25 @@ class SpreadsheetCases(unittest.TestCase):
|
||||
sheet.set('B21', '=pow(-7; 4)')
|
||||
sheet.set('C21', '=pow(7mm; 4)')
|
||||
sheet.set('D21', '=pow(7mm; 4mm)')
|
||||
sheet.set('A23', '=hypot(3; 4)') # Hypot
|
||||
sheet.set('B23', '=hypot(-3; 4)')
|
||||
sheet.set('C23', '=hypot(3mm; 4)')
|
||||
sheet.set('D23', '=hypot(3mm; 4mm)')
|
||||
sheet.set('A24', '=hypot(3; 4; 5)') # Hypot
|
||||
sheet.set('B24', '=hypot(-3; 4; 5)')
|
||||
sheet.set('C24', '=hypot(3mm; 4; 5)')
|
||||
sheet.set('D24', '=hypot(3mm; 4mm; 5mm)')
|
||||
sheet.set('A26', '=cath(5; 3)') # Cath
|
||||
sheet.set('B26', '=cath(-5; 3)')
|
||||
sheet.set('C26', '=cath(5mm; 3)')
|
||||
sheet.set('D26', '=cath(5mm; 3mm)')
|
||||
|
||||
l = math.sqrt(5 * 5 + 4*4 + 3*3)
|
||||
sheet.set('A27', '=cath(%0.15f; 5; 4)' % l) # Cath
|
||||
sheet.set('B27', '=cath(%0.15f; -5; 4)' % l)
|
||||
sheet.set('C27', '=cath(%0.15f mm; 5mm; 4)' % l)
|
||||
sheet.set('D27', '=cath(%0.15f mm; 5mm; 4mm)' % l)
|
||||
|
||||
self.doc.recompute()
|
||||
self.assertMostlyEqual(sheet.A1, 0.5) # Cos
|
||||
self.assertMostlyEqual(sheet.B1, 0.5)
|
||||
@@ -309,6 +328,27 @@ class SpreadsheetCases(unittest.TestCase):
|
||||
self.assertMostlyEqual(sheet.B21, 2401)
|
||||
self.assertMostlyEqual(sheet.C21, Units.Quantity('2401mm^4'))
|
||||
self.assertEqual(sheet.D21, u'ERR: Exponent is not allowed to have a unit.')
|
||||
self.assertMostlyEqual(sheet.A23, 5) # Hypot
|
||||
self.assertMostlyEqual(sheet.B23, 5)
|
||||
self.assertEqual(sheet.C23, u'ERR: Units must be equal')
|
||||
self.assertMostlyEqual(sheet.D23, Units.Quantity('5mm'))
|
||||
|
||||
l = math.sqrt(3*3 + 4*4 + 5*5)
|
||||
self.assertMostlyEqual(sheet.A24, l) # Hypot
|
||||
self.assertMostlyEqual(sheet.B24, l)
|
||||
self.assertEqual(sheet.C24, u'ERR: Units must be equal')
|
||||
self.assertMostlyEqual(sheet.D24, Units.Quantity("7.07106781186548 mm"))
|
||||
self.assertMostlyEqual(sheet.A26, 4) # Cath
|
||||
self.assertMostlyEqual(sheet.B26, 4)
|
||||
self.assertEqual(sheet.C26, u'ERR: Units must be equal')
|
||||
self.assertMostlyEqual(sheet.D26, Units.Quantity('4mm'))
|
||||
|
||||
l = math.sqrt(5 * 5 + 4*4 + 3*3)
|
||||
l = math.sqrt(l * l - 5*5 - 4*4)
|
||||
self.assertMostlyEqual(sheet.A27, l) # Cath
|
||||
self.assertMostlyEqual(sheet.B27, l)
|
||||
self.assertEqual(sheet.C27, u'ERR: Units must be equal')
|
||||
self.assertMostlyEqual(sheet.D27, Units.Quantity("3 mm"))
|
||||
FreeCAD.closeDocument(doc.Name)
|
||||
|
||||
def testRelationalOperators(self):
|
||||
|
||||
Reference in New Issue
Block a user