-
Notifications
You must be signed in to change notification settings - Fork 471
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[parameters] Save parameters to file, Relation constraint #1433
base: parameters
Are you sure you want to change the base?
Conversation
Edit parameterized constraints in the GUI, (instead of their computed values) and save those constraints to a file.
Instead of working on this completely solo and then dumping a big PR with all my progress, figured I should check in with some small changes to get your feedback and make sure I'm on the right track |
@dgramop Thanks. I really appreciate you getting into this. I'll look at what I can, but I've been a bit detached from Solvespace lately. @ruevs seems to be in a similar state ;-) but he might review some stuff too. And of course others pop in sometimes totally unexpected with feedback! The approach of extending the parameters branch is probably good. I'll have a look at this this weekend. |
Alright looks like everyone's good to do the scaling solution. I'm going to still mark this as WIP since there are few more changes that I'd like to add on now that I've tested this version a little more |
In order to preserve token order, we keep a vector of pointers to original tokens, and avoid creating new tokens so that we can preseve metadata from the original string. Previously, I tried keeping pointers into the vector, but of course during re-allocation those pointers became dangling.
Still in progress.... Screen.Recording.2024-04-06.at.4.14.42.AM.movHere is a proof of concept! Code is in my I created a new "Relation" constraint. It's two expressions delimited by an equals sign. The equals sign isn't added as an Op, instead when the Relation is parsed into an equation, it should be split up into two expressions. This is to avoid unintended side effects with "real" expressions that should evaluate to something, and where an assignment operator could through things off |
The following is a snapshot of what still needs to be done before this is ready for review:
|
I decided to postpone variable scoping into a later PR. I think it's best to merge changes into our The next (edit: Apr 12th, big) PR into that branch will be variable scoping, by which point we should (IMO) have more than enough to start discussing merging to |
It won't be useful until an overhaul of the expression handling is done, in particular we need to structure is so that expressions can be stably re-serialized in the same infix order from before the expression was parsed
@@ -621,7 +621,7 @@ class SolveSpaceUI { | |||
std::string MmToString(double v, bool editable=false); | |||
std::string MmToStringSI(double v, int dim = 0); | |||
std::string DegreeToString(double v); | |||
double ExprToMm(Expr *e); | |||
double NonConstraintExprToMm(Expr *e); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I chose to rename this function, since using it to get the value of a constraint's expression in base Mm is a bad idea, considering scale factor stapled to each expression in a constraint, which encodes the scale factor that constraint was "saved" under, which itself was necessarily to correctly render constraint labels while applying the right scalings.
By renaming the function, I'm hoping to force callers to declare compliance with this invariant
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Picasso, I consider myself
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is a beautiful =
sign :-) ;-)
@dgramop I've been following your progress with great interest. Unfortunately only from a phone at odd times of day when I had some spare time. I'll try to spend some time on my SolveSpace development system and will pull, review and try your changes. I agree I should merge them into "parameters" first (no squashing so that we have the history of how things happened) - this way you will have a new "base" for further changes. When we decide that it is time to merge to master I'll do the rabasing and squashing (to a few "meaningful" commits). |
Nice! By squash I meant my own parameters_messy branch, just so the PR is a single commit. Looking forward to more parametric features in solvespace! |
... which is not standard and does not exist in Visual C++.
@ruevs just rewrote history so hard that authoritarian regimes are taking notice. in any case, I went ahead and undid my squash and got pushed the full history in all its glory. |
Just for context so others know what we are talking about dgramop#1 ;-) @dgramop I played with your branch a bit. It actually works surprisingly well. Impressively thorough job! Here is my first file using parameters: first_dgramop_parameters_test.zip I'm particularly impressed and (pleasantly) surprised that there can be two "distance" constraints on the same line segment when one is an "equation". This is beautiful and I'll definitely dig into the code until I figure out why it is possible. I did also notice some interesting corner cases but let me first go through the code more carefully and add "formal" review comments here. Another "sad" finding is that opening the above file in previous versions causes them to "crash" after the:
dialog.
Of course this is normal and "unavoidable" considering the new |
For the next release, should we change the file extension (slvs2)? We can still let the new release open older slvs files, but when saved they'd be converted to slvs2. Parametric constraints will probably also confuse older versions. |
Something I noticed is that underscores are interpreted as "operators" which triggers an unknown operator exception. I'm a big fan of snake case, so I think for better user of parameters we should change this in the expr parser |
@dgramop do you mean this? Line 692 in 7d379e7
To me it looks like they are ignored as part of "numbers" here: Line 693 in 7d379e7
This is a question to @jwesthues. Jonathan what was your plan idea to ignore
|
@ruevs while LexNumber allows underscores, when the generic (Edit: also, how did you get those nice looking links to code with preview?) |
There's another bug here with how constraints are taken care of, I haven't really done much with inter-group named parameters. I think taking care of this falls under variable scoping so maybe we visit that in the next PR... Just wanted to document this here so I can pick up after it |
This is exactly the scope issue I talked about previously. The test_test parameter is first created in the 2D sketch. Later, when it is used in the 3D extrusion, it should be treated as a constant value because it was defined and "solved" in a previous group - so the extrusion height should not be draggable. This should be equivalent to putting an equal length constraint on the height of the extrusion and the width of the extruded rectangle/square. AFAICT part of the issue is that the named parameters are created during expression parsing and are not associated with any group. I'm not sure how such an association is normally created, but it seems to be related to their handles. One thing I had considered is making a named parameters a "request" that gets displayed in the text window for a group. It should be possible to get the group connection established that way, and we need the functionality anyway. Perhaps adding this capability and creating the parameter prior to use would "fix" the problem. If so, one solution would be to require such a definition and NOT create named parameters on the fly during expression evaluation. TLDR; Most parameters are created in response to entity creation. Somehow that gets them associated with the group that entity resides in. We need named parameters to have that same group association. |
In my opinion - no. We have introduced new features that impact the file format many times since 2.0 (which was the first open source version). Here is a few that I can think of: In this cases the old versions simply show the warning - they always do - @jwesthues was forward looking enough to ensure that back in 2009 b974a4a#diff-09121c6f65665acb5c49233fc2f9d269f6da3f97c924fc5ff34aec625f0b01f7R464 So let them show the warning and then "crash and burn" or do whatever the particular new features in the file will cause - many times the entities/constraints are simply missing. |
@dgramop do not forget the other loose end that brought you here ;-) Search for Line 22 in 7d379e7
As I get deeper into the parameters branch I'll also keep it in mind. |
@ruevs I probably intended to allow underscores in literal numbers so that you could write stuff like 1_000_000, inspired by the corresponding behavior in C, and implemented it lazily and half-heartedly. There should be no problem fixing it in the obvious way. And yeah, no change to the file extension. I'd avoid unnecessary breakage where possible (e.g., don't generate new stuff in the saved file if the new feature isn't actually used), but otherwise just let the users get that warning to upgrade. |
I have some code in my other branch that lists parameters by group, but it does so in a roundabout way: by first collecting parameters by constraint in a set, then displaying those parameters.
Fair, and the way the format is structured if they don't use the RELATION constraint, savefiles will be backwards compatible. I walk back that suggestion |
Wow! That feels like an eternity ago! |
This is closer to an "eternity ago" ;-) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dgramop I finally found time to review your changes carefully. My comments are mostly minor. Please take a look.
Also you may want to merge my PR.
@@ -795,8 +797,13 @@ ExprParser::Token ExprParser::Lex(std::string *error) { | |||
} | |||
|
|||
ExprParser::Token ExprParser::PopOperand(std::string *error) { | |||
Token t = Token::From(); | |||
if(stack.empty() || stack.back().type != TokenType::OPERAND) { | |||
Token t; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does the code that uses the returned t
rely on some of the initialization that From
does when we do not go through the else
branch?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't think so, I think I was just explicitly calling constructor for readability. Should I revert this change?
@@ -806,7 +813,7 @@ ExprParser::Token ExprParser::PopOperand(std::string *error) { | |||
} | |||
|
|||
ExprParser::Token ExprParser::PopOperator(std::string *error) { | |||
Token t = Token::From(); | |||
Token t; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does the code that uses the returned t
rely on some of the initialization that From
does when we do not go through the else
branch?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't think so, I think I was just explicitly calling constructor for readability. Should I revert this change?
src/expr.cpp
Outdated
@@ -838,17 +845,31 @@ int ExprParser::Precedence(Token t) { | |||
|
|||
bool ExprParser::Reduce(std::string *error) { | |||
Token a = PopOperand(error); | |||
if(error != NULL && !error->empty()) return false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if((error != NULL) && (!error->empty()))
for clarity. An two more places below
src/mouse.cpp
Outdated
@@ -1429,32 +1465,71 @@ void GraphicsWindow::EditControlDone(const std::string &s) { | |||
c->comment = s; | |||
return; | |||
} | |||
|
|||
// after a user finishes editing an expression in a constraint that has a different scaling_to_base, we can assume that they intend for the expression to be in the currently selected units | |||
if(c->expr_scaling_to_base != SS.MmPerUnit()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this redundant? See 1506 below.
It may also be wrong - if editing the "relation" does not succeed in the "equals checks" below.
} | ||
|
||
switch(c->type) { | ||
case Constraint::Type::RELATION: | ||
// on relation, expr_scaling_to_base should be ignored, since the scaling is done on constraints that directly constrain some entity | ||
c->expr_scaling_to_base = 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But 1506?
sorry folks! I got busy with work and was at hackathon but will be reviewing this ASAP. |
@ruevs addressed some of the items in your review & asked some follow-up questions... will commit review changes soon |
Edit parameterized constraints in the GUI, (instead of their computed values) and save those constraints to the file.
Continues work on #77 on the parameters branch
With these changes, solvespace can still open files created by older versions. Older versions cannot open files created by this version, however.