From c9648805ead2a3b904f5c700f52eb7cf8be5ba16 Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 17 Feb 2016 10:03:07 +0000 Subject: [PATCH] Allow generating groups in arbitrary order. --- src/draw.cpp | 4 +- src/file.cpp | 14 +++-- src/generate.cpp | 121 +++++++++++++++++++++++++------------------- src/graphicswin.cpp | 10 ++-- src/group.cpp | 3 ++ src/groupmesh.cpp | 8 +-- src/solvespace.cpp | 1 + src/solvespace.h | 8 +-- src/textscreens.cpp | 23 ++++----- src/undoredo.cpp | 14 +++-- 10 files changed, 119 insertions(+), 87 deletions(-) diff --git a/src/draw.cpp b/src/draw.cpp index e1deec9..1a3ad0b 100644 --- a/src/draw.cpp +++ b/src/draw.cpp @@ -689,8 +689,8 @@ nogrid:; // specially by assigning a style with a fill color, or when the filled // paths are just being filled by default. This should go last, to make // the transparency work. - Group *g; - for(g = SK.group.First(); g; g = SK.group.NextAfter(g)) { + for(i = 0; i < SK.groupOrder.n; i++) { + Group *g = SK.GetGroup(SK.groupOrder.elem[i]); if(!(g->IsVisible())) continue; g->DrawFilledPaths(); } diff --git a/src/file.cpp b/src/file.cpp index d4aa077..3bb88ab 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -20,14 +20,15 @@ void SolveSpaceUI::ClearExisting(void) { UndoClearStack(&redo); UndoClearStack(&undo); - Group *g; - for(g = SK.group.First(); g; g = SK.group.NextAfter(g)) { + for(int i = 0; i < SK.groupOrder.n; i++) { + Group *g = SK.GetGroup(SK.groupOrder.elem[i]); g->Clear(); } SK.constraint.Clear(); SK.request.Clear(); SK.group.Clear(); + SK.groupOrder.Clear(); SK.style.Clear(); SK.entity.Clear(); @@ -39,12 +40,13 @@ hGroup SolveSpaceUI::CreateDefaultDrawingGroup(void) { // And an empty group, for the first stuff the user draws. g.visible = true; + g.name = "sketch-in-plane"; g.type = Group::DRAWING_WORKPLANE; g.subtype = Group::WORKPLANE_BY_POINT_ORTHO; + g.order = 1; g.predef.q = Quaternion::From(1, 0, 0, 0); hRequest hr = Request::HREQUEST_REFERENCE_XY; g.predef.origin = hr.entity(1); - g.name = "sketch-in-plane"; SK.group.AddAndAssignId(&g); SK.GetGroup(g.h)->activeWorkplane = g.h.entity(0); return g.h; @@ -58,6 +60,7 @@ void SolveSpaceUI::NewFile(void) { g.visible = true; g.name = "#references"; g.type = Group::DRAWING_3D; + g.order = 0; g.h = Group::HGROUP_REFERENCES; SK.group.Add(&g); @@ -308,7 +311,8 @@ bool SolveSpaceUI::SaveToFile(const std::string &filename) { // A group will have either a mesh or a shell, but not both; but the code // to print either of those just does nothing if the mesh/shell is empty. - SMesh *m = &(SK.group.elem[SK.group.n-1].runningMesh); + Group *g = SK.GetGroup(SK.groupOrder.elem[SK.groupOrder.n - 1]); + SMesh *m = &g->runningMesh; for(i = 0; i < m->l.n; i++) { STriangle *tr = &(m->l.elem[i]); fprintf(fh, "Triangle %08x %08x " @@ -317,7 +321,7 @@ bool SolveSpaceUI::SaveToFile(const std::string &filename) { CO(tr->a), CO(tr->b), CO(tr->c)); } - SShell *s = &(SK.group.elem[SK.group.n-1].runningShell); + SShell *s = &g->runningShell; SSurface *srf; for(srf = s->surface.First(); srf; srf = s->surface.NextAfter(srf)) { fprintf(fh, "Surface %08x %08x %08x %d %d\n", diff --git a/src/generate.cpp b/src/generate.cpp index f56643d..c228a4b 100644 --- a/src/generate.cpp +++ b/src/generate.cpp @@ -16,8 +16,8 @@ void SolveSpaceUI::MarkGroupDirtyByEntity(hEntity he) { void SolveSpaceUI::MarkGroupDirty(hGroup hg) { int i; bool go = false; - for(i = 0; i < SK.group.n; i++) { - Group *g = &(SK.group.elem[i]); + for(i = 0; i < SK.groupOrder.n; i++) { + Group *g = SK.GetGroup(SK.groupOrder.elem[i]); if(g->h.v == hg.v) { go = true; } @@ -58,8 +58,8 @@ bool SolveSpaceUI::GroupsInOrder(hGroup before, hGroup after) { int beforep = -1, afterp = -1; int i; - for(i = 0; i < SK.group.n; i++) { - Group *g = &(SK.group.elem[i]); + for(i = 0; i < SK.groupOrder.n; i++) { + Group *g = SK.GetGroup(SK.groupOrder.elem[i]); if(g->h.v == before.v) beforep = i; if(g->h.v == after.v) afterp = i; } @@ -141,52 +141,71 @@ bool SolveSpaceUI::PruneConstraints(hGroup hg) { return false; } -void SolveSpaceUI::GenerateAll(void) { - int i; - int firstDirty = INT_MAX, lastVisible = 0; - // Start from the first dirty group, and solve until the active group, - // since all groups after the active group are hidden. - for(i = 0; i < SK.group.n; i++) { - Group *g = &(SK.group.elem[i]); - g->order = i; - if((!g->clean) || (g->solved.how != System::SOLVED_OKAY)) { - firstDirty = min(firstDirty, i); - } - if(g->h.v == SS.GW.activeGroup.v) { - lastVisible = i; - } - } - if(firstDirty == INT_MAX || lastVisible == 0) { - // All clean; so just regenerate the entities, and don't solve anything. - GenerateAll(GENERATE_REGEN); - } else { - SS.nakedEdges.Clear(); - GenerateAll(firstDirty, lastVisible); - } -} +void SolveSpaceUI::GenerateAll(GenerateType type, bool andFindFree, bool genForBBox) { + int first, last, i, j; + + SK.groupOrder.Clear(); + for(int i = 0; i < SK.group.n; i++) + SK.groupOrder.Add(&SK.group.elem[i].h); + std::sort(&SK.groupOrder.elem[0], &SK.groupOrder.elem[SK.groupOrder.n], + [](const hGroup &ha, const hGroup &hb) { + return SK.GetGroup(ha)->order < SK.GetGroup(hb)->order; + }); -void SolveSpaceUI::GenerateAll(GenerateType type, bool andFindFree) { switch(type) { - case GENERATE_ALL: GenerateAll(0, INT_MAX, andFindFree); break; - case GENERATE_REGEN: GenerateAll(-1, -1, andFindFree); break; - case GENERATE_UNTIL_ACTIVE: GenerateAll(0, -2, andFindFree); break; + case GENERATE_DIRTY: { + first = INT_MAX; + last = 0; + + // Start from the first dirty group, and solve until the active group, + // since all groups after the active group are hidden. + for(i = 0; i < SK.groupOrder.n; i++) { + Group *g = SK.GetGroup(SK.groupOrder.elem[i]); + if((!g->clean) || (g->solved.how != System::SOLVED_OKAY)) { + first = min(first, i); + } + if(g->h.v == SS.GW.activeGroup.v) { + last = i; + } + } + if(first == INT_MAX || last == 0) { + // All clean; so just regenerate the entities, and don't solve anything. + first = -1; + last = -1; + } else { + SS.nakedEdges.Clear(); + } + break; + } + + case GENERATE_ALL: + first = 0; + last = INT_MAX; + break; + + case GENERATE_REGEN: + first = -1; + last = -1; + break; + + case GENERATE_UNTIL_ACTIVE: { + for(i = 0; i < SK.groupOrder.n; i++) { + if(SK.groupOrder.elem[i].v == SS.GW.activeGroup.v) + break; + } + + first = 0; + last = i; + break; + } + default: oops(); } -} - -void SolveSpaceUI::GenerateAll(int first, int last, bool andFindFree, bool genForBBox) { - int i, j; - - // generate until active group - if(last == -2) { - last = SK.group.IndexOf(SS.GW.activeGroup); - if(last == -1) last = INT_MAX; - } // If we're generating entities for display, first we need to find // the bounding box to turn relative chord tolerance to absolute. if(!SS.exportMode && !genForBBox) { - GenerateAll(first, last, /*andFindFree=*/false, /*genForBBox=*/true); + GenerateAll(type, /*andFindFree=*/false, /*genForBBox=*/true); BBox box = SK.CalculateEntityBBox(/*includeInvisibles=*/true); Vector size = box.maxp.Minus(box.minp); double maxSize = std::max({ size.x, size.y, size.z }); @@ -207,19 +226,19 @@ void SolveSpaceUI::GenerateAll(int first, int last, bool andFindFree, bool genFo int64_t inTime = GetMilliseconds(); bool displayedStatusMessage = false; - for(i = 0; i < SK.group.n; i++) { - Group *g = &(SK.group.elem[i]); + for(i = 0; i < SK.groupOrder.n; i++) { + Group *g = SK.GetGroup(SK.groupOrder.elem[i]); int64_t now = GetMilliseconds(); // Display the status message if we've taken more than 400 ms, or // if we've taken 200 ms but we're not even halfway done, or if // we've already started displaying the status message. if( (now - inTime > 400) || - ((now - inTime > 200) && i < (SK.group.n / 2)) || + ((now - inTime > 200) && i < (SK.groupOrder.n / 2)) || displayedStatusMessage) { displayedStatusMessage = true; - std::string msg = ssprintf("generating group %d/%d", i, SK.group.n); + std::string msg = ssprintf("generating group %d/%d", i, SK.groupOrder.n); int w, h; GetGraphicsWindowSize(&w, &h); @@ -377,7 +396,7 @@ pruned: SK.param.Clear(); prev.MoveSelfInto(&(SK.param)); // Try again - GenerateAll(first, last, andFindFree, genForBBox); + GenerateAll(type, andFindFree, genForBBox); } void SolveSpaceUI::ForceReferences(void) { @@ -507,11 +526,11 @@ void SolveSpaceUI::SolveGroup(hGroup hg, bool andFindFree) { } bool SolveSpaceUI::ActiveGroupsOkay() { - for(int i = 0; i < SK.group.n; i++) { - Group *group = &SK.group.elem[i]; - if(!group->IsSolvedOkay()) + for(int i = 0; i < SK.groupOrder.n; i++) { + Group *g = SK.GetGroup(SK.groupOrder.elem[i]); + if(!g->IsSolvedOkay()) return false; - if(group->h.v == SS.GW.activeGroup.v) + if(g->h.v == SS.GW.activeGroup.v) break; } return true; diff --git a/src/graphicswin.cpp b/src/graphicswin.cpp index e5721c1..8f4d56c 100644 --- a/src/graphicswin.cpp +++ b/src/graphicswin.cpp @@ -222,7 +222,7 @@ void GraphicsWindow::Init(void) { orig.projUp = projUp; // And with the last group active - activeGroup = SK.group.elem[SK.group.n-1].h; + activeGroup = SK.groupOrder.elem[SK.groupOrder.n - 1]; SK.GetGroup(activeGroup)->Activate(); showWorkplanes = false; @@ -592,12 +592,12 @@ void GraphicsWindow::EnsureValidActives(void) { Group *g = SK.group.FindByIdNoOops(activeGroup); if((!g) || (g->h.v == Group::HGROUP_REFERENCES.v)) { int i; - for(i = 0; i < SK.group.n; i++) { - if(SK.group.elem[i].h.v != Group::HGROUP_REFERENCES.v) { + for(i = 0; i < SK.groupOrder.n; i++) { + if(SK.groupOrder.elem[i].v != Group::HGROUP_REFERENCES.v) { break; } } - if(i >= SK.group.n) { + if(i >= SK.groupOrder.n) { // This can happen if the user deletes all the groups in the // sketch. It's difficult to prevent that, because the last // group might have been deleted automatically, because it failed @@ -606,7 +606,7 @@ void GraphicsWindow::EnsureValidActives(void) { // to delete the references, though. activeGroup = SS.CreateDefaultDrawingGroup(); } else { - activeGroup = SK.group.elem[i].h; + activeGroup = SK.groupOrder.elem[i]; } SK.GetGroup(activeGroup)->Activate(); change = true; diff --git a/src/group.cpp b/src/group.cpp index 1e25a31..411d807 100644 --- a/src/group.cpp +++ b/src/group.cpp @@ -56,6 +56,9 @@ void Group::MenuGroup(int id) { g.color = RGBi(100, 100, 100); g.scale = 1; + Group *gl = SK.GetGroup(SK.groupOrder.elem[SK.groupOrder.n - 1]); + g.order = gl->order + 1; + if(id >= RECENT_IMPORT && id < (RECENT_IMPORT + MAX_RECENT)) { g.impFile = RecentFile[id-RECENT_IMPORT]; id = GraphicsWindow::MNU_GROUP_IMPORT; diff --git a/src/groupmesh.cpp b/src/groupmesh.cpp index d6d1f1a..aba9f37 100644 --- a/src/groupmesh.cpp +++ b/src/groupmesh.cpp @@ -414,12 +414,12 @@ void Group::GenerateDisplayItems(void) { Group *Group::PreviousGroup(void) { int i; - for(i = 0; i < SK.group.n; i++) { - Group *g = &(SK.group.elem[i]); + for(i = 0; i < SK.groupOrder.n; i++) { + Group *g = SK.GetGroup(SK.groupOrder.elem[i]); if(g->h.v == h.v) break; } - if(i == 0 || i >= SK.group.n) return NULL; - return &(SK.group.elem[i-1]); + if(i == 0 || i >= SK.groupOrder.n) return NULL; + return SK.GetGroup(SK.groupOrder.elem[i - 1]); } Group *Group::RunningMeshGroup(void) { diff --git a/src/solvespace.cpp b/src/solvespace.cpp index 9fe023a..863c89f 100644 --- a/src/solvespace.cpp +++ b/src/solvespace.cpp @@ -811,6 +811,7 @@ void SolveSpaceUI::Clear(void) { void Sketch::Clear(void) { group.Clear(); + groupOrder.Clear(); constraint.Clear(); request.Clear(); style.Clear(); diff --git a/src/solvespace.h b/src/solvespace.h index 6493515..977c399 100644 --- a/src/solvespace.h +++ b/src/solvespace.h @@ -628,6 +628,7 @@ class Sketch { public: // These are user-editable, and define the sketch. IdList group; + List
groupOrder; IdList constraint; IdList request; IdList style; @@ -659,6 +660,7 @@ public: // The state for undo/redo typedef struct { IdList group; + List
groupOrder; IdList request; IdList constraint; IdList param; @@ -879,14 +881,14 @@ public: bool PruneConstraints(hGroup hg); enum GenerateType { + GENERATE_DIRTY, GENERATE_ALL, GENERATE_REGEN, GENERATE_UNTIL_ACTIVE, }; - void GenerateAll(GenerateType type, bool andFindFree = false); - void GenerateAll(void); - void GenerateAll(int first, int last, bool andFindFree = false, bool genForBBox = false); + void GenerateAll(GenerateType type = GENERATE_DIRTY, bool andFindFree = false, + bool genForBBox = false); void SolveGroup(hGroup hg, bool andFindFree); void MarkDraggedParams(void); void ForceReferences(void); diff --git a/src/textscreens.cpp b/src/textscreens.cpp index 5953170..14fe13a 100644 --- a/src/textscreens.cpp +++ b/src/textscreens.cpp @@ -56,15 +56,10 @@ void TextWindow::ScreenToggleGroupShown(int link, uint32_t v) { SS.GenerateAll(); } void TextWindow::ScreenShowGroupsSpecial(int link, uint32_t v) { - int i; - for(i = 0; i < SK.group.n; i++) { - Group *g = &(SK.group.elem[i]); - - if(link == 's') { - g->visible = true; - } else { - g->visible = false; - } + bool state = link == 's'; + for(int i = 0; i < SK.groupOrder.n; i++) { + Group *g = SK.GetGroup(SK.groupOrder.elem[i]); + g->visible = state; } } void TextWindow::ScreenActivateGroup(int link, uint32_t v) { @@ -105,8 +100,8 @@ void TextWindow::ShowListOfGroups(void) { Printf(false, "%Ft shown ok group-name%E"); int i; bool afterActive = false; - for(i = 0; i < SK.group.n; i++) { - Group *g = &(SK.group.elem[i]); + for(i = 0; i < SK.groupOrder.n; i++) { + Group *g = SK.GetGroup(SK.groupOrder.elem[i]); std::string s = g->DescriptionString(); bool active = (g->h.v == SS.GW.activeGroup.v); bool shown = g->visible; @@ -260,14 +255,14 @@ void TextWindow::ScreenDeleteGroup(int link, uint32_t v) { "before proceeding."); return; } - SK.group.RemoveById(SS.TW.shown.group); + SK.group.RemoveById(hg); // This is a major change, so let's re-solve everything. SS.TW.ClearSuper(); SS.GW.ClearSuper(); SS.GenerateAll(SolveSpaceUI::GENERATE_ALL); } void TextWindow::ShowGroupInfo(void) { - Group *g = SK.group.FindById(shown.group); + Group *g = SK.GetGroup(shown.group); const char *s = "???"; if(shown.group.v == Group::HGROUP_REFERENCES.v) { @@ -465,7 +460,7 @@ void TextWindow::ScreenAllowRedundant(int link, uint32_t v) { SS.TW.Show(); } void TextWindow::ShowGroupSolveInfo(void) { - Group *g = SK.group.FindById(shown.group); + Group *g = SK.GetGroup(shown.group); if(g->IsSolvedOkay()) { // Go back to the default group info screen shown.screen = SCREEN_GROUP_INFO; diff --git a/src/undoredo.cpp b/src/undoredo.cpp index 63c89f1..3bdd1a8 100644 --- a/src/undoredo.cpp +++ b/src/undoredo.cpp @@ -73,6 +73,9 @@ void SolveSpaceUI::PushFromCurrentOnto(UndoStack *uk) { dest.impEntity = {}; ut->group.Add(&dest); } + for(i = 0; i < SK.groupOrder.n; i++) { + ut->groupOrder.Add(&(SK.groupOrder.elem[i])); + } for(i = 0; i < SK.request.n; i++) { ut->request.Add(&(SK.request.elem[i])); } @@ -94,6 +97,8 @@ void SolveSpaceUI::PushFromCurrentOnto(UndoStack *uk) { } void SolveSpaceUI::PopOntoCurrentFrom(UndoStack *uk) { + int i; + if(uk->cnt <= 0) oops(); (uk->cnt)--; uk->write = WRAP(uk->write - 1, MAX_UNDO); @@ -101,11 +106,12 @@ void SolveSpaceUI::PopOntoCurrentFrom(UndoStack *uk) { UndoState *ut = &(uk->d[uk->write]); // Free everything in the main copy of the program before replacing it - Group *g; - for(g = SK.group.First(); g; g = SK.group.NextAfter(g)) { + for(i = 0; i < SK.groupOrder.n; i++) { + Group *g = SK.GetGroup(SK.groupOrder.elem[i]); g->Clear(); } SK.group.Clear(); + SK.groupOrder.Clear(); SK.request.Clear(); SK.constraint.Clear(); SK.param.Clear(); @@ -113,6 +119,8 @@ void SolveSpaceUI::PopOntoCurrentFrom(UndoStack *uk) { // And then do a shallow copy of the state from the undo list ut->group.MoveSelfInto(&(SK.group)); + for(i = 0; i < ut->groupOrder.n; i++) + SK.groupOrder.Add(&ut->groupOrder.elem[i]); ut->request.MoveSelfInto(&(SK.request)); ut->constraint.MoveSelfInto(&(SK.constraint)); ut->param.MoveSelfInto(&(SK.param)); @@ -131,7 +139,7 @@ void SolveSpaceUI::PopOntoCurrentFrom(UndoStack *uk) { SS.ScheduleShowTW(); // Activate the group that was active before. - Group *activeGroup = SK.group.FindById(SS.GW.activeGroup); + Group *activeGroup = SK.GetGroup(SS.GW.activeGroup); activeGroup->Activate(); }