diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e99b3e..80843a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 --- diff --git a/src/constrainteq.cpp b/src/constrainteq.cpp index 4b6af81..398c99c 100644 --- a/src/constrainteq.cpp +++ b/src/constrainteq.cpp @@ -217,7 +217,8 @@ void ConstraintBase::AddEq(IdList *l, const ExprVector &v, void ConstraintBase::Generate(IdList *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 *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(); diff --git a/src/file.cpp b/src/file.cpp index 7caae9f..1a16618 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -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 oldParam = {}; SK.param.DeepCopyInto(&oldParam); SS.GenerateAll(SolveSpaceUI::Generate::REGEN); + + auto AllParamsExistFor = [&](const Constraint &c) { + IdList param = {}; + c.Generate(¶m); + 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 = {}; - c.Generate(¶m); - 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 = {}; - c.Generate(¶m); - 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; } diff --git a/test/constraint/cubic_line_tangent/free_in_3d.slvs b/test/constraint/cubic_line_tangent/free_in_3d.slvs index a20030d..19f9658 100644 Binary files a/test/constraint/cubic_line_tangent/free_in_3d.slvs and b/test/constraint/cubic_line_tangent/free_in_3d.slvs differ