Add hidden line and surface removal, and vector shaded surface
export. So I calculate lighting for each triangle in the mesh, make a BSP, and then traverse it in-order and output those as SVG or EPS. And I test edges against the mesh, removing those portions of the edge that overlap a triangle in front of them (using the kd-tree to accelerate). [git-p4: depot-paths = "//depot/solvespace/": change = 1931]solver
parent
ed9f448398
commit
1a845c3432
24
bsp.cpp
24
bsp.cpp
|
@ -390,6 +390,30 @@ SBsp3 *SBsp3::Insert(STriangle *tr, SMesh *instead) {
|
|||
return this;
|
||||
}
|
||||
|
||||
void SBsp3::GenerateInPaintOrder(SMesh *m) {
|
||||
if(!this) return;
|
||||
|
||||
// Doesn't matter which branch we take if the normal has zero z
|
||||
// component, so don't need a separate case for that.
|
||||
if(n.z < 0) {
|
||||
pos->GenerateInPaintOrder(m);
|
||||
} else {
|
||||
neg->GenerateInPaintOrder(m);
|
||||
}
|
||||
|
||||
SBsp3 *flip = this;
|
||||
while(flip) {
|
||||
m->AddTriangle(&(flip->tri));
|
||||
flip = flip->more;
|
||||
}
|
||||
|
||||
if(n.z < 0) {
|
||||
neg->GenerateInPaintOrder(m);
|
||||
} else {
|
||||
pos->GenerateInPaintOrder(m);
|
||||
}
|
||||
}
|
||||
|
||||
void SBsp3::DebugDraw(void) {
|
||||
if(!this) return;
|
||||
|
||||
|
|
4
draw.cpp
4
draw.cpp
|
@ -992,7 +992,9 @@ void GraphicsWindow::Paint(int w, int h) {
|
|||
glLightModelf(GL_LIGHT_MODEL_TWO_SIDE, 0);
|
||||
}
|
||||
|
||||
GLfloat ambient[4] = { 0.4f, 0.4f, 0.4f, 1.0f };
|
||||
GLfloat ambient[4] = { (float)SS.ambientIntensity,
|
||||
(float)SS.ambientIntensity,
|
||||
(float)SS.ambientIntensity, 1 };
|
||||
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient);
|
||||
|
||||
glxUnlockColor();
|
||||
|
|
2
dsc.h
2
dsc.h
|
@ -88,6 +88,8 @@ public:
|
|||
static bool BoundingBoxIntersectsLine(Vector amax, Vector amin,
|
||||
Vector p0, Vector p1, bool segment);
|
||||
bool OutsideAndNotOn(Vector maxv, Vector minv);
|
||||
Vector InPerspective(Vector u, Vector v, Vector n,
|
||||
Vector origin, double cameraTan);
|
||||
Point2d Project2d(Vector u, Vector v);
|
||||
Point2d ProjectXy(void);
|
||||
};
|
||||
|
|
244
export.cpp
244
export.cpp
|
@ -2,9 +2,6 @@
|
|||
#include <png.h>
|
||||
|
||||
void SolveSpace::ExportSectionTo(char *filename) {
|
||||
SPolygon sp;
|
||||
ZERO(&sp);
|
||||
|
||||
Vector gn = (SS.GW.projRight).Cross(SS.GW.projUp);
|
||||
gn = gn.WithMagnitude(1);
|
||||
|
||||
|
@ -89,17 +86,17 @@ void SolveSpace::ExportSectionTo(char *filename) {
|
|||
SEdgeList el;
|
||||
ZERO(&el);
|
||||
root->MakeNakedEdgesInto(&el);
|
||||
// Assemble those edges into a polygon, and clear the edge list
|
||||
el.AssemblePolygon(&sp, NULL);
|
||||
el.Clear();
|
||||
m.Clear();
|
||||
|
||||
// And write the polygon.
|
||||
// And write the edges.
|
||||
VectorFileWriter *out = VectorFileWriter::ForFile(filename);
|
||||
if(out) {
|
||||
ExportPolygon(&sp, u, v, n, origin, out);
|
||||
// parallel projection (no perspective), and no mesh
|
||||
ExportLinesAndMesh(&el, NULL,
|
||||
u, v, n, origin, 0,
|
||||
out);
|
||||
}
|
||||
sp.Clear();
|
||||
el.Clear();
|
||||
}
|
||||
|
||||
void SolveSpace::ExportViewTo(char *filename) {
|
||||
|
@ -113,9 +110,10 @@ void SolveSpace::ExportViewTo(char *filename) {
|
|||
e->GenerateEdges(&edges);
|
||||
}
|
||||
|
||||
SPolygon sp;
|
||||
ZERO(&sp);
|
||||
edges.AssemblePolygon(&sp, NULL);
|
||||
SMesh *sm = NULL;
|
||||
if(SS.GW.showShaded) {
|
||||
sm = &((SS.GetGroup(SS.GW.activeGroup))->runningMesh);
|
||||
}
|
||||
|
||||
Vector u = SS.GW.projRight,
|
||||
v = SS.GW.projUp,
|
||||
|
@ -124,45 +122,124 @@ void SolveSpace::ExportViewTo(char *filename) {
|
|||
|
||||
VectorFileWriter *out = VectorFileWriter::ForFile(filename);
|
||||
if(out) {
|
||||
ExportPolygon(&sp, u, v, n, origin, out);
|
||||
ExportLinesAndMesh(&edges, sm,
|
||||
u, v, n, origin, SS.cameraTangent*SS.GW.scale,
|
||||
out);
|
||||
}
|
||||
edges.Clear();
|
||||
sp.Clear();
|
||||
}
|
||||
|
||||
void SolveSpace::ExportPolygon(SPolygon *sp,
|
||||
Vector u, Vector v, Vector n, Vector origin,
|
||||
void SolveSpace::ExportLinesAndMesh(SEdgeList *sel, SMesh *sm,
|
||||
Vector u, Vector v, Vector n,
|
||||
Vector origin, double cameraTan,
|
||||
VectorFileWriter *out)
|
||||
{
|
||||
int i, j;
|
||||
double s = 1.0 / SS.exportScale;
|
||||
|
||||
// Project into the export plane; so when we're done, z doesn't matter,
|
||||
// and x and y are what goes in the DXF.
|
||||
for(i = 0; i < sp->l.n; i++) {
|
||||
SContour *sc = &(sp->l.elem[i]);
|
||||
for(j = 0; j < sc->l.n; j++) {
|
||||
Vector *p = &(sc->l.elem[j].p);
|
||||
*p = p->Minus(origin);
|
||||
*p = p->DotInToCsys(u, v, n);
|
||||
// and apply the export scale factor
|
||||
double s = SS.exportScale;
|
||||
*p = p->ScaledBy(1.0/s);
|
||||
}
|
||||
SEdge *e;
|
||||
for(e = sel->l.First(); e; e = sel->l.NextAfter(e)) {
|
||||
// project into the specified csys, and apply export scale
|
||||
(e->a) = e->a.InPerspective(u, v, n, origin, cameraTan).ScaledBy(s);
|
||||
(e->b) = e->b.InPerspective(u, v, n, origin, cameraTan).ScaledBy(s);
|
||||
}
|
||||
|
||||
// If cutter radius compensation is requested, then perform it now.
|
||||
// If cutter radius compensation is requested, then perform it now
|
||||
if(fabs(SS.exportOffset) > LENGTH_EPS) {
|
||||
// assemble those edges into a polygon, and clear the edge list
|
||||
SPolygon sp;
|
||||
ZERO(&sp);
|
||||
sel->AssemblePolygon(&sp, NULL);
|
||||
sel->Clear();
|
||||
|
||||
SPolygon compd;
|
||||
ZERO(&compd);
|
||||
sp->normal = Vector::From(0, 0, -1);
|
||||
sp->FixContourDirections();
|
||||
sp->OffsetInto(&compd, SS.exportOffset);
|
||||
sp->Clear();
|
||||
*sp = compd;
|
||||
sp.normal = Vector::From(0, 0, -1);
|
||||
sp.FixContourDirections();
|
||||
sp.OffsetInto(&compd, SS.exportOffset);
|
||||
sp.Clear();
|
||||
|
||||
compd.MakeEdgesInto(sel);
|
||||
compd.Clear();
|
||||
}
|
||||
|
||||
// Now begin the entities, which are just line segments reproduced from
|
||||
// our piecewise linear curves.
|
||||
out->OutputPolygon(sp);
|
||||
// Now the triangle mesh; project, then build a BSP to perform
|
||||
// occlusion testing and generated the shaded surfaces.
|
||||
SMesh smp;
|
||||
ZERO(&smp);
|
||||
if(sm) {
|
||||
Vector l0 = (SS.lightDir[0]).WithMagnitude(1),
|
||||
l1 = (SS.lightDir[1]).WithMagnitude(1);
|
||||
STriangle *tr;
|
||||
for(tr = sm->l.First(); tr; tr = sm->l.NextAfter(tr)) {
|
||||
STriangle tt = *tr;
|
||||
tt.a = (tt.a).InPerspective(u, v, n, origin, cameraTan).ScaledBy(s);
|
||||
tt.b = (tt.b).InPerspective(u, v, n, origin, cameraTan).ScaledBy(s);
|
||||
tt.c = (tt.c).InPerspective(u, v, n, origin, cameraTan).ScaledBy(s);
|
||||
|
||||
// And calculate lighting for the triangle
|
||||
Vector n = tt.Normal().WithMagnitude(1);
|
||||
double lighting = SS.ambientIntensity +
|
||||
max(0, (SS.lightIntensity[0])*(n.Dot(l0))) +
|
||||
max(0, (SS.lightIntensity[1])*(n.Dot(l1)));
|
||||
double r = min(1, REDf (tt.meta.color)*lighting),
|
||||
g = min(1, GREENf(tt.meta.color)*lighting),
|
||||
b = min(1, BLUEf (tt.meta.color)*lighting);
|
||||
tt.meta.color = RGBf(r, g, b);
|
||||
smp.AddTriangle(&tt);
|
||||
}
|
||||
}
|
||||
|
||||
// Use the BSP routines to generate the split triangles in paint order.
|
||||
SBsp3 *bsp = SBsp3::FromMesh(&smp);
|
||||
SMesh sms;
|
||||
ZERO(&sms);
|
||||
bsp->GenerateInPaintOrder(&sms);
|
||||
// And cull the back-facing triangles
|
||||
STriangle *tr;
|
||||
sms.l.ClearTags();
|
||||
for(tr = sms.l.First(); tr; tr = sms.l.NextAfter(tr)) {
|
||||
Vector n = tr->Normal();
|
||||
if(n.z < 0) {
|
||||
tr->tag = 1;
|
||||
}
|
||||
}
|
||||
sms.l.RemoveTagged();
|
||||
|
||||
// And now we perform hidden line removal if requested
|
||||
SEdgeList hlrd;
|
||||
ZERO(&hlrd);
|
||||
if(sm && !SS.GW.showHdnLines) {
|
||||
SKdNode *root = SKdNode::From(&smp);
|
||||
root->ClearTags();
|
||||
int cnt = 1234;
|
||||
|
||||
SEdge *se;
|
||||
for(se = sel->l.First(); se; se = sel->l.NextAfter(se)) {
|
||||
SEdgeList out;
|
||||
ZERO(&out);
|
||||
// Split the original edge against the mesh
|
||||
out.AddEdge(se->a, se->b);
|
||||
root->OcclusionTestLine(*se, &out, cnt);
|
||||
cnt++;
|
||||
// And add the results to our output
|
||||
SEdge *sen;
|
||||
for(sen = out.l.First(); sen; sen = out.l.NextAfter(sen)) {
|
||||
hlrd.AddEdge(sen->a, sen->b);
|
||||
}
|
||||
out.Clear();
|
||||
}
|
||||
|
||||
sel = &hlrd;
|
||||
}
|
||||
|
||||
// Now write the lines and triangles to the output file
|
||||
out->Output(sel, &sms);
|
||||
|
||||
smp.Clear();
|
||||
sms.Clear();
|
||||
hlrd.Clear();
|
||||
}
|
||||
|
||||
bool VectorFileWriter::StringEndsIn(char *str, char *ending) {
|
||||
|
@ -207,28 +284,36 @@ VectorFileWriter *VectorFileWriter::ForFile(char *filename) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
void VectorFileWriter::OutputPolygon(SPolygon *sp) {
|
||||
int i, j;
|
||||
void VectorFileWriter::Output(SEdgeList *sel, SMesh *sm) {
|
||||
STriangle *tr;
|
||||
SEdge *e;
|
||||
|
||||
// First calculate the bounding box.
|
||||
ptMin = Vector::From(VERY_POSITIVE, VERY_POSITIVE, VERY_POSITIVE);
|
||||
ptMax = Vector::From(VERY_NEGATIVE, VERY_NEGATIVE, VERY_NEGATIVE);
|
||||
for(i = 0; i < sp->l.n; i++) {
|
||||
SContour *sc = &(sp->l.elem[i]);
|
||||
for(j = 0; j < sc->l.n; j++) {
|
||||
(sc->l.elem[j].p).MakeMaxMin(&ptMax, &ptMin);
|
||||
if(sel) {
|
||||
for(e = sel->l.First(); e; e = sel->l.NextAfter(e)) {
|
||||
(e->a).MakeMaxMin(&ptMax, &ptMin);
|
||||
(e->b).MakeMaxMin(&ptMax, &ptMin);
|
||||
}
|
||||
}
|
||||
if(sm) {
|
||||
for(tr = sm->l.First(); tr; tr = sm->l.NextAfter(tr)) {
|
||||
(tr->a).MakeMaxMin(&ptMax, &ptMin);
|
||||
(tr->b).MakeMaxMin(&ptMax, &ptMin);
|
||||
(tr->c).MakeMaxMin(&ptMax, &ptMin);
|
||||
}
|
||||
}
|
||||
|
||||
StartFile();
|
||||
for(i = 0; i < sp->l.n; i++) {
|
||||
SContour *sc = &(sp->l.elem[i]);
|
||||
|
||||
for(j = 1; j < sc->l.n; j++) {
|
||||
Vector p0 = sc->l.elem[j-1].p,
|
||||
p1 = sc->l.elem[j].p;
|
||||
|
||||
LineSegment(p0.x, p0.y, p1.x, p1.y);
|
||||
if(sm) {
|
||||
for(tr = sm->l.First(); tr; tr = sm->l.NextAfter(tr)) {
|
||||
Triangle(tr);
|
||||
}
|
||||
}
|
||||
if(sel) {
|
||||
for(e = sel->l.First(); e; e = sel->l.NextAfter(e)) {
|
||||
LineSegment(e->a.x, e->a.y, e->b.x, e->b.y);
|
||||
}
|
||||
}
|
||||
FinishAndCloseFile();
|
||||
|
@ -303,6 +388,8 @@ void DxfFileWriter::LineSegment(double x0, double y0, double x1, double y1) {
|
|||
x0, y0, 0.0,
|
||||
x1, y1, 0.0);
|
||||
}
|
||||
void DxfFileWriter::Triangle(STriangle *tr) {
|
||||
}
|
||||
|
||||
void DxfFileWriter::FinishAndCloseFile(void) {
|
||||
fprintf(f,
|
||||
|
@ -351,6 +438,37 @@ void EpsFileWriter::LineSegment(double x0, double y0, double x1, double y1) {
|
|||
MmToPoints(x0 - ptMin.x), MmToPoints(y0 - ptMin.y),
|
||||
MmToPoints(x1 - ptMin.x), MmToPoints(y1 - ptMin.y));
|
||||
}
|
||||
void EpsFileWriter::Triangle(STriangle *tr) {
|
||||
fprintf(f,
|
||||
"%.3f %.3f %.3f setrgbcolor\r\n"
|
||||
"newpath\r\n"
|
||||
" %.3f %.3f moveto\r\n"
|
||||
" %.3f %.3f lineto\r\n"
|
||||
" %.3f %.3f lineto\r\n"
|
||||
" closepath\r\n"
|
||||
"fill\r\n",
|
||||
REDf(tr->meta.color), GREENf(tr->meta.color), BLUEf(tr->meta.color),
|
||||
MmToPoints(tr->a.x - ptMin.x), MmToPoints(tr->a.y - ptMin.y),
|
||||
MmToPoints(tr->b.x - ptMin.x), MmToPoints(tr->b.y - ptMin.y),
|
||||
MmToPoints(tr->c.x - ptMin.x), MmToPoints(tr->c.y - ptMin.y));
|
||||
|
||||
// same issue with cracks, stroke it to avoid them
|
||||
double sw = max(ptMax.x - ptMin.x, ptMax.y - ptMin.y) / 1000;
|
||||
fprintf(f,
|
||||
"%.3f %.3f %.3f setrgbcolor\r\n"
|
||||
"%.3f setlinewidth\r\n"
|
||||
"newpath\r\n"
|
||||
" %.3f %.3f moveto\r\n"
|
||||
" %.3f %.3f lineto\r\n"
|
||||
" %.3f %.3f lineto\r\n"
|
||||
" closepath\r\n"
|
||||
"stroke\r\n",
|
||||
REDf(tr->meta.color), GREENf(tr->meta.color), BLUEf(tr->meta.color),
|
||||
MmToPoints(sw),
|
||||
MmToPoints(tr->a.x - ptMin.x), MmToPoints(tr->a.y - ptMin.y),
|
||||
MmToPoints(tr->b.x - ptMin.x), MmToPoints(tr->b.y - ptMin.y),
|
||||
MmToPoints(tr->c.x - ptMin.x), MmToPoints(tr->c.y - ptMin.y));
|
||||
}
|
||||
|
||||
void EpsFileWriter::FinishAndCloseFile(void) {
|
||||
fprintf(f,
|
||||
|
@ -379,11 +497,28 @@ void SvgFileWriter::StartFile(void) {
|
|||
}
|
||||
|
||||
void SvgFileWriter::LineSegment(double x0, double y0, double x1, double y1) {
|
||||
// SVG uses a coordinate system with the origin at top left, +y down
|
||||
fprintf(f,
|
||||
"<polyline points='%.3f %.3f, %.3f %.3f' "
|
||||
"<polyline points='%.3f,%.3f %.3f,%.3f' "
|
||||
"stroke-width='1' stroke='black' style='fill: none;' />\r\n",
|
||||
(x0 - ptMin.x), (y0 - ptMin.y),
|
||||
(x1 - ptMin.x), (y1 - ptMin.y));
|
||||
(x0 - ptMin.x), (ptMax.y - y0),
|
||||
(x1 - ptMin.x), (ptMax.y - y1));
|
||||
}
|
||||
void SvgFileWriter::Triangle(STriangle *tr) {
|
||||
// crispEdges turns of anti-aliasing, which tends to cause hairline
|
||||
// cracks between triangles; but there still is some cracking, so
|
||||
// specify a stroke width too, hope for around a pixel
|
||||
double sw = max(ptMax.x - ptMin.x, ptMax.y - ptMin.y) / 1000;
|
||||
fprintf(f,
|
||||
"<polygon points='%.3f,%.3f %.3f,%.3f %.3f,%.3f' "
|
||||
"stroke='#%02x%02x%02x' stroke-width='%.3f' "
|
||||
"style='fill:#%02x%02x%02x' shape-rendering='crispEdges'/>\r\n",
|
||||
(tr->a.x - ptMin.x), (ptMax.y - tr->a.y),
|
||||
(tr->b.x - ptMin.x), (ptMax.y - tr->b.y),
|
||||
(tr->c.x - ptMin.x), (ptMax.y - tr->c.y),
|
||||
RED(tr->meta.color), GREEN(tr->meta.color), BLUE(tr->meta.color),
|
||||
sw,
|
||||
RED(tr->meta.color), GREEN(tr->meta.color), BLUE(tr->meta.color));
|
||||
}
|
||||
|
||||
void SvgFileWriter::FinishAndCloseFile(void) {
|
||||
|
@ -407,6 +542,9 @@ void HpglFileWriter::LineSegment(double x0, double y0, double x1, double y1) {
|
|||
fprintf(f, "PU%d,%d;\r\n", (int)MmToHpglUnits(x0), (int)MmToHpglUnits(y0));
|
||||
fprintf(f, "PD%d,%d;\r\n", (int)MmToHpglUnits(x1), (int)MmToHpglUnits(y1));
|
||||
}
|
||||
void HpglFileWriter::Triangle(STriangle *tr) {
|
||||
// HPGL does not support filled triangles
|
||||
}
|
||||
|
||||
void HpglFileWriter::FinishAndCloseFile(void) {
|
||||
fclose(f);
|
||||
|
|
134
mesh.cpp
134
mesh.cpp
|
@ -535,6 +535,140 @@ void SKdNode::FindEdgeOn(Vector a, Vector b, int *n, int cnt, bool *inter) {
|
|||
}
|
||||
}
|
||||
|
||||
void SKdNode::SplitLinesAgainstTriangle(SEdgeList *sel, STriangle *tr) {
|
||||
SEdgeList seln;
|
||||
ZERO(&seln);
|
||||
|
||||
Vector tn = tr->Normal().WithMagnitude(1);
|
||||
double td = tn.Dot(tr->a);
|
||||
|
||||
// Consider front-facing triangles only
|
||||
if(tn.z > LENGTH_EPS) {
|
||||
// If the edge crosses our triangle's plane, then split into above
|
||||
// and below parts.
|
||||
SEdge *se;
|
||||
for(se = sel->l.First(); se; se = sel->l.NextAfter(se)) {
|
||||
double da = (se->a).Dot(tn) - td,
|
||||
db = (se->b).Dot(tn) - td;
|
||||
if((da < -LENGTH_EPS && db > LENGTH_EPS) ||
|
||||
(db < -LENGTH_EPS && da > LENGTH_EPS))
|
||||
{
|
||||
Vector m = Vector::AtIntersectionOfPlaneAndLine(
|
||||
tn, td,
|
||||
se->a, se->b, NULL);
|
||||
seln.AddEdge(m, se->b);
|
||||
se->b = m;
|
||||
}
|
||||
}
|
||||
for(se = seln.l.First(); se; se = seln.l.NextAfter(se)) {
|
||||
sel->AddEdge(se->a, se->b);
|
||||
}
|
||||
seln.Clear();
|
||||
|
||||
for(se = sel->l.First(); se; se = sel->l.NextAfter(se)) {
|
||||
Vector pt = ((se->a).Plus(se->b)).ScaledBy(0.5);
|
||||
double dt = pt.Dot(tn) - td;
|
||||
if(pt.Dot(tn) - td > -LENGTH_EPS) {
|
||||
// Edge is in front of or on our plane (remember, tn.z > 0)
|
||||
// so it is exempt from further splitting
|
||||
se->auxA = 1;
|
||||
} else {
|
||||
// Edge is behind our plane, needs further splitting
|
||||
se->auxA = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Considering only the (x, y) coordinates, split the edge against our
|
||||
// triangle.
|
||||
Point2d a = (tr->a).ProjectXy(),
|
||||
b = (tr->b).ProjectXy(),
|
||||
c = (tr->c).ProjectXy();
|
||||
|
||||
Point2d n[3] = { (b.Minus(a)).Normal().WithMagnitude(1),
|
||||
(c.Minus(b)).Normal().WithMagnitude(1),
|
||||
(a.Minus(c)).Normal().WithMagnitude(1) };
|
||||
|
||||
double d[3] = { n[0].Dot(b),
|
||||
n[1].Dot(c),
|
||||
n[2].Dot(a) };
|
||||
|
||||
// Split all of the edges where they intersect the triangle edges
|
||||
int i;
|
||||
for(i = 0; i < 3; i++) {
|
||||
for(se = sel->l.First(); se; se = sel->l.NextAfter(se)) {
|
||||
if(se->auxA) continue;
|
||||
|
||||
Point2d ap = (se->a).ProjectXy(),
|
||||
bp = (se->b).ProjectXy();
|
||||
double da = n[i].Dot(ap) - d[i],
|
||||
db = n[i].Dot(bp) - d[i];
|
||||
if((da < -LENGTH_EPS && db > LENGTH_EPS) ||
|
||||
(db < -LENGTH_EPS && da > LENGTH_EPS))
|
||||
{
|
||||
double dab = (db - da);
|
||||
Vector spl = ((se->a).ScaledBy( db/dab)).Plus(
|
||||
(se->b).ScaledBy(-da/dab));
|
||||
seln.AddEdge(spl, se->b);
|
||||
se->b = spl;
|
||||
}
|
||||
}
|
||||
for(se = seln.l.First(); se; se = seln.l.NextAfter(se)) {
|
||||
sel->AddEdge(se->a, se->b, 0);
|
||||
}
|
||||
seln.Clear();
|
||||
}
|
||||
|
||||
for(se = sel->l.First(); se; se = sel->l.NextAfter(se)) {
|
||||
if(se->auxA) {
|
||||
// Lies above or on the triangle plane, so triangle doesn't
|
||||
// occlude it.
|
||||
se->tag = 0;
|
||||
} else {
|
||||
// Test the segment to see if it lies outside the triangle
|
||||
// (i.e., outside wrt at least one edge), and keep it only
|
||||
// then.
|
||||
Point2d pt = ((se->a).Plus(se->b).ScaledBy(0.5)).ProjectXy();
|
||||
se->tag = 1;
|
||||
for(i = 0; i < 3; i++) {
|
||||
if(n[i].Dot(pt) - d[i] > -LENGTH_EPS) se->tag = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
sel->l.RemoveTagged();
|
||||
}
|
||||
}
|
||||
|
||||
void SKdNode::OcclusionTestLine(SEdge orig, SEdgeList *sel, int cnt) {
|
||||
if(gt && lt) {
|
||||
double ac = (orig.a).Element(which),
|
||||
bc = (orig.b).Element(which);
|
||||
// We can ignore triangles that are separated in x or y, but triangles
|
||||
// that are separated in z may still contribute
|
||||
if(ac < c + KDTREE_EPS ||
|
||||
bc < c + KDTREE_EPS ||
|
||||
which == 2)
|
||||
{
|
||||
lt->OcclusionTestLine(orig, sel, cnt);
|
||||
}
|
||||
if(ac > c - KDTREE_EPS ||
|
||||
bc > c - KDTREE_EPS ||
|
||||
which == 2)
|
||||
{
|
||||
gt->OcclusionTestLine(orig, sel, cnt);
|
||||
}
|
||||
} else {
|
||||
STriangleLl *ll;
|
||||
for(ll = tris; ll; ll = ll->next) {
|
||||
STriangle *tr = ll->tri;
|
||||
|
||||
if(tr->tag == cnt) continue;
|
||||
|
||||
SplitLinesAgainstTriangle(sel, tr);
|
||||
tr->tag = cnt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SKdNode::MakeNakedEdgesInto(SEdgeList *sel, bool *inter, bool *leaky) {
|
||||
if(inter) *inter = false;
|
||||
if(leaky) *leaky = false;
|
||||
|
|
|
@ -159,6 +159,8 @@ public:
|
|||
|
||||
void InsertInPlane(bool pos2, STriangle *tr, SMesh *m);
|
||||
|
||||
void GenerateInPaintOrder(SMesh *m);
|
||||
|
||||
void DebugDraw(void);
|
||||
};
|
||||
|
||||
|
@ -222,6 +224,9 @@ public:
|
|||
|
||||
void FindEdgeOn(Vector a, Vector b, int *n, int cnt, bool *inter);
|
||||
void MakeNakedEdgesInto(SEdgeList *sel, bool *inter=NULL, bool *leaky=NULL);
|
||||
|
||||
void OcclusionTestLine(SEdge orig, SEdgeList *sel, int cnt);
|
||||
void SplitLinesAgainstTriangle(SEdgeList *sel, STriangle *tr);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -30,6 +30,7 @@ void SolveSpace::Init(char *cmdLine) {
|
|||
// Light intensities
|
||||
lightIntensity[0] = CnfThawFloat(1.0f, "LightIntensity_0");
|
||||
lightIntensity[1] = CnfThawFloat(0.5f, "LightIntensity_1");
|
||||
ambientIntensity = 0.3; // no setting for that yet
|
||||
// Light positions
|
||||
lightDir[0].x = CnfThawFloat(-1.0f, "LightDir_0_Right" );
|
||||
lightDir[0].y = CnfThawFloat( 1.0f, "LightDir_0_Up" );
|
||||
|
|
11
solvespace.h
11
solvespace.h
|
@ -346,15 +346,17 @@ public:
|
|||
static bool StringEndsIn(char *str, char *ending);
|
||||
static VectorFileWriter *ForFile(char *file);
|
||||
|
||||
void OutputPolygon(SPolygon *sp);
|
||||
void Output(SEdgeList *sel, SMesh *sm);
|
||||
|
||||
virtual void LineSegment(double x0, double y0, double x1, double y1) = 0;
|
||||
virtual void Triangle(STriangle *tr) = 0;
|
||||
virtual void StartFile(void) = 0;
|
||||
virtual void FinishAndCloseFile(void) = 0;
|
||||
};
|
||||
class DxfFileWriter : public VectorFileWriter {
|
||||
public:
|
||||
void LineSegment(double x0, double y0, double x1, double y1);
|
||||
void Triangle(STriangle *tr);
|
||||
void StartFile(void);
|
||||
void FinishAndCloseFile(void);
|
||||
};
|
||||
|
@ -362,12 +364,14 @@ class EpsFileWriter : public VectorFileWriter {
|
|||
public:
|
||||
static double MmToPoints(double mm);
|
||||
void LineSegment(double x0, double y0, double x1, double y1);
|
||||
void Triangle(STriangle *tr);
|
||||
void StartFile(void);
|
||||
void FinishAndCloseFile(void);
|
||||
};
|
||||
class SvgFileWriter : public VectorFileWriter {
|
||||
public:
|
||||
void LineSegment(double x0, double y0, double x1, double y1);
|
||||
void Triangle(STriangle *tr);
|
||||
void StartFile(void);
|
||||
void FinishAndCloseFile(void);
|
||||
};
|
||||
|
@ -375,6 +379,7 @@ class HpglFileWriter : public VectorFileWriter {
|
|||
public:
|
||||
static double MmToHpglUnits(double mm);
|
||||
void LineSegment(double x0, double y0, double x1, double y1);
|
||||
void Triangle(STriangle *tr);
|
||||
void StartFile(void);
|
||||
void FinishAndCloseFile(void);
|
||||
};
|
||||
|
@ -430,6 +435,7 @@ public:
|
|||
int modelColor[MODEL_COLORS];
|
||||
Vector lightDir[2];
|
||||
double lightIntensity[2];
|
||||
double ambientIntensity;
|
||||
double chordTol;
|
||||
int maxSegments;
|
||||
double cameraTangent;
|
||||
|
@ -494,8 +500,9 @@ public:
|
|||
void ExportMeshTo(char *file);
|
||||
void ExportViewTo(char *file);
|
||||
void ExportSectionTo(char *file);
|
||||
void ExportPolygon(SPolygon *sp,
|
||||
void ExportLinesAndMesh(SEdgeList *sel, SMesh *sm,
|
||||
Vector u, Vector v, Vector n, Vector origin,
|
||||
double cameraTan,
|
||||
VectorFileWriter *out);
|
||||
|
||||
static void MenuAnalyze(int id);
|
||||
|
|
10
ui.h
10
ui.h
|
@ -10,9 +10,13 @@ public:
|
|||
#ifndef RGB
|
||||
#define RGB(r, g, b) ((r) | ((g) << 8) | ((b) << 16))
|
||||
#endif
|
||||
#define REDf(v) ((((v) >> 0) & 0xff) / 255.0f)
|
||||
#define GREENf(v) ((((v) >> 8) & 0xff) / 255.0f)
|
||||
#define BLUEf(v) ((((v) >> 16) & 0xff) / 255.0f)
|
||||
#define RGBf(r, g, b) RGB((int)(255*(r)), (int)(255*(g)), (int)(255*(b)))
|
||||
#define RED(v) (((v) >> 0) & 0xff)
|
||||
#define GREEN(v) (((v) >> 8) & 0xff)
|
||||
#define BLUE(v) (((v) >> 16) & 0xff)
|
||||
#define REDf(v) (RED (v) / 255.0f)
|
||||
#define GREENf(v) (GREEN(v) / 255.0f)
|
||||
#define BLUEf(v) (BLUE (v) / 255.0f)
|
||||
typedef struct {
|
||||
char c;
|
||||
int color;
|
||||
|
|
13
util.cpp
13
util.cpp
|
@ -430,6 +430,19 @@ Vector Vector::ScaleOutOfCsys(Vector u, Vector v, Vector n) {
|
|||
return r;
|
||||
}
|
||||
|
||||
Vector Vector::InPerspective(Vector u, Vector v, Vector n,
|
||||
Vector origin, double cameraTan)
|
||||
{
|
||||
Vector r = this->Minus(origin);
|
||||
r = r.DotInToCsys(u, v, n);
|
||||
// yes, minus; we are assuming a csys where u cross v equals n, backwards
|
||||
// from the display stuff
|
||||
double w = (1 - r.z*cameraTan);
|
||||
r = r.ScaledBy(1/w);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
double Vector::DistanceToLine(Vector p0, Vector dp) {
|
||||
double m = dp.Magnitude();
|
||||
return ((this->Minus(p0)).Cross(dp)).Magnitude() / m;
|
||||
|
|
Loading…
Reference in New Issue