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
parent
83f741bd06
commit
8969687904
5
draw.cpp
5
draw.cpp
|
@ -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());
|
||||
|
|
22
dsc.h
22
dsc.h
|
@ -106,20 +106,26 @@ 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;
|
||||
} else {
|
||||
while(i < n && elem[i].h.v < t->h.v) {
|
||||
i++;
|
||||
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 {
|
||||
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++;
|
||||
}
|
||||
|
||||
|
||||
T *FindById(H h) {
|
||||
T *t = FindByIdNoOops(h);
|
||||
if(!t) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
3
file.cpp
3
file.cpp
|
@ -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) },
|
||||
|
|
43
group.cpp
43
group.cpp
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
26
polygon.cpp
26
polygon.cpp
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
15
sketch.h
15
sketch.h
|
@ -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
|
||||
|
|
50
textwin.cpp
50
textwin.cpp
|
@ -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());
|
||||
|
@ -628,10 +641,12 @@ void TextWindow::ShowGroupInfo(void) {
|
|||
s = "EXTRUDE ";
|
||||
} else if(g->type == Group::TRANSLATE) {
|
||||
s = "TRANSLATE";
|
||||
s2 ="REPEAT ";
|
||||
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);
|
||||
}
|
||||
|
||||
Printf(true, "%Ftrequests in group");
|
||||
// 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
1
ui.h
|
@ -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);
|
||||
|
||||
|
|
|
@ -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?
|
||||
|
||||
|
|
Loading…
Reference in New Issue