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
parent
7d4a4fbb76
commit
ea6db67c7d
|
@ -39,7 +39,7 @@ void Constraint::AddConstraint(Constraint *c) {
|
|||
SS.constraint.AddAndAssignId(c);
|
||||
|
||||
SS.MarkGroupDirty(c->group);
|
||||
SS.GenerateAll();
|
||||
SS.later.generateAll = true;
|
||||
}
|
||||
|
||||
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) {
|
||||
ExprVector r = a.Cross(b);
|
||||
// Hairy ball theorem screws me here. There's no clean solution that I
|
||||
// know, so let's pivot on the initial numerical guess.
|
||||
double mx = fabs((a.x)->Eval()) + fabs((b.x)->Eval());
|
||||
double my = fabs((a.y)->Eval()) + fabs((b.y)->Eval());
|
||||
double mz = fabs((a.z)->Eval()) + fabs((b.z)->Eval());
|
||||
// know, so let's pivot on the initial numerical guess. Our caller
|
||||
// has ensured that if one of our input vectors is already known (e.g.
|
||||
// it's from a previous group), then that one's in a; so that one's
|
||||
// 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
|
||||
// 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).
|
||||
|
@ -566,8 +569,13 @@ void Constraint::Generate(IdList<Equation,hEquation> *l) {
|
|||
ExprVector eab = ea.Minus(eb);
|
||||
ExprVector eap = ea.Minus(ep);
|
||||
|
||||
AddEq(l, VectorsParallel(0, eab, eap), 0);
|
||||
AddEq(l, VectorsParallel(1, eab, eap), 1);
|
||||
if(p->group.v == group.v) {
|
||||
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 {
|
||||
AddEq(l, PointLineDistance(workplane, ptA, entityA), 0);
|
||||
}
|
||||
|
@ -715,6 +723,10 @@ void Constraint::Generate(IdList<Equation,hEquation> *l) {
|
|||
case SAME_ORIENTATION: {
|
||||
Entity *a = SS.GetEntity(entityA);
|
||||
Entity *b = SS.GetEntity(entityB);
|
||||
if(b->group.v != group.v) {
|
||||
SWAP(Entity *, a, b);
|
||||
}
|
||||
|
||||
ExprVector au = a->NormalExprsU(),
|
||||
av = a->NormalExprsV(),
|
||||
an = a->NormalExprsN();
|
||||
|
@ -765,8 +777,12 @@ void Constraint::Generate(IdList<Equation,hEquation> *l) {
|
|||
}
|
||||
|
||||
case PARALLEL: {
|
||||
ExprVector a = SS.GetEntity(entityA)->VectorGetExprs();
|
||||
ExprVector b = SS.GetEntity(entityB)->VectorGetExprs();
|
||||
Entity *ea = SS.GetEntity(entityA), *eb = SS.GetEntity(entityB);
|
||||
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) {
|
||||
AddEq(l, VectorsParallel(0, a, b), 0);
|
||||
|
|
|
@ -295,7 +295,7 @@ void GraphicsWindow::EnsureValidActives(void) {
|
|||
ShowTextWindow(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) {
|
||||
|
@ -356,7 +356,7 @@ void GraphicsWindow::MenuEdit(int id) {
|
|||
// that references it (since the regen code checks for that).
|
||||
SS.GenerateAll(0, INT_MAX);
|
||||
SS.GW.EnsureValidActives();
|
||||
SS.TW.Show();
|
||||
SS.later.showTW = true;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -382,13 +382,13 @@ void GraphicsWindow::MenuRequest(int id) {
|
|||
// Align the view with the selected workplane
|
||||
SS.GW.AnimateOntoWorkplane();
|
||||
SS.GW.ClearSuper();
|
||||
SS.TW.Show();
|
||||
SS.later.showTW = true;
|
||||
break;
|
||||
}
|
||||
case MNU_FREE_IN_3D:
|
||||
SS.GW.SetWorkplaneFreeIn3d();
|
||||
SS.GW.EnsureValidActives();
|
||||
SS.TW.Show();
|
||||
SS.later.showTW = true;
|
||||
break;
|
||||
|
||||
case MNU_DATUM_POINT: s = "click to place datum point"; goto c;
|
||||
|
@ -401,7 +401,7 @@ void GraphicsWindow::MenuRequest(int id) {
|
|||
c:
|
||||
SS.GW.pending.operation = id;
|
||||
SS.GW.pending.description = s;
|
||||
SS.TW.Show();
|
||||
SS.later.showTW = true;
|
||||
break;
|
||||
|
||||
case MNU_CONSTRUCTION: {
|
||||
|
@ -578,10 +578,10 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
|
|||
double dx = -(x - orig.mouse.x);
|
||||
double dy = -(y - orig.mouse.y);
|
||||
double s = 0.3*(PI/180); // degrees per pixel
|
||||
u = u.RotatedAbout(orig.projUp, -s*dx);
|
||||
u = u.RotatedAbout(orig.projRight, s*dy);
|
||||
v = v.RotatedAbout(orig.projUp, -s*dx);
|
||||
v = v.RotatedAbout(orig.projRight, s*dy);
|
||||
u = u.RotatedAbout(projUp, -s*dx);
|
||||
u = u.RotatedAbout(projRight, s*dy);
|
||||
v = v.RotatedAbout(projUp, -s*dx);
|
||||
v = v.RotatedAbout(projRight, s*dy);
|
||||
}
|
||||
q = Quaternion::From(u, v);
|
||||
p->PointForceQuaternionTo(q);
|
||||
|
@ -779,7 +779,7 @@ void GraphicsWindow::ClearSelection(void) {
|
|||
for(int i = 0; i < MAX_SELECTED; i++) {
|
||||
selection[i].Clear();
|
||||
}
|
||||
SS.TW.Show();
|
||||
SS.later.showTW = true;
|
||||
InvalidateGraphics();
|
||||
}
|
||||
|
||||
|
@ -1101,7 +1101,7 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
|
|||
}
|
||||
}
|
||||
|
||||
SS.TW.Show();
|
||||
SS.later.showTW = true;
|
||||
InvalidateGraphics();
|
||||
}
|
||||
|
||||
|
@ -1180,7 +1180,7 @@ void GraphicsWindow::ToggleBool(int link, DWORD v) {
|
|||
|
||||
SS.GenerateAll();
|
||||
InvalidateGraphics();
|
||||
SS.TW.Show();
|
||||
SS.later.showTW = true;
|
||||
}
|
||||
|
||||
Vector GraphicsWindow::VectorFromProjs(double right, double up, double fwd) {
|
||||
|
|
10
sketch.cpp
10
sketch.cpp
|
@ -144,7 +144,7 @@ void Group::MenuGroup(int id) {
|
|||
SS.GetGroup(g.h)->Activate();
|
||||
SS.GW.AnimateOntoWorkplane();
|
||||
TextWindow::ScreenSelectGroup(0, g.h.v);
|
||||
SS.TW.Show();
|
||||
SS.later.showTW = true;
|
||||
}
|
||||
|
||||
char *Group::DescriptionString(void) {
|
||||
|
@ -164,8 +164,8 @@ void Group::Activate(void) {
|
|||
SS.GW.showFaces = false;
|
||||
}
|
||||
SS.MarkGroupDirty(h); // for good measure; shouldn't be needed
|
||||
SS.GenerateAll();
|
||||
SS.TW.Show();
|
||||
SS.later.generateAll = true;
|
||||
SS.later.showTW = true;
|
||||
}
|
||||
|
||||
void Group::Generate(IdList<Entity,hEntity> *entity,
|
||||
|
@ -740,8 +740,10 @@ void Group::GenerateMesh(void) {
|
|||
SMesh *a = PreviousGroupMesh();
|
||||
if(meshCombine == COMBINE_AS_UNION) {
|
||||
mesh.MakeFromUnion(a, &outm);
|
||||
} else {
|
||||
} else if(meshCombine == COMBINE_AS_DIFFERENCE) {
|
||||
mesh.MakeFromDifference(a, &outm);
|
||||
} else {
|
||||
|
||||
}
|
||||
outm.Clear();
|
||||
}
|
||||
|
|
1
sketch.h
1
sketch.h
|
@ -127,6 +127,7 @@ public:
|
|||
|
||||
static const int COMBINE_AS_UNION = 0;
|
||||
static const int COMBINE_AS_DIFFERENCE = 1;
|
||||
static const int COMBINE_AS_ASSEMBLE = 2;
|
||||
int meshCombine;
|
||||
|
||||
IdList<EntityMap,EntityId> remap;
|
||||
|
|
|
@ -17,6 +17,12 @@ void SolveSpace::Init(char *cmdLine) {
|
|||
AfterNewFile();
|
||||
}
|
||||
|
||||
void SolveSpace::DoLater(void) {
|
||||
if(later.generateAll) GenerateAll();
|
||||
if(later.showTW) TW.Show();
|
||||
ZERO(&later);
|
||||
}
|
||||
|
||||
void SolveSpace::AfterNewFile(void) {
|
||||
ReloadAllImported();
|
||||
GenerateAll(-1, -1);
|
||||
|
@ -24,8 +30,9 @@ void SolveSpace::AfterNewFile(void) {
|
|||
TW.Init();
|
||||
GW.Init();
|
||||
|
||||
unsaved = false;
|
||||
GenerateAll(0, INT_MAX);
|
||||
TW.Show();
|
||||
later.showTW = true;
|
||||
}
|
||||
|
||||
void SolveSpace::MarkGroupDirtyByEntity(hEntity he) {
|
||||
|
@ -256,7 +263,7 @@ void SolveSpace::GenerateAll(int first, int last) {
|
|||
if(deleted.groups > 0) {
|
||||
SS.TW.ClearSuper();
|
||||
}
|
||||
TW.Show();
|
||||
later.showTW = true;
|
||||
GW.ClearSuper();
|
||||
// Don't display any errors until we've regenerated fully. The
|
||||
// sketch is not necessarily in a consistent state until we've
|
||||
|
@ -365,6 +372,40 @@ void SolveSpace::AddToRecentList(char *file) {
|
|||
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) {
|
||||
|
||||
if(id >= RECENT_OPEN && id < (RECENT_OPEN+MAX_RECENT)) {
|
||||
|
@ -384,12 +425,16 @@ void SolveSpace::MenuFile(int id) {
|
|||
|
||||
switch(id) {
|
||||
case GraphicsWindow::MNU_NEW:
|
||||
if(!SS.OkayToStartNewFile()) break;
|
||||
|
||||
strcpy(SS.saveFile, "");
|
||||
SS.NewFile();
|
||||
SS.AfterNewFile();
|
||||
break;
|
||||
|
||||
case GraphicsWindow::MNU_OPEN: {
|
||||
if(!SS.OkayToStartNewFile()) break;
|
||||
|
||||
char newFile[MAX_PATH] = "";
|
||||
if(GetOpenFile(newFile, SLVS_EXT, SLVS_PATTERN)) {
|
||||
if(SS.LoadFromFile(newFile)) {
|
||||
|
@ -405,21 +450,16 @@ void SolveSpace::MenuFile(int id) {
|
|||
}
|
||||
|
||||
case GraphicsWindow::MNU_SAVE:
|
||||
case GraphicsWindow::MNU_SAVE_AS: {
|
||||
char newFile[MAX_PATH];
|
||||
strcpy(newFile, SS.saveFile);
|
||||
if(id == GraphicsWindow::MNU_SAVE_AS || strlen(newFile)==0) {
|
||||
if(!GetSaveFile(newFile, SLVS_EXT, SLVS_PATTERN)) break;
|
||||
}
|
||||
|
||||
if(SS.SaveToFile(newFile)) {
|
||||
AddToRecentList(newFile);
|
||||
strcpy(SS.saveFile, newFile);
|
||||
}
|
||||
SS.GetFilenameAndSave(false);
|
||||
break;
|
||||
|
||||
case GraphicsWindow::MNU_SAVE_AS:
|
||||
SS.GetFilenameAndSave(true);
|
||||
break;
|
||||
}
|
||||
|
||||
case GraphicsWindow::MNU_EXIT:
|
||||
if(!SS.OkayToStartNewFile()) break;
|
||||
exit(0);
|
||||
break;
|
||||
|
||||
default: oops();
|
||||
|
|
12
solvespace.h
12
solvespace.h
|
@ -12,6 +12,8 @@
|
|||
#define max(x, y) ((x) > (y) ? (x) : (y))
|
||||
#endif
|
||||
|
||||
#define isnan(x) (((x) != (x)) || (x > 1e11) || (x < -1e11))
|
||||
|
||||
inline int WRAP(int v, int n) {
|
||||
while(v >= n) v -= n;
|
||||
while(v < 0) v += n;
|
||||
|
@ -215,8 +217,6 @@ public:
|
|||
inline Param *GetParam (hParam h) { return param. FindById(h); }
|
||||
inline Group *GetGroup (hGroup h) { return group. FindById(h); }
|
||||
|
||||
hGroup activeGroup;
|
||||
|
||||
FILE *fh;
|
||||
|
||||
void Init(char *cmdLine);
|
||||
|
@ -243,6 +243,8 @@ public:
|
|||
Constraint c;
|
||||
} sv;
|
||||
static void MenuFile(int id);
|
||||
bool GetFilenameAndSave(bool saveAs);
|
||||
bool OkayToStartNewFile(void);
|
||||
hGroup CreateDefaultDrawingGroup(void);
|
||||
void NewFile(void);
|
||||
bool SaveToFile(char *filename);
|
||||
|
@ -273,6 +275,12 @@ public:
|
|||
|
||||
// The system to be solved.
|
||||
System sys;
|
||||
|
||||
struct {
|
||||
bool showTW;
|
||||
bool generateAll;
|
||||
} later;
|
||||
void DoLater(void);
|
||||
};
|
||||
|
||||
extern SolveSpace SS;
|
||||
|
|
11
system.cpp
11
system.cpp
|
@ -332,7 +332,12 @@ bool System::NewtonSolve(int tag) {
|
|||
// Take the Newton step;
|
||||
// J(x_n) (x_{n+1} - x_n) = 0 - F(x_n)
|
||||
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.
|
||||
|
@ -342,6 +347,9 @@ bool System::NewtonSolve(int tag) {
|
|||
// Check for convergence
|
||||
converged = true;
|
||||
for(i = 0; i < mat.m; i++) {
|
||||
if(isnan(mat.B.num[i])) {
|
||||
return false;
|
||||
}
|
||||
if(fabs(mat.B.num[i]) > 1e-10) {
|
||||
converged = false;
|
||||
break;
|
||||
|
@ -459,7 +467,6 @@ void System::Solve(Group *g) {
|
|||
} else {
|
||||
val = p->val;
|
||||
}
|
||||
|
||||
Param *pp = SS.GetParam(p->h);
|
||||
pp->val = val;
|
||||
pp->known = true;
|
||||
|
|
70
textwin.cpp
70
textwin.cpp
|
@ -458,7 +458,7 @@ void TextWindow::ReportHowGroupSolved(hGroup hg) {
|
|||
SS.GW.ClearSuper();
|
||||
SS.TW.OneScreenForwardTo(SCREEN_GROUP_SOLVE_INFO);
|
||||
SS.TW.shown->group.v = hg.v;
|
||||
SS.TW.Show();
|
||||
SS.later.showTW = true;
|
||||
}
|
||||
void TextWindow::ScreenHowGroupSolved(int link, DWORD v) {
|
||||
if(SS.GW.activeGroup.v != v) {
|
||||
|
@ -470,6 +470,7 @@ void TextWindow::ScreenHowGroupSolved(int link, DWORD v) {
|
|||
void TextWindow::ShowListOfGroups(void) {
|
||||
Printf(true, "%Ftactv show ok group-name%E");
|
||||
int i;
|
||||
bool afterActive = false;
|
||||
for(i = 0; i < SS.group.n; i++) {
|
||||
Group *g = &(SS.group.elem[i]);
|
||||
char *s = g->DescriptionString();
|
||||
|
@ -479,7 +480,7 @@ void TextWindow::ShowListOfGroups(void) {
|
|||
bool ref = (g->h.v == Group::HGROUP_REFERENCES.v);
|
||||
Printf(false, "%Bp%Fd "
|
||||
"%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 "
|
||||
"%Fl%Ll%D%f%s",
|
||||
// Alternate between light and dark backgrounds, for readability
|
||||
|
@ -491,14 +492,16 @@ void TextWindow::ShowListOfGroups(void) {
|
|||
active ? "" : " ",
|
||||
// Link that hides or shows the group
|
||||
shown ? 's' : 'h', g->h.v, (&TextWindow::ScreenToggleGroupShown),
|
||||
shown ? "yes" : "no",
|
||||
shown ? "" : " ",
|
||||
afterActive ? "" : (shown ? "yes" : "no"),
|
||||
afterActive ? " - " : (shown ? "" : " "),
|
||||
// Link to the errors, if a problem occured while solving
|
||||
ok ? 's' : 'x', g->h.v, (&TextWindow::ScreenHowGroupSolved),
|
||||
ok ? "ok" : "",
|
||||
ok ? "" : "NO",
|
||||
// Link to a screen that gives more details on the group
|
||||
g->h.v, (&TextWindow::ScreenSelectGroup), s);
|
||||
|
||||
if(active) afterActive = true;
|
||||
}
|
||||
|
||||
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) {
|
||||
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.constraint.v = v;
|
||||
SS.GW.hover.constraint = hc;
|
||||
SS.GW.hover.emphasized = true;
|
||||
}
|
||||
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) {
|
||||
Group *g = SS.GetGroup(SS.TW.shown->group);
|
||||
if(g->meshCombine == Group::COMBINE_AS_DIFFERENCE) {
|
||||
g->meshCombine = Group::COMBINE_AS_UNION;
|
||||
} else if(g->meshCombine == Group::COMBINE_AS_UNION) {
|
||||
g->meshCombine = Group::COMBINE_AS_DIFFERENCE;
|
||||
} else oops();
|
||||
g->meshCombine = v;
|
||||
SS.MarkGroupDirty(g->h);
|
||||
SS.GenerateAll();
|
||||
SS.GW.ClearSuper();
|
||||
|
@ -566,7 +573,7 @@ void TextWindow::ScreenChangeExprA(int link, DWORD v) {
|
|||
}
|
||||
void TextWindow::ScreenChangeGroupName(int link, DWORD v) {
|
||||
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.group.v = v;
|
||||
}
|
||||
|
@ -588,9 +595,9 @@ void TextWindow::ShowGroupInfo(void) {
|
|||
char *s, *s2;
|
||||
|
||||
if(shown->group.v == Group::HGROUP_REFERENCES.v) {
|
||||
Printf(true, "%FtGROUP %E%s", g->DescriptionString());
|
||||
Printf(true, "%FtGROUP %E%s", g->DescriptionString());
|
||||
} else {
|
||||
Printf(true, "%FtGROUP %E%s "
|
||||
Printf(true, "%FtGROUP %E%s "
|
||||
"(%Fl%Ll%D%frename%E / %Fl%Ll%D%fdel%E)",
|
||||
g->DescriptionString(),
|
||||
g->h.v, &TextWindow::ScreenChangeGroupName,
|
||||
|
@ -598,17 +605,17 @@ void TextWindow::ShowGroupInfo(void) {
|
|||
}
|
||||
|
||||
if(g->type == Group::IMPORTED) {
|
||||
Printf(true, "%FtIMPORT %E '%s'", g->impFile);
|
||||
Printf(true, "%FtIMPORT%E '%s'", g->impFile);
|
||||
}
|
||||
|
||||
if(g->type == Group::EXTRUDE) {
|
||||
s = "EXTRUDE";
|
||||
s = "EXTRUDE ";
|
||||
} else if(g->type == Group::TRANSLATE) {
|
||||
s = "TRANSLATE";
|
||||
s2 ="REPEAT ";
|
||||
} else if(g->type == Group::ROTATE) {
|
||||
s = "ROTATE";
|
||||
s2 ="REPEAT ";
|
||||
s2 ="REPEAT";
|
||||
}
|
||||
|
||||
if(g->type == Group::EXTRUDE || g->type == Group::ROTATE ||
|
||||
|
@ -621,24 +628,38 @@ void TextWindow::ShowGroupInfo(void) {
|
|||
&TextWindow::ScreenChangeOneOrTwoSides,
|
||||
(!one ? "" : "two sides"), (!one ? "two sides" : ""));
|
||||
}
|
||||
|
||||
if(g->type == Group::ROTATE || g->type == Group::TRANSLATE) {
|
||||
int times = (int)(g->exprA->Eval());
|
||||
Printf(true, "%Ft%s%E %d time%s %Fl%Ll%D%f(change)%E",
|
||||
s2, times, times == 1 ? "" : "s",
|
||||
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);
|
||||
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,
|
||||
(!diff ? "" : "as union"), (!diff ? "as union" : ""),
|
||||
Group::COMBINE_AS_UNION,
|
||||
(un ? "" : "union"), (un ? "union" : ""),
|
||||
&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) {
|
||||
#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[1], 1, &TextWindow::ScreenColor,
|
||||
0x80000000 | modelColor[2], 2, &TextWindow::ScreenColor,
|
||||
|
@ -744,8 +765,8 @@ void TextWindow::EditControlDone(char *s) {
|
|||
g->exprA = e->DeepCopyKeep();
|
||||
|
||||
SS.MarkGroupDirty(g->h);
|
||||
SS.GenerateAll();
|
||||
SS.TW.Show();
|
||||
SS.later.generateAll = true;
|
||||
SS.later.showTW = true;
|
||||
} else {
|
||||
Error("Not a valid number or expression: '%s'", s);
|
||||
}
|
||||
|
@ -765,7 +786,8 @@ void TextWindow::EditControlDone(char *s) {
|
|||
Group *g = SS.GetGroup(edit.group);
|
||||
g->name.strcpy(s);
|
||||
}
|
||||
SS.TW.Show();
|
||||
SS.later.showTW = true;
|
||||
SS.unsaved = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -263,7 +263,7 @@ LRESULT CALLBACK TextWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
|
||||
case WM_CLOSE:
|
||||
case WM_DESTROY:
|
||||
PostQuitMessage(0);
|
||||
SolveSpace::MenuFile(GraphicsWindow::MNU_EXIT);
|
||||
break;
|
||||
|
||||
case WM_PAINT: {
|
||||
|
@ -642,7 +642,7 @@ LRESULT CALLBACK GraphicsWndProc(HWND hwnd, UINT msg, WPARAM wParam,
|
|||
|
||||
case WM_CLOSE:
|
||||
case WM_DESTROY:
|
||||
PostQuitMessage(0);
|
||||
SolveSpace::MenuFile(GraphicsWindow::MNU_EXIT);
|
||||
return 1;
|
||||
|
||||
default:
|
||||
|
@ -916,10 +916,17 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
|||
DWORD ret;
|
||||
while(ret = GetMessage(&msg, NULL, 0, 0)) {
|
||||
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);
|
||||
DispatchMessage(&msg);
|
||||
done:
|
||||
SS.DoLater();
|
||||
}
|
||||
|
||||
// Write everything back to the registry
|
||||
|
|
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue