Welcome to mirror list, hosted at ThFree Co, Russian Federation.

slic3r.cpp « src - github.com/prusa3d/PrusaSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 0b7dada70fa2b1cde405f78f482a9bd5800b4e42 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
#ifdef WIN32
    // Why?
    #define _WIN32_WINNT 0x0502
    // The standard Windows includes.
    #define WIN32_LEAN_AND_MEAN
    #define NOMINMAX
    #include <Windows.h>
    #include <wchar.h>
    // Let the NVIDIA and AMD know we want to use their graphics card
    // on a dual graphics card system.
    __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
    __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
#endif /* WIN32 */

#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <math.h>
#include <boost/filesystem.hpp>
#include <boost/nowide/args.hpp>
#include <boost/nowide/cenv.hpp>
#include <boost/nowide/iostream.hpp>

#include "unix/fhs.hpp"  // Generated by CMake from ../platform/unix/fhs.hpp.in

#include "libslic3r/libslic3r.h"
#include "libslic3r/Config.hpp"
#include "libslic3r/Geometry.hpp"
#include "libslic3r/Model.hpp"
#include "libslic3r/Print.hpp"
#include "libslic3r/SLAPrint.hpp"
#include "libslic3r/TriangleMesh.hpp"
#include "libslic3r/Format/3mf.hpp"
#include "libslic3r/Utils.hpp"

#include "slic3r/GUI/GUI.hpp"
#include "slic3r/GUI/GUI_App.hpp"

using namespace Slic3r;

/// utility function for displaying CLI usage
void printUsage();

#ifdef _MSC_VER
int slic3r_main_(int argc, char **argv)
#else
int main(int argc, char **argv)
#endif
{
    {
        const char *loglevel = boost::nowide::getenv("SLIC3R_LOGLEVEL");
        if (loglevel != nullptr) {
            if (loglevel[0] >= '0' && loglevel[0] <= '9' && loglevel[1] == 0)
                set_logging_level(loglevel[0] - '0');
            else
                boost::nowide::cerr << "Invalid SLIC3R_LOGLEVEL environment variable: " << loglevel << std::endl;
        }
    }

    // parse all command line options into a DynamicConfig
    DynamicPrintAndCLIConfig all_config;
    t_config_option_keys input_files;
    // if any option is unsupported, print usage and abort immediately
    if (! all_config.read_cli(argc, argv, &input_files)) {
        printUsage();
        return 0;
    }

    boost::filesystem::path path_to_binary = boost::filesystem::system_complete(argv[0]);

    // Path from the Slic3r binary to its resources.
#ifdef __APPLE__
    // The application is packed in the .dmg archive as 'Slic3r.app/Contents/MacOS/Slic3r'
    // The resources are packed to 'Slic3r.app/Contents/Resources'
    boost::filesystem::path path_resources = path_to_binary.parent_path() / "../Resources";
#elif defined _WIN32
    // The application is packed in the .zip archive in the root,
    // The resources are packed to 'resources'
    // Path from Slic3r binary to resources:
    boost::filesystem::path path_resources = path_to_binary.parent_path() / "resources";
#elif defined SLIC3R_FHS
    // The application is packaged according to the Linux Filesystem Hierarchy Standard
    // Resources are set to the 'Architecture-independent (shared) data', typically /usr/share or /usr/local/share
    boost::filesystem::path path_resources = SLIC3R_FHS_RESOURCES;
#else
    // The application is packed in the .tar.bz archive (or in AppImage) as 'bin/slic3r',
    // The resources are packed to 'resources'
    // Path from Slic3r binary to resources:
    boost::filesystem::path path_resources = path_to_binary.parent_path() / "../resources";
#endif

    set_resources_dir(path_resources.string());
    set_var_dir((path_resources / "icons").string());
    set_local_dir((path_resources / "localization").string());

    // apply command line options to a more handy CLIConfig
    CLIConfig cli_config;
#ifdef __APPLE__
	// Enable the GUI mode by default, to support drag & drop.
	cli_config.gui.value = true;
#endif /* __APPLE__ */

    cli_config.apply(all_config, true);
    set_data_dir(cli_config.datadir.value);

    // Load the extra config values.
    DynamicPrintConfig extra_config;
    extra_config.apply(all_config, true);

    // load config files supplied via --load
    DynamicPrintConfig print_config;
    for (const std::string &file : cli_config.load.values) {
        if (! boost::filesystem::exists(file)) {
            boost::nowide::cout << "No such file: " << file << std::endl;
            exit(1);
        }
        DynamicPrintConfig c;
        try {
            c.load(file);
        } catch (std::exception &e) {
            boost::nowide::cout << "Error while reading config file: " << e.what() << std::endl;
            exit(1);
        }
        c.normalize();
        print_config.apply(c);
    }

    if ((input_files.empty() || cli_config.gui.value) && ! cli_config.no_gui.value && ! cli_config.help.value && cli_config.save.value.empty()) {
#if 1
        GUI::GUI_App *gui = new GUI::GUI_App();
        GUI::GUI_App::SetInstance(gui);
        gui->CallAfter([gui, &input_files, &cli_config, &extra_config, &print_config] {
#if 0
            // Load the cummulative config over the currently active profiles.
            //FIXME if multiple configs are loaded, only the last one will have an effect.
            // We need to decide what to do about loading of separate presets (just print preset, just filament preset etc).
            // As of now only the full configs are supported here.
            if (! print_config.empty())
                gui->mainframe->load_config(print_config);
#endif
            if (! cli_config.load.values.empty())
                // Load the last config to give it a name at the UI. The name of the preset may be later
                // changed by loading an AMF or 3MF.
                //FIXME this is not strictly correct, as one may pass a print/filament/printer profile here instead of a full config.
				gui->mainframe->load_config_file(cli_config.load.values.back());
            // If loading a 3MF file, the config is loaded from the last one.
            gui->plater()->load_files(input_files, true, true);
            if (! extra_config.empty())
                gui->mainframe->load_config(extra_config);
        });
        return wxEntry(argc, argv);
#else
        std::cout << "GUI support has not been built." << "\n";
		return -1;
#endif
    }

    // apply command line options to a more specific DynamicPrintConfig which provides normalize()
    // (command line options override --load files)
    print_config.apply(extra_config, true);
    
    // write config if requested
    if (! cli_config.save.value.empty()) {
        print_config.normalize();
        print_config.save(cli_config.save.value);
    }

    if (cli_config.help) {
        printUsage();
        return 0;
    }

    // read input file(s) if any
    std::vector<Model> models;
    for (const t_config_option_key &file : input_files) {
        if (! boost::filesystem::exists(file)) {
            boost::nowide::cerr << "No such file: " << file << std::endl;
            exit(1);
        }
        Model model;
        try {
            model = Model::read_from_file(file, &print_config, true);
        } catch (std::exception &e) {
            boost::nowide::cerr << file << ": " << e.what() << std::endl;
            exit(1);
        }
        if (model.objects.empty()) {
            boost::nowide::cerr << "Error: file is empty: " << file << std::endl;
            continue;
        }
        model.add_default_instances();        
        // apply command line transform options
        for (ModelObject* o : model.objects) {
/*
            if (cli_config.scale_to_fit.is_positive_volume())
                o->scale_to_fit(cli_config.scale_to_fit.value);
*/
            // TODO: honor option order?
            o->scale(cli_config.scale.value);
            o->rotate(Geometry::deg2rad(cli_config.rotate_x.value), X);
            o->rotate(Geometry::deg2rad(cli_config.rotate_y.value), Y);
            o->rotate(Geometry::deg2rad(cli_config.rotate.value), Z);
        }
        // TODO: handle --merge
        models.push_back(model);
    }

    for (Model &model : models) {
        if (cli_config.info) {
            // --info works on unrepaired model
            model.print_info();
        } else if (cli_config.export_3mf) {
            std::string outfile = cli_config.output.value;
            if (outfile.empty()) outfile = model.objects.front()->input_file;
            // Check if the file is already a 3mf.
            if(outfile.substr(outfile.find_last_of('.'), outfile.length()) == ".3mf")
                outfile = outfile.substr(0, outfile.find_last_of('.')) + "_2" + ".3mf";
            else
                // Remove the previous extension and add .3mf extention.
                outfile = outfile.substr(0, outfile.find_last_of('.')) + ".3mf";
            store_3mf(outfile.c_str(), &model, nullptr);
            boost::nowide::cout << "File file exported to " << outfile << std::endl;
        } else if (cli_config.cut > 0) {
            model.repair();
            model.translate(0, 0, - model.bounding_box().min(2));
            if (! model.objects.empty()) {
                // XXX
                // Model out;
                // model.objects.front()->cut(cli_config.cut, &out);
                // ModelObject &upper = *out.objects[0];
                // ModelObject &lower = *out.objects[1];
                // // Use the input name and trim off the extension.
                // std::string outfile = cli_config.output.value;
                // if (outfile.empty())
                //     outfile = model.objects.front()->input_file;
                // outfile = outfile.substr(0, outfile.find_last_of('.'));
                // std::cerr << outfile << "\n";
                // if (upper.facets_count() > 0)
                //     upper.mesh().write_binary((outfile + "_upper.stl").c_str());
                // if (lower.facets_count() > 0)
                //     lower.mesh().write_binary((outfile + "_lower.stl").c_str());
            }
        } else if (cli_config.slice) {
            PrinterTechnology printer_technology = print_config.option<ConfigOptionEnum<PrinterTechnology>>("printer_technology", true)->value;
            std::string outfile = cli_config.output.value;
            Print       fff_print;
            SLAPrint    sla_print;
            PrintBase  *print = (printer_technology == ptFFF) ? static_cast<PrintBase*>(&fff_print) : static_cast<PrintBase*>(&sla_print);
            if (! cli_config.dont_arrange) {
                //FIXME make the min_object_distance configurable.
                model.arrange_objects(fff_print.config().min_object_distance());
                model.center_instances_around_point(cli_config.print_center);
            }
            if (outfile.empty()) {
                outfile = model.propose_export_file_name();
                outfile += (printer_technology == ptFFF) ? ".gcode" : ".zip";
            }
            if (printer_technology == ptFFF) {
                for (auto* mo : model.objects)
                    fff_print.auto_assign_extruders(mo);
            }
            print_config.normalize();
            print->apply(model, print_config);
            std::string err = print->validate();
            if (err.empty()) {
                if (printer_technology == ptFFF) {
                    fff_print.export_gcode(outfile, nullptr);
                } else {
                    assert(printer_technology == ptSLA);
					//FIXME add the output here
                }
            } else
                std::cerr << err << "\n";
        } else {
            boost::nowide::cerr << "error: command not supported" << std::endl;
            return 1;
        }
    }
    
    return 0;
}

void printUsage()
{
    std::cout << "Slic3r " << SLIC3R_VERSION << " is a STL-to-GCODE translator for RepRap 3D printers" << "\n"
              << "written by Alessandro Ranellucci <aar@cpan.org> - http://slic3r.org/ - https://github.com/slic3r/Slic3r" << "\n"
//              << "Git Version " << BUILD_COMMIT << "\n\n"
              << "Usage: ./slic3r [ OPTIONS ] [ file.stl ] [ file2.stl ] ..." << "\n";
    // CLI Options
    std::cout << "** CLI OPTIONS **\n";
    print_cli_options(boost::nowide::cout);
    std::cout << "****\n";
        // Print options
        std::cout << "** PRINT OPTIONS **\n";
    print_print_options(boost::nowide::cout);
    std::cout << "****\n";
}

#ifdef _MSC_VER
extern "C" {
	__declspec(dllexport) int __stdcall slic3r_main(int argc, wchar_t **argv)
	{
		// Convert wchar_t arguments to UTF8.
		std::vector<std::string> 	argv_narrow;
		std::vector<char*>			argv_ptrs(argc + 1, nullptr);
		for (size_t i = 0; i < argc; ++ i)
			argv_narrow.emplace_back(boost::nowide::narrow(argv[i]));
		for (size_t i = 0; i < argc; ++ i)
			argv_ptrs[i] = const_cast<char*>(argv_narrow[i].data());
		// Call the UTF8 main.
		return slic3r_main_(argc, argv_ptrs.data());
	}
}
#endif /* _MSC_VER */