426 linhas
17 KiB
C++
426 linhas
17 KiB
C++
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/time.h>
|
|
#include <signal.h>
|
|
#if defined(__linux__) || (defined(__APPLE__) && defined(__MACH__))
|
|
#include <execinfo.h>
|
|
#include <sys/resource.h>
|
|
#endif
|
|
#include <stddef.h>
|
|
#include <vector>
|
|
|
|
#include "utils/gettime.h"
|
|
#include "utils/logoutput.h"
|
|
#include "utils/string.h"
|
|
|
|
#include "FffProcessor.h"
|
|
#include "settings/SettingRegistry.h"
|
|
|
|
#include "settings/SettingsToGV.h"
|
|
|
|
namespace cura
|
|
{
|
|
|
|
void print_usage()
|
|
{
|
|
logAlways("\n");
|
|
logAlways("usage:\n");
|
|
logAlways("CuraEngine help\n");
|
|
logAlways("\tShow this help message\n");
|
|
logAlways("\n");
|
|
logAlways("CuraEngine connect <host>[:<port>] [-j <settings.def.json>]\n");
|
|
logAlways(" --connect <host>[:<port>]\n\tConnect to <host> via a command socket, \n\tinstead of passing information via the command line\n");
|
|
logAlways(" -j<settings.def.json>\n\tLoad settings.json file to register all settings and their defaults\n");
|
|
logAlways(" -v\n\tIncrease the verbose level (show log messages).\n");
|
|
logAlways("\n");
|
|
logAlways("CuraEngine slice [-v] [-p] [-j <settings.json>] [-s <settingkey>=<value>] [-g] [-e<extruder_nr>] [-o <output.gcode>] [-l <model.stl>] [--next]\n");
|
|
logAlways(" -v\n\tIncrease the verbose level (show log messages).\n");
|
|
logAlways(" -p\n\tLog progress information.\n");
|
|
logAlways(" -j\n\tLoad settings.def.json file to register all settings and their defaults.\n");
|
|
logAlways(" -s <setting>=<value>\n\tSet a setting to a value for the last supplied object, \n\textruder train, or general settings.\n");
|
|
logAlways(" -l <model_file>\n\tLoad an STL model. \n");
|
|
logAlways(" -g\n\tSwitch setting focus to the current mesh group only.\n\tUsed for one-at-a-time printing.\n");
|
|
logAlways(" -e<extruder_nr>\n\tSwitch setting focus to the extruder train with the given number.\n");
|
|
logAlways(" --next\n\tGenerate gcode for the previously supplied mesh group and append that to \n\tthe gcode of further models for one-at-a-time printing.\n");
|
|
logAlways(" -o <output_file>\n\tSpecify a file to which to write the generated gcode.\n");
|
|
logAlways("\n");
|
|
logAlways("The settings are appended to the last supplied object:\n");
|
|
logAlways("CuraEngine slice [general settings] \n\t-g [current group settings] \n\t-e0 [extruder train 0 settings] \n\t-l obj_inheriting_from_last_extruder_train.stl [object settings] \n\t--next [next group settings]\n\t... etc.\n");
|
|
logAlways("\n");
|
|
logAlways("In order to load machine definitions from custom locations, you need to create the environment variable CURA_ENGINE_SEARCH_PATH, which should contain all search paths delimited by a (semi-)colon.\n");
|
|
logAlways("\n");
|
|
}
|
|
|
|
//Signal handler for a "floating point exception", which can also be integer division by zero errors.
|
|
void signal_FPE(int n)
|
|
{
|
|
(void)n;
|
|
cura::logError("Arithmetic exception.\n");
|
|
exit(1);
|
|
}
|
|
|
|
void print_call(int argc, char **argv)
|
|
{
|
|
cura::logError("Command called:\n");
|
|
for (int idx= 0; idx < argc; idx++)
|
|
cura::logError("%s ", argv[idx]);
|
|
cura::logError("\n");
|
|
}
|
|
|
|
void connect(int argc, char **argv)
|
|
{
|
|
std::string ip;
|
|
int port = 49674;
|
|
|
|
// parse ip port
|
|
std::string ip_port(argv[2]);
|
|
if (ip_port.find(':') != std::string::npos)
|
|
{
|
|
ip = ip_port.substr(0, ip_port.find(':'));
|
|
port = std::stoi(ip_port.substr(ip_port.find(':') + 1).data());
|
|
}
|
|
|
|
for(int argn = 3; argn < argc; argn++)
|
|
{
|
|
char* str = argv[argn];
|
|
if (str[0] == '-')
|
|
{
|
|
for(str++; *str; str++)
|
|
{
|
|
switch(*str)
|
|
{
|
|
case 'v':
|
|
cura::increaseVerboseLevel();
|
|
break;
|
|
case 'j':
|
|
argn++;
|
|
if (SettingRegistry::getInstance()->loadJSONsettings(argv[argn], FffProcessor::getInstance()))
|
|
{
|
|
cura::logError("Failed to load json file: %s\n", argv[argn]);
|
|
std::exit(1);
|
|
}
|
|
break;
|
|
default:
|
|
cura::logError("Unknown option: %c\n", *str);
|
|
print_call(argc, argv);
|
|
print_usage();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
CommandSocket::instantiate();
|
|
CommandSocket::getInstance()->connect(ip, port);
|
|
}
|
|
|
|
void slice(int argc, char **argv)
|
|
{
|
|
FffProcessor::getInstance()->time_keeper.restart();
|
|
|
|
FMatrix3x3 transformation; // the transformation applied to a model when loaded
|
|
|
|
MeshGroup* meshgroup = new MeshGroup(FffProcessor::getInstance());
|
|
|
|
int extruder_train_nr = 0;
|
|
|
|
SettingsBase* last_extruder_train = nullptr;
|
|
// extruder defaults cannot be loaded yet cause no json has been parsed
|
|
SettingsBase* last_settings_object = FffProcessor::getInstance();
|
|
for(int argn = 2; argn < argc; argn++)
|
|
{
|
|
char* str = argv[argn];
|
|
if (str[0] == '-')
|
|
{
|
|
if (str[1] == '-')
|
|
{
|
|
if (stringcasecompare(str, "--next") == 0)
|
|
{
|
|
try {
|
|
//Catch all exceptions, this prevents the "something went wrong" dialog on windows to pop up on a thrown exception.
|
|
// Only ClipperLib currently throws exceptions. And only in case that it makes an internal error.
|
|
log("Loaded from disk in %5.3fs\n", FffProcessor::getInstance()->time_keeper.restart());
|
|
|
|
for (int extruder_nr = 0; extruder_nr < FffProcessor::getInstance()->getSettingAsCount("machine_extruder_count"); extruder_nr++)
|
|
{ // initialize remaining extruder trains and load the defaults
|
|
meshgroup->createExtruderTrain(extruder_nr); // create new extruder train objects or use already existing ones
|
|
}
|
|
|
|
meshgroup->finalize();
|
|
|
|
//start slicing
|
|
FffProcessor::getInstance()->processMeshGroup(meshgroup);
|
|
|
|
// initialize loading of new meshes
|
|
FffProcessor::getInstance()->time_keeper.restart();
|
|
delete meshgroup;
|
|
meshgroup = new MeshGroup(FffProcessor::getInstance());
|
|
last_extruder_train = meshgroup->createExtruderTrain(0);
|
|
last_settings_object = meshgroup;
|
|
|
|
}catch(...){
|
|
cura::logError("Unknown exception\n");
|
|
exit(1);
|
|
}
|
|
}else{
|
|
cura::logError("Unknown option: %s\n", str);
|
|
}
|
|
}else{
|
|
for(str++; *str; str++)
|
|
{
|
|
switch(*str)
|
|
{
|
|
case 'v':
|
|
cura::increaseVerboseLevel();
|
|
break;
|
|
case 'p':
|
|
cura::enableProgressLogging();
|
|
break;
|
|
case 'j':
|
|
argn++;
|
|
if (SettingRegistry::getInstance()->loadJSONsettings(argv[argn], last_settings_object))
|
|
{
|
|
cura::logError("Failed to load json file: %s\n", argv[argn]);
|
|
std::exit(1);
|
|
}
|
|
break;
|
|
case 'e':
|
|
str++;
|
|
extruder_train_nr = int(*str - '0'); // TODO: parse int instead (now "-e10"="-e:" , "-e11"="-e;" , "-e12"="-e<" .. etc)
|
|
last_settings_object = meshgroup->createExtruderTrain(extruder_train_nr);
|
|
last_extruder_train = last_settings_object;
|
|
break;
|
|
case 'l':
|
|
argn++;
|
|
|
|
log("Loading %s from disk...\n", argv[argn]);
|
|
|
|
transformation = last_settings_object->getSettingAsPointMatrix("mesh_rotation_matrix"); // the transformation applied to a model when loaded
|
|
|
|
if (!last_extruder_train)
|
|
{
|
|
last_extruder_train = meshgroup->createExtruderTrain(0); // assume a json has already been provided on the command line
|
|
}
|
|
if (!loadMeshIntoMeshGroup(meshgroup, argv[argn], transformation, last_extruder_train))
|
|
{
|
|
logError("Failed to load model: %s\n", argv[argn]);
|
|
std::exit(1);
|
|
}
|
|
else
|
|
{
|
|
last_settings_object = &(meshgroup->meshes.back()); // pointer is valid until a new object is added, so this is OK
|
|
}
|
|
break;
|
|
case 'o':
|
|
argn++;
|
|
if (!FffProcessor::getInstance()->setTargetFile(argv[argn]))
|
|
{
|
|
cura::logError("Failed to open %s for output.\n", argv[argn]);
|
|
exit(1);
|
|
}
|
|
break;
|
|
case 'g':
|
|
last_settings_object = meshgroup;
|
|
case 's':
|
|
{
|
|
//Parse the given setting and store it.
|
|
argn++;
|
|
char* valuePtr = strchr(argv[argn], '=');
|
|
if (valuePtr)
|
|
{
|
|
*valuePtr++ = '\0';
|
|
|
|
last_settings_object->setSetting(argv[argn], valuePtr);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
cura::logError("Unknown option: %c\n", *str);
|
|
print_call(argc, argv);
|
|
print_usage();
|
|
exit(1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
cura::logError("Unknown option: %s\n", argv[argn]);
|
|
print_call(argc, argv);
|
|
print_usage();
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
int extruder_count = FffProcessor::getInstance()->getSettingAsCount("machine_extruder_count");
|
|
for (extruder_train_nr = 0; extruder_train_nr < extruder_count; extruder_train_nr++)
|
|
{ // initialize remaining extruder trains and load the defaults
|
|
meshgroup->createExtruderTrain(extruder_train_nr); // create new extruder train objects or use already existing ones
|
|
}
|
|
|
|
|
|
#ifndef DEBUG
|
|
try {
|
|
#endif
|
|
//Catch all exceptions, this prevents the "something went wrong" dialog on windows to pop up on a thrown exception.
|
|
// Only ClipperLib currently throws exceptions. And only in case that it makes an internal error.
|
|
meshgroup->finalize();
|
|
log("Loaded from disk in %5.3fs\n", FffProcessor::getInstance()->time_keeper.restart());
|
|
|
|
//start slicing
|
|
FffProcessor::getInstance()->processMeshGroup(meshgroup);
|
|
|
|
#ifndef DEBUG
|
|
}catch(...){
|
|
cura::logError("Unknown exception\n");
|
|
exit(1);
|
|
}
|
|
#endif
|
|
//Finalize the processor, this adds the end.gcode. And reports statistics.
|
|
FffProcessor::getInstance()->finalize();
|
|
|
|
delete meshgroup;
|
|
}
|
|
|
|
}//namespace cura
|
|
|
|
using namespace cura;
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
#if defined(__linux__) || (defined(__APPLE__) && defined(__MACH__))
|
|
//Lower the process priority on linux and mac. On windows this is done on process creation from the GUI.
|
|
setpriority(PRIO_PROCESS, 0, 10);
|
|
#endif
|
|
|
|
#ifndef DEBUG
|
|
//Register the exception handling for arithmic exceptions, this prevents the "something went wrong" dialog on windows to pop up on a division by zero.
|
|
signal(SIGFPE, signal_FPE);
|
|
#endif
|
|
|
|
Progress::init();
|
|
|
|
std::cerr << std::boolalpha;
|
|
logAlways("\n");
|
|
logAlways("Cura_SteamEngine version %s\n", VERSION);
|
|
logAlways("Copyright (C) 2014 David Braam\n");
|
|
logAlways("\n");
|
|
logAlways("This program is free software: you can redistribute it and/or modify\n");
|
|
logAlways("it under the terms of the GNU Affero General Public License as published by\n");
|
|
logAlways("the Free Software Foundation, either version 3 of the License, or\n");
|
|
logAlways("(at your option) any later version.\n");
|
|
logAlways("\n");
|
|
logAlways("This program is distributed in the hope that it will be useful,\n");
|
|
logAlways("but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
|
|
logAlways("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n");
|
|
logAlways("GNU Affero General Public License for more details.\n");
|
|
logAlways("\n");
|
|
logAlways("You should have received a copy of the GNU Affero General Public License\n");
|
|
logAlways("along with this program. If not, see <http://www.gnu.org/licenses/>.\n");
|
|
|
|
|
|
if (argc < 2)
|
|
{
|
|
print_usage();
|
|
exit(1);
|
|
}
|
|
|
|
if (stringcasecompare(argv[1], "connect") == 0)
|
|
{
|
|
connect(argc, argv);
|
|
}
|
|
else if (stringcasecompare(argv[1], "slice") == 0)
|
|
{
|
|
slice(argc, argv);
|
|
}
|
|
else if (stringcasecompare(argv[1], "help") == 0)
|
|
{
|
|
print_usage();
|
|
exit(0);
|
|
}
|
|
else if (stringcasecompare(argv[1], "analyse") == 0)
|
|
{ // CuraEngine analyse [json] [output.gv] [engine_settings] -[p|i|e|w]
|
|
// p = show parent-child relations
|
|
// i = show inheritance function
|
|
// e = show error functions
|
|
// w = show warning functions
|
|
// dot refl_ff.gv -Tpng > rafl_ff_dotted.png
|
|
// see meta/HOWTO.txt
|
|
|
|
bool parent_child_viz = false;
|
|
bool inherit_viz = false;
|
|
bool warning_viz = false;
|
|
bool error_viz = false;
|
|
bool global_only_viz = false;
|
|
if (argc >= 6)
|
|
{
|
|
char* str = argv[5];
|
|
if (str[0] == '-')
|
|
{
|
|
for(str++; *str; str++)
|
|
{
|
|
switch(*str)
|
|
{
|
|
case 'p':
|
|
parent_child_viz = true;
|
|
break;
|
|
case 'i':
|
|
inherit_viz = true;
|
|
break;
|
|
case 'e':
|
|
error_viz = true;
|
|
break;
|
|
case 'w':
|
|
warning_viz = true;
|
|
break;
|
|
case 'g':
|
|
global_only_viz = true;
|
|
break;
|
|
default:
|
|
cura::logError("Unknown option: %c\n", *str);
|
|
print_call(argc, argv);
|
|
print_usage();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cura::log("\n");
|
|
cura::log("usage:\n");
|
|
cura::log("CuraEngine analyse <fdmPrinter.def.json> <output.gv> <engine_settings_list> -[p|i|e|w]\n");
|
|
cura::log("\tGenerate a grpah to visualize the setting inheritance structure.\n");
|
|
cura::log("\t<fdmPrinter.def.json>\n\tThe base seting definitions file.\n");
|
|
cura::log("\t<output.gv>\n\tThe output file.\n");
|
|
cura::log("\t<engine_settings_list>\n\tA text file with all setting keys used in the engine, separated by newlines.\n");
|
|
cura::log("\t-[p|i|e|w]\n\tOptions for what to include in the visualization\n");
|
|
cura::log("\t\tp\tVisualize the parent-child relationship.\n");
|
|
cura::log("\t\ti\tVisualize inheritance function relationships.\n");
|
|
cura::log("\t\te\tVisualize (max/min) error function relationships.\n");
|
|
cura::log("\t\tw\tVisualize (max/min) warning function relationships.\n");
|
|
cura::log("\n");
|
|
|
|
}
|
|
|
|
SettingsToGv gv_out(argv[3], argv[4], parent_child_viz, inherit_viz, error_viz, warning_viz, global_only_viz);
|
|
if (gv_out.generate(std::string(argv[2])))
|
|
{
|
|
cura::logError("Failed to analyse json file: %s\n", argv[2]);
|
|
}
|
|
exit(0);
|
|
}
|
|
else
|
|
{
|
|
cura::logError("Unknown command: %s\n", argv[1]);
|
|
print_call(argc, argv);
|
|
print_usage();
|
|
exit(1);
|
|
}
|
|
|
|
return 0;
|
|
} |