diff --git a/constraint.cpp b/constraint.cpp index cef99803..17d2daf7 100644 --- a/constraint.cpp +++ b/constraint.cpp @@ -38,7 +38,7 @@ char *Constraint::DescriptionString(void) { void Constraint::AddConstraint(Constraint *c) { SS.constraint.AddAndAssignId(c); - SS.GW.GeneratePerSolving(); + SS.GenerateAll(); } void Constraint::Constrain(int type, hEntity ptA, hEntity ptB, hEntity entityA) @@ -309,18 +309,9 @@ void Constraint::MenuConstrain(int id) { break; case GraphicsWindow::MNU_SOLVE_NOW: - SS.GenerateAll(true, 0, 10000); + SS.GenerateAll(0, INT_MAX); return; - case GraphicsWindow::MNU_SOLVE_AUTO: - if(SS.GW.solving == GraphicsWindow::SOLVE_ALWAYS) { - SS.GW.solving = GraphicsWindow::DONT_SOLVE; - } else { - SS.GW.solving = GraphicsWindow::SOLVE_ALWAYS; - } - SS.GW.EnsureValidActives(); - break; - default: oops(); } diff --git a/entity.cpp b/entity.cpp index 1073a012..f81476b7 100644 --- a/entity.cpp +++ b/entity.cpp @@ -676,11 +676,34 @@ Vector Entity::GetReferencePos(void) { return dogd.refp; } +bool Entity::IsVisible(void) { + Group *g = SS.GetGroup(group); + + if(g->h.v == Group::HGROUP_REFERENCES.v && IsNormal()) { + // The reference normals are always shown + return true; + } + if(!g->visible) return false; + if(SS.GroupsInOrder(SS.GW.activeGroup, group)) return false; + + if(IsPoint() && !SS.GW.showPoints) return false; + if(IsWorkplane() && !SS.GW.showWorkplanes) return false; + if(IsNormal() && !SS.GW.showNormals) return false; + + if(IsWorkplane() && !h.isFromRequest()) { + // The group-associated workplanes are hidden outside their group. + if(g->h.v != SS.GW.activeGroup.v) return false; + } + return true; +} + void Entity::DrawOrGetDistance(int order) { Group *g = SS.GetGroup(group); // If an entity is invisible, then it doesn't get shown, and it doesn't // contribute a distance for the selection, but it still generates edges. - if(!(g->visible) && !dogd.edges) return; + if(!dogd.edges) { + if(!IsVisible()) return; + } glLineWidth(1.5); @@ -700,14 +723,6 @@ void Entity::DrawOrGetDistance(int order) { case POINT_IN_3D: case POINT_IN_2D: { if(order >= 0 && order != 2) break; - if(!SS.GW.showPoints) break; - - if(h.isFromRequest()) { - Entity *isfor = SS.GetEntity(h.request().entity(0)); - if(!SS.GW.showWorkplanes && isfor->type == Entity::WORKPLANE) { - break; - } - } Vector v = PointGetNum(); @@ -754,7 +769,6 @@ void Entity::DrawOrGetDistance(int order) { } else { glxColor3d(0, 0.4, 0.4); if(i > 0) break; - if(!SS.GW.showNormals) break; } Quaternion q = NormalGetNum(); @@ -796,13 +810,6 @@ void Entity::DrawOrGetDistance(int order) { case WORKPLANE: { if(order >= 0 && order != 0) break; - if(!SS.GW.showWorkplanes) break; - - if((!h.isFromRequest()) && (h.group().v != SS.GW.activeGroup.v)) { - // Workplanes that are automatically created by an in-wrkpl - // drawing group appear only when that group is active. - break; - } Vector p; p = SS.GetEntity(point[0])->PointGetNum(); @@ -987,5 +994,6 @@ void Entity::CalculateNumerical(void) { numPoint = Vector::From( p.x->Eval(), p.y->Eval(), p.z->Eval()); numNormal = Quaternion::From(0, n.x->Eval(), n.y->Eval(), n.z->Eval()); } + visible = IsVisible(); } diff --git a/file.cpp b/file.cpp index 8efb62dc..de8b997f 100644 --- a/file.cpp +++ b/file.cpp @@ -86,6 +86,7 @@ const SolveSpace::SaveTable SolveSpace::SAVED[] = { { 'e', "Entity.h.v", 'x', &(SS.sv.e.h.v) }, { 'e', "Entity.type", 'd', &(SS.sv.e.type) }, + { 'e', "Entity.visible", 'b', &(SS.sv.e.visible) }, { 'e', "Entity.group.v", 'x', &(SS.sv.e.group.v) }, { 'e', "Entity.construction", 'b', &(SS.sv.e.construction) }, { 'e', "Entity.param[0].v", 'x', &(SS.sv.e.param[0].v) }, diff --git a/graphicswin.cpp b/graphicswin.cpp index dab70af5..a36a3aa6 100644 --- a/graphicswin.cpp +++ b/graphicswin.cpp @@ -86,7 +86,6 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = { { 1, NULL, 0, NULL }, { 1, "Sym&bolic Equation\tShift+B", 0, 'B'|S, NULL }, { 1, NULL, 0, NULL }, -{ 1, "Sol&ve Automatically\tShift+Tab", MNU_SOLVE_AUTO, '\t'|S, mCon }, { 1, "Solve Once Now\tSpace", MNU_SOLVE_NOW, ' ', mCon }, { 0, "&Help", 0, NULL }, @@ -121,8 +120,6 @@ void GraphicsWindow::Init(void) { showShaded = true; showMesh = false; - solving = SOLVE_ALWAYS; - showTextWindow = true; ShowTextWindow(showTextWindow); } @@ -289,8 +286,6 @@ void GraphicsWindow::EnsureValidActives(void) { ShowTextWindow(SS.GW.showTextWindow); CheckMenuById(MNU_SHOW_TEXT_WND, SS.GW.showTextWindow); - CheckMenuById(MNU_SOLVE_AUTO, (SS.GW.solving == SOLVE_ALWAYS)); - if(change) SS.TW.Show(); } @@ -309,10 +304,6 @@ bool GraphicsWindow::LockedInWorkplane(void) { return (SS.GW.ActiveWorkplane().v != Entity::FREE_IN_3D.v); } -void GraphicsWindow::GeneratePerSolving(void) { - SS.GenerateAll(solving == SOLVE_ALWAYS); -} - void GraphicsWindow::MenuEdit(int id) { switch(id) { case MNU_UNSELECT_ALL: @@ -352,7 +343,7 @@ void GraphicsWindow::MenuEdit(int id) { 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); + SS.GenerateAll(0, INT_MAX); SS.GW.EnsureValidActives(); SS.TW.Show(); break; @@ -412,7 +403,7 @@ c: r->construction = !(r->construction); } SS.GW.ClearSelection(); - SS.GW.GeneratePerSolving(); + SS.GenerateAll(); break; } @@ -659,7 +650,7 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown, default: oops(); } if(pending.operation != 0 && pending.operation != DRAGGING_CONSTRAINT) { - SS.GW.GeneratePerSolving(); + SS.GenerateAll(); } havePainted = false; } @@ -864,7 +855,7 @@ hRequest GraphicsWindow::AddRequest(int type) { // place this request's entities where the mouse is can do so. But // we mustn't try to solve until reasonable values have been supplied // for these new parameters, or else we'll get a numerical blowup. - SS.GenerateAll(false); + SS.GenerateAll(-1, -1); return r.h; } @@ -1036,6 +1027,7 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) { // Create a new line segment, so that we continue drawing. hRequest hr = AddRequest(Request::LINE_SEGMENT); SS.GetEntity(hr.entity(1))->PointForceTo(v); + SS.GetEntity(hr.entity(2))->PointForceTo(v); // Constrain the line segments to share an endpoint Constraint::ConstrainCoincident(pending.point, hr.entity(1)); @@ -1044,7 +1036,6 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) { pending.operation = DRAGGING_NEW_LINE_POINT; pending.point = hr.entity(2); pending.description = "click to place next point of next line"; - SS.GetEntity(pending.point)->PointForceTo(v); break; } @@ -1088,9 +1079,6 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) { break; } } - if(pending.operation != 0 && pending.operation != DRAGGING_CONSTRAINT) { - SS.GW.GeneratePerSolving(); - } SS.TW.Show(); InvalidateGraphics(); @@ -1131,7 +1119,7 @@ void GraphicsWindow::EditControlDone(char *s) { Expr::FreeKeep(&(c->exprA)); c->exprA = e->DeepCopyKeep(); HideGraphicsEditControl(); - SS.GW.GeneratePerSolving(); + SS.GenerateAll(); } else { Error("Not a valid number or expression: '%s'", s); } @@ -1167,7 +1155,7 @@ void GraphicsWindow::ToggleBool(int link, DWORD v) { // so not meaningful to show them and hide the shaded. if(!SS.GW.showShaded) SS.GW.showFaces = false; - SS.GW.GeneratePerSolving(); + SS.GenerateAll(); InvalidateGraphics(); SS.TW.Show(); } diff --git a/sketch.cpp b/sketch.cpp index 559044c4..1a045344 100644 --- a/sketch.cpp +++ b/sketch.cpp @@ -136,7 +136,7 @@ void Group::MenuGroup(int id) { if(g.type == IMPORTED) { SS.ReloadAllImported(); } - SS.GenerateAll(SS.GW.solving == GraphicsWindow::SOLVE_ALWAYS); + SS.GenerateAll(); SS.GW.activeGroup = g.h; if(g.type == DRAWING_WORKPLANE) { SS.GetGroup(g.h)->activeWorkplane = g.h.entity(0); @@ -580,16 +580,6 @@ void Group::CopyEntity(Entity *ep, int timesApplied, int remap, SS.entity.Add(&en); } -SMesh *Group::PreviousGroupMesh(void) { - int i; - for(i = 0; i < SS.group.n; i++) { - Group *g = &(SS.group.elem[i]); - if(g->h.v == h.v) break; - } - if(i == 0 || i >= SS.group.n) oops(); - return &(SS.group.elem[i-1].mesh); -} - void Group::TagEdgesFromLineSegments(SEdgeList *el) { int i, j; for(i = 0; i < SS.entity.n; i++) { @@ -608,17 +598,13 @@ void Group::TagEdgesFromLineSegments(SEdgeList *el) { } } -void Group::MakePolygons(void) { +void Group::GeneratePolygon(void) { poly.Clear(); - SEdgeList edges; - ZERO(&edges); - SMesh outm; - ZERO(&outm); - if(type == DRAWING_3D || type == DRAWING_WORKPLANE || type == ROTATE || type == TRANSLATE) { + SEdgeList edges; ZERO(&edges); int i; for(i = 0; i < SS.entity.n; i++) { Entity *e = &(SS.entity.elem[i]); @@ -636,14 +622,19 @@ void Group::MakePolygons(void) { polyError.notClosedAt = error; poly.Clear(); } - } else if(type == EXTRUDE) { + } +} + +void Group::GenerateMesh(void) { + SMesh outm; + ZERO(&outm); + if(type == EXTRUDE) { + SEdgeList edges; + ZERO(&edges); int i; Group *src = SS.GetGroup(opA); - Vector translate = Vector::From( - SS.GetParam(h.param(0))->val, - SS.GetParam(h.param(1))->val, - SS.GetParam(h.param(2))->val - ); + Vector translate = Vector::From(h.param(0), h.param(1), h.param(2)); + Vector tbot, ttop; if(subtype == ONE_SIDED) { tbot = Vector::From(0, 0, 0); ttop = translate.ScaledBy(2); @@ -713,6 +704,7 @@ void Group::MakePolygons(void) { outm.AddTriangle(meta, bbot, btop, atop); } } + edges.Clear(); } else if(type == IMPORTED) { // Triangles are just copied over, with the appropriate transformation // applied. @@ -739,7 +731,6 @@ void Group::MakePolygons(void) { outm.AddTriangle(&st); } } - edges.Clear(); // So our group's mesh appears in outm. Combine this with the previous // group's mesh, using the requested operation. @@ -753,6 +744,17 @@ void Group::MakePolygons(void) { outm.Clear(); } +SMesh *Group::PreviousGroupMesh(void) { + int i; + for(i = 0; i < SS.group.n; i++) { + Group *g = &(SS.group.elem[i]); + if(g->h.v == h.v) break; + } + if(i == 0 || i >= SS.group.n) oops(); + return &(SS.group.elem[i-1].mesh); +} + + void Group::Draw(void) { // Show this even if the group is not visible. It's already possible // to show or hide just this with the "show solids" flag. diff --git a/sketch.h b/sketch.h index fcab3ca3..5bb6cea4 100644 --- a/sketch.h +++ b/sketch.h @@ -88,6 +88,7 @@ public: hGroup opA; bool visible; + bool clean; hEntity activeWorkplane; Expr *exprA; DWORD color; @@ -164,7 +165,8 @@ public: void GenerateEquations(IdList *l); SMesh *PreviousGroupMesh(void); - void MakePolygons(void); + void GeneratePolygon(void); + void GenerateMesh(void); void Draw(void); SPolygon GetPolygon(void); @@ -264,6 +266,8 @@ public: double numDistance; // and a bit more state that the faces need Vector numVector; + // and the shown state also gets saved here, for later import + bool visible; // All points/normals/distances have their numerical value; this is // a convenience, to simplify the import/assembly code, so that the @@ -281,6 +285,8 @@ public: // times to apply the transformation. int timesApplied; + bool IsVisible(void); + bool IsCircle(void); Expr *CircleGetRadiusExpr(void); double CircleGetRadiusNum(void); diff --git a/solvespace.cpp b/solvespace.cpp index 539c6b68..69389f49 100644 --- a/solvespace.cpp +++ b/solvespace.cpp @@ -19,12 +19,12 @@ void SolveSpace::Init(char *cmdLine) { void SolveSpace::AfterNewFile(void) { ReloadAllImported(); - GenerateAll(false, 0, INT_MAX); + GenerateAll(-1, -1); TW.Init(); GW.Init(); - GenerateAll(true, 0, INT_MAX); + GenerateAll(0, INT_MAX); TW.Show(); } @@ -131,7 +131,7 @@ bool SolveSpace::PruneConstraints(hGroup hg) { return false; } -void SolveSpace::GenerateAll(bool andSolve) { +void SolveSpace::GenerateAll(void) { int i; int firstShown = INT_MAX, lastShown = 0; // The references don't count, so start from group 1 @@ -144,10 +144,10 @@ void SolveSpace::GenerateAll(bool andSolve) { } // Even if nothing is shown, we have to keep going; the entities get // generated for hidden groups, even though they're not solved. - GenerateAll(andSolve, firstShown, lastShown); + GenerateAll(firstShown, lastShown); } -void SolveSpace::GenerateAll(bool andSolve, int first, int last) { +void SolveSpace::GenerateAll(int first, int last) { int i, j; while(PruneOrphans()) @@ -197,8 +197,9 @@ void SolveSpace::GenerateAll(bool andSolve, int first, int last) { if(i >= first && i <= last) { // The group falls inside the range, so really solve it, // and then regenerate the mesh based on the solved stuff. - if(andSolve) SolveGroup(g->h); - g->MakePolygons(); + SolveGroup(g->h); + g->GeneratePolygon(); + g->GenerateMesh(); } else { // The group falls outside the range, so just assume that // it's good wherever we left it. The mesh is unchanged, @@ -253,7 +254,7 @@ pruned: param.Clear(); prev.MoveSelfInto(¶m); // Try again - GenerateAll(andSolve, first, last); + GenerateAll(first, last); } void SolveSpace::ForceReferences(void) { diff --git a/solvespace.h b/solvespace.h index 65fc12e7..f792803b 100644 --- a/solvespace.h +++ b/solvespace.h @@ -249,6 +249,8 @@ public: bool LoadEntitiesFromFile(char *filename, EntityList *le, SMesh *m); void ReloadAllImported(void); + void MarkGroupDirty(hGroup hg); + struct { int requests; int groups; @@ -262,8 +264,8 @@ public: bool PruneRequests(hGroup hg); bool PruneConstraints(hGroup hg); - void GenerateAll(bool andSolve); - void GenerateAll(bool andSolve, int first, int last); + void GenerateAll(void); + void GenerateAll(int first, int last); void SolveGroup(hGroup hg); void ForceReferences(void); diff --git a/textwin.cpp b/textwin.cpp index 54e7b162..b613ef58 100644 --- a/textwin.cpp +++ b/textwin.cpp @@ -429,7 +429,7 @@ void TextWindow::ScreenToggleGroupShown(int link, DWORD v) { g->visible = !(g->visible); // If a group was just shown, then it might not have been generated // previously, so regenerate. - SS.GW.GeneratePerSolving(); + SS.GenerateAll(); } void TextWindow::ScreenShowGroupsSpecial(int link, DWORD v) { int i; @@ -535,7 +535,7 @@ void TextWindow::ScreenChangeOneOrTwoSides(int link, DWORD v) { } else if(g->subtype == Group::TWO_SIDED) { g->subtype = Group::ONE_SIDED; } else oops(); - SS.GW.GeneratePerSolving(); + SS.GenerateAll(); SS.GW.ClearSuper(); } void TextWindow::ScreenChangeMeshCombine(int link, DWORD v) { @@ -545,14 +545,14 @@ void TextWindow::ScreenChangeMeshCombine(int link, DWORD v) { } else if(g->meshCombine == Group::COMBINE_AS_UNION) { g->meshCombine = Group::COMBINE_AS_DIFFERENCE; } else oops(); - SS.GW.GeneratePerSolving(); + SS.GenerateAll(); SS.GW.ClearSuper(); } void TextWindow::ScreenColor(int link, DWORD v) { Group *g = SS.GetGroup(SS.TW.shown->group); if(v < 0 || v >= MODEL_COLORS) return; g->color = SS.TW.modelColor[v]; - SS.GW.GeneratePerSolving(); + SS.GenerateAll(); SS.GW.ClearSuper(); } void TextWindow::ScreenChangeExprA(int link, DWORD v) { @@ -722,7 +722,7 @@ void TextWindow::EditControlDone(char *s) { Group *g = SS.GetGroup(edit.group); Expr::FreeKeep(&(g->exprA)); g->exprA = e->DeepCopyKeep(); - SS.GW.GeneratePerSolving(); + SS.GenerateAll(); SS.TW.Show(); } else { Error("Not a valid number or expression: '%s'", s); diff --git a/ui.h b/ui.h index 70b4a7d3..285d5846 100644 --- a/ui.h +++ b/ui.h @@ -165,7 +165,6 @@ public: MNU_VERTICAL, MNU_PARALLEL, MNU_ORIENTED_SAME, - MNU_SOLVE_AUTO, MNU_SOLVE_NOW, } MenuId; typedef void MenuHandler(int id); @@ -304,11 +303,6 @@ public: bool showHdnLines; static void ToggleBool(int link, DWORD v); - static const int DONT_SOLVE = 0; - static const int SOLVE_ALWAYS = 1; - int solving; - void GeneratePerSolving(void); - void UpdateDraggedNum(Vector *pos, double mx, double my); void UpdateDraggedPoint(hEntity hp, double mx, double my);