Bits and pieces; option to not include original in step translates

and rotates, auto-constrain translates in active workplane, speed
up remap list search with a hash table, other stuff.

[git-p4: depot-paths = "//depot/solvespace/": change = 1786]
solver
Jonathan Westhues 2008-06-11 20:36:33 -08:00
parent 83f741bd06
commit 8969687904
12 changed files with 165 additions and 34 deletions

View File

@ -548,6 +548,11 @@ void GraphicsWindow::MouseLeftDoubleClick(double mx, double my) {
ClearSuper();
Constraint *c = SS.GetConstraint(constraintBeingEdited);
if(c->reference) {
// Not meaningful to edit a reference dimension
return;
}
Vector p3 = c->GetLabelPos();
Point2d p2 = ProjectPoint(p3);
ShowGraphicsEditControl((int)p2.x, (int)p2.y, c->exprA->Print());

18
dsc.h
View File

@ -106,15 +106,21 @@ public:
elem = (T *)MemRealloc(elem, elemsAllocated*sizeof(elem[0]));
}
int i = 0;
if(n == 0 || elem[n-1].h.v < t->h.v) {
i = n;
int first = 0, last = n;
// We know that we must insert within the closed interval [first,last]
while(first != last) {
int mid = (first + last)/2;
H hm = elem[mid].h;
if(hm.v > t->h.v) {
last = mid;
} else if(hm.v < t->h.v) {
first = mid + 1;
} else {
while(i < n && elem[i].h.v < t->h.v) {
i++;
oops();
}
}
if(i < n && elem[i].h.v == t->h.v) oops();
int i = first;
memmove(elem+i+1, elem+i, (n-i)*sizeof(elem[0]));
elem[i] = *t;
n++;

View File

@ -680,6 +680,6 @@ void Entity::CalculateNumerical(void) {
Vector n = FaceGetNormalNum();
numNormal = Quaternion::From(0, n.x, n.y, n.z);
}
visible = IsVisible();
actVisible = IsVisible();
}

View File

@ -68,6 +68,7 @@ const SolveSpace::SaveTable SolveSpace::SAVED[] = {
{ 'g', "Group.exprA", 'E', &(SS.sv.g.exprA) },
{ 'g', "Group.color", 'x', &(SS.sv.g.color) },
{ 'g', "Group.subtype", 'd', &(SS.sv.g.subtype) },
{ 'g', "Group.skipFirst", 'b', &(SS.sv.g.skipFirst) },
{ 'g', "Group.meshCombine", 'd', &(SS.sv.g.meshCombine) },
{ 'g', "Group.predef.q.w", 'f', &(SS.sv.g.predef.q.w) },
{ 'g', "Group.predef.q.vx", 'f', &(SS.sv.g.predef.q.vx) },
@ -94,7 +95,6 @@ const SolveSpace::SaveTable SolveSpace::SAVED[] = {
{ 'e', "Entity.h.v", 'x', &(SS.sv.e.h.v) },
{ 'e', "Entity.type", 'd', &(SS.sv.e.type) },
{ 'e', "Entity.visible", 'b', &(SS.sv.e.visible) },
{ 'e', "Entity.group.v", 'x', &(SS.sv.e.group.v) },
{ 'e', "Entity.construction", 'b', &(SS.sv.e.construction) },
{ 'e', "Entity.param[0].v", 'x', &(SS.sv.e.param[0].v) },
@ -127,6 +127,7 @@ const SolveSpace::SaveTable SolveSpace::SAVED[] = {
{ 'e', "Entity.actNormal.vy", 'f', &(SS.sv.e.actNormal.vy) },
{ 'e', "Entity.actNormal.vz", 'f', &(SS.sv.e.actNormal.vz) },
{ 'e', "Entity.actDistance", 'f', &(SS.sv.e.actDistance) },
{ 'e', "Entity.actVisible", 'b', &(SS.sv.e.actVisible), },
{ 'c', "Constraint.h.v", 'x', &(SS.sv.c.h.v) },

View File

@ -130,6 +130,8 @@ void Group::MenuGroup(int id) {
g.opA = SS.GW.activeGroup;
g.exprA = Expr::From(3)->DeepCopyKeep();
g.subtype = ONE_SIDED;
g.predef.entityB = SS.GW.ActiveWorkplane();
g.activeWorkplane = SS.GW.ActiveWorkplane();
g.name.strcpy("translate");
break;
@ -294,8 +296,12 @@ void Group::Generate(IdList<Entity,hEntity> *entity,
AddParam(param, h.param(1), gp.y);
AddParam(param, h.param(2), gp.z);
int n = (int)(exprA->Eval());
for(a = 0; a < n; a++) {
int n = (int)(exprA->Eval()), a0 = 0;
if(subtype == ONE_SIDED && skipFirst) {
a0++; n++;
}
for(a = a0; a < n; a++) {
for(i = 0; i < entity->n; i++) {
Entity *e = &(entity->elem[i]);
if(e->group.v != opA.v) continue;
@ -322,8 +328,12 @@ void Group::Generate(IdList<Entity,hEntity> *entity,
AddParam(param, h.param(5), gn.y);
AddParam(param, h.param(6), gn.z);
int n = (int)(exprA->Eval());
for(a = 0; a < n; a++) {
int n = (int)(exprA->Eval()), a0 = 0;
if(subtype == ONE_SIDED && skipFirst) {
a0++; n++;
}
for(a = a0; a < n; a++) {
for(i = 0; i < entity->n; i++) {
Entity *e = &(entity->elem[i]);
if(e->group.v != opA.v) continue;
@ -352,7 +362,6 @@ void Group::Generate(IdList<Entity,hEntity> *entity,
for(i = 0; i < impEntity.n; i++) {
Entity *ie = &(impEntity.elem[i]);
CopyEntity(entity, ie, 0, 0,
h.param(0), h.param(1), h.param(2),
h.param(3), h.param(4), h.param(5), h.param(6),
@ -408,19 +417,39 @@ void Group::GenerateEquations(IdList<Equation,hEquation> *l) {
AddEq(l, u.Dot(extruden), 0);
AddEq(l, v.Dot(extruden), 1);
}
} else if(type == TRANSLATE) {
if(predef.entityB.v != Entity::FREE_IN_3D.v) {
Entity *w = SS.GetEntity(predef.entityB);
ExprVector n = w->Normal()->NormalExprsN();
ExprVector trans;
trans = ExprVector::From(h.param(0), h.param(1), h.param(2));
// The translation vector is parallel to the workplane
AddEq(l, trans.Dot(n), 0);
}
}
}
hEntity Group::Remap(hEntity in, int copyNumber) {
int i;
// A hash table is used to accelerate the search
int hash = ((unsigned)(in.v*61 + copyNumber)) % REMAP_PRIME;
int i = remapCache[hash];
if(i >= 0 && i < remap.n) {
EntityMap *em = &(remap.elem[i]);
if(em->input.v == in.v && em->copyNumber == copyNumber) {
return h.entity(em->h.v);
}
}
// but if we don't find it in the hash table, then linear search
for(i = 0; i < remap.n; i++) {
EntityMap *em = &(remap.elem[i]);
if(em->input.v == in.v && em->copyNumber == copyNumber) {
// We already have a mapping for this entity.
remapCache[hash] = i;
return h.entity(em->h.v);
}
}
// We don't have a mapping yet, so create one.
// And if we still don't find it, then create a new entry.
EntityMap em;
em.input = in;
em.copyNumber = copyNumber;

View File

@ -18,11 +18,17 @@ void Group::GeneratePolygon(void) {
}
SEdge error;
if(edges.AssemblePolygon(&poly, &error)) {
polyError.yes = false;
polyError.how = POLY_GOOD;
poly.normal = poly.ComputeNormal();
poly.FixContourDirections();
if(!poly.AllPointsInPlane(&(polyError.notCoplanarAt))) {
// The edges aren't all coplanar; so not a good polygon
polyError.how = POLY_NOT_COPLANAR;
poly.Clear();
}
} else {
polyError.yes = true;
polyError.how = POLY_NOT_CLOSED;
polyError.notClosedAt = error;
poly.Clear();
}
@ -279,8 +285,10 @@ void Group::Draw(void) {
if(SS.GW.showMesh) glxDebugMesh(&mesh);
// And finally show the polygons too
if(!SS.GW.showShaded) return;
if(polyError.yes) {
if(polyError.how == POLY_NOT_CLOSED) {
glDisable(GL_DEPTH_TEST);
glxColor4d(1, 0, 0, 0.2);
glLineWidth(10);
glBegin(GL_LINES);
@ -294,6 +302,16 @@ void Group::Draw(void) {
glxOntoWorkplane(SS.GW.projRight, SS.GW.projUp);
glxWriteText("not closed contour!");
glPopMatrix();
glEnable(GL_DEPTH_TEST);
} else if(polyError.how == POLY_NOT_COPLANAR) {
glDisable(GL_DEPTH_TEST);
glxColor3d(1, 0, 0);
glPushMatrix();
glxTranslatev(polyError.notCoplanarAt);
glxOntoWorkplane(SS.GW.projRight, SS.GW.projUp);
glxWriteText("points not all coplanar!");
glPopMatrix();
glEnable(GL_DEPTH_TEST);
} else {
glxColor4d(0, 0.1, 0.1, 0.5);
glPolygonOffset(-1, -1);

View File

@ -179,6 +179,18 @@ bool SContour::ContainsPointProjdToNormal(Vector n, Vector p) {
return inside;
}
bool SContour::AllPointsInPlane(Vector n, double d, Vector *notCoplanarAt) {
for(int i = 0; i < l.n; i++) {
Vector p = l.elem[i].p;
double dd = n.Dot(p) - d;
if(fabs(dd) > 10*LENGTH_EPS) {
*notCoplanarAt = p;
return false;
}
}
return true;
}
void SContour::Reverse(void) {
int i;
for(i = 0; i < (l.n / 2); i++) {
@ -263,6 +275,20 @@ void SPolygon::FixContourDirections(void) {
}
}
bool SPolygon::AllPointsInPlane(Vector *notCoplanarAt) {
if(l.n == 0 || l.elem[0].l.n == 0) return true;
Vector p0 = l.elem[0].l.elem[0].p;
double d = normal.Dot(p0);
for(int i = 0; i < l.n; i++) {
if(!(l.elem[i]).AllPointsInPlane(normal, d, notCoplanarAt)) {
return false;
}
}
return true;
}
static int TriMode, TriVertexCount;
static Vector Tri1, TriNMinus1, TriNMinus2;
static Vector TriNormal;

View File

@ -84,6 +84,7 @@ public:
Vector ComputeNormal(void);
bool IsClockwiseProjdToNormal(Vector n);
bool ContainsPointProjdToNormal(Vector n, Vector p);
bool AllPointsInPlane(Vector n, double d, Vector *notCoplanarAt);
};
class SPolygon {
@ -99,6 +100,7 @@ public:
void FixContourDirections(void);
void TriangulateInto(SMesh *m);
void Clear(void);
bool AllPointsInPlane(Vector *notCoplanarAt);
};
typedef struct {

View File

@ -108,6 +108,8 @@ public:
static const int TWO_SIDED = 7001;
int subtype;
bool skipFirst; // for step and repeat ops
struct {
Quaternion q;
Vector p;
@ -120,10 +122,15 @@ public:
} predef;
SPolygon poly;
static const int POLY_GOOD = 0;
static const int POLY_NOT_CLOSED = 1;
static const int POLY_NOT_COPLANAR = 2;
struct {
int how;
SEdge notClosedAt;
bool yes;
Vector notCoplanarAt;
} polyError;
SMesh mesh;
struct {
SMesh interferesAt;
@ -136,6 +143,8 @@ public:
int meshCombine;
IdList<EntityMap,EntityId> remap;
static const int REMAP_PRIME = 19477;
int remapCache[REMAP_PRIME];
char impFile[MAX_PATH];
SMesh impMesh;
@ -272,8 +281,6 @@ public:
double numDistance;
// and a bit more state that the faces need
Vector numVector;
// and the shown state also gets saved here, for later import
bool visible;
// All points/normals/distances have their numerical value; this is
// a convenience, to simplify the import/assembly code, so that the
@ -281,6 +288,8 @@ public:
Vector actPoint;
Quaternion actNormal;
double actDistance;
// and the shown state also gets saved here, for later import
bool actVisible;
hGroup group;
hEntity workplane; // or Entity::FREE_IN_3D

View File

@ -560,6 +560,15 @@ void TextWindow::ScreenChangeOneOrTwoSides(int link, DWORD v) {
SS.GenerateAll();
SS.GW.ClearSuper();
}
void TextWindow::ScreenChangeSkipFirst(int link, DWORD v) {
SS.UndoRemember();
Group *g = SS.GetGroup(SS.TW.shown->group);
(g->skipFirst) = !(g->skipFirst);
SS.MarkGroupDirty(g->h);
SS.GenerateAll();
SS.GW.ClearSuper();
}
void TextWindow::ScreenChangeMeshCombine(int link, DWORD v) {
SS.UndoRemember();
@ -581,7 +590,11 @@ void TextWindow::ScreenColor(int link, DWORD v) {
}
void TextWindow::ScreenChangeExprA(int link, DWORD v) {
Group *g = SS.GetGroup(SS.TW.shown->group);
ShowTextEditControl(13, 10, g->exprA->Print());
// There's an extra line for the skipFirst parameter in one-sided groups.
int r = (g->subtype == Group::ONE_SIDED) ? 15 : 13;
ShowTextEditControl(r, 9, g->exprA->Print());
SS.TW.edit.meaning = EDIT_TIMES_REPEATED;
SS.TW.edit.group.v = v;
}
@ -608,7 +621,7 @@ void TextWindow::ScreenDeleteGroup(int link, DWORD v) {
}
void TextWindow::ShowGroupInfo(void) {
Group *g = SS.group.FindById(shown->group);
char *s, *s2;
char *s, *s2, *s3;
if(shown->group.v == Group::HGROUP_REFERENCES.v) {
Printf(true, "%FtGROUP %E%s", g->DescriptionString());
@ -629,9 +642,11 @@ void TextWindow::ShowGroupInfo(void) {
} else if(g->type == Group::TRANSLATE) {
s = "TRANSLATE";
s2 ="REPEAT ";
s3 ="START ";
} else if(g->type == Group::ROTATE) {
s = "ROTATE";
s2 ="REPEAT";
s = "ROTATE ";
s2 ="REPEAT ";
s3 ="START ";
}
if(g->type == Group::EXTRUDE || g->type == Group::ROTATE ||
@ -649,8 +664,22 @@ void TextWindow::ShowGroupInfo(void) {
}
if(g->type == Group::ROTATE || g->type == Group::TRANSLATE) {
bool space;
if(g->subtype == Group::ONE_SIDED) {
bool skip = g->skipFirst;
Printf(true, "%Ft%s%E %Fh%f%Ll%s%E%Fs%s%E / %Fh%f%Ll%s%E%Fs%s%E",
s3,
&ScreenChangeSkipFirst,
(!skip ? "" : "with original"), (!skip ? "with original" : ""),
&ScreenChangeSkipFirst,
(skip ? "":"with copy #1"), (skip ? "with copy #1":""));
space = false;
} else {
space = true;
}
int times = (int)(g->exprA->Eval());
Printf(true, "%Ft%s%E %d time%s %Fl%Ll%D%f[change]%E",
Printf(space, "%Ft%s%E %d time%s %Fl%Ll%D%f[change]%E",
s2, times, times == 1 ? "" : "s",
g->h.v, &TextWindow::ScreenChangeExprA);
}
@ -695,7 +724,14 @@ void TextWindow::ShowGroupInfo(void) {
0x80000000 | SS.modelColor[7], 7, &TextWindow::ScreenColor);
}
// Leave more space if the group has configuration stuff above the req/
// constraint list (as all but the drawing groups do).
if(g->type == Group::DRAWING_3D || g->type == Group::DRAWING_WORKPLANE) {
Printf(true, "%Ftrequests in group");
} else {
Printf(false, "");
Printf(false, "%Ftrequests in group");
}
int i, a = 0;
for(i = 0; i < SS.request.n; i++) {

1
ui.h
View File

@ -100,6 +100,7 @@ public:
static void ScreenUnselectAll(int link, DWORD v);
static void ScreenChangeOneOrTwoSides(int link, DWORD v);
static void ScreenChangeSkipFirst(int link, DWORD v);
static void ScreenChangeMeshCombine(int link, DWORD v);
static void ScreenColor(int link, DWORD v);

View File

@ -1,15 +1,13 @@
STL check for meshes, and T intersection removal
STL export
better triangle combining (Simplify()) for meshes
DXF export
compress file format (binary?)
partitioned subsystems in the solver
TTF font text
display with proper formatting/units
more measurements
some kind of rounding / chamfer
auto-constrain translate in then-active workplane
remove back button in browser?
clean up user-created workplanes
incremental regen of entities?