diff --git a/Makefile b/Makefile index 35a0ff1d..fb3c4098 100644 --- a/Makefile +++ b/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 \ diff --git a/constraint.cpp b/constraint.cpp index 68a64586..8fb0c5a6 100644 --- a/constraint.cpp +++ b/constraint.cpp @@ -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; diff --git a/constrainteq.cpp b/constrainteq.cpp index 43c1f25e..e9d8c4a9 100644 --- a/constrainteq.cpp +++ b/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 *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 *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 *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 *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 *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 *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 *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 *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 *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 *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 *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 *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 *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 *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 *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 *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 *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 *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 *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 *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 *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 *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 *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 *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 *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 *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); } diff --git a/drawconstraint.cpp b/drawconstraint.cpp index 16967e59..37e1d99f 100644 --- a/drawconstraint.cpp +++ b/drawconstraint.cpp @@ -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(); diff --git a/drawentity.cpp b/drawentity.cpp index 697196af..88a3ae7f 100644 --- a/drawentity.cpp +++ b/drawentity.cpp @@ -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; diff --git a/dsc.h b/dsc.h index 560ed994..425d6784 100644 --- a/dsc.h +++ b/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(); } } diff --git a/entity.cpp b/entity.cpp index 51055414..60033511 100644 --- a/entity.cpp +++ b/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 *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; - } -} - diff --git a/exposed/DOC.txt b/exposed/DOC.txt new file mode 100644 index 00000000..e24e5d8a --- /dev/null +++ b/exposed/DOC.txt @@ -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. + + diff --git a/exposed/Makefile b/exposed/Makefile new file mode 100644 index 00000000..90b0c19a --- /dev/null +++ b/exposed/Makefile @@ -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 + + diff --git a/exposed/example.c b/exposed/example.c new file mode 100644 index 00000000..87936a8c --- /dev/null +++ b/exposed/example.c @@ -0,0 +1,190 @@ +#include +#include + +#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(); +} + diff --git a/exposed/lib.cpp b/exposed/lib.cpp new file mode 100644 index 00000000..bf1cea51 --- /dev/null +++ b/exposed/lib.cpp @@ -0,0 +1,234 @@ +#include "solvespace.h" +#include "slvs.h" + +Sketch SK; +System SYS; + +int IsInit = 0; + +void Group::GenerateEquations(IdList *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 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(); +} + +} diff --git a/exposed/obj/t b/exposed/obj/t new file mode 100644 index 00000000..e69de29b diff --git a/generate.cpp b/generate.cpp index bfe08f24..dcc85a96 100644 --- a/generate.cpp +++ b/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; } } diff --git a/sketch.h b/sketch.h index 18d782cd..780db908 100644 --- a/sketch.h +++ b/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); diff --git a/solvespace.h b/solvespace.h index be9bcf32..b2768129 100644 --- a/solvespace.h +++ b/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 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 *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 *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; - IdList constraint; + IdList constraint; IdList request; // These are generated from the above. - IdList entity; + IdList entity; IdList 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); diff --git a/system.cpp b/system.cpp index e5ffd86c..d3562991 100644 --- a/system.cpp +++ b/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 *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 *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; } diff --git a/textscreens.cpp b/textscreens.cpp index 7f63f015..67148d89 100644 --- a/textscreens.cpp +++ b/textscreens.cpp @@ -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; } diff --git a/util.cpp b/util.cpp index e025b519..58c4c00e 100644 --- a/util.cpp +++ b/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); diff --git a/win32/w32main.cpp b/win32/w32main.cpp index eaeb94a5..ac99a757 100644 --- a/win32/w32main.cpp +++ b/win32/w32main.cpp @@ -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. diff --git a/win32/w32util.cpp b/win32/w32util.cpp new file mode 100644 index 00000000..ca4559cd --- /dev/null +++ b/win32/w32util.cpp @@ -0,0 +1,81 @@ +#include +#include +#include +#include + +#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(); +} +