From 2cb4800fbf255fe450f8c8597b4a8e33806563ed Mon Sep 17 00:00:00 2001 From: Jonathan Westhues Date: Sat, 31 May 2008 16:26:41 -0800 Subject: [PATCH] Start to describe the selected entities in the text window. Also more starting work on the selectable faces, and fiddling in an attempt to remove dependencies when stuff gets deleted. [git-p4: depot-paths = "//depot/solvespace/": change = 1760] --- constraint.cpp | 29 ++++++++- file.cpp | 3 + graphicswin.cpp | 44 +++++++++++--- sketch.cpp | 20 ++++++ sketch.h | 7 +++ solvespace.cpp | 14 +++-- textwin.cpp | 158 +++++++++++++++++++++++++++++++++++++++++++++--- ui.h | 10 ++- 8 files changed, 257 insertions(+), 28 deletions(-) diff --git a/constraint.cpp b/constraint.cpp index 1ed47d79..5848f2fd 100644 --- a/constraint.cpp +++ b/constraint.cpp @@ -4,7 +4,34 @@ const hConstraint Constraint::NO_CONSTRAINT = { 0 }; char *Constraint::DescriptionString(void) { static char ret[1024]; - sprintf(ret, "c%03x", h.v); + + char *s; + switch(type) { + case POINTS_COINCIDENT: s = "pts-coincident"; break; + case PT_PT_DISTANCE: s = "pt-pt-distance"; break; + case PT_LINE_DISTANCE: s = "pt-line-distance"; break; + case PT_PLANE_DISTANCE: s = "pt-plane-distance"; break; + case PT_IN_PLANE: s = "pt-in-plane"; break; + case PT_ON_LINE: s = "pt-on-line"; break; + case PT_ON_FACE: s = "pt-on-face"; break; + case EQUAL_LENGTH_LINES:s = "eq-length"; break; + case LENGTH_RATIO: s = "length-ratio"; break; + case SYMMETRIC: s = "symmetric"; break; + case SYMMETRIC_HORIZ: s = "symmetric-h"; break; + case SYMMETRIC_VERT: s = "symmetric-v"; break; + case AT_MIDPOINT: s = "at-midpoint"; break; + case HORIZONTAL: s = "horizontal"; break; + case VERTICAL: s = "vertical"; break; + case DIAMETER: s = "diameter"; break; + case PT_ON_CIRCLE: s = "pt-on-circle"; break; + case SAME_ORIENTATION: s = "same-orientation"; break; + case ANGLE: s = "angle"; break; + case PARALLEL: s = "parallel"; break; + case EQUAL_RADIUS: s = "eq-radius"; break; + default: s = "???"; break; + } + + sprintf(ret, "c%03x-%s", h.v, s); return ret; } diff --git a/file.cpp b/file.cpp index c1aebd20..2339fe5d 100644 --- a/file.cpp +++ b/file.cpp @@ -224,6 +224,9 @@ bool SolveSpace::SaveToFile(char *filename) { SMesh *m = &(group.elem[group.n-1].mesh); for(i = 0; i < m->l.n; i++) { STriangle *tr = &(m->l.elem[i]); +/* + double mag = tr->Normal().Magnitude(); + dbp("triangle: mag=%.5f", mag); */ fprintf(fh, "Triangle %08x %08x " "%.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f\n", tr->meta.face, tr->meta.color, diff --git a/graphicswin.cpp b/graphicswin.cpp index ce365c86..603e8906 100644 --- a/graphicswin.cpp +++ b/graphicswin.cpp @@ -220,6 +220,21 @@ void GraphicsWindow::MenuView(int id) { InvalidateGraphics(); } +char *GraphicsWindow::ToString(double v) { + static int WhichBuf; + static char Bufs[8][128]; + + WhichBuf++; + if(WhichBuf >= 8 || WhichBuf < 0) WhichBuf = 0; + + char *s = Bufs[WhichBuf]; + sprintf(s, "%.3f", v); + return s; +} +double GraphicsWindow::FromString(char *s) { + return atof(s); +} + void GraphicsWindow::EnsureValidActives(void) { bool change = false; // The active group must exist, and not be the references. @@ -280,7 +295,12 @@ void GraphicsWindow::SetWorkplaneFreeIn3d(void) { SS.GetGroup(activeGroup)->activeWorkplane = Entity::FREE_IN_3D; } hEntity GraphicsWindow::ActiveWorkplane(void) { - return SS.GetGroup(activeGroup)->activeWorkplane; + Group *g = SS.group.FindByIdNoOops(activeGroup); + if(g) { + return g->activeWorkplane; + } else { + return Entity::FREE_IN_3D; + } } bool GraphicsWindow::LockedInWorkplane(void) { return (SS.GW.ActiveWorkplane().v != Entity::FREE_IN_3D.v); @@ -293,12 +313,8 @@ void GraphicsWindow::GeneratePerSolving(void) { void GraphicsWindow::MenuEdit(int id) { switch(id) { case MNU_UNSELECT_ALL: - HideGraphicsEditControl(); + SS.GW.ClearSuper(); HideTextEditControl(); - SS.GW.ClearSelection(); - SS.GW.ClearPending(); - SS.TW.ScreenNavigation('h', 0); - SS.TW.Show(); break; case MNU_DELETE: { @@ -321,10 +337,12 @@ void GraphicsWindow::MenuEdit(int id) { SS.request.RemoveTagged(); SS.constraint.RemoveTagged(); - // Forget any mention of the just-deleted entity - SS.GW.ClearSuper(); + // An edit might be in progress for the just-deleted item. So + // now it's not. HideGraphicsEditControl(); HideTextEditControl(); + // And clear out the selection, which could contain that item. + SS.GW.ClearSuper(); // 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); @@ -488,8 +506,12 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown, pending.operation = DRAGGING_CONSTRAINT; } } else { - // Otherwise, just hit test and give up - HitTestMakeSelection(mp); + // Otherwise, just hit test and give up; but don't hit test + // if the mouse is down, because then the user could hover + // a point, mouse down (thus selecting it), and drag, in an + // effort to drag the point, but instead hover a different + // entity before we move far enough to start the drag. + if(!leftDown) HitTestMakeSelection(mp); } return; } @@ -678,6 +700,7 @@ void GraphicsWindow::Selection::Draw(void) { } void GraphicsWindow::ClearSuper(void) { + HideGraphicsEditControl(); ClearPending(); ClearSelection(); hover.Clear(); @@ -728,6 +751,7 @@ void GraphicsWindow::ClearSelection(void) { for(int i = 0; i < MAX_SELECTED; i++) { selection[i].Clear(); } + SS.TW.Show(); InvalidateGraphics(); } diff --git a/sketch.cpp b/sketch.cpp index d4e6ad89..212851dc 100644 --- a/sketch.cpp +++ b/sketch.cpp @@ -465,6 +465,24 @@ SMesh *Group::PreviousGroupMesh(void) { return &(SS.group.elem[i-1].mesh); } +void Group::TagEdgesFromLineSegments(SEdgeList *el) { + int i, j; + for(i = 0; i < SS.entity.n; i++) { + Entity *e = &(SS.entity.elem[i]); + if(e->group.v != opA.v) continue; + if(e->type != Entity::LINE_SEGMENT) continue; + + Vector p0 = SS.GetEntity(e->point[0])->PointGetNum(); + Vector p1 = SS.GetEntity(e->point[1])->PointGetNum(); + + for(j = 0; j < el->l.n; j++) { + SEdge *se = &(el->l.elem[j]); + if((p0.Equals(se->a) && p1.Equals(se->b))) se->tag = 1; + if((p0.Equals(se->b) && p1.Equals(se->a))) se->tag = 1; + } + } +} + void Group::MakePolygons(void) { poly.Clear(); @@ -544,6 +562,8 @@ void Group::MakePolygons(void) { edges.Clear(); (src->poly).MakeEdgesInto(&edges); + edges.l.ClearTags(); + TagEdgesFromLineSegments(&edges); // The sides; these are quads, represented as two triangles. for(i = 0; i < edges.l.n; i++) { SEdge *edge = &(edges.l.elem[i]); diff --git a/sketch.h b/sketch.h index 1a730c2a..58cb62e2 100644 --- a/sketch.h +++ b/sketch.h @@ -146,6 +146,7 @@ public: // mapping list. hEntity Remap(hEntity in, int copyNumber); void MakeExtrusionLines(hEntity in, int ai, int af); + void TagEdgesFromLineSegments(SEdgeList *sle); void CopyEntity(Entity *ep, int a, hParam dx, hParam dy, hParam dz, hParam qw, hParam qvx, hParam qvy, hParam qvz, bool transOnly); @@ -225,6 +226,11 @@ public: static const int DISTANCE = 4000; static const int DISTANCE_N_COPY = 4001; + static const int FACE_N_COPY = 5000; + static const int FACE_N_TRANS = 5001; + static const int FACE_N_XPROD = 5002; + + static const int WORKPLANE = 10000; static const int LINE_SEGMENT = 11000; static const int CUBIC = 12000; @@ -369,6 +375,7 @@ public: static const int PT_PLANE_DISTANCE = 32; static const int PT_IN_PLANE = 40; static const int PT_ON_LINE = 41; + static const int PT_ON_FACE = 42; static const int EQUAL_LENGTH_LINES = 50; static const int LENGTH_RATIO = 51; static const int SYMMETRIC = 60; diff --git a/solvespace.cpp b/solvespace.cpp index 4a1e1dec..40dc0c72 100644 --- a/solvespace.cpp +++ b/solvespace.cpp @@ -221,6 +221,14 @@ void SolveSpace::GenerateAll(bool andSolve, int first, int last) { GW.ClearNonexistentSelectionItems(); if(deleted.requests > 0 || deleted.constraints > 0 || deleted.groups > 0) { + // All sorts of interesting things could have happened; for example, + // the active group or active workplane could have been deleted. So + // clear all that out. + if(deleted.groups > 0) { + SS.TW.ClearSuper(); + } + TW.Show(); + GW.ClearSuper(); // Don't display any errors until we've regenerated fully. The // sketch is not necessarily in a consistent state until we've // pruned any orphaned etc. objects, and the message loop for the @@ -237,12 +245,6 @@ void SolveSpace::GenerateAll(bool andSolve, int first, int last) { deleted.constraints, deleted.constraints == 1 ? "" : "s", deleted.groups, deleted.groups == 1 ? "" : "s"); memset(&deleted, 0, sizeof(deleted)); - // All sorts of interesting things could have happened; for example, - // the active group or active workplane could have been deleted. So - // clear all that out. - GW.ClearSuper(); - HideGraphicsEditControl(); - HideTextEditControl(); } return; diff --git a/textwin.cpp b/textwin.cpp index babb1b25..f87757f2 100644 --- a/textwin.cpp +++ b/textwin.cpp @@ -10,6 +10,7 @@ const TextWindow::Color TextWindow::fgColors[] = { { 'm', RGB(200, 200, 0) }, { 'r', RGB( 0, 0, 0) }, { 'x', RGB(255, 20, 20) }, + { 'i', RGB( 0, 255, 255) }, { 0, 0 }, }; const TextWindow::Color TextWindow::bgColors[] = { @@ -21,8 +22,15 @@ const TextWindow::Color TextWindow::bgColors[] = { }; void TextWindow::Init(void) { + ClearSuper(); +} + +void TextWindow::ClearSuper(void) { + HideTextEditControl(); memset(this, 0, sizeof(*this)); shown = &(showns[shownIndex]); + ClearScreen(); + Show(); // Default list of colors for the model material modelColor[0] = RGB(150, 150, 150); @@ -33,8 +41,6 @@ void TextWindow::Init(void) { modelColor[5] = RGB( 0, 80, 80); modelColor[6] = RGB( 0, 0, 150); modelColor[7] = RGB( 80, 0, 80); - - ClearScreen(); } void TextWindow::ClearScreen(void) { @@ -91,11 +97,21 @@ void TextWindow::Printf(bool halfLine, char *fmt, ...) { sprintf(buf, "%08x", v); break; } + case '3': { + double v = va_arg(vl, double); + sprintf(buf, "%s%.3f", v < 0 ? "" : " ", v); + break; + } case 's': { char *s = va_arg(vl, char *); memcpy(buf, s, min(sizeof(buf), strlen(s)+1)); break; } + case 'c': { + char v = va_arg(vl, char); + sprintf(buf, "%c", v); + break; + } case 'E': fg = 'd'; // leave the background, though @@ -176,20 +192,23 @@ done: va_end(vl); } +#define gs (SS.GW.gs) void TextWindow::Show(void) { if(!(SS.GW.pending.operation)) SS.GW.ClearPending(); SS.GW.GroupSelection(); -#define gs (SS.GW.gs) - - ShowHeader(); if(SS.GW.pending.description) { // A pending operation (that must be completed with the mouse in // the graphics window) will preempt our usual display. + ShowHeader(false); Printf(false, ""); Printf(false, "%s", SS.GW.pending.description); + } else if(gs.n > 0) { + ShowHeader(false); + DescribeSelection(); } else { + ShowHeader(true); switch(shown->screen) { default: shown->screen = SCREEN_LIST_OF_GROUPS; @@ -202,6 +221,122 @@ void TextWindow::Show(void) { InvalidateText(); } +void TextWindow::DescribeSelection(void) { + Entity *e; + Vector p; + int i; + Printf(false, ""); + + if(gs.n == 1 && (gs.points == 1 || gs.entities == 1)) { + e = SS.GetEntity(gs.points == 1 ? gs.point[0] : gs.entity[0]); + +#define COP SS.GW.ToString(p.x), SS.GW.ToString(p.y), SS.GW.ToString(p.z) +#define PT_AS_STR "(%Fi%s%E, %Fi%s%E, %Fi%s%E)" +#define PT_AS_NUM "(%Fi%3%E, %Fi%3%E, %Fi%3%E)" + switch(e->type) { + case Entity::POINT_IN_3D: + case Entity::POINT_IN_2D: + case Entity::POINT_N_TRANS: + case Entity::POINT_N_ROT_TRANS: + case Entity::POINT_N_COPY: + case Entity::POINT_N_ROT_AA: + p = e->PointGetNum(); + Printf(false, "%FtPOINT%E at " PT_AS_STR, COP); + break; + + case Entity::NORMAL_IN_3D: + case Entity::NORMAL_IN_2D: + case Entity::NORMAL_N_COPY: + case Entity::NORMAL_N_ROT: + case Entity::NORMAL_N_ROT_AA: { + Quaternion q = e->NormalGetNum(); + p = q.RotationN(); + Printf(false, "%FtNORMAL / COORDINATE SYSTEM%E"); + Printf(true, " basis n = " PT_AS_NUM, CO(p)); + p = q.RotationU(); + Printf(false, " u = " PT_AS_NUM, CO(p)); + p = q.RotationV(); + Printf(false, " v = " PT_AS_NUM, CO(p)); + break; + } + case Entity::WORKPLANE: { + p = SS.GetEntity(e->point[0])->PointGetNum(); + Printf(false, "%FtWORKPLANE%E"); + Printf(true, " origin = " PT_AS_STR, COP); + Quaternion q = e->Normal()->NormalGetNum(); + p = q.RotationN(); + Printf(true, " normal = " PT_AS_NUM, CO(p)); + break; + } + case Entity::LINE_SEGMENT: { + Vector p0 = SS.GetEntity(e->point[0])->PointGetNum(); + p = p0; + Printf(false, "%FtLINE SEGMENT%E"); + Printf(true, " thru " PT_AS_STR, COP); + Vector p1 = SS.GetEntity(e->point[1])->PointGetNum(); + p = p1; + Printf(false, " " PT_AS_STR, COP); + Printf(true, " len = %Fi%s%E", + SS.GW.ToString((p1.Minus(p0).Magnitude()))); + break; + } + case Entity::CUBIC: + p = SS.GetEntity(e->point[0])->PointGetNum(); + Printf(false, "%FtCUBIC BEZIER CURVE%E"); + for(i = 0; i <= 3; i++) { + p = SS.GetEntity(e->point[i])->PointGetNum(); + Printf((i==0), " p%c = " PT_AS_STR, '0'+i, COP); + } + break; + case Entity::ARC_OF_CIRCLE: { + Printf(false, "%FtARC OF A CIRCLE%E"); + p = SS.GetEntity(e->point[0])->PointGetNum(); + Printf(true, " center = " PT_AS_STR, COP); + p = SS.GetEntity(e->point[1])->PointGetNum(); + Printf(true," endpoints = " PT_AS_STR, COP); + p = SS.GetEntity(e->point[2])->PointGetNum(); + Printf(false," " PT_AS_STR, COP); + double r = e->CircleGetRadiusNum(); + Printf(true, " diameter = %Fi%s", SS.GW.ToString(r*2)); + Printf(false, " radius = %Fi%s", SS.GW.ToString(r)); + break; + } + case Entity::CIRCLE: { + Printf(false, "%FtCIRCLE%E"); + p = SS.GetEntity(e->point[0])->PointGetNum(); + Printf(true, " center = " PT_AS_STR, COP); + double r = e->CircleGetRadiusNum(); + Printf(true, " diameter = %Fi%s", SS.GW.ToString(r*2)); + Printf(false, " radius = %Fi%s", SS.GW.ToString(r)); + break; + } + default: + Printf(true, "%Ft?? ENTITY%E"); + break; + } + + Group *g = SS.GetGroup(e->group); + Printf(false, ""); + Printf(false, "%FtIN GROUP%E %s", g->DescriptionString()); + if(e->workplane.v == Entity::FREE_IN_3D.v) { + Printf(false, "%FtNO WORKPLANE (FREE IN 3D)%E"); + } else { + Entity *w = SS.GetEntity(e->workplane); + Printf(false, "%FtIN WORKPLANE%E %s", w->DescriptionString()); + } + } else if(gs.n == 2 && gs.points == 2) { + Printf(false, "%FtTWO POINTS"); + Vector p0 = SS.GetEntity(gs.point[0])->PointGetNum(); p = p0; + Printf(true, " at " PT_AS_STR, COP); + Vector p1 = SS.GetEntity(gs.point[1])->PointGetNum(); p = p1; + Printf(false, " " PT_AS_STR, COP); + double d = (p1.Minus(p0)).Magnitude(); + Printf(true, " d = %Fi%s", SS.GW.ToString(d)); + } else { + Printf(true, "%FtSELECTED:%E %d item%s", gs.n, gs.n == 1 ? "" : "s"); + } +} + void TextWindow::OneScreenForwardTo(int screen) { SS.TW.shownIndex++; if(SS.TW.shownIndex >= HISTORY_LEN) SS.TW.shownIndex = 0; @@ -232,7 +367,7 @@ void TextWindow::ScreenNavigation(int link, DWORD v) { break; } } -void TextWindow::ShowHeader(void) { +void TextWindow::ShowHeader(bool withNav) { ClearScreen(); char *cd = SS.GW.LockedInWorkplane() ? @@ -240,13 +375,13 @@ void TextWindow::ShowHeader(void) { "free in 3d"; // Navigation buttons - if(SS.GW.pending.description) { - Printf(false, " %Bt%Ft wrkpl:%Fd %s", cd); - } else { + if(withNav) { Printf(false, " %Lb%f<<%E %Lh%fhome%E %Bt%Ft wrkpl:%Fd %s", (&TextWindow::ScreenNavigation), (&TextWindow::ScreenNavigation), cd); + } else { + Printf(false, " %Bt%Ft wrkpl:%Fd %s", cd); } #define hs(b) ((b) ? 's' : 'h') @@ -305,6 +440,7 @@ void TextWindow::ScreenActivateGroup(int link, DWORD v) { SS.GW.ClearSuper(); } 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(); @@ -530,7 +666,9 @@ void TextWindow::ShowGroupSolveInfo(void) { Printf(true, "remove any one of these to fix it"); for(int i = 0; i < g->solved.remove.n; i++) { hConstraint hc = g->solved.remove.elem[i]; - Constraint *c = SS.GetConstraint(hc); + Constraint *c = SS.constraint.FindByIdNoOops(hc); + if(!c) continue; + Printf(false, "%Bp %Fl%Ll%D%f%h%s%E", (i & 1) ? 'd' : 'a', c->h.v, (&TextWindow::ScreenSelectConstraint), diff --git a/ui.h b/ui.h index 346ed83f..a4a3b0cb 100644 --- a/ui.h +++ b/ui.h @@ -67,7 +67,9 @@ public: static void ReportHowGroupSolved(hGroup hg); - void ShowHeader(void); + void ClearSuper(void); + + void ShowHeader(bool withNav); // These are self-contained screens, that show some information about // the sketch. void ShowListOfGroups(void); @@ -76,6 +78,8 @@ public: void ShowEntityInfo(void); void ShowConstraintInfo(void); void ShowGroupSolveInfo(void); + // Special screen, based on selection + void DescribeSelection(void); void OneScreenForwardTo(int screen); @@ -206,6 +210,8 @@ public: UNIT_INCHES, } Unit; Unit viewUnits; + char *ToString(double v); + double FromString(char *str); hGroup activeGroup; void EnsureValidActives(void); @@ -267,10 +273,12 @@ public: hEntity entity[MAX_SELECTED]; hEntity anyNormal[MAX_SELECTED]; hEntity vector[MAX_SELECTED]; + hEntity face[MAX_SELECTED]; hConstraint constraint[MAX_SELECTED]; int points; int entities; int workplanes; + int faces; int lineSegments; int circlesOrArcs; int anyNormals;