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
parent
2ec23ffa3e
commit
3cdbbb83b1
2
Makefile
2
Makefile
|
@ -1,5 +1,5 @@
|
||||||
DEFINES = /D_WIN32_WINNT=0x500 /DISOLATION_AWARE_ENABLED /D_WIN32_IE=0x500 /DWIN32_LEAN_AND_MEAN /DWIN32
|
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
|
HEADERS = ..\common\win32\freeze.h ui.h solvespace.h dsc.h sketch.h expr.h polygon.h
|
||||||
|
|
||||||
|
|
5
dsc.h
5
dsc.h
|
@ -154,6 +154,11 @@ public:
|
||||||
n = dest;
|
n = dest;
|
||||||
// and elemsAllocated is untouched, because we didn't resize
|
// 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) {
|
void MoveSelfInto(IdList<T,H> *l) {
|
||||||
memcpy(l, this, sizeof(*this));
|
memcpy(l, this, sizeof(*this));
|
||||||
|
|
|
@ -263,6 +263,8 @@ void GraphicsWindow::EnsureValidActives(void) {
|
||||||
CheckMenuById(MNU_SHOW_TEXT_WND, SS.GW.showTextWindow);
|
CheckMenuById(MNU_SHOW_TEXT_WND, SS.GW.showTextWindow);
|
||||||
|
|
||||||
CheckMenuById(MNU_SOLVE_AUTO, (SS.GW.solving == SOLVE_ALWAYS));
|
CheckMenuById(MNU_SOLVE_AUTO, (SS.GW.solving == SOLVE_ALWAYS));
|
||||||
|
|
||||||
|
if(change) SS.TW.Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GraphicsWindow::MenuEdit(int id) {
|
void GraphicsWindow::MenuEdit(int id) {
|
||||||
|
@ -287,18 +289,6 @@ void GraphicsWindow::MenuEdit(int id) {
|
||||||
}
|
}
|
||||||
if(r.v && !r.IsFromReferences()) {
|
if(r.v && !r.IsFromReferences()) {
|
||||||
SS.request.Tag(r, 1);
|
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) {
|
if(s->constraint.v) {
|
||||||
SS.constraint.Tag(s->constraint, 1);
|
SS.constraint.Tag(s->constraint, 1);
|
||||||
|
@ -307,9 +297,14 @@ void GraphicsWindow::MenuEdit(int id) {
|
||||||
SS.request.RemoveTagged();
|
SS.request.RemoveTagged();
|
||||||
SS.constraint.RemoveTagged();
|
SS.constraint.RemoveTagged();
|
||||||
|
|
||||||
SS.GenerateAll(SS.GW.solving == SOLVE_ALWAYS);
|
// Forget any mention of the just-deleted entity
|
||||||
SS.GW.ClearSelection();
|
SS.GW.ClearSelection();
|
||||||
SS.GW.hover.Clear();
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -814,6 +809,10 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MNU_RECTANGLE: {
|
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];
|
hRequest lns[4];
|
||||||
int i;
|
int i;
|
||||||
for(i = 0; i < 4; i++) {
|
for(i = 0; i < 4; i++) {
|
||||||
|
|
|
@ -137,7 +137,10 @@ Vector SContour::ComputeNormal(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SContour::IsClockwiseProjdToNormal(Vector n) {
|
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
|
// An arbitrary 2d coordinate system that has n as its normal
|
||||||
Vector u = n.Normal(0);
|
Vector u = n.Normal(0);
|
||||||
Vector v = n.Normal(1);
|
Vector v = n.Normal(1);
|
||||||
|
|
146
solvespace.cpp
146
solvespace.cpp
|
@ -17,9 +17,116 @@ void SolveSpace::Init(char *cmdLine) {
|
||||||
TW.Show();
|
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) {
|
void SolveSpace::GenerateAll(bool andSolve) {
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
|
while(PruneOrphans())
|
||||||
|
;
|
||||||
|
|
||||||
// Don't lose our numerical guesses when we regenerate.
|
// Don't lose our numerical guesses when we regenerate.
|
||||||
IdList<Param,hParam> prev;
|
IdList<Param,hParam> prev;
|
||||||
param.MoveSelfInto(&prev);
|
param.MoveSelfInto(&prev);
|
||||||
|
@ -34,15 +141,25 @@ void SolveSpace::GenerateAll(bool andSolve) {
|
||||||
for(i = 0; i < group.n; i++) {
|
for(i = 0; i < group.n; i++) {
|
||||||
Group *g = &(group.elem[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++) {
|
for(j = 0; j < request.n; j++) {
|
||||||
Request *r = &(request.elem[j]);
|
Request *r = &(request.elem[j]);
|
||||||
if(r->group.v != g->h.v) continue;
|
if(r->group.v != g->h.v) continue;
|
||||||
|
|
||||||
r->Generate(&entity, ¶m);
|
r->Generate(&entity, ¶m);
|
||||||
}
|
}
|
||||||
|
|
||||||
g->Generate(&entity, ¶m);
|
g->Generate(&entity, ¶m);
|
||||||
|
|
||||||
|
// 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
|
// Use the previous values for params that we've seen before, as
|
||||||
// initial guesses for the solver.
|
// initial guesses for the solver.
|
||||||
for(j = 0; j < param.n; j++) {
|
for(j = 0; j < param.n; j++) {
|
||||||
|
@ -66,6 +183,33 @@ void SolveSpace::GenerateAll(bool andSolve) {
|
||||||
|
|
||||||
prev.Clear();
|
prev.Clear();
|
||||||
InvalidateGraphics();
|
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(¶m);
|
||||||
|
// Try again
|
||||||
|
GenerateAll(andSolve);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SolveSpace::ForceReferences(void) {
|
void SolveSpace::ForceReferences(void) {
|
||||||
|
|
12
solvespace.h
12
solvespace.h
|
@ -204,6 +204,18 @@ public:
|
||||||
bool SaveToFile(char *filename);
|
bool SaveToFile(char *filename);
|
||||||
bool LoadFromFile(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);
|
void GenerateAll(bool andSolve);
|
||||||
bool SolveGroup(hGroup hg);
|
bool SolveGroup(hGroup hg);
|
||||||
|
|
|
@ -215,8 +215,6 @@ void TextWindow::ScreenNavigation(int link, DWORD v) {
|
||||||
void TextWindow::ShowHeader(void) {
|
void TextWindow::ShowHeader(void) {
|
||||||
ClearScreen();
|
ClearScreen();
|
||||||
|
|
||||||
SS.GW.EnsureValidActives();
|
|
||||||
|
|
||||||
char *cd = (SS.GW.activeWorkplane.v == Entity::FREE_IN_3D.v) ?
|
char *cd = (SS.GW.activeWorkplane.v == Entity::FREE_IN_3D.v) ?
|
||||||
"free in 3d" :
|
"free in 3d" :
|
||||||
SS.GetEntity(SS.GW.activeWorkplane)->DescriptionString();
|
SS.GetEntity(SS.GW.activeWorkplane)->DescriptionString();
|
||||||
|
|
Loading…
Reference in New Issue