Rewrite equations generated for curve-line tangent constraints (in 3d).

This has the same motivations and implementation as in 3d6d873.
This commit is contained in:
EvilSpirit 2016-11-27 14:59:47 +07:00 committed by whitequark
parent 3d6d873906
commit 78d141cf9c
4 changed files with 60 additions and 39 deletions

View File

@ -41,7 +41,8 @@ Other new features:
Bugs fixed:
* A point in 3d constrained to any line whose length is free no longer
causes the line length to collapse.
* Lines in 3d constrained parallel are solved in a more robust way.
* Curve-line constraints (in 3d) and parallel constraints (in 3d)
are more robust.
2.3
---

View File

@ -217,7 +217,8 @@ void ConstraintBase::AddEq(IdList<Equation,hEquation> *l, const ExprVector &v,
void ConstraintBase::Generate(IdList<Param,hParam> *l) const {
switch(type) {
case Type::PARALLEL:
// Only introduce a new parameter when operating in 3d
case Type::CUBIC_LINE_TANGENT:
// Add new parameter only when we operate in 3d space
if(workplane.v != EntityBase::FREE_IN_3D.v) break;
// fallthrough
case Type::PT_ON_LINE: {
@ -720,8 +721,8 @@ void ConstraintBase::GenerateEquations(IdList<Equation,hEquation> *l,
ExprVector b = line->VectorGetExprs();
if(workplane.v == EntityBase::FREE_IN_3D.v) {
AddEq(l, VectorsParallel(0, a, b), 0);
AddEq(l, VectorsParallel(1, a, b), 1);
ExprVector eq = VectorsParallel3d(a, b, h.param(0));
AddEq(l, eq);
} else {
EntityBase *w = SK.GetEntity(workplane);
ExprVector wn = w->Normal()->NormalExprsN();

View File

@ -564,56 +564,75 @@ void SolveSpaceUI::UpgradeLegacyData() {
}
}
// Constraints saved in versions prior to 3.0 never had any params;
// version 3.0 introduced params to constraints to avoid the hairy ball problem,
// so force them where they belong.
IdList<Param,hParam> oldParam = {};
SK.param.DeepCopyInto(&oldParam);
SS.GenerateAll(SolveSpaceUI::Generate::REGEN);
auto AllParamsExistFor = [&](const Constraint &c) {
IdList<Param,hParam> param = {};
c.Generate(&param);
bool allParamsExist = true;
for(Param &p : param) {
if(oldParam.FindByIdNoOops(p.h) != NULL) continue;
allParamsExist = false;
break;
}
param.Clear();
return allParamsExist;
};
for(Constraint &c : SK.constraint) {
switch(c.type) {
case Constraint::Type::PT_ON_LINE: {
IdList<Param,hParam> param = {};
c.Generate(&param);
bool allParamsExist = true;
for(Param &p : param) {
if(oldParam.FindByIdNoOops(p.h) != NULL) continue;
allParamsExist = false;
}
param.Clear();
if(AllParamsExistFor(c)) continue;
if(!allParamsExist) {
EntityBase *eln = SK.GetEntity(c.entityA);
EntityBase *ea = SK.GetEntity(eln->point[0]);
EntityBase *eb = SK.GetEntity(eln->point[1]);
EntityBase *ep = SK.GetEntity(c.ptA);
EntityBase *eln = SK.GetEntity(c.entityA);
EntityBase *ea = SK.GetEntity(eln->point[0]);
EntityBase *eb = SK.GetEntity(eln->point[1]);
EntityBase *ep = SK.GetEntity(c.ptA);
ExprVector exp = ep->PointGetExprsInWorkplane(c.workplane);
ExprVector exa = ea->PointGetExprsInWorkplane(c.workplane);
ExprVector exb = eb->PointGetExprsInWorkplane(c.workplane);
ExprVector exba = exb.Minus(exa);
Param *p = SK.GetParam(c.h.param(0));
p->val = exba.Dot(exp.Minus(exa))->Eval() / exba.Dot(exba)->Eval();
ExprVector exp = ep->PointGetExprsInWorkplane(c.workplane);
ExprVector exa = ea->PointGetExprsInWorkplane(c.workplane);
ExprVector exb = eb->PointGetExprsInWorkplane(c.workplane);
ExprVector exba = exb.Minus(exa);
Param *p = SK.GetParam(c.h.param(0));
p->val = exba.Dot(exp.Minus(exa))->Eval() / exba.Dot(exba)->Eval();
break;
}
case Constraint::Type::CUBIC_LINE_TANGENT: {
if(AllParamsExistFor(c)) continue;
EntityBase *cubic = SK.GetEntity(c.entityA);
EntityBase *line = SK.GetEntity(c.entityB);
ExprVector a;
if(c.other) {
a = cubic->CubicGetFinishTangentExprs();
} else {
a = cubic->CubicGetStartTangentExprs();
}
ExprVector b = line->VectorGetExprs();
Param *param = SK.GetParam(c.h.param(0));
param->val = a.Dot(b)->Eval() / b.Dot(b)->Eval();
break;
}
case Constraint::Type::PARALLEL: {
IdList<Param,hParam> param = {};
c.Generate(&param);
bool allParamsExist = true;
for(Param &p : param) {
if(oldParam.FindByIdNoOops(p.h) != NULL) continue;
allParamsExist = false;
}
param.Clear();
if(AllParamsExistFor(c)) continue;
if(!allParamsExist) {
EntityBase *ea = SK.GetEntity(c.entityA),
*eb = SK.GetEntity(c.entityB);
ExprVector a = ea->VectorGetExprsInWorkplane(c.workplane);
ExprVector b = eb->VectorGetExprsInWorkplane(c.workplane);
EntityBase *ea = SK.GetEntity(c.entityA),
*eb = SK.GetEntity(c.entityB);
ExprVector a = ea->VectorGetExprsInWorkplane(c.workplane);
ExprVector b = eb->VectorGetExprsInWorkplane(c.workplane);
Param *param = SK.GetParam(c.h.param(0));
param->val = a.Dot(b)->Eval() / b.Dot(b)->Eval();
}
Param *param = SK.GetParam(c.h.param(0));
param->val = a.Dot(b)->Eval() / b.Dot(b)->Eval();
break;
}