mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-07-13 03:11:47 +08:00
Merge branch 'cppsvg'
This commit is contained in:
commit
f7e37fa9ab
@ -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)})) {
|
||||
|
@ -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;
|
||||
|
111
src/CMakeLists.txt
Normal file
111
src/CMakeLists.txt
Normal file
@ -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)
|
||||
|
95
src/slic3r.cpp
Normal file
95
src/slic3r.cpp
Normal file
@ -0,0 +1,95 @@
|
||||
#include "Config.hpp"
|
||||
#include "Model.hpp"
|
||||
#include "IO.hpp"
|
||||
#include "TriangleMesh.hpp"
|
||||
#include "SVGExport.hpp"
|
||||
#include "libslic3r.h"
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
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<Model> 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<Model>::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;
|
||||
}
|
0
src/standalone/config.h
Normal file
0
src/standalone/config.h
Normal file
40
src/windows-build.txt
Normal file
40
src/windows-build.txt
Normal file
@ -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)
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -1,6 +1,8 @@
|
||||
#include "Config.hpp"
|
||||
#include <stdlib.h> // for setenv()
|
||||
#include <assert.h>
|
||||
#include <boost/algorithm/string/erase.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
|
||||
#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<ConfigDef*>(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<ConfigOptionBool>(opt_key, true)) {
|
||||
opt->value = !boost::starts_with(token, "no-");
|
||||
} else if (ConfigOptionBools* opt = this->opt<ConfigOptionBools>(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()
|
||||
{
|
||||
|
@ -20,6 +20,7 @@ typedef std::vector<std::string> 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 T>
|
||||
class ConfigOptionVector : public ConfigOptionVectorBase
|
||||
{
|
||||
public:
|
||||
virtual ~ConfigOptionVector() {};
|
||||
std::vector<T> values;
|
||||
ConfigOptionVector() {};
|
||||
ConfigOptionVector(const std::vector<T> _values) : values(_values) {};
|
||||
virtual ~ConfigOptionVector() {};
|
||||
|
||||
void set(const ConfigOption &option) {
|
||||
const ConfigOptionVector<T>* other = dynamic_cast< const ConfigOptionVector<T>* >(&option);
|
||||
@ -76,6 +79,7 @@ class ConfigOptionFloat : public ConfigOptionSingle<double>
|
||||
public:
|
||||
ConfigOptionFloat() : ConfigOptionSingle<double>(0) {};
|
||||
ConfigOptionFloat(double _value) : ConfigOptionSingle<double>(_value) {};
|
||||
ConfigOptionFloat* clone() const { return new ConfigOptionFloat(this->value); };
|
||||
|
||||
double getFloat() const { return this->value; };
|
||||
|
||||
@ -95,6 +99,9 @@ class ConfigOptionFloat : public ConfigOptionSingle<double>
|
||||
class ConfigOptionFloats : public ConfigOptionVector<double>
|
||||
{
|
||||
public:
|
||||
ConfigOptionFloats() {};
|
||||
ConfigOptionFloats(const std::vector<double> _values) : ConfigOptionVector<double>(_values) {};
|
||||
ConfigOptionFloats* clone() const { return new ConfigOptionFloats(this->values); };
|
||||
|
||||
std::string serialize() const {
|
||||
std::ostringstream ss;
|
||||
@ -134,6 +141,7 @@ class ConfigOptionInt : public ConfigOptionSingle<int>
|
||||
public:
|
||||
ConfigOptionInt() : ConfigOptionSingle<int>(0) {};
|
||||
ConfigOptionInt(double _value) : ConfigOptionSingle<int>(_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<int>
|
||||
class ConfigOptionInts : public ConfigOptionVector<int>
|
||||
{
|
||||
public:
|
||||
ConfigOptionInts() {};
|
||||
ConfigOptionInts(const std::vector<int> _values) : ConfigOptionVector<int>(_values) {};
|
||||
ConfigOptionInts* clone() const { return new ConfigOptionInts(this->values); };
|
||||
|
||||
std::string serialize() const {
|
||||
std::ostringstream ss;
|
||||
@ -193,6 +204,7 @@ class ConfigOptionString : public ConfigOptionSingle<std::string>
|
||||
public:
|
||||
ConfigOptionString() : ConfigOptionSingle<std::string>("") {};
|
||||
ConfigOptionString(std::string _value) : ConfigOptionSingle<std::string>(_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<std::string>
|
||||
class ConfigOptionStrings : public ConfigOptionVector<std::string>
|
||||
{
|
||||
public:
|
||||
ConfigOptionStrings() {};
|
||||
ConfigOptionStrings(const std::vector<std::string> _values) : ConfigOptionVector<std::string>(_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<Pointf>
|
||||
public:
|
||||
ConfigOptionPoint() : ConfigOptionSingle<Pointf>(Pointf(0,0)) {};
|
||||
ConfigOptionPoint(Pointf _value) : ConfigOptionSingle<Pointf>(_value) {};
|
||||
ConfigOptionPoint* clone() const { return new ConfigOptionPoint(this->value); };
|
||||
|
||||
std::string serialize() const {
|
||||
std::ostringstream ss;
|
||||
@ -342,6 +360,9 @@ class ConfigOptionPoint : public ConfigOptionSingle<Pointf>
|
||||
class ConfigOptionPoints : public ConfigOptionVector<Pointf>
|
||||
{
|
||||
public:
|
||||
ConfigOptionPoints() {};
|
||||
ConfigOptionPoints(const std::vector<Pointf> _values) : ConfigOptionVector<Pointf>(_values) {};
|
||||
ConfigOptionPoints* clone() const { return new ConfigOptionPoints(this->values); };
|
||||
|
||||
std::string serialize() const {
|
||||
std::ostringstream ss;
|
||||
@ -389,6 +410,7 @@ class ConfigOptionBool : public ConfigOptionSingle<bool>
|
||||
public:
|
||||
ConfigOptionBool() : ConfigOptionSingle<bool>(false) {};
|
||||
ConfigOptionBool(bool _value) : ConfigOptionSingle<bool>(_value) {};
|
||||
ConfigOptionBool* clone() const { return new ConfigOptionBool(this->value); };
|
||||
|
||||
bool getBool() const { return this->value; };
|
||||
|
||||
@ -405,6 +427,9 @@ class ConfigOptionBool : public ConfigOptionSingle<bool>
|
||||
class ConfigOptionBools : public ConfigOptionVector<bool>
|
||||
{
|
||||
public:
|
||||
ConfigOptionBools() {};
|
||||
ConfigOptionBools(const std::vector<bool> _values) : ConfigOptionVector<bool>(_values) {};
|
||||
ConfigOptionBools* clone() const { return new ConfigOptionBools(this->values); };
|
||||
|
||||
std::string serialize() const {
|
||||
std::ostringstream ss;
|
||||
@ -445,6 +470,7 @@ class ConfigOptionEnum : public ConfigOptionSingle<T>
|
||||
// by default, use the first value (0) of the T enum type
|
||||
ConfigOptionEnum() : ConfigOptionSingle<T>(static_cast<T>(0)) {};
|
||||
ConfigOptionEnum(T _value) : ConfigOptionSingle<T>(_value) {};
|
||||
ConfigOptionEnum<T>* clone() const { return new ConfigOptionEnum<T>(this->value); };
|
||||
|
||||
std::string serialize() const {
|
||||
t_config_enum_values enum_keys_map = ConfigOptionEnum<T>::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_config_option_key,ConfigOptionDef> 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_config_option_key,ConfigOption*> t_options_map;
|
||||
|
@ -1,10 +1,12 @@
|
||||
#include "IO.hpp"
|
||||
#include <stdexcept>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
} }
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
} }
|
||||
|
@ -1,5 +1,7 @@
|
||||
#include "Model.hpp"
|
||||
#include "Geometry.hpp"
|
||||
#include <iostream>
|
||||
#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
|
||||
{
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
88
xs/src/libslic3r/SVGExport.cpp
Normal file
88
xs/src/libslic3r/SVGExport.cpp
Normal file
@ -0,0 +1,88 @@
|
||||
#include "SVGExport.hpp"
|
||||
#include "ClipperUtils.hpp"
|
||||
#include <iostream>
|
||||
#include <cstdio>
|
||||
|
||||
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<float> 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<ExPolygons> 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,
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n"
|
||||
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\" \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n"
|
||||
"<svg width=\"%f\" height=\"%f\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:svg=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:slic3r=\"http://slic3r.org/namespaces/slic3r\">\n"
|
||||
"<!-- Generated using Slic3r %s http://slic3r.org/ -->\n"
|
||||
, size.x, size.y, SLIC3R_VERSION);
|
||||
|
||||
for (size_t i = 0; i < layer_z.size(); ++i) {
|
||||
fprintf(f, "\t<g id=\"layer%zu\" slic3r:z=\"%0.4f\">\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<path d=\"%s\" style=\"fill: %s; stroke: %s; stroke-width: %s; fill-type: evenodd\" slic3r:area=\"%0.4f\" />\n",
|
||||
pd.c_str(), "white", "black", "0", unscale(unscale(it->area()))
|
||||
);
|
||||
}
|
||||
fprintf(f,"\t</g>\n");
|
||||
}
|
||||
fprintf(f,"</svg>\n");
|
||||
}
|
||||
|
||||
}
|
28
xs/src/libslic3r/SVGExport.hpp
Normal file
28
xs/src/libslic3r/SVGExport.hpp
Normal file
@ -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
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user