Improve convergence of constraints involving parallel vectors, by

using the initial numerical guess of whichever vector is already
known to choose our projection planes.

And add a mechanism to defer showing the text window or
regenerating, in order to simplify dependencies on valid actives.
Also yes/no/cancel when about to abandon an unsaved file, and a
bugfix when rotating a rot/trans point.

[git-p4: depot-paths = "//depot/solvespace/": change = 1772]
solver
Jonathan Westhues 2008-06-03 10:28:41 -08:00
parent 7d4a4fbb76
commit ea6db67c7d
10 changed files with 190 additions and 70 deletions

View File

@ -39,7 +39,7 @@ void Constraint::AddConstraint(Constraint *c) {
SS.constraint.AddAndAssignId(c); SS.constraint.AddAndAssignId(c);
SS.MarkGroupDirty(c->group); SS.MarkGroupDirty(c->group);
SS.GenerateAll(); SS.later.generateAll = true;
} }
void Constraint::Constrain(int type, hEntity ptA, hEntity ptB, hEntity entityA) void Constraint::Constrain(int type, hEntity ptA, hEntity ptB, hEntity entityA)
@ -323,10 +323,13 @@ void Constraint::MenuConstrain(int id) {
Expr *Constraint::VectorsParallel(int eq, ExprVector a, ExprVector b) { Expr *Constraint::VectorsParallel(int eq, ExprVector a, ExprVector b) {
ExprVector r = a.Cross(b); ExprVector r = a.Cross(b);
// Hairy ball theorem screws me here. There's no clean solution that I // Hairy ball theorem screws me here. There's no clean solution that I
// know, so let's pivot on the initial numerical guess. // know, so let's pivot on the initial numerical guess. Our caller
double mx = fabs((a.x)->Eval()) + fabs((b.x)->Eval()); // has ensured that if one of our input vectors is already known (e.g.
double my = fabs((a.y)->Eval()) + fabs((b.y)->Eval()); // it's from a previous group), then that one's in a; so that one's
double mz = fabs((a.z)->Eval()) + fabs((b.z)->Eval()); // not going to move, and we should pivot on that one.
double mx = fabs((a.x)->Eval());
double my = fabs((a.y)->Eval());
double mz = fabs((a.z)->Eval());
// The basis vector in which the vectors have the LEAST energy is the // The basis vector in which the vectors have the LEAST energy is the
// one that we should look at most (e.g. if both vectors lie in the xy // one that we should look at most (e.g. if both vectors lie in the xy
// plane, then the z component of the cross product is most important). // plane, then the z component of the cross product is most important).
@ -566,8 +569,13 @@ void Constraint::Generate(IdList<Equation,hEquation> *l) {
ExprVector eab = ea.Minus(eb); ExprVector eab = ea.Minus(eb);
ExprVector eap = ea.Minus(ep); ExprVector eap = ea.Minus(ep);
AddEq(l, VectorsParallel(0, eab, eap), 0); if(p->group.v == group.v) {
AddEq(l, VectorsParallel(1, eab, eap), 1); AddEq(l, VectorsParallel(0, eab, eap), 0);
AddEq(l, VectorsParallel(1, eab, eap), 1);
} else {
AddEq(l, VectorsParallel(0, eap, eab), 0);
AddEq(l, VectorsParallel(1, eap, eab), 1);
}
} else { } else {
AddEq(l, PointLineDistance(workplane, ptA, entityA), 0); AddEq(l, PointLineDistance(workplane, ptA, entityA), 0);
} }
@ -715,6 +723,10 @@ void Constraint::Generate(IdList<Equation,hEquation> *l) {
case SAME_ORIENTATION: { case SAME_ORIENTATION: {
Entity *a = SS.GetEntity(entityA); Entity *a = SS.GetEntity(entityA);
Entity *b = SS.GetEntity(entityB); Entity *b = SS.GetEntity(entityB);
if(b->group.v != group.v) {
SWAP(Entity *, a, b);
}
ExprVector au = a->NormalExprsU(), ExprVector au = a->NormalExprsU(),
av = a->NormalExprsV(), av = a->NormalExprsV(),
an = a->NormalExprsN(); an = a->NormalExprsN();
@ -765,8 +777,12 @@ void Constraint::Generate(IdList<Equation,hEquation> *l) {
} }
case PARALLEL: { case PARALLEL: {
ExprVector a = SS.GetEntity(entityA)->VectorGetExprs(); Entity *ea = SS.GetEntity(entityA), *eb = SS.GetEntity(entityB);
ExprVector b = SS.GetEntity(entityB)->VectorGetExprs(); if(eb->group.v != group.v) {
SWAP(Entity *, ea, eb);
}
ExprVector a = ea->VectorGetExprs();
ExprVector b = eb->VectorGetExprs();
if(workplane.v == Entity::FREE_IN_3D.v) { if(workplane.v == Entity::FREE_IN_3D.v) {
AddEq(l, VectorsParallel(0, a, b), 0); AddEq(l, VectorsParallel(0, a, b), 0);

View File

@ -295,7 +295,7 @@ void GraphicsWindow::EnsureValidActives(void) {
ShowTextWindow(SS.GW.showTextWindow); ShowTextWindow(SS.GW.showTextWindow);
CheckMenuById(MNU_SHOW_TEXT_WND, SS.GW.showTextWindow); CheckMenuById(MNU_SHOW_TEXT_WND, SS.GW.showTextWindow);
if(change) SS.TW.Show(); if(change) SS.later.showTW = true;
} }
void GraphicsWindow::SetWorkplaneFreeIn3d(void) { void GraphicsWindow::SetWorkplaneFreeIn3d(void) {
@ -356,7 +356,7 @@ void GraphicsWindow::MenuEdit(int id) {
// that references it (since the regen code checks for that). // that references it (since the regen code checks for that).
SS.GenerateAll(0, INT_MAX); SS.GenerateAll(0, INT_MAX);
SS.GW.EnsureValidActives(); SS.GW.EnsureValidActives();
SS.TW.Show(); SS.later.showTW = true;
break; break;
} }
@ -382,13 +382,13 @@ void GraphicsWindow::MenuRequest(int id) {
// Align the view with the selected workplane // Align the view with the selected workplane
SS.GW.AnimateOntoWorkplane(); SS.GW.AnimateOntoWorkplane();
SS.GW.ClearSuper(); SS.GW.ClearSuper();
SS.TW.Show(); SS.later.showTW = true;
break; break;
} }
case MNU_FREE_IN_3D: case MNU_FREE_IN_3D:
SS.GW.SetWorkplaneFreeIn3d(); SS.GW.SetWorkplaneFreeIn3d();
SS.GW.EnsureValidActives(); SS.GW.EnsureValidActives();
SS.TW.Show(); SS.later.showTW = true;
break; break;
case MNU_DATUM_POINT: s = "click to place datum point"; goto c; case MNU_DATUM_POINT: s = "click to place datum point"; goto c;
@ -401,7 +401,7 @@ void GraphicsWindow::MenuRequest(int id) {
c: c:
SS.GW.pending.operation = id; SS.GW.pending.operation = id;
SS.GW.pending.description = s; SS.GW.pending.description = s;
SS.TW.Show(); SS.later.showTW = true;
break; break;
case MNU_CONSTRUCTION: { case MNU_CONSTRUCTION: {
@ -578,10 +578,10 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
double dx = -(x - orig.mouse.x); double dx = -(x - orig.mouse.x);
double dy = -(y - orig.mouse.y); double dy = -(y - orig.mouse.y);
double s = 0.3*(PI/180); // degrees per pixel double s = 0.3*(PI/180); // degrees per pixel
u = u.RotatedAbout(orig.projUp, -s*dx); u = u.RotatedAbout(projUp, -s*dx);
u = u.RotatedAbout(orig.projRight, s*dy); u = u.RotatedAbout(projRight, s*dy);
v = v.RotatedAbout(orig.projUp, -s*dx); v = v.RotatedAbout(projUp, -s*dx);
v = v.RotatedAbout(orig.projRight, s*dy); v = v.RotatedAbout(projRight, s*dy);
} }
q = Quaternion::From(u, v); q = Quaternion::From(u, v);
p->PointForceQuaternionTo(q); p->PointForceQuaternionTo(q);
@ -779,7 +779,7 @@ void GraphicsWindow::ClearSelection(void) {
for(int i = 0; i < MAX_SELECTED; i++) { for(int i = 0; i < MAX_SELECTED; i++) {
selection[i].Clear(); selection[i].Clear();
} }
SS.TW.Show(); SS.later.showTW = true;
InvalidateGraphics(); InvalidateGraphics();
} }
@ -1101,7 +1101,7 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
} }
} }
SS.TW.Show(); SS.later.showTW = true;
InvalidateGraphics(); InvalidateGraphics();
} }
@ -1180,7 +1180,7 @@ void GraphicsWindow::ToggleBool(int link, DWORD v) {
SS.GenerateAll(); SS.GenerateAll();
InvalidateGraphics(); InvalidateGraphics();
SS.TW.Show(); SS.later.showTW = true;
} }
Vector GraphicsWindow::VectorFromProjs(double right, double up, double fwd) { Vector GraphicsWindow::VectorFromProjs(double right, double up, double fwd) {

View File

@ -144,7 +144,7 @@ void Group::MenuGroup(int id) {
SS.GetGroup(g.h)->Activate(); SS.GetGroup(g.h)->Activate();
SS.GW.AnimateOntoWorkplane(); SS.GW.AnimateOntoWorkplane();
TextWindow::ScreenSelectGroup(0, g.h.v); TextWindow::ScreenSelectGroup(0, g.h.v);
SS.TW.Show(); SS.later.showTW = true;
} }
char *Group::DescriptionString(void) { char *Group::DescriptionString(void) {
@ -164,8 +164,8 @@ void Group::Activate(void) {
SS.GW.showFaces = false; SS.GW.showFaces = false;
} }
SS.MarkGroupDirty(h); // for good measure; shouldn't be needed SS.MarkGroupDirty(h); // for good measure; shouldn't be needed
SS.GenerateAll(); SS.later.generateAll = true;
SS.TW.Show(); SS.later.showTW = true;
} }
void Group::Generate(IdList<Entity,hEntity> *entity, void Group::Generate(IdList<Entity,hEntity> *entity,
@ -740,8 +740,10 @@ void Group::GenerateMesh(void) {
SMesh *a = PreviousGroupMesh(); SMesh *a = PreviousGroupMesh();
if(meshCombine == COMBINE_AS_UNION) { if(meshCombine == COMBINE_AS_UNION) {
mesh.MakeFromUnion(a, &outm); mesh.MakeFromUnion(a, &outm);
} else { } else if(meshCombine == COMBINE_AS_DIFFERENCE) {
mesh.MakeFromDifference(a, &outm); mesh.MakeFromDifference(a, &outm);
} else {
} }
outm.Clear(); outm.Clear();
} }

View File

@ -127,6 +127,7 @@ public:
static const int COMBINE_AS_UNION = 0; static const int COMBINE_AS_UNION = 0;
static const int COMBINE_AS_DIFFERENCE = 1; static const int COMBINE_AS_DIFFERENCE = 1;
static const int COMBINE_AS_ASSEMBLE = 2;
int meshCombine; int meshCombine;
IdList<EntityMap,EntityId> remap; IdList<EntityMap,EntityId> remap;

View File

@ -17,6 +17,12 @@ void SolveSpace::Init(char *cmdLine) {
AfterNewFile(); AfterNewFile();
} }
void SolveSpace::DoLater(void) {
if(later.generateAll) GenerateAll();
if(later.showTW) TW.Show();
ZERO(&later);
}
void SolveSpace::AfterNewFile(void) { void SolveSpace::AfterNewFile(void) {
ReloadAllImported(); ReloadAllImported();
GenerateAll(-1, -1); GenerateAll(-1, -1);
@ -24,8 +30,9 @@ void SolveSpace::AfterNewFile(void) {
TW.Init(); TW.Init();
GW.Init(); GW.Init();
unsaved = false;
GenerateAll(0, INT_MAX); GenerateAll(0, INT_MAX);
TW.Show(); later.showTW = true;
} }
void SolveSpace::MarkGroupDirtyByEntity(hEntity he) { void SolveSpace::MarkGroupDirtyByEntity(hEntity he) {
@ -256,7 +263,7 @@ void SolveSpace::GenerateAll(int first, int last) {
if(deleted.groups > 0) { if(deleted.groups > 0) {
SS.TW.ClearSuper(); SS.TW.ClearSuper();
} }
TW.Show(); later.showTW = true;
GW.ClearSuper(); GW.ClearSuper();
// Don't display any errors until we've regenerated fully. The // Don't display any errors until we've regenerated fully. The
// sketch is not necessarily in a consistent state until we've // sketch is not necessarily in a consistent state until we've
@ -365,6 +372,40 @@ void SolveSpace::AddToRecentList(char *file) {
RefreshRecentMenus(); RefreshRecentMenus();
} }
bool SolveSpace::GetFilenameAndSave(bool saveAs) {
char newFile[MAX_PATH];
strcpy(newFile, saveFile);
if(saveAs || strlen(newFile)==0) {
if(!GetSaveFile(newFile, SLVS_EXT, SLVS_PATTERN)) return false;
}
if(SaveToFile(newFile)) {
AddToRecentList(newFile);
strcpy(saveFile, newFile);
unsaved = false;
return true;
} else {
return false;
}
}
bool SolveSpace::OkayToStartNewFile(void) {
if(!unsaved) return true;
switch(SaveFileYesNoCancel()) {
case IDYES:
return GetFilenameAndSave(false);
case IDNO:
return true;
case IDCANCEL:
return false;
default: oops();
}
}
void SolveSpace::MenuFile(int id) { void SolveSpace::MenuFile(int id) {
if(id >= RECENT_OPEN && id < (RECENT_OPEN+MAX_RECENT)) { if(id >= RECENT_OPEN && id < (RECENT_OPEN+MAX_RECENT)) {
@ -384,12 +425,16 @@ void SolveSpace::MenuFile(int id) {
switch(id) { switch(id) {
case GraphicsWindow::MNU_NEW: case GraphicsWindow::MNU_NEW:
if(!SS.OkayToStartNewFile()) break;
strcpy(SS.saveFile, ""); strcpy(SS.saveFile, "");
SS.NewFile(); SS.NewFile();
SS.AfterNewFile(); SS.AfterNewFile();
break; break;
case GraphicsWindow::MNU_OPEN: { case GraphicsWindow::MNU_OPEN: {
if(!SS.OkayToStartNewFile()) break;
char newFile[MAX_PATH] = ""; char newFile[MAX_PATH] = "";
if(GetOpenFile(newFile, SLVS_EXT, SLVS_PATTERN)) { if(GetOpenFile(newFile, SLVS_EXT, SLVS_PATTERN)) {
if(SS.LoadFromFile(newFile)) { if(SS.LoadFromFile(newFile)) {
@ -405,21 +450,16 @@ void SolveSpace::MenuFile(int id) {
} }
case GraphicsWindow::MNU_SAVE: case GraphicsWindow::MNU_SAVE:
case GraphicsWindow::MNU_SAVE_AS: { SS.GetFilenameAndSave(false);
char newFile[MAX_PATH]; break;
strcpy(newFile, SS.saveFile);
if(id == GraphicsWindow::MNU_SAVE_AS || strlen(newFile)==0) { case GraphicsWindow::MNU_SAVE_AS:
if(!GetSaveFile(newFile, SLVS_EXT, SLVS_PATTERN)) break; SS.GetFilenameAndSave(true);
}
if(SS.SaveToFile(newFile)) {
AddToRecentList(newFile);
strcpy(SS.saveFile, newFile);
}
break; break;
}
case GraphicsWindow::MNU_EXIT: case GraphicsWindow::MNU_EXIT:
if(!SS.OkayToStartNewFile()) break;
exit(0);
break; break;
default: oops(); default: oops();

View File

@ -12,6 +12,8 @@
#define max(x, y) ((x) > (y) ? (x) : (y)) #define max(x, y) ((x) > (y) ? (x) : (y))
#endif #endif
#define isnan(x) (((x) != (x)) || (x > 1e11) || (x < -1e11))
inline int WRAP(int v, int n) { inline int WRAP(int v, int n) {
while(v >= n) v -= n; while(v >= n) v -= n;
while(v < 0) v += n; while(v < 0) v += n;
@ -215,8 +217,6 @@ public:
inline Param *GetParam (hParam h) { return param. FindById(h); } inline Param *GetParam (hParam h) { return param. FindById(h); }
inline Group *GetGroup (hGroup h) { return group. FindById(h); } inline Group *GetGroup (hGroup h) { return group. FindById(h); }
hGroup activeGroup;
FILE *fh; FILE *fh;
void Init(char *cmdLine); void Init(char *cmdLine);
@ -243,6 +243,8 @@ public:
Constraint c; Constraint c;
} sv; } sv;
static void MenuFile(int id); static void MenuFile(int id);
bool GetFilenameAndSave(bool saveAs);
bool OkayToStartNewFile(void);
hGroup CreateDefaultDrawingGroup(void); hGroup CreateDefaultDrawingGroup(void);
void NewFile(void); void NewFile(void);
bool SaveToFile(char *filename); bool SaveToFile(char *filename);
@ -273,6 +275,12 @@ public:
// The system to be solved. // The system to be solved.
System sys; System sys;
struct {
bool showTW;
bool generateAll;
} later;
void DoLater(void);
}; };
extern SolveSpace SS; extern SolveSpace SS;

View File

@ -332,7 +332,12 @@ bool System::NewtonSolve(int tag) {
// Take the Newton step; // Take the Newton step;
// J(x_n) (x_{n+1} - x_n) = 0 - F(x_n) // J(x_n) (x_{n+1} - x_n) = 0 - F(x_n)
for(i = 0; i < mat.n; i++) { for(i = 0; i < mat.n; i++) {
(param.FindById(mat.param[i]))->val -= mat.X[i]; Param *p = param.FindById(mat.param[i]);
p->val -= mat.X[i];
if(isnan(p->val)) {
// Very bad, and clearly not convergent
return false;
}
} }
// Re-evalute the functions, since the params have just changed. // Re-evalute the functions, since the params have just changed.
@ -342,6 +347,9 @@ bool System::NewtonSolve(int tag) {
// Check for convergence // Check for convergence
converged = true; converged = true;
for(i = 0; i < mat.m; i++) { for(i = 0; i < mat.m; i++) {
if(isnan(mat.B.num[i])) {
return false;
}
if(fabs(mat.B.num[i]) > 1e-10) { if(fabs(mat.B.num[i]) > 1e-10) {
converged = false; converged = false;
break; break;
@ -459,7 +467,6 @@ void System::Solve(Group *g) {
} else { } else {
val = p->val; val = p->val;
} }
Param *pp = SS.GetParam(p->h); Param *pp = SS.GetParam(p->h);
pp->val = val; pp->val = val;
pp->known = true; pp->known = true;

View File

@ -458,7 +458,7 @@ void TextWindow::ReportHowGroupSolved(hGroup hg) {
SS.GW.ClearSuper(); SS.GW.ClearSuper();
SS.TW.OneScreenForwardTo(SCREEN_GROUP_SOLVE_INFO); SS.TW.OneScreenForwardTo(SCREEN_GROUP_SOLVE_INFO);
SS.TW.shown->group.v = hg.v; SS.TW.shown->group.v = hg.v;
SS.TW.Show(); SS.later.showTW = true;
} }
void TextWindow::ScreenHowGroupSolved(int link, DWORD v) { void TextWindow::ScreenHowGroupSolved(int link, DWORD v) {
if(SS.GW.activeGroup.v != v) { if(SS.GW.activeGroup.v != v) {
@ -470,6 +470,7 @@ void TextWindow::ScreenHowGroupSolved(int link, DWORD v) {
void TextWindow::ShowListOfGroups(void) { void TextWindow::ShowListOfGroups(void) {
Printf(true, "%Ftactv show ok group-name%E"); Printf(true, "%Ftactv show ok group-name%E");
int i; int i;
bool afterActive = false;
for(i = 0; i < SS.group.n; i++) { for(i = 0; i < SS.group.n; i++) {
Group *g = &(SS.group.elem[i]); Group *g = &(SS.group.elem[i]);
char *s = g->DescriptionString(); char *s = g->DescriptionString();
@ -479,7 +480,7 @@ void TextWindow::ShowListOfGroups(void) {
bool ref = (g->h.v == Group::HGROUP_REFERENCES.v); bool ref = (g->h.v == Group::HGROUP_REFERENCES.v);
Printf(false, "%Bp%Fd " Printf(false, "%Bp%Fd "
"%Fp%D%f%s%Ll%s%E%s " "%Fp%D%f%s%Ll%s%E%s "
"%Fp%D%f%Ll%s%E%s " "%Fp%D%f%Ll%s%E%Fh%s%E "
"%Fp%D%f%s%Ll%s%E " "%Fp%D%f%s%Ll%s%E "
"%Fl%Ll%D%f%s", "%Fl%Ll%D%f%s",
// Alternate between light and dark backgrounds, for readability // Alternate between light and dark backgrounds, for readability
@ -491,14 +492,16 @@ void TextWindow::ShowListOfGroups(void) {
active ? "" : " ", active ? "" : " ",
// Link that hides or shows the group // Link that hides or shows the group
shown ? 's' : 'h', g->h.v, (&TextWindow::ScreenToggleGroupShown), shown ? 's' : 'h', g->h.v, (&TextWindow::ScreenToggleGroupShown),
shown ? "yes" : "no", afterActive ? "" : (shown ? "yes" : "no"),
shown ? "" : " ", afterActive ? " - " : (shown ? "" : " "),
// Link to the errors, if a problem occured while solving // Link to the errors, if a problem occured while solving
ok ? 's' : 'x', g->h.v, (&TextWindow::ScreenHowGroupSolved), ok ? 's' : 'x', g->h.v, (&TextWindow::ScreenHowGroupSolved),
ok ? "ok" : "", ok ? "ok" : "",
ok ? "" : "NO", ok ? "" : "NO",
// Link to a screen that gives more details on the group // Link to a screen that gives more details on the group
g->h.v, (&TextWindow::ScreenSelectGroup), s); g->h.v, (&TextWindow::ScreenSelectGroup), s);
if(active) afterActive = true;
} }
Printf(true, " %Fl%Ls%fshow all groups before active%E", Printf(true, " %Fl%Ls%fshow all groups before active%E",
@ -509,8 +512,16 @@ void TextWindow::ShowListOfGroups(void) {
void TextWindow::ScreenHoverConstraint(int link, DWORD v) { void TextWindow::ScreenHoverConstraint(int link, DWORD v) {
if(!SS.GW.showConstraints) return;
hConstraint hc = { v };
Constraint *c = SS.GetConstraint(hc);
if(c->group.v != SS.GW.activeGroup.v) {
// Only constraints in the active group are visible
return;
}
SS.GW.hover.Clear(); SS.GW.hover.Clear();
SS.GW.hover.constraint.v = v; SS.GW.hover.constraint = hc;
SS.GW.hover.emphasized = true; SS.GW.hover.emphasized = true;
} }
void TextWindow::ScreenHoverRequest(int link, DWORD v) { void TextWindow::ScreenHoverRequest(int link, DWORD v) {
@ -541,11 +552,7 @@ void TextWindow::ScreenChangeOneOrTwoSides(int link, DWORD v) {
} }
void TextWindow::ScreenChangeMeshCombine(int link, DWORD v) { void TextWindow::ScreenChangeMeshCombine(int link, DWORD v) {
Group *g = SS.GetGroup(SS.TW.shown->group); Group *g = SS.GetGroup(SS.TW.shown->group);
if(g->meshCombine == Group::COMBINE_AS_DIFFERENCE) { g->meshCombine = v;
g->meshCombine = Group::COMBINE_AS_UNION;
} else if(g->meshCombine == Group::COMBINE_AS_UNION) {
g->meshCombine = Group::COMBINE_AS_DIFFERENCE;
} else oops();
SS.MarkGroupDirty(g->h); SS.MarkGroupDirty(g->h);
SS.GenerateAll(); SS.GenerateAll();
SS.GW.ClearSuper(); SS.GW.ClearSuper();
@ -566,7 +573,7 @@ void TextWindow::ScreenChangeExprA(int link, DWORD v) {
} }
void TextWindow::ScreenChangeGroupName(int link, DWORD v) { void TextWindow::ScreenChangeGroupName(int link, DWORD v) {
Group *g = SS.GetGroup(SS.TW.shown->group); Group *g = SS.GetGroup(SS.TW.shown->group);
ShowTextEditControl(7, 13, g->DescriptionString()+5); ShowTextEditControl(7, 14, g->DescriptionString()+5);
SS.TW.edit.meaning = EDIT_GROUP_NAME; SS.TW.edit.meaning = EDIT_GROUP_NAME;
SS.TW.edit.group.v = v; SS.TW.edit.group.v = v;
} }
@ -588,9 +595,9 @@ void TextWindow::ShowGroupInfo(void) {
char *s, *s2; char *s, *s2;
if(shown->group.v == Group::HGROUP_REFERENCES.v) { if(shown->group.v == Group::HGROUP_REFERENCES.v) {
Printf(true, "%FtGROUP %E%s", g->DescriptionString()); Printf(true, "%FtGROUP %E%s", g->DescriptionString());
} else { } else {
Printf(true, "%FtGROUP %E%s " Printf(true, "%FtGROUP %E%s "
"(%Fl%Ll%D%frename%E / %Fl%Ll%D%fdel%E)", "(%Fl%Ll%D%frename%E / %Fl%Ll%D%fdel%E)",
g->DescriptionString(), g->DescriptionString(),
g->h.v, &TextWindow::ScreenChangeGroupName, g->h.v, &TextWindow::ScreenChangeGroupName,
@ -598,17 +605,17 @@ void TextWindow::ShowGroupInfo(void) {
} }
if(g->type == Group::IMPORTED) { if(g->type == Group::IMPORTED) {
Printf(true, "%FtIMPORT %E '%s'", g->impFile); Printf(true, "%FtIMPORT%E '%s'", g->impFile);
} }
if(g->type == Group::EXTRUDE) { if(g->type == Group::EXTRUDE) {
s = "EXTRUDE"; s = "EXTRUDE ";
} else if(g->type == Group::TRANSLATE) { } else if(g->type == Group::TRANSLATE) {
s = "TRANSLATE"; s = "TRANSLATE";
s2 ="REPEAT "; s2 ="REPEAT ";
} else if(g->type == Group::ROTATE) { } else if(g->type == Group::ROTATE) {
s = "ROTATE"; s = "ROTATE";
s2 ="REPEAT "; s2 ="REPEAT";
} }
if(g->type == Group::EXTRUDE || g->type == Group::ROTATE || if(g->type == Group::EXTRUDE || g->type == Group::ROTATE ||
@ -621,24 +628,38 @@ void TextWindow::ShowGroupInfo(void) {
&TextWindow::ScreenChangeOneOrTwoSides, &TextWindow::ScreenChangeOneOrTwoSides,
(!one ? "" : "two sides"), (!one ? "two sides" : "")); (!one ? "" : "two sides"), (!one ? "two sides" : ""));
} }
if(g->type == Group::ROTATE || g->type == Group::TRANSLATE) { if(g->type == Group::ROTATE || g->type == Group::TRANSLATE) {
int times = (int)(g->exprA->Eval()); int times = (int)(g->exprA->Eval());
Printf(true, "%Ft%s%E %d time%s %Fl%Ll%D%f(change)%E", Printf(true, "%Ft%s%E %d time%s %Fl%Ll%D%f(change)%E",
s2, times, times == 1 ? "" : "s", s2, times, times == 1 ? "" : "s",
g->h.v, &TextWindow::ScreenChangeExprA); g->h.v, &TextWindow::ScreenChangeExprA);
} }
if(g->type == Group::EXTRUDE) {
if(g->type == Group::EXTRUDE || g->type == Group::IMPORTED) {
bool un = (g->meshCombine == Group::COMBINE_AS_UNION);
bool diff = (g->meshCombine == Group::COMBINE_AS_DIFFERENCE); bool diff = (g->meshCombine == Group::COMBINE_AS_DIFFERENCE);
Printf(false, "%FtCOMBINE%E %Fh%f%Ll%s%E%Fs%s%E / %Fh%f%Ll%s%E%Fs%s%E", bool asy = (g->meshCombine == Group::COMBINE_AS_ASSEMBLE);
bool asa = (g->type == Group::IMPORTED);
Printf(false,
"%FtMERGE AS%E %Fh%f%D%Ll%s%E%Fs%s%E / %Fh%f%D%Ll%s%E%Fs%s%E %s "
"%Fh%f%D%Ll%s%E%Fs%s%E",
&TextWindow::ScreenChangeMeshCombine, &TextWindow::ScreenChangeMeshCombine,
(!diff ? "" : "as union"), (!diff ? "as union" : ""), Group::COMBINE_AS_UNION,
(un ? "" : "union"), (un ? "union" : ""),
&TextWindow::ScreenChangeMeshCombine, &TextWindow::ScreenChangeMeshCombine,
(diff ? "" : "as difference"), (diff ? "as difference" : "")); Group::COMBINE_AS_DIFFERENCE,
(diff ? "" : "difference"), (diff ? "difference" : ""),
asa ? "/" : "",
&TextWindow::ScreenChangeMeshCombine,
Group::COMBINE_AS_ASSEMBLE,
(asy || !asa ? "" : "assemble"), (asy && asa ? "assemble" : ""));
} }
if(g->type == Group::EXTRUDE) { if(g->type == Group::EXTRUDE) {
#define TWOX(v) v v #define TWOX(v) v v
Printf(true, "%FtMCOLOR%E " TWOX(TWOX(TWOX("%Bp%D%f%Ln %Bd%E "))), Printf(true, "%FtM_COLOR%E " TWOX(TWOX(TWOX("%Bp%D%f%Ln %Bd%E "))),
0x80000000 | modelColor[0], 0, &TextWindow::ScreenColor, 0x80000000 | modelColor[0], 0, &TextWindow::ScreenColor,
0x80000000 | modelColor[1], 1, &TextWindow::ScreenColor, 0x80000000 | modelColor[1], 1, &TextWindow::ScreenColor,
0x80000000 | modelColor[2], 2, &TextWindow::ScreenColor, 0x80000000 | modelColor[2], 2, &TextWindow::ScreenColor,
@ -744,8 +765,8 @@ void TextWindow::EditControlDone(char *s) {
g->exprA = e->DeepCopyKeep(); g->exprA = e->DeepCopyKeep();
SS.MarkGroupDirty(g->h); SS.MarkGroupDirty(g->h);
SS.GenerateAll(); SS.later.generateAll = true;
SS.TW.Show(); SS.later.showTW = true;
} else { } else {
Error("Not a valid number or expression: '%s'", s); Error("Not a valid number or expression: '%s'", s);
} }
@ -765,7 +786,8 @@ void TextWindow::EditControlDone(char *s) {
Group *g = SS.GetGroup(edit.group); Group *g = SS.GetGroup(edit.group);
g->name.strcpy(s); g->name.strcpy(s);
} }
SS.TW.Show(); SS.later.showTW = true;
SS.unsaved = true;
break; break;
} }
} }

View File

@ -263,7 +263,7 @@ LRESULT CALLBACK TextWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
case WM_CLOSE: case WM_CLOSE:
case WM_DESTROY: case WM_DESTROY:
PostQuitMessage(0); SolveSpace::MenuFile(GraphicsWindow::MNU_EXIT);
break; break;
case WM_PAINT: { case WM_PAINT: {
@ -642,7 +642,7 @@ LRESULT CALLBACK GraphicsWndProc(HWND hwnd, UINT msg, WPARAM wParam,
case WM_CLOSE: case WM_CLOSE:
case WM_DESTROY: case WM_DESTROY:
PostQuitMessage(0); SolveSpace::MenuFile(GraphicsWindow::MNU_EXIT);
return 1; return 1;
default: default:
@ -916,10 +916,17 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
DWORD ret; DWORD ret;
while(ret = GetMessage(&msg, NULL, 0, 0)) { while(ret = GetMessage(&msg, NULL, 0, 0)) {
if(msg.message == WM_KEYDOWN) { if(msg.message == WM_KEYDOWN) {
if(ProcessKeyDown(msg.wParam)) continue; if(ProcessKeyDown(msg.wParam)) goto done;
}
if(msg.message == WM_SYSKEYDOWN && msg.hwnd == TextWnd) {
// If the user presses the Alt key when the text window has focus,
// then that should probably go to the graphics window instead.
SetForegroundWindow(GraphicsWnd);
} }
TranslateMessage(&msg); TranslateMessage(&msg);
DispatchMessage(&msg); DispatchMessage(&msg);
done:
SS.DoLater();
} }
// Write everything back to the registry // Write everything back to the registry

17
wishlist.txt Normal file
View File

@ -0,0 +1,17 @@
STL check for meshes, and T intersection removal
STL export
better triangle combining (Simplify()) for meshes
solids of revolution
investigate slowdown with large number of entities
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