2013-07-28 22:08:34 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Generate our model based on its parametric description, by solving each
|
|
|
|
// sketch, generating surfaces from the resulting entities, performing any
|
|
|
|
// requested surface operations (e.g. Booleans) with our model so far, and
|
|
|
|
// then repeating this process for each subsequent group.
|
|
|
|
//
|
|
|
|
// Copyright 2008-2013 Jonathan Westhues.
|
|
|
|
//-----------------------------------------------------------------------------
|
2008-07-08 07:45:47 +00:00
|
|
|
#include "solvespace.h"
|
|
|
|
|
|
|
|
void SolveSpace::MarkGroupDirtyByEntity(hEntity he) {
|
2009-04-19 05:53:16 +00:00
|
|
|
Entity *e = SK.GetEntity(he);
|
2008-07-08 07:45:47 +00:00
|
|
|
MarkGroupDirty(e->group);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SolveSpace::MarkGroupDirty(hGroup hg) {
|
|
|
|
int i;
|
|
|
|
bool go = false;
|
2009-04-19 05:53:16 +00:00
|
|
|
for(i = 0; i < SK.group.n; i++) {
|
|
|
|
Group *g = &(SK.group.elem[i]);
|
2008-07-08 07:45:47 +00:00
|
|
|
if(g->h.v == hg.v) {
|
|
|
|
go = true;
|
|
|
|
}
|
|
|
|
if(go) {
|
|
|
|
g->clean = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
unsaved = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SolveSpace::PruneOrphans(void) {
|
|
|
|
int i;
|
2009-04-19 05:53:16 +00:00
|
|
|
for(i = 0; i < SK.request.n; i++) {
|
|
|
|
Request *r = &(SK.request.elem[i]);
|
2008-07-08 07:45:47 +00:00
|
|
|
if(GroupExists(r->group)) continue;
|
|
|
|
|
|
|
|
(deleted.requests)++;
|
2009-04-19 05:53:16 +00:00
|
|
|
SK.request.RemoveById(r->h);
|
2008-07-08 07:45:47 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-04-19 05:53:16 +00:00
|
|
|
for(i = 0; i < SK.constraint.n; i++) {
|
|
|
|
Constraint *c = &(SK.constraint.elem[i]);
|
2008-07-08 07:45:47 +00:00
|
|
|
if(GroupExists(c->group)) continue;
|
|
|
|
|
|
|
|
(deleted.constraints)++;
|
2009-01-03 12:27:33 +00:00
|
|
|
(deleted.nonTrivialConstraints)++;
|
|
|
|
|
2009-04-19 05:53:16 +00:00
|
|
|
SK.constraint.RemoveById(c->h);
|
2008-07-08 07:45:47 +00:00
|
|
|
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;
|
2009-04-19 05:53:16 +00:00
|
|
|
for(i = 0; i < SK.group.n; i++) {
|
|
|
|
Group *g = &(SK.group.elem[i]);
|
2008-07-08 07:45:47 +00:00
|
|
|
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
|
2009-04-19 05:53:16 +00:00
|
|
|
return SK.group.FindByIdNoOops(hg) ? true : false;
|
2008-07-08 07:45:47 +00:00
|
|
|
}
|
|
|
|
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;
|
2009-04-19 05:53:16 +00:00
|
|
|
return SK.entity.FindByIdNoOops(he) ? true : false;
|
2008-07-08 07:45:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool SolveSpace::PruneGroups(hGroup hg) {
|
2009-04-19 05:53:16 +00:00
|
|
|
Group *g = SK.GetGroup(hg);
|
2008-07-08 07:45:47 +00:00
|
|
|
if(GroupsInOrder(g->opA, hg) &&
|
|
|
|
EntityExists(g->predef.origin) &&
|
|
|
|
EntityExists(g->predef.entityB) &&
|
|
|
|
EntityExists(g->predef.entityC))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
(deleted.groups)++;
|
2009-04-19 05:53:16 +00:00
|
|
|
SK.group.RemoveById(g->h);
|
2008-07-08 07:45:47 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SolveSpace::PruneRequests(hGroup hg) {
|
|
|
|
int i;
|
2009-04-19 05:53:16 +00:00
|
|
|
for(i = 0; i < SK.entity.n; i++) {
|
|
|
|
Entity *e = &(SK.entity.elem[i]);
|
2008-07-08 07:45:47 +00:00
|
|
|
if(e->group.v != hg.v) continue;
|
|
|
|
|
|
|
|
if(EntityExists(e->workplane)) continue;
|
|
|
|
|
|
|
|
if(!e->h.isFromRequest()) oops();
|
|
|
|
|
|
|
|
(deleted.requests)++;
|
2009-04-19 05:53:16 +00:00
|
|
|
SK.request.RemoveById(e->h.request());
|
2008-07-08 07:45:47 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SolveSpace::PruneConstraints(hGroup hg) {
|
|
|
|
int i;
|
2009-04-19 05:53:16 +00:00
|
|
|
for(i = 0; i < SK.constraint.n; i++) {
|
|
|
|
Constraint *c = &(SK.constraint.elem[i]);
|
2008-07-08 07:45:47 +00:00
|
|
|
if(c->group.v != hg.v) continue;
|
|
|
|
|
|
|
|
if(EntityExists(c->workplane) &&
|
|
|
|
EntityExists(c->ptA) &&
|
|
|
|
EntityExists(c->ptB) &&
|
|
|
|
EntityExists(c->entityA) &&
|
2008-07-20 12:24:43 +00:00
|
|
|
EntityExists(c->entityB) &&
|
|
|
|
EntityExists(c->entityC) &&
|
|
|
|
EntityExists(c->entityD))
|
2008-07-08 07:45:47 +00:00
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
(deleted.constraints)++;
|
2009-01-03 12:27:33 +00:00
|
|
|
if(c->type != Constraint::POINTS_COINCIDENT &&
|
|
|
|
c->type != Constraint::HORIZONTAL &&
|
|
|
|
c->type != Constraint::VERTICAL)
|
|
|
|
{
|
|
|
|
(deleted.nonTrivialConstraints)++;
|
|
|
|
}
|
|
|
|
|
2009-04-19 05:53:16 +00:00
|
|
|
SK.constraint.RemoveById(c->h);
|
2008-07-08 07:45:47 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SolveSpace::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.
|
2009-04-19 05:53:16 +00:00
|
|
|
for(i = 0; i < SK.group.n; i++) {
|
|
|
|
Group *g = &(SK.group.elem[i]);
|
2008-02-07 09:53:52 +00:00
|
|
|
g->order = i;
|
2009-04-20 07:30:09 +00:00
|
|
|
if((!g->clean) || (g->solved.how != System::SOLVED_OKAY)) {
|
2008-07-08 07:45:47 +00:00
|
|
|
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(-1, -1);
|
|
|
|
} else {
|
2009-12-15 12:26:22 +00:00
|
|
|
SS.nakedEdges.Clear();
|
2008-07-08 07:45:47 +00:00
|
|
|
GenerateAll(firstDirty, lastVisible);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-04 12:01:46 +00:00
|
|
|
void SolveSpace::GenerateAll(int first, int last, bool andFindFree) {
|
2008-07-08 07:45:47 +00:00
|
|
|
int i, j;
|
|
|
|
|
2008-07-20 11:27:22 +00:00
|
|
|
// Remove any requests or constraints that refer to a nonexistent
|
|
|
|
// group; can check those immediately, since we know what the list
|
|
|
|
// of groups should be.
|
2008-07-08 07:45:47 +00:00
|
|
|
while(PruneOrphans())
|
|
|
|
;
|
|
|
|
|
|
|
|
// Don't lose our numerical guesses when we regenerate.
|
|
|
|
IdList<Param,hParam> prev;
|
2009-04-19 05:53:16 +00:00
|
|
|
SK.param.MoveSelfInto(&prev);
|
|
|
|
SK.entity.Clear();
|
2008-07-08 07:45:47 +00:00
|
|
|
|
2013-10-28 04:28:39 +00:00
|
|
|
int64_t inTime = GetMilliseconds();
|
2009-06-14 04:36:38 +00:00
|
|
|
|
|
|
|
bool displayedStatusMessage = false;
|
2009-04-19 05:53:16 +00:00
|
|
|
for(i = 0; i < SK.group.n; i++) {
|
|
|
|
Group *g = &(SK.group.elem[i]);
|
2008-07-08 07:45:47 +00:00
|
|
|
|
2013-10-28 04:28:39 +00:00
|
|
|
int64_t now = GetMilliseconds();
|
2009-06-14 04:36:38 +00:00
|
|
|
// 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)) ||
|
|
|
|
displayedStatusMessage)
|
|
|
|
{
|
|
|
|
displayedStatusMessage = true;
|
|
|
|
char msg[1024];
|
|
|
|
sprintf(msg, "generating group %d/%d", i, SK.group.n);
|
|
|
|
|
|
|
|
int w, h;
|
|
|
|
GetGraphicsWindowSize(&w, &h);
|
|
|
|
glDrawBuffer(GL_FRONT);
|
|
|
|
glViewport(0, 0, w, h);
|
|
|
|
glLoadIdentity();
|
|
|
|
glTranslated(-1, 1, 0);
|
|
|
|
glScaled(2.0/w, 2.0/h, 1.0);
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
|
|
|
|
double left = 80, top = -20, width = 240, height = 24;
|
|
|
|
glColor3d(0.9, 0.8, 0.8);
|
2013-10-22 04:45:06 +00:00
|
|
|
ssglAxisAlignedQuad(left, left+width, top, top-height);
|
2015-03-22 13:39:12 +00:00
|
|
|
ssglLineWidth(1);
|
2009-06-14 04:36:38 +00:00
|
|
|
glColor3d(0.0, 0.0, 0.0);
|
2013-10-22 04:45:06 +00:00
|
|
|
ssglAxisAlignedLineLoop(left, left+width, top, top-height);
|
2009-06-14 04:36:38 +00:00
|
|
|
|
2013-10-22 04:45:06 +00:00
|
|
|
ssglCreateBitmapFont();
|
2009-06-14 04:36:38 +00:00
|
|
|
glColor3d(0, 0, 0);
|
|
|
|
glPushMatrix();
|
2010-04-26 07:52:49 +00:00
|
|
|
glTranslated(left+8, top-20, 0);
|
|
|
|
glScaled(1, -1, 1);
|
2013-10-22 04:45:06 +00:00
|
|
|
ssglBitmapText(msg, Vector::From(0, 0, 0));
|
2009-06-14 04:36:38 +00:00
|
|
|
glPopMatrix();
|
|
|
|
glFlush();
|
|
|
|
glDrawBuffer(GL_BACK);
|
|
|
|
}
|
|
|
|
|
2008-07-08 07:45:47 +00:00
|
|
|
// 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;
|
|
|
|
|
2009-04-19 05:53:16 +00:00
|
|
|
for(j = 0; j < SK.request.n; j++) {
|
|
|
|
Request *r = &(SK.request.elem[j]);
|
2008-07-08 07:45:47 +00:00
|
|
|
if(r->group.v != g->h.v) continue;
|
|
|
|
|
2009-04-19 05:53:16 +00:00
|
|
|
r->Generate(&(SK.entity), &(SK.param));
|
2008-07-08 07:45:47 +00:00
|
|
|
}
|
2009-04-19 05:53:16 +00:00
|
|
|
g->Generate(&(SK.entity), &(SK.param));
|
2008-07-08 07:45:47 +00:00
|
|
|
|
|
|
|
// 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.
|
2009-04-19 05:53:16 +00:00
|
|
|
for(j = 0; j < SK.param.n; j++) {
|
|
|
|
Param *newp = &(SK.param.elem[j]);
|
2008-07-08 07:45:47 +00:00
|
|
|
if(newp->known) continue;
|
|
|
|
|
|
|
|
Param *prevp = prev.FindByIdNoOops(newp->h);
|
|
|
|
if(prevp) newp->val = prevp->val;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(g->h.v == Group::HGROUP_REFERENCES.v) {
|
|
|
|
ForceReferences();
|
2009-04-20 07:30:09 +00:00
|
|
|
g->solved.how = System::SOLVED_OKAY;
|
2008-07-08 07:45:47 +00:00
|
|
|
g->clean = true;
|
|
|
|
} else {
|
|
|
|
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.
|
2009-01-04 12:01:46 +00:00
|
|
|
SolveGroup(g->h, andFindFree);
|
2009-01-19 03:33:15 +00:00
|
|
|
g->GenerateLoops();
|
2009-01-23 03:30:30 +00:00
|
|
|
g->GenerateShellAndMesh();
|
2008-07-08 07:45:47 +00:00
|
|
|
g->clean = true;
|
|
|
|
} else {
|
|
|
|
// The group falls outside the range, so just assume that
|
|
|
|
// it's good wherever we left it. The mesh is unchanged,
|
|
|
|
// and the parameters must be marked as known.
|
2009-04-19 05:53:16 +00:00
|
|
|
for(j = 0; j < SK.param.n; j++) {
|
|
|
|
Param *newp = &(SK.param.elem[j]);
|
2008-07-08 07:45:47 +00:00
|
|
|
|
|
|
|
Param *prevp = prev.FindByIdNoOops(newp->h);
|
|
|
|
if(prevp) newp->known = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// And update any reference dimensions with their new values
|
2009-04-19 05:53:16 +00:00
|
|
|
for(i = 0; i < SK.constraint.n; i++) {
|
|
|
|
Constraint *c = &(SK.constraint.elem[i]);
|
2008-07-08 07:45:47 +00:00
|
|
|
if(c->reference) {
|
|
|
|
c->ModifyToSatisfy();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-07-20 11:27:22 +00:00
|
|
|
// Make sure the point that we're tracing exists.
|
2009-04-19 05:53:16 +00:00
|
|
|
if(traced.point.v && !SK.entity.FindByIdNoOops(traced.point)) {
|
2008-07-20 11:27:22 +00:00
|
|
|
traced.point = Entity::NO_ENTITY;
|
|
|
|
}
|
|
|
|
// And if we're tracing a point, add its new value to the path
|
|
|
|
if(traced.point.v) {
|
2009-04-19 05:53:16 +00:00
|
|
|
Entity *pt = SK.GetEntity(traced.point);
|
2008-07-20 11:27:22 +00:00
|
|
|
traced.path.AddPoint(pt->PointGetNum());
|
|
|
|
}
|
|
|
|
|
2008-07-08 07:45:47 +00:00
|
|
|
prev.Clear();
|
|
|
|
InvalidateGraphics();
|
|
|
|
|
|
|
|
// Remove nonexistent selection items, for same reason we waited till
|
|
|
|
// the end to put up a dialog box.
|
|
|
|
GW.ClearNonexistentSelectionItems();
|
|
|
|
|
|
|
|
if(deleted.requests > 0 || deleted.constraints > 0 || deleted.groups > 0) {
|
|
|
|
// All sorts of interesting things could have happened; for example,
|
|
|
|
// the active group or active workplane could have been deleted. So
|
|
|
|
// clear all that out.
|
|
|
|
if(deleted.groups > 0) {
|
|
|
|
SS.TW.ClearSuper();
|
|
|
|
}
|
|
|
|
later.showTW = true;
|
|
|
|
GW.ClearSuper();
|
2009-01-03 12:27:33 +00:00
|
|
|
|
|
|
|
// People get annoyed if I complain whenever they delete any request,
|
|
|
|
// and I otherwise will, since those always come with pt-coincident
|
|
|
|
// constraints.
|
|
|
|
if(deleted.requests > 0 || deleted.nonTrivialConstraints > 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.
|
2010-06-14 04:42:47 +00:00
|
|
|
Message("Additional sketch elements were deleted, because they "
|
|
|
|
"depend on the element that was just deleted explicitly. "
|
|
|
|
"These include: \n"
|
|
|
|
" %d request%s\n"
|
|
|
|
" %d constraint%s\n"
|
|
|
|
" %d group%s\n\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");
|
2009-01-03 12:27:33 +00:00
|
|
|
}
|
2008-07-08 07:45:47 +00:00
|
|
|
memset(&deleted, 0, sizeof(deleted));
|
|
|
|
}
|
2015-03-29 00:30:52 +00:00
|
|
|
|
2008-07-08 07:45:47 +00:00
|
|
|
FreeAllTemporary();
|
|
|
|
allConsistent = true;
|
|
|
|
return;
|
|
|
|
|
|
|
|
pruned:
|
|
|
|
// Restore the numerical guesses
|
2009-04-19 05:53:16 +00:00
|
|
|
SK.param.Clear();
|
|
|
|
prev.MoveSelfInto(&(SK.param));
|
2008-07-08 07:45:47 +00:00
|
|
|
// Try again
|
|
|
|
GenerateAll(first, last);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SolveSpace::ForceReferences(void) {
|
2010-05-10 01:06:09 +00:00
|
|
|
// Force the values of the parameters that define the three reference
|
2008-07-08 07:45:47 +00:00
|
|
|
// coordinate systems.
|
|
|
|
static const struct {
|
|
|
|
hRequest hr;
|
|
|
|
Quaternion q;
|
|
|
|
} Quat[] = {
|
|
|
|
{ Request::HREQUEST_REFERENCE_XY, { 1, 0, 0, 0, } },
|
|
|
|
{ Request::HREQUEST_REFERENCE_YZ, { 0.5, 0.5, 0.5, 0.5, } },
|
|
|
|
{ Request::HREQUEST_REFERENCE_ZX, { 0.5, -0.5, -0.5, -0.5, } },
|
|
|
|
};
|
|
|
|
for(int i = 0; i < 3; i++) {
|
|
|
|
hRequest hr = Quat[i].hr;
|
2009-04-19 05:53:16 +00:00
|
|
|
Entity *wrkpl = SK.GetEntity(hr.entity(0));
|
2008-07-08 07:45:47 +00:00
|
|
|
// The origin for our coordinate system, always zero
|
2009-04-19 05:53:16 +00:00
|
|
|
Entity *origin = SK.GetEntity(wrkpl->point[0]);
|
2008-07-08 07:45:47 +00:00
|
|
|
origin->PointForceTo(Vector::From(0, 0, 0));
|
2009-04-19 05:53:16 +00:00
|
|
|
SK.GetParam(origin->param[0])->known = true;
|
|
|
|
SK.GetParam(origin->param[1])->known = true;
|
|
|
|
SK.GetParam(origin->param[2])->known = true;
|
2008-07-08 07:45:47 +00:00
|
|
|
// The quaternion that defines the rotation, from the table.
|
2015-03-29 00:30:52 +00:00
|
|
|
Entity *normal = SK.GetEntity(wrkpl->normal);
|
2008-07-08 07:45:47 +00:00
|
|
|
normal->NormalForceTo(Quat[i].q);
|
2009-04-19 05:53:16 +00:00
|
|
|
SK.GetParam(normal->param[0])->known = true;
|
|
|
|
SK.GetParam(normal->param[1])->known = true;
|
|
|
|
SK.GetParam(normal->param[2])->known = true;
|
|
|
|
SK.GetParam(normal->param[3])->known = true;
|
2008-07-08 07:45:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-20 07:30:09 +00:00
|
|
|
void SolveSpace::MarkDraggedParams(void) {
|
2009-11-03 18:54:49 +00:00
|
|
|
sys.dragged.Clear();
|
|
|
|
|
|
|
|
for(int i = -1; i < SS.GW.pending.points.n; i++) {
|
|
|
|
hEntity hp;
|
|
|
|
if(i == -1) {
|
|
|
|
hp = SS.GW.pending.point;
|
|
|
|
} else {
|
|
|
|
hp = SS.GW.pending.points.elem[i];
|
|
|
|
}
|
|
|
|
if(!hp.v) continue;
|
2009-04-20 07:30:09 +00:00
|
|
|
|
|
|
|
// The pending point could be one in a group that has not yet
|
|
|
|
// been processed, in which case the lookup will fail; but
|
|
|
|
// that's not an error.
|
2009-11-03 18:54:49 +00:00
|
|
|
Entity *pt = SK.entity.FindByIdNoOops(hp);
|
2009-04-20 07:30:09 +00:00
|
|
|
if(pt) {
|
|
|
|
switch(pt->type) {
|
|
|
|
case Entity::POINT_N_TRANS:
|
|
|
|
case Entity::POINT_IN_3D:
|
2009-11-03 18:54:49 +00:00
|
|
|
sys.dragged.Add(&(pt->param[0]));
|
|
|
|
sys.dragged.Add(&(pt->param[1]));
|
|
|
|
sys.dragged.Add(&(pt->param[2]));
|
2009-04-20 07:30:09 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Entity::POINT_IN_2D:
|
2009-11-03 18:54:49 +00:00
|
|
|
sys.dragged.Add(&(pt->param[0]));
|
|
|
|
sys.dragged.Add(&(pt->param[1]));
|
2009-04-20 07:30:09 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(SS.GW.pending.circle.v) {
|
|
|
|
Entity *circ = SK.entity.FindByIdNoOops(SS.GW.pending.circle);
|
|
|
|
if(circ) {
|
|
|
|
Entity *dist = SK.GetEntity(circ->distance);
|
|
|
|
switch(dist->type) {
|
|
|
|
case Entity::DISTANCE:
|
2009-11-03 18:54:49 +00:00
|
|
|
sys.dragged.Add(&(dist->param[0]));
|
2009-04-20 07:30:09 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(SS.GW.pending.normal.v) {
|
|
|
|
Entity *norm = SK.entity.FindByIdNoOops(SS.GW.pending.normal);
|
|
|
|
if(norm) {
|
|
|
|
switch(norm->type) {
|
|
|
|
case Entity::NORMAL_IN_3D:
|
2009-11-03 18:54:49 +00:00
|
|
|
sys.dragged.Add(&(norm->param[0]));
|
|
|
|
sys.dragged.Add(&(norm->param[1]));
|
|
|
|
sys.dragged.Add(&(norm->param[2]));
|
|
|
|
sys.dragged.Add(&(norm->param[3]));
|
2009-04-20 07:30:09 +00:00
|
|
|
break;
|
|
|
|
// other types are locked, so not draggable
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-04 12:01:46 +00:00
|
|
|
void SolveSpace::SolveGroup(hGroup hg, bool andFindFree) {
|
2008-07-08 07:45:47 +00:00
|
|
|
int i;
|
|
|
|
// Clear out the system to be solved.
|
|
|
|
sys.entity.Clear();
|
|
|
|
sys.param.Clear();
|
|
|
|
sys.eq.Clear();
|
|
|
|
// And generate all the params for requests in this group
|
2009-04-19 05:53:16 +00:00
|
|
|
for(i = 0; i < SK.request.n; i++) {
|
|
|
|
Request *r = &(SK.request.elem[i]);
|
2008-07-08 07:45:47 +00:00
|
|
|
if(r->group.v != hg.v) continue;
|
|
|
|
|
|
|
|
r->Generate(&(sys.entity), &(sys.param));
|
|
|
|
}
|
|
|
|
// And for the group itself
|
2009-04-19 05:53:16 +00:00
|
|
|
Group *g = SK.GetGroup(hg);
|
2008-07-08 07:45:47 +00:00
|
|
|
g->Generate(&(sys.entity), &(sys.param));
|
|
|
|
// Set the initial guesses for all the params
|
|
|
|
for(i = 0; i < sys.param.n; i++) {
|
|
|
|
Param *p = &(sys.param.elem[i]);
|
|
|
|
p->known = false;
|
2009-04-19 05:53:16 +00:00
|
|
|
p->val = SK.GetParam(p->h)->val;
|
2008-07-08 07:45:47 +00:00
|
|
|
}
|
|
|
|
|
2009-04-20 07:30:09 +00:00
|
|
|
MarkDraggedParams();
|
|
|
|
g->solved.remove.Clear();
|
|
|
|
int how = sys.Solve(g, &(g->solved.dof),
|
2009-04-21 07:56:17 +00:00
|
|
|
&(g->solved.remove), true, andFindFree);
|
2009-04-20 07:30:09 +00:00
|
|
|
if((how != System::SOLVED_OKAY) ||
|
|
|
|
(how == System::SOLVED_OKAY && g->solved.how != System::SOLVED_OKAY))
|
|
|
|
{
|
|
|
|
TextWindow::ReportHowGroupSolved(g->h);
|
|
|
|
}
|
|
|
|
g->solved.how = how;
|
2008-07-08 07:45:47 +00:00
|
|
|
FreeAllTemporary();
|
|
|
|
}
|
|
|
|
|
2008-07-20 11:27:22 +00:00
|
|
|
bool SolveSpace::AllGroupsOkay(void) {
|
|
|
|
int i;
|
|
|
|
bool allOk = true;
|
2009-04-19 05:53:16 +00:00
|
|
|
for(i = 0; i < SK.group.n; i++) {
|
2009-04-20 07:30:09 +00:00
|
|
|
if(SK.group.elem[i].solved.how != System::SOLVED_OKAY) {
|
2008-07-20 11:27:22 +00:00
|
|
|
allOk = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return allOk;
|
|
|
|
}
|
|
|
|
|