6826581497
That needs to be a C-string.
418 linhas
14 KiB
C++
418 linhas
14 KiB
C++
#include "utils/logoutput.h"
|
|
#include "commandSocket.h"
|
|
#include "FffProcessor.h"
|
|
#include "Progress.h"
|
|
|
|
#include <thread>
|
|
#include <cinttypes>
|
|
|
|
#include <Arcus/Socket.h>
|
|
|
|
#include <string> // stoi
|
|
|
|
#ifdef _WIN32
|
|
#include <windows.h>
|
|
#endif
|
|
|
|
#define DEBUG_OUTPUT_OBJECT_STL_THROUGH_CERR(x)
|
|
// std::cerr << x;
|
|
|
|
namespace cura {
|
|
|
|
#define BYTES_PER_FLOAT 4
|
|
#define FLOATS_PER_VECTOR 3
|
|
#define VECTORS_PER_FACE 3
|
|
|
|
CommandSocket* CommandSocket::instance = nullptr; // instantiate instance
|
|
|
|
class CommandSocket::Private
|
|
{
|
|
public:
|
|
Private()
|
|
: socket(nullptr)
|
|
, object_count(0)
|
|
, current_sliced_object(nullptr)
|
|
, sliced_objects(0)
|
|
, current_layer_count(0)
|
|
, current_layer_offset(0)
|
|
{ }
|
|
|
|
cura::proto::Layer* getLayerById(int id);
|
|
|
|
Arcus::Socket* socket;
|
|
|
|
// Number of objects that need to be sliced
|
|
int object_count;
|
|
|
|
// Message that holds a list of sliced objects
|
|
std::shared_ptr<cura::proto::SlicedObjectList> sliced_object_list;
|
|
|
|
// Message that holds the currently sliced object (to be added to sliced_object_list)
|
|
cura::proto::SlicedObject* current_sliced_object;
|
|
|
|
// Number of sliced objects for this sliced object list
|
|
int sliced_objects;
|
|
|
|
// Number of layers sent to the front end so far
|
|
// Used for incrementing the current layer in one at a time mode
|
|
int current_layer_count;
|
|
int current_layer_offset;
|
|
|
|
// Ids of the sliced objects
|
|
std::vector<int64_t> object_ids;
|
|
|
|
std::string temp_gcode_file;
|
|
std::ostringstream gcode_output_stream;
|
|
|
|
// Print object that olds one or more meshes that need to be sliced.
|
|
std::vector< std::shared_ptr<MeshGroup> > objects_to_slice;
|
|
};
|
|
|
|
CommandSocket::CommandSocket()
|
|
: private_data(new Private)
|
|
{
|
|
}
|
|
|
|
CommandSocket* CommandSocket::getInstance()
|
|
{
|
|
return instance;
|
|
}
|
|
|
|
void CommandSocket::instantiate()
|
|
{
|
|
instance = new CommandSocket();
|
|
}
|
|
|
|
bool CommandSocket::isInstantiated()
|
|
{
|
|
return instance != nullptr;
|
|
}
|
|
|
|
|
|
void CommandSocket::connect(const std::string& ip, int port)
|
|
{
|
|
private_data->socket = new Arcus::Socket();
|
|
//private_data->socket->registerMessageType(1, &Cura::ObjectList::default_instance());
|
|
private_data->socket->registerMessageType(&cura::proto::Slice::default_instance());
|
|
private_data->socket->registerMessageType(&cura::proto::SlicedObjectList::default_instance());
|
|
private_data->socket->registerMessageType(&cura::proto::Progress::default_instance());
|
|
private_data->socket->registerMessageType(&cura::proto::GCodeLayer::default_instance());
|
|
private_data->socket->registerMessageType(&cura::proto::ObjectPrintTime::default_instance());
|
|
private_data->socket->registerMessageType(&cura::proto::SettingList::default_instance());
|
|
private_data->socket->registerMessageType(&cura::proto::GCodePrefix::default_instance());
|
|
private_data->socket->registerMessageType(&cura::proto::SlicingFinished::default_instance());
|
|
|
|
private_data->socket->connect(ip, port);
|
|
|
|
log("Connecting to %s:%i", ip.c_str(), port);
|
|
|
|
while(private_data->socket->getState() != Arcus::SocketState::Connected && private_data->socket->getState() != Arcus::SocketState::Error)
|
|
{
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
}
|
|
|
|
log("Connected to %s:%i", ip.c_str(), port);
|
|
|
|
bool slice_another_time = true;
|
|
|
|
// Start & continue listening as long as socket is not closed and there is no error.
|
|
while(private_data->socket->getState() != Arcus::SocketState::Closed && private_data->socket->getState() != Arcus::SocketState::Error && slice_another_time)
|
|
{
|
|
// Actually start handling messages.
|
|
Arcus::MessagePtr message = private_data->socket->takeNextMessage();
|
|
cura::proto::SettingList* setting_list = dynamic_cast<cura::proto::SettingList*>(message.get());
|
|
if(setting_list)
|
|
{
|
|
handleSettingList(setting_list);
|
|
}
|
|
|
|
/*cura::proto::ObjectList* object_list = dynamic_cast<cura::proto::ObjectList*>(message.get());
|
|
if(object_list)
|
|
{
|
|
handleObjectList(object_list);
|
|
}*/
|
|
|
|
cura::proto::Slice* slice = dynamic_cast<cura::proto::Slice*>(message.get());
|
|
if(slice)
|
|
{
|
|
// Reset object counts
|
|
private_data->object_count = 0;
|
|
private_data->object_ids.clear();
|
|
for(auto object : slice->object_lists())
|
|
{
|
|
handleObjectList(&object);
|
|
}
|
|
}
|
|
|
|
//If there is an object to slice, do so.
|
|
if(private_data->objects_to_slice.size())
|
|
{
|
|
FffProcessor::getInstance()->resetFileNumber();
|
|
for(auto object : private_data->objects_to_slice)
|
|
{
|
|
if(!FffProcessor::getInstance()->processMeshGroup(object.get()))
|
|
{
|
|
logError("Slicing mesh group failed!");
|
|
}
|
|
}
|
|
private_data->objects_to_slice.clear();
|
|
FffProcessor::getInstance()->finalize();
|
|
flushGcode();
|
|
sendPrintTime();
|
|
sendFinishedSlicing();
|
|
slice_another_time = false; // TODO: remove this when multiple slicing with CuraEngine is safe
|
|
//TODO: Support all-at-once/one-at-a-time printing
|
|
//private_data->processor->processModel(private_data->object_to_slice.get());
|
|
//private_data->object_to_slice.reset();
|
|
//private_data->processor->resetFileNumber();
|
|
|
|
//sendPrintTime();
|
|
}
|
|
|
|
if(private_data->socket->getLastError().isValid())
|
|
{
|
|
logError("%s\n", private_data->socket->getLastError().toString().c_str());
|
|
private_data->socket->clearError();
|
|
}
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(250));
|
|
}
|
|
|
|
private_data->socket->close();
|
|
}
|
|
|
|
void CommandSocket::handleObjectList(cura::proto::ObjectList* list)
|
|
{
|
|
if(list->objects_size() <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
FMatrix3x3 matrix;
|
|
//private_data->object_count = 0;
|
|
//private_data->object_ids.clear();
|
|
private_data->objects_to_slice.push_back(std::make_shared<MeshGroup>(FffProcessor::getInstance()));
|
|
MeshGroup* meshgroup = private_data->objects_to_slice.back().get();
|
|
|
|
for(auto setting : list->settings())
|
|
{
|
|
meshgroup->setSetting(setting.name(), setting.value());
|
|
}
|
|
|
|
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)->setExtruderTrainDefaults(extruder_nr); // create new extruder train objects or use already existing ones
|
|
}
|
|
|
|
for(auto object : list->objects())
|
|
{
|
|
int bytes_per_face = BYTES_PER_FLOAT * FLOATS_PER_VECTOR * VECTORS_PER_FACE;
|
|
int face_count = object.vertices().size() / bytes_per_face;
|
|
|
|
if(face_count <= 0)
|
|
{
|
|
logWarning("Got an empty mesh, ignoring it!");
|
|
continue;
|
|
}
|
|
DEBUG_OUTPUT_OBJECT_STL_THROUGH_CERR("solid Cura_out\n");
|
|
int extruder_train_nr = 0; // TODO: make primary extruder configurable!
|
|
for(auto setting : object.settings())
|
|
{
|
|
if (setting.name() == "extruder_nr")
|
|
{
|
|
extruder_train_nr = std::stoi(setting.value());
|
|
break;
|
|
}
|
|
}
|
|
SettingsBase* extruder_train = meshgroup->getExtruderTrain(extruder_train_nr);
|
|
|
|
meshgroup->meshes.push_back(extruder_train); //Construct a new mesh (with the corresponding extruder train as settings parent object) and put it into MeshGroup's mesh list.
|
|
Mesh& mesh = meshgroup->meshes.back();
|
|
|
|
for(int i = 0; i < face_count; ++i)
|
|
{
|
|
//TODO: Apply matrix
|
|
std::string data = object.vertices().substr(i * bytes_per_face, bytes_per_face);
|
|
const FPoint3* float_vertices = reinterpret_cast<const FPoint3*>(data.data());
|
|
|
|
Point3 verts[3];
|
|
verts[0] = matrix.apply(float_vertices[0]);
|
|
verts[1] = matrix.apply(float_vertices[1]);
|
|
verts[2] = matrix.apply(float_vertices[2]);
|
|
mesh.addFace(verts[0], verts[1], verts[2]);
|
|
|
|
DEBUG_OUTPUT_OBJECT_STL_THROUGH_CERR(" facet normal -1 0 0\n");
|
|
DEBUG_OUTPUT_OBJECT_STL_THROUGH_CERR(" outer loop\n");
|
|
DEBUG_OUTPUT_OBJECT_STL_THROUGH_CERR(" vertex "<<INT2MM(verts[0].x) <<" " << INT2MM(verts[0].y) <<" " << INT2MM(verts[0].z) << "\n");
|
|
DEBUG_OUTPUT_OBJECT_STL_THROUGH_CERR(" vertex "<<INT2MM(verts[1].x) <<" " << INT2MM(verts[1].y) <<" " << INT2MM(verts[1].z) << "\n");
|
|
DEBUG_OUTPUT_OBJECT_STL_THROUGH_CERR(" vertex "<<INT2MM(verts[2].x) <<" " << INT2MM(verts[2].y) <<" " << INT2MM(verts[2].z) << "\n");
|
|
DEBUG_OUTPUT_OBJECT_STL_THROUGH_CERR(" endloop\n");
|
|
DEBUG_OUTPUT_OBJECT_STL_THROUGH_CERR(" endfacet\n");
|
|
}
|
|
DEBUG_OUTPUT_OBJECT_STL_THROUGH_CERR("endsolid Cura_out\n");
|
|
for(auto setting : object.settings())
|
|
{
|
|
mesh.setSetting(setting.name(), setting.value());
|
|
}
|
|
|
|
private_data->object_ids.push_back(object.id());
|
|
mesh.finish();
|
|
}
|
|
|
|
private_data->object_count++;
|
|
meshgroup->finalize();
|
|
}
|
|
|
|
void CommandSocket::handleSettingList(cura::proto::SettingList* list)
|
|
{
|
|
for(auto setting : list->settings())
|
|
{
|
|
FffProcessor::getInstance()->setSetting(setting.name(), setting.value());
|
|
}
|
|
}
|
|
|
|
void CommandSocket::sendLayerInfo(int layer_nr, int32_t z, int32_t height)
|
|
{
|
|
if(!private_data->current_sliced_object)
|
|
{
|
|
return;
|
|
}
|
|
|
|
cura::proto::Layer* layer = private_data->getLayerById(layer_nr);
|
|
layer->set_height(z);
|
|
layer->set_thickness(height);
|
|
}
|
|
|
|
void CommandSocket::sendPolygons(PrintFeatureType type, int layer_nr, Polygons& polygons, int line_width)
|
|
{
|
|
if(!private_data->current_sliced_object)
|
|
return;
|
|
|
|
if (polygons.size() == 0)
|
|
return;
|
|
|
|
cura::proto::Layer* proto_layer = private_data->getLayerById(layer_nr);
|
|
|
|
for(unsigned int i = 0; i < polygons.size(); ++i)
|
|
{
|
|
cura::proto::Polygon* p = proto_layer->add_polygons();
|
|
p->set_type(static_cast<cura::proto::Polygon_Type>(type));
|
|
std::string polydata;
|
|
polydata.append(reinterpret_cast<const char*>(polygons[i].data()), polygons[i].size() * sizeof(Point));
|
|
p->set_points(polydata);
|
|
p->set_line_width(line_width);
|
|
}
|
|
}
|
|
|
|
void CommandSocket::sendProgress(float amount)
|
|
{
|
|
auto message = std::make_shared<cura::proto::Progress>();
|
|
amount /= private_data->object_count;
|
|
amount += private_data->sliced_objects * (1. / private_data->object_count);
|
|
message->set_amount(amount);
|
|
private_data->socket->sendMessage(message);
|
|
}
|
|
|
|
void CommandSocket::sendProgressStage(Progress::Stage stage)
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
void CommandSocket::sendPrintTime()
|
|
{
|
|
auto message = std::make_shared<cura::proto::ObjectPrintTime>();
|
|
message->set_time(FffProcessor::getInstance()->getTotalPrintTime());
|
|
message->set_material_amount(FffProcessor::getInstance()->getTotalFilamentUsed(0));
|
|
private_data->socket->sendMessage(message);
|
|
}
|
|
|
|
void CommandSocket::sendPrintMaterialForObject(int index, int extruder_nr, float print_time)
|
|
{
|
|
// socket.sendInt32(CMD_OBJECT_PRINT_MATERIAL);
|
|
// socket.sendInt32(12);
|
|
// socket.sendInt32(index);
|
|
// socket.sendInt32(extruder_nr);
|
|
// socket.sendFloat32(print_time);
|
|
}
|
|
|
|
void CommandSocket::beginSendSlicedObject()
|
|
{
|
|
if(!private_data->sliced_object_list)
|
|
{
|
|
private_data->sliced_object_list = std::make_shared<cura::proto::SlicedObjectList>();
|
|
}
|
|
|
|
private_data->current_sliced_object = private_data->sliced_object_list->add_objects();
|
|
private_data->current_sliced_object->set_id(private_data->object_ids[private_data->sliced_objects]);
|
|
}
|
|
|
|
void CommandSocket::endSendSlicedObject()
|
|
{
|
|
private_data->sliced_objects++;
|
|
private_data->current_layer_offset = private_data->current_layer_count;
|
|
std::cout << "End sliced object called. Sliced objects " << private_data->sliced_objects << " object count: " << private_data->object_count << std::endl;
|
|
|
|
if(private_data->sliced_objects >= private_data->object_count)
|
|
{
|
|
private_data->socket->sendMessage(private_data->sliced_object_list);
|
|
private_data->sliced_objects = 0;
|
|
private_data->current_layer_count = 0;
|
|
private_data->current_layer_offset = 0;
|
|
private_data->sliced_object_list.reset();
|
|
private_data->current_sliced_object = nullptr;
|
|
auto done_message = std::make_shared<cura::proto::SlicingFinished>();
|
|
private_data->socket->sendMessage(done_message);
|
|
}
|
|
}
|
|
|
|
void CommandSocket::sendFinishedSlicing()
|
|
{
|
|
std::shared_ptr<cura::proto::SlicingFinished> done_message = std::make_shared<cura::proto::SlicingFinished>();
|
|
private_data->socket->sendMessage(done_message);
|
|
}
|
|
|
|
void CommandSocket::beginGCode()
|
|
{
|
|
FffProcessor::getInstance()->setTargetStream(&private_data->gcode_output_stream);
|
|
}
|
|
|
|
void CommandSocket::flushGcode()
|
|
{
|
|
auto message = std::make_shared<cura::proto::GCodeLayer>();
|
|
message->set_id(private_data->object_ids[0]);
|
|
message->set_data(private_data->gcode_output_stream.str());
|
|
private_data->socket->sendMessage(message);
|
|
|
|
private_data->gcode_output_stream.str("");
|
|
}
|
|
|
|
void CommandSocket::sendGCodePrefix(std::string prefix)
|
|
{
|
|
auto message = std::make_shared<cura::proto::GCodePrefix>();
|
|
message->set_data(prefix);
|
|
private_data->socket->sendMessage(message);
|
|
}
|
|
|
|
cura::proto::Layer* CommandSocket::Private::getLayerById(int id)
|
|
{
|
|
id += current_layer_offset;
|
|
|
|
auto itr = std::find_if(current_sliced_object->mutable_layers()->begin(), current_sliced_object->mutable_layers()->end(), [id](cura::proto::Layer& l) { return l.id() == id; });
|
|
|
|
cura::proto::Layer* layer = nullptr;
|
|
if(itr != current_sliced_object->mutable_layers()->end())
|
|
{
|
|
layer = &(*itr);
|
|
}
|
|
else
|
|
{
|
|
layer = current_sliced_object->add_layers();
|
|
layer->set_id(id);
|
|
current_layer_count++;
|
|
}
|
|
|
|
return layer;
|
|
}
|
|
|
|
}//namespace cura
|