SVG: export stippled lines.

Also, factor out styles in the exported file, making it much
smaller.
This commit is contained in:
EvilSpirit 2016-04-04 20:31:44 +06:00 committed by whitequark
parent 94cba11f2a
commit d88149e705

View File

@ -486,9 +486,14 @@ bool DxfFileWriter::NeedToOutput(Constraint *c) {
// Routines for EPS output // Routines for EPS output
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
std::string MakeStipplePattern(int pattern, double scale, char delimiter) { static std::string MakeStipplePattern(int pattern, double scale, char delimiter,
bool inkscapeWorkaround = false) {
scale /= 2.0; scale /= 2.0;
// Inkscape ignores all elements that are exactly zero instead of drawing
// them as dots.
double zero = inkscapeWorkaround ? 1e-6 : 0;
std::string result; std::string result;
switch(pattern) { switch(pattern) {
case Style::STIPPLE_CONTINUOUS: case Style::STIPPLE_CONTINUOUS:
@ -500,19 +505,21 @@ std::string MakeStipplePattern(int pattern, double scale, char delimiter) {
result = ssprintf("%.3f_%.3f", scale, scale); result = ssprintf("%.3f_%.3f", scale, scale);
break; break;
case Style::STIPPLE_DASH_DOT: case Style::STIPPLE_DASH_DOT:
result = ssprintf("%.3f_%.3f_0_%.3f", result = ssprintf("%.3f_%.3f_%.6f_%.3f",
scale, scale * 0.5, scale * 0.5); scale, scale * 0.5, zero, scale * 0.5);
break; break;
case Style::STIPPLE_DASH_DOT_DOT: case Style::STIPPLE_DASH_DOT_DOT:
result = ssprintf("%.3f_%.3f_0_%.3f_0_%.3f", result = ssprintf("%.3f_%.3f_%.6f_%.3f_%.6f_%.3f",
scale, scale * 0.5, scale * 0.5, scale * 0.5); scale, scale * 0.5, zero,
scale * 0.5, scale * 0.5, zero);
break; break;
case Style::STIPPLE_DOT: case Style::STIPPLE_DOT:
result = ssprintf("0_%.3f", scale * 0.5); result = ssprintf("%.6f_%.3f", zero, scale * 0.5);
break; break;
case Style::STIPPLE_LONG_DASH: case Style::STIPPLE_LONG_DASH:
result = ssprintf("%.3f_%.3f", scale * 2.0, scale * 0.5); result = ssprintf("%.3f_%.3f", scale * 2.0, scale * 0.5);
break; break;
default: default:
oops(); oops();
} }
@ -863,6 +870,37 @@ void SvgFileWriter::StartFile(void) {
"\r\n", "\r\n",
(ptMax.x - ptMin.x), (ptMax.y - ptMin.y), (ptMax.x - ptMin.x), (ptMax.y - ptMin.y),
(ptMax.x - ptMin.x), (ptMax.y - ptMin.y)); (ptMax.x - ptMin.x), (ptMax.y - ptMin.y));
fprintf(f, "<style><![CDATA[\r\n");
fprintf(f, "polygon {\r\n");
fprintf(f, "shape-rendering:crispEdges;\r\n");
// 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, "stroke-width:%f;\r\n", sw);
fprintf(f, "}\r\n");
for(int i = 0; i < SK.style.n; i++) {
Style *s = &SK.style.elem[i];
RgbaColor strokeRgb = Style::Color(s->h, true);
int pattern = Style::PatternType(s->h);
double stippleScale = Style::StippleScaleMm(s->h);
fprintf(f, ".s%x {\r\n", s->h.v);
fprintf(f, "stroke:#%02x%02x%02x;\r\n", strokeRgb.red, strokeRgb.green, strokeRgb.blue);
// don't know why we have to take a half of the width
fprintf(f, "stroke-width:%f;\r\n", Style::WidthMm(s->h.v) / 2.0);
fprintf(f, "stroke-linecap:round;\r\n");
fprintf(f, "stroke-linejoin:round;\r\n");
std::string patternStr = MakeStipplePattern(pattern, stippleScale, ',',
/*inkscapeWorkaround=*/true);
if(!patternStr.empty()) {
fprintf(f, "stroke-dasharray:%s;\r\n", patternStr.c_str());
}
fprintf(f, "fill:none;\r\n");
fprintf(f, "}\r\n");
}
fprintf(f, "]]></style>\r\n");
} }
void SvgFileWriter::StartPath(RgbaColor strokeRgb, double lineWidth, void SvgFileWriter::StartPath(RgbaColor strokeRgb, double lineWidth,
@ -876,16 +914,11 @@ void SvgFileWriter::FinishPath(RgbaColor strokeRgb, double lineWidth,
{ {
std::string fill; std::string fill;
if(filled) { if(filled) {
fill = ssprintf("#%02x%02x%02x", fill = ssprintf("fill='#%02x%02x%02x'",
fillRgb.red, fillRgb.green, fillRgb.blue); fillRgb.red, fillRgb.green, fillRgb.blue);
} else {
fill = "none";
} }
fprintf(f, "' stroke-width='%.3f' stroke='#%02x%02x%02x' " std::string cls = ssprintf("s%x", style);
"stroke-linecap='round' stroke-linejoin='round' " fprintf(f, "' class='%s' %s/>\r\n", cls.c_str(), fill.c_str());
"fill='%s' />\r\n",
lineWidth, strokeRgb.red, strokeRgb.green, strokeRgb.blue,
fill.c_str());
} }
void SvgFileWriter::MaybeMoveTo(Vector st, Vector fi) { void SvgFileWriter::MaybeMoveTo(Vector st, Vector fi) {
@ -897,19 +930,14 @@ void SvgFileWriter::MaybeMoveTo(Vector st, Vector fi) {
} }
void SvgFileWriter::Triangle(STriangle *tr) { 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, fprintf(f,
"<polygon points='%.3f,%.3f %.3f,%.3f %.3f,%.3f' " "<polygon points='%.3f,%.3f %.3f,%.3f %.3f,%.3f' "
"stroke='#%02x%02x%02x' stroke-width='%.3f' " "stroke='#%02x%02x%02x' "
"style='fill:#%02x%02x%02x' shape-rendering='crispEdges'/>\r\n", "fill='#%02x%02x%02x'/>\r\n",
(tr->a.x - ptMin.x), (ptMax.y - tr->a.y), (tr->a.x - ptMin.x), (ptMax.y - tr->a.y),
(tr->b.x - ptMin.x), (ptMax.y - tr->b.y), (tr->b.x - ptMin.x), (ptMax.y - tr->b.y),
(tr->c.x - ptMin.x), (ptMax.y - tr->c.y), (tr->c.x - ptMin.x), (ptMax.y - tr->c.y),
tr->meta.color.red, tr->meta.color.green, tr->meta.color.blue, tr->meta.color.red, tr->meta.color.green, tr->meta.color.blue,
sw,
tr->meta.color.red, tr->meta.color.green, tr->meta.color.blue); tr->meta.color.red, tr->meta.color.green, tr->meta.color.blue);
} }