mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-09-17 15:03:13 +08:00
Import svg files by button in main bar.
Be carefull: import is made by main thread !!!
This commit is contained in:
parent
52e1ba0448
commit
f05f334e15
@ -146,6 +146,8 @@ set(SLIC3R_SOURCES
|
|||||||
Format/AnycubicSLA.cpp
|
Format/AnycubicSLA.cpp
|
||||||
Format/STEP.hpp
|
Format/STEP.hpp
|
||||||
Format/STEP.cpp
|
Format/STEP.cpp
|
||||||
|
Format/SVG.hpp
|
||||||
|
Format/SVG.cpp
|
||||||
Format/SLAArchiveFormatRegistry.hpp
|
Format/SLAArchiveFormatRegistry.hpp
|
||||||
Format/SLAArchiveFormatRegistry.cpp
|
Format/SLAArchiveFormatRegistry.cpp
|
||||||
GCode/ThumbnailData.cpp
|
GCode/ThumbnailData.cpp
|
||||||
|
102
src/libslic3r/Format/SVG.cpp
Normal file
102
src/libslic3r/Format/SVG.cpp
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
///|/ Copyright (c) Prusa Research 2017 - 2021 Enrico Turri @enricoturri1966, Vojtěch Bubník @bubnikv, Tomáš Mészáros @tamasmeszaros
|
||||||
|
///|/
|
||||||
|
///|/ ported from lib/Slic3r/Format/OBJ.pm:
|
||||||
|
///|/ Copyright (c) Prusa Research 2017 Vojtěch Bubník @bubnikv
|
||||||
|
///|/ Copyright (c) Slic3r 2012 - 2014 Alessandro Ranellucci @alranel
|
||||||
|
///|/
|
||||||
|
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
||||||
|
///|/
|
||||||
|
#include "../libslic3r.h"
|
||||||
|
#include "../Model.hpp"
|
||||||
|
#include "../TriangleMesh.hpp"
|
||||||
|
#include "../NSVGUtils.hpp"
|
||||||
|
#include "../Emboss.hpp"
|
||||||
|
|
||||||
|
#include <boost/log/trivial.hpp>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
std::string get_file_name(const std::string &file_path)
|
||||||
|
{
|
||||||
|
if (file_path.empty())
|
||||||
|
return file_path;
|
||||||
|
|
||||||
|
size_t pos_last_delimiter = file_path.find_last_of("/\\");
|
||||||
|
if (pos_last_delimiter == std::string::npos) {
|
||||||
|
// should not happend that in path is not delimiter
|
||||||
|
assert(false);
|
||||||
|
pos_last_delimiter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t pos_point = file_path.find_last_of('.');
|
||||||
|
if (pos_point == std::string::npos || pos_point < pos_last_delimiter // last point is inside of directory path
|
||||||
|
) {
|
||||||
|
// there is no extension
|
||||||
|
assert(false);
|
||||||
|
pos_point = file_path.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t offset = pos_last_delimiter + 1; // result should not contain last delimiter ( +1 )
|
||||||
|
size_t count = pos_point - pos_last_delimiter - 1; // result should not contain extension point ( -1 )
|
||||||
|
return file_path.substr(offset, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
bool load_svg(const std::string &input_file, Model &output_model)
|
||||||
|
{
|
||||||
|
EmbossShape::SvgFile svg_file{input_file};
|
||||||
|
NSVGimage* image = init_image(svg_file);
|
||||||
|
if (image == nullptr)
|
||||||
|
return false; // Can not load svg file
|
||||||
|
|
||||||
|
double tesselation_tolerance = 1e10;
|
||||||
|
NSVGLineParams params(tesselation_tolerance);
|
||||||
|
ExPolygonsWithIds shapes = create_shape_with_ids(*image, params);
|
||||||
|
if (shapes.empty())
|
||||||
|
return false; // No shapes in svg
|
||||||
|
|
||||||
|
double depth_in_mm = 10.; // in mm
|
||||||
|
bool use_surface = false;
|
||||||
|
EmbossProjection emboss_projection{depth_in_mm, use_surface};
|
||||||
|
|
||||||
|
EmbossShape emboss_shape;
|
||||||
|
emboss_shape.shapes_with_ids = std::move(shapes);
|
||||||
|
emboss_shape.projection = std::move(emboss_projection);
|
||||||
|
emboss_shape.svg_file = std::move(svg_file);
|
||||||
|
|
||||||
|
// unify to one expolygons
|
||||||
|
double delta = 1e-3; // in mm
|
||||||
|
unsigned max_heal_iteration = 10;
|
||||||
|
HealedExPolygons union_shape = union_with_delta(emboss_shape.shapes_with_ids, delta, max_heal_iteration);
|
||||||
|
if (!union_shape.is_healed)
|
||||||
|
return false; // Can not heal union shape
|
||||||
|
|
||||||
|
// create projection
|
||||||
|
double scale = emboss_shape.scale;
|
||||||
|
double depth = emboss_shape.projection.depth / scale;
|
||||||
|
auto projectZ = std::make_unique<Emboss::ProjectZ>(depth);
|
||||||
|
Transform3d tr{Eigen::Scaling(scale)};
|
||||||
|
Emboss::ProjectTransform project(std::move(projectZ), tr);
|
||||||
|
|
||||||
|
// convert 2d shape to 3d triangles
|
||||||
|
indexed_triangle_set its = Emboss::polygons2model(union_shape.expolygons, project);
|
||||||
|
TriangleMesh triangl_mesh(std::move(its));
|
||||||
|
|
||||||
|
// add mesh to model
|
||||||
|
ModelObject *object = output_model.add_object();
|
||||||
|
if (object == nullptr)
|
||||||
|
return false;
|
||||||
|
object->name = get_file_name(input_file);
|
||||||
|
ModelVolume* volume = object->add_volume(std::move(triangl_mesh));
|
||||||
|
if (volume == nullptr) {
|
||||||
|
output_model.delete_object(object);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
volume->name = object->name; // copy
|
||||||
|
volume->emboss_shape = std::move(emboss_shape);
|
||||||
|
object->invalidate_bounding_box();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}; // namespace Slic3r
|
17
src/libslic3r/Format/SVG.hpp
Normal file
17
src/libslic3r/Format/SVG.hpp
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
///|/ Copyright (c) Prusa Research 2023 - 2023
|
||||||
|
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
||||||
|
///|/
|
||||||
|
#ifndef slic3r_Format_SVG_hpp_
|
||||||
|
#define slic3r_Format_SVG_hpp_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
class Model;
|
||||||
|
// Load an SVG file as embossed shape into a provided model.
|
||||||
|
bool load_svg(const std::string &input_file, Model &output_model);
|
||||||
|
|
||||||
|
}; // namespace Slic3r
|
||||||
|
|
||||||
|
#endif /* slic3r_Format_SVG_hpp_ */
|
@ -27,6 +27,7 @@
|
|||||||
#include "Format/STL.hpp"
|
#include "Format/STL.hpp"
|
||||||
#include "Format/3mf.hpp"
|
#include "Format/3mf.hpp"
|
||||||
#include "Format/STEP.hpp"
|
#include "Format/STEP.hpp"
|
||||||
|
#include "Format/SVG.hpp"
|
||||||
|
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
|
|
||||||
@ -137,8 +138,10 @@ Model Model::read_from_file(const std::string& input_file, DynamicPrintConfig* c
|
|||||||
else if (boost::algorithm::iends_with(input_file, ".3mf") || boost::algorithm::iends_with(input_file, ".zip"))
|
else if (boost::algorithm::iends_with(input_file, ".3mf") || boost::algorithm::iends_with(input_file, ".zip"))
|
||||||
//FIXME options & LoadAttribute::CheckVersion ?
|
//FIXME options & LoadAttribute::CheckVersion ?
|
||||||
result = load_3mf(input_file.c_str(), *config, *config_substitutions, &model, false);
|
result = load_3mf(input_file.c_str(), *config, *config_substitutions, &model, false);
|
||||||
|
else if (boost::algorithm::iends_with(input_file, ".svg"))
|
||||||
|
result = load_svg(input_file, model);
|
||||||
else
|
else
|
||||||
throw Slic3r::RuntimeError("Unknown file format. Input file must have .stl, .obj, .amf(.xml), .prusa or .step/.stp extension.");
|
throw Slic3r::RuntimeError("Unknown file format. Input file must have .stl, .obj, .step/.stp, .svg, .amf(.xml) or extension .3mf(.zip).");
|
||||||
|
|
||||||
if (! result)
|
if (! result)
|
||||||
throw Slic3r::RuntimeError("Loading of a model file failed.");
|
throw Slic3r::RuntimeError("Loading of a model file failed.");
|
||||||
@ -2315,6 +2318,19 @@ void check_model_ids_equal(const Model &model1, const Model &model2)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "NSVGUtils.hpp"
|
||||||
|
namespace {
|
||||||
|
using namespace Slic3r;
|
||||||
|
|
||||||
|
bool load_svg(const std::string &input_file, Model &output_model)
|
||||||
|
{
|
||||||
|
NSVGimage_ptr nsvg_image_ptr = nsvgParseFromFile(input_file);
|
||||||
|
double tesselation_tolerance = 1e-4;
|
||||||
|
NSVGLineParams params(tesselation_tolerance);
|
||||||
|
ExPolygonsWithIds shapes = create_shape_with_ids(*nsvg_image_ptr, params);
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
CEREAL_REGISTER_TYPE(Slic3r::ModelObject)
|
CEREAL_REGISTER_TYPE(Slic3r::ModelObject)
|
||||||
CEREAL_REGISTER_TYPE(Slic3r::ModelVolume)
|
CEREAL_REGISTER_TYPE(Slic3r::ModelVolume)
|
||||||
|
@ -120,6 +120,28 @@ NSVGimage_ptr nsvgParse(const std::string& file_data, const char *units, float d
|
|||||||
return {image, &nsvgDelete};
|
return {image, &nsvgDelete};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NSVGimage *init_image(EmbossShape::SvgFile &svg_file){
|
||||||
|
// is already initialized?
|
||||||
|
if (svg_file.image.get() != nullptr)
|
||||||
|
return svg_file.image.get();
|
||||||
|
|
||||||
|
if (svg_file.file_data == nullptr) {
|
||||||
|
// chech if path is known
|
||||||
|
if (svg_file.path.empty())
|
||||||
|
return nullptr;
|
||||||
|
svg_file.file_data = read_from_disk(svg_file.path);
|
||||||
|
if (svg_file.file_data == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// init svg image
|
||||||
|
svg_file.image = nsvgParse(*svg_file.file_data);
|
||||||
|
if (svg_file.image.get() == NULL)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return svg_file.image.get();
|
||||||
|
}
|
||||||
|
|
||||||
size_t get_shapes_count(const NSVGimage &image)
|
size_t get_shapes_count(const NSVGimage &image)
|
||||||
{
|
{
|
||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
|
@ -71,6 +71,7 @@ std::unique_ptr<std::string> read_from_disk(const std::string &path);
|
|||||||
using NSVGimage_ptr = std::unique_ptr<NSVGimage, void (*)(NSVGimage*)>;
|
using NSVGimage_ptr = std::unique_ptr<NSVGimage, void (*)(NSVGimage*)>;
|
||||||
NSVGimage_ptr nsvgParseFromFile(const std::string &svg_file_path, const char *units = "mm", float dpi = 96.0f);
|
NSVGimage_ptr nsvgParseFromFile(const std::string &svg_file_path, const char *units = "mm", float dpi = 96.0f);
|
||||||
NSVGimage_ptr nsvgParse(const std::string& file_data, const char *units = "mm", float dpi = 96.0f);
|
NSVGimage_ptr nsvgParse(const std::string& file_data, const char *units = "mm", float dpi = 96.0f);
|
||||||
|
NSVGimage *init_image(EmbossShape::SvgFile &svg_file);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Iterate over shapes and calculate count
|
/// Iterate over shapes and calculate count
|
||||||
|
@ -489,7 +489,7 @@ static const FileWildcards file_wildcards_by_type[FT_SIZE] = {
|
|||||||
/* FT_AMF */ { "AMF files"sv, { ".amf"sv, ".zip.amf"sv, ".xml"sv } },
|
/* FT_AMF */ { "AMF files"sv, { ".amf"sv, ".zip.amf"sv, ".xml"sv } },
|
||||||
/* FT_3MF */ { "3MF files"sv, { ".3mf"sv } },
|
/* FT_3MF */ { "3MF files"sv, { ".3mf"sv } },
|
||||||
/* FT_GCODE */ { "G-code files"sv, { ".gcode"sv, ".gco"sv, ".bgcode"sv, ".bgc"sv, ".g"sv, ".ngc"sv } },
|
/* FT_GCODE */ { "G-code files"sv, { ".gcode"sv, ".gco"sv, ".bgcode"sv, ".bgc"sv, ".g"sv, ".ngc"sv } },
|
||||||
/* FT_MODEL */ { "Known files"sv, { ".stl"sv, ".obj"sv, ".3mf"sv, ".amf"sv, ".zip.amf"sv, ".xml"sv, ".step"sv, ".stp"sv } },
|
/* FT_MODEL */ { "Known files"sv, { ".stl"sv, ".obj"sv, ".3mf"sv, ".amf"sv, ".zip.amf"sv, ".xml"sv, ".step"sv, ".stp"sv, ".svg"sv } },
|
||||||
/* FT_PROJECT */ { "Project files"sv, { ".3mf"sv, ".amf"sv, ".zip.amf"sv } },
|
/* FT_PROJECT */ { "Project files"sv, { ".3mf"sv, ".amf"sv, ".zip.amf"sv } },
|
||||||
/* FT_FONTS */ { "Font files"sv, { ".ttc"sv, ".ttf"sv } },
|
/* FT_FONTS */ { "Font files"sv, { ".ttc"sv, ".ttf"sv } },
|
||||||
/* FT_GALLERY */ { "Known files"sv, { ".stl"sv, ".obj"sv } },
|
/* FT_GALLERY */ { "Known files"sv, { ".stl"sv, ".obj"sv } },
|
||||||
|
@ -588,32 +588,6 @@ void GLGizmoSVG::on_dragging(const UpdateData &data) { m_rotate_gizmo.dragging(d
|
|||||||
#include "libslic3r/AABBTreeLines.hpp" // aabb lines for draw filled expolygon
|
#include "libslic3r/AABBTreeLines.hpp" // aabb lines for draw filled expolygon
|
||||||
|
|
||||||
namespace{
|
namespace{
|
||||||
NSVGimage* init_image(EmbossShape::SvgFile &svg_file) {
|
|
||||||
// is already initialized?
|
|
||||||
if (svg_file.image.get() != nullptr)
|
|
||||||
return svg_file.image.get();
|
|
||||||
|
|
||||||
|
|
||||||
if (svg_file.file_data == nullptr){
|
|
||||||
// chech if path is known
|
|
||||||
if (svg_file.path.empty())
|
|
||||||
return nullptr;
|
|
||||||
svg_file.file_data = read_from_disk(svg_file.path);
|
|
||||||
if (svg_file.file_data == nullptr)
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// init svg image
|
|
||||||
svg_file.image = nsvgParse(*svg_file.file_data);
|
|
||||||
if (svg_file.image.get() == NULL)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
// Disable stroke
|
|
||||||
//for (NSVGshape *shape = svg_file.image->shapes; shape != NULL; shape = shape->next)
|
|
||||||
// shape->stroke.type = 0;
|
|
||||||
|
|
||||||
return svg_file.image.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
// inspired by Xiaolin Wu's line algorithm - https://en.wikipedia.org/wiki/Xiaolin_Wu's_line_algorithm
|
// inspired by Xiaolin Wu's line algorithm - https://en.wikipedia.org/wiki/Xiaolin_Wu's_line_algorithm
|
||||||
// Draw inner part of polygon CCW line as full brightness(edge of expolygon)
|
// Draw inner part of polygon CCW line as full brightness(edge of expolygon)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user