Add text angle for styles. Add ability to quickly change between

perspective and parallel projections. Add a snap grid, for points
and for text comments. Draw text comments in the plane of their
workplane if they have one, otherwise always facing forward.

And fix a few nasty bugs: the possibility of an extremely long
animation onto a workplane, accidental use of the wrong style line
width for constraints, misplaced text box in style screen for
default styles, other little stuff.

[git-p4: depot-paths = "//depot/solvespace/": change = 2037]
solver
Jonathan Westhues 2009-09-29 03:35:19 -08:00
parent 9f78ee3c33
commit db565438e3
14 changed files with 321 additions and 60 deletions

View File

@ -1148,6 +1148,7 @@ void GraphicsWindow::GroupSelection(void) {
Constraint *c = SK.GetConstraint(s->constraint);
if(c->type == Constraint::COMMENT) {
(gs.stylables)++;
(gs.comments)++;
}
}
}
@ -1226,7 +1227,7 @@ void GraphicsWindow::Paint(int w, int h) {
double mat[16];
// Last thing before display is to apply the perspective
double clp = SS.cameraTangent*scale;
double clp = SS.CameraTangent()*scale;
MakeMatrix(mat, 1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
@ -1323,6 +1324,79 @@ void GraphicsWindow::Paint(int w, int h) {
glxUnlockColor();
if(showSnapGrid && LockedInWorkplane()) {
hEntity he = ActiveWorkplane();
EntityBase *wrkpl = SK.GetEntity(he),
*norm = wrkpl->Normal();
Vector wu, wv, wn, wp;
wp = SK.GetEntity(wrkpl->point[0])->PointGetNum();
wu = norm->NormalU();
wv = norm->NormalV();
wn = norm->NormalN();
double g = SS.gridSpacing;
double umin = VERY_POSITIVE, umax = VERY_NEGATIVE,
vmin = VERY_POSITIVE, vmax = VERY_NEGATIVE;
int a;
for(a = 0; a < 4; a++) {
// Ideally, we would just do +/- half the width and height; but
// allow some extra slop for rounding.
Vector horiz = projRight.ScaledBy((0.6*width)/scale + 2*g),
vert = projUp. ScaledBy((0.6*height)/scale + 2*g);
if(a == 2 || a == 3) horiz = horiz.ScaledBy(-1);
if(a == 1 || a == 3) vert = vert. ScaledBy(-1);
Vector tp = horiz.Plus(vert).Minus(offset);
// Project the point into our grid plane, normal to the screen
// (not to the grid plane). If the plane is on edge then this is
// impossible so don't try to draw the grid.
bool parallel;
Vector tpp = Vector::AtIntersectionOfPlaneAndLine(
wn, wn.Dot(wp),
tp, tp.Plus(n),
&parallel);
if(parallel) goto nogrid;
tpp = tpp.Minus(wp);
double uu = tpp.Dot(wu),
vv = tpp.Dot(wv);
umin = min(uu, umin);
umax = max(uu, umax);
vmin = min(vv, vmin);
vmax = max(vv, vmax);
}
int i, j, i0, i1, j0, j1;
i0 = (int)(umin / g);
i1 = (int)(umax / g);
j0 = (int)(vmin / g);
j1 = (int)(vmax / g);
if(i0 > i1 || i1 - i0 > 400) goto nogrid;
if(j0 > j1 || j1 - j0 > 400) goto nogrid;
glLineWidth(1);
glxColorRGBa(Style::Color(Style::DATUM), 0.3);
glBegin(GL_LINES);
for(i = i0 + 1; i < i1; i++) {
glxVertex3v(wp.Plus(wu.ScaledBy(i*g)).Plus(wv.ScaledBy(j0*g)));
glxVertex3v(wp.Plus(wu.ScaledBy(i*g)).Plus(wv.ScaledBy(j1*g)));
}
for(j = j0 + 1; j < j1; j++) {
glxVertex3v(wp.Plus(wu.ScaledBy(i0*g)).Plus(wv.ScaledBy(j*g)));
glxVertex3v(wp.Plus(wu.ScaledBy(i1*g)).Plus(wv.ScaledBy(j*g)));
}
glEnd();
// Clear the depth buffer, so that the grid is at the very back of
// the Z order.
glClear(GL_DEPTH_BUFFER_BIT);
nogrid:;
}
// Draw the active group; this fills the polygons in a drawing group, and
// draws the solid mesh.
(SK.GetGroup(activeGroup))->Draw();

View File

@ -31,8 +31,10 @@ void Constraint::LineDrawOrGetDistance(Vector a, Vector b) {
if(dogd.sel) {
dogd.sel->AddEdge(a, b, hs.v);
} else {
if(hs.v && Style::Width(disp.style) >= 3.0) {
glxFatLine(a, b, Style::Width(disp.style) / SS.GW.scale);
// The only constraints with styles should be comments, so don't
// check otherwise, save looking up the styles constantly.
if(type == COMMENT && Style::Width(hs) >= 3.0) {
glxFatLine(a, b, Style::Width(hs) / SS.GW.scale);
} else {
glBegin(GL_LINE_STRIP);
glxVertex3v(a);
@ -95,10 +97,18 @@ void Constraint::DoLabel(Vector ref, Vector *labelPos, Vector gr, Vector gu) {
sheight = glxStrHeight(th);
// By default, the reference is from the center; but the style could
// specify otherwise if one is present.
// specify otherwise if one is present, and it could also specify a
// rotation.
if(type == COMMENT && disp.style.v) {
Style *s = Style::Get(disp.style);
int o = s->textOrigin;
Style *st = Style::Get(disp.style);
// rotation first
double rads = st->textAngle*PI/180;
double c = cos(rads), s = sin(rads);
Vector pr = gr, pu = gu;
gr = pr.ScaledBy( c).Plus(pu.ScaledBy(s));
gu = pr.ScaledBy(-s).Plus(pu.ScaledBy(c));
// then origin
int o = st->textOrigin;
if(o & Style::ORIGIN_LEFT) ref = ref.Plus(gr.WithMagnitude(swidth/2));
if(o & Style::ORIGIN_RIGHT) ref = ref.Minus(gr.WithMagnitude(swidth/2));
if(o & Style::ORIGIN_BOT) ref = ref.Plus(gu.WithMagnitude(sheight/2));
@ -378,8 +388,15 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
// If the group is hidden, then the constraints are hidden and not
// able to be selected.
if(!(g->visible)) return;
// And likewise if the group is not the active group.
if(g->h.v != SS.GW.activeGroup.v) return;
// And likewise if the group is not the active group; except for comments
// with an assigned style.
if(g->h.v != SS.GW.activeGroup.v && !(type == COMMENT && disp.style.v)) {
return;
}
if(disp.style.v) {
Style *s = Style::Get(disp.style);
if(!s->visible) return;
}
// Unit vectors that describe our current view of the scene. One pixel
// long, not one actual unit.
@ -917,13 +934,23 @@ s:
}
break;
case COMMENT:
case COMMENT: {
if(disp.style.v) {
glLineWidth(Style::Width(disp.style));
glxColorRGB(Style::Color(disp.style));
}
DoLabel(disp.offset, labelPos, gr, gu);
Vector u, v;
if(workplane.v == Entity::FREE_IN_3D.v) {
u = gr;
v = gu;
} else {
EntityBase *norm = SK.GetEntity(workplane)->Normal();
u = norm->NormalU();
v = norm->NormalV();
}
DoLabel(disp.offset, labelPos, u, v);
break;
}
default: oops();
}

View File

@ -166,7 +166,7 @@ void SolveSpace::ExportViewTo(char *filename) {
VectorFileWriter *out = VectorFileWriter::ForFile(filename);
if(out) {
ExportLinesAndMesh(&edges, &beziers, sm,
u, v, n, origin, SS.cameraTangent*SS.GW.scale,
u, v, n, origin, SS.CameraTangent()*SS.GW.scale,
out);
}
edges.Clear();

View File

@ -157,6 +157,7 @@ const SolveSpace::SaveTable SolveSpace::SAVED[] = {
{ 's', "Style.widthAs", 'd', &(SS.sv.s.widthAs) },
{ 's', "Style.textHeight", 'f', &(SS.sv.s.textHeight) },
{ 's', "Style.textHeightAs", 'd', &(SS.sv.s.textHeightAs) },
{ 's', "Style.textAngle", 'f', &(SS.sv.s.textAngle) },
{ 's', "Style.textOrigin", 'x', &(SS.sv.s.textOrigin) },
{ 's', "Style.color", 'x', &(SS.sv.s.color) },
{ 's', "Style.visible", 'b', &(SS.sv.s.visible) },

View File

@ -32,9 +32,9 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
{ 1, "&Redo\tCtrl+Y", MNU_REDO, 'Y'|C, mEdit },
{ 1, "Re&generate All\tSpace", MNU_REGEN_ALL, ' ', mEdit },
{ 1, NULL, 0, NULL },
{ 1, "Snap Selection to &Grid\t.", MNU_SNAP_TO_GRID, '.', mEdit },
{ 1, "Rotate Imported &90°\t9", MNU_ROTATE_90, '9', mEdit },
{ 1, "&Delete\tDel", MNU_DELETE, 127, mEdit },
{ 1, NULL, 0, NULL },
{ 1, "&Unselect All\tEsc", MNU_UNSELECT_ALL, 27, mEdit },
@ -43,6 +43,9 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
{ 1, "Zoom &Out\t-", MNU_ZOOM_OUT, '-', mView },
{ 1, "Zoom To &Fit\tF", MNU_ZOOM_TO_FIT, 'F', mView },
{ 1, NULL, 0, NULL },
{ 1, "Show Snap &Grid\t>", MNU_SHOW_GRID, '.'|S, mView },
{ 1, "Force &Parallel Projection\t`", MNU_PARALLEL_PROJ, '`', mView },
{ 1, NULL, 0, NULL },
{ 1, "Nearest &Ortho View\tF2", MNU_NEAREST_ORTHO, F(2), mView },
{ 1, "Nearest &Isometric View\tF3", MNU_NEAREST_ISO, F(3), mView },
{ 1, "&Center View At Point\tF4", MNU_CENTER_VIEW, F(4), mView },
@ -154,6 +157,7 @@ void GraphicsWindow::Init(void) {
showTextWindow = true;
ShowTextWindow(showTextWindow);
showSnapGrid = false;
context.active = false;
// Do this last, so that all the menus get updated correctly.
@ -199,7 +203,7 @@ Vector GraphicsWindow::ProjectPoint4(Vector p, double *w) {
r.y = p.Dot(projUp);
r.z = p.Dot(projUp.Cross(projRight));
*w = 1 + r.z*SS.cameraTangent*scale;
*w = 1 + r.z*SS.CameraTangent()*scale;
return r;
}
@ -230,6 +234,10 @@ void GraphicsWindow::AnimateOnto(Quaternion quatf, Vector offsetf) {
// Animate transition, unless it's a tiny move.
SDWORD dt = (mp < 0.01 && mo < 10) ? (-20) :
(SDWORD)(100 + 1000*mp + 0.4*mo);
// Don't ever animate for longer than 2000 ms; we can get absurdly
// long translations (as measured in pixels) if the user zooms out, moves,
// and then zooms in again.
if(dt > 2000) dt = 2000;
SDWORD tn, t0 = GetMilliseconds();
double s = 0;
Quaternion dq = quatf.Times(quat0.Inverse());
@ -347,7 +355,7 @@ void GraphicsWindow::ZoomToFit(bool includingInvisibles) {
// Adjust the scale so that no points are behind the camera
if(wmin < 0.1) {
double k = SS.cameraTangent;
double k = SS.CameraTangent();
// w = 1+k*scale*z
double zmin = (wmin - 1)/(k*scale);
// 0.1 = 1 + k*scale*zmin
@ -370,6 +378,29 @@ void GraphicsWindow::MenuView(int id) {
SS.GW.ZoomToFit(false);
break;
case MNU_SHOW_GRID:
SS.GW.showSnapGrid = !SS.GW.showSnapGrid;
if(SS.GW.showSnapGrid && !SS.GW.LockedInWorkplane()) {
Message("No workplane is active, so the grid will not "
"appear.");
}
SS.GW.EnsureValidActives();
InvalidateGraphics();
break;
case MNU_PARALLEL_PROJ:
SS.forceParallelProj = !SS.forceParallelProj;
if(SS.cameraTangent < 1e-6) {
Error("The perspective factor is set to zero, so the view will "
"always be a parallel projection.\r\n\r\n"
"For a perspective projection, modify the camera tangent "
"in the configuration screen. A value around 0.3 is "
"typical.");
}
SS.GW.EnsureValidActives();
InvalidateGraphics();
break;
case MNU_NEAREST_ORTHO:
case MNU_NEAREST_ISO: {
static const Vector ortho[3] = {
@ -448,7 +479,7 @@ void GraphicsWindow::MenuView(int id) {
case MNU_SHOW_TOOLBAR:
SS.showToolbar = !SS.showToolbar;
SS.GW.EnsureValidActives();
PaintGraphics();
InvalidateGraphics();
break;
case MNU_UNITS_MM:
@ -532,6 +563,8 @@ void GraphicsWindow::EnsureValidActives(void) {
CheckMenuById(MNU_SHOW_TEXT_WND, SS.GW.showTextWindow);
CheckMenuById(MNU_SHOW_TOOLBAR, SS.showToolbar);
CheckMenuById(MNU_PARALLEL_PROJ, SS.forceParallelProj);
CheckMenuById(MNU_SHOW_GRID, SS.GW.showSnapGrid);
if(change) SS.later.showTW = true;
}
@ -583,6 +616,24 @@ void GraphicsWindow::DeleteTaggedRequests(void) {
SS.later.showTW = true;
}
Vector GraphicsWindow::SnapToGrid(Vector p) {
if(!LockedInWorkplane()) return p;
EntityBase *wrkpl = SK.GetEntity(ActiveWorkplane()),
*norm = wrkpl->Normal();
Vector wo = SK.GetEntity(wrkpl->point[0])->PointGetNum(),
wu = norm->NormalU(),
wv = norm->NormalV(),
wn = norm->NormalN();
Vector pp = (p.Minus(wo)).DotInToCsys(wu, wv, wn);
pp.x = floor((pp.x / SS.gridSpacing) + 0.5)*SS.gridSpacing;
pp.y = floor((pp.y / SS.gridSpacing) + 0.5)*SS.gridSpacing;
pp.z = 0;
return pp.ScaleOutOfCsys(wu, wv, wn).Plus(wo);
}
void GraphicsWindow::MenuEdit(int id) {
switch(id) {
case MNU_UNSELECT_ALL:
@ -590,7 +641,10 @@ void GraphicsWindow::MenuEdit(int id) {
// If there's nothing selected to de-select, and no operation
// to cancel, then perhaps they want to return to the home
// screen in the text window.
if(SS.GW.gs.n == 0 && SS.GW.pending.operation == 0) {
if(SS.GW.gs.n == 0 &&
SS.GW.gs.constraints == 0 &&
SS.GW.pending.operation == 0)
{
if(!(TextEditControlIsVisible() ||
GraphicsEditControlIsVisible()))
{
@ -667,6 +721,46 @@ void GraphicsWindow::MenuEdit(int id) {
break;
}
case MNU_SNAP_TO_GRID: {
if(!SS.GW.LockedInWorkplane()) {
Error("No workplane is active. Select a workplane to define "
"the plane for the snap grid.");
break;
}
SS.GW.GroupSelection();
if(SS.GW.gs.n != SS.GW.gs.points ||
SS.GW.gs.constraints != SS.GW.gs.comments ||
(SS.GW.gs.n == 0 && SS.GW.gs.constraints == 0))
{
Error("Can't snap these items to grid; select only points or "
"text comments. To snap a line, select its endpoints.");
break;
}
SS.UndoRemember();
int i;
for(i = 0; i < SS.GW.gs.points; i++) {
hEntity hp = SS.GW.gs.point[i];
Entity *ep = SK.GetEntity(hp);
Vector p = ep->PointGetNum();
ep->PointForceTo(SS.GW.SnapToGrid(p));
// Regenerate, with this point marked as dragged so that it
// gets placed as close as possible to our snap
SS.GW.pending.point = hp;
SS.MarkGroupDirty(ep->group);
SS.GenerateAll();
SS.GW.pending.point = Entity::NO_ENTITY;
}
for(i = 0; i < SS.GW.gs.constraints; i++) {
Constraint *c = SK.GetConstraint(SS.GW.gs.constraint[i]);
c->disp.offset = SS.GW.SnapToGrid(c->disp.offset);
}
SS.GW.ClearSelection();
InvalidateGraphics();
break;
}
case MNU_UNDO:
SS.UndoUndo();
break;
@ -715,6 +809,7 @@ void GraphicsWindow::MenuRequest(int id) {
SS.GW.SetWorkplaneFreeIn3d();
SS.GW.EnsureValidActives();
SS.later.showTW = true;
InvalidateGraphics();
break;
case MNU_ARC: {

View File

@ -635,6 +635,7 @@ public:
static const int ORIGIN_BOT = 0x04;
static const int ORIGIN_TOP = 0x08;
int textOrigin;
double textAngle;
DWORD color;
bool visible;
bool exportable;

View File

@ -64,6 +64,8 @@ void SolveSpace::Init(char *cmdLine) {
viewUnits = (Unit)CnfThawDWORD((DWORD)UNIT_MM, "ViewUnits");
// Camera tangent (determines perspective)
cameraTangent = CnfThawFloat(0.0f, "CameraTangent");
// Grid spacing
gridSpacing = CnfThawFloat(5.0f, "GridSpacing");
// Export scale factor
exportScale = CnfThawFloat(1.0f, "ExportScale");
// Export offset (cutter radius comp)
@ -150,6 +152,8 @@ void SolveSpace::Exit(void) {
CnfFreezeDWORD((DWORD)viewUnits, "ViewUnits");
// Camera tangent (determines perspective)
CnfFreezeFloat((float)cameraTangent, "CameraTangent");
// Grid spacing
CnfFreezeFloat(gridSpacing, "GridSpacing");
// Export scale (a float, stored as a DWORD)
CnfFreezeFloat(exportScale, "ExportScale");
// Export offset (cutter radius comp)
@ -191,25 +195,6 @@ void SolveSpace::DoLater(void) {
ZERO(&later);
}
int SolveSpace::CircleSides(double r) {
// Let the pwl segment be symmetric about the x axis; then the curve
// goes out to r, and if there's n segments, then the endpoints are
// at +/- (2pi/n)/2 = +/- pi/n. So the chord goes to x = r cos pi/n,
// from x = r, so it's
// tol = r - r cos pi/n
// tol = r(1 - cos pi/n)
// tol ~ r(1 - (1 - (pi/n)^2/2)) (Taylor expansion)
// tol = r((pi/n)^2/2)
// 2*tol/r = (pi/n)^2
// sqrt(2*tol/r) = pi/n
// n = pi/sqrt(2*tol/r);
double tol = chordTol/GW.scale;
int n = 3 + (int)(PI/sqrt(2*tol/r));
return max(7, min(n, maxSegments));
}
char *SolveSpace::MmToString(double v) {
static int WhichBuf;
static char Bufs[8][128];
@ -243,6 +228,13 @@ double SolveSpace::ChordTolMm(void) {
return SS.chordTol / SS.GW.scale;
}
double SolveSpace::CameraTangent(void) {
if(forceParallelProj) {
return 0;
} else {
return cameraTangent;
}
}
void SolveSpace::AfterNewFile(void) {
// Clear out the traced point, which is no longer valid

View File

@ -547,6 +547,7 @@ public:
double chordTol;
int maxSegments;
double cameraTangent;
float gridSpacing;
float exportScale;
float exportOffset;
int fixExportColors;
@ -569,7 +570,6 @@ public:
float dy;
} exportCanvas;
int CircleSides(double r);
typedef enum {
UNIT_MM = 0,
UNIT_INCHES,
@ -579,6 +579,8 @@ public:
double ExprToMm(Expr *e);
double StringToMm(char *s);
double ChordTolMm(void);
bool forceParallelProj;
double CameraTangent(void);
// The platform-dependent code calls this before entering the msg loop
void Init(char *cmdLine);

View File

@ -73,6 +73,8 @@ void Style::CreateDefaultStyle(hStyle h) {
ns.widthAs = UNITS_AS_PIXELS;
ns.textHeight = DEFAULT_TEXT_HEIGHT;
ns.textHeightAs = UNITS_AS_PIXELS;
ns.textOrigin = 0;
ns.textAngle = 0;
ns.visible = true;
ns.exportable = true;
ns.h = h;
@ -95,6 +97,8 @@ void Style::LoadFactoryDefaults(void) {
s->widthAs = UNITS_AS_PIXELS;
s->textHeight = DEFAULT_TEXT_HEIGHT;
s->textHeightAs = UNITS_AS_PIXELS;
s->textOrigin = 0;
s->textAngle = 0;
s->visible = true;
s->exportable = true;
s->name.strcpy(CnfPrefixToName(d->cnfPrefix));
@ -375,8 +379,8 @@ void TextWindow::ScreenDeleteStyle(int link, DWORD v) {
void TextWindow::ScreenChangeStyleWidthOrTextHeight(int link, DWORD v) {
hStyle hs = { v };
Style *s = Style::Get(hs);
double val = (link == 'w') ? s->width : s->textHeight;
int units = (link == 'w') ? s->widthAs : s->textHeightAs;
double val = (link == 't') ? s->textHeight : s->width;
int units = (link == 't') ? s->textHeightAs : s->widthAs;
char str[300];
if(units == Style::UNITS_AS_PIXELS) {
@ -384,10 +388,28 @@ void TextWindow::ScreenChangeStyleWidthOrTextHeight(int link, DWORD v) {
} else {
strcpy(str, SS.MmToString(val));
}
ShowTextEditControl((link == 'w') ? 21 : 26, 13, str);
int row = 0;
if(link == 'w') {
row = 16; // width for a default style
} else if(link == 'W') {
row = 21; // width for a custom style
} else if(link == 't') {
row = 27; // text height (for custom styles only)
}
ShowTextEditControl(row, 13, str);
SS.TW.edit.style = hs;
SS.TW.edit.meaning = (link == 'w') ? EDIT_STYLE_WIDTH :
EDIT_STYLE_TEXT_HEIGHT;
SS.TW.edit.meaning = (link == 't') ? EDIT_STYLE_TEXT_HEIGHT :
EDIT_STYLE_WIDTH;
}
void TextWindow::ScreenChangeStyleTextAngle(int link, DWORD v) {
hStyle hs = { v };
Style *s = Style::Get(hs);
char str[300];
sprintf(str, "%.2f", s->textAngle);
ShowTextEditControl(32, 13, str);
SS.TW.edit.style = hs;
SS.TW.edit.meaning = EDIT_STYLE_TEXT_ANGLE;
}
void TextWindow::ScreenChangeStyleColor(int link, DWORD v) {
@ -491,6 +513,12 @@ bool TextWindow::EditControlDoneForStyles(char *str) {
}
return true;
}
case EDIT_STYLE_TEXT_ANGLE:
SS.UndoRemember();
s = Style::Get(edit.style);
s->textAngle = WRAP_SYMMETRIC(atof(str), 360);
return true;
case EDIT_BACKGROUND_COLOR:
case EDIT_STYLE_COLOR: {
double r, g, b;
@ -565,13 +593,15 @@ void TextWindow::ShowStyleInfo(void) {
// The line width, and its units
if(s->widthAs == Style::UNITS_AS_PIXELS) {
Printf(true, "%FtLINE WIDTH %E%@ %D%f%Lw%Fl[change]%E",
Printf(true, "%FtLINE WIDTH %E%@ %D%f%Lp%Fl[change]%E",
s->width,
s->h.v, &ScreenChangeStyleWidthOrTextHeight);
s->h.v, &ScreenChangeStyleWidthOrTextHeight,
(s->h.v < Style::FIRST_CUSTOM) ? 'w' : 'W');
} else {
Printf(true, "%FtLINE WIDTH %E%s %D%f%Lw%Fl[change]%E",
Printf(true, "%FtLINE WIDTH %E%s %D%f%Lp%Fl[change]%E",
SS.MmToString(s->width),
s->h.v, &ScreenChangeStyleWidthOrTextHeight);
s->h.v, &ScreenChangeStyleWidthOrTextHeight,
(s->h.v < Style::FIRST_CUSTOM) ? 'w' : 'W');
}
bool widthpx = (s->widthAs == Style::UNITS_AS_PIXELS);
@ -589,14 +619,15 @@ void TextWindow::ShowStyleInfo(void) {
}
// The text height, and its units
Printf(false, "");
char *chng = (s->h.v < Style::FIRST_CUSTOM) ? "" : "[change]";
if(s->textHeightAs == Style::UNITS_AS_PIXELS) {
Printf(true, "%FtTEXT HEIGHT %E%@ %D%f%Lt%Fl%s%E",
Printf(false, "%FtTEXT HEIGHT %E%@ %D%f%Lt%Fl%s%E",
s->textHeight,
s->h.v, &ScreenChangeStyleWidthOrTextHeight,
chng);
} else {
Printf(true, "%FtTEXT HEIGHT %E%s %D%f%Lt%Fl%s%E",
Printf(false, "%FtTEXT HEIGHT %E%s %D%f%Lt%Fl%s%E",
SS.MmToString(s->textHeight),
s->h.v, &ScreenChangeStyleWidthOrTextHeight,
chng);
@ -619,6 +650,10 @@ void TextWindow::ShowStyleInfo(void) {
if(s->h.v >= Style::FIRST_CUSTOM) {
bool neither;
Printf(true, "%FtTEXT ANGLE %E%@ %D%f%Ll%Fl[change]%E",
s->textAngle,
s->h.v, &ScreenChangeStyleTextAngle);
neither = !(s->textOrigin & (Style::ORIGIN_LEFT | Style::ORIGIN_RIGHT));
Printf(true, "%FtALIGN TEXT "
"%Fh%D%f%LL%s%E%Fs%s%E / "

View File

@ -273,7 +273,7 @@ void TextWindow::ScreenChangeHelixParameter(int link, DWORD v) {
sprintf(str, "%.3f", g->valA);
SS.TW.edit.meaning = EDIT_HELIX_TURNS;
r = 12;
} else if(link == 'p') {
} else if(link == 'i') {
strcpy(str, SS.MmToString(g->valB));
SS.TW.edit.meaning = EDIT_HELIX_PITCH;
r = 14;
@ -383,7 +383,7 @@ void TextWindow::ShowGroupInfo(void) {
(!rh ? "" : "left-hand"), (!rh ? "left-hand" : ""));
Printf(false, "%FtTHROUGH%E %@ turns %Fl%Lt%D%f[change]%E",
g->valA, g->h.v, &ScreenChangeHelixParameter);
Printf(false, "%FtPITCH%E %s axially per turn %Fl%Lp%D%f[change]%E",
Printf(false, "%FtPITCH%E %s axially per turn %Fl%Li%D%f[change]%E",
SS.MmToString(g->valB), g->h.v, &ScreenChangeHelixParameter);
Printf(false, "%FtdRADIUS%E %s radially per turn %Fl%Lr%D%f[change]%E",
SS.MmToString(g->valC), g->h.v, &ScreenChangeHelixParameter);
@ -625,15 +625,19 @@ void TextWindow::ScreenChangeCameraTangent(int link, DWORD v) {
ShowTextEditControl(47, 3, str);
SS.TW.edit.meaning = EDIT_CAMERA_TANGENT;
}
void TextWindow::ScreenChangeGridSpacing(int link, DWORD v) {
ShowTextEditControl(51, 3, SS.MmToString(SS.gridSpacing));
SS.TW.edit.meaning = EDIT_GRID_SPACING;
}
void TextWindow::ScreenChangeExportScale(int link, DWORD v) {
char str[1024];
sprintf(str, "%.3f", (double)SS.exportScale);
ShowTextEditControl(53, 3, str);
ShowTextEditControl(57, 3, str);
SS.TW.edit.meaning = EDIT_EXPORT_SCALE;
}
void TextWindow::ScreenChangeExportOffset(int link, DWORD v) {
ShowTextEditControl(57, 3, SS.MmToString(SS.exportOffset));
ShowTextEditControl(61, 3, SS.MmToString(SS.exportOffset));
SS.TW.edit.meaning = EDIT_EXPORT_OFFSET;
}
void TextWindow::ScreenChangeFixExportColors(int link, DWORD v) {
@ -670,7 +674,7 @@ void TextWindow::ScreenChangeCanvasSize(int link, DWORD v) {
default: return;
}
int row = 71, col;
int row = 75, col;
if(v < 10) {
row += v*2;
col = 11;
@ -723,6 +727,10 @@ void TextWindow::ShowConfiguration(void) {
Printf(false, "%Ba %3 %Fl%Ll%f%D[change]%E",
SS.cameraTangent*1000,
&ScreenChangeCameraTangent, 0);
Printf(false, "%Ft snap grid spacing%E");
Printf(false, "%Ba %s %Fl%Ll%f%D[change]%E",
SS.MmToString(SS.gridSpacing),
&ScreenChangeGridSpacing, 0);
Printf(false, "");
Printf(false, "%Ft export scale factor (1.0=mm, 25.4=inch)");
@ -984,6 +992,15 @@ void TextWindow::EditControlDone(char *s) {
}
case EDIT_CAMERA_TANGENT: {
SS.cameraTangent = (min(2, max(0, atof(s))))/1000.0;
if(SS.forceParallelProj) {
Message("The perspective factor will have no effect until you "
"disable View -> Force Parallel Projection.");
}
InvalidateGraphics();
break;
}
case EDIT_GRID_SPACING: {
SS.gridSpacing = (float)min(1e4, max(1e-3, SS.StringToMm(s)));
InvalidateGraphics();
break;
}

View File

@ -144,7 +144,11 @@ void TextWindow::Printf(bool halfLine, char *fmt, ...) {
case 'L':
if(fmt[1] == '\0') goto done;
fmt++;
if(*fmt == 'p') {
link = va_arg(vl, int);
} else {
link = *fmt;
}
break;
case 'f':

23
ui.h
View File

@ -80,9 +80,10 @@ public:
static const int EDIT_CHORD_TOLERANCE = 13;
static const int EDIT_MAX_SEGMENTS = 14;
static const int EDIT_CAMERA_TANGENT = 15;
static const int EDIT_EXPORT_SCALE = 16;
static const int EDIT_EXPORT_OFFSET = 17;
static const int EDIT_CANVAS_SIZE = 18;
static const int EDIT_GRID_SPACING = 16;
static const int EDIT_EXPORT_SCALE = 17;
static const int EDIT_EXPORT_OFFSET = 18;
static const int EDIT_CANVAS_SIZE = 19;
// For the helical sweep
static const int EDIT_HELIX_TURNS = 20;
static const int EDIT_HELIX_PITCH = 21;
@ -95,9 +96,10 @@ public:
// For the styles stuff
static const int EDIT_STYLE_WIDTH = 50;
static const int EDIT_STYLE_TEXT_HEIGHT = 51;
static const int EDIT_STYLE_COLOR = 52;
static const int EDIT_STYLE_NAME = 53;
static const int EDIT_BACKGROUND_COLOR = 54;
static const int EDIT_STYLE_TEXT_ANGLE = 52;
static const int EDIT_STYLE_COLOR = 53;
static const int EDIT_STYLE_NAME = 54;
static const int EDIT_BACKGROUND_COLOR = 55;
struct {
int meaning;
int i;
@ -187,10 +189,12 @@ public:
static void ScreenChangeChordTolerance(int link, DWORD v);
static void ScreenChangeMaxSegments(int link, DWORD v);
static void ScreenChangeCameraTangent(int link, DWORD v);
static void ScreenChangeGridSpacing(int link, DWORD v);
static void ScreenChangeExportScale(int link, DWORD v);
static void ScreenChangeExportOffset(int link, DWORD v);
static void ScreenChangeStyleName(int link, DWORD v);
static void ScreenChangeStyleWidthOrTextHeight(int link, DWORD v);
static void ScreenChangeStyleTextAngle(int link, DWORD v);
static void ScreenChangeStyleColor(int link, DWORD v);
static void ScreenChangeBackgroundColor(int link, DWORD v);
@ -220,6 +224,8 @@ public:
MNU_ZOOM_IN,
MNU_ZOOM_OUT,
MNU_ZOOM_TO_FIT,
MNU_SHOW_GRID,
MNU_PARALLEL_PROJ,
MNU_NEAREST_ORTHO,
MNU_NEAREST_ISO,
MNU_CENTER_VIEW,
@ -231,6 +237,7 @@ public:
MNU_UNDO,
MNU_REDO,
MNU_DELETE,
MNU_SNAP_TO_GRID,
MNU_ROTATE_90,
MNU_UNSELECT_ALL,
MNU_REGEN_ALL,
@ -373,6 +380,7 @@ public:
// The constraint that is being edited with the on-screen textbox.
hConstraint constraintBeingEdited;
Vector SnapToGrid(Vector p);
bool ConstrainPointByHovered(hEntity pt);
void DeleteTaggedRequests(void);
hRequest AddRequest(int type, bool rememberForUndo);
@ -428,6 +436,7 @@ public:
int vectors;
int constraints;
int stylables;
int comments;
int n;
} gs;
void GroupSelection(void);
@ -469,6 +478,8 @@ public:
bool showHdnLines;
static void ToggleBool(int link, DWORD v);
bool showSnapGrid;
void UpdateDraggedNum(Vector *pos, double mx, double my);
void UpdateDraggedPoint(hEntity hp, double mx, double my);

View File

@ -539,9 +539,11 @@ static BOOL ProcessKeyDown(WPARAM wParam)
case VK_OEM_MINUS: c = '-'; break;
case VK_ESCAPE: c = 27; break;
case VK_OEM_1: c = ';'; break;
case VK_OEM_3: c = '`'; break;
case VK_OEM_4: c = '['; break;
case VK_OEM_6: c = ']'; break;
case VK_OEM_5: c = '\\'; break;
case VK_OEM_PERIOD: c = '.'; break;
case VK_SPACE: c = ' '; break;
case VK_DELETE: c = 127; break;
case VK_TAB: c = '\t'; break;

View File

@ -1,5 +1,5 @@
grid
split draw.cpp
multi-drag
-----