2008-06-06 08:14:37 +00:00
|
|
|
#include "solvespace.h"
|
|
|
|
|
|
|
|
#define gs (SS.GW.gs)
|
|
|
|
|
2009-01-19 03:33:15 +00:00
|
|
|
bool Group::AssembleLoops(void) {
|
2009-01-19 03:51:00 +00:00
|
|
|
SBezierList sbl;
|
|
|
|
ZERO(&sbl);
|
2009-01-19 03:33:15 +00:00
|
|
|
|
2008-02-10 12:43:48 +00:00
|
|
|
int i;
|
|
|
|
for(i = 0; i < SS.entity.n; i++) {
|
|
|
|
Entity *e = &(SS.entity.elem[i]);
|
|
|
|
if(e->group.v != h.v) continue;
|
2009-01-19 03:33:15 +00:00
|
|
|
if(e->construction) continue;
|
2008-02-10 12:43:48 +00:00
|
|
|
|
2009-01-19 03:51:00 +00:00
|
|
|
e->GenerateBezierCurves(&sbl);
|
2008-02-10 12:43:48 +00:00
|
|
|
}
|
2009-01-19 03:33:15 +00:00
|
|
|
|
|
|
|
bool allClosed;
|
2009-01-19 03:51:00 +00:00
|
|
|
bezierLoopSet = SBezierLoopSet::From(&sbl, &poly,
|
|
|
|
&allClosed, &(polyError.notClosedAt));
|
|
|
|
sbl.Clear();
|
2009-01-19 03:33:15 +00:00
|
|
|
return allClosed;
|
2008-02-10 12:43:48 +00:00
|
|
|
}
|
|
|
|
|
2009-01-19 03:33:15 +00:00
|
|
|
void Group::GenerateLoops(void) {
|
2008-06-06 08:14:37 +00:00
|
|
|
poly.Clear();
|
2009-01-19 03:51:00 +00:00
|
|
|
bezierLoopSet.Clear();
|
2008-06-06 08:14:37 +00:00
|
|
|
|
|
|
|
if(type == DRAWING_3D || type == DRAWING_WORKPLANE ||
|
2008-02-13 16:15:33 +00:00
|
|
|
type == ROTATE || type == TRANSLATE || type == IMPORTED)
|
2008-06-06 08:14:37 +00:00
|
|
|
{
|
2009-01-19 03:33:15 +00:00
|
|
|
if(AssembleLoops()) {
|
2008-06-12 04:36:33 +00:00
|
|
|
polyError.how = POLY_GOOD;
|
|
|
|
|
2009-01-23 03:30:30 +00:00
|
|
|
if(!poly.AllPointsInPlane(&(polyError.errorPointAt))) {
|
2008-06-12 04:36:33 +00:00
|
|
|
// The edges aren't all coplanar; so not a good polygon
|
|
|
|
polyError.how = POLY_NOT_COPLANAR;
|
|
|
|
poly.Clear();
|
2009-01-19 03:51:00 +00:00
|
|
|
bezierLoopSet.Clear();
|
2008-06-12 04:36:33 +00:00
|
|
|
}
|
2009-01-23 03:30:30 +00:00
|
|
|
if(poly.SelfIntersecting(&(polyError.errorPointAt))) {
|
|
|
|
polyError.how = POLY_SELF_INTERSECTING;
|
|
|
|
poly.Clear();
|
|
|
|
bezierLoopSet.Clear();
|
|
|
|
}
|
2008-06-06 08:14:37 +00:00
|
|
|
} else {
|
2008-06-12 04:36:33 +00:00
|
|
|
polyError.how = POLY_NOT_CLOSED;
|
2008-06-06 08:14:37 +00:00
|
|
|
poly.Clear();
|
2009-01-19 03:51:00 +00:00
|
|
|
bezierLoopSet.Clear();
|
2008-06-06 08:14:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-23 03:30:30 +00:00
|
|
|
void Group::GenerateShellForStepAndRepeat(void) {
|
2008-06-21 22:49:57 +00:00
|
|
|
Group *src = SS.GetGroup(opA);
|
2009-01-23 03:30:30 +00:00
|
|
|
SShell *srcs = &(src->thisShell); // the shell to step and repeat
|
2008-06-21 22:49:57 +00:00
|
|
|
|
|
|
|
int n = (int)valA, a0 = 0;
|
|
|
|
if(subtype == ONE_SIDED && skipFirst) {
|
|
|
|
a0++; n++;
|
|
|
|
}
|
|
|
|
int a;
|
|
|
|
for(a = a0; a < n; a++) {
|
|
|
|
int ap = a*2 - (subtype == ONE_SIDED ? 0 : (n-1));
|
|
|
|
int remap = (a == (n - 1)) ? REMAP_LAST : a;
|
|
|
|
|
|
|
|
if(type == TRANSLATE) {
|
|
|
|
Vector trans = Vector::From(h.param(0), h.param(1), h.param(2));
|
|
|
|
trans = trans.ScaledBy(ap);
|
2009-01-23 03:30:30 +00:00
|
|
|
|
2008-06-21 22:49:57 +00:00
|
|
|
} else {
|
|
|
|
Vector trans = Vector::From(h.param(0), h.param(1), h.param(2));
|
|
|
|
double theta = ap * SS.GetParam(h.param(3))->val;
|
|
|
|
double c = cos(theta), s = sin(theta);
|
|
|
|
Vector axis = Vector::From(h.param(4), h.param(5), h.param(6));
|
|
|
|
Quaternion q = Quaternion::From(c, s*axis.x, s*axis.y, s*axis.z);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if(src->meshCombine == COMBINE_AS_DIFFERENCE) {
|
2009-01-23 03:30:30 +00:00
|
|
|
|
2008-06-21 22:49:57 +00:00
|
|
|
} else {
|
2009-01-23 03:30:30 +00:00
|
|
|
|
2008-06-21 22:49:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-23 03:30:30 +00:00
|
|
|
void Group::GenerateShellAndMesh(void) {
|
2009-01-19 10:37:10 +00:00
|
|
|
thisShell.Clear();
|
2008-06-21 10:18:20 +00:00
|
|
|
|
2008-06-21 22:49:57 +00:00
|
|
|
if(type == TRANSLATE || type == ROTATE) {
|
2009-01-23 03:30:30 +00:00
|
|
|
GenerateShellForStepAndRepeat();
|
2008-07-06 07:56:24 +00:00
|
|
|
goto done;
|
2008-06-21 22:49:57 +00:00
|
|
|
}
|
|
|
|
|
2008-06-06 08:14:37 +00:00
|
|
|
if(type == EXTRUDE) {
|
|
|
|
Group *src = SS.GetGroup(opA);
|
|
|
|
Vector translate = Vector::From(h.param(0), h.param(1), h.param(2));
|
|
|
|
|
|
|
|
Vector tbot, ttop;
|
|
|
|
if(subtype == ONE_SIDED) {
|
|
|
|
tbot = Vector::From(0, 0, 0); ttop = translate.ScaledBy(2);
|
|
|
|
} else {
|
|
|
|
tbot = translate.ScaledBy(-1); ttop = translate.ScaledBy(1);
|
|
|
|
}
|
2009-01-19 10:37:10 +00:00
|
|
|
|
2009-01-25 09:19:59 +00:00
|
|
|
thisShell.MakeFromExtrusionOf(&(src->bezierLoopSet), tbot, ttop, color);
|
2008-06-06 11:35:28 +00:00
|
|
|
} else if(type == LATHE) {
|
|
|
|
Group *src = SS.GetGroup(opA);
|
|
|
|
|
|
|
|
Vector orig = SS.GetEntity(predef.origin)->PointGetNum();
|
|
|
|
Vector axis = SS.GetEntity(predef.entityB)->VectorGetNum();
|
|
|
|
axis = axis.WithMagnitude(1);
|
|
|
|
|
2008-06-06 08:14:37 +00:00
|
|
|
} else if(type == IMPORTED) {
|
|
|
|
// Triangles are just copied over, with the appropriate transformation
|
|
|
|
// applied.
|
|
|
|
Vector offset = {
|
|
|
|
SS.GetParam(h.param(0))->val,
|
|
|
|
SS.GetParam(h.param(1))->val,
|
|
|
|
SS.GetParam(h.param(2))->val };
|
|
|
|
Quaternion q = {
|
|
|
|
SS.GetParam(h.param(3))->val,
|
|
|
|
SS.GetParam(h.param(4))->val,
|
|
|
|
SS.GetParam(h.param(5))->val,
|
|
|
|
SS.GetParam(h.param(6))->val };
|
|
|
|
|
|
|
|
for(int i = 0; i < impMesh.l.n; i++) {
|
|
|
|
STriangle st = impMesh.l.elem[i];
|
|
|
|
|
|
|
|
if(st.meta.face != 0) {
|
|
|
|
hEntity he = { st.meta.face };
|
|
|
|
st.meta.face = Remap(he, 0).v;
|
|
|
|
}
|
|
|
|
st.a = q.Rotate(st.a).Plus(offset);
|
|
|
|
st.b = q.Rotate(st.b).Plus(offset);
|
|
|
|
st.c = q.Rotate(st.c).Plus(offset);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-21 22:49:57 +00:00
|
|
|
runningMesh.Clear();
|
2009-01-19 10:37:10 +00:00
|
|
|
runningShell.Clear();
|
2008-06-21 22:49:57 +00:00
|
|
|
|
|
|
|
// If this group contributes no new mesh, then our running mesh is the
|
2008-02-15 11:35:15 +00:00
|
|
|
// same as last time, no combining required. Likewise if we have a mesh
|
|
|
|
// but it's suppressed.
|
2009-01-23 03:30:30 +00:00
|
|
|
if(suppress) {
|
|
|
|
runningShell.MakeFromCopyOf(PreviousGroupShell());
|
2008-07-06 07:56:24 +00:00
|
|
|
goto done;
|
2008-06-21 22:49:57 +00:00
|
|
|
}
|
|
|
|
|
2008-06-21 10:18:20 +00:00
|
|
|
// So our group's mesh appears in thisMesh. Combine this with the previous
|
2008-06-06 08:14:37 +00:00
|
|
|
// group's mesh, using the requested operation.
|
|
|
|
bool prevMeshError = meshError.yes;
|
2009-01-23 03:30:30 +00:00
|
|
|
|
2008-06-06 08:14:37 +00:00
|
|
|
meshError.yes = false;
|
|
|
|
meshError.interferesAt.Clear();
|
2009-01-23 03:30:30 +00:00
|
|
|
|
|
|
|
SShell *a = PreviousGroupShell();
|
2008-06-06 08:14:37 +00:00
|
|
|
if(meshCombine == COMBINE_AS_UNION) {
|
2009-01-23 03:30:30 +00:00
|
|
|
runningShell.MakeFromUnionOf(a, &thisShell);
|
2008-06-06 08:14:37 +00:00
|
|
|
} else if(meshCombine == COMBINE_AS_DIFFERENCE) {
|
2009-01-23 03:30:30 +00:00
|
|
|
runningShell.MakeFromDifferenceOf(a, &thisShell);
|
2008-06-06 08:14:37 +00:00
|
|
|
} else {
|
2009-01-23 03:30:30 +00:00
|
|
|
if(0) //&(meshError.interferesAt)
|
2008-06-21 10:18:20 +00:00
|
|
|
{
|
2008-06-06 08:14:37 +00:00
|
|
|
meshError.yes = true;
|
2008-06-21 10:18:20 +00:00
|
|
|
// And the list of failed triangles goes in meshError.interferesAt
|
|
|
|
}
|
2008-06-06 08:14:37 +00:00
|
|
|
}
|
|
|
|
if(prevMeshError != meshError.yes) {
|
|
|
|
// The error is reported in the text window for the group.
|
|
|
|
SS.later.showTW = true;
|
|
|
|
}
|
2008-07-06 07:56:24 +00:00
|
|
|
|
|
|
|
done:
|
2009-01-23 03:30:30 +00:00
|
|
|
runningShell.TriangulateInto(&runningMesh);
|
|
|
|
emphEdges.Clear();
|
|
|
|
if(h.v == SS.GW.activeGroup.v && SS.edgeColor != 0) {
|
|
|
|
thisShell.MakeEdgesInto(&emphEdges);
|
2008-07-06 07:56:24 +00:00
|
|
|
}
|
2008-06-06 08:14:37 +00:00
|
|
|
}
|
|
|
|
|
2009-01-23 03:30:30 +00:00
|
|
|
SShell *Group::PreviousGroupShell(void) {
|
2008-06-06 08:14:37 +00:00
|
|
|
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();
|
2009-01-23 03:30:30 +00:00
|
|
|
return &(SS.group.elem[i-1].runningShell);
|
2008-06-06 08:14:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Group::Draw(void) {
|
|
|
|
// Show this even if the group is not visible. It's already possible
|
|
|
|
// to show or hide just this with the "show solids" flag.
|
|
|
|
|
|
|
|
int specColor;
|
2008-06-21 22:49:57 +00:00
|
|
|
if(type == DRAWING_3D || type == DRAWING_WORKPLANE) {
|
2008-06-06 08:14:37 +00:00
|
|
|
specColor = RGB(25, 25, 25); // force the color to something dim
|
|
|
|
} else {
|
|
|
|
specColor = -1; // use the model color
|
|
|
|
}
|
|
|
|
// 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);
|
|
|
|
|
|
|
|
// When we fill the mesh, we need to know which triangles are selected
|
|
|
|
// or hovered, in order to draw them differently.
|
|
|
|
DWORD mh = 0, ms1 = 0, ms2 = 0;
|
|
|
|
hEntity he = SS.GW.hover.entity;
|
|
|
|
if(he.v != 0 && SS.GetEntity(he)->IsFace()) {
|
|
|
|
mh = he.v;
|
|
|
|
}
|
|
|
|
SS.GW.GroupSelection();
|
|
|
|
if(gs.faces > 0) ms1 = gs.face[0].v;
|
|
|
|
if(gs.faces > 1) ms2 = gs.face[1].v;
|
|
|
|
|
2008-07-06 07:56:24 +00:00
|
|
|
if(SS.GW.showShaded) {
|
|
|
|
glEnable(GL_LIGHTING);
|
|
|
|
glxFillMesh(specColor, &runningMesh, mh, ms1, ms2);
|
|
|
|
glDisable(GL_LIGHTING);
|
|
|
|
|
2009-01-25 09:19:59 +00:00
|
|
|
glLineWidth(1);
|
|
|
|
glxDepthRangeOffset(2);
|
|
|
|
glxColor3d(REDf (SS.edgeColor),
|
|
|
|
GREENf(SS.edgeColor),
|
|
|
|
BLUEf (SS.edgeColor));
|
2008-07-06 07:56:24 +00:00
|
|
|
glxDrawEdges(&emphEdges);
|
|
|
|
}
|
2008-06-06 08:14:37 +00:00
|
|
|
|
|
|
|
if(meshError.yes) {
|
|
|
|
// Draw the error triangles in bright red stripes, with no Z buffering
|
|
|
|
GLubyte mask[32*32/8];
|
|
|
|
memset(mask, 0xf0, sizeof(mask));
|
|
|
|
glPolygonStipple(mask);
|
|
|
|
|
|
|
|
int specColor = 0;
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
glColor3d(0, 0, 0);
|
|
|
|
glxFillMesh(0, &meshError.interferesAt, 0, 0, 0);
|
|
|
|
glEnable(GL_POLYGON_STIPPLE);
|
|
|
|
glColor3d(1, 0, 0);
|
|
|
|
glxFillMesh(0, &meshError.interferesAt, 0, 0, 0);
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
glDisable(GL_POLYGON_STIPPLE);
|
|
|
|
}
|
|
|
|
|
2008-06-21 10:18:20 +00:00
|
|
|
if(SS.GW.showMesh) glxDebugMesh(&runningMesh);
|
2008-06-06 08:14:37 +00:00
|
|
|
|
2008-06-12 04:36:33 +00:00
|
|
|
// And finally show the polygons too
|
2008-06-06 08:14:37 +00:00
|
|
|
if(!SS.GW.showShaded) return;
|
2008-06-12 04:36:33 +00:00
|
|
|
if(polyError.how == POLY_NOT_CLOSED) {
|
2008-07-13 09:57:46 +00:00
|
|
|
// Report this error only in sketch-in-workplane groups; otherwise
|
|
|
|
// it's just a nuisance.
|
|
|
|
if(type == DRAWING_WORKPLANE) {
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
glxColor4d(1, 0, 0, 0.2);
|
|
|
|
glLineWidth(10);
|
|
|
|
glBegin(GL_LINES);
|
|
|
|
glxVertex3v(polyError.notClosedAt.a);
|
|
|
|
glxVertex3v(polyError.notClosedAt.b);
|
|
|
|
glEnd();
|
|
|
|
glLineWidth(1);
|
|
|
|
glxColor3d(1, 0, 0);
|
|
|
|
glPushMatrix();
|
|
|
|
glxTranslatev(polyError.notClosedAt.b);
|
|
|
|
glxOntoWorkplane(SS.GW.projRight, SS.GW.projUp);
|
|
|
|
glxWriteText("not closed contour!");
|
|
|
|
glPopMatrix();
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
}
|
2009-01-23 03:30:30 +00:00
|
|
|
} else if(polyError.how == POLY_NOT_COPLANAR ||
|
|
|
|
polyError.how == POLY_SELF_INTERSECTING)
|
|
|
|
{
|
|
|
|
// These errors occur at points, not lines
|
2008-07-13 09:57:46 +00:00
|
|
|
if(type == DRAWING_WORKPLANE) {
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
glxColor3d(1, 0, 0);
|
|
|
|
glPushMatrix();
|
2009-01-23 03:30:30 +00:00
|
|
|
glxTranslatev(polyError.errorPointAt);
|
2008-07-13 09:57:46 +00:00
|
|
|
glxOntoWorkplane(SS.GW.projRight, SS.GW.projUp);
|
2009-01-23 03:30:30 +00:00
|
|
|
if(polyError.how == POLY_NOT_COPLANAR) {
|
|
|
|
glxWriteText("points not all coplanar!");
|
|
|
|
} else {
|
|
|
|
glxWriteText("contour is self-intersecting!");
|
|
|
|
}
|
2008-07-13 09:57:46 +00:00
|
|
|
glPopMatrix();
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
}
|
2008-06-06 08:14:37 +00:00
|
|
|
} else {
|
|
|
|
glxColor4d(0, 0.1, 0.1, 0.5);
|
2008-06-17 19:12:25 +00:00
|
|
|
glxDepthRangeOffset(1);
|
2008-06-06 08:14:37 +00:00
|
|
|
glxFillPolygon(&poly);
|
2008-06-17 19:12:25 +00:00
|
|
|
glxDepthRangeOffset(0);
|
2008-06-06 08:14:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|