Add user interface to specify union/difference for extrudes, and

implement that. Also make solver work only between the first and
last visible group; earlier can just work from previous solve
result, and later don't matter.

There's some issues with the csg code; it will eventually produce
an open mesh, which is very bad. Not sure whether that's a logic
bug, or a numerical issue; still generating absurd triangles pretty
routinely.

[git-p4: depot-paths = "//depot/solvespace/": change = 1741]
This commit is contained in:
Jonathan Westhues 2008-05-25 05:11:44 -08:00
parent 1909d4c520
commit 248f74547e
12 changed files with 166 additions and 84 deletions

View File

@ -276,7 +276,7 @@ void Constraint::MenuConstrain(int id) {
break;
case GraphicsWindow::MNU_SOLVE_NOW:
SS.GenerateAll(true);
SS.GenerateAll(true, 0, 10000);
return;
case GraphicsWindow::MNU_SOLVE_AUTO:

View File

@ -83,7 +83,7 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
Vector gu = SS.GW.projUp.ScaledBy(1/SS.GW.scale);
Vector gn = (gr.Cross(gu)).WithMagnitude(1/SS.GW.scale);
glxColor3d(1, 0.2, 1);
glxColor3d(1, 0.4, 1);
switch(type) {
case PT_PT_DISTANCE: {
Vector ap = SS.GetEntity(ptA)->PointGetNum();

View File

@ -51,6 +51,7 @@ const SolveSpace::SaveTable SolveSpace::SAVED[] = {
{ 'g', "Group.opA.v", 'x', &(SS.sv.g.opA.v) },
{ 'g', "Group.opB.v", 'x', &(SS.sv.g.opB.v) },
{ 'g', "Group.subtype", 'd', &(SS.sv.g.subtype) },
{ 'g', "Group.meshCombine", 'd', &(SS.sv.g.meshCombine) },
{ 'g', "Group.wrkpl.q.w", 'f', &(SS.sv.g.wrkpl.q.w) },
{ 'g', "Group.wrkpl.q.vx", 'f', &(SS.sv.g.wrkpl.q.vx) },
{ 'g', "Group.wrkpl.q.vy", 'f', &(SS.sv.g.wrkpl.q.vy) },

View File

@ -102,12 +102,19 @@ void GraphicsWindow::Init(void) {
projRight.x = 1; projRight.y = projRight.z = 0;
projUp.y = 1; projUp.z = projUp.x = 0;
EnsureValidActives();
// Start locked on to the XY plane.
hRequest r = Request::HREQUEST_REFERENCE_XY;
activeWorkplane = r.entity(0);
// And with the latest visible group active
int i;
for(i = 0; i < SS.group.n; i++) {
Group *g = &(SS.group.elem[i]);
if(g->visible) activeGroup = g->h;
}
EnsureValidActives();
showWorkplanes = true;
showNormals = true;
showPoints = true;
@ -1144,11 +1151,10 @@ void GraphicsWindow::Paint(int w, int h) {
glxUnlockColor();
int i, a;
// Draw the groups; this fills the polygons, if requested.
// Draw the groups; this fills the polygons in a drawing group, and
// draws the solid mesh.
if(showSolids) {
for(i = 0; i < SS.group.n; i++) {
SS.group.elem[i].Draw();
}
(SS.GetGroup(activeGroup))->Draw();
}
// First, draw the entire scene. We don't necessarily want to draw
@ -1180,35 +1186,5 @@ void GraphicsWindow::Paint(int w, int h) {
for(i = 0; i < MAX_SELECTED; i++) {
selection[i].Draw();
}
if(SS.group.n >= 5) {
SMesh *ma = &(SS.group.elem[2].mesh);
SMesh *mb = &(SS.group.elem[4].mesh);
SBsp3 *pa = SBsp3::FromMesh(ma);
SBsp3 *pb = SBsp3::FromMesh(mb);
SMesh br; ZERO(&br);
br.flipNormal = true;
br.keepCoplanar = false;
br.AddAgainstBsp(mb, pa);
br.flipNormal = false;
br.keepCoplanar = false;
br.AddAgainstBsp(ma, pb);
dbp("triangles in = %d %d out = %d", ma->l.n, mb->l.n, br.l.n);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glxFillMesh(&br);
glDisable(GL_LIGHTING);
glxLockColorTo(0, 1, 0);
glEnable(GL_DEPTH_TEST);
glxDebugMesh(&br);
br.Clear();
FreeAllTemporary();
}
}

View File

@ -51,6 +51,7 @@ void SMesh::GetBounding(Vector *vmax, Vector *vmin) {
void SMesh::AddAgainstBsp(SMesh *srcm, SBsp3 *bsp3) {
int i;
for(i = 0; i < srcm->l.n; i++) {
STriangle *st = &(srcm->l.elem[i]);
int pn = l.n;
@ -68,6 +69,32 @@ void SMesh::AddAgainstBsp(SMesh *srcm, SBsp3 *bsp3) {
}
}
void SMesh::MakeFromUnion(SMesh *a, SMesh *b) {
SBsp3 *bspa = SBsp3::FromMesh(a);
SBsp3 *bspb = SBsp3::FromMesh(b);
flipNormal = false;
keepCoplanar = false;
AddAgainstBsp(b, bspa);
flipNormal = false;
keepCoplanar = true;
AddAgainstBsp(a, bspb);
}
void SMesh::MakeFromDifference(SMesh *a, SMesh *b) {
SBsp3 *bspa = SBsp3::FromMesh(a);
SBsp3 *bspb = SBsp3::FromMesh(b);
flipNormal = true;
keepCoplanar = false;
AddAgainstBsp(b, bspa);
flipNormal = false;
keepCoplanar = false;
AddAgainstBsp(a, bspb);
}
SBsp2 *SBsp2::Alloc(void) { return (SBsp2 *)AllocTemporary(sizeof(SBsp2)); }
SBsp3 *SBsp3::Alloc(void) { return (SBsp3 *)AllocTemporary(sizeof(SBsp3)); }
@ -153,7 +180,6 @@ alt:
} else {
// I suppose this actually is allowed to happen, if the coplanar
// face is the leaf, and all of its neighbors are earlier in tree?
dbp("insert in plane");
InsertInPlane(false, tr, instead);
}
} else {

View File

@ -178,6 +178,8 @@ public:
void GetBounding(Vector *vmax, Vector *vmin);
void AddAgainstBsp(SMesh *srcm, SBsp3 *bsp3);
void MakeFromUnion(SMesh *a, SMesh *b);
void MakeFromDifference(SMesh *a, SMesh *b);
};
#endif

View File

@ -381,15 +381,27 @@ void Group::CopyEntity(hEntity in, int a, hParam dx, hParam dy, hParam dz,
SS.entity.Add(&en);
}
void Group::MakePolygons(void) {
SMesh *Group::PreviousGroupMesh(void) {
int i;
for(i = 0; i < SS.group.n; i++) {
Group *g = &(SS.group.elem[i]);
if(g->h.v == h.v) break;
}
if(i == 0 || i >= SS.group.n) oops();
return &(SS.group.elem[i-1].mesh);
}
void Group::MakePolygons(void) {
poly.Clear();
mesh.Clear();
SEdgeList edges;
ZERO(&edges);
SMesh outm;
ZERO(&outm);
if(type == DRAWING_3D || type == DRAWING_WORKPLANE) {
if(type == DRAWING_3D || type == DRAWING_WORKPLANE ||
type == ROTATE || type == TRANSLATE)
{
int i;
for(i = 0; i < SS.entity.n; i++) {
Entity *e = &(SS.entity.elem[i]);
@ -427,7 +439,6 @@ void Group::MakePolygons(void) {
SMesh srcm; ZERO(&srcm);
(src->poly).TriangulateInto(&srcm);
SMesh outm; ZERO(&outm);
// Do the bottom; that has normal pointing opposite from translate
for(i = 0; i < srcm.l.n; i++) {
STriangle *st = &(srcm.l.elem[i]);
@ -435,9 +446,9 @@ void Group::MakePolygons(void) {
bt = (st->b).Plus(tbot),
ct = (st->c).Plus(tbot);
if(flipBottom) {
mesh.AddTriangle(ct, bt, at);
outm.AddTriangle(ct, bt, at);
} else {
mesh.AddTriangle(at, bt, ct);
outm.AddTriangle(at, bt, ct);
}
}
// And the top; that has the normal pointing the same dir as translate
@ -447,9 +458,9 @@ void Group::MakePolygons(void) {
bt = (st->b).Plus(ttop),
ct = (st->c).Plus(ttop);
if(flipBottom) {
mesh.AddTriangle(at, bt, ct);
outm.AddTriangle(at, bt, ct);
} else {
mesh.AddTriangle(ct, bt, at);
outm.AddTriangle(ct, bt, at);
}
}
srcm.Clear();
@ -463,26 +474,50 @@ void Group::MakePolygons(void) {
Vector abot = (edge->a).Plus(tbot), bbot = (edge->b).Plus(tbot);
Vector atop = (edge->a).Plus(ttop), btop = (edge->b).Plus(ttop);
if(flipBottom) {
mesh.AddTriangle(bbot, abot, atop);
mesh.AddTriangle(bbot, atop, btop);
outm.AddTriangle(bbot, abot, atop);
outm.AddTriangle(bbot, atop, btop);
} else {
mesh.AddTriangle(abot, bbot, atop);
mesh.AddTriangle(bbot, btop, atop);
outm.AddTriangle(abot, bbot, atop);
outm.AddTriangle(bbot, btop, atop);
}
}
}
edges.Clear();
// So our group's mesh appears in outm. Combine this with the previous
// group's mesh, using the requested operation.
mesh.Clear();
SMesh *a = PreviousGroupMesh();
if(meshCombine == COMBINE_AS_UNION) {
mesh.MakeFromUnion(a, &outm);
} else {
mesh.MakeFromDifference(a, &outm);
}
outm.Clear();
}
void Group::Draw(void) {
if(!visible) return;
// Show this even if the group is not visible. It's already possible
// to show or hide just this with the "show solids" flag.
GLfloat mpf[] = { 0.4f, 0.4f, 0.4f, 1.0 };
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mpf);
if(type == DRAWING_3D || type == DRAWING_WORKPLANE) {
GLfloat mpf[] = { 0.1f, 0.1f, 0.1f, 1.0 };
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mpf);
} else {
GLfloat mpf[] = { 0.3f, 0.3f, 0.3f, 1.0 };
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mpf);
}
// The back faces are drawn in red; should never seem them, since we
// draw closed shells, so that's a debugging aid.
GLfloat mpb[] = { 1.0f, 0.1f, 0.1f, 1.0 };
glMaterialfv(GL_BACK, GL_AMBIENT_AND_DIFFUSE, mpb);
glEnable(GL_LIGHTING);
glxFillMesh(&mesh);
glDisable(GL_LIGHTING);
// glxDebugMesh(&mesh);
if(polyError.yes) {
glxColor4d(1, 0, 0, 0.2);
glLineWidth(10);
@ -498,13 +533,11 @@ void Group::Draw(void) {
glxWriteText("not closed contour!");
glPopMatrix();
} else {
// glxFillPolygon(&poly);
glxColor4d(0, 1.0, 1.0, 0.1);
glPolygonOffset(-1, -1);
glxFillPolygon(&poly);
glPolygonOffset(0, 0);
}
glEnable(GL_LIGHTING);
// glxFillMesh(&mesh);
glDisable(GL_LIGHTING);
// glxDebugMesh(&mesh);
}
hParam Request::AddParam(IdList<Param,hParam> *param, hParam hp) {

View File

@ -84,8 +84,6 @@ public:
static const int TRANSLATE = 5030;
int type;
bool solved;
hGroup opA;
hGroup opB;
bool visible;
@ -113,6 +111,10 @@ public:
} polyError;
SMesh mesh;
static const int COMBINE_AS_UNION = 0;
static const int COMBINE_AS_DIFFERENCE = 1;
int meshCombine;
NameStr name;
char *DescriptionString(void);
@ -131,6 +133,7 @@ public:
void GenerateEquations(IdList<Equation,hEquation> *l);
SMesh *PreviousGroupMesh(void);
void MakePolygons(void);
void Draw(void);

View File

@ -9,11 +9,11 @@ void SolveSpace::Init(char *cmdLine) {
LoadFromFile(cmdLine);
}
GenerateAll(false, 0, INT_MAX);
TW.Init();
GW.Init();
GenerateAll(false);
TW.Show();
}
@ -122,6 +122,21 @@ bool SolveSpace::PruneConstraints(hGroup hg) {
}
void SolveSpace::GenerateAll(bool andSolve) {
int i;
int firstShown = INT_MAX, lastShown = 0;
// The references don't count, so start from group 1
for(i = 1; i < group.n; i++) {
if(group.elem[i].visible) {
firstShown = min(firstShown, i);
lastShown = max(lastShown, i);
}
}
// Even if nothing is shown, we have to keep going; the entities get
// generated for hidden groups, even though they're not solved.
GenerateAll(andSolve, firstShown, lastShown);
}
void SolveSpace::GenerateAll(bool andSolve, int first, int last) {
int i, j;
while(PruneOrphans())
@ -132,12 +147,6 @@ void SolveSpace::GenerateAll(bool andSolve) {
param.MoveSelfInto(&prev);
entity.Clear();
for(i = 0; i < group.n; i++) {
group.elem[i].solved = false;
}
// For now, solve the groups in given order; should discover the
// correct order later.
for(i = 0; i < group.n; i++) {
Group *g = &(group.elem[i]);
@ -172,13 +181,24 @@ void SolveSpace::GenerateAll(bool andSolve) {
if(g->h.v == Group::HGROUP_REFERENCES.v) {
ForceReferences();
group.elem[0].solved = true;
} else {
// Solve this group.
if(andSolve) SolveGroup(g->h);
}
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.
if(andSolve) SolveGroup(g->h);
g->MakePolygons();
} 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.
for(j = 0; j < param.n; j++) {
Param *newp = &(param.elem[j]);
g->MakePolygons();
Param *prevp = prev.FindByIdNoOops(newp->h);
if(prevp) newp->known = true;
}
}
}
}
prev.Clear();
@ -217,7 +237,7 @@ pruned:
param.Clear();
prev.MoveSelfInto(&param);
// Try again
GenerateAll(andSolve);
GenerateAll(andSolve, first, last);
}
void SolveSpace::ForceReferences(void) {
@ -299,8 +319,8 @@ void SolveSpace::MenuFile(int id) {
case GraphicsWindow::MNU_NEW:
SS.NewFile();
SS.GenerateAll(false);
SS.GW.Init();
SS.TW.Init();
SS.GW.Init();
SS.TW.Show();
break;

View File

@ -229,6 +229,7 @@ public:
bool PruneConstraints(hGroup hg);
void GenerateAll(bool andSolve);
void GenerateAll(bool andSolve, int first, int last);
bool SolveGroup(hGroup hg);
void ForceReferences(void);

View File

@ -266,6 +266,9 @@ void TextWindow::ScreenToggleGroupShown(int link, DWORD v) {
hGroup hg = { v };
Group *g = SS.GetGroup(hg);
g->visible = !(g->visible);
// If a group was just shown, then it might not have been generated
// previously, so regenerate.
SS.GW.GeneratePerSolving();
}
void TextWindow::ScreenShowGroupsSpecial(int link, DWORD v) {
int i;
@ -341,9 +344,19 @@ void TextWindow::ScreenChangeExtrudeSides(int link, DWORD v) {
Group *g = SS.GetGroup(SS.TW.shown->group);
if(g->subtype == Group::EXTRUDE_ONE_SIDED) {
g->subtype = Group::EXTRUDE_TWO_SIDED;
} else {
} else if(g->subtype == Group::EXTRUDE_TWO_SIDED) {
g->subtype = Group::EXTRUDE_ONE_SIDED;
}
} else oops();
SS.GW.GeneratePerSolving();
SS.GW.ClearSuper();
}
void TextWindow::ScreenChangeMeshCombine(int link, DWORD v) {
Group *g = SS.GetGroup(SS.TW.shown->group);
if(g->meshCombine == Group::COMBINE_AS_DIFFERENCE) {
g->meshCombine = Group::COMBINE_AS_UNION;
} else if(g->meshCombine == Group::COMBINE_AS_UNION) {
g->meshCombine = Group::COMBINE_AS_DIFFERENCE;
} else oops();
SS.GW.GeneratePerSolving();
SS.GW.ClearSuper();
}
@ -361,12 +374,18 @@ void TextWindow::ShowGroupInfo(void) {
if(g->type == Group::EXTRUDE) {
bool one = (g->subtype == Group::EXTRUDE_ONE_SIDED);
Printf(true, "%FtEXTRUDE%E one-sided: %Fh%f%Ll%s%E%Fs%s%E",
Printf(true, "%FtEXTRUDE%E %Fh%f%Ll%s%E%Fs%s%E / %Fh%f%Ll%s%E%Fs%s%E",
&TextWindow::ScreenChangeExtrudeSides,
(one ? "" : "no"), (one ? "yes" : ""));
Printf(false, " two-sided: %Fh%f%Ll%s%E%Fs%s%E",
(one ? "" : "one side"), (one ? "one-side" : ""),
&TextWindow::ScreenChangeExtrudeSides,
(!one ? "" : "no"), (!one ? "yes" : ""));
(!one ? "" : "two sides"), (!one ? "two sides" : ""));
bool diff = (g->meshCombine == Group::COMBINE_AS_DIFFERENCE);
Printf(false, "%FtCOMBINE%E %Fh%f%Ll%s%E%Fs%s%E / %Fh%f%Ll%s%E%Fs%s%E",
&TextWindow::ScreenChangeMeshCombine,
(!diff ? "" : "as union"), (!diff ? "as union" : ""),
&TextWindow::ScreenChangeMeshCombine,
(diff ? "" : "as difference"), (diff ? "as difference" : ""));
}
Printf(true, "%Ftrequests in group");

1
ui.h
View File

@ -74,6 +74,7 @@ public:
static void ScreenSelectRequest(int link, DWORD v);
static void ScreenSelectConstraint(int link, DWORD v);
static void ScreenChangeExtrudeSides(int link, DWORD v);
static void ScreenChangeMeshCombine(int link, DWORD v);
static void ScreenNavigation(int link, DWORD v);
};