If a deletion makes it impossible to define other elements of the

sketch (e.g., a line whose length is constrained gets deleted, but
the constraint is left behind; or the point that's the origin for a
drawing group in plane gets deleted), then deleted the dependencies
too.

[git-p4: depot-paths = "//depot/solvespace/": change = 1725]
solver
Jonathan Westhues 2008-05-16 22:04:55 -08:00
parent 2ec23ffa3e
commit 3cdbbb83b1
7 changed files with 179 additions and 18 deletions

View File

@ -1,5 +1,5 @@
DEFINES = /D_WIN32_WINNT=0x500 /DISOLATION_AWARE_ENABLED /D_WIN32_IE=0x500 /DWIN32_LEAN_AND_MEAN /DWIN32
CFLAGS = /W3 /nologo -I..\common\win32 /O2 /D_DEBUG /D_CRT_SECURE_NO_WARNINGS /Zi /I. /EHs
CFLAGS = /W3 /nologo -I..\common\win32 /D_DEBUG /D_CRT_SECURE_NO_WARNINGS /Zi /I. /EHs
HEADERS = ..\common\win32\freeze.h ui.h solvespace.h dsc.h sketch.h expr.h polygon.h

5
dsc.h
View File

@ -154,6 +154,11 @@ public:
n = dest;
// and elemsAllocated is untouched, because we didn't resize
}
void RemoveById(H h) {
ClearTags();
FindById(h)->tag = 1;
RemoveTagged();
}
void MoveSelfInto(IdList<T,H> *l) {
memcpy(l, this, sizeof(*this));

View File

@ -263,6 +263,8 @@ void GraphicsWindow::EnsureValidActives(void) {
CheckMenuById(MNU_SHOW_TEXT_WND, SS.GW.showTextWindow);
CheckMenuById(MNU_SOLVE_AUTO, (SS.GW.solving == SOLVE_ALWAYS));
if(change) SS.TW.Show();
}
void GraphicsWindow::MenuEdit(int id) {
@ -287,18 +289,6 @@ void GraphicsWindow::MenuEdit(int id) {
}
if(r.v && !r.IsFromReferences()) {
SS.request.Tag(r, 1);
int j;
for(j = 0; j < SS.constraint.n; j++) {
Constraint *c = &(SS.constraint.elem[j]);
if(((c->ptA).request().v == r.v) ||
((c->ptB).request().v == r.v) ||
((c->ptC).request().v == r.v) ||
((c->entityA).request().v == r.v) ||
((c->entityB).request().v == r.v))
{
SS.constraint.Tag(c->h, 1);
}
}
}
if(s->constraint.v) {
SS.constraint.Tag(s->constraint, 1);
@ -307,9 +297,14 @@ void GraphicsWindow::MenuEdit(int id) {
SS.request.RemoveTagged();
SS.constraint.RemoveTagged();
SS.GenerateAll(SS.GW.solving == SOLVE_ALWAYS);
// Forget any mention of the just-deleted entity
SS.GW.ClearSelection();
SS.GW.hover.Clear();
// 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);
SS.GW.EnsureValidActives();
SS.TW.Show();
break;
}
@ -814,6 +809,10 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
break;
case MNU_RECTANGLE: {
if(SS.GW.activeWorkplane.v == Entity::FREE_IN_3D.v) {
Error("Can't draw rectangle in 3d; select a workplane first.");
break;
}
hRequest lns[4];
int i;
for(i = 0; i < 4; i++) {

View File

@ -137,7 +137,10 @@ Vector SContour::ComputeNormal(void) {
}
bool SContour::IsClockwiseProjdToNormal(Vector n) {
if(n.Magnitude() < 0.01) oops();
// Degenerate things might happen as we draw; doesn't really matter
// what we do then.
if(n.Magnitude() < 0.01) return true;
// An arbitrary 2d coordinate system that has n as its normal
Vector u = n.Normal(0);
Vector v = n.Normal(1);

View File

@ -17,9 +17,116 @@ void SolveSpace::Init(char *cmdLine) {
TW.Show();
}
bool SolveSpace::PruneOrphans(void) {
int i;
for(i = 0; i < request.n; i++) {
Request *r = &(request.elem[i]);
if(GroupExists(r->group)) continue;
(deleted.requests)++;
request.RemoveById(r->h);
return true;
}
for(i = 0; i < constraint.n; i++) {
Constraint *c = &(constraint.elem[i]);
if(GroupExists(c->group)) continue;
(deleted.constraints)++;
constraint.RemoveById(c->h);
return true;
}
return false;
}
bool SolveSpace::GroupsInOrder(hGroup before, hGroup after) {
if(before.v == 0) return true;
if(after.v == 0) return true;
int beforep = -1, afterp = -1;
int i;
for(i = 0; i < group.n; i++) {
Group *g = &(group.elem[i]);
if(g->h.v == before.v) beforep = i;
if(g->h.v == after.v) afterp = i;
}
if(beforep < 0 || afterp < 0) return false;
if(beforep >= afterp) return false;
return true;
}
bool SolveSpace::GroupExists(hGroup hg) {
// A nonexistent group is not acceptable
return group.FindByIdNoOops(hg) ? true : false;
}
bool SolveSpace::EntityExists(hEntity he) {
// A nonexstient entity is acceptable, though, usually just means it
// doesn't apply.
if(he.v == Entity::NO_ENTITY.v) return true;
return entity.FindByIdNoOops(he) ? true : false;
}
bool SolveSpace::PruneGroups(hGroup hg) {
Group *g = GetGroup(hg);
if(GroupsInOrder(g->opA, hg) &&
GroupsInOrder(g->opB, hg) &&
EntityExists(g->wrkpl.origin) &&
EntityExists(g->wrkpl.entityB) &&
EntityExists(g->wrkpl.entityC))
{
return false;
}
(deleted.groups)++;
group.RemoveById(g->h);
return true;
}
bool SolveSpace::PruneRequests(hGroup hg) {
int i;
for(i = 0; i < entity.n; i++) {
Entity *e = &(entity.elem[i]);
if(e->group.v != hg.v) continue;
if(EntityExists(e->workplane)) continue;
if(!e->h.isFromRequest()) oops();
(deleted.requests)++;
request.RemoveById(e->h.request());
return true;
}
return false;
}
bool SolveSpace::PruneConstraints(hGroup hg) {
int i;
for(i = 0; i < constraint.n; i++) {
Constraint *c = &(constraint.elem[i]);
if(c->group.v != hg.v) continue;
if(EntityExists(c->workplane) &&
EntityExists(c->ptA) &&
EntityExists(c->ptB) &&
EntityExists(c->ptC) &&
EntityExists(c->entityA) &&
EntityExists(c->entityB))
{
continue;
}
(deleted.constraints)++;
constraint.RemoveById(c->h);
return true;
}
return false;
}
void SolveSpace::GenerateAll(bool andSolve) {
int i, j;
while(PruneOrphans())
;
// Don't lose our numerical guesses when we regenerate.
IdList<Param,hParam> prev;
param.MoveSelfInto(&prev);
@ -34,15 +141,25 @@ void SolveSpace::GenerateAll(bool andSolve) {
for(i = 0; i < group.n; i++) {
Group *g = &(group.elem[i]);
// The group may depend on entities or other groups, to define its
// workplane geometry or for its operands. Those must already exist
// in a previous group, so check them before generating.
if(PruneGroups(g->h))
goto pruned;
for(j = 0; j < request.n; j++) {
Request *r = &(request.elem[j]);
if(r->group.v != g->h.v) continue;
r->Generate(&entity, &param);
}
g->Generate(&entity, &param);
// The requests and constraints depend on stuff in this or the
// previous group, so check them after generating.
if(PruneRequests(g->h) || PruneConstraints(g->h))
goto pruned;
// Use the previous values for params that we've seen before, as
// initial guesses for the solver.
for(j = 0; j < param.n; j++) {
@ -66,6 +183,33 @@ void SolveSpace::GenerateAll(bool andSolve) {
prev.Clear();
InvalidateGraphics();
if(deleted.requests > 0 || deleted.constraints > 0 || deleted.groups > 0) {
// 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
// messagebox could allow us to repaint and crash. But now we must
// be fine.
Error("Additional sketch elements were deleted, because they depend "
"on the element that was just deleted explicitly. These "
"include: \r\n"
" %d request%s\r\n"
" %d constraint%s\r\n"
" %d group%s\r\n\r\n"
"Choose Edit -> Undo to undelete all elements.",
deleted.requests, deleted.requests == 1 ? "" : "s",
deleted.constraints, deleted.constraints == 1 ? "" : "s",
deleted.groups, deleted.groups == 1 ? "" : "s");
memset(&deleted, 0, sizeof(deleted));
}
return;
pruned:
// Restore the numerical guesses
param.Clear();
prev.MoveSelfInto(&param);
// Try again
GenerateAll(andSolve);
}
void SolveSpace::ForceReferences(void) {

View File

@ -204,6 +204,18 @@ public:
bool SaveToFile(char *filename);
bool LoadFromFile(char *filename);
struct {
int requests;
int groups;
int constraints;
} deleted;
bool GroupExists(hGroup hg);
bool PruneOrphans(void);
bool EntityExists(hEntity he);
bool GroupsInOrder(hGroup before, hGroup after);
bool PruneGroups(hGroup hg);
bool PruneRequests(hGroup hg);
bool PruneConstraints(hGroup hg);
void GenerateAll(bool andSolve);
bool SolveGroup(hGroup hg);

View File

@ -215,8 +215,6 @@ void TextWindow::ScreenNavigation(int link, DWORD v) {
void TextWindow::ShowHeader(void) {
ClearScreen();
SS.GW.EnsureValidActives();
char *cd = (SS.GW.activeWorkplane.v == Entity::FREE_IN_3D.v) ?
"free in 3d" :
SS.GetEntity(SS.GW.activeWorkplane)->DescriptionString();