Make the EPS, PDF, and SVG targets output filled contours. This
also means that closed contours will get output as a single path now, vs. one open path per Bezier segment before. I've simplified the 2d/3d wireframe export targets somewhat; they now support only Beziers, without an additional special case for line segments. The performance penalty for that should not be worth caring about, since that's infrequent. And fix a memory leak in FindOuterFacesFrom(), fix ugly output of filled triangles in PDF (because the line join style did bad things on long skinny triangles), fix non-zero Z coordinates for exported views or sections in DXF or STEP. [git-p4: depot-paths = "//depot/solvespace/": change = 2061]solver
parent
2f115ec950
commit
3515748334
146
export.cpp
146
export.cpp
|
@ -181,17 +181,27 @@ void SolveSpace::ExportViewOrWireframeTo(char *filename, bool wireframe) {
|
|||
beziers.Clear();
|
||||
}
|
||||
|
||||
|
||||
void SolveSpace::ExportWireframeCurves(SEdgeList *sel, SBezierList *sbl,
|
||||
VectorFileWriter *out)
|
||||
{
|
||||
sbl->ScaleSelfBy(1.0/SS.exportScale);
|
||||
SBezierLoopSetSet sblss;
|
||||
ZERO(&sblss);
|
||||
SEdge *se;
|
||||
for(se = sel->l.First(); se; se = sel->l.NextAfter(se)) {
|
||||
se->a = (se->a).ScaledBy(1.0/SS.exportScale);
|
||||
se->b = (se->b).ScaledBy(1.0/SS.exportScale);
|
||||
SBezier sb = SBezier::From(
|
||||
(se->a).ScaledBy(1.0 / SS.exportScale),
|
||||
(se->b).ScaledBy(1.0 / SS.exportScale));
|
||||
sblss.AddOpenPath(&sb);
|
||||
}
|
||||
out->Output(sel, sbl, NULL);
|
||||
|
||||
sbl->ScaleSelfBy(1.0/SS.exportScale);
|
||||
SBezier *sb;
|
||||
for(sb = sbl->l.First(); sb; sb = sbl->l.NextAfter(sb)) {
|
||||
sblss.AddOpenPath(sb);
|
||||
}
|
||||
|
||||
out->Output(&sblss, NULL);
|
||||
sblss.Clear();
|
||||
}
|
||||
|
||||
void SolveSpace::ExportLinesAndMesh(SEdgeList *sel, SBezierList *sbl, SMesh *sm,
|
||||
|
@ -327,9 +337,49 @@ void SolveSpace::ExportLinesAndMesh(SEdgeList *sel, SBezierList *sbl, SMesh *sm,
|
|||
sel = &hlrd;
|
||||
}
|
||||
|
||||
// Now write the lines and triangles to the output file
|
||||
out->Output(sel, sbl, &sms);
|
||||
// We kept the line segments and Beziers separate until now; but put them
|
||||
// all together, and also project everything into the xy plane, since not
|
||||
// all export targets ignore the z component of the points.
|
||||
for(e = sel->l.First(); e; e = sel->l.NextAfter(e)) {
|
||||
SBezier sb = SBezier::From(e->a, e->b);
|
||||
sb.auxA = e->auxA;
|
||||
sbl->l.Add(&sb);
|
||||
}
|
||||
for(b = sbl->l.First(); b; b = sbl->l.NextAfter(b)) {
|
||||
for(int i = 0; i <= b->deg; i++) {
|
||||
b->ctrl[i].z = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// If possible, then we will assemble these output curves into loops. They
|
||||
// will then get exported as closed paths.
|
||||
SBezierLoopSetSet sblss;
|
||||
ZERO(&sblss);
|
||||
SBezierList leftovers;
|
||||
ZERO(&leftovers);
|
||||
SSurface srf = SSurface::FromPlane(Vector::From(0, 0, 0),
|
||||
Vector::From(1, 0, 0),
|
||||
Vector::From(0, 1, 0));
|
||||
SPolygon spxyz;
|
||||
ZERO(&spxyz);
|
||||
bool allClosed;
|
||||
SEdge notClosedAt;
|
||||
sbl->l.ClearTags();
|
||||
sblss.FindOuterFacesFrom(sbl, &spxyz, &srf,
|
||||
SS.ChordTolMm()*s,
|
||||
&allClosed, ¬ClosedAt,
|
||||
NULL, NULL,
|
||||
&leftovers);
|
||||
for(b = leftovers.l.First(); b; b = leftovers.l.NextAfter(b)) {
|
||||
sblss.AddOpenPath(b);
|
||||
}
|
||||
|
||||
// Now write the lines and triangles to the output file
|
||||
out->Output(&sblss, &sms);
|
||||
|
||||
leftovers.Clear();
|
||||
spxyz.Clear();
|
||||
sblss.Clear();
|
||||
smp.Clear();
|
||||
sms.Clear();
|
||||
hlrd.Clear();
|
||||
|
@ -379,24 +429,19 @@ VectorFileWriter *VectorFileWriter::ForFile(char *filename) {
|
|||
|
||||
static void AddUnregMessageCallback(void *fndata, Vector a, Vector b)
|
||||
{
|
||||
SEdgeList *sel = (SEdgeList *)fndata;
|
||||
sel->AddEdge(a, b, Style::SELECTED);
|
||||
SBezierLoopSetSet *sblss = (SBezierLoopSetSet *)fndata;
|
||||
SBezier sb = SBezier::From(a, b);
|
||||
sb.auxA = Style::SELECTED;
|
||||
sblss->AddOpenPath(&sb);
|
||||
}
|
||||
|
||||
void VectorFileWriter::Output(SEdgeList *sel, SBezierList *sbl, SMesh *sm) {
|
||||
void VectorFileWriter::Output(SBezierLoopSetSet *sblss, SMesh *sm) {
|
||||
STriangle *tr;
|
||||
SEdge *e;
|
||||
SBezier *b;
|
||||
|
||||
// First calculate the bounding box.
|
||||
ptMin = Vector::From(VERY_POSITIVE, VERY_POSITIVE, VERY_POSITIVE);
|
||||
ptMax = Vector::From(VERY_NEGATIVE, VERY_NEGATIVE, VERY_NEGATIVE);
|
||||
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);
|
||||
|
@ -404,11 +449,16 @@ void VectorFileWriter::Output(SEdgeList *sel, SBezierList *sbl, SMesh *sm) {
|
|||
(tr->c).MakeMaxMin(&ptMax, &ptMin);
|
||||
}
|
||||
}
|
||||
if(sbl) {
|
||||
for(b = sbl->l.First(); b; b = sbl->l.NextAfter(b)) {
|
||||
int i;
|
||||
for(i = 0; i <= b->deg; i++) {
|
||||
(b->ctrl[i]).MakeMaxMin(&ptMax, &ptMin);
|
||||
if(sblss) {
|
||||
SBezierLoopSet *sbls;
|
||||
for(sbls = sblss->l.First(); sbls; sbls = sblss->l.NextAfter(sbls)) {
|
||||
SBezierLoop *sbl;
|
||||
for(sbl = sbls->l.First(); sbl; sbl = sbls->l.NextAfter(sbl)) {
|
||||
for(b = sbl->l.First(); b; b = sbl->l.NextAfter(b)) {
|
||||
for(int i = 0; i <= b->deg; i++) {
|
||||
(b->ctrl[i]).MakeMaxMin(&ptMax, &ptMin);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -431,7 +481,7 @@ void VectorFileWriter::Output(SEdgeList *sel, SBezierList *sbl, SMesh *sm) {
|
|||
|
||||
// If the demo period has expired and there's no license, then print
|
||||
// a message in any exported file.
|
||||
if((!SS.license.licensed) && (SS.license.trialDaysRemaining <= 0)) {
|
||||
if((!SS.license.licensed) && (SS.license.trialDaysRemaining <= 0) && sblss){
|
||||
char *str =
|
||||
"eval / nonprofit use only -- buy at http://solvespace.com/";
|
||||
double aspect = (glxStrWidth(str, 1) / glxStrHeight(1));
|
||||
|
@ -453,7 +503,7 @@ void VectorFileWriter::Output(SEdgeList *sel, SBezierList *sbl, SMesh *sm) {
|
|||
str,
|
||||
0.9 * th * SS.GW.scale,
|
||||
t, u, v,
|
||||
AddUnregMessageCallback, sel);
|
||||
AddUnregMessageCallback, sblss);
|
||||
if(w > h) {
|
||||
ptMin.y -= th*3;
|
||||
} else {
|
||||
|
@ -467,41 +517,45 @@ void VectorFileWriter::Output(SEdgeList *sel, SBezierList *sbl, SMesh *sm) {
|
|||
Triangle(tr);
|
||||
}
|
||||
}
|
||||
if(sel) {
|
||||
for(e = sel->l.First(); e; e = sel->l.NextAfter(e)) {
|
||||
if(!Style::Exportable(e->auxA)) continue;
|
||||
if(sblss) {
|
||||
SBezierLoopSet *sbls;
|
||||
for(sbls = sblss->l.First(); sbls; sbls = sblss->l.NextAfter(sbls)) {
|
||||
SBezierLoop *sbl;
|
||||
sbl = sbls->l.First();
|
||||
if(!sbl) continue;
|
||||
b = sbl->l.First();
|
||||
if(!b || !Style::Exportable(b->auxA)) continue;
|
||||
|
||||
DWORD rgb = Style::Color (e->auxA, true);
|
||||
double w = Style::WidthMm(e->auxA)*s;
|
||||
LineSegment(rgb, w, e->a, e->b);
|
||||
}
|
||||
}
|
||||
if(sbl) {
|
||||
for(b = sbl->l.First(); b; b = sbl->l.NextAfter(b)) {
|
||||
if(!Style::Exportable(b->auxA)) continue;
|
||||
hStyle hs = { b->auxA };
|
||||
Style *stl = Style::Get(hs);
|
||||
double lineWidth = Style::WidthMm(b->auxA)*s;
|
||||
DWORD strokeRgb = Style::Color(b->auxA, true);
|
||||
|
||||
DWORD rgb = Style::Color (b->auxA, true);
|
||||
double w = Style::WidthMm(b->auxA)*s;
|
||||
Bezier(rgb, w, b);
|
||||
StartPath(strokeRgb, lineWidth, stl->filled, stl->fillColor);
|
||||
for(sbl = sbls->l.First(); sbl; sbl = sbls->l.NextAfter(sbl)) {
|
||||
for(b = sbl->l.First(); b; b = sbl->l.NextAfter(b)) {
|
||||
Bezier(b);
|
||||
}
|
||||
}
|
||||
FinishPath(strokeRgb, lineWidth, stl->filled, stl->fillColor);
|
||||
}
|
||||
}
|
||||
FinishAndCloseFile();
|
||||
}
|
||||
|
||||
void VectorFileWriter::BezierAsPwl(DWORD rgb, double width, SBezier *sb) {
|
||||
void VectorFileWriter::BezierAsPwl(SBezier *sb) {
|
||||
List<Vector> lv;
|
||||
ZERO(&lv);
|
||||
sb->MakePwlInto(&lv, SS.ChordTolMm() / SS.exportScale);
|
||||
int i;
|
||||
for(i = 1; i < lv.n; i++) {
|
||||
LineSegment(rgb, width, lv.elem[i-1], lv.elem[i]);
|
||||
SBezier sb = SBezier::From(lv.elem[i-1], lv.elem[i]);
|
||||
Bezier(&sb);
|
||||
}
|
||||
lv.Clear();
|
||||
}
|
||||
|
||||
void VectorFileWriter::BezierAsNonrationalCubic(DWORD rgb, double width,
|
||||
SBezier *sb, int depth)
|
||||
{
|
||||
void VectorFileWriter::BezierAsNonrationalCubic(SBezier *sb, int depth) {
|
||||
Vector t0 = sb->TangentAt(0), t1 = sb->TangentAt(1);
|
||||
// The curve is correct, and the first derivatives are correct, at the
|
||||
// endpoints.
|
||||
|
@ -529,12 +583,12 @@ void VectorFileWriter::BezierAsNonrationalCubic(DWORD rgb, double width,
|
|||
}
|
||||
|
||||
if(closeEnough || depth > 3) {
|
||||
Bezier(rgb, width, &bnr);
|
||||
Bezier(&bnr);
|
||||
} else {
|
||||
SBezier bef, aft;
|
||||
sb->SplitAt(0.5, &bef, &aft);
|
||||
BezierAsNonrationalCubic(rgb, width, &bef, depth+1);
|
||||
BezierAsNonrationalCubic(rgb, width, &aft, depth+1);
|
||||
BezierAsNonrationalCubic(&bef, depth+1);
|
||||
BezierAsNonrationalCubic(&aft, depth+1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
332
exportvector.cpp
332
exportvector.cpp
|
@ -62,8 +62,23 @@ void DxfFileWriter::StartFile(void) {
|
|||
"ENTITIES\r\n");
|
||||
}
|
||||
|
||||
void DxfFileWriter::LineSegment(DWORD rgb, double w, Vector ptA, Vector ptB) {
|
||||
fprintf(f,
|
||||
void DxfFileWriter::StartPath(DWORD strokeRgb, double lineWidth,
|
||||
bool filled, DWORD fillRgb)
|
||||
{
|
||||
}
|
||||
void DxfFileWriter::FinishPath(DWORD strokeRgb, double lineWidth,
|
||||
bool filled, DWORD fillRgb)
|
||||
{
|
||||
}
|
||||
|
||||
void DxfFileWriter::Triangle(STriangle *tr) {
|
||||
}
|
||||
|
||||
void DxfFileWriter::Bezier(SBezier *sb) {
|
||||
Vector c, n = Vector::From(0, 0, 1);
|
||||
double r;
|
||||
if(sb->deg == 1) {
|
||||
fprintf(f,
|
||||
" 0\r\n"
|
||||
"LINE\r\n"
|
||||
" 8\r\n" // Layer code
|
||||
|
@ -80,18 +95,10 @@ void DxfFileWriter::LineSegment(DWORD rgb, double w, Vector ptA, Vector ptB) {
|
|||
"%.6f\r\n"
|
||||
" 31\r\n" // zB
|
||||
"%.6f\r\n",
|
||||
0,
|
||||
ptA.x, ptA.y, ptA.z,
|
||||
ptB.x, ptB.y, ptB.z);
|
||||
}
|
||||
|
||||
void DxfFileWriter::Triangle(STriangle *tr) {
|
||||
}
|
||||
|
||||
void DxfFileWriter::Bezier(DWORD rgb, double w, SBezier *sb) {
|
||||
Vector c, n = Vector::From(0, 0, 1);
|
||||
double r;
|
||||
if(sb->IsInPlane(n, 0) && sb->IsCircle(n, &c, &r)) {
|
||||
0,
|
||||
sb->ctrl[0].x, sb->ctrl[0].y, sb->ctrl[0].z,
|
||||
sb->ctrl[1].x, sb->ctrl[1].y, sb->ctrl[1].z);
|
||||
} else if(sb->IsInPlane(n, 0) && sb->IsCircle(n, &c, &r)) {
|
||||
double theta0 = atan2(sb->ctrl[0].y - c.y, sb->ctrl[0].x - c.x),
|
||||
theta1 = atan2(sb->ctrl[2].y - c.y, sb->ctrl[2].x - c.x),
|
||||
dtheta = WRAP_SYMMETRIC(theta1 - theta0, 2*PI);
|
||||
|
@ -121,7 +128,7 @@ void DxfFileWriter::Bezier(DWORD rgb, double w, SBezier *sb) {
|
|||
r,
|
||||
theta0*180/PI, theta1*180/PI);
|
||||
} else {
|
||||
BezierAsPwl(rgb, w, sb);
|
||||
BezierAsPwl(sb);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -137,17 +144,6 @@ void DxfFileWriter::FinishAndCloseFile(void) {
|
|||
//-----------------------------------------------------------------------------
|
||||
// Routines for EPS output
|
||||
//-----------------------------------------------------------------------------
|
||||
char *EpsFileWriter::StyleString(DWORD rgb, double w) {
|
||||
static char ret[300];
|
||||
sprintf(ret, " %.3f setlinewidth\r\n"
|
||||
" %.3f %.3f %.3f setrgbcolor\r\n"
|
||||
" 1 setlinejoin\r\n" // rounded
|
||||
" 1 setlinecap\r\n", // rounded
|
||||
MmToPts(w),
|
||||
REDf(rgb), GREENf(rgb), BLUEf(rgb));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void EpsFileWriter::StartFile(void) {
|
||||
fprintf(f,
|
||||
"%%!PS-Adobe-2.0\r\n"
|
||||
|
@ -167,16 +163,35 @@ void EpsFileWriter::StartFile(void) {
|
|||
MmToPts(ptMax.y - ptMin.y));
|
||||
}
|
||||
|
||||
void EpsFileWriter::LineSegment(DWORD rgb, double w, Vector ptA, Vector ptB) {
|
||||
fprintf(f,
|
||||
"newpath\r\n"
|
||||
" %.3f %.3f moveto\r\n"
|
||||
" %.3f %.3f lineto\r\n"
|
||||
"%s"
|
||||
"stroke\r\n",
|
||||
MmToPts(ptA.x - ptMin.x), MmToPts(ptA.y - ptMin.y),
|
||||
MmToPts(ptB.x - ptMin.x), MmToPts(ptB.y - ptMin.y),
|
||||
StyleString(rgb, w));
|
||||
void EpsFileWriter::StartPath(DWORD strokeRgb, double lineWidth,
|
||||
bool filled, DWORD fillRgb)
|
||||
{
|
||||
fprintf(f, "newpath\r\n");
|
||||
prevPt = Vector::From(VERY_POSITIVE, VERY_POSITIVE, VERY_POSITIVE);
|
||||
}
|
||||
void EpsFileWriter::FinishPath(DWORD strokeRgb, double lineWidth,
|
||||
bool filled, DWORD fillRgb)
|
||||
{
|
||||
fprintf(f, " %.3f setlinewidth\r\n"
|
||||
" %.3f %.3f %.3f setrgbcolor\r\n"
|
||||
" 1 setlinejoin\r\n" // rounded
|
||||
" 1 setlinecap\r\n" // rounded
|
||||
" gsave stroke grestore\r\n",
|
||||
MmToPts(lineWidth),
|
||||
REDf(strokeRgb), GREENf(strokeRgb), BLUEf(strokeRgb));
|
||||
if(filled) {
|
||||
fprintf(f, " %.3f %.3f %.3f setrgbcolor\r\n"
|
||||
" gsave fill grestore\r\n",
|
||||
REDf(fillRgb), GREENf(fillRgb), BLUEf(fillRgb));
|
||||
}
|
||||
}
|
||||
|
||||
void EpsFileWriter::MaybeMoveTo(Vector st, Vector fi) {
|
||||
if(!prevPt.Equals(st)) {
|
||||
fprintf(f, " %.3f %.3f moveto\r\n",
|
||||
MmToPts(st.x - ptMin.x), MmToPts(st.y - ptMin.y));
|
||||
}
|
||||
prevPt = fi;
|
||||
}
|
||||
|
||||
void EpsFileWriter::Triangle(STriangle *tr) {
|
||||
|
@ -187,7 +202,7 @@ void EpsFileWriter::Triangle(STriangle *tr) {
|
|||
" %.3f %.3f lineto\r\n"
|
||||
" %.3f %.3f lineto\r\n"
|
||||
" closepath\r\n"
|
||||
"fill\r\n",
|
||||
"gsave fill grestore\r\n",
|
||||
REDf(tr->meta.color), GREENf(tr->meta.color), BLUEf(tr->meta.color),
|
||||
MmToPts(tr->a.x - ptMin.x), MmToPts(tr->a.y - ptMin.y),
|
||||
MmToPts(tr->b.x - ptMin.x), MmToPts(tr->b.y - ptMin.y),
|
||||
|
@ -196,25 +211,22 @@ void EpsFileWriter::Triangle(STriangle *tr) {
|
|||
// 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"
|
||||
"1 setlinejoin\r\n"
|
||||
"1 setlinecap\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),
|
||||
MmToPts(sw),
|
||||
MmToPts(tr->a.x - ptMin.x), MmToPts(tr->a.y - ptMin.y),
|
||||
MmToPts(tr->b.x - ptMin.x), MmToPts(tr->b.y - ptMin.y),
|
||||
MmToPts(tr->c.x - ptMin.x), MmToPts(tr->c.y - ptMin.y));
|
||||
"gsave stroke grestore\r\n",
|
||||
MmToPts(sw));
|
||||
}
|
||||
|
||||
void EpsFileWriter::Bezier(DWORD rgb, double w, SBezier *sb) {
|
||||
void EpsFileWriter::Bezier(SBezier *sb) {
|
||||
Vector c, n = Vector::From(0, 0, 1);
|
||||
double r;
|
||||
if(sb->IsCircle(n, &c, &r)) {
|
||||
if(sb->deg == 1) {
|
||||
MaybeMoveTo(sb->ctrl[0], sb->ctrl[1]);
|
||||
fprintf(f, " %.3f %.3f lineto\r\n",
|
||||
MmToPts(sb->ctrl[1].x - ptMin.x),
|
||||
MmToPts(sb->ctrl[1].y - ptMin.y));
|
||||
} else if(sb->IsCircle(n, &c, &r)) {
|
||||
Vector p0 = sb->ctrl[0], p1 = sb->ctrl[2];
|
||||
double theta0 = atan2(p0.y - c.y, p0.x - c.x),
|
||||
theta1 = atan2(p1.y - c.y, p1.x - c.x),
|
||||
|
@ -223,31 +235,21 @@ void EpsFileWriter::Bezier(DWORD rgb, double w, SBezier *sb) {
|
|||
SWAP(double, theta0, theta1);
|
||||
SWAP(Vector, p0, p1);
|
||||
}
|
||||
MaybeMoveTo(p0, p1);
|
||||
fprintf(f,
|
||||
"newpath\r\n"
|
||||
" %.3f %.3f moveto\r\n"
|
||||
" %.3f %.3f %.3f %.3f %.3f arc\r\n"
|
||||
"%s"
|
||||
"stroke\r\n",
|
||||
MmToPts(p0.x - ptMin.x), MmToPts(p0.y - ptMin.y),
|
||||
" %.3f %.3f %.3f %.3f %.3f arc\r\n",
|
||||
MmToPts(c.x - ptMin.x), MmToPts(c.y - ptMin.y),
|
||||
MmToPts(r),
|
||||
theta0*180/PI, theta1*180/PI,
|
||||
StyleString(rgb, w));
|
||||
theta0*180/PI, theta1*180/PI);
|
||||
} else if(sb->deg == 3 && !sb->IsRational()) {
|
||||
MaybeMoveTo(sb->ctrl[0], sb->ctrl[3]);
|
||||
fprintf(f,
|
||||
"newpath\r\n"
|
||||
" %.3f %.3f moveto\r\n"
|
||||
" %.3f %.3f %.3f %.3f %.3f %.3f curveto\r\n"
|
||||
"%s"
|
||||
"stroke\r\n",
|
||||
MmToPts(sb->ctrl[0].x - ptMin.x), MmToPts(sb->ctrl[0].y - ptMin.y),
|
||||
" %.3f %.3f %.3f %.3f %.3f %.3f curveto\r\n",
|
||||
MmToPts(sb->ctrl[1].x - ptMin.x), MmToPts(sb->ctrl[1].y - ptMin.y),
|
||||
MmToPts(sb->ctrl[2].x - ptMin.x), MmToPts(sb->ctrl[2].y - ptMin.y),
|
||||
MmToPts(sb->ctrl[3].x - ptMin.x), MmToPts(sb->ctrl[3].y - ptMin.y),
|
||||
StyleString(rgb, w));
|
||||
MmToPts(sb->ctrl[3].x - ptMin.x), MmToPts(sb->ctrl[3].y - ptMin.y));
|
||||
} else {
|
||||
BezierAsNonrationalCubic(rgb, w, sb);
|
||||
BezierAsNonrationalCubic(sb);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -263,16 +265,6 @@ void EpsFileWriter::FinishAndCloseFile(void) {
|
|||
// Routines for PDF output, some extra complexity because we have to generate
|
||||
// a correct xref table.
|
||||
//-----------------------------------------------------------------------------
|
||||
char *PdfFileWriter::StyleString(DWORD rgb, double w) {
|
||||
static char ret[300];
|
||||
sprintf(ret, "1 J 1 j " // round endcaps and joins
|
||||
"%.3f w "
|
||||
"%.3f %.3f %.3f RG\r\n",
|
||||
MmToPts(w),
|
||||
REDf(rgb), GREENf(rgb), BLUEf(rgb));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void PdfFileWriter::StartFile(void) {
|
||||
fprintf(f,
|
||||
"%%PDF-1.1\r\n"
|
||||
|
@ -392,21 +384,44 @@ void PdfFileWriter::FinishAndCloseFile(void) {
|
|||
|
||||
}
|
||||
|
||||
void PdfFileWriter::LineSegment(DWORD rgb, double w, Vector ptA, Vector ptB) {
|
||||
fprintf(f,
|
||||
"%s"
|
||||
"%.3f %.3f m\r\n"
|
||||
"%.3f %.3f l\r\n"
|
||||
"S\r\n",
|
||||
StyleString(rgb, w),
|
||||
MmToPts(ptA.x - ptMin.x), MmToPts(ptA.y - ptMin.y),
|
||||
MmToPts(ptB.x - ptMin.x), MmToPts(ptB.y - ptMin.y));
|
||||
void PdfFileWriter::StartPath(DWORD strokeRgb, double lineWidth,
|
||||
bool filled, DWORD fillRgb)
|
||||
{
|
||||
fprintf(f, "1 J 1 j " // round endcaps and joins
|
||||
"%.3f w "
|
||||
"%.3f %.3f %.3f RG\r\n",
|
||||
MmToPts(lineWidth),
|
||||
REDf(strokeRgb), GREENf(strokeRgb), BLUEf(strokeRgb));
|
||||
if(filled) {
|
||||
fprintf(f, "%.3f %.3f %.3f rg\r\n",
|
||||
REDf(fillRgb), GREENf(fillRgb), BLUEf(fillRgb));
|
||||
}
|
||||
|
||||
prevPt = Vector::From(VERY_POSITIVE, VERY_POSITIVE, VERY_POSITIVE);
|
||||
}
|
||||
void PdfFileWriter::FinishPath(DWORD strokeRgb, double lineWidth,
|
||||
bool filled, DWORD fillRgb)
|
||||
{
|
||||
if(filled) {
|
||||
fprintf(f, "b\r\n");
|
||||
} else {
|
||||
fprintf(f, "S\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
void PdfFileWriter::MaybeMoveTo(Vector st, Vector fi) {
|
||||
if(!prevPt.Equals(st)) {
|
||||
fprintf(f, "%.3f %.3f m\r\n",
|
||||
MmToPts(st.x - ptMin.x), MmToPts(st.y - ptMin.y));
|
||||
}
|
||||
prevPt = fi;
|
||||
}
|
||||
|
||||
void PdfFileWriter::Triangle(STriangle *tr) {
|
||||
double sw = max(ptMax.x - ptMin.x, ptMax.y - ptMin.y) / 1000;
|
||||
|
||||
fprintf(f,
|
||||
"1 J 1 j\r\n"
|
||||
"%.3f %.3f %.3f RG\r\n"
|
||||
"%.3f %.3f %.3f rg\r\n"
|
||||
"%.3f w\r\n"
|
||||
|
@ -422,35 +437,27 @@ void PdfFileWriter::Triangle(STriangle *tr) {
|
|||
MmToPts(tr->c.x - ptMin.x), MmToPts(tr->c.y - ptMin.y));
|
||||
}
|
||||
|
||||
void PdfFileWriter::Bezier(DWORD rgb, double w, SBezier *sb) {
|
||||
if(sb->deg == 3 && !sb->IsRational()) {
|
||||
void PdfFileWriter::Bezier(SBezier *sb) {
|
||||
if(sb->deg == 1) {
|
||||
MaybeMoveTo(sb->ctrl[0], sb->ctrl[1]);
|
||||
fprintf(f,
|
||||
"%s"
|
||||
"%.3f %.3f m\r\n"
|
||||
"%.3f %.3f %.3f %.3f %.3f %.3f c\r\n"
|
||||
"S\r\n",
|
||||
StyleString(rgb, w),
|
||||
MmToPts(sb->ctrl[0].x - ptMin.x), MmToPts(sb->ctrl[0].y - ptMin.y),
|
||||
"%.3f %.3f l\r\n",
|
||||
MmToPts(sb->ctrl[1].x - ptMin.x), MmToPts(sb->ctrl[1].y - ptMin.y));
|
||||
} else if(sb->deg == 3 && !sb->IsRational()) {
|
||||
MaybeMoveTo(sb->ctrl[0], sb->ctrl[3]);
|
||||
fprintf(f,
|
||||
"%.3f %.3f %.3f %.3f %.3f %.3f c\r\n",
|
||||
MmToPts(sb->ctrl[1].x - ptMin.x), MmToPts(sb->ctrl[1].y - ptMin.y),
|
||||
MmToPts(sb->ctrl[2].x - ptMin.x), MmToPts(sb->ctrl[2].y - ptMin.y),
|
||||
MmToPts(sb->ctrl[3].x - ptMin.x), MmToPts(sb->ctrl[3].y - ptMin.y));
|
||||
} else {
|
||||
BezierAsNonrationalCubic(rgb, w, sb);
|
||||
BezierAsNonrationalCubic(sb);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Routines for SVG output
|
||||
//-----------------------------------------------------------------------------
|
||||
char *SvgFileWriter::StyleString(DWORD rgb, double w) {
|
||||
static char ret[200];
|
||||
sprintf(ret, "stroke-width='%.3f' stroke='#%02x%02x%02x' "
|
||||
"style='fill: none;' "
|
||||
"stroke-linecap='round' stroke-linejoin='round' ",
|
||||
w, RED(rgb), GREEN(rgb), BLUE(rgb));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SvgFileWriter::StartFile(void) {
|
||||
fprintf(f,
|
||||
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\" "
|
||||
|
@ -467,13 +474,35 @@ void SvgFileWriter::StartFile(void) {
|
|||
// A little bit of extra space for the stroke width.
|
||||
}
|
||||
|
||||
void SvgFileWriter::LineSegment(DWORD rgb, double w, Vector ptA, Vector ptB) {
|
||||
void SvgFileWriter::StartPath(DWORD strokeRgb, double lineWidth,
|
||||
bool filled, DWORD fillRgb)
|
||||
{
|
||||
fprintf(f, "<path d='");
|
||||
prevPt = Vector::From(VERY_POSITIVE, VERY_POSITIVE, VERY_POSITIVE);
|
||||
}
|
||||
void SvgFileWriter::FinishPath(DWORD strokeRgb, double lineWidth,
|
||||
bool filled, DWORD fillRgb)
|
||||
{
|
||||
char fill[100];
|
||||
if(filled) {
|
||||
sprintf(fill, "#%02x%02x%02x",
|
||||
RED(fillRgb), GREEN(fillRgb), BLUE(fillRgb));
|
||||
} else {
|
||||
strcpy(fill, "none");
|
||||
}
|
||||
fprintf(f, "' stroke-width='%.3f' stroke='#%02x%02x%02x' "
|
||||
"stroke-linecap='round' stroke-linejoin='round' "
|
||||
"fill='%s' />\r\n",
|
||||
lineWidth, RED(strokeRgb), GREEN(strokeRgb), BLUE(strokeRgb),
|
||||
fill);
|
||||
}
|
||||
|
||||
void SvgFileWriter::MaybeMoveTo(Vector st, Vector fi) {
|
||||
// SVG uses a coordinate system with the origin at top left, +y down
|
||||
fprintf(f,
|
||||
"<polyline points='%.3f,%.3f %.3f,%.3f' %s />\r\n",
|
||||
(ptA.x - ptMin.x), (ptMax.y - ptA.y),
|
||||
(ptB.x - ptMin.x), (ptMax.y - ptB.y),
|
||||
StyleString(rgb, w));
|
||||
if(!prevPt.Equals(st)) {
|
||||
fprintf(f, "M%.3f %.3f ", (st.x - ptMin.x), (ptMax.y - st.y));
|
||||
}
|
||||
prevPt = fi;
|
||||
}
|
||||
|
||||
void SvgFileWriter::Triangle(STriangle *tr) {
|
||||
|
@ -493,10 +522,14 @@ void SvgFileWriter::Triangle(STriangle *tr) {
|
|||
RED(tr->meta.color), GREEN(tr->meta.color), BLUE(tr->meta.color));
|
||||
}
|
||||
|
||||
void SvgFileWriter::Bezier(DWORD rgb, double w, SBezier *sb) {
|
||||
void SvgFileWriter::Bezier(SBezier *sb) {
|
||||
Vector c, n = Vector::From(0, 0, 1);
|
||||
double r;
|
||||
if(sb->IsCircle(n, &c, &r)) {
|
||||
if(sb->deg == 1) {
|
||||
MaybeMoveTo(sb->ctrl[0], sb->ctrl[1]);
|
||||
fprintf(f, "L%.3f,%.3f ",
|
||||
(sb->ctrl[1].x - ptMin.x), (ptMax.y - sb->ctrl[1].y));
|
||||
} else if(sb->IsCircle(n, &c, &r)) {
|
||||
Vector p0 = sb->ctrl[0], p1 = sb->ctrl[2];
|
||||
double theta0 = atan2(p0.y - c.y, p0.x - c.x),
|
||||
theta1 = atan2(p1.y - c.y, p1.x - c.x),
|
||||
|
@ -508,36 +541,25 @@ void SvgFileWriter::Bezier(DWORD rgb, double w, SBezier *sb) {
|
|||
if(dtheta < 0) {
|
||||
SWAP(Vector, p0, p1);
|
||||
}
|
||||
fprintf(f,
|
||||
"<path d='M%.3f,%.3f "
|
||||
"A%.3f,%.3f 0 0,0 %.3f,%.3f' %s />\r\n",
|
||||
p0.x - ptMin.x, ptMax.y - p0.y,
|
||||
r, r,
|
||||
p1.x - ptMin.x, ptMax.y - p1.y,
|
||||
StyleString(rgb, w));
|
||||
MaybeMoveTo(p0, p1);
|
||||
fprintf(f, "A%.3f,%.3f 0 0,0 %.3f,%.3f ",
|
||||
r, r,
|
||||
p1.x - ptMin.x, ptMax.y - p1.y);
|
||||
} else if(!sb->IsRational()) {
|
||||
if(sb->deg == 1) {
|
||||
LineSegment(rgb, w, sb->ctrl[0], sb->ctrl[1]);
|
||||
} else if(sb->deg == 2) {
|
||||
fprintf(f,
|
||||
"<path d='M%.3f,%.3f "
|
||||
"Q%.3f,%.3f %.3f,%.3f' %s />\r\n",
|
||||
sb->ctrl[0].x - ptMin.x, ptMax.y - sb->ctrl[0].y,
|
||||
if(sb->deg == 2) {
|
||||
MaybeMoveTo(sb->ctrl[0], sb->ctrl[2]);
|
||||
fprintf(f, "Q%.3f,%.3f %.3f,%.3f ",
|
||||
sb->ctrl[1].x - ptMin.x, ptMax.y - sb->ctrl[1].y,
|
||||
sb->ctrl[2].x - ptMin.x, ptMax.y - sb->ctrl[2].y,
|
||||
StyleString(rgb, w));
|
||||
sb->ctrl[2].x - ptMin.x, ptMax.y - sb->ctrl[2].y);
|
||||
} else if(sb->deg == 3) {
|
||||
fprintf(f,
|
||||
"<path d='M%.3f,%.3f "
|
||||
"C%.3f,%.3f %.3f,%.3f %.3f,%.3f' %s />\r\n",
|
||||
sb->ctrl[0].x - ptMin.x, ptMax.y - sb->ctrl[0].y,
|
||||
MaybeMoveTo(sb->ctrl[0], sb->ctrl[3]);
|
||||
fprintf(f, "C%.3f,%.3f %.3f,%.3f %.3f,%.3f ",
|
||||
sb->ctrl[1].x - ptMin.x, ptMax.y - sb->ctrl[1].y,
|
||||
sb->ctrl[2].x - ptMin.x, ptMax.y - sb->ctrl[2].y,
|
||||
sb->ctrl[3].x - ptMin.x, ptMax.y - sb->ctrl[3].y,
|
||||
StyleString(rgb, w));
|
||||
sb->ctrl[3].x - ptMin.x, ptMax.y - sb->ctrl[3].y);
|
||||
}
|
||||
} else {
|
||||
BezierAsNonrationalCubic(rgb, w, sb);
|
||||
BezierAsNonrationalCubic(sb);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -558,20 +580,29 @@ void HpglFileWriter::StartFile(void) {
|
|||
fprintf(f, "SP1;\r\n");
|
||||
}
|
||||
|
||||
void HpglFileWriter::LineSegment(DWORD rgb, double w, Vector ptA, Vector ptB) {
|
||||
fprintf(f, "PU%d,%d;\r\n",
|
||||
(int)MmToHpglUnits(ptA.x),
|
||||
(int)MmToHpglUnits(ptA.y));
|
||||
fprintf(f, "PD%d,%d;\r\n",
|
||||
(int)MmToHpglUnits(ptB.x),
|
||||
(int)MmToHpglUnits(ptB.y));
|
||||
void HpglFileWriter::StartPath(DWORD strokeRgb, double lineWidth,
|
||||
bool filled, DWORD fillRgb)
|
||||
{
|
||||
}
|
||||
void HpglFileWriter::FinishPath(DWORD strokeRgb, double lineWidth,
|
||||
bool filled, DWORD fillRgb)
|
||||
{
|
||||
}
|
||||
|
||||
void HpglFileWriter::Triangle(STriangle *tr) {
|
||||
}
|
||||
|
||||
void HpglFileWriter::Bezier(DWORD rgb, double w, SBezier *sb) {
|
||||
BezierAsPwl(rgb, w, sb);
|
||||
void HpglFileWriter::Bezier(SBezier *sb) {
|
||||
if(sb->deg == 1) {
|
||||
fprintf(f, "PU%d,%d;\r\n",
|
||||
(int)MmToHpglUnits(sb->ctrl[0].x),
|
||||
(int)MmToHpglUnits(sb->ctrl[0].y));
|
||||
fprintf(f, "PD%d,%d;\r\n",
|
||||
(int)MmToHpglUnits(sb->ctrl[1].x),
|
||||
(int)MmToHpglUnits(sb->ctrl[1].y));
|
||||
} else {
|
||||
BezierAsPwl(sb);
|
||||
}
|
||||
}
|
||||
|
||||
void HpglFileWriter::FinishAndCloseFile(void) {
|
||||
|
@ -591,13 +622,16 @@ void Step2dFileWriter::StartFile(void) {
|
|||
void Step2dFileWriter::Triangle(STriangle *tr) {
|
||||
}
|
||||
|
||||
void Step2dFileWriter::LineSegment(DWORD rgb, double w, Vector ptA, Vector ptB)
|
||||
void Step2dFileWriter::StartPath(DWORD strokeRgb, double lineWidth,
|
||||
bool filled, DWORD fillRgb)
|
||||
{
|
||||
}
|
||||
void Step2dFileWriter::FinishPath(DWORD strokeRgb, double lineWidth,
|
||||
bool filled, DWORD fillRgb)
|
||||
{
|
||||
SBezier sb = SBezier::From(ptA, ptB);
|
||||
Bezier(rgb, w, &sb);
|
||||
}
|
||||
|
||||
void Step2dFileWriter::Bezier(DWORD rgb, double w, SBezier *sb) {
|
||||
void Step2dFileWriter::Bezier(SBezier *sb) {
|
||||
int c = sfw.ExportCurve(sb);
|
||||
sfw.curves.Add(&c);
|
||||
}
|
||||
|
|
|
@ -467,7 +467,8 @@ void Group::Draw(void) {
|
|||
glxVertex3v(polyError.notClosedAt.b);
|
||||
glEnd();
|
||||
glxColorRGB(Style::Color(Style::DRAW_ERROR));
|
||||
glxWriteText("not closed contour!", DEFAULT_TEXT_HEIGHT,
|
||||
glxWriteText("not closed contour, or not all same style!",
|
||||
DEFAULT_TEXT_HEIGHT,
|
||||
polyError.notClosedAt.b, SS.GW.projRight, SS.GW.projUp,
|
||||
NULL, NULL);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
@ -492,45 +493,6 @@ void Group::Draw(void) {
|
|||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Verify that the Beziers in this loop set all have the same auxA, and return
|
||||
// that value. If they don't, then set allSame to be false, and indicate a
|
||||
// point on the non-matching curve.
|
||||
//-----------------------------------------------------------------------------
|
||||
DWORD Group::GetLoopSetFillColor(SBezierLoopSet *sbls,
|
||||
bool *allSame, Vector *errorAt)
|
||||
{
|
||||
bool first = true;
|
||||
DWORD fillRgb = (DWORD)-1;
|
||||
|
||||
SBezierLoop *sbl;
|
||||
for(sbl = sbls->l.First(); sbl; sbl = sbls->l.NextAfter(sbl)) {
|
||||
SBezier *sb;
|
||||
for(sb = sbl->l.First(); sb; sb = sbl->l.NextAfter(sb)) {
|
||||
DWORD thisRgb = (DWORD)-1;
|
||||
if(sb->auxA != 0) {
|
||||
hStyle hs = { sb->auxA };
|
||||
Style *s = Style::Get(hs);
|
||||
if(s->filled) {
|
||||
thisRgb = s->fillColor;
|
||||
}
|
||||
}
|
||||
if(first) {
|
||||
fillRgb = thisRgb;
|
||||
first = false;
|
||||
} else {
|
||||
if(fillRgb != thisRgb) {
|
||||
*allSame = false;
|
||||
*errorAt = sb->Start();
|
||||
return fillRgb;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*allSame = true;
|
||||
return fillRgb;
|
||||
}
|
||||
|
||||
void Group::FillLoopSetAsPolygon(SBezierLoopSet *sbls) {
|
||||
SPolygon sp;
|
||||
ZERO(&sp);
|
||||
|
@ -545,18 +507,16 @@ void Group::DrawFilledPaths(void) {
|
|||
SBezierLoopSet *sbls;
|
||||
SBezierLoopSetSet *sblss = &bezierLoops;
|
||||
for(sbls = sblss->l.First(); sbls; sbls = sblss->l.NextAfter(sbls)) {
|
||||
bool allSame;
|
||||
Vector errorPt;
|
||||
DWORD fillRgb = GetLoopSetFillColor(sbls, &allSame, &errorPt);
|
||||
if(allSame && fillRgb != (DWORD)-1) {
|
||||
glxColorRGBa(fillRgb, 1);
|
||||
if(sbls->l.n == 0 || sbls->l.elem[0].l.n == 0) continue;
|
||||
// In an assembled loop, all the styles should be the same; so doesn't
|
||||
// matter which one we grab.
|
||||
SBezier *sb = &(sbls->l.elem[0].l.elem[0]);
|
||||
hStyle hs = { sb->auxA };
|
||||
Style *s = Style::Get(hs);
|
||||
if(s->filled) {
|
||||
// This is a filled loop, where the user specified a fill color.
|
||||
glxColorRGBa(s->fillColor, 1);
|
||||
FillLoopSetAsPolygon(sbls);
|
||||
} else if(!allSame) {
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glxColorRGB(Style::Color(Style::DRAW_ERROR));
|
||||
glxWriteText("not all same fill color!", DEFAULT_TEXT_HEIGHT,
|
||||
errorPt, SS.GW.projRight, SS.GW.projUp, NULL, NULL);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
} else {
|
||||
if(h.v == SS.GW.activeGroup.v && SS.checkClosedContour &&
|
||||
polyError.how == POLY_GOOD)
|
||||
|
|
68
solvespace.h
68
solvespace.h
|
@ -415,33 +415,42 @@ public:
|
|||
|
||||
static VectorFileWriter *ForFile(char *file);
|
||||
|
||||
void Output(SEdgeList *sel, SBezierList *sbl, SMesh *sm);
|
||||
void Output(SBezierLoopSetSet *sblss, SMesh *sm);
|
||||
|
||||
void BezierAsPwl(DWORD rgb, double width, SBezier *sb);
|
||||
void BezierAsNonrationalCubic(DWORD rgb, double width,
|
||||
SBezier *sb, int depth=0);
|
||||
void BezierAsPwl(SBezier *sb);
|
||||
void BezierAsNonrationalCubic(SBezier *sb, int depth=0);
|
||||
|
||||
virtual void Bezier(DWORD rgb, double width, SBezier *sb) = 0;
|
||||
virtual void LineSegment(DWORD rgb, double width, Vector ptA, Vector ptB)
|
||||
= 0;
|
||||
virtual void StartPath( DWORD strokeRgb, double lineWidth,
|
||||
bool filled, DWORD fillRgb) = 0;
|
||||
virtual void FinishPath(DWORD strokeRgb, double lineWidth,
|
||||
bool filled, DWORD fillRgb) = 0;
|
||||
virtual void Bezier(SBezier *sb) = 0;
|
||||
virtual void Triangle(STriangle *tr) = 0;
|
||||
virtual void StartFile(void) = 0;
|
||||
virtual void FinishAndCloseFile(void) = 0;
|
||||
};
|
||||
class DxfFileWriter : public VectorFileWriter {
|
||||
public:
|
||||
void LineSegment(DWORD rgb, double width, Vector ptA, Vector ptB);
|
||||
void StartPath( DWORD strokeRgb, double lineWidth,
|
||||
bool filled, DWORD fillRgb);
|
||||
void FinishPath(DWORD strokeRgb, double lineWidth,
|
||||
bool filled, DWORD fillRgb);
|
||||
void Triangle(STriangle *tr);
|
||||
void Bezier(DWORD rgb, double width, SBezier *sb);
|
||||
void Bezier(SBezier *sb);
|
||||
void StartFile(void);
|
||||
void FinishAndCloseFile(void);
|
||||
};
|
||||
class EpsFileWriter : public VectorFileWriter {
|
||||
public:
|
||||
static char *StyleString(DWORD rgb, double width);
|
||||
void LineSegment(DWORD rgb, double width, Vector ptA, Vector ptB);
|
||||
Vector prevPt;
|
||||
void MaybeMoveTo(Vector s, Vector f);
|
||||
|
||||
void StartPath( DWORD strokeRgb, double lineWidth,
|
||||
bool filled, DWORD fillRgb);
|
||||
void FinishPath(DWORD strokeRgb, double lineWidth,
|
||||
bool filled, DWORD fillRgb);
|
||||
void Triangle(STriangle *tr);
|
||||
void Bezier(DWORD rgb, double width, SBezier *sb);
|
||||
void Bezier(SBezier *sb);
|
||||
void StartFile(void);
|
||||
void FinishAndCloseFile(void);
|
||||
};
|
||||
|
@ -449,37 +458,52 @@ class PdfFileWriter : public VectorFileWriter {
|
|||
public:
|
||||
DWORD xref[10];
|
||||
DWORD bodyStart;
|
||||
Vector prevPt;
|
||||
void MaybeMoveTo(Vector s, Vector f);
|
||||
|
||||
static char *StyleString(DWORD rgb, double width);
|
||||
void LineSegment(DWORD rgb, double width, Vector ptA, Vector ptB);
|
||||
void StartPath( DWORD strokeRgb, double lineWidth,
|
||||
bool filled, DWORD fillRgb);
|
||||
void FinishPath(DWORD strokeRgb, double lineWidth,
|
||||
bool filled, DWORD fillRgb);
|
||||
void Triangle(STriangle *tr);
|
||||
void Bezier(DWORD rgb, double width, SBezier *sb);
|
||||
void Bezier(SBezier *sb);
|
||||
void StartFile(void);
|
||||
void FinishAndCloseFile(void);
|
||||
};
|
||||
class SvgFileWriter : public VectorFileWriter {
|
||||
public:
|
||||
static char *StyleString(DWORD rgb, double width);
|
||||
void LineSegment(DWORD rgb, double width, Vector ptA, Vector ptB);
|
||||
Vector prevPt;
|
||||
void MaybeMoveTo(Vector s, Vector f);
|
||||
|
||||
void StartPath( DWORD strokeRgb, double lineWidth,
|
||||
bool filled, DWORD fillRgb);
|
||||
void FinishPath(DWORD strokeRgb, double lineWidth,
|
||||
bool filled, DWORD fillRgb);
|
||||
void Triangle(STriangle *tr);
|
||||
void Bezier(DWORD rgb, double width, SBezier *sb);
|
||||
void Bezier(SBezier *sb);
|
||||
void StartFile(void);
|
||||
void FinishAndCloseFile(void);
|
||||
};
|
||||
class HpglFileWriter : public VectorFileWriter {
|
||||
public:
|
||||
static double MmToHpglUnits(double mm);
|
||||
void LineSegment(DWORD rgb, double width, Vector ptA, Vector ptB);
|
||||
void StartPath( DWORD strokeRgb, double lineWidth,
|
||||
bool filled, DWORD fillRgb);
|
||||
void FinishPath(DWORD strokeRgb, double lineWidth,
|
||||
bool filled, DWORD fillRgb);
|
||||
void Triangle(STriangle *tr);
|
||||
void Bezier(DWORD rgb, double width, SBezier *sb);
|
||||
void Bezier(SBezier *sb);
|
||||
void StartFile(void);
|
||||
void FinishAndCloseFile(void);
|
||||
};
|
||||
class Step2dFileWriter : public VectorFileWriter {
|
||||
StepFileWriter sfw;
|
||||
void LineSegment(DWORD rgb, double width, Vector ptA, Vector ptB);
|
||||
void StartPath( DWORD strokeRgb, double lineWidth,
|
||||
bool filled, DWORD fillRgb);
|
||||
void FinishPath(DWORD strokeRgb, double lineWidth,
|
||||
bool filled, DWORD fillRgb);
|
||||
void Triangle(STriangle *tr);
|
||||
void Bezier(DWORD rgb, double width, SBezier *sb);
|
||||
void Bezier(SBezier *sb);
|
||||
void StartFile(void);
|
||||
void FinishAndCloseFile(void);
|
||||
};
|
||||
|
|
|
@ -402,6 +402,7 @@ SBezierLoop SBezierLoop::FromCurves(SBezierList *sbl,
|
|||
loop.l.Add(first);
|
||||
Vector start = first->Start();
|
||||
Vector hanging = first->Finish();
|
||||
int auxA = first->auxA;
|
||||
|
||||
sbl->l.RemoveTagged();
|
||||
|
||||
|
@ -411,11 +412,11 @@ SBezierLoop SBezierLoop::FromCurves(SBezierList *sbl,
|
|||
for(i = 0; i < sbl->l.n; i++) {
|
||||
SBezier *test = &(sbl->l.elem[i]);
|
||||
|
||||
if((test->Finish()).Equals(hanging)) {
|
||||
if((test->Finish()).Equals(hanging) && test->auxA == auxA) {
|
||||
test->Reverse();
|
||||
// and let the next test catch it
|
||||
}
|
||||
if((test->Start()).Equals(hanging)) {
|
||||
if((test->Start()).Equals(hanging) && test->auxA == auxA) {
|
||||
test->tag = 1;
|
||||
loop.l.Add(test);
|
||||
hanging = test->Finish();
|
||||
|
@ -690,11 +691,48 @@ void SBezierLoopSetSet::FindOuterFacesFrom(SBezierList *sbl, SPolygon *spxyz,
|
|||
l.Add(&outerAndInners);
|
||||
}
|
||||
}
|
||||
|
||||
// If we have poorly-formed loops--for example, overlapping zero-area
|
||||
// stuff--then we can end up with leftovers. We use this function to
|
||||
// group stuff into closed paths for export when possible, so it's bad
|
||||
// to screw up on that stuff. So just add them onto the open curve list.
|
||||
// Very ugly, but better than losing curves.
|
||||
for(i = 0; i < sbls.l.n; i++) {
|
||||
SBezierLoop *loop = &(sbls.l.elem[i]);
|
||||
if(loop->tag == USED_LOOP) continue;
|
||||
|
||||
if(openContours) {
|
||||
SBezier *sb;
|
||||
for(sb = loop->l.First(); sb; sb = loop->l.NextAfter(sb)) {
|
||||
openContours->l.Add(sb);
|
||||
}
|
||||
}
|
||||
loop->Clear();
|
||||
// but don't free the used loops, since we shallow-copied them to
|
||||
// ourself
|
||||
}
|
||||
|
||||
sbls.l.Clear(); // not sbls.Clear(), since that would deep-clear
|
||||
spuv.Clear();
|
||||
// Don't free sbls; we've shallow-copied all of its members to ourself.
|
||||
}
|
||||
|
||||
void SBezierLoopSetSet::AddOpenPath(SBezier *sb) {
|
||||
SBezierLoop sbl;
|
||||
ZERO(&sbl);
|
||||
sbl.l.Add(sb);
|
||||
|
||||
SBezierLoopSet sbls;
|
||||
ZERO(&sbls);
|
||||
sbls.l.Add(&sbl);
|
||||
|
||||
l.Add(&sbls);
|
||||
}
|
||||
|
||||
void SBezierLoopSetSet::Clear(void) {
|
||||
SBezierLoopSet *sbls;
|
||||
for(sbls = l.First(); sbls; sbls = l.NextAfter(sbls)) {
|
||||
sbls->Clear();
|
||||
}
|
||||
l.Clear();
|
||||
}
|
||||
|
||||
|
|
|
@ -144,7 +144,6 @@ public:
|
|||
|
||||
void GetBoundingProjd(Vector u, Vector orig, double *umin, double *umax);
|
||||
void MakePwlInto(SPolygon *sp);
|
||||
int GetAuxA(bool *allSame, Vector *errorAt);
|
||||
void Clear(void);
|
||||
};
|
||||
|
||||
|
@ -157,6 +156,7 @@ public:
|
|||
bool *allClosed, SEdge *notClosedAt,
|
||||
bool *allCoplanar, Vector *notCoplanarAt,
|
||||
SBezierList *openContours);
|
||||
void AddOpenPath(SBezier *sb);
|
||||
void Clear(void);
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue