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
|
||||
|
||||
W32OBJS = $(OBJDIR)\w32main.obj \
|
||||
$(OBJDIR)\w32util.obj \
|
||||
|
||||
SSOBJS = $(OBJDIR)\solvespace.obj \
|
||||
$(OBJDIR)\textwin.obj \
|
||||
|
|
|
@ -387,7 +387,7 @@ void Constraint::MenuConstrain(int id) {
|
|||
Vector pa = SK.GetEntity(c.ptA)->PointGetNum();
|
||||
Vector pb = SK.GetEntity(c.ptB)->PointGetNum();
|
||||
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();
|
||||
if(fabs(dp.Dot(u)) > fabs(dp.Dot(v))) {
|
||||
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)
|
||||
{
|
||||
Entity *ln = SK.GetEntity(hln);
|
||||
Entity *a = SK.GetEntity(ln->point[0]);
|
||||
Entity *b = SK.GetEntity(ln->point[1]);
|
||||
EntityBase *ln = SK.GetEntity(hln);
|
||||
EntityBase *a = SK.GetEntity(ln->point[0]);
|
||||
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 ea = a->PointGetExprs();
|
||||
|
@ -76,11 +76,11 @@ Expr *ConstraintBase::PointPlaneDistance(ExprVector p, hEntity hpl) {
|
|||
}
|
||||
|
||||
Expr *ConstraintBase::Distance(hEntity wrkpl, hEntity hpa, hEntity hpb) {
|
||||
Entity *pa = SK.GetEntity(hpa);
|
||||
Entity *pb = SK.GetEntity(hpb);
|
||||
EntityBase *pa = SK.GetEntity(hpa);
|
||||
EntityBase *pb = SK.GetEntity(hpb);
|
||||
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
|
||||
ExprVector ea, eb, eab;
|
||||
ea = pa->PointGetExprs();
|
||||
|
@ -109,11 +109,11 @@ Expr *ConstraintBase::Distance(hEntity wrkpl, hEntity hpa, hEntity hpb) {
|
|||
Expr *ConstraintBase::DirectionCosine(hEntity wrkpl,
|
||||
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());
|
||||
return (ae.Dot(be))->Div(mags);
|
||||
} else {
|
||||
Entity *w = SK.GetEntity(wrkpl);
|
||||
EntityBase *w = SK.GetEntity(wrkpl);
|
||||
ExprVector u = w->Normal()->NormalExprsU();
|
||||
ExprVector v = w->Normal()->NormalExprsV();
|
||||
Expr *ua = u.Dot(ae);
|
||||
|
@ -130,7 +130,7 @@ Expr *ConstraintBase::DirectionCosine(hEntity wrkpl,
|
|||
ExprVector ConstraintBase::PointInThreeSpace(hEntity workplane,
|
||||
Expr *u, Expr *v)
|
||||
{
|
||||
Entity *w = SK.GetEntity(workplane);
|
||||
EntityBase *w = SK.GetEntity(workplane);
|
||||
|
||||
ExprVector ub = w->Normal()->NormalExprsU();
|
||||
ExprVector vb = w->Normal()->NormalExprsV();
|
||||
|
@ -144,7 +144,7 @@ void ConstraintBase::ModifyToSatisfy(void) {
|
|||
Vector a = SK.GetEntity(entityA)->VectorGetNum();
|
||||
Vector b = SK.GetEntity(entityB)->VectorGetNum();
|
||||
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);
|
||||
b = b.ProjectVectorInto(workplane);
|
||||
}
|
||||
|
@ -202,7 +202,7 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
|||
|
||||
case PT_FACE_DISTANCE: {
|
||||
ExprVector pt = SK.GetEntity(ptA)->PointGetExprs();
|
||||
Entity *f = SK.GetEntity(entityA);
|
||||
EntityBase *f = SK.GetEntity(entityA);
|
||||
ExprVector p0 = f->FaceGetPointExprs();
|
||||
ExprVector n = f->FaceGetNormalExprs();
|
||||
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: {
|
||||
Entity *a = SK.GetEntity(entityA);
|
||||
Entity *b = SK.GetEntity(entityB);
|
||||
EntityBase *a = SK.GetEntity(entityA);
|
||||
EntityBase *b = SK.GetEntity(entityB);
|
||||
AddEq(l, Distance(workplane, a->point[0], a->point[1])->Minus(
|
||||
Distance(workplane, b->point[0], b->point[1])), 0);
|
||||
break;
|
||||
|
@ -220,7 +220,7 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
|||
// These work on distance squared, since the pt-line distances are
|
||||
// signed, and we want the absolute value.
|
||||
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 *d2 = PointLineDistance(workplane, ptA, entityB);
|
||||
AddEq(l, (d1->Square())->Minus(d2->Square()), 0);
|
||||
|
@ -234,8 +234,8 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
|||
}
|
||||
|
||||
case LENGTH_RATIO: {
|
||||
Entity *a = SK.GetEntity(entityA);
|
||||
Entity *b = SK.GetEntity(entityB);
|
||||
EntityBase *a = SK.GetEntity(entityA);
|
||||
EntityBase *b = SK.GetEntity(entityB);
|
||||
Expr *la = Distance(workplane, a->point[0], a->point[1]);
|
||||
Expr *lb = Distance(workplane, b->point[0], b->point[1]);
|
||||
AddEq(l, (la->Div(lb))->Minus(exA), 0);
|
||||
|
@ -243,23 +243,23 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
|||
}
|
||||
|
||||
case DIAMETER: {
|
||||
Entity *circle = SK.GetEntity(entityA);
|
||||
EntityBase *circle = SK.GetEntity(entityA);
|
||||
Expr *r = circle->CircleGetRadiusExpr();
|
||||
AddEq(l, (r->Times(Expr::From(2)))->Minus(exA), 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case EQUAL_RADIUS: {
|
||||
Entity *c1 = SK.GetEntity(entityA);
|
||||
Entity *c2 = SK.GetEntity(entityB);
|
||||
EntityBase *c1 = SK.GetEntity(entityA);
|
||||
EntityBase *c2 = SK.GetEntity(entityB);
|
||||
AddEq(l, (c1->CircleGetRadiusExpr())->Minus(
|
||||
c2->CircleGetRadiusExpr()), 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case EQUAL_LINE_ARC_LEN: {
|
||||
Entity *line = SK.GetEntity(entityA),
|
||||
*arc = SK.GetEntity(entityB);
|
||||
EntityBase *line = SK.GetEntity(entityA),
|
||||
*arc = SK.GetEntity(entityB);
|
||||
|
||||
// Get the line length
|
||||
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();
|
||||
|
||||
// And get the arc radius, and the cosine of its angle
|
||||
Entity *ao = SK.GetEntity(arc->point[0]),
|
||||
*as = SK.GetEntity(arc->point[1]),
|
||||
*af = SK.GetEntity(arc->point[2]);
|
||||
EntityBase *ao = SK.GetEntity(arc->point[0]),
|
||||
*as = SK.GetEntity(arc->point[1]),
|
||||
*af = SK.GetEntity(arc->point[2]);
|
||||
|
||||
ExprVector aos = (as->PointGetExprs()).Minus(ao->PointGetExprs()),
|
||||
aof = (af->PointGetExprs()).Minus(ao->PointGetExprs());
|
||||
|
@ -301,9 +301,9 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
|||
}
|
||||
|
||||
case POINTS_COINCIDENT: {
|
||||
Entity *a = SK.GetEntity(ptA);
|
||||
Entity *b = SK.GetEntity(ptB);
|
||||
if(workplane.v == Entity::FREE_IN_3D.v) {
|
||||
EntityBase *a = SK.GetEntity(ptA);
|
||||
EntityBase *b = SK.GetEntity(ptB);
|
||||
if(workplane.v == EntityBase::FREE_IN_3D.v) {
|
||||
ExprVector pa = a->PointGetExprs();
|
||||
ExprVector pb = b->PointGetExprs();
|
||||
AddEq(l, pa.x->Minus(pb.x), 0);
|
||||
|
@ -329,7 +329,7 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
|||
case PT_ON_FACE: {
|
||||
// a plane, n dot (p - p0) = 0
|
||||
ExprVector p = SK.GetEntity(ptA)->PointGetExprs();
|
||||
Entity *f = SK.GetEntity(entityA);
|
||||
EntityBase *f = SK.GetEntity(entityA);
|
||||
ExprVector p0 = f->FaceGetPointExprs();
|
||||
ExprVector n = f->FaceGetNormalExprs();
|
||||
AddEq(l, (p.Minus(p0)).Dot(n), 0);
|
||||
|
@ -337,11 +337,11 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
|||
}
|
||||
|
||||
case PT_ON_LINE:
|
||||
if(workplane.v == Entity::FREE_IN_3D.v) {
|
||||
Entity *ln = SK.GetEntity(entityA);
|
||||
Entity *a = SK.GetEntity(ln->point[0]);
|
||||
Entity *b = SK.GetEntity(ln->point[1]);
|
||||
Entity *p = SK.GetEntity(ptA);
|
||||
if(workplane.v == EntityBase::FREE_IN_3D.v) {
|
||||
EntityBase *ln = SK.GetEntity(entityA);
|
||||
EntityBase *a = SK.GetEntity(ln->point[0]);
|
||||
EntityBase *b = SK.GetEntity(ln->point[1]);
|
||||
EntityBase *p = SK.GetEntity(ptA);
|
||||
|
||||
ExprVector ep = p->PointGetExprs();
|
||||
ExprVector ea = a->PointGetExprs();
|
||||
|
@ -370,10 +370,10 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
|||
|
||||
case PT_ON_CIRCLE: {
|
||||
// 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 pt = SK.GetEntity(ptA)->PointGetExprs();
|
||||
Entity *normal = SK.GetEntity(circle->normal);
|
||||
EntityBase *normal = SK.GetEntity(circle->normal);
|
||||
ExprVector u = normal->NormalExprsU(),
|
||||
v = normal->NormalExprsV();
|
||||
|
||||
|
@ -388,8 +388,8 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
|||
}
|
||||
|
||||
case AT_MIDPOINT:
|
||||
if(workplane.v == Entity::FREE_IN_3D.v) {
|
||||
Entity *ln = SK.GetEntity(entityA);
|
||||
if(workplane.v == EntityBase::FREE_IN_3D.v) {
|
||||
EntityBase *ln = SK.GetEntity(entityA);
|
||||
ExprVector a = SK.GetEntity(ln->point[0])->PointGetExprs();
|
||||
ExprVector b = SK.GetEntity(ln->point[1])->PointGetExprs();
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
Entity *ln = SK.GetEntity(entityA);
|
||||
Entity *a = SK.GetEntity(ln->point[0]);
|
||||
Entity *b = SK.GetEntity(ln->point[1]);
|
||||
EntityBase *ln = SK.GetEntity(entityA);
|
||||
EntityBase *a = SK.GetEntity(ln->point[0]);
|
||||
EntityBase *b = SK.GetEntity(ln->point[1]);
|
||||
|
||||
Expr *au, *av, *bu, *bv;
|
||||
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));
|
||||
|
||||
if(ptA.v) {
|
||||
Entity *p = SK.GetEntity(ptA);
|
||||
EntityBase *p = SK.GetEntity(ptA);
|
||||
Expr *pu, *pv;
|
||||
p->PointGetExprsInWorkplane(workplane, &pu, &pv);
|
||||
AddEq(l, pu->Minus(mu), 0);
|
||||
|
@ -427,10 +427,10 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
|||
break;
|
||||
|
||||
case SYMMETRIC:
|
||||
if(workplane.v == Entity::FREE_IN_3D.v) {
|
||||
Entity *plane = SK.GetEntity(entityA);
|
||||
Entity *ea = SK.GetEntity(ptA);
|
||||
Entity *eb = SK.GetEntity(ptB);
|
||||
if(workplane.v == EntityBase::FREE_IN_3D.v) {
|
||||
EntityBase *plane = SK.GetEntity(entityA);
|
||||
EntityBase *ea = SK.GetEntity(ptA);
|
||||
EntityBase *eb = SK.GetEntity(ptB);
|
||||
ExprVector a = ea->PointGetExprs();
|
||||
ExprVector b = eb->PointGetExprs();
|
||||
|
||||
|
@ -447,9 +447,9 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
|||
AddEq(l, au->Minus(bu), 1);
|
||||
AddEq(l, av->Minus(bv), 2);
|
||||
} else {
|
||||
Entity *plane = SK.GetEntity(entityA);
|
||||
Entity *a = SK.GetEntity(ptA);
|
||||
Entity *b = SK.GetEntity(ptB);
|
||||
EntityBase *plane = SK.GetEntity(entityA);
|
||||
EntityBase *a = SK.GetEntity(ptA);
|
||||
EntityBase *b = SK.GetEntity(ptB);
|
||||
|
||||
Expr *au, *av, *bu, *bv;
|
||||
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
|
||||
// plane of symmetry). The line connecting the points is
|
||||
// perpendicular to that constructed vector.
|
||||
Entity *w = SK.GetEntity(workplane);
|
||||
EntityBase *w = SK.GetEntity(workplane);
|
||||
ExprVector u = w->Normal()->NormalExprsU();
|
||||
ExprVector v = w->Normal()->NormalExprsV();
|
||||
|
||||
|
@ -479,8 +479,8 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
|||
|
||||
case SYMMETRIC_HORIZ:
|
||||
case SYMMETRIC_VERT: {
|
||||
Entity *a = SK.GetEntity(ptA);
|
||||
Entity *b = SK.GetEntity(ptB);
|
||||
EntityBase *a = SK.GetEntity(ptA);
|
||||
EntityBase *b = SK.GetEntity(ptB);
|
||||
|
||||
Expr *au, *av, *bu, *bv;
|
||||
a->PointGetExprsInWorkplane(workplane, &au, &av);
|
||||
|
@ -497,16 +497,16 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
|||
}
|
||||
|
||||
case SYMMETRIC_LINE: {
|
||||
Entity *pa = SK.GetEntity(ptA);
|
||||
Entity *pb = SK.GetEntity(ptB);
|
||||
EntityBase *pa = SK.GetEntity(ptA);
|
||||
EntityBase *pb = SK.GetEntity(ptB);
|
||||
|
||||
Expr *pau, *pav, *pbu, *pbv;
|
||||
pa->PointGetExprsInWorkplane(workplane, &pau, &pav);
|
||||
pb->PointGetExprsInWorkplane(workplane, &pbu, &pbv);
|
||||
|
||||
Entity *ln = SK.GetEntity(entityA);
|
||||
Entity *la = SK.GetEntity(ln->point[0]);
|
||||
Entity *lb = SK.GetEntity(ln->point[1]);
|
||||
EntityBase *ln = SK.GetEntity(entityA);
|
||||
EntityBase *la = SK.GetEntity(ln->point[0]);
|
||||
EntityBase *lb = SK.GetEntity(ln->point[1]);
|
||||
Expr *lau, *lav, *lbu, *lbv;
|
||||
la->PointGetExprsInWorkplane(workplane, &lau, &lav);
|
||||
lb->PointGetExprsInWorkplane(workplane, &lbu, &lbv);
|
||||
|
@ -533,15 +533,15 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
|||
case VERTICAL: {
|
||||
hEntity ha, hb;
|
||||
if(entityA.v) {
|
||||
Entity *e = SK.GetEntity(entityA);
|
||||
EntityBase *e = SK.GetEntity(entityA);
|
||||
ha = e->point[0];
|
||||
hb = e->point[1];
|
||||
} else {
|
||||
ha = ptA;
|
||||
hb = ptB;
|
||||
}
|
||||
Entity *a = SK.GetEntity(ha);
|
||||
Entity *b = SK.GetEntity(hb);
|
||||
EntityBase *a = SK.GetEntity(ha);
|
||||
EntityBase *b = SK.GetEntity(hb);
|
||||
|
||||
Expr *au, *av, *bu, *bv;
|
||||
a->PointGetExprsInWorkplane(workplane, &au, &av);
|
||||
|
@ -552,10 +552,10 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
|||
}
|
||||
|
||||
case SAME_ORIENTATION: {
|
||||
Entity *a = SK.GetEntity(entityA);
|
||||
Entity *b = SK.GetEntity(entityB);
|
||||
EntityBase *a = SK.GetEntity(entityA);
|
||||
EntityBase *b = SK.GetEntity(entityB);
|
||||
if(b->group.v != group.v) {
|
||||
SWAP(Entity *, a, b);
|
||||
SWAP(EntityBase *, a, b);
|
||||
}
|
||||
|
||||
ExprVector au = a->NormalExprsU(),
|
||||
|
@ -581,8 +581,8 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
|||
|
||||
case PERPENDICULAR:
|
||||
case ANGLE: {
|
||||
Entity *a = SK.GetEntity(entityA);
|
||||
Entity *b = SK.GetEntity(entityB);
|
||||
EntityBase *a = SK.GetEntity(entityA);
|
||||
EntityBase *b = SK.GetEntity(entityB);
|
||||
ExprVector ae = a->VectorGetExprs();
|
||||
ExprVector be = b->VectorGetExprs();
|
||||
if(other) ae = ae.ScaledBy(Expr::From(-1));
|
||||
|
@ -602,10 +602,10 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
|||
}
|
||||
|
||||
case EQUAL_ANGLE: {
|
||||
Entity *a = SK.GetEntity(entityA);
|
||||
Entity *b = SK.GetEntity(entityB);
|
||||
Entity *c = SK.GetEntity(entityC);
|
||||
Entity *d = SK.GetEntity(entityD);
|
||||
EntityBase *a = SK.GetEntity(entityA);
|
||||
EntityBase *b = SK.GetEntity(entityB);
|
||||
EntityBase *c = SK.GetEntity(entityC);
|
||||
EntityBase *d = SK.GetEntity(entityD);
|
||||
ExprVector ae = a->VectorGetExprs();
|
||||
ExprVector be = b->VectorGetExprs();
|
||||
ExprVector ce = c->VectorGetExprs();
|
||||
|
@ -621,8 +621,8 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
|||
}
|
||||
|
||||
case ARC_LINE_TANGENT: {
|
||||
Entity *arc = SK.GetEntity(entityA);
|
||||
Entity *line = SK.GetEntity(entityB);
|
||||
EntityBase *arc = SK.GetEntity(entityA);
|
||||
EntityBase *line = SK.GetEntity(entityB);
|
||||
|
||||
ExprVector ac = SK.GetEntity(arc->point[0])->PointGetExprs();
|
||||
ExprVector ap =
|
||||
|
@ -636,8 +636,8 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
|||
}
|
||||
|
||||
case CUBIC_LINE_TANGENT: {
|
||||
Entity *cubic = SK.GetEntity(entityA);
|
||||
Entity *line = SK.GetEntity(entityB);
|
||||
EntityBase *cubic = SK.GetEntity(entityA);
|
||||
EntityBase *line = SK.GetEntity(entityB);
|
||||
|
||||
ExprVector endpoint =
|
||||
SK.GetEntity(cubic->point[other ? 3 : 0])->PointGetExprs();
|
||||
|
@ -648,11 +648,11 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
|||
|
||||
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(1, a, b), 1);
|
||||
} else {
|
||||
Entity *w = SK.GetEntity(workplane);
|
||||
EntityBase *w = SK.GetEntity(workplane);
|
||||
ExprVector wn = w->Normal()->NormalExprsN();
|
||||
AddEq(l, (a.Cross(b)).Dot(wn), 0);
|
||||
}
|
||||
|
@ -660,18 +660,18 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
|||
}
|
||||
|
||||
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) {
|
||||
SWAP(Entity *, ea, eb);
|
||||
SWAP(EntityBase *, ea, eb);
|
||||
}
|
||||
ExprVector a = ea->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(1, a, b), 1);
|
||||
} else {
|
||||
Entity *w = SK.GetEntity(workplane);
|
||||
EntityBase *w = SK.GetEntity(workplane);
|
||||
ExprVector wn = w->Normal()->NormalExprsN();
|
||||
AddEq(l, (a.Cross(b)).Dot(wn), 0);
|
||||
}
|
||||
|
|
|
@ -354,7 +354,7 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
|
|||
r = n.Normal(0);
|
||||
d = n.Normal(1);
|
||||
} else if(type == PT_IN_PLANE) {
|
||||
Entity *n = SK.GetEntity(entityA)->Normal();
|
||||
EntityBase *n = SK.GetEntity(entityA)->Normal();
|
||||
r = n->NormalU();
|
||||
d = n->NormalV();
|
||||
} else {
|
||||
|
@ -434,7 +434,7 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
|
|||
rn = gn;
|
||||
ru = gu;
|
||||
} else {
|
||||
Entity *normal = SK.GetEntity(workplane)->Normal();
|
||||
EntityBase *normal = SK.GetEntity(workplane)->Normal();
|
||||
rn = normal->NormalN();
|
||||
ru = normal->NormalV(); // ru meaning r_up, not u/v
|
||||
}
|
||||
|
@ -485,7 +485,7 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
|
|||
v = gu;
|
||||
n = gn;
|
||||
} else {
|
||||
Entity *wn = SK.GetEntity(workplane)->Normal();
|
||||
EntityBase *wn = SK.GetEntity(workplane)->Normal();
|
||||
u = wn->NormalU();
|
||||
v = wn->NormalV();
|
||||
n = wn->NormalN();
|
||||
|
|
|
@ -173,6 +173,30 @@ bool Entity::IsVisible(void) {
|
|||
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) {
|
||||
SBezier sb;
|
||||
|
||||
|
|
1
dsc.h
1
dsc.h
|
@ -233,6 +233,7 @@ public:
|
|||
} else if(hm.v < t->h.v) {
|
||||
first = mid + 1;
|
||||
} else {
|
||||
dbp("can't insert in list; is handle %d not unique?", t->h.v);
|
||||
oops();
|
||||
}
|
||||
}
|
||||
|
|
42
entity.cpp
42
entity.cpp
|
@ -162,7 +162,7 @@ void EntityBase::DistanceForceTo(double v) {
|
|||
} else oops();
|
||||
}
|
||||
|
||||
Entity *EntityBase::Normal(void) {
|
||||
EntityBase *EntityBase::Normal(void) {
|
||||
return SK.GetEntity(normal);
|
||||
}
|
||||
|
||||
|
@ -202,8 +202,8 @@ Quaternion EntityBase::NormalGetNum(void) {
|
|||
break;
|
||||
|
||||
case NORMAL_IN_2D: {
|
||||
Entity *wrkpl = SK.GetEntity(workplane);
|
||||
Entity *norm = SK.GetEntity(wrkpl->normal);
|
||||
EntityBase *wrkpl = SK.GetEntity(workplane);
|
||||
EntityBase *norm = SK.GetEntity(wrkpl->normal);
|
||||
q = norm->NormalGetNum();
|
||||
break;
|
||||
}
|
||||
|
@ -286,8 +286,8 @@ ExprQuaternion EntityBase::NormalGetExprs(void) {
|
|||
break;
|
||||
|
||||
case NORMAL_IN_2D: {
|
||||
Entity *wrkpl = SK.GetEntity(workplane);
|
||||
Entity *norm = SK.GetEntity(wrkpl->normal);
|
||||
EntityBase *wrkpl = SK.GetEntity(workplane);
|
||||
EntityBase *norm = SK.GetEntity(wrkpl->normal);
|
||||
q = norm->NormalGetExprs();
|
||||
break;
|
||||
}
|
||||
|
@ -315,10 +315,6 @@ ExprQuaternion EntityBase::NormalGetExprs(void) {
|
|||
return q;
|
||||
}
|
||||
|
||||
bool EntityBase::PointIsFromReferences(void) {
|
||||
return h.request().IsFromReferences();
|
||||
}
|
||||
|
||||
void EntityBase::PointForceTo(Vector p) {
|
||||
switch(type) {
|
||||
case POINT_IN_3D:
|
||||
|
@ -328,7 +324,7 @@ void EntityBase::PointForceTo(Vector p) {
|
|||
break;
|
||||
|
||||
case POINT_IN_2D: {
|
||||
Entity *c = SK.GetEntity(workplane);
|
||||
EntityBase *c = SK.GetEntity(workplane);
|
||||
p = p.Minus(c->WorkplaneGetOffset());
|
||||
SK.GetParam(param[0])->val = p.Dot(c->Normal()->NormalU());
|
||||
SK.GetParam(param[1])->val = p.Dot(c->Normal()->NormalV());
|
||||
|
@ -390,7 +386,7 @@ Vector EntityBase::PointGetNum(void) {
|
|||
break;
|
||||
|
||||
case POINT_IN_2D: {
|
||||
Entity *c = SK.GetEntity(workplane);
|
||||
EntityBase *c = SK.GetEntity(workplane);
|
||||
Vector u = c->Normal()->NormalU();
|
||||
Vector v = c->Normal()->NormalV();
|
||||
p = u.ScaledBy(SK.GetParam(param[0])->val);
|
||||
|
@ -439,7 +435,7 @@ ExprVector EntityBase::PointGetExprs(void) {
|
|||
break;
|
||||
|
||||
case POINT_IN_2D: {
|
||||
Entity *c = SK.GetEntity(workplane);
|
||||
EntityBase *c = SK.GetEntity(workplane);
|
||||
ExprVector u = c->Normal()->NormalExprsU();
|
||||
ExprVector v = c->Normal()->NormalExprsV();
|
||||
r = c->WorkplaneGetOffsetExprs();
|
||||
|
@ -488,7 +484,7 @@ void EntityBase::PointGetExprsInWorkplane(hEntity wrkpl, Expr **u, Expr **v) {
|
|||
*v = Expr::From(param[1]);
|
||||
} else {
|
||||
// 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 wu = w->Normal()->NormalExprsU();
|
||||
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++) {
|
||||
Group *g = &(SK.group.elem[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);
|
||||
}
|
||||
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) {
|
||||
ForceReferences();
|
||||
g->solved.how = Group::SOLVED_OKAY;
|
||||
g->solved.how = System::SOLVED_OKAY;
|
||||
g->clean = true;
|
||||
} else {
|
||||
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) {
|
||||
int i;
|
||||
// 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;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -361,7 +424,7 @@ bool SolveSpace::AllGroupsOkay(void) {
|
|||
int i;
|
||||
bool allOk = true;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
7
sketch.h
7
sketch.h
|
@ -104,9 +104,6 @@ public:
|
|||
double valC;
|
||||
DWORD color;
|
||||
|
||||
static const int SOLVED_OKAY = 0;
|
||||
static const int DIDNT_CONVERGE = 10;
|
||||
static const int SINGULAR_JACOBIAN = 11;
|
||||
struct {
|
||||
int how;
|
||||
int dof;
|
||||
|
@ -336,7 +333,7 @@ public:
|
|||
void WorkplaneGetPlaneExprs(ExprVector *n, Expr **d);
|
||||
ExprVector WorkplaneGetOffsetExprs(void);
|
||||
Vector WorkplaneGetOffset(void);
|
||||
Entity *Normal(void);
|
||||
EntityBase *Normal(void);
|
||||
|
||||
bool IsFace(void);
|
||||
ExprVector FaceGetNormalExprs(void);
|
||||
|
@ -350,7 +347,6 @@ public:
|
|||
ExprVector PointGetExprs(void);
|
||||
void PointGetExprsInWorkplane(hEntity wrkpl, Expr **u, Expr **v);
|
||||
void PointForceTo(Vector v);
|
||||
bool PointIsFromReferences(void);
|
||||
// These apply only the POINT_N_ROT_TRANS, which has an assoc rotation
|
||||
Quaternion PointGetQuaternion(void);
|
||||
void PointForceQuaternionTo(Quaternion q);
|
||||
|
@ -401,6 +397,7 @@ public:
|
|||
void DrawOrGetDistance(void);
|
||||
|
||||
bool IsVisible(void);
|
||||
bool PointIsFromReferences(void);
|
||||
|
||||
void GenerateBezierCurves(SBezierList *sbl);
|
||||
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 *MemAlloc(int n);
|
||||
void MemFree(void *p);
|
||||
void InitHeaps(void);
|
||||
void vl(void); // debug function to validate heaps
|
||||
|
||||
// End of platform-specific functions
|
||||
|
@ -202,12 +203,17 @@ void MakePathAbsolute(char *base, char *path);
|
|||
|
||||
class System {
|
||||
public:
|
||||
#define MAX_UNKNOWNS 1000
|
||||
static const int MAX_UNKNOWNS = 1000;
|
||||
static const int MAX_DRAGGED = 4;
|
||||
|
||||
EntityList entity;
|
||||
ParamList param;
|
||||
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
|
||||
// has been assigned to; these are exceptions for variables:
|
||||
static const int VAR_SUBSTITUTED = 10000;
|
||||
|
@ -253,14 +259,19 @@ public:
|
|||
bool WriteJacobian(int tag);
|
||||
void EvalJacobian(void);
|
||||
|
||||
void WriteEquationsExceptFor(hConstraint hc, hGroup hg);
|
||||
void FindWhichToRemoveToFixJacobian(Group *g);
|
||||
void WriteEquationsExceptFor(hConstraint hc, Group *g);
|
||||
void FindWhichToRemoveToFixJacobian(Group *g, List<hConstraint> *bad);
|
||||
void SolveBySubstitution(void);
|
||||
|
||||
static bool IsDragged(hParam p);
|
||||
bool IsDragged(hParam p);
|
||||
|
||||
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 {
|
||||
|
@ -410,20 +421,27 @@ public:
|
|||
void FinishAndCloseFile(void);
|
||||
};
|
||||
|
||||
#ifdef LIBRARY
|
||||
# define ENTITY EntityBase
|
||||
# define CONSTRAINT ConstraintBase
|
||||
#else
|
||||
# define ENTITY Entity
|
||||
# define CONSTRAINT Constraint
|
||||
#endif
|
||||
class Sketch {
|
||||
public:
|
||||
// These are user-editable, and define the sketch.
|
||||
IdList<Group,hGroup> group;
|
||||
IdList<Constraint,hConstraint> constraint;
|
||||
IdList<CONSTRAINT,hConstraint> constraint;
|
||||
IdList<Request,hRequest> request;
|
||||
|
||||
// These are generated from the above.
|
||||
IdList<Entity,hEntity> entity;
|
||||
IdList<ENTITY,hEntity> entity;
|
||||
IdList<Param,hParam> param;
|
||||
|
||||
inline Constraint *GetConstraint(hConstraint h)
|
||||
inline CONSTRAINT *GetConstraint(hConstraint 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 Request *GetRequest(hRequest h) { return request.FindById(h); }
|
||||
inline Group *GetGroup (hGroup h) { return group. FindById(h); }
|
||||
|
@ -565,6 +583,7 @@ public:
|
|||
void GenerateAll(void);
|
||||
void GenerateAll(int first, int last, bool andFindFree=false);
|
||||
void SolveGroup(hGroup hg, bool andFindFree);
|
||||
void MarkDraggedParams(void);
|
||||
void ForceReferences(void);
|
||||
|
||||
bool AllGroupsOkay(void);
|
||||
|
|
106
system.cpp
106
system.cpp
|
@ -61,51 +61,9 @@ void System::EvalJacobian(void) {
|
|||
}
|
||||
|
||||
bool System::IsDragged(hParam p) {
|
||||
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:
|
||||
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
|
||||
}
|
||||
}
|
||||
int i;
|
||||
for(i = 0; i < MAX_DRAGGED; i++) {
|
||||
if(p.v == dragged[i].v) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -346,34 +304,33 @@ bool System::NewtonSolve(int tag) {
|
|||
return converged;
|
||||
}
|
||||
|
||||
void System::WriteEquationsExceptFor(hConstraint hc, hGroup hg) {
|
||||
void System::WriteEquationsExceptFor(hConstraint hc, Group *g) {
|
||||
int i;
|
||||
// Generate all the equations from constraints in this group
|
||||
for(i = 0; i < SK.constraint.n; i++) {
|
||||
Constraint *c = &(SK.constraint.elem[i]);
|
||||
if(c->group.v != hg.v) continue;
|
||||
ConstraintBase *c = &(SK.constraint.elem[i]);
|
||||
if(c->group.v != g->h.v) continue;
|
||||
if(c->h.v == hc.v) continue;
|
||||
|
||||
c->Generate(&eq);
|
||||
}
|
||||
// And the equations from entities
|
||||
for(i = 0; i < SK.entity.n; i++) {
|
||||
Entity *e = &(SK.entity.elem[i]);
|
||||
if(e->group.v != hg.v) continue;
|
||||
EntityBase *e = &(SK.entity.elem[i]);
|
||||
if(e->group.v != g->h.v) continue;
|
||||
|
||||
e->GenerateEquations(&eq);
|
||||
}
|
||||
// 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;
|
||||
(g->solved.remove).Clear();
|
||||
|
||||
for(a = 0; a < 2; a++) {
|
||||
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->type == Constraint::POINTS_COINCIDENT && a == 0) ||
|
||||
(c->type != Constraint::POINTS_COINCIDENT && a == 1))
|
||||
|
@ -386,7 +343,7 @@ void System::FindWhichToRemoveToFixJacobian(Group *g) {
|
|||
|
||||
param.ClearTags();
|
||||
eq.Clear();
|
||||
WriteEquationsExceptFor(c->h, g->h);
|
||||
WriteEquationsExceptFor(c->h, g);
|
||||
eq.ClearTags();
|
||||
|
||||
// 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();
|
||||
if(rank == mat.m) {
|
||||
// We fixed it by removing this constraint
|
||||
(g->solved.remove).Add(&(c->h));
|
||||
bad->Add(&(c->h));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void System::Solve(Group *g, bool andFindFree) {
|
||||
g->solved.remove.Clear();
|
||||
|
||||
WriteEquationsExceptFor(Constraint::NO_CONSTRAINT, g->h);
|
||||
int System::Solve(Group *g, int *dof, List<hConstraint> *bad,
|
||||
bool andFindFree)
|
||||
{
|
||||
WriteEquationsExceptFor(Constraint::NO_CONSTRAINT, g);
|
||||
|
||||
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
|
||||
// tells us if the system is inconsistently constrained.
|
||||
if(!WriteJacobian(0)) {
|
||||
g->solved.how = Group::TOO_MANY_UNKNOWNS;
|
||||
TextWindow::ReportHowGroupSolved(g->h);
|
||||
return;
|
||||
return System::TOO_MANY_UNKNOWNS;
|
||||
}
|
||||
|
||||
EvalJacobian();
|
||||
|
||||
int rank = CalculateRank();
|
||||
if(rank != mat.m) {
|
||||
FindWhichToRemoveToFixJacobian(g);
|
||||
g->solved.how = Group::SINGULAR_JACOBIAN;
|
||||
g->solved.dof = 0;
|
||||
TextWindow::ReportHowGroupSolved(g->h);
|
||||
return;
|
||||
FindWhichToRemoveToFixJacobian(g, bad);
|
||||
return System::SINGULAR_JACOBIAN;
|
||||
}
|
||||
// This is not the full Jacobian, but any substitutions or single-eq
|
||||
// solves removed one equation and one unknown, therefore no effect
|
||||
// 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
|
||||
if(!NewtonSolve(0)) {
|
||||
|
@ -517,15 +469,9 @@ void System::Solve(Group *g, bool andFindFree) {
|
|||
pp->known = true;
|
||||
pp->free = p->free;
|
||||
}
|
||||
if(g->solved.how != Group::SOLVED_OKAY) {
|
||||
g->solved.how = Group::SOLVED_OKAY;
|
||||
TextWindow::ReportHowGroupSolved(g->h);
|
||||
}
|
||||
return;
|
||||
return System::SOLVED_OKAY;
|
||||
|
||||
didnt_converge:
|
||||
g->solved.how = Group::DIDNT_CONVERGE;
|
||||
(g->solved.remove).Clear();
|
||||
SK.constraint.ClearTags();
|
||||
for(i = 0; i < eq.n; 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;
|
||||
|
||||
hConstraint hc = mat.eq[i].constraint();
|
||||
Constraint *c = SK.constraint.FindByIdNoOops(hc);
|
||||
ConstraintBase *c = SK.constraint.FindByIdNoOops(hc);
|
||||
if(!c) continue;
|
||||
// Don't double-show constraints that generated multiple
|
||||
// unsatisfied equations
|
||||
if(!c->tag) {
|
||||
(g->solved.remove).Add(&(c->h));
|
||||
bad->Add(&(c->h));
|
||||
c->tag = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextWindow::ReportHowGroupSolved(g->h);
|
||||
|
||||
return System::DIDNT_CONVERGE;
|
||||
}
|
||||
|
||||
|
|
|
@ -112,7 +112,7 @@ void TextWindow::ShowListOfGroups(void) {
|
|||
char *s = g->DescriptionString();
|
||||
bool active = (g->h.v == SS.GW.activeGroup.v);
|
||||
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);
|
||||
Printf(false, "%Bp%Fd "
|
||||
"%Fp%D%f%s%Ll%s%E%s "
|
||||
|
@ -498,7 +498,7 @@ void TextWindow::ShowGroupInfo(void) {
|
|||
//-----------------------------------------------------------------------------
|
||||
void TextWindow::ShowGroupSolveInfo(void) {
|
||||
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
|
||||
shown.screen = SCREEN_GROUP_INFO;
|
||||
Show();
|
||||
|
@ -507,17 +507,17 @@ void TextWindow::ShowGroupSolveInfo(void) {
|
|||
|
||||
Printf(true, "%FtGROUP %E%s", g->DescriptionString());
|
||||
switch(g->solved.how) {
|
||||
case Group::DIDNT_CONVERGE:
|
||||
case System::DIDNT_CONVERGE:
|
||||
Printf(true, "%FxSOLVE FAILED!%Fd no convergence");
|
||||
Printf(true, "the following constraints are unsatisfied");
|
||||
break;
|
||||
|
||||
case Group::SINGULAR_JACOBIAN:
|
||||
case System::SINGULAR_JACOBIAN:
|
||||
Printf(true, "%FxSOLVE FAILED!%Fd inconsistent system");
|
||||
Printf(true, "remove any one of these to fix it");
|
||||
break;
|
||||
|
||||
case Group::TOO_MANY_UNKNOWNS:
|
||||
case System::TOO_MANY_UNKNOWNS:
|
||||
Printf(true, "Too many unknowns in a single group!");
|
||||
return;
|
||||
}
|
||||
|
|
4
util.cpp
4
util.cpp
|
@ -504,7 +504,7 @@ Vector Vector::WithMagnitude(double v) {
|
|||
}
|
||||
|
||||
Vector Vector::ProjectVectorInto(hEntity wrkpl) {
|
||||
Entity *w = SK.GetEntity(wrkpl);
|
||||
EntityBase *w = SK.GetEntity(wrkpl);
|
||||
Vector u = w->Normal()->NormalU();
|
||||
Vector v = w->Normal()->NormalV();
|
||||
|
||||
|
@ -515,7 +515,7 @@ Vector Vector::ProjectVectorInto(hEntity wrkpl) {
|
|||
}
|
||||
|
||||
Vector Vector::ProjectInto(hEntity wrkpl) {
|
||||
Entity *w = SK.GetEntity(wrkpl);
|
||||
EntityBase *w = SK.GetEntity(wrkpl);
|
||||
Vector p0 = w->WorkplaneGetOffset();
|
||||
|
||||
Vector f = this->Minus(p0);
|
||||
|
|
|
@ -49,18 +49,6 @@ int ClientIsSmallerBy;
|
|||
|
||||
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)
|
||||
{
|
||||
char buf[1024*50];
|
||||
|
@ -159,56 +147,6 @@ void SetWindowTitle(char *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)
|
||||
{
|
||||
int i;
|
||||
|
@ -892,13 +830,6 @@ int SaveFileYesNoCancel(void)
|
|||
return r;
|
||||
}
|
||||
|
||||
void GetAbsoluteFilename(char *file)
|
||||
{
|
||||
char absoluteFile[MAX_PATH];
|
||||
GetFullPathName(file, sizeof(absoluteFile), absoluteFile, NULL);
|
||||
strcpy(file, absoluteFile);
|
||||
}
|
||||
|
||||
void LoadAllFontFiles(void)
|
||||
{
|
||||
WIN32_FIND_DATA wfd;
|
||||
|
@ -1114,10 +1045,8 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
|||
ThawWindowPos(TextWnd);
|
||||
ThawWindowPos(GraphicsWnd);
|
||||
|
||||
// Create the heap used for long-lived stuff (that gets freed piecewise).
|
||||
Perm = HeapCreate(HEAP_NO_SERIALIZE, 1024*1024*20, 0);
|
||||
// Create the heap that we use to store Exprs and other temp stuff.
|
||||
FreeAllTemporary();
|
||||
// Create the heaps for all dynamic memory (AllocTemporary, MemAlloc)
|
||||
InitHeaps();
|
||||
|
||||
// A filename may have been specified on the command line; if so, then
|
||||
// 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