The constraint solver now compiles as a library, and I have a
little test app that links against it. I still need to polish a few things, but this is more or less as it should be. [git-p4: depot-paths = "//depot/solvespace/": change = 1944]solver
parent
11e4c7f5d9
commit
4d742a5777
1
Makefile
1
Makefile
|
@ -10,6 +10,7 @@ OBJDIR = obj
|
||||||
FREEZE = $(OBJDIR)\freeze.obj
|
FREEZE = $(OBJDIR)\freeze.obj
|
||||||
|
|
||||||
W32OBJS = $(OBJDIR)\w32main.obj \
|
W32OBJS = $(OBJDIR)\w32main.obj \
|
||||||
|
$(OBJDIR)\w32util.obj \
|
||||||
|
|
||||||
SSOBJS = $(OBJDIR)\solvespace.obj \
|
SSOBJS = $(OBJDIR)\solvespace.obj \
|
||||||
$(OBJDIR)\textwin.obj \
|
$(OBJDIR)\textwin.obj \
|
||||||
|
|
|
@ -387,7 +387,7 @@ void Constraint::MenuConstrain(int id) {
|
||||||
Vector pa = SK.GetEntity(c.ptA)->PointGetNum();
|
Vector pa = SK.GetEntity(c.ptA)->PointGetNum();
|
||||||
Vector pb = SK.GetEntity(c.ptB)->PointGetNum();
|
Vector pb = SK.GetEntity(c.ptB)->PointGetNum();
|
||||||
Vector dp = pa.Minus(pb);
|
Vector dp = pa.Minus(pb);
|
||||||
Entity *norm = SK.GetEntity(c.workplane)->Normal();;
|
EntityBase *norm = SK.GetEntity(c.workplane)->Normal();;
|
||||||
Vector u = norm->NormalU(), v = norm->NormalV();
|
Vector u = norm->NormalU(), v = norm->NormalV();
|
||||||
if(fabs(dp.Dot(u)) > fabs(dp.Dot(v))) {
|
if(fabs(dp.Dot(u)) > fabs(dp.Dot(v))) {
|
||||||
c.type = SYMMETRIC_HORIZ;
|
c.type = SYMMETRIC_HORIZ;
|
||||||
|
|
160
constrainteq.cpp
160
constrainteq.cpp
|
@ -33,13 +33,13 @@ Expr *ConstraintBase::VectorsParallel(int eq, ExprVector a, ExprVector b) {
|
||||||
|
|
||||||
Expr *ConstraintBase::PointLineDistance(hEntity wrkpl, hEntity hpt, hEntity hln)
|
Expr *ConstraintBase::PointLineDistance(hEntity wrkpl, hEntity hpt, hEntity hln)
|
||||||
{
|
{
|
||||||
Entity *ln = SK.GetEntity(hln);
|
EntityBase *ln = SK.GetEntity(hln);
|
||||||
Entity *a = SK.GetEntity(ln->point[0]);
|
EntityBase *a = SK.GetEntity(ln->point[0]);
|
||||||
Entity *b = SK.GetEntity(ln->point[1]);
|
EntityBase *b = SK.GetEntity(ln->point[1]);
|
||||||
|
|
||||||
Entity *p = SK.GetEntity(hpt);
|
EntityBase *p = SK.GetEntity(hpt);
|
||||||
|
|
||||||
if(wrkpl.v == Entity::FREE_IN_3D.v) {
|
if(wrkpl.v == EntityBase::FREE_IN_3D.v) {
|
||||||
ExprVector ep = p->PointGetExprs();
|
ExprVector ep = p->PointGetExprs();
|
||||||
|
|
||||||
ExprVector ea = a->PointGetExprs();
|
ExprVector ea = a->PointGetExprs();
|
||||||
|
@ -76,11 +76,11 @@ Expr *ConstraintBase::PointPlaneDistance(ExprVector p, hEntity hpl) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr *ConstraintBase::Distance(hEntity wrkpl, hEntity hpa, hEntity hpb) {
|
Expr *ConstraintBase::Distance(hEntity wrkpl, hEntity hpa, hEntity hpb) {
|
||||||
Entity *pa = SK.GetEntity(hpa);
|
EntityBase *pa = SK.GetEntity(hpa);
|
||||||
Entity *pb = SK.GetEntity(hpb);
|
EntityBase *pb = SK.GetEntity(hpb);
|
||||||
if(!(pa->IsPoint() && pb->IsPoint())) oops();
|
if(!(pa->IsPoint() && pb->IsPoint())) oops();
|
||||||
|
|
||||||
if(wrkpl.v == Entity::FREE_IN_3D.v) {
|
if(wrkpl.v == EntityBase::FREE_IN_3D.v) {
|
||||||
// This is true distance
|
// This is true distance
|
||||||
ExprVector ea, eb, eab;
|
ExprVector ea, eb, eab;
|
||||||
ea = pa->PointGetExprs();
|
ea = pa->PointGetExprs();
|
||||||
|
@ -109,11 +109,11 @@ Expr *ConstraintBase::Distance(hEntity wrkpl, hEntity hpa, hEntity hpb) {
|
||||||
Expr *ConstraintBase::DirectionCosine(hEntity wrkpl,
|
Expr *ConstraintBase::DirectionCosine(hEntity wrkpl,
|
||||||
ExprVector ae, ExprVector be)
|
ExprVector ae, ExprVector be)
|
||||||
{
|
{
|
||||||
if(wrkpl.v == Entity::FREE_IN_3D.v) {
|
if(wrkpl.v == EntityBase::FREE_IN_3D.v) {
|
||||||
Expr *mags = (ae.Magnitude())->Times(be.Magnitude());
|
Expr *mags = (ae.Magnitude())->Times(be.Magnitude());
|
||||||
return (ae.Dot(be))->Div(mags);
|
return (ae.Dot(be))->Div(mags);
|
||||||
} else {
|
} else {
|
||||||
Entity *w = SK.GetEntity(wrkpl);
|
EntityBase *w = SK.GetEntity(wrkpl);
|
||||||
ExprVector u = w->Normal()->NormalExprsU();
|
ExprVector u = w->Normal()->NormalExprsU();
|
||||||
ExprVector v = w->Normal()->NormalExprsV();
|
ExprVector v = w->Normal()->NormalExprsV();
|
||||||
Expr *ua = u.Dot(ae);
|
Expr *ua = u.Dot(ae);
|
||||||
|
@ -130,7 +130,7 @@ Expr *ConstraintBase::DirectionCosine(hEntity wrkpl,
|
||||||
ExprVector ConstraintBase::PointInThreeSpace(hEntity workplane,
|
ExprVector ConstraintBase::PointInThreeSpace(hEntity workplane,
|
||||||
Expr *u, Expr *v)
|
Expr *u, Expr *v)
|
||||||
{
|
{
|
||||||
Entity *w = SK.GetEntity(workplane);
|
EntityBase *w = SK.GetEntity(workplane);
|
||||||
|
|
||||||
ExprVector ub = w->Normal()->NormalExprsU();
|
ExprVector ub = w->Normal()->NormalExprsU();
|
||||||
ExprVector vb = w->Normal()->NormalExprsV();
|
ExprVector vb = w->Normal()->NormalExprsV();
|
||||||
|
@ -144,7 +144,7 @@ void ConstraintBase::ModifyToSatisfy(void) {
|
||||||
Vector a = SK.GetEntity(entityA)->VectorGetNum();
|
Vector a = SK.GetEntity(entityA)->VectorGetNum();
|
||||||
Vector b = SK.GetEntity(entityB)->VectorGetNum();
|
Vector b = SK.GetEntity(entityB)->VectorGetNum();
|
||||||
if(other) a = a.ScaledBy(-1);
|
if(other) a = a.ScaledBy(-1);
|
||||||
if(workplane.v != Entity::FREE_IN_3D.v) {
|
if(workplane.v != EntityBase::FREE_IN_3D.v) {
|
||||||
a = a.ProjectVectorInto(workplane);
|
a = a.ProjectVectorInto(workplane);
|
||||||
b = b.ProjectVectorInto(workplane);
|
b = b.ProjectVectorInto(workplane);
|
||||||
}
|
}
|
||||||
|
@ -202,7 +202,7 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
||||||
|
|
||||||
case PT_FACE_DISTANCE: {
|
case PT_FACE_DISTANCE: {
|
||||||
ExprVector pt = SK.GetEntity(ptA)->PointGetExprs();
|
ExprVector pt = SK.GetEntity(ptA)->PointGetExprs();
|
||||||
Entity *f = SK.GetEntity(entityA);
|
EntityBase *f = SK.GetEntity(entityA);
|
||||||
ExprVector p0 = f->FaceGetPointExprs();
|
ExprVector p0 = f->FaceGetPointExprs();
|
||||||
ExprVector n = f->FaceGetNormalExprs();
|
ExprVector n = f->FaceGetNormalExprs();
|
||||||
AddEq(l, (pt.Minus(p0)).Dot(n)->Minus(exA), 0);
|
AddEq(l, (pt.Minus(p0)).Dot(n)->Minus(exA), 0);
|
||||||
|
@ -210,8 +210,8 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case EQUAL_LENGTH_LINES: {
|
case EQUAL_LENGTH_LINES: {
|
||||||
Entity *a = SK.GetEntity(entityA);
|
EntityBase *a = SK.GetEntity(entityA);
|
||||||
Entity *b = SK.GetEntity(entityB);
|
EntityBase *b = SK.GetEntity(entityB);
|
||||||
AddEq(l, Distance(workplane, a->point[0], a->point[1])->Minus(
|
AddEq(l, Distance(workplane, a->point[0], a->point[1])->Minus(
|
||||||
Distance(workplane, b->point[0], b->point[1])), 0);
|
Distance(workplane, b->point[0], b->point[1])), 0);
|
||||||
break;
|
break;
|
||||||
|
@ -220,7 +220,7 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
||||||
// These work on distance squared, since the pt-line distances are
|
// These work on distance squared, since the pt-line distances are
|
||||||
// signed, and we want the absolute value.
|
// signed, and we want the absolute value.
|
||||||
case EQ_LEN_PT_LINE_D: {
|
case EQ_LEN_PT_LINE_D: {
|
||||||
Entity *forLen = SK.GetEntity(entityA);
|
EntityBase *forLen = SK.GetEntity(entityA);
|
||||||
Expr *d1 = Distance(workplane, forLen->point[0], forLen->point[1]);
|
Expr *d1 = Distance(workplane, forLen->point[0], forLen->point[1]);
|
||||||
Expr *d2 = PointLineDistance(workplane, ptA, entityB);
|
Expr *d2 = PointLineDistance(workplane, ptA, entityB);
|
||||||
AddEq(l, (d1->Square())->Minus(d2->Square()), 0);
|
AddEq(l, (d1->Square())->Minus(d2->Square()), 0);
|
||||||
|
@ -234,8 +234,8 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case LENGTH_RATIO: {
|
case LENGTH_RATIO: {
|
||||||
Entity *a = SK.GetEntity(entityA);
|
EntityBase *a = SK.GetEntity(entityA);
|
||||||
Entity *b = SK.GetEntity(entityB);
|
EntityBase *b = SK.GetEntity(entityB);
|
||||||
Expr *la = Distance(workplane, a->point[0], a->point[1]);
|
Expr *la = Distance(workplane, a->point[0], a->point[1]);
|
||||||
Expr *lb = Distance(workplane, b->point[0], b->point[1]);
|
Expr *lb = Distance(workplane, b->point[0], b->point[1]);
|
||||||
AddEq(l, (la->Div(lb))->Minus(exA), 0);
|
AddEq(l, (la->Div(lb))->Minus(exA), 0);
|
||||||
|
@ -243,23 +243,23 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case DIAMETER: {
|
case DIAMETER: {
|
||||||
Entity *circle = SK.GetEntity(entityA);
|
EntityBase *circle = SK.GetEntity(entityA);
|
||||||
Expr *r = circle->CircleGetRadiusExpr();
|
Expr *r = circle->CircleGetRadiusExpr();
|
||||||
AddEq(l, (r->Times(Expr::From(2)))->Minus(exA), 0);
|
AddEq(l, (r->Times(Expr::From(2)))->Minus(exA), 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case EQUAL_RADIUS: {
|
case EQUAL_RADIUS: {
|
||||||
Entity *c1 = SK.GetEntity(entityA);
|
EntityBase *c1 = SK.GetEntity(entityA);
|
||||||
Entity *c2 = SK.GetEntity(entityB);
|
EntityBase *c2 = SK.GetEntity(entityB);
|
||||||
AddEq(l, (c1->CircleGetRadiusExpr())->Minus(
|
AddEq(l, (c1->CircleGetRadiusExpr())->Minus(
|
||||||
c2->CircleGetRadiusExpr()), 0);
|
c2->CircleGetRadiusExpr()), 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case EQUAL_LINE_ARC_LEN: {
|
case EQUAL_LINE_ARC_LEN: {
|
||||||
Entity *line = SK.GetEntity(entityA),
|
EntityBase *line = SK.GetEntity(entityA),
|
||||||
*arc = SK.GetEntity(entityB);
|
*arc = SK.GetEntity(entityB);
|
||||||
|
|
||||||
// Get the line length
|
// Get the line length
|
||||||
ExprVector l0 = SK.GetEntity(line->point[0])->PointGetExprs(),
|
ExprVector l0 = SK.GetEntity(line->point[0])->PointGetExprs(),
|
||||||
|
@ -267,9 +267,9 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
||||||
Expr *ll = (l1.Minus(l0)).Magnitude();
|
Expr *ll = (l1.Minus(l0)).Magnitude();
|
||||||
|
|
||||||
// And get the arc radius, and the cosine of its angle
|
// And get the arc radius, and the cosine of its angle
|
||||||
Entity *ao = SK.GetEntity(arc->point[0]),
|
EntityBase *ao = SK.GetEntity(arc->point[0]),
|
||||||
*as = SK.GetEntity(arc->point[1]),
|
*as = SK.GetEntity(arc->point[1]),
|
||||||
*af = SK.GetEntity(arc->point[2]);
|
*af = SK.GetEntity(arc->point[2]);
|
||||||
|
|
||||||
ExprVector aos = (as->PointGetExprs()).Minus(ao->PointGetExprs()),
|
ExprVector aos = (as->PointGetExprs()).Minus(ao->PointGetExprs()),
|
||||||
aof = (af->PointGetExprs()).Minus(ao->PointGetExprs());
|
aof = (af->PointGetExprs()).Minus(ao->PointGetExprs());
|
||||||
|
@ -301,9 +301,9 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case POINTS_COINCIDENT: {
|
case POINTS_COINCIDENT: {
|
||||||
Entity *a = SK.GetEntity(ptA);
|
EntityBase *a = SK.GetEntity(ptA);
|
||||||
Entity *b = SK.GetEntity(ptB);
|
EntityBase *b = SK.GetEntity(ptB);
|
||||||
if(workplane.v == Entity::FREE_IN_3D.v) {
|
if(workplane.v == EntityBase::FREE_IN_3D.v) {
|
||||||
ExprVector pa = a->PointGetExprs();
|
ExprVector pa = a->PointGetExprs();
|
||||||
ExprVector pb = b->PointGetExprs();
|
ExprVector pb = b->PointGetExprs();
|
||||||
AddEq(l, pa.x->Minus(pb.x), 0);
|
AddEq(l, pa.x->Minus(pb.x), 0);
|
||||||
|
@ -329,7 +329,7 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
||||||
case PT_ON_FACE: {
|
case PT_ON_FACE: {
|
||||||
// a plane, n dot (p - p0) = 0
|
// a plane, n dot (p - p0) = 0
|
||||||
ExprVector p = SK.GetEntity(ptA)->PointGetExprs();
|
ExprVector p = SK.GetEntity(ptA)->PointGetExprs();
|
||||||
Entity *f = SK.GetEntity(entityA);
|
EntityBase *f = SK.GetEntity(entityA);
|
||||||
ExprVector p0 = f->FaceGetPointExprs();
|
ExprVector p0 = f->FaceGetPointExprs();
|
||||||
ExprVector n = f->FaceGetNormalExprs();
|
ExprVector n = f->FaceGetNormalExprs();
|
||||||
AddEq(l, (p.Minus(p0)).Dot(n), 0);
|
AddEq(l, (p.Minus(p0)).Dot(n), 0);
|
||||||
|
@ -337,11 +337,11 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case PT_ON_LINE:
|
case PT_ON_LINE:
|
||||||
if(workplane.v == Entity::FREE_IN_3D.v) {
|
if(workplane.v == EntityBase::FREE_IN_3D.v) {
|
||||||
Entity *ln = SK.GetEntity(entityA);
|
EntityBase *ln = SK.GetEntity(entityA);
|
||||||
Entity *a = SK.GetEntity(ln->point[0]);
|
EntityBase *a = SK.GetEntity(ln->point[0]);
|
||||||
Entity *b = SK.GetEntity(ln->point[1]);
|
EntityBase *b = SK.GetEntity(ln->point[1]);
|
||||||
Entity *p = SK.GetEntity(ptA);
|
EntityBase *p = SK.GetEntity(ptA);
|
||||||
|
|
||||||
ExprVector ep = p->PointGetExprs();
|
ExprVector ep = p->PointGetExprs();
|
||||||
ExprVector ea = a->PointGetExprs();
|
ExprVector ea = a->PointGetExprs();
|
||||||
|
@ -370,10 +370,10 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
||||||
|
|
||||||
case PT_ON_CIRCLE: {
|
case PT_ON_CIRCLE: {
|
||||||
// This actually constrains the point to lie on the cylinder.
|
// This actually constrains the point to lie on the cylinder.
|
||||||
Entity *circle = SK.GetEntity(entityA);
|
EntityBase *circle = SK.GetEntity(entityA);
|
||||||
ExprVector center = SK.GetEntity(circle->point[0])->PointGetExprs();
|
ExprVector center = SK.GetEntity(circle->point[0])->PointGetExprs();
|
||||||
ExprVector pt = SK.GetEntity(ptA)->PointGetExprs();
|
ExprVector pt = SK.GetEntity(ptA)->PointGetExprs();
|
||||||
Entity *normal = SK.GetEntity(circle->normal);
|
EntityBase *normal = SK.GetEntity(circle->normal);
|
||||||
ExprVector u = normal->NormalExprsU(),
|
ExprVector u = normal->NormalExprsU(),
|
||||||
v = normal->NormalExprsV();
|
v = normal->NormalExprsV();
|
||||||
|
|
||||||
|
@ -388,8 +388,8 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case AT_MIDPOINT:
|
case AT_MIDPOINT:
|
||||||
if(workplane.v == Entity::FREE_IN_3D.v) {
|
if(workplane.v == EntityBase::FREE_IN_3D.v) {
|
||||||
Entity *ln = SK.GetEntity(entityA);
|
EntityBase *ln = SK.GetEntity(entityA);
|
||||||
ExprVector a = SK.GetEntity(ln->point[0])->PointGetExprs();
|
ExprVector a = SK.GetEntity(ln->point[0])->PointGetExprs();
|
||||||
ExprVector b = SK.GetEntity(ln->point[1])->PointGetExprs();
|
ExprVector b = SK.GetEntity(ln->point[1])->PointGetExprs();
|
||||||
ExprVector m = (a.Plus(b)).ScaledBy(Expr::From(0.5));
|
ExprVector m = (a.Plus(b)).ScaledBy(Expr::From(0.5));
|
||||||
|
@ -403,9 +403,9 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
||||||
AddEq(l, PointPlaneDistance(m, entityB), 0);
|
AddEq(l, PointPlaneDistance(m, entityB), 0);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Entity *ln = SK.GetEntity(entityA);
|
EntityBase *ln = SK.GetEntity(entityA);
|
||||||
Entity *a = SK.GetEntity(ln->point[0]);
|
EntityBase *a = SK.GetEntity(ln->point[0]);
|
||||||
Entity *b = SK.GetEntity(ln->point[1]);
|
EntityBase *b = SK.GetEntity(ln->point[1]);
|
||||||
|
|
||||||
Expr *au, *av, *bu, *bv;
|
Expr *au, *av, *bu, *bv;
|
||||||
a->PointGetExprsInWorkplane(workplane, &au, &av);
|
a->PointGetExprsInWorkplane(workplane, &au, &av);
|
||||||
|
@ -414,7 +414,7 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
||||||
Expr *mv = Expr::From(0.5)->Times(av->Plus(bv));
|
Expr *mv = Expr::From(0.5)->Times(av->Plus(bv));
|
||||||
|
|
||||||
if(ptA.v) {
|
if(ptA.v) {
|
||||||
Entity *p = SK.GetEntity(ptA);
|
EntityBase *p = SK.GetEntity(ptA);
|
||||||
Expr *pu, *pv;
|
Expr *pu, *pv;
|
||||||
p->PointGetExprsInWorkplane(workplane, &pu, &pv);
|
p->PointGetExprsInWorkplane(workplane, &pu, &pv);
|
||||||
AddEq(l, pu->Minus(mu), 0);
|
AddEq(l, pu->Minus(mu), 0);
|
||||||
|
@ -427,10 +427,10 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SYMMETRIC:
|
case SYMMETRIC:
|
||||||
if(workplane.v == Entity::FREE_IN_3D.v) {
|
if(workplane.v == EntityBase::FREE_IN_3D.v) {
|
||||||
Entity *plane = SK.GetEntity(entityA);
|
EntityBase *plane = SK.GetEntity(entityA);
|
||||||
Entity *ea = SK.GetEntity(ptA);
|
EntityBase *ea = SK.GetEntity(ptA);
|
||||||
Entity *eb = SK.GetEntity(ptB);
|
EntityBase *eb = SK.GetEntity(ptB);
|
||||||
ExprVector a = ea->PointGetExprs();
|
ExprVector a = ea->PointGetExprs();
|
||||||
ExprVector b = eb->PointGetExprs();
|
ExprVector b = eb->PointGetExprs();
|
||||||
|
|
||||||
|
@ -447,9 +447,9 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
||||||
AddEq(l, au->Minus(bu), 1);
|
AddEq(l, au->Minus(bu), 1);
|
||||||
AddEq(l, av->Minus(bv), 2);
|
AddEq(l, av->Minus(bv), 2);
|
||||||
} else {
|
} else {
|
||||||
Entity *plane = SK.GetEntity(entityA);
|
EntityBase *plane = SK.GetEntity(entityA);
|
||||||
Entity *a = SK.GetEntity(ptA);
|
EntityBase *a = SK.GetEntity(ptA);
|
||||||
Entity *b = SK.GetEntity(ptB);
|
EntityBase *b = SK.GetEntity(ptB);
|
||||||
|
|
||||||
Expr *au, *av, *bu, *bv;
|
Expr *au, *av, *bu, *bv;
|
||||||
a->PointGetExprsInWorkplane(workplane, &au, &av);
|
a->PointGetExprsInWorkplane(workplane, &au, &av);
|
||||||
|
@ -464,7 +464,7 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
||||||
// to the symmetry pane's normal (i.e., that lies in the
|
// to the symmetry pane's normal (i.e., that lies in the
|
||||||
// plane of symmetry). The line connecting the points is
|
// plane of symmetry). The line connecting the points is
|
||||||
// perpendicular to that constructed vector.
|
// perpendicular to that constructed vector.
|
||||||
Entity *w = SK.GetEntity(workplane);
|
EntityBase *w = SK.GetEntity(workplane);
|
||||||
ExprVector u = w->Normal()->NormalExprsU();
|
ExprVector u = w->Normal()->NormalExprsU();
|
||||||
ExprVector v = w->Normal()->NormalExprsV();
|
ExprVector v = w->Normal()->NormalExprsV();
|
||||||
|
|
||||||
|
@ -479,8 +479,8 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
||||||
|
|
||||||
case SYMMETRIC_HORIZ:
|
case SYMMETRIC_HORIZ:
|
||||||
case SYMMETRIC_VERT: {
|
case SYMMETRIC_VERT: {
|
||||||
Entity *a = SK.GetEntity(ptA);
|
EntityBase *a = SK.GetEntity(ptA);
|
||||||
Entity *b = SK.GetEntity(ptB);
|
EntityBase *b = SK.GetEntity(ptB);
|
||||||
|
|
||||||
Expr *au, *av, *bu, *bv;
|
Expr *au, *av, *bu, *bv;
|
||||||
a->PointGetExprsInWorkplane(workplane, &au, &av);
|
a->PointGetExprsInWorkplane(workplane, &au, &av);
|
||||||
|
@ -497,16 +497,16 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case SYMMETRIC_LINE: {
|
case SYMMETRIC_LINE: {
|
||||||
Entity *pa = SK.GetEntity(ptA);
|
EntityBase *pa = SK.GetEntity(ptA);
|
||||||
Entity *pb = SK.GetEntity(ptB);
|
EntityBase *pb = SK.GetEntity(ptB);
|
||||||
|
|
||||||
Expr *pau, *pav, *pbu, *pbv;
|
Expr *pau, *pav, *pbu, *pbv;
|
||||||
pa->PointGetExprsInWorkplane(workplane, &pau, &pav);
|
pa->PointGetExprsInWorkplane(workplane, &pau, &pav);
|
||||||
pb->PointGetExprsInWorkplane(workplane, &pbu, &pbv);
|
pb->PointGetExprsInWorkplane(workplane, &pbu, &pbv);
|
||||||
|
|
||||||
Entity *ln = SK.GetEntity(entityA);
|
EntityBase *ln = SK.GetEntity(entityA);
|
||||||
Entity *la = SK.GetEntity(ln->point[0]);
|
EntityBase *la = SK.GetEntity(ln->point[0]);
|
||||||
Entity *lb = SK.GetEntity(ln->point[1]);
|
EntityBase *lb = SK.GetEntity(ln->point[1]);
|
||||||
Expr *lau, *lav, *lbu, *lbv;
|
Expr *lau, *lav, *lbu, *lbv;
|
||||||
la->PointGetExprsInWorkplane(workplane, &lau, &lav);
|
la->PointGetExprsInWorkplane(workplane, &lau, &lav);
|
||||||
lb->PointGetExprsInWorkplane(workplane, &lbu, &lbv);
|
lb->PointGetExprsInWorkplane(workplane, &lbu, &lbv);
|
||||||
|
@ -533,15 +533,15 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
||||||
case VERTICAL: {
|
case VERTICAL: {
|
||||||
hEntity ha, hb;
|
hEntity ha, hb;
|
||||||
if(entityA.v) {
|
if(entityA.v) {
|
||||||
Entity *e = SK.GetEntity(entityA);
|
EntityBase *e = SK.GetEntity(entityA);
|
||||||
ha = e->point[0];
|
ha = e->point[0];
|
||||||
hb = e->point[1];
|
hb = e->point[1];
|
||||||
} else {
|
} else {
|
||||||
ha = ptA;
|
ha = ptA;
|
||||||
hb = ptB;
|
hb = ptB;
|
||||||
}
|
}
|
||||||
Entity *a = SK.GetEntity(ha);
|
EntityBase *a = SK.GetEntity(ha);
|
||||||
Entity *b = SK.GetEntity(hb);
|
EntityBase *b = SK.GetEntity(hb);
|
||||||
|
|
||||||
Expr *au, *av, *bu, *bv;
|
Expr *au, *av, *bu, *bv;
|
||||||
a->PointGetExprsInWorkplane(workplane, &au, &av);
|
a->PointGetExprsInWorkplane(workplane, &au, &av);
|
||||||
|
@ -552,10 +552,10 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case SAME_ORIENTATION: {
|
case SAME_ORIENTATION: {
|
||||||
Entity *a = SK.GetEntity(entityA);
|
EntityBase *a = SK.GetEntity(entityA);
|
||||||
Entity *b = SK.GetEntity(entityB);
|
EntityBase *b = SK.GetEntity(entityB);
|
||||||
if(b->group.v != group.v) {
|
if(b->group.v != group.v) {
|
||||||
SWAP(Entity *, a, b);
|
SWAP(EntityBase *, a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
ExprVector au = a->NormalExprsU(),
|
ExprVector au = a->NormalExprsU(),
|
||||||
|
@ -581,8 +581,8 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
||||||
|
|
||||||
case PERPENDICULAR:
|
case PERPENDICULAR:
|
||||||
case ANGLE: {
|
case ANGLE: {
|
||||||
Entity *a = SK.GetEntity(entityA);
|
EntityBase *a = SK.GetEntity(entityA);
|
||||||
Entity *b = SK.GetEntity(entityB);
|
EntityBase *b = SK.GetEntity(entityB);
|
||||||
ExprVector ae = a->VectorGetExprs();
|
ExprVector ae = a->VectorGetExprs();
|
||||||
ExprVector be = b->VectorGetExprs();
|
ExprVector be = b->VectorGetExprs();
|
||||||
if(other) ae = ae.ScaledBy(Expr::From(-1));
|
if(other) ae = ae.ScaledBy(Expr::From(-1));
|
||||||
|
@ -602,10 +602,10 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case EQUAL_ANGLE: {
|
case EQUAL_ANGLE: {
|
||||||
Entity *a = SK.GetEntity(entityA);
|
EntityBase *a = SK.GetEntity(entityA);
|
||||||
Entity *b = SK.GetEntity(entityB);
|
EntityBase *b = SK.GetEntity(entityB);
|
||||||
Entity *c = SK.GetEntity(entityC);
|
EntityBase *c = SK.GetEntity(entityC);
|
||||||
Entity *d = SK.GetEntity(entityD);
|
EntityBase *d = SK.GetEntity(entityD);
|
||||||
ExprVector ae = a->VectorGetExprs();
|
ExprVector ae = a->VectorGetExprs();
|
||||||
ExprVector be = b->VectorGetExprs();
|
ExprVector be = b->VectorGetExprs();
|
||||||
ExprVector ce = c->VectorGetExprs();
|
ExprVector ce = c->VectorGetExprs();
|
||||||
|
@ -621,8 +621,8 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case ARC_LINE_TANGENT: {
|
case ARC_LINE_TANGENT: {
|
||||||
Entity *arc = SK.GetEntity(entityA);
|
EntityBase *arc = SK.GetEntity(entityA);
|
||||||
Entity *line = SK.GetEntity(entityB);
|
EntityBase *line = SK.GetEntity(entityB);
|
||||||
|
|
||||||
ExprVector ac = SK.GetEntity(arc->point[0])->PointGetExprs();
|
ExprVector ac = SK.GetEntity(arc->point[0])->PointGetExprs();
|
||||||
ExprVector ap =
|
ExprVector ap =
|
||||||
|
@ -636,8 +636,8 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case CUBIC_LINE_TANGENT: {
|
case CUBIC_LINE_TANGENT: {
|
||||||
Entity *cubic = SK.GetEntity(entityA);
|
EntityBase *cubic = SK.GetEntity(entityA);
|
||||||
Entity *line = SK.GetEntity(entityB);
|
EntityBase *line = SK.GetEntity(entityB);
|
||||||
|
|
||||||
ExprVector endpoint =
|
ExprVector endpoint =
|
||||||
SK.GetEntity(cubic->point[other ? 3 : 0])->PointGetExprs();
|
SK.GetEntity(cubic->point[other ? 3 : 0])->PointGetExprs();
|
||||||
|
@ -648,11 +648,11 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
||||||
|
|
||||||
ExprVector b = line->VectorGetExprs();
|
ExprVector b = line->VectorGetExprs();
|
||||||
|
|
||||||
if(workplane.v == Entity::FREE_IN_3D.v) {
|
if(workplane.v == EntityBase::FREE_IN_3D.v) {
|
||||||
AddEq(l, VectorsParallel(0, a, b), 0);
|
AddEq(l, VectorsParallel(0, a, b), 0);
|
||||||
AddEq(l, VectorsParallel(1, a, b), 1);
|
AddEq(l, VectorsParallel(1, a, b), 1);
|
||||||
} else {
|
} else {
|
||||||
Entity *w = SK.GetEntity(workplane);
|
EntityBase *w = SK.GetEntity(workplane);
|
||||||
ExprVector wn = w->Normal()->NormalExprsN();
|
ExprVector wn = w->Normal()->NormalExprsN();
|
||||||
AddEq(l, (a.Cross(b)).Dot(wn), 0);
|
AddEq(l, (a.Cross(b)).Dot(wn), 0);
|
||||||
}
|
}
|
||||||
|
@ -660,18 +660,18 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case PARALLEL: {
|
case PARALLEL: {
|
||||||
Entity *ea = SK.GetEntity(entityA), *eb = SK.GetEntity(entityB);
|
EntityBase *ea = SK.GetEntity(entityA), *eb = SK.GetEntity(entityB);
|
||||||
if(eb->group.v != group.v) {
|
if(eb->group.v != group.v) {
|
||||||
SWAP(Entity *, ea, eb);
|
SWAP(EntityBase *, ea, eb);
|
||||||
}
|
}
|
||||||
ExprVector a = ea->VectorGetExprs();
|
ExprVector a = ea->VectorGetExprs();
|
||||||
ExprVector b = eb->VectorGetExprs();
|
ExprVector b = eb->VectorGetExprs();
|
||||||
|
|
||||||
if(workplane.v == Entity::FREE_IN_3D.v) {
|
if(workplane.v == EntityBase::FREE_IN_3D.v) {
|
||||||
AddEq(l, VectorsParallel(0, a, b), 0);
|
AddEq(l, VectorsParallel(0, a, b), 0);
|
||||||
AddEq(l, VectorsParallel(1, a, b), 1);
|
AddEq(l, VectorsParallel(1, a, b), 1);
|
||||||
} else {
|
} else {
|
||||||
Entity *w = SK.GetEntity(workplane);
|
EntityBase *w = SK.GetEntity(workplane);
|
||||||
ExprVector wn = w->Normal()->NormalExprsN();
|
ExprVector wn = w->Normal()->NormalExprsN();
|
||||||
AddEq(l, (a.Cross(b)).Dot(wn), 0);
|
AddEq(l, (a.Cross(b)).Dot(wn), 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -354,7 +354,7 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
|
||||||
r = n.Normal(0);
|
r = n.Normal(0);
|
||||||
d = n.Normal(1);
|
d = n.Normal(1);
|
||||||
} else if(type == PT_IN_PLANE) {
|
} else if(type == PT_IN_PLANE) {
|
||||||
Entity *n = SK.GetEntity(entityA)->Normal();
|
EntityBase *n = SK.GetEntity(entityA)->Normal();
|
||||||
r = n->NormalU();
|
r = n->NormalU();
|
||||||
d = n->NormalV();
|
d = n->NormalV();
|
||||||
} else {
|
} else {
|
||||||
|
@ -434,7 +434,7 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
|
||||||
rn = gn;
|
rn = gn;
|
||||||
ru = gu;
|
ru = gu;
|
||||||
} else {
|
} else {
|
||||||
Entity *normal = SK.GetEntity(workplane)->Normal();
|
EntityBase *normal = SK.GetEntity(workplane)->Normal();
|
||||||
rn = normal->NormalN();
|
rn = normal->NormalN();
|
||||||
ru = normal->NormalV(); // ru meaning r_up, not u/v
|
ru = normal->NormalV(); // ru meaning r_up, not u/v
|
||||||
}
|
}
|
||||||
|
@ -485,7 +485,7 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
|
||||||
v = gu;
|
v = gu;
|
||||||
n = gn;
|
n = gn;
|
||||||
} else {
|
} else {
|
||||||
Entity *wn = SK.GetEntity(workplane)->Normal();
|
EntityBase *wn = SK.GetEntity(workplane)->Normal();
|
||||||
u = wn->NormalU();
|
u = wn->NormalU();
|
||||||
v = wn->NormalV();
|
v = wn->NormalV();
|
||||||
n = wn->NormalN();
|
n = wn->NormalN();
|
||||||
|
|
|
@ -173,6 +173,30 @@ bool Entity::IsVisible(void) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Entity::CalculateNumerical(bool forExport) {
|
||||||
|
if(IsPoint()) actPoint = PointGetNum();
|
||||||
|
if(IsNormal()) actNormal = NormalGetNum();
|
||||||
|
if(type == DISTANCE || type == DISTANCE_N_COPY) {
|
||||||
|
actDistance = DistanceGetNum();
|
||||||
|
}
|
||||||
|
if(IsFace()) {
|
||||||
|
actPoint = FaceGetPointNum();
|
||||||
|
Vector n = FaceGetNormalNum();
|
||||||
|
actNormal = Quaternion::From(0, n.x, n.y, n.z);
|
||||||
|
}
|
||||||
|
if(forExport) {
|
||||||
|
// Visibility in copied import entities follows source file
|
||||||
|
actVisible = IsVisible();
|
||||||
|
} else {
|
||||||
|
// Copied entities within a file are always visible
|
||||||
|
actVisible = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Entity::PointIsFromReferences(void) {
|
||||||
|
return h.request().IsFromReferences();
|
||||||
|
}
|
||||||
|
|
||||||
void Entity::GenerateBezierCurves(SBezierList *sbl) {
|
void Entity::GenerateBezierCurves(SBezierList *sbl) {
|
||||||
SBezier sb;
|
SBezier sb;
|
||||||
|
|
||||||
|
|
1
dsc.h
1
dsc.h
|
@ -233,6 +233,7 @@ public:
|
||||||
} else if(hm.v < t->h.v) {
|
} else if(hm.v < t->h.v) {
|
||||||
first = mid + 1;
|
first = mid + 1;
|
||||||
} else {
|
} else {
|
||||||
|
dbp("can't insert in list; is handle %d not unique?", t->h.v);
|
||||||
oops();
|
oops();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
42
entity.cpp
42
entity.cpp
|
@ -162,7 +162,7 @@ void EntityBase::DistanceForceTo(double v) {
|
||||||
} else oops();
|
} else oops();
|
||||||
}
|
}
|
||||||
|
|
||||||
Entity *EntityBase::Normal(void) {
|
EntityBase *EntityBase::Normal(void) {
|
||||||
return SK.GetEntity(normal);
|
return SK.GetEntity(normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,8 +202,8 @@ Quaternion EntityBase::NormalGetNum(void) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NORMAL_IN_2D: {
|
case NORMAL_IN_2D: {
|
||||||
Entity *wrkpl = SK.GetEntity(workplane);
|
EntityBase *wrkpl = SK.GetEntity(workplane);
|
||||||
Entity *norm = SK.GetEntity(wrkpl->normal);
|
EntityBase *norm = SK.GetEntity(wrkpl->normal);
|
||||||
q = norm->NormalGetNum();
|
q = norm->NormalGetNum();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -286,8 +286,8 @@ ExprQuaternion EntityBase::NormalGetExprs(void) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NORMAL_IN_2D: {
|
case NORMAL_IN_2D: {
|
||||||
Entity *wrkpl = SK.GetEntity(workplane);
|
EntityBase *wrkpl = SK.GetEntity(workplane);
|
||||||
Entity *norm = SK.GetEntity(wrkpl->normal);
|
EntityBase *norm = SK.GetEntity(wrkpl->normal);
|
||||||
q = norm->NormalGetExprs();
|
q = norm->NormalGetExprs();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -315,10 +315,6 @@ ExprQuaternion EntityBase::NormalGetExprs(void) {
|
||||||
return q;
|
return q;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EntityBase::PointIsFromReferences(void) {
|
|
||||||
return h.request().IsFromReferences();
|
|
||||||
}
|
|
||||||
|
|
||||||
void EntityBase::PointForceTo(Vector p) {
|
void EntityBase::PointForceTo(Vector p) {
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case POINT_IN_3D:
|
case POINT_IN_3D:
|
||||||
|
@ -328,7 +324,7 @@ void EntityBase::PointForceTo(Vector p) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case POINT_IN_2D: {
|
case POINT_IN_2D: {
|
||||||
Entity *c = SK.GetEntity(workplane);
|
EntityBase *c = SK.GetEntity(workplane);
|
||||||
p = p.Minus(c->WorkplaneGetOffset());
|
p = p.Minus(c->WorkplaneGetOffset());
|
||||||
SK.GetParam(param[0])->val = p.Dot(c->Normal()->NormalU());
|
SK.GetParam(param[0])->val = p.Dot(c->Normal()->NormalU());
|
||||||
SK.GetParam(param[1])->val = p.Dot(c->Normal()->NormalV());
|
SK.GetParam(param[1])->val = p.Dot(c->Normal()->NormalV());
|
||||||
|
@ -390,7 +386,7 @@ Vector EntityBase::PointGetNum(void) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case POINT_IN_2D: {
|
case POINT_IN_2D: {
|
||||||
Entity *c = SK.GetEntity(workplane);
|
EntityBase *c = SK.GetEntity(workplane);
|
||||||
Vector u = c->Normal()->NormalU();
|
Vector u = c->Normal()->NormalU();
|
||||||
Vector v = c->Normal()->NormalV();
|
Vector v = c->Normal()->NormalV();
|
||||||
p = u.ScaledBy(SK.GetParam(param[0])->val);
|
p = u.ScaledBy(SK.GetParam(param[0])->val);
|
||||||
|
@ -439,7 +435,7 @@ ExprVector EntityBase::PointGetExprs(void) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case POINT_IN_2D: {
|
case POINT_IN_2D: {
|
||||||
Entity *c = SK.GetEntity(workplane);
|
EntityBase *c = SK.GetEntity(workplane);
|
||||||
ExprVector u = c->Normal()->NormalExprsU();
|
ExprVector u = c->Normal()->NormalExprsU();
|
||||||
ExprVector v = c->Normal()->NormalExprsV();
|
ExprVector v = c->Normal()->NormalExprsV();
|
||||||
r = c->WorkplaneGetOffsetExprs();
|
r = c->WorkplaneGetOffsetExprs();
|
||||||
|
@ -488,7 +484,7 @@ void EntityBase::PointGetExprsInWorkplane(hEntity wrkpl, Expr **u, Expr **v) {
|
||||||
*v = Expr::From(param[1]);
|
*v = Expr::From(param[1]);
|
||||||
} else {
|
} else {
|
||||||
// Get the offset and basis vectors for this weird exotic csys.
|
// Get the offset and basis vectors for this weird exotic csys.
|
||||||
Entity *w = SK.GetEntity(wrkpl);
|
EntityBase *w = SK.GetEntity(wrkpl);
|
||||||
ExprVector wp = w->WorkplaneGetOffsetExprs();
|
ExprVector wp = w->WorkplaneGetOffsetExprs();
|
||||||
ExprVector wu = w->Normal()->NormalExprsU();
|
ExprVector wu = w->Normal()->NormalExprsU();
|
||||||
ExprVector wv = w->Normal()->NormalExprsV();
|
ExprVector wv = w->Normal()->NormalExprsV();
|
||||||
|
@ -696,23 +692,3 @@ void EntityBase::GenerateEquations(IdList<Equation,hEquation> *l) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Entity::CalculateNumerical(bool forExport) {
|
|
||||||
if(IsPoint()) actPoint = PointGetNum();
|
|
||||||
if(IsNormal()) actNormal = NormalGetNum();
|
|
||||||
if(type == DISTANCE || type == DISTANCE_N_COPY) {
|
|
||||||
actDistance = DistanceGetNum();
|
|
||||||
}
|
|
||||||
if(IsFace()) {
|
|
||||||
actPoint = FaceGetPointNum();
|
|
||||||
Vector n = FaceGetNormalNum();
|
|
||||||
actNormal = Quaternion::From(0, n.x, n.y, n.z);
|
|
||||||
}
|
|
||||||
if(forExport) {
|
|
||||||
// Visibility in copied import entities follows source file
|
|
||||||
actVisible = IsVisible();
|
|
||||||
} else {
|
|
||||||
// Copied entities within a file are always visible
|
|
||||||
actVisible = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,403 @@
|
||||||
|
|
||||||
|
A sketch in SolveSpace consists of three basic elements: parameters,
|
||||||
|
entities, and constraints.
|
||||||
|
|
||||||
|
A parameter (Slvs_Param) is a single real number, represented internally
|
||||||
|
by a double-precision floating point variable. The parameters are unknown
|
||||||
|
variables that the solver modifies in order to satisfy the constraints.
|
||||||
|
|
||||||
|
An entity (Slvs_Entity) is a geometric thing, like a point or a line
|
||||||
|
segment or a circle. Entities are defined in terms of parameters,
|
||||||
|
and in terms of other entities. For example, a point in three-space
|
||||||
|
is represented by three parameters, corresponding to its x, y, and z
|
||||||
|
coordinates in our base coordinate frame. A line segment is represented
|
||||||
|
by two point entities, corresponding to its endpoints.
|
||||||
|
|
||||||
|
A constraint (Slvs_Constraint) is a geometric property of an entity,
|
||||||
|
or a relationship among multiple entities. For example, a point-point
|
||||||
|
distance constraint will set the distance between two point entities.
|
||||||
|
|
||||||
|
Paramters, entities, and constraints are typically referenced by their
|
||||||
|
handles (Slvs_hParam, Slvs_hEntity, Slvs_hConstraint). These handles are
|
||||||
|
32-bit integer values starting from 1. Each object has a unique handle
|
||||||
|
within its type (but it's acceptable, for example to have a constraint
|
||||||
|
with an Slvs_hConstraint of 7, and also to have an entity with an
|
||||||
|
Slvs_hEntity of 7). The use of handles instead of pointers helps to
|
||||||
|
avoid memory corruption.
|
||||||
|
|
||||||
|
Entities and constraints are assigned into groups. A group is a set of
|
||||||
|
entities and constraints that is solved simultaneously. In a parametric
|
||||||
|
CAD system, a single group would typically correspond to a single sketch.
|
||||||
|
Constraints within a group may refer to entities outside that group,
|
||||||
|
but only the entities within that group will be modified by the solver.
|
||||||
|
|
||||||
|
(Consider point A in group 1, and point B in group 2. We have a constraint
|
||||||
|
in group 2 that makes the points coincident. When we solve group 2, the
|
||||||
|
solver is allowed to move point B to place it on top of point A. It is
|
||||||
|
not allowed to move point A to put it on top of point B, because point
|
||||||
|
A is outside the group being solved.)
|
||||||
|
|
||||||
|
This corresponds to the typical structure of a parametric CAD system. In a
|
||||||
|
later sketch, we may constrain our entities against existing geometry from
|
||||||
|
earlier sketches. The constraints will move the entities in our current
|
||||||
|
sketch, but will not change the geometry from the earlier sketches.
|
||||||
|
|
||||||
|
To use the solver, we first define a set of parameters, entities,
|
||||||
|
and constraints. We provide an initial guess for each parameter; this
|
||||||
|
will improve convergence, and also determine which solution gets chosen
|
||||||
|
when (finitely many) multiple solutions exist. Typically, these initial
|
||||||
|
guesses are provided by the initial configuration in which the user drew
|
||||||
|
the entities before constraining them.
|
||||||
|
|
||||||
|
We then run the solver for a given group. The entities within that group
|
||||||
|
are modified in an attempt to satisfy the constraints.
|
||||||
|
|
||||||
|
After running the solver, there are three possible outcomes:
|
||||||
|
|
||||||
|
* All constraints were satisfied to within our numerical
|
||||||
|
tolerance (i.e., success).
|
||||||
|
|
||||||
|
* The solver can prove that two constraints are inconsistent (for
|
||||||
|
example, if a line with nonzero length is constrained both
|
||||||
|
horizontal and vertical). In that case, a list of inconsistent
|
||||||
|
constraints is generated.
|
||||||
|
|
||||||
|
* The solver cannot prove that two constraints are inconsistent, but
|
||||||
|
it cannot find a solution. In that case, the list of unsatisfied
|
||||||
|
constraints is generated.
|
||||||
|
|
||||||
|
|
||||||
|
SLVS_E_POINT_IN_3D
|
||||||
|
|
||||||
|
A point in 3d. Defined by three parameters:
|
||||||
|
|
||||||
|
param[0] the point's x coordinate
|
||||||
|
param[1] y
|
||||||
|
param[1] z
|
||||||
|
|
||||||
|
|
||||||
|
SLVS_E_POINT_IN_2D
|
||||||
|
|
||||||
|
A point within a workplane. Defined by the workplane
|
||||||
|
|
||||||
|
wrkpl
|
||||||
|
|
||||||
|
and by two parameters
|
||||||
|
|
||||||
|
param[0] the point's u coordinate
|
||||||
|
param[1] v
|
||||||
|
|
||||||
|
within the coordinate system of the workplane. For example, if the
|
||||||
|
workplane is the zx plane, then u = z and v = x. If the workplane is
|
||||||
|
parallel to the zx plane, but translated so that the workplane's
|
||||||
|
origin is (3, 4, 5), then u = z - 5 and v = x - 3.
|
||||||
|
|
||||||
|
|
||||||
|
SLVS_E_NORMAL_IN_3D
|
||||||
|
|
||||||
|
A normal. In SolveSpace, "normals" represent a 3x3 rotation matrix
|
||||||
|
from our base coordinate system to a new frame. Defined by the
|
||||||
|
unit quaternion
|
||||||
|
|
||||||
|
param[0] w
|
||||||
|
param[1] x
|
||||||
|
param[2] y
|
||||||
|
param[3] z
|
||||||
|
|
||||||
|
where the quaternion is given by w + x*i + y*j + z*k.
|
||||||
|
|
||||||
|
It is useful to think of this quaternion as representing a plane
|
||||||
|
through the origin. This plane has three associated vectors: basis
|
||||||
|
vectors U, V that lie within the plane, and normal N that is
|
||||||
|
perpendicular to it. This means that
|
||||||
|
|
||||||
|
[ U V N ]'
|
||||||
|
|
||||||
|
defines a 3x3 rotation matrix. So U, V, and N all have unit length,
|
||||||
|
and are orthogonal so that
|
||||||
|
|
||||||
|
U cross V = N
|
||||||
|
V cross N = U
|
||||||
|
N cross U = V
|
||||||
|
|
||||||
|
Convenience functions (Slvs_Quaternion*) are provided to convert
|
||||||
|
between this representation as vectors U, V, N and the unit
|
||||||
|
quaternion.
|
||||||
|
|
||||||
|
A unit quaternion has only 3 degrees of freedom, but is specified in
|
||||||
|
terms of 4 parameters. An extra constraint is therefore generated
|
||||||
|
implicitly, that
|
||||||
|
|
||||||
|
w^2 + x^2 + y^2 + z^2 = 1
|
||||||
|
|
||||||
|
|
||||||
|
SLVS_E_NORMAL_IN_2D
|
||||||
|
|
||||||
|
A normal within a workplane. This is identical to the workplane's
|
||||||
|
normal, so it is simply defined by
|
||||||
|
|
||||||
|
wrkpl
|
||||||
|
|
||||||
|
This entity type is used, for example, to define a circle that lies
|
||||||
|
within a workplane. The circle's normal is the same as the workplane's
|
||||||
|
normal, so we can use an SLVS_E_NORMAL_IN_2D to copy the workplane's
|
||||||
|
normal.
|
||||||
|
|
||||||
|
|
||||||
|
SLVS_E_DISTANCE
|
||||||
|
|
||||||
|
A distance. This entity is used to define the radius of a circle, by
|
||||||
|
a single parameter
|
||||||
|
|
||||||
|
param[0] r
|
||||||
|
|
||||||
|
|
||||||
|
SLVS_E_WORKPLANE
|
||||||
|
|
||||||
|
An oriented plane, somewhere in 3d. This entity therefore has 6
|
||||||
|
degrees of freedom: three translational, and three rotational. It is
|
||||||
|
specified in terms of its origin
|
||||||
|
|
||||||
|
point[0] origin
|
||||||
|
|
||||||
|
and a normal
|
||||||
|
|
||||||
|
normal
|
||||||
|
|
||||||
|
The normal describes three vectors U, V, N, as discussed in the
|
||||||
|
documentation for SLVS_E_NORMAL_IN_3D. The plane is therefore given
|
||||||
|
by the equation
|
||||||
|
|
||||||
|
p = origin + s*U + t*V
|
||||||
|
|
||||||
|
for any scalar s and t.
|
||||||
|
|
||||||
|
|
||||||
|
SLVS_E_LINE_SEGMENT
|
||||||
|
|
||||||
|
A line segment between two endpoints
|
||||||
|
|
||||||
|
point[0]
|
||||||
|
point[1]
|
||||||
|
|
||||||
|
|
||||||
|
SLVS_E_CUBIC
|
||||||
|
|
||||||
|
A nonrational cubic Bezier segment
|
||||||
|
|
||||||
|
point[0] starting point P0
|
||||||
|
point[1] control point P1
|
||||||
|
point[2] control point P2
|
||||||
|
point[3] ending point P3
|
||||||
|
|
||||||
|
The curve then has equation
|
||||||
|
|
||||||
|
p(t) = P0*(1 - t)^3 + 3*P1*(1 - t)^2*t + 3*P2*(1 - t)*t^2 + P3*t^3
|
||||||
|
|
||||||
|
as t goes from 0 to 1.
|
||||||
|
|
||||||
|
|
||||||
|
SLVS_E_CIRCLE
|
||||||
|
|
||||||
|
A complete circle. The circle lies within a plane with normal
|
||||||
|
|
||||||
|
normal
|
||||||
|
|
||||||
|
The circle is centered at
|
||||||
|
|
||||||
|
point[0]
|
||||||
|
|
||||||
|
The circle's radius is
|
||||||
|
|
||||||
|
distance
|
||||||
|
|
||||||
|
|
||||||
|
SLVS_E_ARC_OF_CIRCLE
|
||||||
|
|
||||||
|
An arc of a circle. An arc must always lie within a workplane; it
|
||||||
|
cannot be free in 3d. So it is specified with a workplane
|
||||||
|
|
||||||
|
wrkpl
|
||||||
|
|
||||||
|
It is then defined by three points
|
||||||
|
|
||||||
|
point[0] center of the circle
|
||||||
|
point[1] begining of the arc
|
||||||
|
point[2] end of the arc
|
||||||
|
|
||||||
|
The arc runs counter-clockwise from its beginning to its end (with
|
||||||
|
the workplane's normal pointing owards the viewer). If the begining
|
||||||
|
and end of the arc are coincident, then the arc is considered to
|
||||||
|
represent a full circle.
|
||||||
|
|
||||||
|
This representation has an extra degree of freedom. An extra
|
||||||
|
constraint is therefore generated implicitly, so that
|
||||||
|
|
||||||
|
distance(center, beginning) = distance(center, end)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Many constraints can apply either in 3d, or in a workplane. This is
|
||||||
|
determined by the wrkpl member of the constraint. If that member is set
|
||||||
|
to SLVS_FREE_IN_3D, then the constraint applies in 3d. If that member
|
||||||
|
is set equal to a workplane, the the constraint applies projected into
|
||||||
|
that workplane. (For example, a constraint on the distance between two
|
||||||
|
points actually applies to the projected distance).
|
||||||
|
|
||||||
|
Constraints that may be used in 3d or projected into a workplane are
|
||||||
|
marked with a single star (*). Constraints that must always be used with
|
||||||
|
a workplane are marked with a double star (**). Constraints that ignore
|
||||||
|
the wrkpl member are marked with no star.
|
||||||
|
|
||||||
|
SLVS_C_PT_PT_DISTANCE*
|
||||||
|
|
||||||
|
The distance between points ptA and ptB is equal to valA.
|
||||||
|
|
||||||
|
SLVS_C_POINTS_COINCIDENT*
|
||||||
|
|
||||||
|
Points ptA and ptB are coincident (i.e., exactly on top of each
|
||||||
|
other).
|
||||||
|
|
||||||
|
SLVS_C_PT_PLANE_DISTANCE
|
||||||
|
|
||||||
|
The distance from point ptA to workplane entityA is equal to
|
||||||
|
valA. This is a signed distance; positive versus negative valA
|
||||||
|
correspond to a point that is above vs. below the plane.
|
||||||
|
|
||||||
|
SLVS_C_PT_LINE_DISTANCE*
|
||||||
|
|
||||||
|
The distance from point ptA to line segment entityA is equal to valA.
|
||||||
|
|
||||||
|
If the constraint is projected, then valA is a signed distance;
|
||||||
|
positive versus negative valA correspond to a point that is above
|
||||||
|
vs. below the line.
|
||||||
|
|
||||||
|
If the constraint applies in 3d, then valA must always be positive.
|
||||||
|
|
||||||
|
SLVS_C_PT_IN_PLANE
|
||||||
|
|
||||||
|
The point ptA lies in plane entityA.
|
||||||
|
|
||||||
|
SLVS_C_PT_ON_LINE*
|
||||||
|
|
||||||
|
The point ptA lies on the line entityA.
|
||||||
|
|
||||||
|
Note that this constraint removes one degree of freedom when projected
|
||||||
|
in to the plane, but two degrees of freedom in 3d.
|
||||||
|
|
||||||
|
SLVS_C_EQUAL_LENGTH_LINES*
|
||||||
|
|
||||||
|
The lines entityA and entityB have equal length.
|
||||||
|
|
||||||
|
SLVS_C_LENGTH_RATIO*
|
||||||
|
|
||||||
|
The length of line entityA divided by the length of line entityB is
|
||||||
|
equal to valA.
|
||||||
|
|
||||||
|
SLVS_C_EQ_LEN_PT_LINE_D*
|
||||||
|
|
||||||
|
The length of the line entityA is equal to the distance from point
|
||||||
|
ptA to line entityB.
|
||||||
|
|
||||||
|
SLVS_C_EQ_PT_LN_DISTANCES*
|
||||||
|
|
||||||
|
The distance from the line entityA to the point ptA is equal to the
|
||||||
|
distance from the line entityB to the point ptB.
|
||||||
|
|
||||||
|
SLVS_C_EQUAL_ANGLE*
|
||||||
|
|
||||||
|
The angle between lines entityA and entityB is equal to the angle
|
||||||
|
between lines entityC and entityD.
|
||||||
|
|
||||||
|
If other is true, then the angles are supplementary (i.e., theta1 =
|
||||||
|
180 - theta2) instead of equal.
|
||||||
|
|
||||||
|
SLVS_C_EQUAL_LINE_ARC_LEN*
|
||||||
|
|
||||||
|
The length of the line entityA is equal to the length of the circular
|
||||||
|
arc entityB.
|
||||||
|
|
||||||
|
SLVS_C_SYMMETRIC*
|
||||||
|
|
||||||
|
The points ptA and ptB are symmetric about the plane entityA. This
|
||||||
|
means that they are on opposite sides of the plane and at equal
|
||||||
|
distances from the plane, and that the line connecting ptA and ptB
|
||||||
|
is normal to the plane.
|
||||||
|
|
||||||
|
SLVS_C_SYMMETRIC_HORIZ
|
||||||
|
SLVS_C_SYMMETRIC_VERT**
|
||||||
|
|
||||||
|
The points ptA and ptB are symmetric about the horizontal or vertical
|
||||||
|
axis of the specified workplane.
|
||||||
|
|
||||||
|
SLVS_C_SYMMETRIC_LINE*
|
||||||
|
|
||||||
|
The points ptA and ptB are symmetric about the line entityA.
|
||||||
|
|
||||||
|
SLVS_C_AT_MIDPOINT*
|
||||||
|
|
||||||
|
The point ptA lies at the midpoint of the line entityA.
|
||||||
|
|
||||||
|
SLVS_C_HORIZONTAL
|
||||||
|
SLVS_C_VERTICAL**
|
||||||
|
|
||||||
|
The line connecting points ptA and ptB is horizontal or vertical.
|
||||||
|
|
||||||
|
SLVS_C_DIAMETER
|
||||||
|
|
||||||
|
The diameter of circle or arc entityA is equal to valA.
|
||||||
|
|
||||||
|
SLVS_C_PT_ON_CIRCLE
|
||||||
|
|
||||||
|
The point ptA lies on the right cylinder obtained by extruding circle
|
||||||
|
entityA normal to its plane.
|
||||||
|
|
||||||
|
SLVS_C_SAME_ORIENTATION
|
||||||
|
|
||||||
|
The normals entityA and entityB describe identical rotations. This
|
||||||
|
constraint therefore restricts three degrees of freedom.
|
||||||
|
|
||||||
|
SLVS_C_ANGLE*
|
||||||
|
|
||||||
|
The angle between lines entityA and entityB is equal to valA, where
|
||||||
|
valA is specified in degrees. This constraint equation is written
|
||||||
|
in the form
|
||||||
|
|
||||||
|
(A dot B)/(|A||B|) = cos(valA)
|
||||||
|
|
||||||
|
where A and B are vectors in the directions of lines A and B. This
|
||||||
|
equation does not specify the angle unambiguously; for example,
|
||||||
|
note that val A = +/- 90 degrees will produce the same equation.
|
||||||
|
|
||||||
|
If other is true, then the constraint is instead that
|
||||||
|
|
||||||
|
(A dot B)/(|A||B|) = -cos(valA)
|
||||||
|
|
||||||
|
SLVS_C_PERPENDICULAR*
|
||||||
|
|
||||||
|
Identical to SLVS_C_ANGLE with valA = 90 degrees.
|
||||||
|
|
||||||
|
SLVS_C_PARALLEL*
|
||||||
|
|
||||||
|
Lines entityA and entityB are parallel.
|
||||||
|
|
||||||
|
Note that this constraint removes one degree of freedom when projected
|
||||||
|
in to the plane, but two degrees of freedom in 3d.
|
||||||
|
|
||||||
|
SLVS_C_ARC_LINE_TANGENT**
|
||||||
|
|
||||||
|
The arc entityA is tangent to the line entityB. If other is false,
|
||||||
|
then the arc is tangent at its beginning (point[1]). If other is true,
|
||||||
|
then the arc is tangent at its end (point[2]).
|
||||||
|
|
||||||
|
SLVS_C_CUBIC_LINE_TANGENT*
|
||||||
|
|
||||||
|
The cubic entityA is tangent to the line entityB. If other is false,
|
||||||
|
then the cubic is tangent at its beginning (point[0]). If other is
|
||||||
|
true, then the arc is tangent at its end (point[3]).
|
||||||
|
|
||||||
|
SLVS_C_EQUAL_RADIUS
|
||||||
|
|
||||||
|
The circles or arcs entityA and entityB have equal radius.
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
DEFINES = /D_WIN32_WINNT=0x500 /DISOLATION_AWARE_ENABLED /D_WIN32_IE=0x500 /DWIN32_LEAN_AND_MEAN /DWIN32 /DLIBRARY
|
||||||
|
# Use the multi-threaded static libc because libpng and zlib do; not sure if anything bad
|
||||||
|
# happens if those mix, but don't want to risk it.
|
||||||
|
CFLAGS = /W3 /nologo -MT -Iextlib -I..\..\common\win32 /D_DEBUG /D_CRT_SECURE_NO_WARNINGS /I. /I.. /Zi /EHs
|
||||||
|
|
||||||
|
HEADERS = ..\solvespace.h ..\dsc.h ..\sketch.h ..\expr.h slvs.h
|
||||||
|
|
||||||
|
OBJDIR = obj
|
||||||
|
|
||||||
|
SSOBJS = $(OBJDIR)\util.obj \
|
||||||
|
$(OBJDIR)\entity.obj \
|
||||||
|
$(OBJDIR)\expr.obj \
|
||||||
|
$(OBJDIR)\constrainteq.obj \
|
||||||
|
$(OBJDIR)\system.obj \
|
||||||
|
|
||||||
|
|
||||||
|
W32OBJS = $(OBJDIR)\w32util.obj \
|
||||||
|
|
||||||
|
|
||||||
|
LIBOBJS = $(OBJDIR)\lib.obj \
|
||||||
|
|
||||||
|
|
||||||
|
LIBS = user32.lib gdi32.lib comctl32.lib advapi32.lib shell32.lib
|
||||||
|
|
||||||
|
all: $(OBJDIR)/ctest.exe
|
||||||
|
@cp $(OBJDIR)/ctest.exe .
|
||||||
|
ctest.exe
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f obj/*
|
||||||
|
|
||||||
|
$(OBJDIR)/slvs.lib: $(SSOBJS) $(LIBOBJS) $(W32OBJS)
|
||||||
|
@lib /OUT:$(OBJDIR)/slvs.lib $(SSOBJS) $(LIBOBJS) $(W32OBJS)
|
||||||
|
@echo slvs.lib
|
||||||
|
|
||||||
|
$(OBJDIR)/ctest.exe: example.c $(OBJDIR)/slvs.lib
|
||||||
|
@$(CC) $(CFLAGS) -Fe$(OBJDIR)/ctest.exe example.c $(OBJDIR)/slvs.lib $(LIBS)
|
||||||
|
@echo ctest.exe
|
||||||
|
|
||||||
|
$(SSOBJS): ..\$(@B).cpp $(HEADERS)
|
||||||
|
@$(CC) $(CFLAGS) $(DEFINES) -c -Fo$(OBJDIR)/$(@B).obj ..\$(@B).cpp
|
||||||
|
|
||||||
|
$(W32OBJS): ..\win32\$(@B).cpp $(HEADERS)
|
||||||
|
@$(CC) $(CFLAGS) $(DEFINES) -c -Fo$(OBJDIR)/$(@B).obj ..\win32\$(@B).cpp
|
||||||
|
|
||||||
|
$(LIBOBJS): $(@B).cpp $(HEADERS)
|
||||||
|
@$(CC) $(CFLAGS) $(DEFINES) -c -Fo$(OBJDIR)/$(@B).obj $(@B).cpp
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,190 @@
|
||||||
|
#include <windows.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "slvs.h"
|
||||||
|
|
||||||
|
Slvs_System sys;
|
||||||
|
|
||||||
|
void *CheckMalloc(size_t n)
|
||||||
|
{
|
||||||
|
void *r = malloc(n);
|
||||||
|
if(!r) {
|
||||||
|
printf("out of memory!\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// An example of a constraint in 3d. We create
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
void Example3d(void)
|
||||||
|
{
|
||||||
|
// This will contain a single group, which will arbitrarily number 1.
|
||||||
|
int g = 1;
|
||||||
|
|
||||||
|
// A point, initially at (x y z) = (10 10 10)
|
||||||
|
sys.param[sys.params++] = Slvs_MakeParam(1, g, 10.0);
|
||||||
|
sys.param[sys.params++] = Slvs_MakeParam(2, g, 10.0);
|
||||||
|
sys.param[sys.params++] = Slvs_MakeParam(3, g, 10.0);
|
||||||
|
sys.entity[sys.entities++] = Slvs_MakePoint3d(101, g, 1, 2, 3);
|
||||||
|
// and a second point at (20 20 20)
|
||||||
|
sys.param[sys.params++] = Slvs_MakeParam(4, g, 20.0);
|
||||||
|
sys.param[sys.params++] = Slvs_MakeParam(5, g, 20.0);
|
||||||
|
sys.param[sys.params++] = Slvs_MakeParam(6, g, 20.0);
|
||||||
|
sys.entity[sys.entities++] = Slvs_MakePoint3d(102, g, 4, 5, 6);
|
||||||
|
// and a line segment connecting them.
|
||||||
|
sys.entity[sys.entities++] = Slvs_MakeLineSegment(200, g,
|
||||||
|
SLVS_FREE_IN_3D, 101, 102);
|
||||||
|
|
||||||
|
// The distance between the points should be 30.0 units.
|
||||||
|
sys.constraint[sys.constraints++] = Slvs_MakeConstraint(
|
||||||
|
1, g,
|
||||||
|
SLVS_C_PT_PT_DISTANCE,
|
||||||
|
SLVS_FREE_IN_3D,
|
||||||
|
30.0,
|
||||||
|
101, 102, 0, 0);
|
||||||
|
|
||||||
|
// Let's tell the solver to keep the second point as close to constant
|
||||||
|
// as possible, instead moving the first point.
|
||||||
|
sys.dragged[0] = 4;
|
||||||
|
sys.dragged[1] = 5;
|
||||||
|
sys.dragged[2] = 6;
|
||||||
|
|
||||||
|
// Now that we have written our system, we solve.
|
||||||
|
Slvs_Solve(&sys, g);
|
||||||
|
|
||||||
|
if(sys.result == SLVS_RESULT_OKAY) {
|
||||||
|
printf("okay; now at (%.3f %.3f %.3f)\n"
|
||||||
|
" (%.3f %.3f %.3f)\n",
|
||||||
|
sys.param[0].val, sys.param[1].val, sys.param[2].val,
|
||||||
|
sys.param[3].val, sys.param[4].val, sys.param[5].val);
|
||||||
|
printf("%d DOF\n", sys.dof);
|
||||||
|
} else {
|
||||||
|
printf("solve failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// An example of a constraint in 2d. In an earlier group, we have created a
|
||||||
|
// workplane. Then in our group to be solved, we create a line segment, which
|
||||||
|
// we dimension to be horizontal and 2.0 units long.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
void Example2d(void)
|
||||||
|
{
|
||||||
|
int g;
|
||||||
|
double qw, qx, qy, qz;
|
||||||
|
|
||||||
|
g = 1;
|
||||||
|
// First, we create our workplane. Its origin corresponds to the origin
|
||||||
|
// of our base frame (x y z) = (0 0 0)
|
||||||
|
sys.param[sys.params++] = Slvs_MakeParam(1, g, 0.0);
|
||||||
|
sys.param[sys.params++] = Slvs_MakeParam(2, g, 0.0);
|
||||||
|
sys.param[sys.params++] = Slvs_MakeParam(3, g, 0.0);
|
||||||
|
sys.entity[sys.entities++] = Slvs_MakePoint3d(101, g, 1, 2, 3);
|
||||||
|
// and it is parallel to the xy plane, so it has basis vectors (1 0 0)
|
||||||
|
// and (0 1 0).
|
||||||
|
Slvs_MakeQuaternion(1, 0, 0,
|
||||||
|
0, 1, 0, &qw, &qx, &qy, &qz);
|
||||||
|
sys.param[sys.params++] = Slvs_MakeParam(4, g, qw);
|
||||||
|
sys.param[sys.params++] = Slvs_MakeParam(5, g, qx);
|
||||||
|
sys.param[sys.params++] = Slvs_MakeParam(6, g, qy);
|
||||||
|
sys.param[sys.params++] = Slvs_MakeParam(7, g, qz);
|
||||||
|
sys.entity[sys.entities++] = Slvs_MakeNormal3d(102, g, 3, 4, 5, 6);
|
||||||
|
|
||||||
|
sys.entity[sys.entities++] = Slvs_MakeWorkplane(200, g, 101, 102);
|
||||||
|
|
||||||
|
// Now create a second group. We'll solve group 2, while leaving group 1
|
||||||
|
// constant; so the workplane that we've created will be locked down,
|
||||||
|
// and the solver can't move it.
|
||||||
|
g = 2;
|
||||||
|
// These points are represented by their coordinates (u v) within the
|
||||||
|
// workplane, so they need only two parameters each.
|
||||||
|
sys.param[sys.params++] = Slvs_MakeParam(11, g, 10.0);
|
||||||
|
sys.param[sys.params++] = Slvs_MakeParam(12, g, 20.0);
|
||||||
|
sys.entity[sys.entities++] = Slvs_MakePoint2d(301, g, 200, 11, 12);
|
||||||
|
|
||||||
|
sys.param[sys.params++] = Slvs_MakeParam(13, g, 20.0);
|
||||||
|
sys.param[sys.params++] = Slvs_MakeParam(14, g, 10.0);
|
||||||
|
sys.entity[sys.entities++] = Slvs_MakePoint2d(302, g, 200, 13, 14);
|
||||||
|
|
||||||
|
// And we create a line segment with those endpoints.
|
||||||
|
sys.entity[sys.entities++] = Slvs_MakeLineSegment(400, g,
|
||||||
|
200, 301, 302);
|
||||||
|
|
||||||
|
// The length of our line segment is 30.0 units.
|
||||||
|
sys.constraint[sys.constraints++] = Slvs_MakeConstraint(
|
||||||
|
1, g,
|
||||||
|
SLVS_C_PT_PT_DISTANCE,
|
||||||
|
200,
|
||||||
|
30.0,
|
||||||
|
301, 302, 0, 0);
|
||||||
|
|
||||||
|
// And the distance from our line segment to the origin is 10.0 units.
|
||||||
|
sys.constraint[sys.constraints++] = Slvs_MakeConstraint(
|
||||||
|
2, g,
|
||||||
|
SLVS_C_PT_LINE_DISTANCE,
|
||||||
|
200,
|
||||||
|
10.0,
|
||||||
|
101, 0, 400, 0);
|
||||||
|
// And the line segment is vertical.
|
||||||
|
sys.constraint[sys.constraints++] = Slvs_MakeConstraint(
|
||||||
|
3, g,
|
||||||
|
SLVS_C_VERTICAL,
|
||||||
|
200,
|
||||||
|
0.0,
|
||||||
|
0, 0, 400, 0);
|
||||||
|
// And the distance from one endpoint to the origin is 15.0 units.
|
||||||
|
sys.constraint[sys.constraints++] = Slvs_MakeConstraint(
|
||||||
|
4, g,
|
||||||
|
SLVS_C_PT_PT_DISTANCE,
|
||||||
|
200,
|
||||||
|
15.0,
|
||||||
|
301, 101, 0, 0);
|
||||||
|
|
||||||
|
// And the distance from one endpoint to the origin is 15.0 units.
|
||||||
|
sys.constraint[sys.constraints++] = Slvs_MakeConstraint(
|
||||||
|
5, g,
|
||||||
|
SLVS_C_PT_PT_DISTANCE,
|
||||||
|
200,
|
||||||
|
18.0,
|
||||||
|
302, 101, 0, 0);
|
||||||
|
|
||||||
|
// And solve.
|
||||||
|
Slvs_Solve(&sys, g);
|
||||||
|
|
||||||
|
if(sys.result == SLVS_RESULT_OKAY) {
|
||||||
|
printf("okay; now at (%.3f %.3f)\n"
|
||||||
|
" (%.3f %.3f)\n",
|
||||||
|
sys.param[7].val, sys.param[8].val,
|
||||||
|
sys.param[9].val, sys.param[10].val);
|
||||||
|
printf("%d DOF\n", sys.dof);
|
||||||
|
} else {
|
||||||
|
int i;
|
||||||
|
printf("solve failed: problematic constraints are:");
|
||||||
|
for(i = 0; i < sys.faileds; i++) {
|
||||||
|
printf(" %d", sys.failed[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
if(sys.result == SLVS_RESULT_INCONSISTENT) {
|
||||||
|
printf("system inconsistent\n");
|
||||||
|
} else {
|
||||||
|
printf("system nonconvergent\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
memset(&sys, 0, sizeof(sys));
|
||||||
|
sys.param = CheckMalloc(50*sizeof(sys.param[0]));
|
||||||
|
sys.entity = CheckMalloc(50*sizeof(sys.entity[0]));
|
||||||
|
sys.constraint = CheckMalloc(50*sizeof(sys.constraint[0]));
|
||||||
|
|
||||||
|
sys.failed = CheckMalloc(50*sizeof(sys.failed[0]));
|
||||||
|
sys.faileds = 50;
|
||||||
|
|
||||||
|
// Example3d();
|
||||||
|
Example2d();
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,234 @@
|
||||||
|
#include "solvespace.h"
|
||||||
|
#include "slvs.h"
|
||||||
|
|
||||||
|
Sketch SK;
|
||||||
|
System SYS;
|
||||||
|
|
||||||
|
int IsInit = 0;
|
||||||
|
|
||||||
|
void Group::GenerateEquations(IdList<Equation,hEquation> *l) {
|
||||||
|
// Nothing to do for now.
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
void Slvs_QuaternionU(double qw, double qx, double qy, double qz,
|
||||||
|
double *x, double *y, double *z)
|
||||||
|
{
|
||||||
|
Quaternion q = Quaternion::From(qw, qx, qy, qz);
|
||||||
|
Vector v = q.RotationU();
|
||||||
|
*x = v.x;
|
||||||
|
*y = v.y;
|
||||||
|
*z = v.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Slvs_QuaternionV(double qw, double qx, double qy, double qz,
|
||||||
|
double *x, double *y, double *z)
|
||||||
|
{
|
||||||
|
Quaternion q = Quaternion::From(qw, qx, qy, qz);
|
||||||
|
Vector v = q.RotationV();
|
||||||
|
*x = v.x;
|
||||||
|
*y = v.y;
|
||||||
|
*z = v.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Slvs_QuaternionN(double qw, double qx, double qy, double qz,
|
||||||
|
double *x, double *y, double *z)
|
||||||
|
{
|
||||||
|
Quaternion q = Quaternion::From(qw, qx, qy, qz);
|
||||||
|
Vector v = q.RotationN();
|
||||||
|
*x = v.x;
|
||||||
|
*y = v.y;
|
||||||
|
*z = v.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Slvs_MakeQuaternion(double ux, double uy, double uz,
|
||||||
|
double vx, double vy, double vz,
|
||||||
|
double *qw, double *qx, double *qy, double *qz)
|
||||||
|
{
|
||||||
|
Vector u = Vector::From(ux, uy, uz),
|
||||||
|
v = Vector::From(vx, vy, vz);
|
||||||
|
Quaternion q = Quaternion::From(u, v);
|
||||||
|
*qw = q.w;
|
||||||
|
*qx = q.vx;
|
||||||
|
*qy = q.vy;
|
||||||
|
*qz = q.vz;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Slvs_Solve(Slvs_System *ssys, Slvs_hGroup shg)
|
||||||
|
{
|
||||||
|
if(!IsInit) {
|
||||||
|
InitHeaps();
|
||||||
|
IsInit = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < ssys->params; i++) {
|
||||||
|
Slvs_Param *sp = &(ssys->param[i]);
|
||||||
|
Param p;
|
||||||
|
ZERO(&p);
|
||||||
|
|
||||||
|
p.h.v = sp->h;
|
||||||
|
p.val = sp->val;
|
||||||
|
SK.param.Add(&p);
|
||||||
|
if(sp->group == shg) {
|
||||||
|
SYS.param.Add(&p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 0; i < ssys->entities; i++) {
|
||||||
|
Slvs_Entity *se = &(ssys->entity[i]);
|
||||||
|
EntityBase e;
|
||||||
|
ZERO(&e);
|
||||||
|
|
||||||
|
switch(se->type) {
|
||||||
|
case SLVS_E_POINT_IN_3D: e.type = Entity::POINT_IN_3D; break;
|
||||||
|
case SLVS_E_POINT_IN_2D: e.type = Entity::POINT_IN_2D; break;
|
||||||
|
case SLVS_E_NORMAL_IN_3D: e.type = Entity::NORMAL_IN_3D; break;
|
||||||
|
case SLVS_E_NORMAL_IN_2D: e.type = Entity::NORMAL_IN_2D; break;
|
||||||
|
case SLVS_E_DISTANCE: e.type = Entity::DISTANCE; break;
|
||||||
|
case SLVS_E_WORKPLANE: e.type = Entity::WORKPLANE; break;
|
||||||
|
case SLVS_E_LINE_SEGMENT: e.type = Entity::LINE_SEGMENT; break;
|
||||||
|
case SLVS_E_CUBIC: e.type = Entity::CUBIC; break;
|
||||||
|
case SLVS_E_CIRCLE: e.type = Entity::CIRCLE; break;
|
||||||
|
case SLVS_E_ARC_OF_CIRCLE: e.type = Entity::ARC_OF_CIRCLE; break;
|
||||||
|
|
||||||
|
default: dbp("bad entity type %d", se->type); return;
|
||||||
|
}
|
||||||
|
e.h.v = se->h;
|
||||||
|
e.group.v = se->group;
|
||||||
|
e.workplane.v = se->wrkpl;
|
||||||
|
e.point[0].v = se->point[0];
|
||||||
|
e.point[1].v = se->point[1];
|
||||||
|
e.point[2].v = se->point[2];
|
||||||
|
e.point[3].v = se->point[3];
|
||||||
|
e.normal.v = se->normal;
|
||||||
|
e.distance.v = se->distance;
|
||||||
|
e.param[0].v = se->param[0];
|
||||||
|
e.param[1].v = se->param[1];
|
||||||
|
e.param[2].v = se->param[2];
|
||||||
|
e.param[3].v = se->param[3];
|
||||||
|
|
||||||
|
SK.entity.Add(&e);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 0; i < ssys->constraints; i++) {
|
||||||
|
Slvs_Constraint *sc = &(ssys->constraint[i]);
|
||||||
|
ConstraintBase c;
|
||||||
|
ZERO(&c);
|
||||||
|
|
||||||
|
int t;
|
||||||
|
switch(sc->type) {
|
||||||
|
case SLVS_C_POINTS_COINCIDENT: t = Constraint::POINTS_COINCIDENT; break;
|
||||||
|
case SLVS_C_PT_PT_DISTANCE: t = Constraint::PT_PT_DISTANCE; break;
|
||||||
|
case SLVS_C_PT_PLANE_DISTANCE: t = Constraint::PT_PLANE_DISTANCE; break;
|
||||||
|
case SLVS_C_PT_LINE_DISTANCE: t = Constraint::PT_LINE_DISTANCE; break;
|
||||||
|
case SLVS_C_PT_FACE_DISTANCE: t = Constraint::PT_FACE_DISTANCE; break;
|
||||||
|
case SLVS_C_PT_IN_PLANE: t = Constraint::PT_IN_PLANE; break;
|
||||||
|
case SLVS_C_PT_ON_LINE: t = Constraint::PT_ON_LINE; break;
|
||||||
|
case SLVS_C_PT_ON_FACE: t = Constraint::PT_ON_FACE; break;
|
||||||
|
case SLVS_C_EQUAL_LENGTH_LINES: t = Constraint::EQUAL_LENGTH_LINES; break;
|
||||||
|
case SLVS_C_LENGTH_RATIO: t = Constraint::LENGTH_RATIO; break;
|
||||||
|
case SLVS_C_EQ_LEN_PT_LINE_D: t = Constraint::EQ_LEN_PT_LINE_D; break;
|
||||||
|
case SLVS_C_EQ_PT_LN_DISTANCES: t = Constraint::EQ_PT_LN_DISTANCES; break;
|
||||||
|
case SLVS_C_EQUAL_ANGLE: t = Constraint::EQUAL_ANGLE; break;
|
||||||
|
case SLVS_C_EQUAL_LINE_ARC_LEN: t = Constraint::EQUAL_LINE_ARC_LEN; break;
|
||||||
|
case SLVS_C_SYMMETRIC: t = Constraint::SYMMETRIC; break;
|
||||||
|
case SLVS_C_SYMMETRIC_HORIZ: t = Constraint::SYMMETRIC_HORIZ; break;
|
||||||
|
case SLVS_C_SYMMETRIC_VERT: t = Constraint::SYMMETRIC_VERT; break;
|
||||||
|
case SLVS_C_SYMMETRIC_LINE: t = Constraint::SYMMETRIC_LINE; break;
|
||||||
|
case SLVS_C_AT_MIDPOINT: t = Constraint::AT_MIDPOINT; break;
|
||||||
|
case SLVS_C_HORIZONTAL: t = Constraint::HORIZONTAL; break;
|
||||||
|
case SLVS_C_VERTICAL: t = Constraint::VERTICAL; break;
|
||||||
|
case SLVS_C_DIAMETER: t = Constraint::DIAMETER; break;
|
||||||
|
case SLVS_C_PT_ON_CIRCLE: t = Constraint::PT_ON_CIRCLE; break;
|
||||||
|
case SLVS_C_SAME_ORIENTATION: t = Constraint::SAME_ORIENTATION; break;
|
||||||
|
case SLVS_C_ANGLE: t = Constraint::ANGLE; break;
|
||||||
|
case SLVS_C_PARALLEL: t = Constraint::PARALLEL; break;
|
||||||
|
case SLVS_C_PERPENDICULAR: t = Constraint::PERPENDICULAR; break;
|
||||||
|
case SLVS_C_ARC_LINE_TANGENT: t = Constraint::ARC_LINE_TANGENT; break;
|
||||||
|
case SLVS_C_CUBIC_LINE_TANGENT: t = Constraint::CUBIC_LINE_TANGENT; break;
|
||||||
|
case SLVS_C_EQUAL_RADIUS: t = Constraint::EQUAL_RADIUS; break;
|
||||||
|
|
||||||
|
default: dbp("bad constraint type %d", sc->type); return;
|
||||||
|
}
|
||||||
|
|
||||||
|
c.type = t;
|
||||||
|
|
||||||
|
c.h.v = sc->h;
|
||||||
|
c.group.v = sc->group;
|
||||||
|
c.workplane.v = sc->wrkpl;
|
||||||
|
c.valA = sc->valA;
|
||||||
|
c.ptA.v = sc->ptA;
|
||||||
|
c.ptB.v = sc->ptB;
|
||||||
|
c.entityA.v = sc->entityA;
|
||||||
|
c.entityB.v = sc->entityB;
|
||||||
|
c.entityC.v = sc->entityC;
|
||||||
|
c.entityD.v = sc->entityD;
|
||||||
|
c.other = (sc->other) ? true : false;
|
||||||
|
|
||||||
|
SK.constraint.Add(&c);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(System::MAX_DRAGGED < 4) oops();
|
||||||
|
for(i = 0; i < System::MAX_DRAGGED; i++) {
|
||||||
|
SYS.dragged[i].v = 0;
|
||||||
|
}
|
||||||
|
SYS.dragged[0].v = ssys->dragged[0];
|
||||||
|
SYS.dragged[1].v = ssys->dragged[1];
|
||||||
|
SYS.dragged[2].v = ssys->dragged[2];
|
||||||
|
SYS.dragged[3].v = ssys->dragged[3];
|
||||||
|
|
||||||
|
Group g;
|
||||||
|
ZERO(&g);
|
||||||
|
g.h.v = shg;
|
||||||
|
|
||||||
|
List<hConstraint> bad;
|
||||||
|
ZERO(&bad);
|
||||||
|
|
||||||
|
// Now we're finally ready to solve!
|
||||||
|
int how = SYS.Solve(&g, &(ssys->dof), &bad, false);
|
||||||
|
|
||||||
|
switch(how) {
|
||||||
|
case System::SOLVED_OKAY:
|
||||||
|
ssys->result = SLVS_RESULT_OKAY;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case System::DIDNT_CONVERGE:
|
||||||
|
ssys->result = SLVS_RESULT_DIDNT_CONVERGE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case System::SINGULAR_JACOBIAN:
|
||||||
|
ssys->result = SLVS_RESULT_INCONSISTENT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case System::TOO_MANY_UNKNOWNS:
|
||||||
|
ssys->result = SLVS_RESULT_TOO_MANY_UNKNOWNS;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: oops();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the new parameter values back to our caller.
|
||||||
|
for(i = 0; i < ssys->params; i++) {
|
||||||
|
Slvs_Param *sp = &(ssys->param[i]);
|
||||||
|
hParam hp = { sp->h };
|
||||||
|
sp->val = SK.GetParam(hp)->val;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ssys->failed) {
|
||||||
|
// Copy over any the list of problematic constraints.
|
||||||
|
for(i = 0; i < ssys->faileds && i < bad.n; i++) {
|
||||||
|
ssys->failed[i] = bad.elem[i].v;
|
||||||
|
}
|
||||||
|
ssys->faileds = bad.n;
|
||||||
|
}
|
||||||
|
|
||||||
|
bad.Clear();
|
||||||
|
SYS.param.Clear();
|
||||||
|
SK.param.Clear();
|
||||||
|
SK.entity.Clear();
|
||||||
|
SK.constraint.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
71
generate.cpp
71
generate.cpp
|
@ -141,7 +141,7 @@ void SolveSpace::GenerateAll(void) {
|
||||||
for(i = 0; i < SK.group.n; i++) {
|
for(i = 0; i < SK.group.n; i++) {
|
||||||
Group *g = &(SK.group.elem[i]);
|
Group *g = &(SK.group.elem[i]);
|
||||||
g->order = i;
|
g->order = i;
|
||||||
if((!g->clean) || (g->solved.how != Group::SOLVED_OKAY)) {
|
if((!g->clean) || (g->solved.how != System::SOLVED_OKAY)) {
|
||||||
firstDirty = min(firstDirty, i);
|
firstDirty = min(firstDirty, i);
|
||||||
}
|
}
|
||||||
if(g->h.v == SS.GW.activeGroup.v) {
|
if(g->h.v == SS.GW.activeGroup.v) {
|
||||||
|
@ -204,7 +204,7 @@ void SolveSpace::GenerateAll(int first, int last, bool andFindFree) {
|
||||||
|
|
||||||
if(g->h.v == Group::HGROUP_REFERENCES.v) {
|
if(g->h.v == Group::HGROUP_REFERENCES.v) {
|
||||||
ForceReferences();
|
ForceReferences();
|
||||||
g->solved.how = Group::SOLVED_OKAY;
|
g->solved.how = System::SOLVED_OKAY;
|
||||||
g->clean = true;
|
g->clean = true;
|
||||||
} else {
|
} else {
|
||||||
if(i >= first && i <= last) {
|
if(i >= first && i <= last) {
|
||||||
|
@ -330,6 +330,60 @@ void SolveSpace::ForceReferences(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SolveSpace::MarkDraggedParams(void) {
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < System::MAX_DRAGGED; i++) {
|
||||||
|
sys.dragged[i] = Param::NO_PARAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(SS.GW.pending.point.v) {
|
||||||
|
// The pending point could be one in a group that has not yet
|
||||||
|
// been processed, in which case the lookup will fail; but
|
||||||
|
// that's not an error.
|
||||||
|
Entity *pt = SK.entity.FindByIdNoOops(SS.GW.pending.point);
|
||||||
|
if(pt) {
|
||||||
|
switch(pt->type) {
|
||||||
|
case Entity::POINT_N_TRANS:
|
||||||
|
case Entity::POINT_IN_3D:
|
||||||
|
sys.dragged[0] = pt->param[0];
|
||||||
|
sys.dragged[1] = pt->param[1];
|
||||||
|
sys.dragged[2] = pt->param[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Entity::POINT_IN_2D:
|
||||||
|
sys.dragged[0] = pt->param[0];
|
||||||
|
sys.dragged[1] = pt->param[1];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(SS.GW.pending.circle.v) {
|
||||||
|
Entity *circ = SK.entity.FindByIdNoOops(SS.GW.pending.circle);
|
||||||
|
if(circ) {
|
||||||
|
Entity *dist = SK.GetEntity(circ->distance);
|
||||||
|
switch(dist->type) {
|
||||||
|
case Entity::DISTANCE:
|
||||||
|
sys.dragged[0] = dist->param[0];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(SS.GW.pending.normal.v) {
|
||||||
|
Entity *norm = SK.entity.FindByIdNoOops(SS.GW.pending.normal);
|
||||||
|
if(norm) {
|
||||||
|
switch(norm->type) {
|
||||||
|
case Entity::NORMAL_IN_3D:
|
||||||
|
sys.dragged[0] = norm->param[0];
|
||||||
|
sys.dragged[1] = norm->param[1];
|
||||||
|
sys.dragged[2] = norm->param[2];
|
||||||
|
sys.dragged[3] = norm->param[3];
|
||||||
|
break;
|
||||||
|
// other types are locked, so not draggable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SolveSpace::SolveGroup(hGroup hg, bool andFindFree) {
|
void SolveSpace::SolveGroup(hGroup hg, bool andFindFree) {
|
||||||
int i;
|
int i;
|
||||||
// Clear out the system to be solved.
|
// Clear out the system to be solved.
|
||||||
|
@ -353,7 +407,16 @@ void SolveSpace::SolveGroup(hGroup hg, bool andFindFree) {
|
||||||
p->val = SK.GetParam(p->h)->val;
|
p->val = SK.GetParam(p->h)->val;
|
||||||
}
|
}
|
||||||
|
|
||||||
sys.Solve(g, andFindFree);
|
MarkDraggedParams();
|
||||||
|
g->solved.remove.Clear();
|
||||||
|
int how = sys.Solve(g, &(g->solved.dof),
|
||||||
|
&(g->solved.remove), andFindFree);
|
||||||
|
if((how != System::SOLVED_OKAY) ||
|
||||||
|
(how == System::SOLVED_OKAY && g->solved.how != System::SOLVED_OKAY))
|
||||||
|
{
|
||||||
|
TextWindow::ReportHowGroupSolved(g->h);
|
||||||
|
}
|
||||||
|
g->solved.how = how;
|
||||||
FreeAllTemporary();
|
FreeAllTemporary();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -361,7 +424,7 @@ bool SolveSpace::AllGroupsOkay(void) {
|
||||||
int i;
|
int i;
|
||||||
bool allOk = true;
|
bool allOk = true;
|
||||||
for(i = 0; i < SK.group.n; i++) {
|
for(i = 0; i < SK.group.n; i++) {
|
||||||
if(SK.group.elem[i].solved.how != Group::SOLVED_OKAY) {
|
if(SK.group.elem[i].solved.how != System::SOLVED_OKAY) {
|
||||||
allOk = false;
|
allOk = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
7
sketch.h
7
sketch.h
|
@ -104,9 +104,6 @@ public:
|
||||||
double valC;
|
double valC;
|
||||||
DWORD color;
|
DWORD color;
|
||||||
|
|
||||||
static const int SOLVED_OKAY = 0;
|
|
||||||
static const int DIDNT_CONVERGE = 10;
|
|
||||||
static const int SINGULAR_JACOBIAN = 11;
|
|
||||||
struct {
|
struct {
|
||||||
int how;
|
int how;
|
||||||
int dof;
|
int dof;
|
||||||
|
@ -336,7 +333,7 @@ public:
|
||||||
void WorkplaneGetPlaneExprs(ExprVector *n, Expr **d);
|
void WorkplaneGetPlaneExprs(ExprVector *n, Expr **d);
|
||||||
ExprVector WorkplaneGetOffsetExprs(void);
|
ExprVector WorkplaneGetOffsetExprs(void);
|
||||||
Vector WorkplaneGetOffset(void);
|
Vector WorkplaneGetOffset(void);
|
||||||
Entity *Normal(void);
|
EntityBase *Normal(void);
|
||||||
|
|
||||||
bool IsFace(void);
|
bool IsFace(void);
|
||||||
ExprVector FaceGetNormalExprs(void);
|
ExprVector FaceGetNormalExprs(void);
|
||||||
|
@ -350,7 +347,6 @@ public:
|
||||||
ExprVector PointGetExprs(void);
|
ExprVector PointGetExprs(void);
|
||||||
void PointGetExprsInWorkplane(hEntity wrkpl, Expr **u, Expr **v);
|
void PointGetExprsInWorkplane(hEntity wrkpl, Expr **u, Expr **v);
|
||||||
void PointForceTo(Vector v);
|
void PointForceTo(Vector v);
|
||||||
bool PointIsFromReferences(void);
|
|
||||||
// These apply only the POINT_N_ROT_TRANS, which has an assoc rotation
|
// These apply only the POINT_N_ROT_TRANS, which has an assoc rotation
|
||||||
Quaternion PointGetQuaternion(void);
|
Quaternion PointGetQuaternion(void);
|
||||||
void PointForceQuaternionTo(Quaternion q);
|
void PointForceQuaternionTo(Quaternion q);
|
||||||
|
@ -401,6 +397,7 @@ public:
|
||||||
void DrawOrGetDistance(void);
|
void DrawOrGetDistance(void);
|
||||||
|
|
||||||
bool IsVisible(void);
|
bool IsVisible(void);
|
||||||
|
bool PointIsFromReferences(void);
|
||||||
|
|
||||||
void GenerateBezierCurves(SBezierList *sbl);
|
void GenerateBezierCurves(SBezierList *sbl);
|
||||||
void GenerateEdges(SEdgeList *el, bool includingConstruction=false);
|
void GenerateEdges(SEdgeList *el, bool includingConstruction=false);
|
||||||
|
|
37
solvespace.h
37
solvespace.h
|
@ -143,6 +143,7 @@ void FreeAllTemporary(void);
|
||||||
void *MemRealloc(void *p, int n);
|
void *MemRealloc(void *p, int n);
|
||||||
void *MemAlloc(int n);
|
void *MemAlloc(int n);
|
||||||
void MemFree(void *p);
|
void MemFree(void *p);
|
||||||
|
void InitHeaps(void);
|
||||||
void vl(void); // debug function to validate heaps
|
void vl(void); // debug function to validate heaps
|
||||||
|
|
||||||
// End of platform-specific functions
|
// End of platform-specific functions
|
||||||
|
@ -202,12 +203,17 @@ void MakePathAbsolute(char *base, char *path);
|
||||||
|
|
||||||
class System {
|
class System {
|
||||||
public:
|
public:
|
||||||
#define MAX_UNKNOWNS 1000
|
static const int MAX_UNKNOWNS = 1000;
|
||||||
|
static const int MAX_DRAGGED = 4;
|
||||||
|
|
||||||
EntityList entity;
|
EntityList entity;
|
||||||
ParamList param;
|
ParamList param;
|
||||||
IdList<Equation,hEquation> eq;
|
IdList<Equation,hEquation> eq;
|
||||||
|
|
||||||
|
// A list of parameters that are being dragged; these are the ones that
|
||||||
|
// we should put as close as possible to their initial positions.
|
||||||
|
hParam dragged[MAX_DRAGGED];
|
||||||
|
|
||||||
// In general, the tag indicates the subsys that a variable/equation
|
// In general, the tag indicates the subsys that a variable/equation
|
||||||
// has been assigned to; these are exceptions for variables:
|
// has been assigned to; these are exceptions for variables:
|
||||||
static const int VAR_SUBSTITUTED = 10000;
|
static const int VAR_SUBSTITUTED = 10000;
|
||||||
|
@ -253,14 +259,19 @@ public:
|
||||||
bool WriteJacobian(int tag);
|
bool WriteJacobian(int tag);
|
||||||
void EvalJacobian(void);
|
void EvalJacobian(void);
|
||||||
|
|
||||||
void WriteEquationsExceptFor(hConstraint hc, hGroup hg);
|
void WriteEquationsExceptFor(hConstraint hc, Group *g);
|
||||||
void FindWhichToRemoveToFixJacobian(Group *g);
|
void FindWhichToRemoveToFixJacobian(Group *g, List<hConstraint> *bad);
|
||||||
void SolveBySubstitution(void);
|
void SolveBySubstitution(void);
|
||||||
|
|
||||||
static bool IsDragged(hParam p);
|
bool IsDragged(hParam p);
|
||||||
|
|
||||||
bool NewtonSolve(int tag);
|
bool NewtonSolve(int tag);
|
||||||
void Solve(Group *g, bool andFindFree);
|
|
||||||
|
static const int SOLVED_OKAY = 0;
|
||||||
|
static const int DIDNT_CONVERGE = 10;
|
||||||
|
static const int SINGULAR_JACOBIAN = 11;
|
||||||
|
static const int TOO_MANY_UNKNOWNS = 20;
|
||||||
|
int Solve(Group *g, int *dof, List<hConstraint> *bad, bool andFindFree);
|
||||||
};
|
};
|
||||||
|
|
||||||
class TtfFont {
|
class TtfFont {
|
||||||
|
@ -410,20 +421,27 @@ public:
|
||||||
void FinishAndCloseFile(void);
|
void FinishAndCloseFile(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef LIBRARY
|
||||||
|
# define ENTITY EntityBase
|
||||||
|
# define CONSTRAINT ConstraintBase
|
||||||
|
#else
|
||||||
|
# define ENTITY Entity
|
||||||
|
# define CONSTRAINT Constraint
|
||||||
|
#endif
|
||||||
class Sketch {
|
class Sketch {
|
||||||
public:
|
public:
|
||||||
// These are user-editable, and define the sketch.
|
// These are user-editable, and define the sketch.
|
||||||
IdList<Group,hGroup> group;
|
IdList<Group,hGroup> group;
|
||||||
IdList<Constraint,hConstraint> constraint;
|
IdList<CONSTRAINT,hConstraint> constraint;
|
||||||
IdList<Request,hRequest> request;
|
IdList<Request,hRequest> request;
|
||||||
|
|
||||||
// These are generated from the above.
|
// These are generated from the above.
|
||||||
IdList<Entity,hEntity> entity;
|
IdList<ENTITY,hEntity> entity;
|
||||||
IdList<Param,hParam> param;
|
IdList<Param,hParam> param;
|
||||||
|
|
||||||
inline Constraint *GetConstraint(hConstraint h)
|
inline CONSTRAINT *GetConstraint(hConstraint h)
|
||||||
{ return constraint.FindById(h); }
|
{ return constraint.FindById(h); }
|
||||||
inline Entity *GetEntity (hEntity h) { return entity. FindById(h); }
|
inline ENTITY *GetEntity (hEntity h) { return entity. FindById(h); }
|
||||||
inline Param *GetParam (hParam h) { return param. FindById(h); }
|
inline Param *GetParam (hParam h) { return param. FindById(h); }
|
||||||
inline Request *GetRequest(hRequest h) { return request.FindById(h); }
|
inline Request *GetRequest(hRequest h) { return request.FindById(h); }
|
||||||
inline Group *GetGroup (hGroup h) { return group. FindById(h); }
|
inline Group *GetGroup (hGroup h) { return group. FindById(h); }
|
||||||
|
@ -565,6 +583,7 @@ public:
|
||||||
void GenerateAll(void);
|
void GenerateAll(void);
|
||||||
void GenerateAll(int first, int last, bool andFindFree=false);
|
void GenerateAll(int first, int last, bool andFindFree=false);
|
||||||
void SolveGroup(hGroup hg, bool andFindFree);
|
void SolveGroup(hGroup hg, bool andFindFree);
|
||||||
|
void MarkDraggedParams(void);
|
||||||
void ForceReferences(void);
|
void ForceReferences(void);
|
||||||
|
|
||||||
bool AllGroupsOkay(void);
|
bool AllGroupsOkay(void);
|
||||||
|
|
106
system.cpp
106
system.cpp
|
@ -61,51 +61,9 @@ void System::EvalJacobian(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool System::IsDragged(hParam p) {
|
bool System::IsDragged(hParam p) {
|
||||||
if(SS.GW.pending.point.v) {
|
int i;
|
||||||
// The pending point could be one in a group that has not yet
|
for(i = 0; i < MAX_DRAGGED; i++) {
|
||||||
// been processed, in which case the lookup will fail; but
|
if(p.v == dragged[i].v) return true;
|
||||||
// that's not an error.
|
|
||||||
Entity *pt = SK.entity.FindByIdNoOops(SS.GW.pending.point);
|
|
||||||
if(pt) {
|
|
||||||
switch(pt->type) {
|
|
||||||
case Entity::POINT_N_TRANS:
|
|
||||||
case Entity::POINT_IN_3D:
|
|
||||||
if(p.v == (pt->param[0]).v) return true;
|
|
||||||
if(p.v == (pt->param[1]).v) return true;
|
|
||||||
if(p.v == (pt->param[2]).v) return true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Entity::POINT_IN_2D:
|
|
||||||
if(p.v == (pt->param[0]).v) return true;
|
|
||||||
if(p.v == (pt->param[1]).v) return true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(SS.GW.pending.circle.v) {
|
|
||||||
Entity *circ = SK.entity.FindByIdNoOops(SS.GW.pending.circle);
|
|
||||||
if(circ) {
|
|
||||||
Entity *dist = SK.GetEntity(circ->distance);
|
|
||||||
switch(dist->type) {
|
|
||||||
case Entity::DISTANCE:
|
|
||||||
if(p.v == (dist->param[0].v)) return true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(SS.GW.pending.normal.v) {
|
|
||||||
Entity *norm = SK.entity.FindByIdNoOops(SS.GW.pending.normal);
|
|
||||||
if(norm) {
|
|
||||||
switch(norm->type) {
|
|
||||||
case Entity::NORMAL_IN_3D:
|
|
||||||
if(p.v == (norm->param[0].v)) return true;
|
|
||||||
if(p.v == (norm->param[1].v)) return true;
|
|
||||||
if(p.v == (norm->param[2].v)) return true;
|
|
||||||
if(p.v == (norm->param[3].v)) return true;
|
|
||||||
break;
|
|
||||||
// other types are locked, so not draggable
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -346,34 +304,33 @@ bool System::NewtonSolve(int tag) {
|
||||||
return converged;
|
return converged;
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::WriteEquationsExceptFor(hConstraint hc, hGroup hg) {
|
void System::WriteEquationsExceptFor(hConstraint hc, Group *g) {
|
||||||
int i;
|
int i;
|
||||||
// Generate all the equations from constraints in this group
|
// Generate all the equations from constraints in this group
|
||||||
for(i = 0; i < SK.constraint.n; i++) {
|
for(i = 0; i < SK.constraint.n; i++) {
|
||||||
Constraint *c = &(SK.constraint.elem[i]);
|
ConstraintBase *c = &(SK.constraint.elem[i]);
|
||||||
if(c->group.v != hg.v) continue;
|
if(c->group.v != g->h.v) continue;
|
||||||
if(c->h.v == hc.v) continue;
|
if(c->h.v == hc.v) continue;
|
||||||
|
|
||||||
c->Generate(&eq);
|
c->Generate(&eq);
|
||||||
}
|
}
|
||||||
// And the equations from entities
|
// And the equations from entities
|
||||||
for(i = 0; i < SK.entity.n; i++) {
|
for(i = 0; i < SK.entity.n; i++) {
|
||||||
Entity *e = &(SK.entity.elem[i]);
|
EntityBase *e = &(SK.entity.elem[i]);
|
||||||
if(e->group.v != hg.v) continue;
|
if(e->group.v != g->h.v) continue;
|
||||||
|
|
||||||
e->GenerateEquations(&eq);
|
e->GenerateEquations(&eq);
|
||||||
}
|
}
|
||||||
// And from the groups themselves
|
// And from the groups themselves
|
||||||
(SK.GetGroup(hg))->GenerateEquations(&eq);
|
g->GenerateEquations(&eq);
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::FindWhichToRemoveToFixJacobian(Group *g) {
|
void System::FindWhichToRemoveToFixJacobian(Group *g, List<hConstraint> *bad) {
|
||||||
int a, i;
|
int a, i;
|
||||||
(g->solved.remove).Clear();
|
|
||||||
|
|
||||||
for(a = 0; a < 2; a++) {
|
for(a = 0; a < 2; a++) {
|
||||||
for(i = 0; i < SK.constraint.n; i++) {
|
for(i = 0; i < SK.constraint.n; i++) {
|
||||||
Constraint *c = &(SK.constraint.elem[i]);
|
ConstraintBase *c = &(SK.constraint.elem[i]);
|
||||||
if(c->group.v != g->h.v) continue;
|
if(c->group.v != g->h.v) continue;
|
||||||
if((c->type == Constraint::POINTS_COINCIDENT && a == 0) ||
|
if((c->type == Constraint::POINTS_COINCIDENT && a == 0) ||
|
||||||
(c->type != Constraint::POINTS_COINCIDENT && a == 1))
|
(c->type != Constraint::POINTS_COINCIDENT && a == 1))
|
||||||
|
@ -386,7 +343,7 @@ void System::FindWhichToRemoveToFixJacobian(Group *g) {
|
||||||
|
|
||||||
param.ClearTags();
|
param.ClearTags();
|
||||||
eq.Clear();
|
eq.Clear();
|
||||||
WriteEquationsExceptFor(c->h, g->h);
|
WriteEquationsExceptFor(c->h, g);
|
||||||
eq.ClearTags();
|
eq.ClearTags();
|
||||||
|
|
||||||
// It's a major speedup to solve the easy ones by substitution here,
|
// It's a major speedup to solve the easy ones by substitution here,
|
||||||
|
@ -399,16 +356,16 @@ void System::FindWhichToRemoveToFixJacobian(Group *g) {
|
||||||
int rank = CalculateRank();
|
int rank = CalculateRank();
|
||||||
if(rank == mat.m) {
|
if(rank == mat.m) {
|
||||||
// We fixed it by removing this constraint
|
// We fixed it by removing this constraint
|
||||||
(g->solved.remove).Add(&(c->h));
|
bad->Add(&(c->h));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::Solve(Group *g, bool andFindFree) {
|
int System::Solve(Group *g, int *dof, List<hConstraint> *bad,
|
||||||
g->solved.remove.Clear();
|
bool andFindFree)
|
||||||
|
{
|
||||||
WriteEquationsExceptFor(Constraint::NO_CONSTRAINT, g->h);
|
WriteEquationsExceptFor(Constraint::NO_CONSTRAINT, g);
|
||||||
|
|
||||||
int i, j = 0;
|
int i, j = 0;
|
||||||
/*
|
/*
|
||||||
|
@ -456,25 +413,20 @@ void System::Solve(Group *g, bool andFindFree) {
|
||||||
// Now write the Jacobian for what's left, and do a rank test; that
|
// Now write the Jacobian for what's left, and do a rank test; that
|
||||||
// tells us if the system is inconsistently constrained.
|
// tells us if the system is inconsistently constrained.
|
||||||
if(!WriteJacobian(0)) {
|
if(!WriteJacobian(0)) {
|
||||||
g->solved.how = Group::TOO_MANY_UNKNOWNS;
|
return System::TOO_MANY_UNKNOWNS;
|
||||||
TextWindow::ReportHowGroupSolved(g->h);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EvalJacobian();
|
EvalJacobian();
|
||||||
|
|
||||||
int rank = CalculateRank();
|
int rank = CalculateRank();
|
||||||
if(rank != mat.m) {
|
if(rank != mat.m) {
|
||||||
FindWhichToRemoveToFixJacobian(g);
|
FindWhichToRemoveToFixJacobian(g, bad);
|
||||||
g->solved.how = Group::SINGULAR_JACOBIAN;
|
return System::SINGULAR_JACOBIAN;
|
||||||
g->solved.dof = 0;
|
|
||||||
TextWindow::ReportHowGroupSolved(g->h);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
// This is not the full Jacobian, but any substitutions or single-eq
|
// This is not the full Jacobian, but any substitutions or single-eq
|
||||||
// solves removed one equation and one unknown, therefore no effect
|
// solves removed one equation and one unknown, therefore no effect
|
||||||
// on the number of DOF.
|
// on the number of DOF.
|
||||||
g->solved.dof = mat.n - mat.m;
|
if(dof) *dof = mat.n - mat.m;
|
||||||
|
|
||||||
// And do the leftovers as one big system
|
// And do the leftovers as one big system
|
||||||
if(!NewtonSolve(0)) {
|
if(!NewtonSolve(0)) {
|
||||||
|
@ -517,15 +469,9 @@ void System::Solve(Group *g, bool andFindFree) {
|
||||||
pp->known = true;
|
pp->known = true;
|
||||||
pp->free = p->free;
|
pp->free = p->free;
|
||||||
}
|
}
|
||||||
if(g->solved.how != Group::SOLVED_OKAY) {
|
return System::SOLVED_OKAY;
|
||||||
g->solved.how = Group::SOLVED_OKAY;
|
|
||||||
TextWindow::ReportHowGroupSolved(g->h);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
|
|
||||||
didnt_converge:
|
didnt_converge:
|
||||||
g->solved.how = Group::DIDNT_CONVERGE;
|
|
||||||
(g->solved.remove).Clear();
|
|
||||||
SK.constraint.ClearTags();
|
SK.constraint.ClearTags();
|
||||||
for(i = 0; i < eq.n; i++) {
|
for(i = 0; i < eq.n; i++) {
|
||||||
if(fabs(mat.B.num[i]) > CONVERGE_TOLERANCE || isnan(mat.B.num[i])) {
|
if(fabs(mat.B.num[i]) > CONVERGE_TOLERANCE || isnan(mat.B.num[i])) {
|
||||||
|
@ -533,17 +479,17 @@ didnt_converge:
|
||||||
if(!mat.eq[i].isFromConstraint()) continue;
|
if(!mat.eq[i].isFromConstraint()) continue;
|
||||||
|
|
||||||
hConstraint hc = mat.eq[i].constraint();
|
hConstraint hc = mat.eq[i].constraint();
|
||||||
Constraint *c = SK.constraint.FindByIdNoOops(hc);
|
ConstraintBase *c = SK.constraint.FindByIdNoOops(hc);
|
||||||
if(!c) continue;
|
if(!c) continue;
|
||||||
// Don't double-show constraints that generated multiple
|
// Don't double-show constraints that generated multiple
|
||||||
// unsatisfied equations
|
// unsatisfied equations
|
||||||
if(!c->tag) {
|
if(!c->tag) {
|
||||||
(g->solved.remove).Add(&(c->h));
|
bad->Add(&(c->h));
|
||||||
c->tag = 1;
|
c->tag = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TextWindow::ReportHowGroupSolved(g->h);
|
return System::DIDNT_CONVERGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -112,7 +112,7 @@ void TextWindow::ShowListOfGroups(void) {
|
||||||
char *s = g->DescriptionString();
|
char *s = g->DescriptionString();
|
||||||
bool active = (g->h.v == SS.GW.activeGroup.v);
|
bool active = (g->h.v == SS.GW.activeGroup.v);
|
||||||
bool shown = g->visible;
|
bool shown = g->visible;
|
||||||
bool ok = (g->solved.how == Group::SOLVED_OKAY);
|
bool ok = (g->solved.how == System::SOLVED_OKAY);
|
||||||
bool ref = (g->h.v == Group::HGROUP_REFERENCES.v);
|
bool ref = (g->h.v == Group::HGROUP_REFERENCES.v);
|
||||||
Printf(false, "%Bp%Fd "
|
Printf(false, "%Bp%Fd "
|
||||||
"%Fp%D%f%s%Ll%s%E%s "
|
"%Fp%D%f%s%Ll%s%E%s "
|
||||||
|
@ -498,7 +498,7 @@ void TextWindow::ShowGroupInfo(void) {
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void TextWindow::ShowGroupSolveInfo(void) {
|
void TextWindow::ShowGroupSolveInfo(void) {
|
||||||
Group *g = SK.group.FindById(shown.group);
|
Group *g = SK.group.FindById(shown.group);
|
||||||
if(g->solved.how == Group::SOLVED_OKAY) {
|
if(g->solved.how == System::SOLVED_OKAY) {
|
||||||
// Go back to the default group info screen
|
// Go back to the default group info screen
|
||||||
shown.screen = SCREEN_GROUP_INFO;
|
shown.screen = SCREEN_GROUP_INFO;
|
||||||
Show();
|
Show();
|
||||||
|
@ -507,17 +507,17 @@ void TextWindow::ShowGroupSolveInfo(void) {
|
||||||
|
|
||||||
Printf(true, "%FtGROUP %E%s", g->DescriptionString());
|
Printf(true, "%FtGROUP %E%s", g->DescriptionString());
|
||||||
switch(g->solved.how) {
|
switch(g->solved.how) {
|
||||||
case Group::DIDNT_CONVERGE:
|
case System::DIDNT_CONVERGE:
|
||||||
Printf(true, "%FxSOLVE FAILED!%Fd no convergence");
|
Printf(true, "%FxSOLVE FAILED!%Fd no convergence");
|
||||||
Printf(true, "the following constraints are unsatisfied");
|
Printf(true, "the following constraints are unsatisfied");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Group::SINGULAR_JACOBIAN:
|
case System::SINGULAR_JACOBIAN:
|
||||||
Printf(true, "%FxSOLVE FAILED!%Fd inconsistent system");
|
Printf(true, "%FxSOLVE FAILED!%Fd inconsistent system");
|
||||||
Printf(true, "remove any one of these to fix it");
|
Printf(true, "remove any one of these to fix it");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Group::TOO_MANY_UNKNOWNS:
|
case System::TOO_MANY_UNKNOWNS:
|
||||||
Printf(true, "Too many unknowns in a single group!");
|
Printf(true, "Too many unknowns in a single group!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
4
util.cpp
4
util.cpp
|
@ -504,7 +504,7 @@ Vector Vector::WithMagnitude(double v) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector Vector::ProjectVectorInto(hEntity wrkpl) {
|
Vector Vector::ProjectVectorInto(hEntity wrkpl) {
|
||||||
Entity *w = SK.GetEntity(wrkpl);
|
EntityBase *w = SK.GetEntity(wrkpl);
|
||||||
Vector u = w->Normal()->NormalU();
|
Vector u = w->Normal()->NormalU();
|
||||||
Vector v = w->Normal()->NormalV();
|
Vector v = w->Normal()->NormalV();
|
||||||
|
|
||||||
|
@ -515,7 +515,7 @@ Vector Vector::ProjectVectorInto(hEntity wrkpl) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector Vector::ProjectInto(hEntity wrkpl) {
|
Vector Vector::ProjectInto(hEntity wrkpl) {
|
||||||
Entity *w = SK.GetEntity(wrkpl);
|
EntityBase *w = SK.GetEntity(wrkpl);
|
||||||
Vector p0 = w->WorkplaneGetOffset();
|
Vector p0 = w->WorkplaneGetOffset();
|
||||||
|
|
||||||
Vector f = this->Minus(p0);
|
Vector f = this->Minus(p0);
|
||||||
|
|
|
@ -49,18 +49,6 @@ int ClientIsSmallerBy;
|
||||||
|
|
||||||
HFONT FixedFont, LinkFont;
|
HFONT FixedFont, LinkFont;
|
||||||
|
|
||||||
void dbp(char *str, ...)
|
|
||||||
{
|
|
||||||
va_list f;
|
|
||||||
static char buf[1024*50];
|
|
||||||
va_start(f, str);
|
|
||||||
_vsnprintf(buf, sizeof(buf), str, f);
|
|
||||||
va_end(f);
|
|
||||||
|
|
||||||
OutputDebugString(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void DoMessageBox(char *str, va_list f, BOOL error)
|
static void DoMessageBox(char *str, va_list f, BOOL error)
|
||||||
{
|
{
|
||||||
char buf[1024*50];
|
char buf[1024*50];
|
||||||
|
@ -159,56 +147,6 @@ void SetWindowTitle(char *str) {
|
||||||
SetWindowText(GraphicsWnd, str);
|
SetWindowText(GraphicsWnd, str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// A separate heap, on which we allocate expressions. Maybe a bit faster,
|
|
||||||
// since no fragmentation issues whatsoever, and it also makes it possible
|
|
||||||
// to be sloppy with our memory management, and just free everything at once
|
|
||||||
// at the end.
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
static HANDLE Temp;
|
|
||||||
void *AllocTemporary(int n)
|
|
||||||
{
|
|
||||||
void *v = HeapAlloc(Temp, HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY, n);
|
|
||||||
if(!v) oops();
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
void FreeTemporary(void *p) {
|
|
||||||
HeapFree(Temp, HEAP_NO_SERIALIZE, p);
|
|
||||||
}
|
|
||||||
void FreeAllTemporary(void)
|
|
||||||
{
|
|
||||||
if(Temp) HeapDestroy(Temp);
|
|
||||||
Temp = HeapCreate(HEAP_NO_SERIALIZE, 1024*1024*20, 0);
|
|
||||||
// This is a good place to validate, because it gets called fairly
|
|
||||||
// often.
|
|
||||||
vl();
|
|
||||||
}
|
|
||||||
|
|
||||||
static HANDLE Perm;
|
|
||||||
void *MemRealloc(void *p, int n) {
|
|
||||||
if(!p) {
|
|
||||||
return MemAlloc(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
p = HeapReAlloc(Perm, HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY, p, n);
|
|
||||||
if(!p) oops();
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
void *MemAlloc(int n) {
|
|
||||||
void *p = HeapAlloc(Perm, HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY, n);
|
|
||||||
if(!p) oops();
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
void MemFree(void *p) {
|
|
||||||
HeapFree(Perm, HEAP_NO_SERIALIZE, p);
|
|
||||||
}
|
|
||||||
|
|
||||||
void vl(void) {
|
|
||||||
if(!HeapValidate(Temp, HEAP_NO_SERIALIZE, NULL)) oops();
|
|
||||||
if(!HeapValidate(Perm, HEAP_NO_SERIALIZE, NULL)) oops();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void PaintTextWnd(HDC hdc)
|
static void PaintTextWnd(HDC hdc)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -892,13 +830,6 @@ int SaveFileYesNoCancel(void)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetAbsoluteFilename(char *file)
|
|
||||||
{
|
|
||||||
char absoluteFile[MAX_PATH];
|
|
||||||
GetFullPathName(file, sizeof(absoluteFile), absoluteFile, NULL);
|
|
||||||
strcpy(file, absoluteFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
void LoadAllFontFiles(void)
|
void LoadAllFontFiles(void)
|
||||||
{
|
{
|
||||||
WIN32_FIND_DATA wfd;
|
WIN32_FIND_DATA wfd;
|
||||||
|
@ -1114,10 +1045,8 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
||||||
ThawWindowPos(TextWnd);
|
ThawWindowPos(TextWnd);
|
||||||
ThawWindowPos(GraphicsWnd);
|
ThawWindowPos(GraphicsWnd);
|
||||||
|
|
||||||
// Create the heap used for long-lived stuff (that gets freed piecewise).
|
// Create the heaps for all dynamic memory (AllocTemporary, MemAlloc)
|
||||||
Perm = HeapCreate(HEAP_NO_SERIALIZE, 1024*1024*20, 0);
|
InitHeaps();
|
||||||
// Create the heap that we use to store Exprs and other temp stuff.
|
|
||||||
FreeAllTemporary();
|
|
||||||
|
|
||||||
// A filename may have been specified on the command line; if so, then
|
// A filename may have been specified on the command line; if so, then
|
||||||
// strip any quotation marks, and make it absolute.
|
// strip any quotation marks, and make it absolute.
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
#include <windows.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "solvespace.h"
|
||||||
|
|
||||||
|
static HANDLE PermHeap, TempHeap;
|
||||||
|
|
||||||
|
void dbp(char *str, ...)
|
||||||
|
{
|
||||||
|
va_list f;
|
||||||
|
static char buf[1024*50];
|
||||||
|
va_start(f, str);
|
||||||
|
_vsnprintf(buf, sizeof(buf), str, f);
|
||||||
|
va_end(f);
|
||||||
|
|
||||||
|
OutputDebugString(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetAbsoluteFilename(char *file)
|
||||||
|
{
|
||||||
|
char absoluteFile[MAX_PATH];
|
||||||
|
GetFullPathName(file, sizeof(absoluteFile), absoluteFile, NULL);
|
||||||
|
strcpy(file, absoluteFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// A separate heap, on which we allocate expressions. Maybe a bit faster,
|
||||||
|
// since no fragmentation issues whatsoever, and it also makes it possible
|
||||||
|
// to be sloppy with our memory management, and just free everything at once
|
||||||
|
// at the end.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
void *AllocTemporary(int n)
|
||||||
|
{
|
||||||
|
void *v = HeapAlloc(TempHeap, HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY, n);
|
||||||
|
if(!v) oops();
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
void FreeTemporary(void *p) {
|
||||||
|
HeapFree(TempHeap, HEAP_NO_SERIALIZE, p);
|
||||||
|
}
|
||||||
|
void FreeAllTemporary(void)
|
||||||
|
{
|
||||||
|
if(TempHeap) HeapDestroy(TempHeap);
|
||||||
|
TempHeap = HeapCreate(HEAP_NO_SERIALIZE, 1024*1024*20, 0);
|
||||||
|
// This is a good place to validate, because it gets called fairly
|
||||||
|
// often.
|
||||||
|
vl();
|
||||||
|
}
|
||||||
|
|
||||||
|
void *MemRealloc(void *p, int n) {
|
||||||
|
if(!p) {
|
||||||
|
return MemAlloc(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
p = HeapReAlloc(PermHeap, HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY, p, n);
|
||||||
|
if(!p) oops();
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
void *MemAlloc(int n) {
|
||||||
|
void *p = HeapAlloc(PermHeap, HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY, n);
|
||||||
|
if(!p) oops();
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
void MemFree(void *p) {
|
||||||
|
HeapFree(PermHeap, HEAP_NO_SERIALIZE, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vl(void) {
|
||||||
|
if(!HeapValidate(TempHeap, HEAP_NO_SERIALIZE, NULL)) oops();
|
||||||
|
if(!HeapValidate(PermHeap, HEAP_NO_SERIALIZE, NULL)) oops();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitHeaps(void) {
|
||||||
|
// Create the heap used for long-lived stuff (that gets freed piecewise).
|
||||||
|
PermHeap = HeapCreate(HEAP_NO_SERIALIZE, 1024*1024*20, 0);
|
||||||
|
// Create the heap that we use to store Exprs and other temp stuff.
|
||||||
|
FreeAllTemporary();
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue