Add step and repeat translate, with multiple copies; that all works

nicely. And to do that, I've added the user interface to show an
edit control in the text window.

[git-p4: depot-paths = "//depot/solvespace/": change = 1749]
solver
Jonathan Westhues 2008-05-26 22:36:59 -08:00
parent ecee90965e
commit 4375c01c51
12 changed files with 189 additions and 32 deletions

View File

@ -460,7 +460,7 @@ s:
Vector a = SS.GetEntity(ptA)->PointGetNum();
Vector b = SS.GetEntity(ptB)->PointGetNum();
Entity *w = SS.GetEntity(SS.GetEntity(ptA)->workplane);
Entity *w = SS.GetEntity(workplane);
Vector cu = w->Normal()->NormalU();
Vector cv = w->Normal()->NormalV();
Vector cn = w->Normal()->NormalN();

View File

@ -332,6 +332,7 @@ void Entity::PointForceTo(Vector p) {
}
case POINT_N_TRANS: {
if(timesApplied == 0) break;
Vector trans = (p.Minus(numPoint)).ScaledBy(1.0/timesApplied);
SS.GetParam(param[0])->val = trans.x;
SS.GetParam(param[1])->val = trans.y;

View File

@ -55,6 +55,7 @@ const SolveSpace::SaveTable SolveSpace::SAVED[] = {
{ 'g', "Group.activeWorkplane.v", 'x', &(SS.sv.g.activeWorkplane.v) },
{ 'g', "Group.opA.v", 'x', &(SS.sv.g.opA.v) },
{ 'g', "Group.opB.v", 'x', &(SS.sv.g.opB.v) },
{ 'g', "Group.exprA", 'E', &(SS.sv.g.exprA) },
{ 'g', "Group.subtype", 'd', &(SS.sv.g.subtype) },
{ 'g', "Group.meshCombine", 'd', &(SS.sv.g.meshCombine) },
{ 'g', "Group.wrkpl.q.w", 'f', &(SS.sv.g.wrkpl.q.w) },

View File

@ -292,6 +292,7 @@ void GraphicsWindow::MenuEdit(int id) {
switch(id) {
case MNU_UNSELECT_ALL:
HideGraphicsEditControl();
HideTextEditControl();
SS.GW.ClearSelection();
SS.GW.ClearPending();
SS.TW.ScreenNavigation('h', 0);
@ -320,6 +321,8 @@ void GraphicsWindow::MenuEdit(int id) {
// Forget any mention of the just-deleted entity
SS.GW.ClearSuper();
HideGraphicsEditControl();
HideTextEditControl();
// And regenerate to get rid of what it generates, plus anything
// that references it (since the regen code checks for that).
SS.GenerateAll(SS.GW.solving == SOLVE_ALWAYS, 0, INT_MAX);

View File

@ -50,7 +50,7 @@ void SMesh::GetBounding(Vector *vmax, Vector *vmin) {
}
void SMesh::Simplify(int start) {
#define MAX_TRIANGLES 500
#define MAX_TRIANGLES 2000
if(l.n - start > MAX_TRIANGLES) oops();
STriangle tout[MAX_TRIANGLES];

View File

@ -75,16 +75,26 @@ void Group::MenuGroup(int id) {
g.type = EXTRUDE;
g.opA = SS.GW.activeGroup;
g.wrkpl.entityB = SS.GW.ActiveWorkplane();
g.subtype = EXTRUDE_ONE_SIDED;
g.subtype = ONE_SIDED;
g.name.strcpy("extrude");
break;
case GraphicsWindow::MNU_GROUP_ROT:
g.type = ROTATE;
g.opA = SS.GW.activeGroup;
g.exprA = Expr::FromConstant(7)->DeepCopyKeep();
g.subtype = ONE_SIDED;
g.name.strcpy("rotate");
break;
case GraphicsWindow::MNU_GROUP_TRANS:
g.type = TRANSLATE;
g.opA = SS.GW.activeGroup;
g.exprA = Expr::FromConstant(7)->DeepCopyKeep();
g.subtype = ONE_SIDED;
g.name.strcpy("translate");
break;
default: oops();
}
@ -113,8 +123,10 @@ void Group::Generate(IdList<Entity,hEntity> *entity,
IdList<Param,hParam> *param)
{
Vector gn = (SS.GW.projRight).Cross(SS.GW.projUp);
Vector gp = SS.GW.projRight.Plus(SS.GW.projUp);
gn = gn.WithMagnitude(200/SS.GW.scale);
int i;
gp = gp.WithMagnitude(200/SS.GW.scale);
int a, i;
switch(type) {
case DRAWING_3D:
break;
@ -170,9 +182,9 @@ void Group::Generate(IdList<Entity,hEntity> *entity,
AddParam(param, h.param(1), gn.y);
AddParam(param, h.param(2), gn.z);
int ai, af;
if(subtype == EXTRUDE_ONE_SIDED) {
ai = 0; af = 1;
} else if(subtype == EXTRUDE_TWO_SIDED) {
if(subtype == ONE_SIDED) {
ai = 0; af = 2;
} else if(subtype == TWO_SIDED) {
ai = -1; af = 1;
} else oops();
for(i = 0; i < entity->n; i++) {
@ -194,11 +206,31 @@ void Group::Generate(IdList<Entity,hEntity> *entity,
}
break;
case TRANSLATE: {
// The translation vector
AddParam(param, h.param(0), gp.x);
AddParam(param, h.param(1), gp.y);
AddParam(param, h.param(2), gp.z);
int n = (int)(exprA->Eval());
for(a = 0; a < n; a++) {
for(i = 0; i < entity->n; i++) {
Entity *e = &(entity->elem[i]);
if(e->group.v != opA.v) continue;
CopyEntity(e->h, a*2 - (subtype == ONE_SIDED ? 0 : (n-1)),
h.param(0), h.param(1), h.param(2),
NO_PARAM, NO_PARAM, NO_PARAM, NO_PARAM,
true);
}
}
break;
}
case ROTATE:
// The translation vector
AddParam(param, h.param(0), 100);
AddParam(param, h.param(1), 100);
AddParam(param, h.param(2), 100);
AddParam(param, h.param(0), gp.x);
AddParam(param, h.param(1), gp.y);
AddParam(param, h.param(2), gp.z);
// The rotation quaternion
AddParam(param, h.param(3), 1);
AddParam(param, h.param(4), 0);
@ -427,8 +459,8 @@ void Group::MakePolygons(void) {
SS.GetParam(h.param(2))->val
);
Vector tbot, ttop;
if(subtype == EXTRUDE_ONE_SIDED) {
tbot = Vector::MakeFrom(0, 0, 0); ttop = translate;
if(subtype == ONE_SIDED) {
tbot = Vector::MakeFrom(0, 0, 0); ttop = translate.ScaledBy(2);
} else {
tbot = translate.ScaledBy(-1); ttop = translate.ScaledBy(1);
}

View File

@ -89,6 +89,7 @@ public:
hGroup opB;
bool visible;
hEntity activeWorkplane;
Expr *exprA;
static const int SOLVED_OKAY = 0;
static const int DIDNT_CONVERGE = 10;
@ -100,8 +101,8 @@ public:
static const int WORKPLANE_BY_POINT_ORTHO = 6000;
static const int WORKPLANE_BY_LINE_SEGMENTS = 6001;
static const int EXTRUDE_ONE_SIDED = 7000;
static const int EXTRUDE_TWO_SIDED = 7001;
static const int ONE_SIDED = 7000;
static const int TWO_SIDED = 7001;
int subtype;
struct {

View File

@ -232,6 +232,8 @@ void SolveSpace::GenerateAll(bool andSolve, int first, int last) {
// the active group or active workplane could have been deleted. So
// clear all that out.
GW.ClearSuper();
HideGraphicsEditControl();
HideTextEditControl();
}
return;

View File

@ -52,6 +52,9 @@ void EnableMenuById(int id, BOOL checked);
void ShowGraphicsEditControl(int x, int y, char *s);
void HideGraphicsEditControl(void);
BOOL GraphicsEditControlIsVisible(void);
void ShowTextEditControl(int hr, int c, char *s);
void HideTextEditControl(void);
BOOL TextEditControlIsVisible(void);
void ShowTextWindow(BOOL visible);
void InvalidateText(void);

View File

@ -374,12 +374,12 @@ void TextWindow::ScreenSelectRequest(int link, DWORD v) {
SS.GW.ClearSelection();
SS.GW.selection[0].entity = hr.entity(0);
}
void TextWindow::ScreenChangeExtrudeSides(int link, DWORD v) {
void TextWindow::ScreenChangeOneOrTwoSides(int link, DWORD v) {
Group *g = SS.GetGroup(SS.TW.shown->group);
if(g->subtype == Group::EXTRUDE_ONE_SIDED) {
g->subtype = Group::EXTRUDE_TWO_SIDED;
} else if(g->subtype == Group::EXTRUDE_TWO_SIDED) {
g->subtype = Group::EXTRUDE_ONE_SIDED;
if(g->subtype == Group::ONE_SIDED) {
g->subtype = Group::TWO_SIDED;
} else if(g->subtype == Group::TWO_SIDED) {
g->subtype = Group::ONE_SIDED;
} else oops();
SS.GW.GeneratePerSolving();
SS.GW.ClearSuper();
@ -394,9 +394,15 @@ void TextWindow::ScreenChangeMeshCombine(int link, DWORD v) {
SS.GW.GeneratePerSolving();
SS.GW.ClearSuper();
}
void TextWindow::ScreenChangeExprA(int link, DWORD v) {
Group *g = SS.GetGroup(SS.TW.shown->group);
ShowTextEditControl(13, 10, g->exprA->Print());
SS.TW.edit.meaning = EDIT_TIMES_REPEATED;
SS.TW.edit.group.v = v;
}
void TextWindow::ShowGroupInfo(void) {
Group *g = SS.group.FindById(shown->group);
char *s;
char *s, *s2;
if(SS.GW.activeGroup.v == shown->group.v) {
s = "active ";
} else if(shown->group.v == Group::HGROUP_REFERENCES.v) {
@ -407,13 +413,33 @@ void TextWindow::ShowGroupInfo(void) {
Printf(true, "%Ft%sGROUP %E%s", s, g->DescriptionString());
if(g->type == Group::EXTRUDE) {
bool one = (g->subtype == Group::EXTRUDE_ONE_SIDED);
Printf(true, "%FtEXTRUDE%E %Fh%f%Ll%s%E%Fs%s%E / %Fh%f%Ll%s%E%Fs%s%E",
&TextWindow::ScreenChangeExtrudeSides,
(one ? "" : "one side"), (one ? "one-side" : ""),
&TextWindow::ScreenChangeExtrudeSides,
s = "EXTRUDE";
} else if(g->type == Group::TRANSLATE) {
s = "TRANSLATE";
s2 ="REPEAT ";
} else if(g->type == Group::ROTATE) {
s = "ROTATE";
s2 ="REPEAT ";
}
if(g->type == Group::EXTRUDE || g->type == Group::ROTATE ||
g->type == Group::TRANSLATE)
{
bool one = (g->subtype == Group::ONE_SIDED);
Printf(true, "%Ft%s%E %Fh%f%Ll%s%E%Fs%s%E / %Fh%f%Ll%s%E%Fs%s%E", s,
&TextWindow::ScreenChangeOneOrTwoSides,
(one ? "" : "one side"), (one ? "one side" : ""),
&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, &TextWindow::ScreenChangeExprA);
}
if(g->type == Group::EXTRUDE) {
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",
&TextWindow::ScreenChangeMeshCombine,
@ -505,4 +531,23 @@ void TextWindow::ShowConstraintInfo(void) {
Printf(false, "[[constraint]]");
}
void TextWindow::EditControlDone(char *s) {
HideTextEditControl();
switch(edit.meaning) {
case EDIT_TIMES_REPEATED: {
Expr *e = Expr::FromString(s);
if(e) {
Group *g = SS.GetGroup(edit.group);
Expr::FreeKeep(&(g->exprA));
g->exprA = e->DeepCopyKeep();
SS.GW.GeneratePerSolving();
SS.TW.Show();
} else {
Error("Not a valid number or expression: '%s'", s);
}
break;
}
}
edit.meaning = EDIT_NOTHING;
}

14
ui.h
View File

@ -55,6 +55,13 @@ public:
int history;
ShownState *shown;
static const int EDIT_NOTHING = 0;
static const int EDIT_TIMES_REPEATED = 1;
struct {
int meaning;
hGroup group;
} edit;
static void ReportHowGroupSolved(hGroup hg);
void ShowHeader(void);
@ -68,6 +75,8 @@ public:
void ShowGroupSolveInfo(void);
void OneScreenForwardTo(int screen);
// All of these are callbacks from the GUI code.
static void ScreenSelectGroup(int link, DWORD v);
static void ScreenActivateGroup(int link, DWORD v);
static void ScreenToggleGroupShown(int link, DWORD v);
@ -79,10 +88,13 @@ public:
static void ScreenSelectRequest(int link, DWORD v);
static void ScreenSelectConstraint(int link, DWORD v);
static void ScreenChangeExtrudeSides(int link, DWORD v);
static void ScreenChangeOneOrTwoSides(int link, DWORD v);
static void ScreenChangeMeshCombine(int link, DWORD v);
static void ScreenChangeExprA(int link, DWORD v);
static void ScreenNavigation(int link, DWORD v);
void EditControlDone(char *s);
};
class GraphicsWindow {

View File

@ -15,11 +15,18 @@
#define MIN_COLS 45
#define TEXT_HEIGHT 20
#define TEXT_WIDTH 9
#define TEXT_LEFT_MARGIN 4
// For the edit controls
#define EDIT_WIDTH 220
#define EDIT_HEIGHT 21
HINSTANCE Instance;
HWND TextWnd;
HWND TextWndScrollBar;
HWND TextEditControl;
int TextEditControlCol, TextEditControlHalfRow;
int TextWndScrollPos; // The scrollbar position, in half-row units
int TextWndHalfRows; // The height of our window, in half-row units
@ -182,7 +189,7 @@ static void PaintTextWnd(HDC hdc)
SelectObject(backDc, FixedFont);
}
int x = 4 + c*TEXT_WIDTH;
int x = TEXT_LEFT_MARGIN + c*TEXT_WIDTH;
int y = (top-TextWndScrollPos)*(TEXT_HEIGHT/2);
RECT a;
@ -227,6 +234,11 @@ void HandleTextWindowScrollBar(WPARAM wParam, LPARAM lParam)
si.nPos = TextWndScrollPos;
SetScrollInfo(TextWndScrollBar, SB_CTL, &si, TRUE);
if(TextEditControlIsVisible()) {
int x = TEXT_LEFT_MARGIN + TEXT_WIDTH*TextEditControlCol;
int y = (TextEditControlHalfRow - TextWndScrollPos)*(TEXT_HEIGHT/2);
MoveWindow(TextEditControl, x, y, EDIT_WIDTH, EDIT_HEIGHT, TRUE);
}
InvalidateRect(TextWnd, NULL, FALSE);
}
}
@ -288,6 +300,10 @@ LRESULT CALLBACK TextWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
case WM_LBUTTONDOWN:
case WM_MOUSEMOVE: {
if(TextEditControlIsVisible() || GraphicsEditControlIsVisible()) {
SetCursor(LoadCursor(NULL, IDC_ARROW));
break;
}
GraphicsWindow::Selection ps = SS.GW.hover;
SS.GW.hover.Clear();
@ -340,6 +356,9 @@ done:
GetClientRect(hwnd, &r);
MoveWindow(TextWndScrollBar, r.right - sw, r.top, sw,
(r.bottom - r.top), TRUE);
// If the window is growing, then the scrollbar position may
// be moving, so it's as if we're dragging the scrollbar.
HandleTextWindowScrollBar(0, 0);
InvalidateRect(TextWnd, NULL, FALSE);
break;
}
@ -368,6 +387,16 @@ static BOOL ProcessKeyDown(WPARAM wParam)
return FALSE;
}
}
if(TextEditControlIsVisible() && wParam != VK_ESCAPE) {
if(wParam == VK_RETURN) {
char s[1024];
memset(s, 0, sizeof(s));
SendMessage(TextEditControl, WM_GETTEXT, 900, (LPARAM)s);
SS.TW.EditControlDone(s);
} else {
return FALSE;
}
}
if(wParam == VK_BACK && !GraphicsEditControlIsVisible()) {
TextWindow::ScreenNavigation('b', 0);
@ -463,8 +492,35 @@ void InvalidateText(void)
InvalidateRect(TextWnd, NULL, FALSE);
}
static void ShowEditControl(HWND h, int x, int y, char *s) {
MoveWindow(h, x, y, EDIT_WIDTH, EDIT_HEIGHT, TRUE);
ShowWindow(h, SW_SHOW);
SendMessage(h, WM_SETTEXT, 0, (LPARAM)s);
SendMessage(h, EM_SETSEL, 0, strlen(s));
SetFocus(h);
}
void ShowTextEditControl(int hr, int c, char *s)
{
if(TextEditControlIsVisible() || GraphicsEditControlIsVisible()) return;
int x = TEXT_LEFT_MARGIN + TEXT_WIDTH*c;
int y = (hr - TextWndScrollPos)*(TEXT_HEIGHT/2);
TextEditControlCol = c;
TextEditControlHalfRow = hr;
ShowEditControl(TextEditControl, x, y, s);
}
void HideTextEditControl(void)
{
ShowWindow(TextEditControl, SW_HIDE);
}
BOOL TextEditControlIsVisible(void)
{
return IsWindowVisible(TextEditControl);
}
void ShowGraphicsEditControl(int x, int y, char *s)
{
if(TextEditControlIsVisible() || GraphicsEditControlIsVisible()) return;
RECT r;
GetClientRect(GraphicsWnd, &r);
x = x + (r.right - r.left)/2;
@ -474,11 +530,7 @@ void ShowGraphicsEditControl(int x, int y, char *s)
// top left corner
y -= 20;
MoveWindow(GraphicsEditControl, x, y, 220, 21, TRUE);
ShowWindow(GraphicsEditControl, SW_SHOW);
SendMessage(GraphicsEditControl, WM_SETTEXT, 0, (LPARAM)s);
SendMessage(GraphicsEditControl, EM_SETSEL, 0, strlen(s));
SetFocus(GraphicsEditControl);
ShowEditControl(GraphicsEditControl, x, y, s);
}
void HideGraphicsEditControl(void)
{
@ -745,6 +797,11 @@ static void CreateMainWindows(void)
// Force the scrollbar to get resized to the window,
TextWndProc(TextWnd, WM_SIZE, 0, 0);
TextEditControl = CreateWindowEx(WS_EX_CLIENTEDGE, WC_EDIT, "",
WS_CHILD | ES_AUTOHSCROLL | WS_TABSTOP | WS_CLIPSIBLINGS,
50, 50, 100, 21, TextWnd, NULL, Instance, NULL);
SendMessage(TextEditControl, WM_SETFONT, (WPARAM)FixedFont, TRUE);
RECT r, rc;
GetWindowRect(TextWnd, &r);