diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index 79e9ae2598..f10ca13148 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -1640,7 +1640,7 @@ sub selection_changed { $self->{object_info_size}->SetLabel(sprintf("%.2f x %.2f x %.2f", @{$model_object->instance_bounding_box(0)->size})); $self->{object_info_materials}->SetLabel($model_object->materials_count); - if (my $stats = $model_object->mesh_stats) { + if (my $stats = $model_object->raw_mesh->stats) { $self->{object_info_volume}->SetLabel(sprintf('%.2f', $stats->{volume} * ($model_instance->scaling_factor**3))); $self->{object_info_facets}->SetLabel(sprintf('%d (%d shells)', $model_object->facets_count, $stats->{number_of_parts})); if (my $errors = sum(@$stats{qw(degenerate_facets edges_fixed facets_removed facets_added facets_reversed backwards_edges)})) { diff --git a/lib/Slic3r/Model.pm b/lib/Slic3r/Model.pm index 057c1f7fee..01797316b0 100644 --- a/lib/Slic3r/Model.pm +++ b/lib/Slic3r/Model.pm @@ -67,11 +67,6 @@ sub set_material { return $material; } -sub print_info { - my $self = shift; - $_->print_info for @{$self->objects}; -} - sub looks_like_multipart_object { my ($self) = @_; @@ -182,36 +177,4 @@ sub add_instance { } } -sub mesh_stats { - my $self = shift; - - # TODO: sum values from all volumes - return $self->volumes->[0]->mesh->stats; -} - -sub print_info { - my $self = shift; - - printf "Info about %s:\n", basename($self->input_file); - printf " size: x=%.3f y=%.3f z=%.3f\n", @{$self->raw_mesh->bounding_box->size}; - if (my $stats = $self->mesh_stats) { - printf " number of facets: %d\n", $stats->{number_of_facets}; - printf " number of shells: %d\n", $stats->{number_of_parts}; - printf " volume: %.3f\n", $stats->{volume}; - if ($self->needed_repair) { - printf " needed repair: yes\n"; - printf " degenerate facets: %d\n", $stats->{degenerate_facets}; - printf " edges fixed: %d\n", $stats->{edges_fixed}; - printf " facets removed: %d\n", $stats->{facets_removed}; - printf " facets added: %d\n", $stats->{facets_added}; - printf " facets reversed: %d\n", $stats->{facets_reversed}; - printf " backwards edges: %d\n", $stats->{backwards_edges}; - } else { - printf " needed repair: no\n"; - } - } else { - printf " number of facets: %d\n", scalar(map @{$_->facets}, grep !$_->modifier, @{$self->volumes}); - } -} - 1; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000000..acd711e772 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,111 @@ +cmake_minimum_required (VERSION 2.8) +project (slic3r) + +# only on newer GCCs: -ftemplate-backtrace-limit=0 +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSLIC3R_DEBUG") + +set(workaround "") +if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.7.0) + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.7.3) + set(workaround "-fno-inline-small-functions") + endif(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.7.3) +endif(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.7.0) + +set(CMAKE_CXX_FLAGS "-DM_PI=3.14159265358979323846 -D_GLIBCXX_USE_C99 -DHAS_BOOL -DNOGDI -DBOOST_ASIO_DISABLE_KQUEUE ${workaround}") +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +IF(CMAKE_HOST_APPLE) + set(CMAKE_EXE_LINKER_FLAGS "-framework IOKit -framework CoreFoundation") +ELSE(CMAKE_HOST_APPLE) + set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++") +ENDIF(CMAKE_HOST_APPLE) +set(Boost_USE_STATIC_LIBS ON) +set(Boost_USE_STATIC_RUNTIME ON) +set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") +find_package(Boost COMPONENTS system thread filesystem) + +set(LIBDIR ${CMAKE_CURRENT_SOURCE_DIR}/../xs/src/) + +include_directories(${LIBDIR}) +include_directories(${LIBDIR}/libslic3r) +include_directories(${LIBDIR}/Slic3r/GUI/) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/standalone/) +include_directories(${LIBDIR}/admesh/) +include_directories(${LIBDIR}/poly2tri/) +include_directories(${LIBDIR}/poly2tri/sweep) +include_directories(${LIBDIR}/poly2tri/common) +add_library(libslic3r STATIC ${LIBDIR}/libslic3r/BoundingBox.cpp + ${LIBDIR}/libslic3r/ExPolygon.cpp + ${LIBDIR}/libslic3r/GCode.cpp + ${LIBDIR}/libslic3r/LayerRegion.cpp + ${LIBDIR}/libslic3r/PerimeterGenerator.cpp + ${LIBDIR}/libslic3r/Polyline.cpp + ${LIBDIR}/libslic3r/SurfaceCollection.cpp + ${LIBDIR}/libslic3r/BridgeDetector.cpp + ${LIBDIR}/libslic3r/Extruder.cpp + ${LIBDIR}/libslic3r/GCodeSender.cpp + ${LIBDIR}/libslic3r/IO.cpp + ${LIBDIR}/libslic3r/Line.cpp + ${LIBDIR}/libslic3r/PlaceholderParser.cpp + ${LIBDIR}/libslic3r/PrintConfig.cpp + ${LIBDIR}/libslic3r/Surface.cpp + ${LIBDIR}/libslic3r/ClipperUtils.cpp + ${LIBDIR}/libslic3r/ExtrusionEntityCollection.cpp + ${LIBDIR}/libslic3r/GCodeWriter.cpp + ${LIBDIR}/libslic3r/Model.cpp + ${LIBDIR}/libslic3r/Point.cpp + ${LIBDIR}/libslic3r/Print.cpp + ${LIBDIR}/libslic3r/SVG.cpp + ${LIBDIR}/libslic3r/SVGExport.cpp + ${LIBDIR}/libslic3r/Config.cpp + ${LIBDIR}/libslic3r/ExtrusionEntity.cpp + ${LIBDIR}/libslic3r/Geometry.cpp + ${LIBDIR}/libslic3r/MotionPlanner.cpp + ${LIBDIR}/libslic3r/Polygon.cpp + ${LIBDIR}/libslic3r/PrintObject.cpp + ${LIBDIR}/libslic3r/TriangleMesh.cpp + ${LIBDIR}/libslic3r/ExPolygonCollection.cpp + ${LIBDIR}/libslic3r/Flow.cpp + ${LIBDIR}/libslic3r/Layer.cpp + ${LIBDIR}/libslic3r/MultiPoint.cpp + ${LIBDIR}/libslic3r/PolylineCollection.cpp + ${LIBDIR}/libslic3r/PrintRegion.cpp) +add_library(admesh STATIC ${LIBDIR}/admesh/util.c ${LIBDIR}/admesh/stl_io.c ${LIBDIR}/admesh/stlinit.c ${LIBDIR}/admesh/shared.c ${LIBDIR}/admesh/normals.c ${LIBDIR}/admesh/connect.c) +add_library(clipper STATIC ${LIBDIR}/clipper.cpp) +add_library(polypartition STATIC ${LIBDIR}/polypartition.cpp) +add_library(poly2tri STATIC ${LIBDIR}/poly2tri/sweep/sweep.cc ${LIBDIR}/poly2tri/sweep/sweep_context.cc ${LIBDIR}/poly2tri/sweep/cdt.cc ${LIBDIR}/poly2tri/sweep/advancing_front.cc ${LIBDIR}/poly2tri/common/shapes.cc) +add_executable(slic3r slic3r.cpp) +set_target_properties(slic3r PROPERTIES LINK_SEARCH_START_STATIC 1) +set_target_properties(slic3r PROPERTIES LINK_SEARCH_END_STATIC 1) +set(wxWidgets_USE_STATIC) +SET(wxWidgets_USE_LIBS) + +set(Boost_USE_STATIC_LIBS ON) +set(Boost_USE_STATIC_RUNTIME ON) +set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") +find_library(bsystem_l boost_system) +add_library(bsystem STATIC IMPORTED) +set_target_properties(bsystem PROPERTIES IMPORTED_LOCATION ${bsystem_l}) +find_library(bthread_l boost_thread) +add_library(bthread STATIC IMPORTED) +set_target_properties(bthread PROPERTIES IMPORTED_LOCATION ${bthread_l}) +include_directories(${Boost_INCLUDE_DIRS}) + +#find_package(wxWidgets) +#disable wx for the time being - we're not building any of the gui yet +IF(CMAKE_HOST_UNIX) + #set(Boost_LIBRARIES bsystem bthread bfilesystem) +ENDIF(CMAKE_HOST_UNIX) +IF(wxWidgets_FOUND) + MESSAGE("wx found!") + INCLUDE("${wxWidgets_USE_FILE}") + add_library(slic3r_gui STATIC ${LIBDIR}/slic3r/GUI/3DScene.cpp ${LIBDIR}/slic3r/GUI/GUI.cpp) + #only build GUI lib if building with wx + target_link_libraries (slic3r slic3r_gui libslic3r admesh clipper polypartition poly2tri ${Boost_LIBRARIES} ${wxWidgets_LIBRARIES}) +ELSE(wxWidgets_FOUND) + # For convenience. When we cannot continue, inform the user + MESSAGE("wx not found!") + target_link_libraries (slic3r libslic3r admesh clipper polypartition poly2tri ${Boost_LIBRARIES}) + #skip gui when no wx included +ENDIF(wxWidgets_FOUND) + diff --git a/src/slic3r.cpp b/src/slic3r.cpp new file mode 100644 index 0000000000..ac888deebe --- /dev/null +++ b/src/slic3r.cpp @@ -0,0 +1,95 @@ +#include "Config.hpp" +#include "Model.hpp" +#include "IO.hpp" +#include "TriangleMesh.hpp" +#include "SVGExport.hpp" +#include "libslic3r.h" +#include +#include +#include +#include + +using namespace Slic3r; + +void confess_at(const char *file, int line, const char *func, const char *pat, ...){} + +int +main(const int argc, const char **argv) +{ + // parse all command line options into a DynamicConfig + ConfigDef config_def; + config_def.merge(cli_config_def); + config_def.merge(print_config_def); + DynamicConfig config(&config_def); + t_config_option_keys input_files; + config.read_cli(argc, argv, &input_files); + + // apply command line options to a more specific DynamicPrintConfig which provides normalize() + DynamicPrintConfig print_config; + print_config.apply(config, true); + print_config.normalize(); + + // apply command line options to a more handy CLIConfig + CLIConfig cli_config; + cli_config.apply(config, true); + + /* TODO: loop through the config files supplied on the command line (now stored in + cli_config), load each one, normalize it and apply it to print_config */ + + // read input file(s) if any + std::vector models; + for (t_config_option_keys::const_iterator it = input_files.begin(); it != input_files.end(); ++it) { + Model model; + // TODO: read other file formats with Model::read_from_file() + Slic3r::IO::STL::read(*it, &model); + + if (model.objects.empty()) { + printf("Error: file is empty: %s\n", it->c_str()); + continue; + } + + model.add_default_instances(); + + // apply command line transform options + for (ModelObjectPtrs::iterator o = model.objects.begin(); o != model.objects.end(); ++o) { + (*o)->scale(cli_config.scale.value); + (*o)->rotate(cli_config.rotate.value, Z); + } + + // TODO: handle --merge + models.push_back(model); + } + + for (std::vector::iterator model = models.begin(); model != models.end(); ++model) { + if (cli_config.info) { + model->print_info(); + } else if (cli_config.export_obj) { + std::string outfile = cli_config.output.value; + if (outfile.empty()) outfile = model->objects.front()->input_file + ".obj"; + + TriangleMesh mesh = model->mesh(); + Slic3r::IO::OBJ::write(mesh, outfile); + printf("File exported to %s\n", outfile.c_str()); + } else if (cli_config.export_pov) { + std::string outfile = cli_config.output.value; + if (outfile.empty()) outfile = model->objects.front()->input_file + ".pov"; + + TriangleMesh mesh = model->mesh(); + Slic3r::IO::POV::write(mesh, outfile); + printf("File exported to %s\n", outfile.c_str()); + } else if (cli_config.export_svg) { + std::string outfile = cli_config.output.value; + if (outfile.empty()) outfile = model->objects.front()->input_file + ".svg"; + + SVGExport svg_export(model->mesh()); + svg_export.config.apply(print_config, true); + svg_export.writeSVG(outfile); + printf("SVG file exported to %s\n", outfile.c_str()); + } else { + std::cerr << "error: only --export-svg and --export-obj are currently supported" << std::endl; + return 1; + } + } + + return 0; +} diff --git a/src/standalone/config.h b/src/standalone/config.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/windows-build.txt b/src/windows-build.txt new file mode 100644 index 0000000000..e2a4aa23cd --- /dev/null +++ b/src/windows-build.txt @@ -0,0 +1,40 @@ +Install: +mingw +boost +cmake +git + +Assuming boost is in c:\program files\boost\boost_1_61_0 and mingw is in c:\mingw + +start cmd.exe +> cd c:\program files\boost\boost_1_61_0 +> set PATH=c:\mingw\bin +> bootstrap gcc +> .\b2 --build-dir=c:\boost-mingw toolset=gcc link=static runtime-link=static variant=release --with-system --with-thread +leave cmd window open + +start git bash +> cd /c +> git clone http://github.com/alexrj/slic3r +> cd slic3r +> git checkout cppsvg +close git bash when done + +make sure c:\mingw\bin is part of the Path system variable, add it otherwise + +start cmake gui +source code: c:\slic3r\src +build directory: c:\slic3r\build +click configure, select "mingw makefiles" from list, select "default native compilers", click finish +click generate +close cmake gui + +alternatively, do it from command line: +cmake ..\src -G "MinGW Makefiles" -DBOOST_ROOT="c:\program files\boost\boost_1_61_0" +(in case cmake can't find the libs, -DBoost_DEBUG=1 and -DBoost_COMPILER=-mgw46 are useful) + +go back to cmd window +> cd c:\slic3r\build +> mingw32-make.exe +might be mingw64 on 64-bit setup, I'm not sure +The resulting slic3r.exe is the target executable, it has no dependencies except windows system libraries (kernel32 and msvcrt) diff --git a/xs/Build.PL b/xs/Build.PL index 6145777c7b..8a111c1a44 100644 --- a/xs/Build.PL +++ b/xs/Build.PL @@ -47,7 +47,7 @@ if (defined $ENV{BOOST_DIR}) { # In order to generate the -l switches we need to know how Boost libraries are named my $have_boost = 0; -my @boost_libraries = qw(system thread); # we need these +my @boost_libraries = qw(system thread filesystem); # we need these # check without explicit lib path (works on Linux) $have_boost = 1 diff --git a/xs/src/libslic3r/ClipperUtils.cpp b/xs/src/libslic3r/ClipperUtils.cpp index aea0ef5959..3490118ee3 100644 --- a/xs/src/libslic3r/ClipperUtils.cpp +++ b/xs/src/libslic3r/ClipperUtils.cpp @@ -222,6 +222,18 @@ offset_ex(const Slic3r::Polygons &polygons, const float delta, return expp; } +Slic3r::ExPolygons +offset_ex(const Slic3r::ExPolygons &expolygons, const float delta, + double scale, ClipperLib::JoinType joinType, double miterLimit) +{ + Slic3r::Polygons pp; + for (Slic3r::ExPolygons::const_iterator ex = expolygons.begin(); ex != expolygons.end(); ++ex) { + Slic3r::Polygons pp2 = *ex; + pp.insert(pp.end(), pp2.begin(), pp2.end()); + } + return offset_ex(pp, delta, scale, joinType, miterLimit); +} + void offset2(const Slic3r::Polygons &polygons, ClipperLib::Paths* retval, const float delta1, const float delta2, const double scale, const ClipperLib::JoinType joinType, const double miterLimit) diff --git a/xs/src/libslic3r/ClipperUtils.hpp b/xs/src/libslic3r/ClipperUtils.hpp index f3ab6158e4..4bc5ceb89a 100644 --- a/xs/src/libslic3r/ClipperUtils.hpp +++ b/xs/src/libslic3r/ClipperUtils.hpp @@ -61,6 +61,9 @@ void offset(const Slic3r::Polygons &polygons, Slic3r::ExPolygons* retval, const Slic3r::ExPolygons offset_ex(const Slic3r::Polygons &polygons, const float delta, double scale = 100000, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3); +Slic3r::ExPolygons offset_ex(const Slic3r::ExPolygons &expolygons, const float delta, + double scale = 100000, ClipperLib::JoinType joinType = ClipperLib::jtMiter, + double miterLimit = 3); void offset2(const Slic3r::Polygons &polygons, ClipperLib::Paths* retval, const float delta1, const float delta2, double scale = 100000, ClipperLib::JoinType joinType = ClipperLib::jtMiter, diff --git a/xs/src/libslic3r/Config.cpp b/xs/src/libslic3r/Config.cpp index 9194548c77..778c984ed8 100644 --- a/xs/src/libslic3r/Config.cpp +++ b/xs/src/libslic3r/Config.cpp @@ -1,6 +1,8 @@ #include "Config.hpp" #include // for setenv() #include +#include +#include #if defined(_WIN32) && !defined(setenv) && defined(_putenv_s) #define setenv(k, v, o) _putenv_s(k, v) @@ -20,12 +22,22 @@ operator!= (const ConfigOption &a, const ConfigOption &b) return !(a == b); } -ConfigDef::~ConfigDef() +ConfigOptionDef::ConfigOptionDef(const ConfigOptionDef &other) + : type(other.type), default_value(NULL), + gui_type(other.gui_type), gui_flags(other.gui_flags), label(other.label), + full_label(other.full_label), category(other.category), tooltip(other.tooltip), + sidetext(other.sidetext), cli(other.cli), ratio_over(other.ratio_over), + multiline(other.multiline), full_width(other.full_width), readonly(other.readonly), + height(other.height), width(other.width), min(other.min), max(other.max) { - for (t_optiondef_map::iterator it = this->options.begin(); it != this->options.end(); ++it) { - if (it->second.default_value != NULL) - delete it->second.default_value; - } + if (other.default_value != NULL) + this->default_value = other.default_value->clone(); +} + +ConfigOptionDef::~ConfigOptionDef() +{ + if (this->default_value != NULL) + delete this->default_value; } ConfigOptionDef* @@ -43,6 +55,12 @@ ConfigDef::get(const t_config_option_key &opt_key) const return &const_cast(this)->options[opt_key]; } +void +ConfigDef::merge(const ConfigDef &other) +{ + this->options.insert(other.options.begin(), other.options.end()); +} + bool ConfigBase::has(const t_config_option_key &opt_key) { return (this->option(opt_key, false) != NULL); @@ -200,7 +218,7 @@ DynamicConfig::optptr(const t_config_option_key &opt_key, bool create) { if (this->options.count(opt_key) == 0) { if (create) { const ConfigOptionDef* optdef = this->def->get(opt_key); - assert(optdef != NULL); + if (optdef == NULL) return NULL; ConfigOption* opt; if (optdef->type == coFloat) { opt = new ConfigOptionFloat (); @@ -265,6 +283,58 @@ DynamicConfig::erase(const t_config_option_key &opt_key) { this->options.erase(opt_key); } +void +DynamicConfig::read_cli(const int argc, const char** argv, t_config_option_keys* extra) +{ + bool parse_options = true; + for (int i = 1; i < argc; ++i) { + std::string token = argv[i]; + + if (token == "--") { + // stop parsing tokens as options + parse_options = false; + } else if (parse_options && boost::starts_with(token, "--")) { + boost::algorithm::erase_head(token, 2); + // TODO: handle --key=value + + // look for the option def + t_config_option_key opt_key; + const ConfigOptionDef* optdef; + for (t_optiondef_map::const_iterator oit = this->def->options.begin(); + oit != this->def->options.end(); ++oit) { + optdef = &oit->second; + + if (optdef->cli == token + || optdef->cli == token + '!' + || boost::starts_with(optdef->cli, token + "=")) { + opt_key = oit->first; + break; + } + } + + if (opt_key.empty()) { + printf("Warning: unknown option --%s\n", token.c_str()); + continue; + } + + if (ConfigOptionBool* opt = this->opt(opt_key, true)) { + opt->value = !boost::starts_with(token, "no-"); + } else if (ConfigOptionBools* opt = this->opt(opt_key, true)) { + opt->values.push_back(!boost::starts_with(token, "no-")); + } else { + // we expect one more token carrying the value + if (i == argc) { + printf("No value supplied for --%s\n", token.c_str()); + exit(1); + } + this->option(opt_key, true)->deserialize(argv[++i]); + } + } else { + extra->push_back(token); + } + } +} + void StaticConfig::set_defaults() { diff --git a/xs/src/libslic3r/Config.hpp b/xs/src/libslic3r/Config.hpp index 99cc02fb0c..a8a54baa19 100644 --- a/xs/src/libslic3r/Config.hpp +++ b/xs/src/libslic3r/Config.hpp @@ -20,6 +20,7 @@ typedef std::vector t_config_option_keys; class ConfigOption { public: virtual ~ConfigOption() {}; + virtual ConfigOption* clone() const = 0; virtual std::string serialize() const = 0; virtual bool deserialize(std::string str) = 0; virtual void set(const ConfigOption &option) = 0; @@ -54,8 +55,10 @@ template class ConfigOptionVector : public ConfigOptionVectorBase { public: - virtual ~ConfigOptionVector() {}; std::vector values; + ConfigOptionVector() {}; + ConfigOptionVector(const std::vector _values) : values(_values) {}; + virtual ~ConfigOptionVector() {}; void set(const ConfigOption &option) { const ConfigOptionVector* other = dynamic_cast< const ConfigOptionVector* >(&option); @@ -76,6 +79,7 @@ class ConfigOptionFloat : public ConfigOptionSingle public: ConfigOptionFloat() : ConfigOptionSingle(0) {}; ConfigOptionFloat(double _value) : ConfigOptionSingle(_value) {}; + ConfigOptionFloat* clone() const { return new ConfigOptionFloat(this->value); }; double getFloat() const { return this->value; }; @@ -95,6 +99,9 @@ class ConfigOptionFloat : public ConfigOptionSingle class ConfigOptionFloats : public ConfigOptionVector { public: + ConfigOptionFloats() {}; + ConfigOptionFloats(const std::vector _values) : ConfigOptionVector(_values) {}; + ConfigOptionFloats* clone() const { return new ConfigOptionFloats(this->values); }; std::string serialize() const { std::ostringstream ss; @@ -134,6 +141,7 @@ class ConfigOptionInt : public ConfigOptionSingle public: ConfigOptionInt() : ConfigOptionSingle(0) {}; ConfigOptionInt(double _value) : ConfigOptionSingle(_value) {}; + ConfigOptionInt* clone() const { return new ConfigOptionInt(this->value); }; int getInt() const { return this->value; }; void setInt(int val) { this->value = val; }; @@ -154,6 +162,9 @@ class ConfigOptionInt : public ConfigOptionSingle class ConfigOptionInts : public ConfigOptionVector { public: + ConfigOptionInts() {}; + ConfigOptionInts(const std::vector _values) : ConfigOptionVector(_values) {}; + ConfigOptionInts* clone() const { return new ConfigOptionInts(this->values); }; std::string serialize() const { std::ostringstream ss; @@ -193,6 +204,7 @@ class ConfigOptionString : public ConfigOptionSingle public: ConfigOptionString() : ConfigOptionSingle("") {}; ConfigOptionString(std::string _value) : ConfigOptionSingle(_value) {}; + ConfigOptionString* clone() const { return new ConfigOptionString(this->value); }; std::string serialize() const { std::string str = this->value; @@ -224,6 +236,9 @@ class ConfigOptionString : public ConfigOptionSingle class ConfigOptionStrings : public ConfigOptionVector { public: + ConfigOptionStrings() {}; + ConfigOptionStrings(const std::vector _values) : ConfigOptionVector(_values) {}; + ConfigOptionStrings* clone() const { return new ConfigOptionStrings(this->values); }; std::string serialize() const { std::ostringstream ss; @@ -254,6 +269,7 @@ class ConfigOptionPercent : public ConfigOptionFloat public: ConfigOptionPercent() : ConfigOptionFloat(0) {}; ConfigOptionPercent(double _value) : ConfigOptionFloat(_value) {}; + ConfigOptionPercent* clone() const { return new ConfigOptionPercent(this->value); }; double get_abs_value(double ratio_over) const { return ratio_over * this->value / 100; @@ -282,6 +298,7 @@ class ConfigOptionFloatOrPercent : public ConfigOptionPercent ConfigOptionFloatOrPercent() : ConfigOptionPercent(0), percent(false) {}; ConfigOptionFloatOrPercent(double _value, bool _percent) : ConfigOptionPercent(_value), percent(_percent) {}; + ConfigOptionFloatOrPercent* clone() const { return new ConfigOptionFloatOrPercent(this->value, this->percent); }; void set(const ConfigOption &option) { const ConfigOptionFloatOrPercent* other = dynamic_cast< const ConfigOptionFloatOrPercent* >(&option); @@ -320,6 +337,7 @@ class ConfigOptionPoint : public ConfigOptionSingle public: ConfigOptionPoint() : ConfigOptionSingle(Pointf(0,0)) {}; ConfigOptionPoint(Pointf _value) : ConfigOptionSingle(_value) {}; + ConfigOptionPoint* clone() const { return new ConfigOptionPoint(this->value); }; std::string serialize() const { std::ostringstream ss; @@ -342,6 +360,9 @@ class ConfigOptionPoint : public ConfigOptionSingle class ConfigOptionPoints : public ConfigOptionVector { public: + ConfigOptionPoints() {}; + ConfigOptionPoints(const std::vector _values) : ConfigOptionVector(_values) {}; + ConfigOptionPoints* clone() const { return new ConfigOptionPoints(this->values); }; std::string serialize() const { std::ostringstream ss; @@ -389,6 +410,7 @@ class ConfigOptionBool : public ConfigOptionSingle public: ConfigOptionBool() : ConfigOptionSingle(false) {}; ConfigOptionBool(bool _value) : ConfigOptionSingle(_value) {}; + ConfigOptionBool* clone() const { return new ConfigOptionBool(this->value); }; bool getBool() const { return this->value; }; @@ -405,6 +427,9 @@ class ConfigOptionBool : public ConfigOptionSingle class ConfigOptionBools : public ConfigOptionVector { public: + ConfigOptionBools() {}; + ConfigOptionBools(const std::vector _values) : ConfigOptionVector(_values) {}; + ConfigOptionBools* clone() const { return new ConfigOptionBools(this->values); }; std::string serialize() const { std::ostringstream ss; @@ -445,6 +470,7 @@ class ConfigOptionEnum : public ConfigOptionSingle // by default, use the first value (0) of the T enum type ConfigOptionEnum() : ConfigOptionSingle(static_cast(0)) {}; ConfigOptionEnum(T _value) : ConfigOptionSingle(_value) {}; + ConfigOptionEnum* clone() const { return new ConfigOptionEnum(this->value); }; std::string serialize() const { t_config_enum_values enum_keys_map = ConfigOptionEnum::get_enum_values(); @@ -532,6 +558,11 @@ class ConfigOptionDef ConfigOptionDef() : type(coNone), default_value(NULL), multiline(false), full_width(false), readonly(false), height(-1), width(-1), min(INT_MIN), max(INT_MAX) {}; + ConfigOptionDef(const ConfigOptionDef &other); + ~ConfigOptionDef(); + + private: + ConfigOptionDef& operator= (ConfigOptionDef other); }; typedef std::map t_optiondef_map; @@ -540,9 +571,9 @@ class ConfigDef { public: t_optiondef_map options; - ~ConfigDef(); ConfigOptionDef* add(const t_config_option_key &opt_key, ConfigOptionType type); const ConfigOptionDef* get(const t_config_option_key &opt_key) const; + void merge(const ConfigDef &other); }; class ConfigBase @@ -551,6 +582,7 @@ class ConfigBase const ConfigDef* def; ConfigBase() : def(NULL) {}; + ConfigBase(const ConfigDef* def) : def(def) {}; virtual ~ConfigBase() {}; bool has(const t_config_option_key &opt_key); const ConfigOption* option(const t_config_option_key &opt_key) const; @@ -571,6 +603,7 @@ class DynamicConfig : public virtual ConfigBase { public: DynamicConfig() {}; + DynamicConfig(const ConfigDef* def) : ConfigBase(def) {}; DynamicConfig(const DynamicConfig& other); DynamicConfig& operator= (DynamicConfig other); void swap(DynamicConfig &other); @@ -579,6 +612,7 @@ class DynamicConfig : public virtual ConfigBase virtual ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false); t_config_option_keys keys() const; void erase(const t_config_option_key &opt_key); + void read_cli(const int argc, const char **argv, t_config_option_keys* extra); private: typedef std::map t_options_map; diff --git a/xs/src/libslic3r/IO.cpp b/xs/src/libslic3r/IO.cpp index 81ac8a127e..ee81924e5c 100644 --- a/xs/src/libslic3r/IO.cpp +++ b/xs/src/libslic3r/IO.cpp @@ -1,10 +1,12 @@ #include "IO.hpp" #include +#include +#include namespace Slic3r { namespace IO { bool -STL::read_file(std::string input_file, Model* model) +STL::read(std::string input_file, Model* model) { // TODO: encode file name // TODO: check that file exists @@ -44,4 +46,30 @@ OBJ::write(TriangleMesh& mesh, std::string output_file) return true; } +bool +POV::write(TriangleMesh& mesh, std::string output_file) +{ + TriangleMesh mesh2 = mesh; + mesh2.center_around_origin(); + { + Sizef3 size = mesh2.bounding_box().size(); + coordf_t maxdim = fmax(size.x, fmax(size.y, size.y)); + mesh2.scale(10.0/maxdim); + } + + using namespace std; + ofstream pov; + pov.open(output_file.c_str(), ios::out | ios::trunc); + for (int i = 0; i < mesh2.stl.stats.number_of_facets; ++i) { + const stl_facet &f = mesh2.stl.facet_start[i]; + pov << "triangle { "; + pov << "<" << f.vertex[0].x << "," << f.vertex[0].y << "," << f.vertex[0].z << ">,"; + pov << "<" << f.vertex[1].x << "," << f.vertex[1].y << "," << f.vertex[1].z << ">,"; + pov << "<" << f.vertex[2].x << "," << f.vertex[2].y << "," << f.vertex[2].z << ">"; + pov << " }" << endl; + } + pov.close(); + return true; +} + } } diff --git a/xs/src/libslic3r/IO.hpp b/xs/src/libslic3r/IO.hpp index 248f3be540..0fe76a0681 100644 --- a/xs/src/libslic3r/IO.hpp +++ b/xs/src/libslic3r/IO.hpp @@ -11,14 +11,20 @@ namespace Slic3r { namespace IO { class STL { public: - bool read_file(std::string input_file, Model* model); - bool write(TriangleMesh& mesh, std::string output_file, bool binary = true); + static bool read(std::string input_file, Model* model); + static bool write(TriangleMesh& mesh, std::string output_file, bool binary = true); }; class OBJ { public: - bool write(TriangleMesh& mesh, std::string output_file); + static bool write(TriangleMesh& mesh, std::string output_file); +}; + +class POV +{ + public: + static bool write(TriangleMesh& mesh, std::string output_file); }; } } diff --git a/xs/src/libslic3r/Model.cpp b/xs/src/libslic3r/Model.cpp index 9eaf5e2f78..ee389e5173 100644 --- a/xs/src/libslic3r/Model.cpp +++ b/xs/src/libslic3r/Model.cpp @@ -1,5 +1,7 @@ #include "Model.hpp" #include "Geometry.hpp" +#include +#include "boost/filesystem.hpp" namespace Slic3r { @@ -311,6 +313,13 @@ Model::duplicate_objects_grid(size_t x, size_t y, coordf_t dist) } } +void +Model::print_info() const +{ + for (ModelObjectPtrs::const_iterator o = this->objects.begin(); o != this->objects.end(); ++o) + (*o)->print_info(); +} + ModelMaterial::ModelMaterial(Model *model) : model(model) {} ModelMaterial::ModelMaterial(Model *model, const ModelMaterial &other) : attributes(other.attributes), config(other.config), model(model) @@ -479,7 +488,7 @@ ModelObject::mesh() const TriangleMesh raw_mesh = this->raw_mesh(); for (ModelInstancePtrs::const_iterator i = this->instances.begin(); i != this->instances.end(); ++i) { - TriangleMesh m = raw_mesh; + TriangleMesh m(raw_mesh); (*i)->transform_mesh(&m); mesh.merge(m); } @@ -568,6 +577,12 @@ ModelObject::translate(coordf_t x, coordf_t y, coordf_t z) if (this->_bounding_box_valid) this->_bounding_box.translate(x, y, z); } +void +ModelObject::scale(float factor) +{ + this->scale(Pointf3(factor, factor, factor)); +} + void ModelObject::scale(const Pointf3 &versor) { @@ -701,6 +716,32 @@ ModelObject::split(ModelObjectPtrs* new_objects) return; } +void +ModelObject::print_info() const +{ + using namespace std; + cout << "Info about " << boost::filesystem::basename(this->input_file) << ":" << endl; + + TriangleMesh mesh = this->raw_mesh(); + mesh.repair(); + Sizef3 size = mesh.bounding_box().size(); + cout << " size: x=" << size.x << " y=" << size.y << " z=" << size.z << endl; + cout << " number of facets: " << mesh.stl.stats.number_of_facets << endl; + cout << " number of shells: " << mesh.stl.stats.number_of_parts << endl; + cout << " volume: " << mesh.stl.stats.volume << endl; + if (this->needed_repair()) { + cout << " needed repair: yes" << endl; + cout << " degenerate facets: " << mesh.stl.stats.degenerate_facets << endl; + cout << " edges fixed: " << mesh.stl.stats.edges_fixed << endl; + cout << " facets removed: " << mesh.stl.stats.facets_removed << endl; + cout << " facets added: " << mesh.stl.stats.facets_added << endl; + cout << " facets reversed: " << mesh.stl.stats.facets_reversed << endl; + cout << " backwards edges: " << mesh.stl.stats.backwards_edges << endl; + } else { + cout << " needed repair: no" << endl; + } +} + ModelVolume::ModelVolume(ModelObject* object, const TriangleMesh &mesh) : mesh(mesh), modifier(false), object(object) @@ -713,6 +754,21 @@ ModelVolume::ModelVolume(ModelObject* object, const ModelVolume &other) this->material_id(other.material_id()); } +ModelVolume& ModelVolume::operator= (ModelVolume other) +{ + this->swap(other); + return *this; +} + +void +ModelVolume::swap(ModelVolume &other) +{ + std::swap(this->name, other.name); + std::swap(this->mesh, other.mesh); + std::swap(this->config, other.config); + std::swap(this->modifier, other.modifier); +} + t_model_material_id ModelVolume::material_id() const { @@ -760,6 +816,20 @@ ModelInstance::ModelInstance(ModelObject *object, const ModelInstance &other) : rotation(other.rotation), scaling_factor(other.scaling_factor), offset(other.offset), object(object) {} +ModelInstance& ModelInstance::operator= (ModelInstance other) +{ + this->swap(other); + return *this; +} + +void +ModelInstance::swap(ModelInstance &other) +{ + std::swap(this->rotation, other.rotation); + std::swap(this->scaling_factor, other.scaling_factor); + std::swap(this->offset, other.offset); +} + void ModelInstance::transform_mesh(TriangleMesh* mesh, bool dont_translate) const { diff --git a/xs/src/libslic3r/Model.hpp b/xs/src/libslic3r/Model.hpp index f10707457a..e98d1db281 100644 --- a/xs/src/libslic3r/Model.hpp +++ b/xs/src/libslic3r/Model.hpp @@ -61,6 +61,7 @@ class Model void duplicate(size_t copies_num, coordf_t dist, const BoundingBoxf* bb = NULL); void duplicate_objects(size_t copies_num, coordf_t dist, const BoundingBoxf* bb = NULL); void duplicate_objects_grid(size_t x, size_t y, coordf_t dist); + void print_info() const; }; class ModelMaterial @@ -124,6 +125,7 @@ class ModelObject void center_around_origin(); void translate(const Vectorf3 &vector); void translate(coordf_t x, coordf_t y, coordf_t z); + void scale(float factor); void scale(const Pointf3 &versor); void rotate(float angle, const Axis &axis); void mirror(const Axis &axis); @@ -133,6 +135,7 @@ class ModelObject void cut(coordf_t z, Model* model) const; void split(ModelObjectPtrs* new_objects); void update_bounding_box(); // this is a private method but we expose it until we need to expose it via XS + void print_info() const; private: Model* model; @@ -167,6 +170,8 @@ class ModelVolume ModelVolume(ModelObject *object, const TriangleMesh &mesh); ModelVolume(ModelObject *object, const ModelVolume &other); + ModelVolume& operator= (ModelVolume other); + void swap(ModelVolume &other); }; class ModelInstance @@ -186,6 +191,8 @@ class ModelInstance ModelInstance(ModelObject *object); ModelInstance(ModelObject *object, const ModelInstance &other); + ModelInstance& operator= (ModelInstance other); + void swap(ModelInstance &other); }; } diff --git a/xs/src/libslic3r/MotionPlanner.cpp b/xs/src/libslic3r/MotionPlanner.cpp index 21afb37c41..a1df679cfd 100644 --- a/xs/src/libslic3r/MotionPlanner.cpp +++ b/xs/src/libslic3r/MotionPlanner.cpp @@ -142,7 +142,7 @@ MotionPlanner::shortest_path(const Point &from, const Point &to) { // grow our environment slightly in order for simplify_by_visibility() // to work best by considering moves on boundaries valid as well - ExPolygonCollection grown_env(offset_ex(env.env, +SCALED_EPSILON)); + ExPolygonCollection grown_env(offset_ex((Polygons)env.env, +SCALED_EPSILON)); if (island_idx == -1) { /* If 'from' or 'to' are not inside our env, they were connected using the diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp index ea745fc189..a505bd888f 100644 --- a/xs/src/libslic3r/PrintConfig.cpp +++ b/xs/src/libslic3r/PrintConfig.cpp @@ -756,6 +756,15 @@ PrintConfigDef::PrintConfigDef() def->min = 0; def->default_value = new ConfigOptionInt(0); + def = this->add("raft_offset", coFloat); + def->label = "Raft offset"; + def->category = "Support material"; + def->tooltip = "Horizontal margin between object base layer and raft contour."; + def->sidetext = "mm"; + def->cli = "raft-offset=f"; + def->min = 0; + def->default_value = new ConfigOptionFloat(4); + def = this->add("resolution", coFloat); def->label = "Resolution"; def->tooltip = "Minimum detail resolution, used to simplify the input file for speeding up the slicing job and reducing memory usage. High-resolution models often carry more detail than printers can render. Set to zero to disable any simplification and use full resolution from input."; @@ -1344,4 +1353,55 @@ PrintConfigBase::min_object_distance() const : duplicate_distance; } +CLIConfigDef::CLIConfigDef() +{ + t_optiondef_map &Options = this->options; + + ConfigOptionDef* def; + + def = this->add("export_obj", coBool); + def->label = "Export SVG"; + def->tooltip = "Export the model as OBJ."; + def->cli = "export-obj"; + def->default_value = new ConfigOptionBool(false); + + def = this->add("export_pov", coBool); + def->label = "Export POV"; + def->tooltip = "Export the model as POV-Ray definition."; + def->cli = "export-pov"; + def->default_value = new ConfigOptionBool(false); + + def = this->add("export_svg", coBool); + def->label = "Export SVG"; + def->tooltip = "Slice the model and export slices as SVG."; + def->cli = "export-svg"; + def->default_value = new ConfigOptionBool(false); + + def = this->add("info", coBool); + def->label = "Output Model Info"; + def->tooltip = "Write information about the model to the console."; + def->cli = "info"; + def->default_value = new ConfigOptionBool(false); + + def = this->add("output", coString); + def->label = "Output File"; + def->tooltip = "The file where the output will be written (if not specified, it will be based on the input file)."; + def->cli = "output"; + def->default_value = new ConfigOptionString(""); + + def = this->add("rotate", coFloat); + def->label = "Rotate"; + def->tooltip = "Rotation angle around the Z axis in degrees (0-360, default: 0)."; + def->cli = "rotate"; + def->default_value = new ConfigOptionFloat(0); + + def = this->add("scale", coFloat); + def->label = "Scale"; + def->tooltip = "Scaling factor (default: 1)."; + def->cli = "scale"; + def->default_value = new ConfigOptionFloat(1); +} + +CLIConfigDef cli_config_def; + } diff --git a/xs/src/libslic3r/PrintConfig.hpp b/xs/src/libslic3r/PrintConfig.hpp index 63a8f5329c..442af51c23 100644 --- a/xs/src/libslic3r/PrintConfig.hpp +++ b/xs/src/libslic3r/PrintConfig.hpp @@ -467,6 +467,67 @@ class FullPrintConfig }; }; +class SVGExportConfig + : public virtual StaticPrintConfig +{ + public: + ConfigOptionFloatOrPercent first_layer_height; + ConfigOptionFloat layer_height; + ConfigOptionInt raft_layers; + ConfigOptionFloat raft_offset; + + SVGExportConfig() : StaticPrintConfig() { + this->set_defaults(); + }; + + virtual ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) { + OPT_PTR(first_layer_height); + OPT_PTR(layer_height); + OPT_PTR(raft_layers); + OPT_PTR(raft_offset); + + return NULL; + }; +}; + +class CLIConfigDef : public ConfigDef +{ + public: + CLIConfigDef(); +}; + +extern CLIConfigDef cli_config_def; + +class CLIConfig + : public virtual ConfigBase, public StaticConfig +{ + public: + ConfigOptionBool export_obj; + ConfigOptionBool export_pov; + ConfigOptionBool export_svg; + ConfigOptionBool info; + ConfigOptionString output; + ConfigOptionFloat rotate; + ConfigOptionFloat scale; + + CLIConfig() : ConfigBase(), StaticConfig() { + this->def = &cli_config_def; + this->set_defaults(); + }; + + virtual ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) { + OPT_PTR(export_obj); + OPT_PTR(export_pov); + OPT_PTR(export_svg); + OPT_PTR(info); + OPT_PTR(output); + OPT_PTR(rotate); + OPT_PTR(scale); + + return NULL; + }; +}; + } #endif diff --git a/xs/src/libslic3r/SVGExport.cpp b/xs/src/libslic3r/SVGExport.cpp new file mode 100644 index 0000000000..c34b5216ed --- /dev/null +++ b/xs/src/libslic3r/SVGExport.cpp @@ -0,0 +1,88 @@ +#include "SVGExport.hpp" +#include "ClipperUtils.hpp" +#include +#include + +namespace Slic3r { + +void +SVGExport::writeSVG(const std::string &outputfile) +{ + // align to origin taking raft into account + BoundingBoxf3 bb = this->mesh.bounding_box(); + if (this->config.raft_layers > 0) { + bb.min.x -= this->config.raft_offset.value; + bb.min.y -= this->config.raft_offset.value; + bb.max.x += this->config.raft_offset.value; + bb.max.y += this->config.raft_offset.value; + } + this->mesh.translate(-bb.min.x, -bb.min.y, -bb.min.z); // align to origin + const Sizef3 size = bb.size(); + + // if we are generating a raft, first_layer_height will not affect mesh slicing + const float lh = this->config.layer_height.value; + const float first_lh = this->config.first_layer_height.value; + + // generate the list of Z coordinates for mesh slicing + // (we slice each layer at half of its thickness) + std::vector slice_z, layer_z; + { + const float first_slice_lh = (this->config.raft_layers > 0) ? lh : first_lh; + slice_z.push_back(first_slice_lh/2); + layer_z.push_back(first_slice_lh); + } + while (layer_z.back() + lh/2 <= this->mesh.stl.stats.max.z) { + slice_z.push_back(layer_z.back() + lh/2); + layer_z.push_back(layer_z.back() + lh); + } + + // perform the slicing + std::vector layers; + TriangleMeshSlicer(&this->mesh).slice(slice_z, &layers); + + // generate a solid raft if requested + if (this->config.raft_layers > 0) { + ExPolygons raft = offset_ex(layers.front(), scale_(this->config.raft_offset)); + for (int i = this->config.raft_layers; i >= 1; --i) { + layer_z.insert(layer_z.begin(), first_lh + lh * (i-1)); + layers.insert(layers.begin(), raft); + } + + // prepend total raft height to all sliced layers + for (int i = this->config.raft_layers; i < layer_z.size(); ++i) + layer_z[i] += first_lh + lh * (this->config.raft_layers-1); + } + + FILE* f = fopen(outputfile.c_str(), "w"); + fprintf(f, + "\n" + "\n" + "\n" + "\n" + , size.x, size.y, SLIC3R_VERSION); + + for (size_t i = 0; i < layer_z.size(); ++i) { + fprintf(f, "\t\n", i, layer_z[i]); + for (ExPolygons::const_iterator it = layers[i].begin(); it != layers[i].end(); ++it){ + std::string pd; + Polygons pp = *it; + for (Polygons::const_iterator mp = pp.begin(); mp != pp.end(); ++mp) { + std::ostringstream d; + d << "M "; + for (Points::const_iterator p = mp->points.begin(); p != mp->points.end(); ++p) { + d << unscale(p->x) << " "; + d << unscale(p->y) << " "; + } + d << "z"; + pd += d.str() + " "; + } + fprintf(f,"\t\t\n", + pd.c_str(), "white", "black", "0", unscale(unscale(it->area())) + ); + } + fprintf(f,"\t\n"); + } + fprintf(f,"\n"); +} + +} diff --git a/xs/src/libslic3r/SVGExport.hpp b/xs/src/libslic3r/SVGExport.hpp new file mode 100644 index 0000000000..b77a21fa88 --- /dev/null +++ b/xs/src/libslic3r/SVGExport.hpp @@ -0,0 +1,28 @@ +#ifndef slic3r_SVGExport_hpp_ +#define slic3r_SVGExport_hpp_ + +#include "libslic3r.h" +#include "ExPolygon.hpp" +#include "PrintConfig.hpp" +#include "SVG.hpp" +#include "TriangleMesh.hpp" + +namespace Slic3r { + +class SVGExport +{ + public: + SVGExportConfig config; + + SVGExport(const TriangleMesh &mesh) : mesh(mesh) { + this->mesh.mirror_x(); + }; + void writeSVG(const std::string &outputfile); + + private: + TriangleMesh mesh; +}; + +} + +#endif diff --git a/xs/src/libslic3r/TriangleMesh.cpp b/xs/src/libslic3r/TriangleMesh.cpp index 40d0e480b1..cea6706e99 100644 --- a/xs/src/libslic3r/TriangleMesh.cpp +++ b/xs/src/libslic3r/TriangleMesh.cpp @@ -50,19 +50,15 @@ TriangleMesh::TriangleMesh(const TriangleMesh &other) TriangleMesh& TriangleMesh::operator= (TriangleMesh other) { - this->swap(other); + swap(*this, other); return *this; } void -TriangleMesh::swap(TriangleMesh &other) +TriangleMesh::swap(TriangleMesh &first, TriangleMesh &second) { - std::swap(this->stl, other.stl); - std::swap(this->repaired, other.repaired); - std::swap(this->stl.facet_start, other.stl.facet_start); - std::swap(this->stl.neighbors_start, other.stl.neighbors_start); - std::swap(this->stl.v_indices, other.stl.v_indices); - std::swap(this->stl.v_shared, other.stl.v_shared); + std::swap(first.repaired, second.repaired); + std::swap(first.stl, second.stl); } TriangleMesh::~TriangleMesh() { @@ -266,6 +262,16 @@ void TriangleMesh::align_to_origin() ); } +void TriangleMesh::center_around_origin() +{ + this->align_to_origin(); + this->translate( + -(this->stl.stats.size.x/2), + -(this->stl.stats.size.y/2), + -(this->stl.stats.size.z/2) + ); +} + void TriangleMesh::rotate(double angle, Point* center) { this->translate(-center->x, -center->y, 0); @@ -340,9 +346,8 @@ TriangleMesh::merge(const TriangleMesh &mesh) stl_reallocate(&this->stl); // copy facets - for (int i = 0; i < mesh.stl.stats.number_of_facets; i++) { - this->stl.facet_start[number_of_facets + i] = mesh.stl.facet_start[i]; - } + std::copy(mesh.stl.facet_start, mesh.stl.facet_start + mesh.stl.stats.number_of_facets, this->stl.facet_start); + std::copy(mesh.stl.neighbors_start, mesh.stl.neighbors_start + mesh.stl.stats.number_of_facets, this->stl.neighbors_start); // update size stl_get_size(&this->stl); diff --git a/xs/src/libslic3r/TriangleMesh.hpp b/xs/src/libslic3r/TriangleMesh.hpp index 0eb62d65e0..f0dd66fbad 100644 --- a/xs/src/libslic3r/TriangleMesh.hpp +++ b/xs/src/libslic3r/TriangleMesh.hpp @@ -22,7 +22,7 @@ class TriangleMesh TriangleMesh(); TriangleMesh(const TriangleMesh &other); TriangleMesh& operator= (TriangleMesh other); - void swap(TriangleMesh &other); + void swap(TriangleMesh &first, TriangleMesh &second); ~TriangleMesh(); void ReadSTLFile(const std::string &input_file); void write_ascii(const std::string &output_file); @@ -41,6 +41,7 @@ class TriangleMesh void mirror_y(); void mirror_z(); void align_to_origin(); + void center_around_origin(); void rotate(double angle, Point* center); TriangleMeshPtrs split() const; void merge(const TriangleMesh &mesh); diff --git a/xs/xsp/Model.xsp b/xs/xsp/Model.xsp index 3cc0f5e3b2..8bfd10123b 100644 --- a/xs/xsp/Model.xsp +++ b/xs/xsp/Model.xsp @@ -71,6 +71,7 @@ void duplicate(unsigned int copies_num, double dist, BoundingBoxf* bb = NULL); void duplicate_objects(unsigned int copies_num, double dist, BoundingBoxf* bb = NULL); void duplicate_objects_grid(unsigned int x, unsigned int y, double dist); + void print_info(); }; @@ -196,6 +197,8 @@ ModelMaterial::attributes() RETVAL = new ModelObjectPtrs(); // leak? THIS->split(RETVAL); %}; + + void print_info(); };