Skip to content

Commit

Permalink
Crazy visual debugging code for boolean oparations.
Browse files Browse the repository at this point in the history
Intersection works properly now!
  • Loading branch information
ruevs committed May 7, 2020
1 parent 9a82cbf commit 11e2db1
Show file tree
Hide file tree
Showing 8 changed files with 123 additions and 32 deletions.
3 changes: 2 additions & 1 deletion src/dsc.h
Expand Up @@ -209,8 +209,9 @@ class List {

public:
int n = 0;
uint32_t cc = 0;

bool IsEmpty() const { return n == 0; }
bool IsEmpty() const { return 0 >= n; } // A negative number of list elements?!

void ReserveMore(int howMuch) {
if(n + howMuch > elemsAllocated) {
Expand Down
3 changes: 2 additions & 1 deletion src/polygon.cpp
Expand Up @@ -213,13 +213,14 @@ void SEdgeList::Clear() {
l.Clear();
}

void SEdgeList::AddEdge(Vector a, Vector b, int auxA, int auxB, int tag) {
void SEdgeList::AddEdge(Vector a, Vector b, int auxA, int auxB, int tag, uint32_t cc) {
SEdge e = {};
e.tag = tag;
e.a = a;
e.b = b;
e.auxA = auxA;
e.auxB = auxB;
e.cc = cc;
l.Add(&e);
}

Expand Down
3 changes: 2 additions & 1 deletion src/polygon.h
Expand Up @@ -38,6 +38,7 @@ enum class EdgeKind : uint32_t {
class SEdge {
public:
int tag;
uint32_t cc;
int auxA, auxB;
Vector a, b;

Expand All @@ -50,7 +51,7 @@ class SEdgeList {
List<SEdge> l;

void Clear();
void AddEdge(Vector a, Vector b, int auxA=0, int auxB=0, int tag=0);
void AddEdge(Vector a, Vector b, int auxA=0, int auxB=0, int tag=0, uint32_t cc=0);
bool AssemblePolygon(SPolygon *dest, SEdge *errorAt, bool keepDir=false) const;
bool AssembleContour(Vector first, Vector last, SContour *dest,
SEdge *errorAt, bool keepDir, int start) const;
Expand Down
19 changes: 19 additions & 0 deletions src/render/rendergl1.cpp
Expand Up @@ -476,9 +476,28 @@ void OpenGl1Renderer::DrawLine(const Vector &a, const Vector &b, hStroke hcs) {

void OpenGl1Renderer::DrawEdges(const SEdgeList &el, hStroke hcs) {
double phase = 0.0;
unsigned n = 0;
for(const SEdge *e = el.l.First(); e; e = el.l.NextAfter(e)) {
DoStippledLine(e->a, e->b, hcs, phase);
phase += e->a.Minus(e->b).Magnitude();

/*debug*/
if(0 != e->cc) {
std::shared_ptr<SolveSpace::ViewportCanvas> canvas = SS.GW.canvas;

const Camera &camera = canvas->GetCamera();

Canvas::Stroke strokeError = Style::Stroke(Style::DRAW_ERROR);
strokeError.layer = Canvas::Layer::FRONT;
strokeError.width = 1.0f;
Canvas::hStroke hcsError = canvas->GetStroke(strokeError);

double textHeight = Style::DefaultTextHeight()*8 / camera.scale;

DrawVectorText(ssprintf(" %03u-%lu-%i-%i", n, e->cc, e->auxA, e->auxB ), textHeight + textHeight*n/1000, e->a,
camera.projRight, camera.projUp, hcsError);
++n;
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/sketch.h
Expand Up @@ -240,7 +240,7 @@ class Group {
UNION = 0,
DIFFERENCE = 1,
ASSEMBLE = 2,
INTERSECTION = 3,
INTERSECTION = 3
};
CombineAs meshCombine;

Expand Down
118 changes: 91 additions & 27 deletions src/srf/boolean.cpp
Expand Up @@ -167,7 +167,7 @@ void SSurface::TrimFromEdgeList(SEdgeList *el, bool asUv) {
stb.start = se->a;
stb.finish = se->b;
stb.curve.v = se->auxA;
stb.backwards = se->auxB ? true : false;
stb.backwards = se->auxB ? true : false; // ruevs: reverse here? No?

// Find adjoining edges from the same curve; those should be
// merged into a single trim.
Expand Down Expand Up @@ -239,6 +239,7 @@ static bool KeepEdge(SSurface::CombineAs type, bool opA,
SShell::Class indir_shell, SShell::Class outdir_shell,
SShell::Class indir_orig, SShell::Class outdir_orig)
{
// return true;
/*
INSIDE = 100,
OUTSIDE = 200,
Expand Down Expand Up @@ -271,34 +272,63 @@ static bool KeepEdge(SSurface::CombineAs type, bool opA,
break;

case SSurface::CombineAs::DIFFERENCE:
resultsmart = (SShell::Class::OUTSIDE==indir_shell) || // 1112 1212
resultsmart = (1112 == cc) || // Internal
(1211 == cc) ||
(2111 == cc) || // X intersections
(2311 == cc) ||
(2312 == cc) ||
(2411 == cc) ||
(4111 == cc) || // X with one side face on face opposite normals
(3112 == cc) ||
(3211 == cc) ||
((!opA) && // Edges which should be kept only from one shell
((3212 == cc) ||
(1212 == cc) || // Face on face same normal
(3312 == cc))
) ||
((opA) && // Edges which should be kept only from one shell
((2112 == cc) || // opA?
(2212 == cc))
);


/* resultsmart = (SShell::Class::OUTSIDE==indir_shell) || // 1112 1212
((!opA) && (
(SShell::Class::INSIDE==indir_shell) ||
(SShell::Class::COINC_SAME==indir_shell)
)
);
);*/
break;

case SSurface::CombineAs::INTERSECTION:
// "Stupid" decision derived by a lot of debugging
result = (1112 == cc) || // Internal
resultsmart = (1112 == cc) || // Internal
(1211 == cc) || // ??? visual
(1212 == cc) || // Face on face same normal
(1311 == cc) || // ??? visual
(1411 == cc) || // ??? visual
(2111 == cc) || // X intersections
(1212 == cc) || // Face on face same normal
(4111 == cc) || // X with one side face on face opposite normals
( (!opA) && // Edges which should be kept only from one shell
( (3312 == cc) || (2311 == cc) || // Face on face same normal
(2321 == cc) // Edge on edge
(2311 == cc) || // Face on face same normal
(3111 == cc) || // from smart ;-)
(3211 == cc) || // ??? visual
(4111 == cc) || // X with one side face on face opposite normals
((!opA) && // Edges which should be kept only from one shell
( (3312 == cc) ||
(3212 == cc) /*|| // ??? visual
(2321 == cc) // Edge on edge*/
)
);

// "Smart" decision derived from the above with a Karnaugh map
resultsmart = (SShell::Class::INSIDE==indir_shell) || // 1112 1212
((SShell::Class::INSIDE==outdir_shell)&&(SShell::Class::INSIDE==indir_orig)&&(SShell::Class::INSIDE==outdir_orig)) || // 2111 4111
/*
// "Smart" decision derived from the above with a Karnaugh map (and the above updated in reverse later :-)
resultsmart = (SShell::Class::INSIDE==indir_shell) || // 1112 1212
((SShell::Class::INSIDE==outdir_shell)&&(SShell::Class::INSIDE==indir_orig)&&(SShell::Class::INSIDE==outdir_orig)) || // 2111 3111 4111
((!opA) && (
((SShell::Class::COINC_SAME==indir_shell)&&(SShell::Class::COINC_SAME==outdir_shell))|| // 3312
((SShell::Class::COINC_SAME==outdir_shell)&&(SShell::Class::INSIDE==outdir_orig)) // 2311 2321
((SShell::Class::COINC_SAME==indir_shell)&&(SShell::Class::COINC_SAME==outdir_shell))|| // 3312
((SShell::Class::COINC_SAME==outdir_shell)&&(SShell::Class::INSIDE==outdir_orig)) // 2311 2321
)
);
*/
/*
2121 is the same as 1212 keep only one
3212 is the same as 2321 keep only one
Expand All @@ -319,6 +349,7 @@ static bool KeepEdge(SSurface::CombineAs type, bool opA,
dbp("I: %d opA: %d cc: %d %d %s", I, opA, cc, result, (result!=resultsmart)?"NOOOOOOOOOOOOOOOOOO":"");
#endif
return result;
// return resultsmart;

// If the regions to the left and right of this edge are both in or both
// out, then this edge is not useful and should be discarded.
Expand Down Expand Up @@ -357,21 +388,21 @@ static void TagByClassifiedEdge(SBspUv::Class bspclass, SShell::Class *indir, SS
}
}

static void DEBUGEDGELIST(SEdgeList *sel, SSurface *surf) {
void DEBUGEDGELIST(SEdgeList *sel, SSurface *surf) {
dbp("print %d edges", sel->l.n);
SEdge *se;
for(se = sel->l.First(); se; se = sel->l.NextAfter(se)) {
Vector mid = (se->a).Plus(se->b).ScaledBy(0.5);
Vector arrow = (se->b).Minus(se->a);
swap(arrow.x, arrow.y);
arrow.x *= -1;
arrow = arrow.WithMagnitude(0.01);
arrow = arrow.WithMagnitude(0.05);
arrow = arrow.Plus(mid);

SS.nakedEdges.AddEdge(surf->PointAt(se->a.x, se->a.y),
surf->PointAt(se->b.x, se->b.y));
SS.nakedEdges.AddEdge(surf->PointAt(mid.x, mid.y),
surf->PointAt(arrow.x, arrow.y));
surf->PointAt(arrow.x, arrow.y), se->auxA, se->auxB, se->tag,se->cc);
}
}

Expand Down Expand Up @@ -480,6 +511,28 @@ void SSurface::EdgeNormalsWithinSurface(Point2d auv, Point2d buv,
*enout = pout.Minus(*pt);
}


static uint32_t DebugEdgeClassification(Vector pt, bool opA, SShell::Class indir_shell,
SShell::Class outdir_shell, SShell::Class indir_orig,
SShell::Class outdir_orig) {
uint32_t cc = (uint32_t)indir_shell * 100 + (uint32_t)outdir_shell*10 + (uint32_t)indir_orig*1 +
(uint32_t)outdir_orig / 10 + (uint32_t)opA;

/* std::shared_ptr<SolveSpace::ViewportCanvas> canvas = SS.GW.canvas;
const Camera &camera = canvas->GetCamera();
Canvas::Stroke strokeError = Style::Stroke(Style::DRAW_ERROR);
strokeError.layer = Canvas::Layer::FRONT;
strokeError.width = 1.0f;
Canvas::hStroke hcsError = canvas->GetStroke(strokeError);
double textHeight = Style::DefaultTextHeight() / camera.scale;
canvas->DrawVectorText(ssprintf("%lu", cc), textHeight*10,
pt, camera.projRight, camera.projUp, hcsError); */
return cc;
}
//-----------------------------------------------------------------------------
// Trim this surface against the specified shell, in the way that's appropriate
// for the specified Boolean operation type (and which operand we are). We
Expand Down Expand Up @@ -560,7 +613,10 @@ SSurface SSurface::MakeCopyTrimAgainst(SShell *parent,
// point opposite to the surface normal.
bool bkwds = true;
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)) { // ruevs: invert edges for intersection here?
bkwds = !bkwds;
}
if(bkwds) {
inter.AddEdge(tb, ta, sc->h.v, 1);
} else {
Expand Down Expand Up @@ -623,14 +679,16 @@ SSurface SSurface::MakeCopyTrimAgainst(SShell *parent,
ret.PointAt(auv), ret.PointAt(buv), pt,
enin, enout, surfn);

uint32_t cc = DebugEdgeClassification(se->a, opA, indir_shell, outdir_shell, indir_orig, outdir_orig);

if(KeepEdge(type, opA, indir_shell, outdir_shell,
indir_orig, outdir_orig))
{
#ifndef NDEBUG
origKept++;
#endif
for(se = chain.l.First(); se; se = chain.l.NextAfter(se)) {
final.AddEdge(se->a, se->b, se->auxA, se->auxB);
final.AddEdge(se->a, se->b, se->auxA, se->auxB, 0, cc);
}
}
chain.Clear();
Expand Down Expand Up @@ -659,14 +717,17 @@ SSurface SSurface::MakeCopyTrimAgainst(SShell *parent,
ret.PointAt(auv), ret.PointAt(buv), pt,
enin, enout, surfn);

uint32_t cc = DebugEdgeClassification(se->a, opA, indir_shell, outdir_shell, indir_orig, outdir_orig);

if(KeepEdge(type, opA, indir_shell, outdir_shell,
indir_orig, outdir_orig))
{
#ifndef NDEBUG
interKept++;
#endif
for(se = chain.l.First(); se; se = chain.l.NextAfter(se)) {
final.AddEdge(se->a, se->b, se->auxA, se->auxB);
// se->auxB = 1; // ruevs: Will cause the TrimFromEdgeList function below to reverse edges resulting from the intersection.
final.AddEdge(se->a, se->b, se->auxA, se->auxB, 0, cc); // ruevs: swap a and b here?
}
}
chain.Clear();
Expand All @@ -680,7 +741,7 @@ SSurface SSurface::MakeCopyTrimAgainst(SShell *parent,
// we can get duplicate edges if our surface intersects the other shell
// at an edge, so that both surfaces intersect coincident (and both
// generate an intersection edge).
final.CullExtraneousEdges();
final.CullExtraneousEdges(/*both=*/true); // ruevs: cull flase? Or wrong choice of edges?

#ifndef NDEBUG
dbp("Total %d, left after culling: %d", origKept + interKept, final.l.n);
Expand All @@ -691,10 +752,13 @@ SSurface SSurface::MakeCopyTrimAgainst(SShell *parent,

SPolygon poly = {};
final.l.ClearTags();
if(!final.AssemblePolygon(&poly, NULL, /*keepDir=*/false)) { // ruevs: passing false is a hack according to jwesthues https://github.com/solvespace/solvespace/issues/35#issuecomment-531173543
DEBUGEDGELIST(&final, &ret);
SEdge errorAt;
if(!final.AssemblePolygon(&poly, &errorAt, /*keepDir=*/true)) { // ruevs: passing false is a hack according to jwesthues https://github.com/solvespace/solvespace/issues/35#issuecomment-531173543
into->booleanFailed = true;
dbp("failed: I=%d, avoid=%d", I, choosing.l.n);
DEBUGEDGELIST(&final, &ret);
SS.nakedEdges.AddEdge(errorAt.a, errorAt.b, 0, 0, 0, 8888888);
// DEBUGEDGELIST(&final, &ret);
}
poly.Clear();

Expand Down Expand Up @@ -968,14 +1032,14 @@ void SBspUv::InsertEdge(Point2d ea, Point2d eb, SSurface *srf) {
m->more = more;
more = m;
} 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) {
pos = InsertOrCreateEdge(pos, ea, eb, srf);
} else {
neg = InsertOrCreateEdge(neg, ea, eb, srf);
}
} 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) {
pos = InsertOrCreateEdge(pos, ea, eb, srf);
} else {
Expand Down Expand Up @@ -1025,7 +1089,7 @@ SBspUv::Class SBspUv::ClassifyPoint(Point2d p, Point2d eb, SSurface *srf) const
// Pick arbitrarily which side to send it down, doesn't matter
Class c1 = neg ? neg->ClassifyPoint(p, eb, srf) : Class::OUTSIDE;
Class c2 = pos ? pos->ClassifyPoint(p, eb, srf) : Class::INSIDE;
if(c1 != c2) {
if(c1 != c2) { //ruevs
dbp("MISMATCH: %d %d %08x %08x", c1, c2, neg, pos);
}
return c1;
Expand All @@ -1042,7 +1106,7 @@ SBspUv::Class SBspUv::ClassifyEdge(Point2d ea, Point2d eb, SSurface *srf) const
// Perhaps the edge is tangent at its midpoint (and we screwed up
// somewhere earlier and failed to split it); try a different
// point on the edge.
ret = ClassifyPoint(ea.Plus((eb.Minus(ea)).ScaledBy(0.294)), eb, srf);
ret = ClassifyPoint(ea.Plus((eb.Minus(ea)).ScaledBy(0.294)), eb, srf); // ruevs: BP here
}
return ret;
}
Expand Down
4 changes: 3 additions & 1 deletion src/srf/surface.cpp
Expand Up @@ -415,7 +415,8 @@ void SSurface::TriangulateInto(SShell *shell, SMesh *sm) {
MakeEdgesInto(shell, &el, MakeAs::UV);

SPolygon poly = {};
if(el.AssemblePolygon(&poly, NULL, /*keepDir=*/false)) { // ruevs: passing false is a hack according to jwesthues https://github.com/solvespace/solvespace/issues/35#issuecomment-531173543
SEdge errorAt;
if(el.AssemblePolygon(&poly, &errorAt, /*keepDir=*/true)) { // ruevs: passing false is a hack according to jwesthues https://github.com/solvespace/solvespace/issues/35#issuecomment-531173543
int i, start = sm->l.n;
if(degm == 1 && degn == 1) {
// A surface with curvature along one direction only; so
Expand Down Expand Up @@ -448,6 +449,7 @@ void SSurface::TriangulateInto(SShell *shell, SMesh *sm) {
st->FlipNormal();
}
} else {
SS.nakedEdges.AddEdge(errorAt.a, errorAt.b, 0, 0, 0, 9999999);
dbp("failed to assemble polygon to trim nurbs surface in uv space");
}

Expand Down
3 changes: 3 additions & 0 deletions src/srf/triangulate.cpp
Expand Up @@ -286,6 +286,8 @@ void SContour::ClipEarInto(SMesh *m, int bp, double scaledEps) {
l.RemoveTagged();
}

extern void DEBUGEDGELIST(SEdgeList *sel, SSurface *surf);

void SContour::UvTriangulateInto(SMesh *m, SSurface *srf) {
Vector tu, tv;
srf->TangentsAt(0.5, 0.5, &tu, &tv);
Expand Down Expand Up @@ -351,6 +353,7 @@ void SContour::UvTriangulateInto(SMesh *m, SSurface *srf) {
}
if(bestEar < 0) {
dbp("couldn't find an ear! fail");
DEBUGEDGELIST(&srf->edges, srf);
return;
}
ClipEarInto(m, bestEar, scaledEps);
Expand Down

0 comments on commit 11e2db1

Please sign in to comment.