Tear everything apart, moving away from meshes and toward shells.
Add stubs for functions to perform Booleans, and get rid of mesh stuff, including the kd tree accelerated snap to vertex (which should not be required if the shell triangulation performs as it should). Also check that a sketch is not self-intersecting before extruding it or whatever. This is dead slow, needs n*log(n) implementation. [git-p4: depot-paths = "//depot/solvespace/": change = 1902]solver
parent
6d7954e167
commit
bb4b767e99
1
Makefile
1
Makefile
|
@ -41,6 +41,7 @@ SSOBJS = $(OBJDIR)\solvespace.obj \
|
|||
|
||||
SRFOBJS = $(OBJDIR)\ratpoly.obj \
|
||||
$(OBJDIR)\triangulate.obj \
|
||||
$(OBJDIR)\boolean.obj \
|
||||
|
||||
|
||||
RES = $(OBJDIR)\resource.res
|
||||
|
|
14
export.cpp
14
export.cpp
|
@ -86,7 +86,6 @@ void SolveSpace::ExportSectionTo(char *filename) {
|
|||
|
||||
// Select the naked edges in our resulting open mesh.
|
||||
SKdNode *root = SKdNode::From(&m);
|
||||
root->SnapToMesh(&m);
|
||||
SEdgeList el;
|
||||
ZERO(&el);
|
||||
root->MakeCertainEdgesInto(&el, false);
|
||||
|
@ -294,16 +293,10 @@ void SolveSpace::ExportMeshTo(char *filename) {
|
|||
Error("Active group mesh is empty; nothing to export.");
|
||||
return;
|
||||
}
|
||||
SKdNode *root = SKdNode::From(m);
|
||||
root->SnapToMesh(m);
|
||||
SMesh vvm;
|
||||
ZERO(&vvm);
|
||||
root->MakeMeshInto(&vvm);
|
||||
|
||||
FILE *f = fopen(filename, "wb");
|
||||
if(!f) {
|
||||
Error("Couldn't write to '%s'", filename);
|
||||
vvm.Clear();
|
||||
return;
|
||||
}
|
||||
char str[80];
|
||||
|
@ -311,13 +304,13 @@ void SolveSpace::ExportMeshTo(char *filename) {
|
|||
strcpy(str, "STL exported mesh");
|
||||
fwrite(str, 1, 80, f);
|
||||
|
||||
DWORD n = vvm.l.n;
|
||||
DWORD n = m->l.n;
|
||||
fwrite(&n, 4, 1, f);
|
||||
|
||||
double s = SS.exportScale;
|
||||
int i;
|
||||
for(i = 0; i < vvm.l.n; i++) {
|
||||
STriangle *tr = &(vvm.l.elem[i]);
|
||||
for(i = 0; i < m->l.n; i++) {
|
||||
STriangle *tr = &(m->l.elem[i]);
|
||||
Vector n = tr->Normal().WithMagnitude(1);
|
||||
float w;
|
||||
w = (float)n.x; fwrite(&w, 4, 1, f);
|
||||
|
@ -336,7 +329,6 @@ void SolveSpace::ExportMeshTo(char *filename) {
|
|||
fputc(0, f);
|
||||
}
|
||||
|
||||
vvm.Clear();
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
|
|
13
generate.cpp
13
generate.cpp
|
@ -208,22 +208,11 @@ void SolveSpace::GenerateAll(int first, int last, bool andFindFree) {
|
|||
g->clean = true;
|
||||
} else {
|
||||
if(i >= first && i <= last) {
|
||||
// See if we have to do the vertex-to-vertex mesh, that
|
||||
// we used for emphasized edges.
|
||||
if(first == i &&
|
||||
(g->type == Group::DRAWING_3D ||
|
||||
g->type == Group::DRAWING_WORKPLANE))
|
||||
{
|
||||
// Special case--if the first dirty group doesn't change
|
||||
// the mesh, then no need to regen edges for it.
|
||||
} else {
|
||||
g->vvMeshClean = false; // so we'll regen it
|
||||
}
|
||||
// The group falls inside the range, so really solve it,
|
||||
// and then regenerate the mesh based on the solved stuff.
|
||||
SolveGroup(g->h, andFindFree);
|
||||
g->GenerateLoops();
|
||||
g->GenerateMesh();
|
||||
g->GenerateShellAndMesh();
|
||||
g->clean = true;
|
||||
} else {
|
||||
// The group falls outside the range, so just assume that
|
||||
|
|
231
groupmesh.cpp
231
groupmesh.cpp
|
@ -32,12 +32,17 @@ void Group::GenerateLoops(void) {
|
|||
if(AssembleLoops()) {
|
||||
polyError.how = POLY_GOOD;
|
||||
|
||||
if(!poly.AllPointsInPlane(&(polyError.notCoplanarAt))) {
|
||||
if(!poly.AllPointsInPlane(&(polyError.errorPointAt))) {
|
||||
// The edges aren't all coplanar; so not a good polygon
|
||||
polyError.how = POLY_NOT_COPLANAR;
|
||||
poly.Clear();
|
||||
bezierLoopSet.Clear();
|
||||
}
|
||||
if(poly.SelfIntersecting(&(polyError.errorPointAt))) {
|
||||
polyError.how = POLY_SELF_INTERSECTING;
|
||||
poly.Clear();
|
||||
bezierLoopSet.Clear();
|
||||
}
|
||||
} else {
|
||||
polyError.how = POLY_NOT_CLOSED;
|
||||
poly.Clear();
|
||||
|
@ -46,40 +51,9 @@ void Group::GenerateLoops(void) {
|
|||
}
|
||||
}
|
||||
|
||||
void Group::AddQuadWithNormal(STriMeta meta, Vector out,
|
||||
Vector a, Vector b, Vector c, Vector d)
|
||||
{
|
||||
// The quad becomes two triangles
|
||||
STriangle quad1 = STriangle::From(meta, a, b, c),
|
||||
quad2 = STriangle::From(meta, c, d, a);
|
||||
|
||||
// Could be only one of the triangles has area; be sure
|
||||
// to use that one for normal checking, then.
|
||||
Vector n1 = quad1.Normal(), n2 = quad2.Normal();
|
||||
Vector n = (n1.Magnitude() > n2.Magnitude()) ? n1 : n2;
|
||||
if(n.Dot(out) < 0) {
|
||||
quad1.FlipNormal();
|
||||
quad2.FlipNormal();
|
||||
}
|
||||
// One or both of the endpoints might lie on the axis of
|
||||
// rotation, in which case its triangle is zero-area.
|
||||
if(n1.Magnitude() > LENGTH_EPS) thisMesh.AddTriangle(&quad1);
|
||||
if(n2.Magnitude() > LENGTH_EPS) thisMesh.AddTriangle(&quad2);
|
||||
}
|
||||
|
||||
void Group::GenerateMeshForStepAndRepeat(void) {
|
||||
void Group::GenerateShellForStepAndRepeat(void) {
|
||||
Group *src = SS.GetGroup(opA);
|
||||
SMesh *srcm = &(src->thisMesh); // the mesh to step and repeat
|
||||
|
||||
if(srcm->l.n == 0) {
|
||||
runningMesh.Clear();
|
||||
runningMesh.MakeFromCopy(PreviousGroupMesh());
|
||||
return;
|
||||
}
|
||||
|
||||
SMesh origm;
|
||||
ZERO(&origm);
|
||||
origm.MakeFromCopy(src->PreviousGroupMesh());
|
||||
SShell *srcs = &(src->thisShell); // the shell to step and repeat
|
||||
|
||||
int n = (int)valA, a0 = 0;
|
||||
if(subtype == ONE_SIDED && skipFirst) {
|
||||
|
@ -90,21 +64,10 @@ void Group::GenerateMeshForStepAndRepeat(void) {
|
|||
int ap = a*2 - (subtype == ONE_SIDED ? 0 : (n-1));
|
||||
int remap = (a == (n - 1)) ? REMAP_LAST : a;
|
||||
|
||||
thisMesh.Clear();
|
||||
if(type == TRANSLATE) {
|
||||
Vector trans = Vector::From(h.param(0), h.param(1), h.param(2));
|
||||
trans = trans.ScaledBy(ap);
|
||||
for(int i = 0; i < srcm->l.n; i++) {
|
||||
STriangle tr = srcm->l.elem[i];
|
||||
tr.a = (tr.a).Plus(trans);
|
||||
tr.b = (tr.b).Plus(trans);
|
||||
tr.c = (tr.c).Plus(trans);
|
||||
if(tr.meta.face != 0) {
|
||||
hEntity he = { tr.meta.face };
|
||||
tr.meta.face = Remap(he, remap).v;
|
||||
}
|
||||
thisMesh.AddTriangle(&tr);
|
||||
}
|
||||
|
||||
} else {
|
||||
Vector trans = Vector::From(h.param(0), h.param(1), h.param(2));
|
||||
double theta = ap * SS.GetParam(h.param(3))->val;
|
||||
|
@ -112,46 +75,26 @@ void Group::GenerateMeshForStepAndRepeat(void) {
|
|||
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);
|
||||
|
||||
for(int i = 0; i < srcm->l.n; i++) {
|
||||
STriangle tr = srcm->l.elem[i];
|
||||
tr.a = (q.Rotate((tr.a).Minus(trans))).Plus(trans);
|
||||
tr.b = (q.Rotate((tr.b).Minus(trans))).Plus(trans);
|
||||
tr.c = (q.Rotate((tr.c).Minus(trans))).Plus(trans);
|
||||
if(tr.meta.face != 0) {
|
||||
hEntity he = { tr.meta.face };
|
||||
tr.meta.face = Remap(he, remap).v;
|
||||
}
|
||||
thisMesh.AddTriangle(&tr);
|
||||
}
|
||||
}
|
||||
|
||||
runningMesh.Clear();
|
||||
if(src->meshCombine == COMBINE_AS_DIFFERENCE) {
|
||||
runningMesh.MakeFromDifference(&origm, &thisMesh);
|
||||
|
||||
} else {
|
||||
runningMesh.MakeFromUnion(&origm, &thisMesh);
|
||||
|
||||
}
|
||||
origm.Clear();
|
||||
origm.MakeFromCopy(&runningMesh);
|
||||
}
|
||||
origm.Clear();
|
||||
thisMesh.Clear();
|
||||
}
|
||||
|
||||
void Group::GenerateMesh(void) {
|
||||
thisMesh.Clear();
|
||||
void Group::GenerateShellAndMesh(void) {
|
||||
thisShell.Clear();
|
||||
STriMeta meta = { 0, color };
|
||||
|
||||
if(type == TRANSLATE || type == ROTATE) {
|
||||
GenerateMeshForStepAndRepeat();
|
||||
GenerateShellForStepAndRepeat();
|
||||
goto done;
|
||||
}
|
||||
|
||||
if(type == EXTRUDE) {
|
||||
SEdgeList edges;
|
||||
ZERO(&edges);
|
||||
int i;
|
||||
Group *src = SS.GetGroup(opA);
|
||||
Vector translate = Vector::From(h.param(0), h.param(1), h.param(2));
|
||||
|
||||
|
@ -162,112 +105,14 @@ void Group::GenerateMesh(void) {
|
|||
tbot = translate.ScaledBy(-1); ttop = translate.ScaledBy(1);
|
||||
}
|
||||
|
||||
thisShell = SShell::FromExtrusionOf(&(src->bezierLoopSet), tbot, ttop);
|
||||
thisShell.TriangulateInto(&thisMesh);
|
||||
/*
|
||||
bool flipBottom = translate.Dot(src->poly.normal) > 0;
|
||||
|
||||
// Get a triangulation of the source poly; this is not a closed mesh.
|
||||
SMesh srcm; ZERO(&srcm);
|
||||
(src->poly).TriangulateInto(&srcm);
|
||||
|
||||
// Do the bottom; that has normal pointing opposite from translate
|
||||
meta.face = Remap(Entity::NO_ENTITY, REMAP_BOTTOM).v;
|
||||
for(i = 0; i < srcm.l.n; i++) {
|
||||
STriangle *st = &(srcm.l.elem[i]);
|
||||
Vector at = (st->a).Plus(tbot),
|
||||
bt = (st->b).Plus(tbot),
|
||||
ct = (st->c).Plus(tbot);
|
||||
if(flipBottom) {
|
||||
thisMesh.AddTriangle(meta, ct, bt, at);
|
||||
} else {
|
||||
thisMesh.AddTriangle(meta, at, bt, ct);
|
||||
}
|
||||
}
|
||||
// And the top; that has the normal pointing the same dir as translate
|
||||
meta.face = Remap(Entity::NO_ENTITY, REMAP_TOP).v;
|
||||
for(i = 0; i < srcm.l.n; i++) {
|
||||
STriangle *st = &(srcm.l.elem[i]);
|
||||
Vector at = (st->a).Plus(ttop),
|
||||
bt = (st->b).Plus(ttop),
|
||||
ct = (st->c).Plus(ttop);
|
||||
if(flipBottom) {
|
||||
thisMesh.AddTriangle(meta, at, bt, ct);
|
||||
} else {
|
||||
thisMesh.AddTriangle(meta, ct, bt, at);
|
||||
}
|
||||
}
|
||||
srcm.Clear();
|
||||
// Get the source polygon to extrude, and break it down to edges
|
||||
edges.Clear();
|
||||
(src->poly).MakeEdgesInto(&edges);
|
||||
|
||||
edges.l.ClearTags();
|
||||
TagEdgesFromLineSegments(&edges);
|
||||
// The sides; these are quads, represented as two triangles.
|
||||
for(i = 0; i < edges.l.n; i++) {
|
||||
SEdge *edge = &(edges.l.elem[i]);
|
||||
Vector abot = (edge->a).Plus(tbot), bbot = (edge->b).Plus(tbot);
|
||||
Vector atop = (edge->a).Plus(ttop), btop = (edge->b).Plus(ttop);
|
||||
// We tagged the edges that came from line segments; their
|
||||
// triangles should be associated with that plane face.
|
||||
if(edge->tag) {
|
||||
hEntity hl = { edge->tag };
|
||||
hEntity hf = Remap(hl, REMAP_LINE_TO_FACE);
|
||||
meta.face = hf.v;
|
||||
} else {
|
||||
meta.face = 0;
|
||||
}
|
||||
if(flipBottom) {
|
||||
thisMesh.AddTriangle(meta, bbot, abot, atop);
|
||||
thisMesh.AddTriangle(meta, bbot, atop, btop);
|
||||
} else {
|
||||
thisMesh.AddTriangle(meta, abot, bbot, atop);
|
||||
thisMesh.AddTriangle(meta, bbot, btop, atop);
|
||||
}
|
||||
}
|
||||
edges.Clear(); */
|
||||
thisShell.MakeFromExtrusionOf(&(src->bezierLoopSet), tbot, ttop);
|
||||
} else if(type == LATHE) {
|
||||
SEdgeList edges;
|
||||
ZERO(&edges);
|
||||
int a, i;
|
||||
|
||||
Group *src = SS.GetGroup(opA);
|
||||
(src->poly).MakeEdgesInto(&edges);
|
||||
|
||||
Vector orig = SS.GetEntity(predef.origin)->PointGetNum();
|
||||
Vector axis = SS.GetEntity(predef.entityB)->VectorGetNum();
|
||||
axis = axis.WithMagnitude(1);
|
||||
|
||||
// Calculate the max radius, to determine fineness of mesh
|
||||
double r, rmax = 0;
|
||||
for(i = 0; i < edges.l.n; i++) {
|
||||
SEdge *edge = &(edges.l.elem[i]);
|
||||
r = (edge->a).DistanceToLine(orig, axis);
|
||||
rmax = max(r, rmax);
|
||||
r = (edge->b).DistanceToLine(orig, axis);
|
||||
rmax = max(r, rmax);
|
||||
}
|
||||
|
||||
int n = SS.CircleSides(rmax);
|
||||
for(a = 0; a < n; a++) {
|
||||
double thetai = (2*PI*WRAP(a-1, n))/n, thetaf = (2*PI*a)/n;
|
||||
for(i = 0; i < edges.l.n; i++) {
|
||||
SEdge *edge = &(edges.l.elem[i]);
|
||||
|
||||
Vector ai = (edge->a).RotatedAbout(orig, axis, thetai);
|
||||
Vector bi = (edge->b).RotatedAbout(orig, axis, thetai);
|
||||
Vector af = (edge->a).RotatedAbout(orig, axis, thetaf);
|
||||
Vector bf = (edge->b).RotatedAbout(orig, axis, thetaf);
|
||||
|
||||
Vector ab = (edge->b).Minus(edge->a);
|
||||
Vector out = ((src->poly).normal).Cross(ab);
|
||||
// This is a vector, not a point, so no origin for rotation
|
||||
out = out.RotatedAbout(axis, thetai);
|
||||
|
||||
AddQuadWithNormal(meta, out, ai, bi, bf, af);
|
||||
}
|
||||
}
|
||||
} else if(type == IMPORTED) {
|
||||
// Triangles are just copied over, with the appropriate transformation
|
||||
// applied.
|
||||
|
@ -291,7 +136,6 @@ void Group::GenerateMesh(void) {
|
|||
st.a = q.Rotate(st.a).Plus(offset);
|
||||
st.b = q.Rotate(st.b).Plus(offset);
|
||||
st.c = q.Rotate(st.c).Plus(offset);
|
||||
thisMesh.AddTriangle(&st);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -301,26 +145,25 @@ void Group::GenerateMesh(void) {
|
|||
// If this group contributes no new mesh, then our running mesh is the
|
||||
// same as last time, no combining required. Likewise if we have a mesh
|
||||
// but it's suppressed.
|
||||
if(thisMesh.l.n == 0 || suppress) {
|
||||
runningMesh.MakeFromCopy(PreviousGroupMesh());
|
||||
if(suppress) {
|
||||
runningShell.MakeFromCopyOf(PreviousGroupShell());
|
||||
goto done;
|
||||
}
|
||||
|
||||
// So our group's mesh appears in thisMesh. Combine this with the previous
|
||||
// group's mesh, using the requested operation.
|
||||
bool prevMeshError = meshError.yes;
|
||||
|
||||
meshError.yes = false;
|
||||
meshError.interferesAt.Clear();
|
||||
SMesh *a = PreviousGroupMesh();
|
||||
|
||||
SShell *a = PreviousGroupShell();
|
||||
if(meshCombine == COMBINE_AS_UNION) {
|
||||
runningMesh.MakeFromUnion(a, &thisMesh);
|
||||
runningMesh = thisMesh;
|
||||
ZERO(&thisMesh);
|
||||
runningShell.MakeFromUnionOf(a, &thisShell);
|
||||
} else if(meshCombine == COMBINE_AS_DIFFERENCE) {
|
||||
runningMesh.MakeFromDifference(a, &thisMesh);
|
||||
runningShell.MakeFromDifferenceOf(a, &thisShell);
|
||||
} else {
|
||||
if(!runningMesh.MakeFromInterferenceCheck(a, &thisMesh,
|
||||
&(meshError.interferesAt)))
|
||||
if(0) //&(meshError.interferesAt)
|
||||
{
|
||||
meshError.yes = true;
|
||||
// And the list of failed triangles goes in meshError.interferesAt
|
||||
|
@ -332,25 +175,21 @@ void Group::GenerateMesh(void) {
|
|||
}
|
||||
|
||||
done:
|
||||
if(!vvMeshClean) {
|
||||
emphEdges.Clear();
|
||||
if(h.v == SS.GW.activeGroup.v && SS.edgeColor != 0) {
|
||||
SKdNode *root = SKdNode::From(&runningMesh);
|
||||
root->SnapToMesh(&runningMesh);
|
||||
root->MakeCertainEdgesInto(&emphEdges, true);
|
||||
}
|
||||
vvMeshClean = true;
|
||||
runningShell.TriangulateInto(&runningMesh);
|
||||
emphEdges.Clear();
|
||||
if(h.v == SS.GW.activeGroup.v && SS.edgeColor != 0) {
|
||||
thisShell.MakeEdgesInto(&emphEdges);
|
||||
}
|
||||
}
|
||||
|
||||
SMesh *Group::PreviousGroupMesh(void) {
|
||||
SShell *Group::PreviousGroupShell(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].runningMesh);
|
||||
return &(SS.group.elem[i-1].runningShell);
|
||||
}
|
||||
|
||||
void Group::Draw(void) {
|
||||
|
@ -428,15 +267,21 @@ void Group::Draw(void) {
|
|||
glPopMatrix();
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
}
|
||||
} else if(polyError.how == POLY_NOT_COPLANAR) {
|
||||
// And this one too
|
||||
} else if(polyError.how == POLY_NOT_COPLANAR ||
|
||||
polyError.how == POLY_SELF_INTERSECTING)
|
||||
{
|
||||
// These errors occur at points, not lines
|
||||
if(type == DRAWING_WORKPLANE) {
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glxColor3d(1, 0, 0);
|
||||
glPushMatrix();
|
||||
glxTranslatev(polyError.notCoplanarAt);
|
||||
glxTranslatev(polyError.errorPointAt);
|
||||
glxOntoWorkplane(SS.GW.projRight, SS.GW.projUp);
|
||||
glxWriteText("points not all coplanar!");
|
||||
if(polyError.how == POLY_NOT_COPLANAR) {
|
||||
glxWriteText("points not all coplanar!");
|
||||
} else {
|
||||
glxWriteText("contour is self-intersecting!");
|
||||
}
|
||||
glPopMatrix();
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
}
|
||||
|
|
89
mesh.cpp
89
mesh.cpp
|
@ -476,95 +476,6 @@ void SKdNode::MakeMeshInto(SMesh *m) {
|
|||
}
|
||||
}
|
||||
|
||||
void SKdNode::SnapToVertex(Vector v, SMesh *extras) {
|
||||
if(gt && lt) {
|
||||
double vc = v.Element(which);
|
||||
if(vc < c + KDTREE_EPS) {
|
||||
lt->SnapToVertex(v, extras);
|
||||
}
|
||||
if(vc > c - KDTREE_EPS) {
|
||||
gt->SnapToVertex(v, extras);
|
||||
}
|
||||
// Nothing bad happens if the triangle to be split appears in both
|
||||
// branches; the first call will split the triangle, so that the
|
||||
// second call will do nothing, because the modified triangle will
|
||||
// already contain v
|
||||
} else {
|
||||
STriangleLl *ll;
|
||||
for(ll = tris; ll; ll = ll->next) {
|
||||
STriangle *tr = ll->tri;
|
||||
|
||||
// Do a cheap bbox test first
|
||||
int k;
|
||||
bool mightHit = true;
|
||||
|
||||
for(k = 0; k < 3; k++) {
|
||||
if((tr->a).Element(k) < v.Element(k) - KDTREE_EPS &&
|
||||
(tr->b).Element(k) < v.Element(k) - KDTREE_EPS &&
|
||||
(tr->c).Element(k) < v.Element(k) - KDTREE_EPS)
|
||||
{
|
||||
mightHit = false;
|
||||
break;
|
||||
}
|
||||
if((tr->a).Element(k) > v.Element(k) + KDTREE_EPS &&
|
||||
(tr->b).Element(k) > v.Element(k) + KDTREE_EPS &&
|
||||
(tr->c).Element(k) > v.Element(k) + KDTREE_EPS)
|
||||
{
|
||||
mightHit = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!mightHit) continue;
|
||||
|
||||
if(tr->a.Equals(v)) { tr->a = v; continue; }
|
||||
if(tr->b.Equals(v)) { tr->b = v; continue; }
|
||||
if(tr->c.Equals(v)) { tr->c = v; continue; }
|
||||
|
||||
if(v.OnLineSegment(tr->a, tr->b)) {
|
||||
STriangle nt = STriangle::From(tr->meta, tr->a, v, tr->c);
|
||||
extras->AddTriangle(&nt);
|
||||
tr->a = v;
|
||||
continue;
|
||||
}
|
||||
if(v.OnLineSegment(tr->b, tr->c)) {
|
||||
STriangle nt = STriangle::From(tr->meta, tr->b, v, tr->a);
|
||||
extras->AddTriangle(&nt);
|
||||
tr->b = v;
|
||||
continue;
|
||||
}
|
||||
if(v.OnLineSegment(tr->c, tr->a)) {
|
||||
STriangle nt = STriangle::From(tr->meta, tr->c, v, tr->b);
|
||||
extras->AddTriangle(&nt);
|
||||
tr->c = v;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SKdNode::SnapToMesh(SMesh *m) {
|
||||
int i, j, k;
|
||||
for(i = 0; i < m->l.n; i++) {
|
||||
STriangle *tr = &(m->l.elem[i]);
|
||||
for(j = 0; j < 3; j++) {
|
||||
Vector v = ((j == 0) ? tr->a :
|
||||
((j == 1) ? tr->b :
|
||||
tr->c));
|
||||
|
||||
SMesh extra;
|
||||
ZERO(&extra);
|
||||
SnapToVertex(v, &extra);
|
||||
|
||||
for(k = 0; k < extra.l.n; k++) {
|
||||
STriangle *tra = (STriangle *)AllocTemporary(sizeof(*tra));
|
||||
*tra = extra.l.elem[k];
|
||||
AddTriangle(tra);
|
||||
}
|
||||
extra.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SKdNode::FindEdgeOn(Vector a, Vector b, int *n, int *nOther,
|
||||
STriMeta m, int cnt)
|
||||
{
|
||||
|
|
61
polygon.cpp
61
polygon.cpp
|
@ -140,22 +140,29 @@ bool SEdgeList::AssemblePolygon(SPolygon *dest, SEdge *errorAt) {
|
|||
// Test if the specified edge crosses any of the edges in our list. Two edges
|
||||
// are not considered to cross if they share an endpoint (within LENGTH_EPS),
|
||||
// but they are considered to cross if they are coincident and overlapping.
|
||||
// If pi is not NULL, then a crossing is returned in that.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool SEdgeList::AnyEdgeCrosses(Vector a, Vector b) {
|
||||
int SEdgeList::AnyEdgeCrossings(Vector a, Vector b, Vector *ppi) {
|
||||
Vector d = b.Minus(a);
|
||||
double t_eps = LENGTH_EPS/d.Magnitude();
|
||||
|
||||
int cnt = 0;
|
||||
SEdge *se;
|
||||
for(se = l.First(); se; se = l.NextAfter(se)) {
|
||||
double dist_a, dist_b;
|
||||
double t, tse;
|
||||
bool skew;
|
||||
Vector pi;
|
||||
bool inOrEdge0, inOrEdge1;
|
||||
|
||||
Vector dse = (se->b).Minus(se->a);
|
||||
double tse_eps = LENGTH_EPS/dse.Magnitude();
|
||||
|
||||
if(a.Equals(se->a) && b.Equals(se->b)) return true;
|
||||
if(b.Equals(se->a) && a.Equals(se->b)) return true;
|
||||
if(a.Equals(se->a) && b.Equals(se->b)) goto intersects;
|
||||
if(b.Equals(se->a) && a.Equals(se->b)) goto intersects;
|
||||
|
||||
double dist_a = (se->a).DistanceToLine(a, d),
|
||||
dist_b = (se->b).DistanceToLine(a, d);
|
||||
dist_a = (se->a).DistanceToLine(a, d),
|
||||
dist_b = (se->b).DistanceToLine(a, d);
|
||||
|
||||
if(fabs(dist_a - dist_b) < LENGTH_EPS) {
|
||||
// The edges are parallel.
|
||||
|
@ -167,28 +174,25 @@ bool SEdgeList::AnyEdgeCrosses(Vector a, Vector b) {
|
|||
// on the other
|
||||
double t;
|
||||
t = ((se->a).Minus(a)).DivPivoting(d);
|
||||
if(t > t_eps && t < (1 - t_eps)) return true;
|
||||
if(t > t_eps && t < (1 - t_eps)) goto intersects;
|
||||
t = ((se->b).Minus(a)).DivPivoting(d);
|
||||
if(t > t_eps && t < (1 - t_eps)) return true;
|
||||
if(t > t_eps && t < (1 - t_eps)) goto intersects;
|
||||
t = a.Minus(se->a).DivPivoting(dse);
|
||||
if(t > tse_eps && t < (1 - tse_eps)) return true;
|
||||
if(t > tse_eps && t < (1 - tse_eps)) goto intersects;
|
||||
t = b.Minus(se->a).DivPivoting(dse);
|
||||
if(t > tse_eps && t < (1 - tse_eps)) return true;
|
||||
if(t > tse_eps && t < (1 - tse_eps)) goto intersects;
|
||||
// So coincident but disjoint, okay.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Lines are not parallel, so look for an intersection.
|
||||
double t, tse;
|
||||
bool skew;
|
||||
Vector pi = Vector::AtIntersectionOfLines(a, b,
|
||||
se->a, se->b,
|
||||
&skew,
|
||||
&t, &tse);
|
||||
pi = Vector::AtIntersectionOfLines(a, b, se->a, se->b,
|
||||
&skew,
|
||||
&t, &tse);
|
||||
if(skew) continue;
|
||||
|
||||
bool inOrEdge0 = (t > -t_eps) && (t < (1 + t_eps));
|
||||
bool inOrEdge1 = (tse > -tse_eps) && (tse < (1 + tse_eps));
|
||||
inOrEdge0 = (t > -t_eps) && (t < (1 + t_eps));
|
||||
inOrEdge1 = (tse > -tse_eps) && (tse < (1 + tse_eps));
|
||||
|
||||
if(inOrEdge0 && inOrEdge1) {
|
||||
if((se->a).Equals(a) || (se->b).Equals(a) ||
|
||||
|
@ -200,10 +204,16 @@ bool SEdgeList::AnyEdgeCrosses(Vector a, Vector b) {
|
|||
// But it's an intersection if a vertex of one edge lies on the
|
||||
// inside of the other (or if they cross away from either's
|
||||
// vertex).
|
||||
return true;
|
||||
if(ppi) *ppi = pi;
|
||||
goto intersects;
|
||||
}
|
||||
continue;
|
||||
|
||||
intersects:
|
||||
cnt++;
|
||||
// and continue with the loop
|
||||
}
|
||||
return false;
|
||||
return cnt;
|
||||
}
|
||||
|
||||
void SContour::AddPoint(Vector p) {
|
||||
|
@ -416,6 +426,19 @@ bool SPolygon::AllPointsInPlane(Vector *notCoplanarAt) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool SPolygon::SelfIntersecting(Vector *intersectsAt) {
|
||||
SEdgeList el;
|
||||
ZERO(&el);
|
||||
MakeEdgesInto(&el);
|
||||
|
||||
SEdge *se;
|
||||
for(se = el.l.First(); se; se = el.l.NextAfter(se)) {
|
||||
int inters = el.AnyEdgeCrossings(se->a, se->b, intersectsAt);
|
||||
if(inters != 1) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int TriMode, TriVertexCount;
|
||||
static Vector Tri1, TriNMinus1, TriNMinus2;
|
||||
static Vector TriNormal;
|
||||
|
|
|
@ -24,7 +24,7 @@ public:
|
|||
bool AssemblePolygon(SPolygon *dest, SEdge *errorAt);
|
||||
bool AssembleContour(Vector first, Vector last, SContour *dest,
|
||||
SEdge *errorAt);
|
||||
bool AnyEdgeCrosses(Vector a, Vector b);
|
||||
int AnyEdgeCrossings(Vector a, Vector b, Vector *pi=NULL);
|
||||
};
|
||||
|
||||
class SPoint {
|
||||
|
@ -83,6 +83,7 @@ public:
|
|||
void TriangulateInto(SMesh *m, STriMeta meta);
|
||||
void Clear(void);
|
||||
bool AllPointsInPlane(Vector *notCoplanarAt);
|
||||
bool SelfIntersecting(Vector *intersectsAt);
|
||||
bool IsEmpty(void);
|
||||
Vector AnyPoint(void);
|
||||
void OffsetInto(SPolygon *dest, double r);
|
||||
|
@ -220,9 +221,6 @@ public:
|
|||
void FindEdgeOn(Vector a, Vector b, int *n, int *nOther,
|
||||
STriMeta m, int cnt);
|
||||
void MakeCertainEdgesInto(SEdgeList *sel, bool emphasized);
|
||||
|
||||
void SnapToMesh(SMesh *m);
|
||||
void SnapToVertex(Vector v, SMesh *extras);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
22
sketch.h
22
sketch.h
|
@ -138,24 +138,24 @@ public:
|
|||
|
||||
SPolygon poly;
|
||||
SBezierLoopSet bezierLoopSet;
|
||||
static const int POLY_GOOD = 0;
|
||||
static const int POLY_NOT_CLOSED = 1;
|
||||
static const int POLY_NOT_COPLANAR = 2;
|
||||
static const int POLY_GOOD = 0;
|
||||
static const int POLY_NOT_CLOSED = 1;
|
||||
static const int POLY_NOT_COPLANAR = 2;
|
||||
static const int POLY_SELF_INTERSECTING = 3;
|
||||
struct {
|
||||
int how;
|
||||
SEdge notClosedAt;
|
||||
Vector notCoplanarAt;
|
||||
Vector errorPointAt;
|
||||
} polyError;
|
||||
|
||||
SMesh thisMesh;
|
||||
SShell thisShell;
|
||||
SShell runningShell;
|
||||
SMesh runningMesh;
|
||||
struct {
|
||||
SMesh interferesAt;
|
||||
bool yes;
|
||||
} meshError;
|
||||
SEdgeList emphEdges;
|
||||
SShell thisShell;
|
||||
SShell runningShell;
|
||||
|
||||
static const int COMBINE_AS_UNION = 0;
|
||||
static const int COMBINE_AS_DIFFERENCE = 1;
|
||||
|
@ -206,11 +206,9 @@ public:
|
|||
bool AssembleLoops(void);
|
||||
void GenerateLoops(void);
|
||||
// And the mesh stuff
|
||||
SMesh *PreviousGroupMesh(void);
|
||||
void AddQuadWithNormal(STriMeta meta, Vector out,
|
||||
Vector a, Vector b, Vector c, Vector d);
|
||||
void GenerateMeshForStepAndRepeat(void);
|
||||
void GenerateMesh(void);
|
||||
SShell *PreviousGroupShell(void);
|
||||
void GenerateShellForStepAndRepeat(void);
|
||||
void GenerateShellAndMesh(void);
|
||||
void Draw(void);
|
||||
|
||||
SPolygon GetPolygon(void);
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
#include "solvespace.h"
|
||||
|
||||
void SShell::MakeFromUnionOf(SShell *a, SShell *b) {
|
||||
MakeFromCopyOf(b);
|
||||
}
|
||||
|
||||
void SShell::MakeFromDifferenceOf(SShell *a, SShell *b) {
|
||||
MakeFromCopyOf(b);
|
||||
}
|
||||
|
156
srf/ratpoly.cpp
156
srf/ratpoly.cpp
|
@ -147,6 +147,14 @@ void SBezier::Reverse(void) {
|
|||
}
|
||||
}
|
||||
|
||||
SBezier SBezier::TransformedBy(Vector t, Quaternion q) {
|
||||
SBezier ret = *this;
|
||||
int i;
|
||||
for(i = 0; i <= deg; i++) {
|
||||
ret.ctrl[i] = (q.Rotate(ret.ctrl[i])).Plus(t);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SBezierList::Clear(void) {
|
||||
l.Clear();
|
||||
|
@ -292,6 +300,22 @@ void SBezierLoopSet::Clear(void) {
|
|||
l.Clear();
|
||||
}
|
||||
|
||||
SCurve SCurve::FromTransformationOf(SCurve *a, Vector t, Quaternion q) {
|
||||
SCurve ret;
|
||||
ZERO(&ret);
|
||||
|
||||
ret.h = a->h;
|
||||
ret.isExact = a->isExact;
|
||||
ret.exact = (a->exact).TransformedBy(t, q);
|
||||
|
||||
Vector *p;
|
||||
for(p = a->pts.First(); p; p = a->pts.NextAfter(p)) {
|
||||
Vector pp = (q.Rotate(*p)).Plus(t);
|
||||
ret.pts.Add(&pp);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SCurve::Clear(void) {
|
||||
pts.Clear();
|
||||
}
|
||||
|
@ -346,6 +370,37 @@ SSurface SSurface::FromPlane(Vector pt, Vector n) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
SSurface SSurface::FromTransformationOf(SSurface *a, Vector t, Quaternion q,
|
||||
bool includingTrims)
|
||||
{
|
||||
SSurface ret;
|
||||
ZERO(&ret);
|
||||
|
||||
ret.h = a->h;
|
||||
|
||||
ret.degm = a->degm;
|
||||
ret.degn = a->degn;
|
||||
int i, j;
|
||||
for(i = 0; i <= 3; i++) {
|
||||
for(j = 0; j <= 3; j++) {
|
||||
ret.ctrl[i][j] = (q.Rotate(a->ctrl[i][j])).Plus(t);
|
||||
ret.weight[i][j] = a->weight[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
if(includingTrims) {
|
||||
STrimBy *stb;
|
||||
for(stb = a->trim.First(); stb; stb = a->trim.NextAfter(stb)) {
|
||||
STrimBy n = *stb;
|
||||
n.start = (q.Rotate(n.start)) .Plus(t);
|
||||
n.finish = (q.Rotate(n.finish)).Plus(t);
|
||||
ret.trim.Add(&n);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Vector SSurface::PointAt(double u, double v) {
|
||||
Vector num = Vector::From(0, 0, 0);
|
||||
double den = 0;
|
||||
|
@ -449,32 +504,42 @@ void SSurface::ClosestPointTo(Vector p, double *u, double *v) {
|
|||
}
|
||||
}
|
||||
|
||||
void SSurface::TriangulateInto(SShell *shell, SMesh *sm) {
|
||||
SEdgeList el;
|
||||
ZERO(&el);
|
||||
|
||||
void SSurface::MakeEdgesInto(SShell *shell, SEdgeList *sel, bool asUv) {
|
||||
STrimBy *stb;
|
||||
for(stb = trim.First(); stb; stb = trim.NextAfter(stb)) {
|
||||
SCurve *sc = shell->curve.FindById(stb->curve);
|
||||
|
||||
Vector prevuv, ptuv;
|
||||
Vector prev, prevuv, ptuv;
|
||||
bool inCurve = false;
|
||||
Vector *pt;
|
||||
double u = 0, v = 0;
|
||||
for(pt = sc->pts.First(); pt; pt = sc->pts.NextAfter(pt)) {
|
||||
ClosestPointTo(*pt, &u, &v);
|
||||
ptuv = Vector::From(u, v, 0);
|
||||
|
||||
if(inCurve) {
|
||||
el.AddEdge(prevuv, ptuv);
|
||||
if(asUv) {
|
||||
ClosestPointTo(*pt, &u, &v);
|
||||
ptuv = Vector::From(u, v, 0);
|
||||
if(inCurve) {
|
||||
sel->AddEdge(prevuv, ptuv);
|
||||
}
|
||||
prevuv = ptuv;
|
||||
} else {
|
||||
if(inCurve) {
|
||||
sel->AddEdge(prev, *pt);
|
||||
}
|
||||
prev = *pt;
|
||||
}
|
||||
prevuv = ptuv;
|
||||
|
||||
if(pt->EqualsExactly(stb->start)) inCurve = true;
|
||||
if(pt->EqualsExactly(stb->finish)) inCurve = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SSurface::TriangulateInto(SShell *shell, SMesh *sm) {
|
||||
SEdgeList el;
|
||||
ZERO(&el);
|
||||
|
||||
MakeEdgesInto(shell, &el, true);
|
||||
|
||||
SPolygon poly;
|
||||
ZERO(&poly);
|
||||
if(!el.AssemblePolygon(&poly, NULL)) {
|
||||
|
@ -508,9 +573,8 @@ void SSurface::Clear(void) {
|
|||
trim.Clear();
|
||||
}
|
||||
|
||||
SShell SShell::FromExtrusionOf(SBezierLoopSet *sbls, Vector t0, Vector t1) {
|
||||
SShell ret;
|
||||
ZERO(&ret);
|
||||
void SShell::MakeFromExtrusionOf(SBezierLoopSet *sbls, Vector t0, Vector t1) {
|
||||
ZERO(this);
|
||||
|
||||
// Make the extrusion direction consistent with respect to the normal
|
||||
// of the sketch we're extruding.
|
||||
|
@ -523,8 +587,8 @@ SShell SShell::FromExtrusionOf(SBezierLoopSet *sbls, Vector t0, Vector t1) {
|
|||
SSurface s0, s1;
|
||||
s0 = SSurface::FromPlane(sbls->point.Plus(t0), sbls->normal.ScaledBy(-1));
|
||||
s1 = SSurface::FromPlane(sbls->point.Plus(t1), sbls->normal.ScaledBy( 1));
|
||||
hSSurface hs0 = ret.surface.AddAndAssignId(&s0),
|
||||
hs1 = ret.surface.AddAndAssignId(&s1);
|
||||
hSSurface hs0 = surface.AddAndAssignId(&s0),
|
||||
hs1 = surface.AddAndAssignId(&s1);
|
||||
|
||||
// Now go through the input curves. For each one, generate its surface
|
||||
// of extrusion, its two translated trim curves, and one trim line. We
|
||||
|
@ -544,27 +608,27 @@ SShell SShell::FromExtrusionOf(SBezierLoopSet *sbls, Vector t0, Vector t1) {
|
|||
// Generate the surface of extrusion of this curve, and add
|
||||
// it to the list
|
||||
SSurface ss = SSurface::FromExtrusionOf(sb, t0, t1);
|
||||
hSSurface hsext = ret.surface.AddAndAssignId(&ss);
|
||||
hSSurface hsext = surface.AddAndAssignId(&ss);
|
||||
|
||||
// Translate the curve by t0 and t1 to produce two trim curves
|
||||
SCurve sc;
|
||||
ZERO(&sc);
|
||||
sb->MakePwlInto(&(sc.pts), t0);
|
||||
hSCurve hc0 = ret.curve.AddAndAssignId(&sc);
|
||||
STrimBy stb0 = STrimBy::EntireCurve(&ret, hc0);
|
||||
hSCurve hc0 = curve.AddAndAssignId(&sc);
|
||||
STrimBy stb0 = STrimBy::EntireCurve(this, hc0);
|
||||
|
||||
ZERO(&sc);
|
||||
sb->MakePwlInto(&(sc.pts), t1);
|
||||
hSCurve hc1 = ret.curve.AddAndAssignId(&sc);
|
||||
STrimBy stb1 = STrimBy::EntireCurve(&ret, hc1);
|
||||
hSCurve hc1 = curve.AddAndAssignId(&sc);
|
||||
STrimBy stb1 = STrimBy::EntireCurve(this, hc1);
|
||||
|
||||
// The translated curves trim the flat top and bottom surfaces.
|
||||
// (ret.surface.FindById(hs0))->trim.Add(&stb0);
|
||||
(ret.surface.FindById(hs1))->trim.Add(&stb1);
|
||||
(surface.FindById(hs0))->trim.Add(&stb0);
|
||||
(surface.FindById(hs1))->trim.Add(&stb1);
|
||||
|
||||
// The translated curves also trim the surface of extrusion.
|
||||
// (ret.surface.FindById(hsext))->trim.Add(&stb0);
|
||||
// (ret.surface.FindById(hsext))->trim.Add(&stb1);
|
||||
(surface.FindById(hsext))->trim.Add(&stb0);
|
||||
(surface.FindById(hsext))->trim.Add(&stb1);
|
||||
|
||||
// And form the trim line
|
||||
Vector pt = sb->Finish();
|
||||
|
@ -572,10 +636,10 @@ SShell SShell::FromExtrusionOf(SBezierLoopSet *sbls, Vector t0, Vector t1) {
|
|||
ZERO(&sc);
|
||||
sc.pts.Add(&p0);
|
||||
sc.pts.Add(&p1);
|
||||
hSCurve hl = ret.curve.AddAndAssignId(&sc);
|
||||
hSCurve hl = curve.AddAndAssignId(&sc);
|
||||
// save this for later
|
||||
TrimLine tl;
|
||||
tl.trim = STrimBy::EntireCurve(&ret, hl);
|
||||
tl.trim = STrimBy::EntireCurve(this, hl);
|
||||
tl.hs = hsext;
|
||||
trimLines.Add(&tl);
|
||||
}
|
||||
|
@ -583,17 +647,45 @@ SShell SShell::FromExtrusionOf(SBezierLoopSet *sbls, Vector t0, Vector t1) {
|
|||
int i;
|
||||
for(i = 0; i < trimLines.n; i++) {
|
||||
TrimLine *tl = &(trimLines.elem[i]);
|
||||
SSurface *ss = ret.surface.FindById(tl->hs);
|
||||
SSurface *ss = surface.FindById(tl->hs);
|
||||
|
||||
TrimLine *tlp = &(trimLines.elem[WRAP(i-1, trimLines.n)]);
|
||||
|
||||
// ss->trim.Add(&(tl->trim));
|
||||
// ss->trim.Add(&(tlp->trim));
|
||||
ss->trim.Add(&(tl->trim));
|
||||
ss->trim.Add(&(tlp->trim));
|
||||
}
|
||||
trimLines.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
void SShell::MakeFromCopyOf(SShell *a) {
|
||||
Vector t = Vector::From(0, 0, 0);
|
||||
Quaternion q = Quaternion::From(1, 0, 0, 0);
|
||||
|
||||
MakeFromTransformationOf(a, t, q);
|
||||
}
|
||||
|
||||
void SShell::MakeFromTransformationOf(SShell *a, Vector t, Quaternion q) {
|
||||
SSurface *s;
|
||||
for(s = a->surface.First(); s; s = a->surface.NextAfter(s)) {
|
||||
SSurface n;
|
||||
n = SSurface::FromTransformationOf(s, t, q, true);
|
||||
surface.Add(&n); // keeping the old ID
|
||||
}
|
||||
|
||||
SCurve *c;
|
||||
for(c = a->curve.First(); c; c = a->curve.NextAfter(c)) {
|
||||
SCurve n;
|
||||
n = SCurve::FromTransformationOf(c, t, q);
|
||||
curve.Add(&n); // keeping the old ID
|
||||
}
|
||||
}
|
||||
|
||||
void SShell::MakeEdgesInto(SEdgeList *sel) {
|
||||
SSurface *s;
|
||||
for(s = surface.First(); s; s = surface.NextAfter(s)) {
|
||||
s->MakeEdgesInto(this, sel, false);
|
||||
}
|
||||
}
|
||||
|
||||
void SShell::TriangulateInto(SMesh *sm) {
|
||||
|
|
|
@ -36,6 +36,8 @@ public:
|
|||
|
||||
void Reverse(void);
|
||||
|
||||
SBezier TransformedBy(Vector t, Quaternion q);
|
||||
|
||||
static SBezier From(Vector p0, Vector p1, Vector p2, Vector p3);
|
||||
static SBezier From(Vector p0, Vector p1, Vector p2);
|
||||
static SBezier From(Vector p0, Vector p1);
|
||||
|
@ -82,6 +84,9 @@ public:
|
|||
|
||||
List<Vector> pts;
|
||||
|
||||
static SCurve SCurve::FromTransformationOf(SCurve *a,
|
||||
Vector t, Quaternion q);
|
||||
|
||||
void Clear(void);
|
||||
};
|
||||
|
||||
|
@ -112,6 +117,8 @@ public:
|
|||
|
||||
static SSurface FromExtrusionOf(SBezier *spc, Vector t0, Vector t1);
|
||||
static SSurface FromPlane(Vector pt, Vector n);
|
||||
static SSurface FromTransformationOf(SSurface *a, Vector t, Quaternion q,
|
||||
bool includingTrims);
|
||||
|
||||
void ClosestPointTo(Vector p, double *u, double *v);
|
||||
Vector PointAt(double u, double v);
|
||||
|
@ -119,6 +126,7 @@ public:
|
|||
Vector NormalAt(double u, double v);
|
||||
|
||||
void TriangulateInto(SShell *shell, SMesh *sm);
|
||||
void MakeEdgesInto(SShell *shell, SEdgeList *sel, bool asUv);
|
||||
|
||||
void Clear(void);
|
||||
};
|
||||
|
@ -128,11 +136,14 @@ public:
|
|||
IdList<SCurve,hSCurve> curve;
|
||||
IdList<SSurface,hSSurface> surface;
|
||||
|
||||
static SShell FromExtrusionOf(SBezierLoopSet *sbls, Vector t0, Vector t1);
|
||||
|
||||
static SShell FromUnionOf(SShell *a, SShell *b);
|
||||
void MakeFromExtrusionOf(SBezierLoopSet *sbls, Vector t0, Vector t1);
|
||||
void MakeFromUnionOf(SShell *a, SShell *b);
|
||||
void MakeFromDifferenceOf(SShell *a, SShell *b);
|
||||
void MakeFromCopyOf(SShell *a);
|
||||
void MakeFromTransformationOf(SShell *a, Vector trans, Quaternion q);
|
||||
|
||||
void TriangulateInto(SMesh *sm);
|
||||
void MakeEdgesInto(SEdgeList *sel);
|
||||
void Clear(void);
|
||||
};
|
||||
|
||||
|
|
|
@ -133,7 +133,7 @@ bool SContour::BridgeToContour(SContour *sc,
|
|||
}
|
||||
if(f) continue;
|
||||
|
||||
if(avoidEdges->AnyEdgeCrosses(a, b)) {
|
||||
if(avoidEdges->AnyEdgeCrossings(a, b) > 0) {
|
||||
// doesn't work, bridge crosses an existing edge
|
||||
} else {
|
||||
goto haveEdge;
|
||||
|
|
|
@ -46,12 +46,10 @@ void SolveSpace::PushFromCurrentOnto(UndoStack *uk) {
|
|||
// And then clean up all the stuff that needs to be a deep copy,
|
||||
// and zero out all the dynamic stuff that will get regenerated.
|
||||
dest.clean = false;
|
||||
dest.vvMeshClean = false;
|
||||
ZERO(&(dest.solved));
|
||||
ZERO(&(dest.poly));
|
||||
ZERO(&(dest.bezierLoopSet));
|
||||
ZERO(&(dest.polyError));
|
||||
ZERO(&(dest.thisMesh));
|
||||
ZERO(&(dest.runningMesh));
|
||||
ZERO(&(dest.thisShell));
|
||||
ZERO(&(dest.runningShell));
|
||||
|
@ -95,7 +93,6 @@ void SolveSpace::PopOntoCurrentFrom(UndoStack *uk) {
|
|||
Group *g = &(group.elem[i]);
|
||||
g->poly.Clear();
|
||||
g->bezierLoopSet.Clear();
|
||||
g->thisMesh.Clear();
|
||||
g->runningMesh.Clear();
|
||||
g->thisShell.Clear();
|
||||
g->runningShell.Clear();
|
||||
|
|
Loading…
Reference in New Issue