Allow generating groups in arbitrary order.

pull/4/head
whitequark 2016-02-17 10:03:07 +00:00
parent df87ac6e6f
commit c9648805ea
10 changed files with 119 additions and 87 deletions

View File

@ -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();
}

View File

@ -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",

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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) {

View File

@ -811,6 +811,7 @@ void SolveSpaceUI::Clear(void) {
void Sketch::Clear(void) {
group.Clear();
groupOrder.Clear();
constraint.Clear();
request.Clear();
style.Clear();

View File

@ -628,6 +628,7 @@ class Sketch {
public:
// These are user-editable, and define the sketch.
IdList<Group,hGroup> group;
List<hGroup> groupOrder;
IdList<CONSTRAINT,hConstraint> constraint;
IdList<Request,hRequest> request;
IdList<Style,hStyle> style;
@ -659,6 +660,7 @@ public:
// The state for undo/redo
typedef struct {
IdList<Group,hGroup> group;
List<hGroup> groupOrder;
IdList<Request,hRequest> request;
IdList<Constraint,hConstraint> constraint;
IdList<Param,hParam> 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);

View File

@ -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;

View File

@ -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();
}