Dimension Parser Help

Have some feature requests, feedback, cool stuff to share, or want to know where FreeCAD is going? This is the place.
Forum rules
Be nice to others! Read the FreeCAD code of conduct!
openBrain
Veteran
Posts: 9041
Joined: Fri Nov 09, 2018 5:38 pm
Contact:

Re: Dimension Parser Help

Post by openBrain »

adrianinsaval wrote: Tue Jun 21, 2022 8:12 pm does this use a completely separate parser from the expression engine? can't we reuse a subset of the expression parser for this?
Yes indeed, those are 2 separate parsers. Probably not so easy to merge both because they are targeting close but still different things. :?
User avatar
adrianinsaval
Veteran
Posts: 5544
Joined: Thu Apr 05, 2018 5:15 pm

Re: Dimension Parser Help

Post by adrianinsaval »

yes but it would be nice if we can separate the part of that parser that handles units and math and skip all about object references.
ChemicalCoal
Posts: 24
Joined: Sun May 09, 2021 3:38 am

Re: Dimension Parser Help

Post by ChemicalCoal »

adrianinsaval wrote: Wed Jun 22, 2022 1:09 pm yes but it would be nice if we can separate the part of that parser that handles units and math and skip all about object references.
I was thinking it should pass whatever string that is typed in the box to the expression parser, units, references and all. Evaluate it down to a number and just use that. That way the parsers are identical, no need to artificially restrict the input.

Its possible this could be done entirely in GUI land, and just use Sketch.setExpression("Constraint[?], u"number/units here"), that way all the dimensions and expressions are handled the same way. (Not sure about this though).

This would also need to evaluate whether the expression is parsable or not and reject if not; just like the expression box.
User avatar
adrianinsaval
Veteran
Posts: 5544
Joined: Thu Apr 05, 2018 5:15 pm

Re: Dimension Parser Help

Post by adrianinsaval »

IMO it's not a good idea to parse object references there as it might give users the wrong impression that they have set an expression
ChemicalCoal
Posts: 24
Joined: Sun May 09, 2021 3:38 am

Re: Dimension Parser Help

Post by ChemicalCoal »

Here's my hack and slash proof of concept for this:

It pre parses the input with the Expression Parser before the Quantity Parser parses it.
It allows for inputs of 1mm + 1in -> 26.4mm
It also can do 1mm + Spreadsheet.Value -> Expected value (I agree with adrianinsaval, not sure why anyone would do this but it works)

Needed to disable the auto update of input text to parsed text to avoid parsing:
1mm + 1m
when you were just not finished typing:
1mm + 1mm

Let me know if y'all have any comments.
I'd like to carve out the Quantity Parser from this input entirely, but I haven't investigated how reasonable that is.

Code: Select all

diff --git a/src/Gui/QuantitySpinBox.cpp b/src/Gui/QuantitySpinBox.cpp
index 096b7d4b01..65de752617 100644
--- a/src/Gui/QuantitySpinBox.cpp
+++ b/src/Gui/QuantitySpinBox.cpp
@@ -43,13 +43,14 @@
 #include <Base/Exception.h>
 #include <Base/UnitsApi.h>
 #include <Base/Tools.h>
+#include <App/ExpressionParser.h>
 
 #include "QuantitySpinBox.h"
 #include "QuantitySpinBox_p.h"
 #include "Command.h"
 #include "DlgExpressionInput.h"
 #include "Tools.h"
-
+#include <App/DocumentObject.h>
 
 using namespace Gui;
 using namespace App;
@@ -84,7 +85,7 @@ public:
         return text;
     }
 
-    bool validate(QString& input, Base::Quantity& result) const
+    bool validate(QString& input, Base::Quantity& result, const App::ObjectIdentifier& path) const
     {
         Q_Q(const QuantitySpinBox);
 
@@ -99,7 +100,7 @@ public:
         auto validateInput = [&](QString& tmp) -> QValidator::State {
             int pos = 0;
             QValidator::State state;
-            Base::Quantity res = validateAndInterpret(tmp, pos, state);
+            Base::Quantity res = validateAndInterpret(tmp, pos, state, path);
             res.setFormat(quantity.getFormat());
             if (state == QValidator::Acceptable) {
                 success = true;
@@ -149,7 +150,7 @@ public:
             return false;
         }
     }
-    Base::Quantity validateAndInterpret(QString& input, int& pos, QValidator::State& state) const
+    Base::Quantity validateAndInterpret(QString& input, int& pos, QValidator::State& state, const App::ObjectIdentifier& path) const
     {
         Base::Quantity res;
         const double max = this->maximum;
@@ -157,6 +158,23 @@ public:
 
         QString copy = input;
 
+		try{
+			std::shared_ptr<Expression> expr(ExpressionParser::parse(path.getDocumentObject(), input.toUtf8().constData()));
+  
+			if (expr) {
+				std::unique_ptr<Expression> result(expr->eval());
+				NumberExpression * n = Base::freecad_dynamic_cast<NumberExpression>(result.get());
+				Base::Quantity value = n->getQuantity();
+				QString msg = value.getUserString();
+				//input = msg;
+				copy = msg;
+
+			}
+		}
+		catch(...){
+			qDebug() << "Expression Parse Failed:";
+		}
+
         int len = copy.size();
 
         const bool plus = max >= 0;
@@ -286,7 +304,7 @@ end:
             res.setValue(max > 0 ? min : max);
         }
 
-        input = copy;
+        //input = copy;
         return res;
     }
 
@@ -482,7 +500,8 @@ void QuantitySpinBox::validateInput()
     int pos = 0;
     QValidator::State state;
     QString text = lineEdit()->text();
-    d->validateAndInterpret(text, pos, state);
+	const App::ObjectIdentifier & path = getPath();
+    d->validateAndInterpret(text, pos, state, path);
     if (state != QValidator::Acceptable) {
         lineEdit()->setText(d->validStr);
     }
@@ -538,7 +557,8 @@ void QuantitySpinBox::userInput(const QString & text)
 
     QString tmp = text;
     Base::Quantity res;
-    if (d->validate(tmp, res)) {
+	const App::ObjectIdentifier & path = getPath();
+    if (d->validate(tmp, res, path)) {
         d->validStr = tmp;
         d->validInput = true;
     }
@@ -990,10 +1010,11 @@ Base::Quantity QuantitySpinBox::valueFromText(const QString &text) const
     QString copy = text;
     int pos = lineEdit()->cursorPosition();
     QValidator::State state = QValidator::Acceptable;
-    Base::Quantity quant = d->validateAndInterpret(copy, pos, state);
+	const App::ObjectIdentifier & path = getPath();
+    Base::Quantity quant = d->validateAndInterpret(copy, pos, state, path);
     if (state != QValidator::Acceptable) {
         fixup(copy);
-        quant = d->validateAndInterpret(copy, pos, state);
+        quant = d->validateAndInterpret(copy, pos, state, path);
     }
 
     return quant;
@@ -1004,7 +1025,8 @@ QValidator::State QuantitySpinBox::validate(QString &text, int &pos) const
     Q_D(const QuantitySpinBox);
 
     QValidator::State state;
-    d->validateAndInterpret(text, pos, state);
+	const App::ObjectIdentifier & path = getPath();
+    d->validateAndInterpret(text, pos, state, path);
     return state;
 }
User avatar
adrianinsaval
Veteran
Posts: 5544
Joined: Thu Apr 05, 2018 5:15 pm

Re: Dimension Parser Help

Post by adrianinsaval »

Good news, the PR for this was merged: git commit 7cd01505fc6e1cddbf5ec39b5474f55c782d1753 so the next weekly builds should exhibit better behavior. Anyone volunteers to add this to Release_notes_1.0? @ChemicalCoal
is there documentation somewhere else that needs to be updated?
ChemicalCoal
Posts: 24
Joined: Sun May 09, 2021 3:38 am

Re: Dimension Parser Help

Post by ChemicalCoal »

@adrianinsaval I can add this to the release notes once my Wiki account is created,

For documentation I can add a short note, but I don't see a great place to put it,

Maybe here somewhere https://wiki.freecadweb.org/Expressions
or here https://wiki.freecadweb.org/Sketcher_Workbench under Dimensional constraints

Thoughts?
Post Reply