Allow rendering solid outlines using a distinct style.
A new button is added, "Show/hide outline of solid model". When the outline is hidden, it is rendered using the "solid edge" style. When the outline is shown, it is rendered using the "outline" style. In SolveSpace's true WYSIWYG tradition, the 2d view export follows the rendered view exactly. Moreover, shell edges are not rendered anymore, since there is not much need in them anymore and not drawing them lessens the overlap between various kinds of lines, which already includes entities, solid edges and outlines.pull/4/head
parent
d1a2eb6d18
commit
24fc65a71c
|
@ -328,7 +328,8 @@ void SolveSpaceUI::ExportLinesAndMesh(SEdgeList *sel, SBezierList *sbl, SMesh *s
|
|||
// to back-facing.
|
||||
if(SS.GW.showEdges) {
|
||||
root->MakeCertainEdgesInto(sel, SKdNode::TURNING_EDGES,
|
||||
false, NULL, NULL);
|
||||
/*coplanarIsInter=*/false, NULL, NULL,
|
||||
GW.showOutlines ? Style::OUTLINE : Style::SOLID_EDGE);
|
||||
}
|
||||
|
||||
root->ClearTags();
|
||||
|
|
|
@ -201,7 +201,7 @@ static void FatLineEndcap(Vector p, Vector u, Vector v)
|
|||
}
|
||||
|
||||
void ssglLine(const Vector &a, const Vector &b, double pixelWidth, bool maybeFat) {
|
||||
if(!maybeFat || pixelWidth < 3.0) {
|
||||
if(!maybeFat || pixelWidth <= 3.0) {
|
||||
glBegin(GL_LINES);
|
||||
ssglVertex3v(a);
|
||||
ssglVertex3v(b);
|
||||
|
@ -213,7 +213,7 @@ void ssglLine(const Vector &a, const Vector &b, double pixelWidth, bool maybeFat
|
|||
|
||||
void ssglPoint(Vector p, double pixelSize)
|
||||
{
|
||||
if(/*!maybeFat || */pixelSize < 3.0) {
|
||||
if(/*!maybeFat || */pixelSize <= 3.0) {
|
||||
glBegin(GL_LINES);
|
||||
Vector u = SS.GW.projRight.WithMagnitude(pixelSize / SS.GW.scale / 2.0);
|
||||
ssglVertex3v(p.Minus(u));
|
||||
|
@ -587,6 +587,22 @@ void ssglDrawEdges(SEdgeList *el, bool endpointsToo, hStyle hs)
|
|||
}
|
||||
}
|
||||
|
||||
void ssglDrawOutlines(SOutlineList *sol, Vector projDir, hStyle hs)
|
||||
{
|
||||
double lineWidth = Style::Width(hs);
|
||||
int stippleType = Style::PatternType(hs);
|
||||
double stippleScale = Style::StippleScaleMm(hs);
|
||||
ssglLineWidth((float)lineWidth);
|
||||
ssglColorRGB(Style::Color(hs));
|
||||
|
||||
sol->FillOutlineTags(projDir);
|
||||
for(SOutline *so = sol->l.First(); so; so = sol->l.NextAfter(so)) {
|
||||
if(!so->tag) continue;
|
||||
ssglStippledLine(so->a, so->b, lineWidth, stippleType, stippleScale,
|
||||
/*maybeFat=*/true);
|
||||
}
|
||||
}
|
||||
|
||||
void ssglDebugMesh(SMesh *m)
|
||||
{
|
||||
int i;
|
||||
|
|
|
@ -233,6 +233,7 @@ void GraphicsWindow::Init(void) {
|
|||
showShaded = true;
|
||||
showEdges = true;
|
||||
showMesh = false;
|
||||
showOutlines = false;
|
||||
|
||||
showTextWindow = true;
|
||||
ShowTextWindow(showTextWindow);
|
||||
|
|
|
@ -29,6 +29,7 @@ void Group::Clear(void) {
|
|||
runningShell.Clear();
|
||||
displayMesh.Clear();
|
||||
displayEdges.Clear();
|
||||
displayOutlines.Clear();
|
||||
impMesh.Clear();
|
||||
impShell.Clear();
|
||||
impEntity.Clear();
|
||||
|
|
|
@ -378,12 +378,14 @@ void Group::GenerateDisplayItems(void) {
|
|||
displayMesh.MakeFromCopyOf(&(pg->displayMesh));
|
||||
|
||||
displayEdges.Clear();
|
||||
displayOutlines.Clear();
|
||||
if(SS.GW.showEdges) {
|
||||
SEdge *se;
|
||||
SEdgeList *src = &(pg->displayEdges);
|
||||
for(se = src->l.First(); se; se = src->l.NextAfter(se)) {
|
||||
displayEdges.l.Add(se);
|
||||
}
|
||||
displayOutlines.MakeFromCopyOf(&pg->displayOutlines);
|
||||
}
|
||||
} else {
|
||||
// We do contribute new solid model, so we have to triangulate the
|
||||
|
@ -401,17 +403,20 @@ void Group::GenerateDisplayItems(void) {
|
|||
}
|
||||
|
||||
displayEdges.Clear();
|
||||
displayOutlines.Clear();
|
||||
|
||||
if(SS.GW.showEdges) {
|
||||
if(runningMesh.l.n > 0) {
|
||||
// Triangle mesh only; no shell or emphasized edges.
|
||||
runningMesh.MakeCertainEdgesInto(&displayEdges, SKdNode::EMPHASIZED_EDGES);
|
||||
runningMesh.MakeCertainEdgesAndOutlinesInto(
|
||||
&displayEdges, &displayOutlines, SKdNode::EMPHASIZED_EDGES);
|
||||
} else {
|
||||
if(SS.exportMode) {
|
||||
displayMesh.MakeCertainEdgesInto(&displayEdges, SKdNode::SHARP_EDGES);
|
||||
displayMesh.MakeCertainEdgesAndOutlinesInto(
|
||||
&displayEdges, &displayOutlines, SKdNode::SHARP_EDGES);
|
||||
} else {
|
||||
runningShell.MakeEdgesInto(&displayEdges);
|
||||
displayMesh.MakeCertainEdgesInto(&displayEdges, SKdNode::EMPHASIZED_EDGES);
|
||||
displayMesh.MakeCertainEdgesAndOutlinesInto(
|
||||
&displayEdges, &displayOutlines, SKdNode::EMPHASIZED_EDGES);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -495,15 +500,23 @@ void Group::DrawDisplayItems(int t) {
|
|||
}
|
||||
|
||||
if(SS.GW.showEdges) {
|
||||
Vector projDir = SS.GW.projRight.Cross(SS.GW.projUp);
|
||||
|
||||
glDepthMask(GL_FALSE);
|
||||
if(SS.GW.showHdnLines) {
|
||||
ssglDepthRangeOffset(0);
|
||||
glDepthFunc(GL_GREATER);
|
||||
ssglDrawEdges(&displayEdges, false, { Style::HIDDEN_EDGE });
|
||||
ssglDrawOutlines(&displayOutlines, projDir, { Style::HIDDEN_EDGE });
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
}
|
||||
ssglDepthRangeOffset(2);
|
||||
ssglDrawEdges(&displayEdges, false, { Style::SOLID_EDGE });
|
||||
if(SS.GW.showOutlines) {
|
||||
ssglDrawOutlines(&displayOutlines, projDir, { Style::OUTLINE });
|
||||
} else {
|
||||
ssglDrawOutlines(&displayOutlines, projDir, { Style::SOLID_EDGE });
|
||||
}
|
||||
glDepthMask(GL_TRUE);
|
||||
}
|
||||
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 930 B |
68
src/mesh.cpp
68
src/mesh.cpp
|
@ -91,9 +91,10 @@ void SMesh::MakeEdgesInPlaneInto(SEdgeList *sel, Vector n, double d) {
|
|||
m.Clear();
|
||||
}
|
||||
|
||||
void SMesh::MakeCertainEdgesInto(SEdgeList *sel, int type) {
|
||||
void SMesh::MakeCertainEdgesAndOutlinesInto(SEdgeList *sel, SOutlineList *sol, int type) {
|
||||
SKdNode *root = SKdNode::From(this);
|
||||
root->MakeCertainEdgesInto(sel, type, false, NULL, NULL);
|
||||
root->MakeOutlinesInto(sol);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -923,8 +924,8 @@ static bool CheckAndAddTrianglePair(std::set<std::pair<STriangle *, STriangle *>
|
|||
// * emphasized edges (i.e., edges where a triangle from one face joins
|
||||
// a triangle from a different face)
|
||||
//-----------------------------------------------------------------------------
|
||||
void SKdNode::MakeCertainEdgesInto(SEdgeList *sel, int how,
|
||||
bool coplanarIsInter, bool *inter, bool *leaky)
|
||||
void SKdNode::MakeCertainEdgesInto(SEdgeList *sel, int how, bool coplanarIsInter,
|
||||
bool *inter, bool *leaky, int auxA)
|
||||
{
|
||||
if(inter) *inter = false;
|
||||
if(leaky) *leaky = false;
|
||||
|
@ -946,18 +947,18 @@ void SKdNode::MakeCertainEdgesInto(SEdgeList *sel, int how,
|
|||
switch(how) {
|
||||
case NAKED_OR_SELF_INTER_EDGES:
|
||||
if(info.count != 1) {
|
||||
sel->AddEdge(a, b);
|
||||
sel->AddEdge(a, b, auxA);
|
||||
if(leaky) *leaky = true;
|
||||
}
|
||||
if(info.intersectsMesh) {
|
||||
sel->AddEdge(a, b);
|
||||
sel->AddEdge(a, b, auxA);
|
||||
if(inter) *inter = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case SELF_INTER_EDGES:
|
||||
if(info.intersectsMesh) {
|
||||
sel->AddEdge(a, b);
|
||||
sel->AddEdge(a, b, auxA);
|
||||
if(inter) *inter = true;
|
||||
}
|
||||
break;
|
||||
|
@ -972,7 +973,7 @@ void SKdNode::MakeCertainEdgesInto(SEdgeList *sel, int how,
|
|||
// This triangle is back-facing (or on edge), and
|
||||
// this edge has exactly one mate, and that mate is
|
||||
// front-facing. So this is a turning edge.
|
||||
sel->AddEdge(a, b, Style::SOLID_EDGE);
|
||||
sel->AddEdge(a, b, auxA);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -984,7 +985,7 @@ void SKdNode::MakeCertainEdgesInto(SEdgeList *sel, int how,
|
|||
// different faces; either really different faces,
|
||||
// or one is from a face and the other is zero (i.e.,
|
||||
// not from a face).
|
||||
sel->AddEdge(a, b);
|
||||
sel->AddEdge(a, b, auxA);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1008,7 +1009,7 @@ void SKdNode::MakeCertainEdgesInto(SEdgeList *sel, int how,
|
|||
break;
|
||||
// The two triangles that join at this edge meet at a sharp
|
||||
// angle. This implies they come from different faces.
|
||||
sel->AddEdge(a, b);
|
||||
sel->AddEdge(a, b, auxA);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -1021,3 +1022,52 @@ void SKdNode::MakeCertainEdgesInto(SEdgeList *sel, int how,
|
|||
}
|
||||
}
|
||||
|
||||
void SKdNode::MakeOutlinesInto(SOutlineList *sol)
|
||||
{
|
||||
std::vector<STriangle *> tris;
|
||||
ClearTags();
|
||||
ListTrianglesInto(&tris);
|
||||
|
||||
std::set<std::pair<STriangle *, STriangle *>> edgeTris;
|
||||
int cnt = 1234;
|
||||
for(STriangle *tr : tris) {
|
||||
for(int j = 0; j < 3; j++) {
|
||||
Vector a = (j == 0) ? tr->a : ((j == 1) ? tr->b : tr->c);
|
||||
Vector b = (j == 0) ? tr->b : ((j == 1) ? tr->c : tr->a);
|
||||
|
||||
SKdNode::EdgeOnInfo info = {};
|
||||
FindEdgeOn(a, b, cnt, /*coplanarIsInter=*/false, &info);
|
||||
cnt++;
|
||||
if(info.count != 1) continue;
|
||||
if(CheckAndAddTrianglePair(&edgeTris, tr, info.tr))
|
||||
continue;
|
||||
|
||||
sol->AddEdge(a, b, tr->Normal(), info.tr->Normal());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SOutlineList::Clear() {
|
||||
l.Clear();
|
||||
}
|
||||
|
||||
void SOutlineList::AddEdge(Vector a, Vector b, Vector nl, Vector nr) {
|
||||
SOutline so = {};
|
||||
so.a = a;
|
||||
so.b = b;
|
||||
so.nl = nl;
|
||||
so.nr = nr;
|
||||
l.Add(&so);
|
||||
}
|
||||
|
||||
void SOutlineList::FillOutlineTags(Vector projDir) {
|
||||
for(SOutline *so = l.First(); so; so = l.NextAfter(so)) {
|
||||
so->tag = ((so->nl.Dot(projDir) > 0.0) != (so->nr.Dot(projDir) > 0.0));
|
||||
}
|
||||
}
|
||||
|
||||
void SOutlineList::MakeFromCopyOf(SOutlineList *sol) {
|
||||
for(SOutline *so = sol->l.First(); so; so = sol->l.NextAfter(so)) {
|
||||
l.Add(so);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ class SPolygon;
|
|||
class SContour;
|
||||
class SMesh;
|
||||
class SBsp3;
|
||||
class SOutlineList;
|
||||
|
||||
class SEdge {
|
||||
public:
|
||||
|
@ -249,7 +250,7 @@ public:
|
|||
void MakeFromAssemblyOf(SMesh *a, SMesh *b);
|
||||
|
||||
void MakeEdgesInPlaneInto(SEdgeList *sel, Vector n, double d);
|
||||
void MakeCertainEdgesInto(SEdgeList *sel, int type);
|
||||
void MakeCertainEdgesAndOutlinesInto(SEdgeList *sel, SOutlineList *sol, int type);
|
||||
|
||||
bool IsEmpty(void);
|
||||
void RemapFaces(Group *g, int remap);
|
||||
|
@ -267,6 +268,24 @@ public:
|
|||
static STriangleLl *Alloc(void);
|
||||
};
|
||||
|
||||
class SOutline {
|
||||
public:
|
||||
int tag;
|
||||
Vector a, b, nl, nr;
|
||||
};
|
||||
|
||||
class SOutlineList {
|
||||
public:
|
||||
List<SOutline> l;
|
||||
|
||||
void Clear();
|
||||
void AddEdge(Vector a, Vector b, Vector nl, Vector nr);
|
||||
|
||||
void MakeFromCopyOf(SOutlineList *ol);
|
||||
|
||||
void FillOutlineTags(Vector projDir);
|
||||
};
|
||||
|
||||
class SKdNode {
|
||||
public:
|
||||
struct EdgeOnInfo {
|
||||
|
@ -304,7 +323,8 @@ public:
|
|||
SHARP_EDGES = 500,
|
||||
};
|
||||
void MakeCertainEdgesInto(SEdgeList *sel, int how, bool coplanarIsInter,
|
||||
bool *inter, bool *leaky);
|
||||
bool *inter, bool *leaky, int auxA=0);
|
||||
void MakeOutlinesInto(SOutlineList *sel);
|
||||
|
||||
void OcclusionTestLine(SEdge orig, SEdgeList *sel, int cnt, bool removeHidden);
|
||||
void SplitLinesAgainstTriangle(SEdgeList *sel, STriangle *tr, bool removeHidden);
|
||||
|
|
|
@ -176,6 +176,7 @@ public:
|
|||
bool displayDirty;
|
||||
SMesh displayMesh;
|
||||
SEdgeList displayEdges;
|
||||
SOutlineList displayOutlines;
|
||||
|
||||
enum {
|
||||
COMBINE_AS_UNION = 0,
|
||||
|
@ -768,6 +769,7 @@ public:
|
|||
DRAW_ERROR = 12,
|
||||
DIM_SOLID = 13,
|
||||
HIDDEN_EDGE = 14,
|
||||
OUTLINE = 15,
|
||||
|
||||
FIRST_CUSTOM = 0x100
|
||||
};
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#ifdef HAVE_STDINT_H
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
|
@ -346,6 +347,7 @@ void ssglFillMesh(bool useSpecColor, RgbaColor color,
|
|||
SMesh *m, uint32_t h, uint32_t s1, uint32_t s2);
|
||||
void ssglDebugPolygon(SPolygon *p);
|
||||
void ssglDrawEdges(SEdgeList *l, bool endpointsToo, hStyle hs);
|
||||
void ssglDrawOutlines(SOutlineList *l, Vector projDir, hStyle hs);
|
||||
void ssglDebugMesh(SMesh *m);
|
||||
void ssglMarkPolygonNormal(SPolygon *p);
|
||||
typedef void ssglLineFn(void *data, Vector a, Vector b);
|
||||
|
|
|
@ -25,6 +25,7 @@ const Style::Default Style::Defaults[] = {
|
|||
{ { DRAW_ERROR }, "DrawError", RGBf(1.0, 0.0, 0.0), 8.0, 0 },
|
||||
{ { DIM_SOLID }, "DimSolid", RGBf(0.1, 0.1, 0.1), 1.0, 0 },
|
||||
{ { HIDDEN_EDGE }, "HiddenEdge", RGBf(0.8, 0.8, 0.8), 2.0, 1 },
|
||||
{ { OUTLINE }, "Outline", RGBf(0.8, 0.8, 0.8), 3.0, 5 },
|
||||
{ { 0 }, NULL, RGBf(0.0, 0.0, 0.0), 0.0, 0 }
|
||||
};
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ TextWindow::HideShowIcon TextWindow::hideShowIcons[] = {
|
|||
{ &SPACER, 0, 0 },
|
||||
{ &(SS.GW.showShaded), Icon_shaded, "shaded view of solid model" },
|
||||
{ &(SS.GW.showEdges), Icon_edges, "edges of solid model" },
|
||||
{ &(SS.GW.showOutlines), Icon_outlines, "outline of solid model" },
|
||||
{ &(SS.GW.showMesh), Icon_mesh, "triangle mesh of solid model" },
|
||||
{ &SPACER, 0, 0 },
|
||||
{ &(SS.GW.showHdnLines), Icon_hidden_lines, "hidden lines" },
|
||||
|
|
1
src/ui.h
1
src/ui.h
|
@ -704,6 +704,7 @@ public:
|
|||
bool showTextWindow;
|
||||
bool showShaded;
|
||||
bool showEdges;
|
||||
bool showOutlines;
|
||||
bool showFaces;
|
||||
bool showMesh;
|
||||
bool showHdnLines;
|
||||
|
|
|
@ -64,6 +64,7 @@ void SolveSpaceUI::PushFromCurrentOnto(UndoStack *uk) {
|
|||
dest.runningShell = {};
|
||||
dest.displayMesh = {};
|
||||
dest.displayEdges = {};
|
||||
dest.displayOutlines = {};
|
||||
|
||||
dest.remap = {};
|
||||
src->remap.DeepCopyInto(&(dest.remap));
|
||||
|
|
Loading…
Reference in New Issue