diff --git a/src/libslic3r/NSVGUtils.cpp b/src/libslic3r/NSVGUtils.cpp index 058d205380..7a989ed8e9 100644 --- a/src/libslic3r/NSVGUtils.cpp +++ b/src/libslic3r/NSVGUtils.cpp @@ -3,6 +3,10 @@ namespace { Slic3r::Polygons to_polygons(const NSVGshape &shape, float tessTol, int max_level, float scale, bool is_y_negative); + +// see function nsvg__lineTo(NSVGparser* p, float x, float y) +bool is_line(const float *p, float precision = 1e-4); + } // namespace namespace Slic3r { @@ -34,23 +38,102 @@ NSVGimage_ptr nsvgParseFromFile(const std::string &filename, const char *units, bool save(const NSVGimage &image, const std::string &svg_file_path) { - //BoundingBox bb = get_extents(to_polygons(image)); FILE * file = boost::nowide::fopen(svg_file_path.c_str(), "w"); if (file == NULL) return false; - fprintf(file, "\n"); + fprintf(file, ""); + + Vec2f tl(std::numeric_limits::max(), std::numeric_limits::max()); + Vec2f br(std::numeric_limits::min(), std::numeric_limits::min()); + for (const NSVGshape *shape = image.shapes; shape != NULL; shape = shape->next) + for (const NSVGpath *path = shape->paths; path != NULL; path = path->next) { + if (tl.x() > path->bounds[0]) + tl.x() = path->bounds[0]; + if (tl.y() > path->bounds[1]) + tl.y() = path->bounds[1]; + if (br.x() < path->bounds[2]) + br.x() = path->bounds[2]; + if (br.y() < path->bounds[3]) + br.y() = path->bounds[3]; + } + + tl.x() = std::floor(tl.x()); + tl.y() = std::floor(tl.y()); + + br.x() = std::ceil(br.x()); + br.y() = std::ceil(br.y()); + Vec2f s = br - tl; + + //// IMPROVE: use path bounds instead of BoundingBox + //BoundingBox bb = get_extents(to_polygons(image)); + //// bb has opposit value of y axe + //// Values stored in point are fixed point numbers need extend + //Point s = bb.size() + Point(2, 2); // extended size + //Point tl(bb.min.x() - 1, -bb.max.y() - 1); // top left corner + //Point br(tl.x() + s.x(), tl.y() + s.y()); // bottom right + + fprintf(file, "\n", + (int)s.x(), (int)s.y(), (int)tl.x(), (int)tl.y(), (int)br.x(), (int)br.y()); + fprintf(file, "\n"); + + auto write_point = [](std::string &d, const float *p) { + d += std::to_string(p[0]) + "," + std::to_string(p[1]) + " "; + }; + for (const NSVGshape *shape = image.shapes; shape != NULL; shape = shape->next) { + enum struct Type { move, line, curve, close }; // https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d + Type type = Type::move; std::string d = "M "; // move on start point for (const NSVGpath *path = shape->paths; path != NULL; path = path->next) { - size_t path_size = (path->npts > 1) ? static_cast(path->npts - 1) : 0; + if (path->npts <= 1) + continue; + + if (type == Type::close) { + Type type = Type::move; + // NOTE: After close must be a space + d += " M "; // move on start point + } + //write_point(d, path->pts); + d += std::to_string(path->pts[0]) + "," + std::to_string(path->pts[1]) + " "; + size_t path_size = static_cast(path->npts - 1); + + if (path->closed) { + // Do not use last point in path it is duplicit + if (path->npts <= 4) + continue; + path_size = static_cast(path->npts - 4); + } + for (size_t i = 0; i < path_size; i += 3) { const float *p = &path->pts[i * 2]; - d += std::to_string(p[0]) + "," + std::to_string(p[1]) + " "; + if (!::is_line(p)) { + if (type != Type::curve) { + type = Type::curve; + d += "C "; // start sequence of triplets defining curves + } + + d += std::to_string(p[2]) + "," + std::to_string(p[3]) + " " + + std::to_string(p[4]) + "," + std::to_string(p[5]) + " " ; + } else { + + if (type != Type::line) { + type = Type::line; + d += "L "; // start sequence of line points + } + } + d += std::to_string(p[6]) + "," + std::to_string(p[7]) + " "; + } + if (path->closed) { + type = Type::close; + d += "Z"; // start sequence of line points } } - d += "Z"; // closed path - fprintf(file, " \n", d.c_str()); + if (type != Type::close) { + type = Type::close; + d += "Z"; // closed path + } + fprintf(file, "\n", d.c_str()); } fprintf(file, "\n"); fclose(file); @@ -91,7 +174,7 @@ bool need_flattening(float tessTol, const Vec2f &p1, const Vec2f &p2, const Vec2 } // see function nsvg__lineTo(NSVGparser* p, float x, float y) -bool is_line(const float *p, float precision = 1e-4){ +bool is_line(const float *p, float precision){ //Vec2f p1(p[0], p[1]); //Vec2f p2(p[2], p[3]); //Vec2f p3(p[4], p[5]);