NURBS: Add intersection boolean operation.
The NURBS operation is properly implemented. ToDo: The mesh operation in SMesh::MakeFromIntersectionOf is still done as C=A-(A-B). Implements: https://github.com/solvespace/solvespace/issues/35pull/607/head
parent
c95a07a1de
commit
3888909d02
|
@ -5,6 +5,7 @@ Changelog
|
||||||
---
|
---
|
||||||
|
|
||||||
New sketch features:
|
New sketch features:
|
||||||
|
* New intersection boolean operation for solid models.
|
||||||
* New groups, revolution and helical extrusion.
|
* New groups, revolution and helical extrusion.
|
||||||
* Extrude, lathe, translate and rotate groups can use the "assembly"
|
* Extrude, lathe, translate and rotate groups can use the "assembly"
|
||||||
boolean operation, to increase performance.
|
boolean operation, to increase performance.
|
||||||
|
|
|
@ -143,7 +143,7 @@ void Group::GenerateForStepAndRepeat(T *steps, T *outs, Group::CombineAs forWhat
|
||||||
// And tack this transformed copy on to the return.
|
// And tack this transformed copy on to the return.
|
||||||
if(soFar->IsEmpty()) {
|
if(soFar->IsEmpty()) {
|
||||||
scratch->MakeFromCopyOf(&transd);
|
scratch->MakeFromCopyOf(&transd);
|
||||||
} else if (forWhat == CombineAs::ASSEMBLE) {
|
} else if(forWhat == CombineAs::ASSEMBLE) {
|
||||||
scratch->MakeFromAssemblyOf(soFar, &transd);
|
scratch->MakeFromAssemblyOf(soFar, &transd);
|
||||||
} else {
|
} else {
|
||||||
scratch->MakeFromUnionOf(soFar, &transd);
|
scratch->MakeFromUnionOf(soFar, &transd);
|
||||||
|
@ -170,12 +170,22 @@ void Group::GenerateForBoolean(T *prevs, T *thiss, T *outs, Group::CombineAs how
|
||||||
|
|
||||||
// So our group's shell appears in thisShell. Combine this with the
|
// So our group's shell appears in thisShell. Combine this with the
|
||||||
// previous group's shell, using the requested operation.
|
// previous group's shell, using the requested operation.
|
||||||
if(how == CombineAs::UNION) {
|
switch(how) {
|
||||||
outs->MakeFromUnionOf(prevs, thiss);
|
case CombineAs::UNION:
|
||||||
} else if(how == CombineAs::DIFFERENCE) {
|
outs->MakeFromUnionOf(prevs, thiss);
|
||||||
outs->MakeFromDifferenceOf(prevs, thiss);
|
break;
|
||||||
} else {
|
|
||||||
outs->MakeFromAssemblyOf(prevs, thiss);
|
case CombineAs::DIFFERENCE:
|
||||||
|
outs->MakeFromDifferenceOf(prevs, thiss);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CombineAs::INTERSECTION:
|
||||||
|
outs->MakeFromIntersectionOf(prevs, thiss);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CombineAs::ASSEMBLE:
|
||||||
|
outs->MakeFromAssemblyOf(prevs, thiss);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
17
src/mesh.cpp
17
src/mesh.cpp
|
@ -286,6 +286,23 @@ void SMesh::MakeFromDifferenceOf(SMesh *a, SMesh *b) {
|
||||||
AddAgainstBsp(a, bspb);
|
AddAgainstBsp(a, bspb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SMesh::MakeFromIntersectionOf(SMesh *a, SMesh *b) {
|
||||||
|
// Emulate triangle mesh intersection with difference
|
||||||
|
// by doing C=A-(A-B). Figure out how to do it properly later.
|
||||||
|
SMesh c = {};
|
||||||
|
c.MakeFromDifferenceOf(a, b);
|
||||||
|
MakeFromDifferenceOf(a, &c);
|
||||||
|
|
||||||
|
c.Clear();
|
||||||
|
|
||||||
|
/* SBsp3 *bspa = SBsp3::FromMesh(a);
|
||||||
|
SBsp3 *bspb = SBsp3::FromMesh(b);
|
||||||
|
|
||||||
|
AddAgainstBsp(a, bspb);
|
||||||
|
AddAgainstBsp(b, bspa);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
void SMesh::MakeFromCopyOf(SMesh *a) {
|
void SMesh::MakeFromCopyOf(SMesh *a) {
|
||||||
ssassert(this != a, "Can't make from copy of self");
|
ssassert(this != a, "Can't make from copy of self");
|
||||||
for(int i = 0; i < a->l.n; i++) {
|
for(int i = 0; i < a->l.n; i++) {
|
||||||
|
|
|
@ -269,6 +269,7 @@ public:
|
||||||
void AddAgainstBsp(SMesh *srcm, SBsp3 *bsp3);
|
void AddAgainstBsp(SMesh *srcm, SBsp3 *bsp3);
|
||||||
void MakeFromUnionOf(SMesh *a, SMesh *b);
|
void MakeFromUnionOf(SMesh *a, SMesh *b);
|
||||||
void MakeFromDifferenceOf(SMesh *a, SMesh *b);
|
void MakeFromDifferenceOf(SMesh *a, SMesh *b);
|
||||||
|
void MakeFromIntersectionOf(SMesh *a, SMesh *b);
|
||||||
|
|
||||||
void MakeFromCopyOf(SMesh *a);
|
void MakeFromCopyOf(SMesh *a);
|
||||||
void MakeFromTransformationOf(SMesh *a, Vector trans,
|
void MakeFromTransformationOf(SMesh *a, Vector trans,
|
||||||
|
|
|
@ -239,7 +239,8 @@ public:
|
||||||
enum class CombineAs : uint32_t {
|
enum class CombineAs : uint32_t {
|
||||||
UNION = 0,
|
UNION = 0,
|
||||||
DIFFERENCE = 1,
|
DIFFERENCE = 1,
|
||||||
ASSEMBLE = 2
|
ASSEMBLE = 2,
|
||||||
|
INTERSECTION = 3
|
||||||
};
|
};
|
||||||
CombineAs meshCombine;
|
CombineAs meshCombine;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Top-level functions to compute the Boolean union or difference between
|
// Top-level functions to compute the Boolean union, difference or intersection
|
||||||
// two shells of rational polynomial surfaces.
|
// between two shells of rational polynomial surfaces.
|
||||||
//
|
//
|
||||||
// Copyright 2008-2013 Jonathan Westhues.
|
// Copyright 2008-2013 Jonathan Westhues.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
@ -16,6 +16,10 @@ void SShell::MakeFromDifferenceOf(SShell *a, SShell *b) {
|
||||||
MakeFromBoolean(a, b, SSurface::CombineAs::DIFFERENCE);
|
MakeFromBoolean(a, b, SSurface::CombineAs::DIFFERENCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SShell::MakeFromIntersectionOf(SShell *a, SShell *b) {
|
||||||
|
MakeFromBoolean(a, b, SSurface::CombineAs::INTERSECTION);
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Take our original pwl curve. Wherever an edge intersects a surface within
|
// Take our original pwl curve. Wherever an edge intersects a surface within
|
||||||
// either agnstA or agnstB, split the piecewise linear element. Then refine
|
// either agnstA or agnstB, split the piecewise linear element. Then refine
|
||||||
|
@ -213,6 +217,13 @@ static bool KeepRegion(SSurface::CombineAs type, bool opA, SShell::Class shell,
|
||||||
return inShell || inSame;
|
return inShell || inSame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case SSurface::CombineAs::INTERSECTION:
|
||||||
|
if(opA) {
|
||||||
|
return inShell;
|
||||||
|
} else {
|
||||||
|
return inShell || inSame;
|
||||||
|
}
|
||||||
|
|
||||||
default: ssassert(false, "Unexpected combine type");
|
default: ssassert(false, "Unexpected combine type");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -463,7 +474,10 @@ SSurface SSurface::MakeCopyTrimAgainst(SShell *parent,
|
||||||
// point opposite to the surface normal.
|
// point opposite to the surface normal.
|
||||||
bool bkwds = true;
|
bool bkwds = true;
|
||||||
if((tn.Cross(b.Minus(a))).Dot(sn) < 0) bkwds = !bkwds;
|
if((tn.Cross(b.Minus(a))).Dot(sn) < 0) bkwds = !bkwds;
|
||||||
if(type == SSurface::CombineAs::DIFFERENCE && !opA) bkwds = !bkwds;
|
if((type == SSurface::CombineAs::DIFFERENCE && !opA) ||
|
||||||
|
(type == SSurface::CombineAs::INTERSECTION)) { // Invert all newly created edges for intersection
|
||||||
|
bkwds = !bkwds;
|
||||||
|
}
|
||||||
if(bkwds) {
|
if(bkwds) {
|
||||||
inter.AddEdge(tb, ta, sc->h.v, 1);
|
inter.AddEdge(tb, ta, sc->h.v, 1);
|
||||||
} else {
|
} else {
|
||||||
|
@ -573,7 +587,7 @@ SSurface SSurface::MakeCopyTrimAgainst(SShell *parent,
|
||||||
// we can get duplicate edges if our surface intersects the other shell
|
// we can get duplicate edges if our surface intersects the other shell
|
||||||
// at an edge, so that both surfaces intersect coincident (and both
|
// at an edge, so that both surfaces intersect coincident (and both
|
||||||
// generate an intersection edge).
|
// generate an intersection edge).
|
||||||
final.CullExtraneousEdges();
|
final.CullExtraneousEdges(/*both=*/true);
|
||||||
|
|
||||||
// Use our reassembled edges to trim the new surface.
|
// Use our reassembled edges to trim the new surface.
|
||||||
ret.TrimFromEdgeList(&final, /*asUv=*/true);
|
ret.TrimFromEdgeList(&final, /*asUv=*/true);
|
||||||
|
@ -849,14 +863,14 @@ void SBspUv::InsertEdge(Point2d ea, Point2d eb, SSurface *srf) {
|
||||||
m->more = more;
|
m->more = more;
|
||||||
more = m;
|
more = m;
|
||||||
} else if(fabs(dea) < LENGTH_EPS) {
|
} else if(fabs(dea) < LENGTH_EPS) {
|
||||||
// Point A lies on this lie, but point B does not
|
// Point A lies on this line, but point B does not
|
||||||
if(deb > 0) {
|
if(deb > 0) {
|
||||||
pos = InsertOrCreateEdge(pos, ea, eb, srf);
|
pos = InsertOrCreateEdge(pos, ea, eb, srf);
|
||||||
} else {
|
} else {
|
||||||
neg = InsertOrCreateEdge(neg, ea, eb, srf);
|
neg = InsertOrCreateEdge(neg, ea, eb, srf);
|
||||||
}
|
}
|
||||||
} else if(fabs(deb) < LENGTH_EPS) {
|
} else if(fabs(deb) < LENGTH_EPS) {
|
||||||
// Point B lies on this lie, but point A does not
|
// Point B lies on this line, but point A does not
|
||||||
if(dea > 0) {
|
if(dea > 0) {
|
||||||
pos = InsertOrCreateEdge(pos, ea, eb, srf);
|
pos = InsertOrCreateEdge(pos, ea, eb, srf);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -256,7 +256,7 @@ public:
|
||||||
enum class CombineAs : uint32_t {
|
enum class CombineAs : uint32_t {
|
||||||
UNION = 10,
|
UNION = 10,
|
||||||
DIFFERENCE = 11,
|
DIFFERENCE = 11,
|
||||||
INTERSECT = 12
|
INTERSECTION = 12
|
||||||
};
|
};
|
||||||
|
|
||||||
int tag;
|
int tag;
|
||||||
|
@ -386,6 +386,7 @@ public:
|
||||||
void MakeFirstOrderRevolvedSurfaces(Vector pt, Vector axis, int i0);
|
void MakeFirstOrderRevolvedSurfaces(Vector pt, Vector axis, int i0);
|
||||||
void MakeFromUnionOf(SShell *a, SShell *b);
|
void MakeFromUnionOf(SShell *a, SShell *b);
|
||||||
void MakeFromDifferenceOf(SShell *a, SShell *b);
|
void MakeFromDifferenceOf(SShell *a, SShell *b);
|
||||||
|
void MakeFromIntersectionOf(SShell *a, SShell *b);
|
||||||
void MakeFromBoolean(SShell *a, SShell *b, SSurface::CombineAs type);
|
void MakeFromBoolean(SShell *a, SShell *b, SSurface::CombineAs type);
|
||||||
void CopyCurvesSplitAgainst(bool opA, SShell *agnst, SShell *into);
|
void CopyCurvesSplitAgainst(bool opA, SShell *agnst, SShell *into);
|
||||||
void CopySurfacesTrimAgainst(SShell *sha, SShell *shb, SShell *into, SSurface::CombineAs type);
|
void CopySurfacesTrimAgainst(SShell *sha, SShell *shb, SShell *into, SSurface::CombineAs type);
|
||||||
|
|
|
@ -210,11 +210,19 @@ void TextWindow::ScreenChangeGroupOption(int link, uint32_t v) {
|
||||||
if(g->type == Group::Type::EXTRUDE) {
|
if(g->type == Group::Type::EXTRUDE) {
|
||||||
// When an extrude group is first created, it's positioned for a union
|
// When an extrude group is first created, it's positioned for a union
|
||||||
// extrusion. If no constraints were added, flip it when we switch between
|
// extrusion. If no constraints were added, flip it when we switch between
|
||||||
// union and difference modes to avoid manual work doing the same.
|
// union/assemble and difference/intersection modes to avoid manual work doing the same.
|
||||||
if(g->meshCombine != (Group::CombineAs)v && g->GetNumConstraints() == 0 &&
|
if(g->meshCombine != (Group::CombineAs)v && g->GetNumConstraints() == 0) {
|
||||||
((Group::CombineAs)v == Group::CombineAs::DIFFERENCE ||
|
// I apologise for his if statement
|
||||||
g->meshCombine == Group::CombineAs::DIFFERENCE)) {
|
if(((Group::CombineAs::DIFFERENCE == g->meshCombine ||
|
||||||
g->ExtrusionForceVectorTo(g->ExtrusionGetVector().Negated());
|
Group::CombineAs::INTERSECTION == g->meshCombine) &&
|
||||||
|
(Group::CombineAs::DIFFERENCE != (Group::CombineAs)v &&
|
||||||
|
Group::CombineAs::INTERSECTION != (Group::CombineAs)v)) ||
|
||||||
|
((Group::CombineAs::DIFFERENCE != g->meshCombine &&
|
||||||
|
Group::CombineAs::INTERSECTION != g->meshCombine) &&
|
||||||
|
(Group::CombineAs::DIFFERENCE == (Group::CombineAs)v ||
|
||||||
|
Group::CombineAs::INTERSECTION == (Group::CombineAs)v))) {
|
||||||
|
g->ExtrusionForceVectorTo(g->ExtrusionGetVector().Negated());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g->meshCombine = (Group::CombineAs)v;
|
g->meshCombine = (Group::CombineAs)v;
|
||||||
|
@ -375,11 +383,13 @@ void TextWindow::ShowGroupInfo() {
|
||||||
g->type == Group::Type::HELIX) {
|
g->type == Group::Type::HELIX) {
|
||||||
bool un = (g->meshCombine == Group::CombineAs::UNION);
|
bool un = (g->meshCombine == Group::CombineAs::UNION);
|
||||||
bool diff = (g->meshCombine == Group::CombineAs::DIFFERENCE);
|
bool diff = (g->meshCombine == Group::CombineAs::DIFFERENCE);
|
||||||
|
bool intr = (g->meshCombine == Group::CombineAs::INTERSECTION);
|
||||||
bool asy = (g->meshCombine == Group::CombineAs::ASSEMBLE);
|
bool asy = (g->meshCombine == Group::CombineAs::ASSEMBLE);
|
||||||
|
|
||||||
Printf(false, " %Ftsolid model as");
|
Printf(false, " %Ftsolid model as");
|
||||||
Printf(false, "%Ba %f%D%Lc%Fd%s union%E "
|
Printf(false, "%Ba %f%D%Lc%Fd%s union%E "
|
||||||
"%f%D%Lc%Fd%s difference%E "
|
"%f%D%Lc%Fd%s difference%E "
|
||||||
|
"%f%D%Lc%Fd%s intersection%E "
|
||||||
"%f%D%Lc%Fd%s assemble%E ",
|
"%f%D%Lc%Fd%s assemble%E ",
|
||||||
&TextWindow::ScreenChangeGroupOption,
|
&TextWindow::ScreenChangeGroupOption,
|
||||||
Group::CombineAs::UNION,
|
Group::CombineAs::UNION,
|
||||||
|
@ -388,6 +398,9 @@ void TextWindow::ShowGroupInfo() {
|
||||||
Group::CombineAs::DIFFERENCE,
|
Group::CombineAs::DIFFERENCE,
|
||||||
diff ? RADIO_TRUE : RADIO_FALSE,
|
diff ? RADIO_TRUE : RADIO_FALSE,
|
||||||
&TextWindow::ScreenChangeGroupOption,
|
&TextWindow::ScreenChangeGroupOption,
|
||||||
|
Group::CombineAs::INTERSECTION,
|
||||||
|
intr ? RADIO_TRUE : RADIO_FALSE,
|
||||||
|
&TextWindow::ScreenChangeGroupOption,
|
||||||
Group::CombineAs::ASSEMBLE,
|
Group::CombineAs::ASSEMBLE,
|
||||||
(asy ? RADIO_TRUE : RADIO_FALSE));
|
(asy ? RADIO_TRUE : RADIO_FALSE));
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue