Add undo/redo. This saves the param guesses, constraints, groups,
and requests to a separate list. It's messy, because I have to make a deep copy (e.g. of the remap list for the groups, or Expr * stuff) of some things. Others (e.g. the polygon or mesh) will be regenerated, so they should be discarded, but they must not get double-freed. In any case, works superficially. And fix a few memory leaks unrelated to this, and remove some dead code. [git-p4: depot-paths = "//depot/solvespace/": change = 1775]solver
parent
71391e6a55
commit
48612bde3d
1
Makefile
1
Makefile
|
@ -20,6 +20,7 @@ SSOBJS = $(OBJDIR)\solvespace.obj \
|
|||
$(OBJDIR)\constraint.obj \
|
||||
$(OBJDIR)\drawconstraint.obj \
|
||||
$(OBJDIR)\file.obj \
|
||||
$(OBJDIR)\undoredo.obj \
|
||||
$(OBJDIR)\system.obj \
|
||||
$(OBJDIR)\polygon.obj \
|
||||
$(OBJDIR)\mesh.obj \
|
||||
|
|
|
@ -36,6 +36,11 @@ char *Constraint::DescriptionString(void) {
|
|||
}
|
||||
|
||||
void Constraint::AddConstraint(Constraint *c) {
|
||||
AddConstraint(c, true);
|
||||
}
|
||||
void Constraint::AddConstraint(Constraint *c, bool rememberForUndo) {
|
||||
if(rememberForUndo) SS.UndoRemember();
|
||||
|
||||
SS.constraint.AddAndAssignId(c);
|
||||
|
||||
SS.MarkGroupDirty(c->group);
|
||||
|
@ -52,7 +57,7 @@ void Constraint::Constrain(int type, hEntity ptA, hEntity ptB, hEntity entityA)
|
|||
c.ptA = ptA;
|
||||
c.ptB = ptB;
|
||||
c.entityA = entityA;
|
||||
AddConstraint(&c);
|
||||
AddConstraint(&c, false);
|
||||
}
|
||||
|
||||
void Constraint::ConstrainCoincident(hEntity ptA, hEntity ptB) {
|
||||
|
@ -310,6 +315,7 @@ void Constraint::MenuConstrain(int id) {
|
|||
break;
|
||||
|
||||
case GraphicsWindow::MNU_SOLVE_NOW:
|
||||
SS.ReloadAllImported();
|
||||
SS.GenerateAll(0, INT_MAX);
|
||||
return;
|
||||
|
||||
|
|
11
file.cpp
11
file.cpp
|
@ -20,6 +20,9 @@ hGroup SolveSpace::CreateDefaultDrawingGroup(void) {
|
|||
}
|
||||
|
||||
void SolveSpace::NewFile(void) {
|
||||
UndoClearStack(&redo);
|
||||
UndoClearStack(&undo);
|
||||
|
||||
constraint.Clear();
|
||||
request.Clear();
|
||||
group.Clear();
|
||||
|
@ -131,7 +134,6 @@ const SolveSpace::SaveTable SolveSpace::SAVED[] = {
|
|||
{ 'c', "Constraint.group.v", 'x', &(SS.sv.c.group.v) },
|
||||
{ 'c', "Constraint.workplane.v", 'x', &(SS.sv.c.workplane.v) },
|
||||
{ 'c', "Constraint.exprA", 'E', &(SS.sv.c.exprA) },
|
||||
{ 'c', "Constraint.exprB", 'E', &(SS.sv.c.exprB) },
|
||||
{ 'c', "Constraint.ptA.v", 'x', &(SS.sv.c.ptA.v) },
|
||||
{ 'c', "Constraint.ptB.v", 'x', &(SS.sv.c.ptB.v) },
|
||||
{ 'c', "Constraint.ptC.v", 'x', &(SS.sv.c.ptC.v) },
|
||||
|
@ -373,7 +375,10 @@ bool SolveSpace::LoadEntitiesFromFile(char *file, EntityList *le, SMesh *m) {
|
|||
char *key = line, *val = e+1;
|
||||
LoadUsingTable(key, val);
|
||||
} else if(strcmp(line, "AddGroup")==0) {
|
||||
|
||||
// Don't leak memory; these get allocated whether we want them
|
||||
// or not.
|
||||
if(sv.g.exprA) Expr::FreeKeep(&(sv.g.exprA));
|
||||
sv.g.remap.Clear();
|
||||
} else if(strcmp(line, "AddParam")==0) {
|
||||
|
||||
} else if(strcmp(line, "AddEntity")==0) {
|
||||
|
@ -382,7 +387,7 @@ bool SolveSpace::LoadEntitiesFromFile(char *file, EntityList *le, SMesh *m) {
|
|||
} else if(strcmp(line, "AddRequest")==0) {
|
||||
|
||||
} else if(strcmp(line, "AddConstraint")==0) {
|
||||
|
||||
if(sv.c.exprA) Expr::FreeKeep(&(sv.c.exprA));
|
||||
} else if(strcmp(line, VERSION_STRING)==0) {
|
||||
|
||||
} else if(memcmp(line, "Triangle", 8)==0) {
|
||||
|
|
|
@ -21,8 +21,8 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
|
|||
{ 1, "E&xit", MNU_EXIT, 0, mFile },
|
||||
|
||||
{ 0, "&Edit", 0, NULL },
|
||||
{ 1, "&Undo\tCtrl+Z", 0, NULL },
|
||||
{ 1, "&Redo\tCtrl+Y", 0, NULL },
|
||||
{ 1, "&Undo\tCtrl+Z", MNU_UNDO, 'Z'|C, mEdit },
|
||||
{ 1, "&Redo\tCtrl+Y", MNU_REDO, 'Y'|C, mEdit },
|
||||
{ 1, NULL, 0, NULL },
|
||||
{ 1, "&Delete\tDel", MNU_DELETE, 127, mEdit },
|
||||
{ 1, NULL, 0, NULL },
|
||||
|
@ -277,11 +277,13 @@ void GraphicsWindow::EnsureValidActives(void) {
|
|||
}
|
||||
}
|
||||
|
||||
// And update the checked state for various menus
|
||||
bool locked = LockedInWorkplane();
|
||||
CheckMenuById(MNU_FREE_IN_3D, !locked);
|
||||
CheckMenuById(MNU_SEL_WORKPLANE, locked);
|
||||
|
||||
// And update the checked state for various menus
|
||||
SS.UndoEnableMenus();
|
||||
|
||||
switch(viewUnits) {
|
||||
case UNIT_MM:
|
||||
case UNIT_INCHES:
|
||||
|
@ -360,6 +362,14 @@ void GraphicsWindow::MenuEdit(int id) {
|
|||
break;
|
||||
}
|
||||
|
||||
case MNU_UNDO:
|
||||
SS.UndoUndo();
|
||||
break;
|
||||
|
||||
case MNU_REDO:
|
||||
SS.UndoRedo();
|
||||
break;
|
||||
|
||||
default: oops();
|
||||
}
|
||||
}
|
||||
|
@ -515,6 +525,11 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
|
|||
pending.constraint = hover.constraint;
|
||||
pending.operation = DRAGGING_CONSTRAINT;
|
||||
}
|
||||
if(pending.operation != 0) {
|
||||
// We just started a drag, so remember for the undo before
|
||||
// the drag changes anything.
|
||||
SS.UndoRemember();
|
||||
}
|
||||
} else {
|
||||
// Otherwise, just hit test and give up; but don't hit test
|
||||
// if the mouse is down, because then the user could hover
|
||||
|
@ -859,6 +874,11 @@ void GraphicsWindow::MouseMiddleDown(double x, double y) {
|
|||
}
|
||||
|
||||
hRequest GraphicsWindow::AddRequest(int type) {
|
||||
return AddRequest(type, true);
|
||||
}
|
||||
hRequest GraphicsWindow::AddRequest(int type, bool rememberForUndo) {
|
||||
if(rememberForUndo) SS.UndoRemember();
|
||||
|
||||
Request r;
|
||||
memset(&r, 0, sizeof(r));
|
||||
r.group = activeGroup;
|
||||
|
@ -921,6 +941,7 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
|
|||
case MNU_DATUM_POINT:
|
||||
hr = AddRequest(Request::DATUM_POINT);
|
||||
SS.GetEntity(hr.entity(0))->PointForceTo(v);
|
||||
ConstrainPointByHovered(hr.entity(0));
|
||||
|
||||
ClearSuper();
|
||||
|
||||
|
@ -947,8 +968,9 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
|
|||
}
|
||||
hRequest lns[4];
|
||||
int i;
|
||||
SS.UndoRemember();
|
||||
for(i = 0; i < 4; i++) {
|
||||
lns[i] = AddRequest(Request::LINE_SEGMENT);
|
||||
lns[i] = AddRequest(Request::LINE_SEGMENT, false);
|
||||
}
|
||||
for(i = 0; i < 4; i++) {
|
||||
Constraint::ConstrainCoincident(
|
||||
|
@ -1136,6 +1158,8 @@ void GraphicsWindow::MouseLeftDoubleClick(double mx, double my) {
|
|||
void GraphicsWindow::EditControlDone(char *s) {
|
||||
Expr *e = Expr::From(s);
|
||||
if(e) {
|
||||
SS.UndoRemember();
|
||||
|
||||
Constraint *c = SS.GetConstraint(constraintBeingEdited);
|
||||
Expr::FreeKeep(&(c->exprA));
|
||||
c->exprA = e->DeepCopyKeep();
|
||||
|
@ -1193,6 +1217,8 @@ Vector GraphicsWindow::VectorFromProjs(double right, double up, double fwd) {
|
|||
}
|
||||
|
||||
void GraphicsWindow::Paint(int w, int h) {
|
||||
SDWORD in = GetMilliseconds();
|
||||
|
||||
havePainted = true;
|
||||
width = w; height = h;
|
||||
|
||||
|
@ -1250,6 +1276,7 @@ void GraphicsWindow::Paint(int w, int h) {
|
|||
// Draw the groups; this fills the polygons in a drawing group, and
|
||||
// draws the solid mesh.
|
||||
(SS.GetGroup(activeGroup))->Draw();
|
||||
dbp("done group: %d ms", GetMilliseconds() - in);
|
||||
|
||||
// First, draw the entire scene. We don't necessarily want to draw
|
||||
// things with normal z-buffering behaviour; e.g. we always want to
|
||||
|
@ -1263,6 +1290,7 @@ void GraphicsWindow::Paint(int w, int h) {
|
|||
SS.entity.elem[i].Draw(a);
|
||||
}
|
||||
}
|
||||
dbp("done entity: %d ms", GetMilliseconds() - in);
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
// Draw the constraints
|
||||
|
@ -1280,5 +1308,9 @@ void GraphicsWindow::Paint(int w, int h) {
|
|||
for(i = 0; i < MAX_SELECTED; i++) {
|
||||
selection[i].Draw();
|
||||
}
|
||||
|
||||
dbp("till end: %d ms", GetMilliseconds() - in);
|
||||
dbp("entity.n: %d", SS.entity.n);
|
||||
dbp("param.n: %d", SS.param.n);
|
||||
}
|
||||
|
||||
|
|
|
@ -131,7 +131,7 @@ void Group::MenuGroup(int id) {
|
|||
|
||||
default: oops();
|
||||
}
|
||||
|
||||
SS.UndoRemember();
|
||||
SS.group.AddAndAssignId(&g);
|
||||
if(g.type == IMPORTED) {
|
||||
SS.ReloadAllImported();
|
||||
|
@ -624,6 +624,7 @@ void Group::GeneratePolygon(void) {
|
|||
polyError.notClosedAt = error;
|
||||
poly.Clear();
|
||||
}
|
||||
edges.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
3
sketch.h
3
sketch.h
|
@ -375,7 +375,6 @@ public:
|
|||
|
||||
double val;
|
||||
bool known;
|
||||
bool assumed;
|
||||
|
||||
// Used only in the solver
|
||||
hParam substd;
|
||||
|
@ -428,7 +427,6 @@ public:
|
|||
|
||||
// These are the parameters for the constraint.
|
||||
Expr *exprA;
|
||||
Expr *exprB;
|
||||
hEntity ptA;
|
||||
hEntity ptB;
|
||||
hEntity ptC;
|
||||
|
@ -443,6 +441,7 @@ public:
|
|||
|
||||
char *DescriptionString(void);
|
||||
|
||||
static void AddConstraint(Constraint *c, bool rememberForUndo);
|
||||
static void AddConstraint(Constraint *c);
|
||||
static void MenuConstrain(int id);
|
||||
|
||||
|
|
34
solvespace.h
34
solvespace.h
|
@ -141,8 +141,7 @@ public:
|
|||
|
||||
// In general, the tag indicates the subsys that a variable/equation
|
||||
// has been assigned to; these are exceptions for variables:
|
||||
static const int VAR_ASSUMED = 10000;
|
||||
static const int VAR_SUBSTITUTED = 10001;
|
||||
static const int VAR_SUBSTITUTED = 10000;
|
||||
// and for equations:
|
||||
static const int EQ_SUBSTITUTED = 20000;
|
||||
|
||||
|
@ -218,13 +217,38 @@ public:
|
|||
inline Param *GetParam (hParam h) { return param. FindById(h); }
|
||||
inline Group *GetGroup (hGroup h) { return group. FindById(h); }
|
||||
|
||||
FILE *fh;
|
||||
// The state for undo/redo
|
||||
typedef struct {
|
||||
IdList<Group,hGroup> group;
|
||||
IdList<Request,hRequest> request;
|
||||
IdList<Constraint,hConstraint> constraint;
|
||||
IdList<Param,hParam> param;
|
||||
hGroup activeGroup;
|
||||
} UndoState;
|
||||
static const int MAX_UNDO = 16;
|
||||
typedef struct {
|
||||
UndoState d[MAX_UNDO];
|
||||
int cnt;
|
||||
int write;
|
||||
} UndoStack;
|
||||
UndoStack undo;
|
||||
UndoStack redo;
|
||||
void UndoEnableMenus(void);
|
||||
void UndoRemember(void);
|
||||
void UndoUndo(void);
|
||||
void UndoRedo(void);
|
||||
void PushFromCurrentOnto(UndoStack *uk);
|
||||
void PopOntoCurrentFrom(UndoStack *uk);
|
||||
void UndoClearState(UndoState *ut);
|
||||
void UndoClearStack(UndoStack *uk);
|
||||
|
||||
// File load/save routines, including the additional files that get
|
||||
// loaded when we have import groups.
|
||||
FILE *fh;
|
||||
void Init(char *cmdLine);
|
||||
void AfterNewFile(void);
|
||||
static void RemoveFromRecentList(char *file);
|
||||
static void AddToRecentList(char *file);
|
||||
|
||||
char saveFile[MAX_PATH];
|
||||
bool unsaved;
|
||||
typedef struct {
|
||||
|
@ -256,6 +280,8 @@ public:
|
|||
void MarkGroupDirty(hGroup hg);
|
||||
void MarkGroupDirtyByEntity(hEntity he);
|
||||
|
||||
// Consistency checking on the sketch: stuff with missing dependencies
|
||||
// will get deleted automatically.
|
||||
struct {
|
||||
int requests;
|
||||
int groups;
|
||||
|
|
|
@ -470,8 +470,6 @@ void System::Solve(Group *g) {
|
|||
Param *pp = SS.GetParam(p->h);
|
||||
pp->val = val;
|
||||
pp->known = true;
|
||||
// The main param table keeps track of what was assumed.
|
||||
pp->assumed = (p->tag == VAR_ASSUMED);
|
||||
}
|
||||
if(g->solved.how != Group::SOLVED_OKAY) {
|
||||
g->solved.how = Group::SOLVED_OKAY;
|
||||
|
|
12
textwin.cpp
12
textwin.cpp
|
@ -540,6 +540,8 @@ void TextWindow::ScreenSelectRequest(int link, DWORD v) {
|
|||
SS.GW.selection[0].entity = hr.entity(0);
|
||||
}
|
||||
void TextWindow::ScreenChangeOneOrTwoSides(int link, DWORD v) {
|
||||
SS.UndoRemember();
|
||||
|
||||
Group *g = SS.GetGroup(SS.TW.shown->group);
|
||||
if(g->subtype == Group::ONE_SIDED) {
|
||||
g->subtype = Group::TWO_SIDED;
|
||||
|
@ -551,6 +553,8 @@ void TextWindow::ScreenChangeOneOrTwoSides(int link, DWORD v) {
|
|||
SS.GW.ClearSuper();
|
||||
}
|
||||
void TextWindow::ScreenChangeMeshCombine(int link, DWORD v) {
|
||||
SS.UndoRemember();
|
||||
|
||||
Group *g = SS.GetGroup(SS.TW.shown->group);
|
||||
g->meshCombine = v;
|
||||
SS.MarkGroupDirty(g->h);
|
||||
|
@ -558,6 +562,8 @@ void TextWindow::ScreenChangeMeshCombine(int link, DWORD v) {
|
|||
SS.GW.ClearSuper();
|
||||
}
|
||||
void TextWindow::ScreenColor(int link, DWORD v) {
|
||||
SS.UndoRemember();
|
||||
|
||||
Group *g = SS.GetGroup(SS.TW.shown->group);
|
||||
if(v < 0 || v >= MODEL_COLORS) return;
|
||||
g->color = SS.TW.modelColor[v];
|
||||
|
@ -578,6 +584,8 @@ void TextWindow::ScreenChangeGroupName(int link, DWORD v) {
|
|||
SS.TW.edit.group.v = v;
|
||||
}
|
||||
void TextWindow::ScreenDeleteGroup(int link, DWORD v) {
|
||||
SS.UndoRemember();
|
||||
|
||||
hGroup hg = SS.TW.shown->group;
|
||||
if(hg.v == SS.GW.activeGroup.v) {
|
||||
Error("This group is currently active; activate a different group "
|
||||
|
@ -763,6 +771,8 @@ void TextWindow::EditControlDone(char *s) {
|
|||
case EDIT_TIMES_REPEATED: {
|
||||
Expr *e = Expr::From(s);
|
||||
if(e) {
|
||||
SS.UndoRemember();
|
||||
|
||||
Group *g = SS.GetGroup(edit.group);
|
||||
Expr::FreeKeep(&(g->exprA));
|
||||
g->exprA = e->DeepCopyKeep();
|
||||
|
@ -786,6 +796,8 @@ void TextWindow::EditControlDone(char *s) {
|
|||
if(invalid || !*s) {
|
||||
Error("Invalid characters. Allowed are: A-Z a-z 0-9 _ -");
|
||||
} else {
|
||||
SS.UndoRemember();
|
||||
|
||||
Group *g = SS.GetGroup(edit.group);
|
||||
g->name.strcpy(s);
|
||||
}
|
||||
|
|
3
ui.h
3
ui.h
|
@ -132,6 +132,8 @@ public:
|
|||
MNU_UNITS_INCHES,
|
||||
MNU_UNITS_MM,
|
||||
// Edit
|
||||
MNU_UNDO,
|
||||
MNU_REDO,
|
||||
MNU_DELETE,
|
||||
MNU_UNSELECT_ALL,
|
||||
// Request
|
||||
|
@ -248,6 +250,7 @@ public:
|
|||
hConstraint constraintBeingEdited;
|
||||
|
||||
bool ConstrainPointByHovered(hEntity pt);
|
||||
hRequest AddRequest(int type, bool rememberForUndo);
|
||||
hRequest AddRequest(int type);
|
||||
|
||||
// The current selection.
|
||||
|
|
|
@ -0,0 +1,154 @@
|
|||
#include "solvespace.h"
|
||||
|
||||
void SolveSpace::UndoRemember(void) {
|
||||
PushFromCurrentOnto(&undo);
|
||||
UndoClearStack(&redo);
|
||||
UndoEnableMenus();
|
||||
}
|
||||
|
||||
void SolveSpace::UndoUndo(void) {
|
||||
if(undo.cnt <= 0) return;
|
||||
|
||||
PushFromCurrentOnto(&redo);
|
||||
PopOntoCurrentFrom(&undo);
|
||||
UndoEnableMenus();
|
||||
}
|
||||
|
||||
void SolveSpace::UndoRedo(void) {
|
||||
if(redo.cnt <= 0) return;
|
||||
|
||||
PushFromCurrentOnto(&undo);
|
||||
PopOntoCurrentFrom(&redo);
|
||||
UndoEnableMenus();
|
||||
}
|
||||
|
||||
void SolveSpace::UndoEnableMenus(void) {
|
||||
EnableMenuById(GraphicsWindow::MNU_UNDO, undo.cnt > 0);
|
||||
EnableMenuById(GraphicsWindow::MNU_REDO, redo.cnt > 0);
|
||||
}
|
||||
|
||||
void SolveSpace::PushFromCurrentOnto(UndoStack *uk) {
|
||||
int i;
|
||||
|
||||
if(uk->cnt == MAX_UNDO) {
|
||||
UndoClearState(&(uk->d[uk->write]));
|
||||
// And then write in to this one again
|
||||
} else {
|
||||
(uk->cnt)++;
|
||||
}
|
||||
|
||||
UndoState *ut = &(uk->d[uk->write]);
|
||||
ZERO(ut);
|
||||
for(i = 0; i < group.n; i++) {
|
||||
Group *src = &(group.elem[i]);
|
||||
Group dest = *src;
|
||||
// And then clean up all the stuff that needs to be a deep copy,
|
||||
// and zero out all the dynamic stuff that will get regenerated.
|
||||
dest.clean = false;
|
||||
if(src->exprA) dest.exprA = src->exprA->DeepCopyKeep();
|
||||
ZERO(&(dest.solved));
|
||||
ZERO(&(dest.poly));
|
||||
ZERO(&(dest.polyError));
|
||||
ZERO(&(dest.mesh));
|
||||
ZERO(&(dest.meshError));
|
||||
|
||||
ZERO(&(dest.remap));
|
||||
src->remap.DeepCopyInto(&(dest.remap));
|
||||
|
||||
ZERO(&(dest.impMesh));
|
||||
ZERO(&(dest.impEntity));
|
||||
ut->group.Add(&dest);
|
||||
}
|
||||
for(i = 0; i < request.n; i++) {
|
||||
ut->request.Add(&(request.elem[i]));
|
||||
}
|
||||
for(i = 0; i < constraint.n; i++) {
|
||||
Constraint *src = &(constraint.elem[i]);
|
||||
Constraint dest = *src;
|
||||
if(src->exprA) dest.exprA = src->exprA->DeepCopyKeep();
|
||||
ZERO(&(dest.dogd));
|
||||
ut->constraint.Add(&dest);
|
||||
}
|
||||
for(i = 0; i < param.n; i++) {
|
||||
ut->param.Add(&(param.elem[i]));
|
||||
}
|
||||
ut->activeGroup = SS.GW.activeGroup;
|
||||
|
||||
uk->write = WRAP(uk->write + 1, MAX_UNDO);
|
||||
}
|
||||
|
||||
void SolveSpace::PopOntoCurrentFrom(UndoStack *uk) {
|
||||
if(uk->cnt <= 0) oops();
|
||||
(uk->cnt)--;
|
||||
uk->write = WRAP(uk->write - 1, MAX_UNDO);
|
||||
|
||||
UndoState *ut = &(uk->d[uk->write]);
|
||||
|
||||
int i;
|
||||
// Free everything in the main copy of the program before replacing it
|
||||
for(i = 0; i < group.n; i++) {
|
||||
Group *g = &(group.elem[i]);
|
||||
if(g->exprA) Expr::FreeKeep(&(g->exprA));
|
||||
g->poly.Clear();
|
||||
g->mesh.Clear();
|
||||
g->meshError.interferesAt.Clear();
|
||||
g->remap.Clear();
|
||||
g->impMesh.Clear();
|
||||
g->impEntity.Clear();
|
||||
}
|
||||
for(i = 0; i < constraint.n; i++) {
|
||||
Constraint *c = &(constraint.elem[i]);
|
||||
if(c->exprA) Expr::FreeKeep(&(c->exprA));
|
||||
}
|
||||
group.Clear();
|
||||
request.Clear();
|
||||
constraint.Clear();
|
||||
param.Clear();
|
||||
|
||||
// And then do a shallow copy of the state from the undo list
|
||||
ut->group.MoveSelfInto(&group);
|
||||
ut->request.MoveSelfInto(&request);
|
||||
ut->constraint.MoveSelfInto(&constraint);
|
||||
ut->param.MoveSelfInto(¶m);
|
||||
SS.GW.activeGroup = ut->activeGroup;
|
||||
|
||||
// No need to free it, since a shallow copy was made above
|
||||
ZERO(ut);
|
||||
|
||||
// And reset the state everywhere else in the program, since the
|
||||
// sketch just changed a lot.
|
||||
SS.GW.ClearSuper();
|
||||
SS.TW.ClearSuper();
|
||||
SS.ReloadAllImported();
|
||||
SS.GenerateAll(0, INT_MAX);
|
||||
later.showTW = true;
|
||||
}
|
||||
|
||||
void SolveSpace::UndoClearStack(UndoStack *uk) {
|
||||
while(uk->cnt > 0) {
|
||||
uk->write = WRAP(uk->write - 1, MAX_UNDO);
|
||||
(uk->cnt)--;
|
||||
UndoClearState(&(uk->d[uk->write]));
|
||||
}
|
||||
ZERO(uk); // for good measure
|
||||
}
|
||||
|
||||
void SolveSpace::UndoClearState(UndoState *ut) {
|
||||
int i;
|
||||
for(i = 0; i < ut->group.n; i++) {
|
||||
Group *g = &(ut->group.elem[i]);
|
||||
|
||||
if(g->exprA) Expr::FreeKeep(&(g->exprA));
|
||||
g->remap.Clear();
|
||||
}
|
||||
ut->group.Clear();
|
||||
ut->request.Clear();
|
||||
for(i = 0; i < ut->constraint.n; i++) {
|
||||
Constraint *c = &(ut->constraint.elem[i]);
|
||||
if(c->exprA) Expr::FreeKeep(&(c->exprA));
|
||||
}
|
||||
ut->constraint.Clear();
|
||||
ut->param.Clear();
|
||||
ZERO(ut);
|
||||
}
|
||||
|
|
@ -1,4 +1,8 @@
|
|||
|
||||
stupidity where stuff gets double-added to entity list
|
||||
replace linear search through IdLists with faster (binary search?)
|
||||
point face distance constraint
|
||||
|
||||
STL check for meshes, and T intersection removal
|
||||
STL export
|
||||
better triangle combining (Simplify()) for meshes
|
||||
|
@ -8,10 +12,8 @@ DXF export
|
|||
compress file format (binary?)
|
||||
partitioned subsystems in the solver
|
||||
arbitrary color specification
|
||||
union/difference/interference check option for imports
|
||||
undo/redo
|
||||
TTF font text
|
||||
display with proper formatting/units
|
||||
more measurements
|
||||
|
||||
reference dimensions (just to look at, no equations)
|
||||
|
||||
|
|
Loading…
Reference in New Issue