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(); ClearSuper();
Constraint *c = SS.GetConstraint(constraintBeingEdited); Constraint *c = SS.GetConstraint(constraintBeingEdited);
if(c->reference) {
// Not meaningful to edit a reference dimension
return;
}
Vector p3 = c->GetLabelPos(); Vector p3 = c->GetLabelPos();
Point2d p2 = ProjectPoint(p3); Point2d p2 = ProjectPoint(p3);
ShowGraphicsEditControl((int)p2.x, (int)p2.y, c->exprA->Print()); 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])); elem = (T *)MemRealloc(elem, elemsAllocated*sizeof(elem[0]));
} }
int i = 0; int first = 0, last = n;
if(n == 0 || elem[n-1].h.v < t->h.v) { // We know that we must insert within the closed interval [first,last]
i = n; 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 { } else {
while(i < n && elem[i].h.v < t->h.v) { oops();
i++;
} }
} }
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])); memmove(elem+i+1, elem+i, (n-i)*sizeof(elem[0]));
elem[i] = *t; elem[i] = *t;
n++; n++;

View File

@ -680,6 +680,6 @@ void Entity::CalculateNumerical(void) {
Vector n = FaceGetNormalNum(); Vector n = FaceGetNormalNum();
numNormal = Quaternion::From(0, n.x, n.y, n.z); 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.exprA", 'E', &(SS.sv.g.exprA) },
{ 'g', "Group.color", 'x', &(SS.sv.g.color) }, { 'g', "Group.color", 'x', &(SS.sv.g.color) },
{ 'g', "Group.subtype", 'd', &(SS.sv.g.subtype) }, { '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.meshCombine", 'd', &(SS.sv.g.meshCombine) },
{ 'g', "Group.predef.q.w", 'f', &(SS.sv.g.predef.q.w) }, { 'g', "Group.predef.q.w", 'f', &(SS.sv.g.predef.q.w) },
{ 'g', "Group.predef.q.vx", 'f', &(SS.sv.g.predef.q.vx) }, { '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.h.v", 'x', &(SS.sv.e.h.v) },
{ 'e', "Entity.type", 'd', &(SS.sv.e.type) }, { '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.group.v", 'x', &(SS.sv.e.group.v) },
{ 'e', "Entity.construction", 'b', &(SS.sv.e.construction) }, { 'e', "Entity.construction", 'b', &(SS.sv.e.construction) },
{ 'e', "Entity.param[0].v", 'x', &(SS.sv.e.param[0].v) }, { '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.vy", 'f', &(SS.sv.e.actNormal.vy) },
{ 'e', "Entity.actNormal.vz", 'f', &(SS.sv.e.actNormal.vz) }, { 'e', "Entity.actNormal.vz", 'f', &(SS.sv.e.actNormal.vz) },
{ 'e', "Entity.actDistance", 'f', &(SS.sv.e.actDistance) }, { '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) }, { '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.opA = SS.GW.activeGroup;
g.exprA = Expr::From(3)->DeepCopyKeep(); g.exprA = Expr::From(3)->DeepCopyKeep();
g.subtype = ONE_SIDED; g.subtype = ONE_SIDED;
g.predef.entityB = SS.GW.ActiveWorkplane();
g.activeWorkplane = SS.GW.ActiveWorkplane();
g.name.strcpy("translate"); g.name.strcpy("translate");
break; break;
@ -294,8 +296,12 @@ void Group::Generate(IdList<Entity,hEntity> *entity,
AddParam(param, h.param(1), gp.y); AddParam(param, h.param(1), gp.y);
AddParam(param, h.param(2), gp.z); AddParam(param, h.param(2), gp.z);
int n = (int)(exprA->Eval()); int n = (int)(exprA->Eval()), a0 = 0;
for(a = 0; a < n; a++) { if(subtype == ONE_SIDED && skipFirst) {
a0++; n++;
}
for(a = a0; a < n; a++) {
for(i = 0; i < entity->n; i++) { for(i = 0; i < entity->n; i++) {
Entity *e = &(entity->elem[i]); Entity *e = &(entity->elem[i]);
if(e->group.v != opA.v) continue; 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(5), gn.y);
AddParam(param, h.param(6), gn.z); AddParam(param, h.param(6), gn.z);
int n = (int)(exprA->Eval()); int n = (int)(exprA->Eval()), a0 = 0;
for(a = 0; a < n; a++) { if(subtype == ONE_SIDED && skipFirst) {
a0++; n++;
}
for(a = a0; a < n; a++) {
for(i = 0; i < entity->n; i++) { for(i = 0; i < entity->n; i++) {
Entity *e = &(entity->elem[i]); Entity *e = &(entity->elem[i]);
if(e->group.v != opA.v) continue; 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++) { for(i = 0; i < impEntity.n; i++) {
Entity *ie = &(impEntity.elem[i]); Entity *ie = &(impEntity.elem[i]);
CopyEntity(entity, ie, 0, 0, CopyEntity(entity, ie, 0, 0,
h.param(0), h.param(1), h.param(2), h.param(0), h.param(1), h.param(2),
h.param(3), h.param(4), h.param(5), h.param(6), 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, u.Dot(extruden), 0);
AddEq(l, v.Dot(extruden), 1); 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) { 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++) { for(i = 0; i < remap.n; i++) {
EntityMap *em = &(remap.elem[i]); EntityMap *em = &(remap.elem[i]);
if(em->input.v == in.v && em->copyNumber == copyNumber) { if(em->input.v == in.v && em->copyNumber == copyNumber) {
// We already have a mapping for this entity. // We already have a mapping for this entity.
remapCache[hash] = i;
return h.entity(em->h.v); 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; EntityMap em;
em.input = in; em.input = in;
em.copyNumber = copyNumber; em.copyNumber = copyNumber;

View File

@ -18,11 +18,17 @@ void Group::GeneratePolygon(void) {
} }
SEdge error; SEdge error;
if(edges.AssemblePolygon(&poly, &error)) { if(edges.AssemblePolygon(&poly, &error)) {
polyError.yes = false; polyError.how = POLY_GOOD;
poly.normal = poly.ComputeNormal(); poly.normal = poly.ComputeNormal();
poly.FixContourDirections(); 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 { } else {
polyError.yes = true; polyError.how = POLY_NOT_CLOSED;
polyError.notClosedAt = error; polyError.notClosedAt = error;
poly.Clear(); poly.Clear();
} }
@ -279,8 +285,10 @@ void Group::Draw(void) {
if(SS.GW.showMesh) glxDebugMesh(&mesh); if(SS.GW.showMesh) glxDebugMesh(&mesh);
// And finally show the polygons too
if(!SS.GW.showShaded) return; if(!SS.GW.showShaded) return;
if(polyError.yes) { if(polyError.how == POLY_NOT_CLOSED) {
glDisable(GL_DEPTH_TEST);
glxColor4d(1, 0, 0, 0.2); glxColor4d(1, 0, 0, 0.2);
glLineWidth(10); glLineWidth(10);
glBegin(GL_LINES); glBegin(GL_LINES);
@ -294,6 +302,16 @@ void Group::Draw(void) {
glxOntoWorkplane(SS.GW.projRight, SS.GW.projUp); glxOntoWorkplane(SS.GW.projRight, SS.GW.projUp);
glxWriteText("not closed contour!"); glxWriteText("not closed contour!");
glPopMatrix(); 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 { } else {
glxColor4d(0, 0.1, 0.1, 0.5); glxColor4d(0, 0.1, 0.1, 0.5);
glPolygonOffset(-1, -1); glPolygonOffset(-1, -1);

View File

@ -179,6 +179,18 @@ bool SContour::ContainsPointProjdToNormal(Vector n, Vector p) {
return inside; 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) { void SContour::Reverse(void) {
int i; int i;
for(i = 0; i < (l.n / 2); 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 int TriMode, TriVertexCount;
static Vector Tri1, TriNMinus1, TriNMinus2; static Vector Tri1, TriNMinus1, TriNMinus2;
static Vector TriNormal; static Vector TriNormal;

View File

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

View File

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

View File

@ -560,6 +560,15 @@ void TextWindow::ScreenChangeOneOrTwoSides(int link, DWORD v) {
SS.GenerateAll(); SS.GenerateAll();
SS.GW.ClearSuper(); 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) { void TextWindow::ScreenChangeMeshCombine(int link, DWORD v) {
SS.UndoRemember(); SS.UndoRemember();
@ -581,7 +590,11 @@ void TextWindow::ScreenColor(int link, DWORD v) {
} }
void TextWindow::ScreenChangeExprA(int link, DWORD v) { void TextWindow::ScreenChangeExprA(int link, DWORD v) {
Group *g = SS.GetGroup(SS.TW.shown->group); 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.meaning = EDIT_TIMES_REPEATED;
SS.TW.edit.group.v = v; SS.TW.edit.group.v = v;
} }
@ -608,7 +621,7 @@ void TextWindow::ScreenDeleteGroup(int link, DWORD v) {
} }
void TextWindow::ShowGroupInfo(void) { void TextWindow::ShowGroupInfo(void) {
Group *g = SS.group.FindById(shown->group); Group *g = SS.group.FindById(shown->group);
char *s, *s2; char *s, *s2, *s3;
if(shown->group.v == Group::HGROUP_REFERENCES.v) { if(shown->group.v == Group::HGROUP_REFERENCES.v) {
Printf(true, "%FtGROUP %E%s", g->DescriptionString()); Printf(true, "%FtGROUP %E%s", g->DescriptionString());
@ -629,9 +642,11 @@ void TextWindow::ShowGroupInfo(void) {
} else if(g->type == Group::TRANSLATE) { } else if(g->type == Group::TRANSLATE) {
s = "TRANSLATE"; s = "TRANSLATE";
s2 ="REPEAT "; s2 ="REPEAT ";
s3 ="START ";
} else if(g->type == Group::ROTATE) { } else if(g->type == Group::ROTATE) {
s = "ROTATE "; s = "ROTATE ";
s2 ="REPEAT "; s2 ="REPEAT ";
s3 ="START ";
} }
if(g->type == Group::EXTRUDE || g->type == Group::ROTATE || 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) { 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()); 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", s2, times, times == 1 ? "" : "s",
g->h.v, &TextWindow::ScreenChangeExprA); g->h.v, &TextWindow::ScreenChangeExprA);
} }
@ -695,7 +724,14 @@ void TextWindow::ShowGroupInfo(void) {
0x80000000 | SS.modelColor[7], 7, &TextWindow::ScreenColor); 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"); Printf(true, "%Ftrequests in group");
} else {
Printf(false, "");
Printf(false, "%Ftrequests in group");
}
int i, a = 0; int i, a = 0;
for(i = 0; i < SS.request.n; i++) { 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 ScreenUnselectAll(int link, DWORD v);
static void ScreenChangeOneOrTwoSides(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 ScreenChangeMeshCombine(int link, DWORD v);
static void ScreenColor(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 check for meshes, and T intersection removal
STL export STL export
better triangle combining (Simplify()) for meshes
DXF export DXF export
compress file format (binary?)
partitioned subsystems in the solver partitioned subsystems in the solver
TTF font text TTF font text
display with proper formatting/units display with proper formatting/units
more measurements more measurements
some kind of rounding / chamfer some kind of rounding / chamfer
auto-constrain translate in then-active workplane
remove back button in browser? remove back button in browser?
clean up user-created workplanes
incremental regen of entities?