diff --git a/src/sketch.h b/src/sketch.h
index 812375f..dc5a19e 100644
--- a/src/sketch.h
+++ b/src/sketch.h
@@ -622,7 +622,7 @@ public:
bool free;
// Used only in the solver
- hParam substd;
+ Param *substd;
static const hParam NO_PARAM;
diff --git a/src/solvespace.h b/src/solvespace.h
index 7305b8a..934a506 100644
--- a/src/solvespace.h
+++ b/src/solvespace.h
@@ -291,6 +291,9 @@ public:
bool andFindBad = false, bool andFindFree = false);
void Clear();
+ Param *GetLastParamSubstitution(Param *p);
+ void SubstituteParamsByLast(Expr *e);
+ void SortSubstitutionByDragged(Param *p);
};
#include "ttf.h"
diff --git a/src/system.cpp b/src/system.cpp
index 1119c34..71712b7 100644
--- a/src/system.cpp
+++ b/src/system.cpp
@@ -85,6 +85,60 @@ bool System::IsDragged(hParam p) {
return false;
}
+Param *System::GetLastParamSubstitution(Param *p) {
+ Param *current = p;
+ while(current->substd != NULL) {
+ current = current->substd;
+ if(current == p) {
+ // Break the loop
+ current->substd = NULL;
+ break;
+ }
+ }
+ return current;
+}
+
+void System::SortSubstitutionByDragged(Param *p) {
+ std::vector subsParams;
+ Param *by = NULL;
+ Param *current = p;
+ while(current != NULL) {
+ subsParams.push_back(current);
+ if(IsDragged(current->h)) {
+ by = current;
+ }
+ current = current->substd;
+ }
+ if(by == NULL) by = p;
+ for(Param *p : subsParams) {
+ if(p == by) continue;
+ p->substd = by;
+ p->tag = VAR_SUBSTITUTED;
+ }
+ by->substd = NULL;
+ by->tag = 0;
+}
+
+void System::SubstituteParamsByLast(Expr *e) {
+ ssassert(e->op != Expr::Op::PARAM_PTR, "Expected an expression that refer to params via handles");
+
+ if(e->op == Expr::Op::PARAM) {
+ Param *p = param.FindByIdNoOops(e->parh);
+ if(p != NULL) {
+ Param *s = GetLastParamSubstitution(p);
+ if(s != NULL) {
+ e->parh = s->h;
+ }
+ }
+ } else {
+ int c = e->Children();
+ if(c >= 1) {
+ SubstituteParamsByLast(e->a);
+ if(c >= 2) SubstituteParamsByLast(e->b);
+ }
+ }
+}
+
void System::SolveBySubstitution() {
for(auto &teq : eq) {
Expr *tex = teq.e;
@@ -102,26 +156,48 @@ void System::SolveBySubstitution() {
continue;
}
- if(IsDragged(a)) {
- // A is being dragged, so A should stay, and B should go
- std::swap(a, b);
+ if(a.v == b.v) {
+ teq.tag = EQ_SUBSTITUTED;
+ continue;
}
- for(auto &req : eq) {
- req.e->Substitute(a, b); // A becomes B, B unchanged
- }
- for(auto &rp : param) {
- if(rp.substd == a) {
- rp.substd = b;
+ Param *pa = param.FindById(a);
+ Param *pb = param.FindById(b);
+
+ // Take the last substitution of parameter a
+ // This resulted in creation of substitution chains
+ Param *last = GetLastParamSubstitution(pa);
+ last->substd = pb;
+ last->tag = VAR_SUBSTITUTED;
+
+ if(pb->substd != NULL) {
+ // Break the loops
+ GetLastParamSubstitution(pb);
+ // if b loop was broken
+ if(pb->substd == NULL) {
+ // Clear substitution
+ pb->tag = 0;
}
}
- Param *ptr = param.FindById(a);
- ptr->tag = VAR_SUBSTITUTED;
- ptr->substd = b;
-
teq.tag = EQ_SUBSTITUTED;
}
}
+
+ //
+ for(Param &p : param) {
+ SortSubstitutionByDragged(&p);
+ }
+
+ // Substitute all the equations
+ for(auto &req : eq) {
+ SubstituteParamsByLast(req.e);
+ }
+
+ // Substitute all the parameters with last substitutions
+ for(auto &p : param) {
+ if(p.substd == NULL) continue;
+ p.substd = GetLastParamSubstitution(p.substd);
+ }
}
//-----------------------------------------------------------------------------
@@ -485,7 +561,7 @@ SolveResult System::Solve(Group *g, int *rank, int *dof, List *bad,
for(auto &p : param) {
double val;
if(p.tag == VAR_SUBSTITUTED) {
- val = param.FindById(p.substd)->val;
+ val = p.substd->val;
} else {
val = p.val;
}