void FffPolygonGenerator::processDraftShield(SliceDataStorage& storage, unsigned int totalLayers) { int draft_shield_height = getSettingInMicrons("draft_shield_height"); int draft_shield_dist = getSettingInMicrons("draft_shield_dist"); int layer_height_0 = getSettingInMicrons("layer_height_0"); int layer_height = getSettingInMicrons("layer_height"); if (draft_shield_height < layer_height_0) { return; } unsigned int max_screen_layer = (draft_shield_height - layer_height_0) / layer_height + 1; int layer_skip = 500 / layer_height + 1; Polygons& draft_shield = storage.draft_protection_shield; for (unsigned int layer_nr = 0; layer_nr < totalLayers && layer_nr < max_screen_layer; layer_nr += layer_skip) { for (SliceMeshStorage& mesh : storage.meshes) { for (SliceLayerPart& part : mesh.layers[layer_nr].parts) { draft_shield = draft_shield.unionPolygons(part.outline); } } draft_shield = draft_shield.unionPolygons(storage.support.supportLayers[layer_nr].supportAreas); // draft_shield = draft_shield.unionPolygons(storage.support.supportLayers[layer_nr].roofs); // will already be included by supportAreas below, and if the roof is at a low level, the screen will most likely avoid it at a higher level } storage.draft_protection_shield = draft_shield.convexHull(draft_shield_dist); }
void FffPolygonGenerator::processOozeShield(SliceDataStorage& storage, unsigned int total_layers) { if (!getSettingBoolean("ooze_shield_enabled")) { return; } int ooze_shield_dist = getSettingInMicrons("ooze_shield_dist"); for(unsigned int layer_nr=0; layer_nr<total_layers; layer_nr++) { storage.oozeShield.push_back(storage.getLayerOutlines(layer_nr, true).offset(ooze_shield_dist)); } int largest_printed_radius = MM2INT(1.0); // TODO: make var a parameter, and perhaps even a setting? for(unsigned int layer_nr=0; layer_nr<total_layers; layer_nr++) { storage.oozeShield[layer_nr] = storage.oozeShield[layer_nr].offset(-largest_printed_radius).offset(largest_printed_radius); } int allowed_angle_offset = tan(getSettingInAngleRadians("ooze_shield_angle")) * getSettingInMicrons("layer_height");//Allow for a 60deg angle in the oozeShield. for(unsigned int layer_nr=1; layer_nr<total_layers; layer_nr++) { storage.oozeShield[layer_nr] = storage.oozeShield[layer_nr].unionPolygons(storage.oozeShield[layer_nr-1].offset(-allowed_angle_offset)); } for(unsigned int layer_nr=total_layers-1; layer_nr>0; layer_nr--) { storage.oozeShield[layer_nr-1] = storage.oozeShield[layer_nr-1].unionPolygons(storage.oozeShield[layer_nr].offset(-allowed_angle_offset)); } }
void FffPolygonGenerator::processOozeShield(SliceDataStorage& storage, unsigned int totalLayers) { if (!getSettingBoolean("ooze_shield_enabled")) { return; } int ooze_shield_dist = getSettingInMicrons("ooze_shield_dist"); for(unsigned int layer_nr=0; layer_nr<totalLayers; layer_nr++) { Polygons oozeShield; for(SliceMeshStorage& mesh : storage.meshes) { for(SliceLayerPart& part : mesh.layers[layer_nr].parts) { oozeShield = oozeShield.unionPolygons(part.outline.offset(ooze_shield_dist)); } } storage.oozeShield.push_back(oozeShield); } int largest_printed_radius = MM2INT(1.0); // TODO: make var a parameter, and perhaps even a setting? for(unsigned int layer_nr=0; layer_nr<totalLayers; layer_nr++) storage.oozeShield[layer_nr] = storage.oozeShield[layer_nr].offset(-largest_printed_radius).offset(largest_printed_radius); int offsetAngle = tan(getSettingInAngleRadians("ooze_shield_angle")) * getSettingInMicrons("layer_height");//Allow for a 60deg angle in the oozeShield. for(unsigned int layer_nr=1; layer_nr<totalLayers; layer_nr++) storage.oozeShield[layer_nr] = storage.oozeShield[layer_nr].unionPolygons(storage.oozeShield[layer_nr-1].offset(-offsetAngle)); for(unsigned int layer_nr=totalLayers-1; layer_nr>0; layer_nr--) storage.oozeShield[layer_nr-1] = storage.oozeShield[layer_nr-1].unionPolygons(storage.oozeShield[layer_nr].offset(-offsetAngle)); }
void FffPolygonGenerator::processPlatformAdhesion(SliceDataStorage& storage) { switch(getSettingAsPlatformAdhesion("adhesion_type")) { case EPlatformAdhesion::SKIRT: if (getSettingInMicrons("draft_shield_height") == 0) { // draft screen replaces skirt generateSkirt(storage, getSettingInMicrons("skirt_gap"), getSettingAsCount("skirt_line_count"), getSettingInMicrons("skirt_minimal_length")); } break; case EPlatformAdhesion::BRIM: generateSkirt(storage, 0, getSettingAsCount("brim_line_count"), getSettingInMicrons("skirt_minimal_length")); break; case EPlatformAdhesion::RAFT: generateRaft(storage, getSettingInMicrons("raft_margin")); break; } Polygons skirt_sent = storage.skirt[0]; for (int extruder = 1; extruder < storage.meshgroup->getExtruderCount(); extruder++) skirt_sent.add(storage.skirt[extruder]); }
void FffPolygonGenerator::processDraftShield(SliceDataStorage& storage, unsigned int total_layers) { int draft_shield_height = getSettingInMicrons("draft_shield_height"); int draft_shield_dist = getSettingInMicrons("draft_shield_dist"); int layer_height_0 = getSettingInMicrons("layer_height_0"); int layer_height = getSettingInMicrons("layer_height"); if (draft_shield_height < layer_height_0) { return; } unsigned int max_screen_layer = (draft_shield_height - layer_height_0) / layer_height + 1; int layer_skip = 500 / layer_height + 1; Polygons& draft_shield = storage.draft_protection_shield; for (unsigned int layer_nr = 0; layer_nr < total_layers && layer_nr < max_screen_layer; layer_nr += layer_skip) { draft_shield = draft_shield.unionPolygons(storage.getLayerOutlines(layer_nr, true)); } storage.draft_protection_shield = draft_shield.convexHull(draft_shield_dist); }
void FffPolygonGenerator::processPlatformAdhesion(SliceDataStorage& storage) { switch(getSettingAsPlatformAdhesion("adhesion_type")) { case Adhesion_Skirt: if (getSettingInMicrons("draft_shield_height") == 0) { // draft screen replaces skirt generateSkirt(storage, getSettingInMicrons("skirt_gap"), getSettingInMicrons("skirt_line_width"), getSettingAsCount("skirt_line_count"), getSettingInMicrons("skirt_minimal_length")); } break; case Adhesion_Brim: generateSkirt(storage, 0, getSettingInMicrons("skirt_line_width"), getSettingAsCount("brim_line_count"), getSettingInMicrons("skirt_minimal_length")); break; case Adhesion_Raft: generateRaft(storage, getSettingInMicrons("raft_margin")); break; } sendPolygons(SkirtType, 0, storage.skirt, getSettingInMicrons("skirt_line_width")); }
bool FffPolygonGenerator::sliceModel(PrintObject* object, TimeKeeper& timeKeeper, SliceDataStorage& storage) /// slices the model { Progress::messageProgressStage(Progress::Stage::SLICING, &timeKeeper, commandSocket); storage.model_min = object->min(); storage.model_max = object->max(); storage.model_size = storage.model_max - storage.model_min; log("Slicing model...\n"); int initial_layer_thickness = object->getSettingInMicrons("layer_height_0"); int layer_thickness = object->getSettingInMicrons("layer_height"); if (object->getSettingAsPlatformAdhesion("adhesion_type") == Adhesion_Raft) { initial_layer_thickness = layer_thickness; } int initial_slice_z = initial_layer_thickness - layer_thickness / 2; int layer_count = (storage.model_max.z - initial_slice_z) / layer_thickness + 1; std::vector<Slicer*> slicerList; for(unsigned int mesh_idx = 0; mesh_idx < object->meshes.size(); mesh_idx++) { Mesh& mesh = object->meshes[mesh_idx]; Slicer* slicer = new Slicer(&mesh, initial_slice_z, layer_thickness, layer_count, mesh.getSettingBoolean("meshfix_keep_open_polygons"), mesh.getSettingBoolean("meshfix_extensive_stitching")); slicerList.push_back(slicer); /* for(SlicerLayer& layer : slicer->layers) { //Reporting the outline here slows down the engine quite a bit, so only do so when debugging. //sendPolygons("outline", layer_nr, layer.z, layer.polygonList); //sendPolygons("openoutline", layer_nr, layer.openPolygonList); } */ Progress::messageProgress(Progress::Stage::SLICING, mesh_idx + 1, object->meshes.size(), commandSocket); } log("Layer count: %i\n", layer_count); object->clear();///Clear the mesh data, it is no longer needed after this point, and it saves a lot of memory. Progress::messageProgressStage(Progress::Stage::PARTS, &timeKeeper, commandSocket); //carveMultipleVolumes(storage.meshes); generateMultipleVolumesOverlap(slicerList, getSettingInMicrons("multiple_mesh_overlap")); for(unsigned int meshIdx=0; meshIdx < slicerList.size(); meshIdx++) { storage.meshes.emplace_back(&object->meshes[meshIdx]); SliceMeshStorage& meshStorage = storage.meshes[meshIdx]; createLayerParts(meshStorage, slicerList[meshIdx], meshStorage.settings->getSettingBoolean("meshfix_union_all"), meshStorage.settings->getSettingBoolean("meshfix_union_all_remove_holes")); delete slicerList[meshIdx]; bool has_raft = meshStorage.settings->getSettingAsPlatformAdhesion("adhesion_type") == Adhesion_Raft; //Add the raft offset to each layer. for(unsigned int layer_nr=0; layer_nr<meshStorage.layers.size(); layer_nr++) { SliceLayer& layer = meshStorage.layers[layer_nr]; if (has_raft) { layer.printZ += meshStorage.settings->getSettingInMicrons("raft_base_thickness") + meshStorage.settings->getSettingInMicrons("raft_interface_thickness") + meshStorage.settings->getSettingAsCount("raft_surface_layers") * getSettingInMicrons("layer_height") //raft_surface_thickness") + meshStorage.settings->getSettingInMicrons("raft_airgap") - initial_slice_z; } else { meshStorage.layers[layer_nr].printZ += meshStorage.settings->getSettingInMicrons("layer_height_0") - initial_slice_z; } if (layer.parts.size() > 0) { meshStorage.layer_nr_max_filled_layer = layer_nr; // last set by the highest non-empty layer } if (commandSocket) commandSocket->sendLayerInfo(layer_nr, layer.printZ, layer_nr == 0 && !has_raft? meshStorage.settings->getSettingInMicrons("layer_height_0") : meshStorage.settings->getSettingInMicrons("layer_height")); } Progress::messageProgress(Progress::Stage::PARTS, meshIdx + 1, slicerList.size(), commandSocket); } Progress::messageProgressStage(Progress::Stage::INSET, &timeKeeper, commandSocket); return true; }
void FffPolygonGenerator::processWipeTower(SliceDataStorage& storage, unsigned int totalLayers) { // TODO: move this code into its own function? { // compute storage.max_object_height_second_to_last_extruder, which is used to determine the highest point in the wipe tower int max_object_height_per_extruder[MAX_EXTRUDERS]; { // compute max_object_height_per_extruder memset(max_object_height_per_extruder, -1, sizeof(max_object_height_per_extruder)); for (SliceMeshStorage& mesh : storage.meshes) { max_object_height_per_extruder[mesh.settings->getSettingAsIndex("extruder_nr")] = std::max( max_object_height_per_extruder[mesh.settings->getSettingAsIndex("extruder_nr")] , mesh.layer_nr_max_filled_layer ); } int support_extruder_nr = getSettingAsIndex("support_extruder_nr"); max_object_height_per_extruder[support_extruder_nr] = std::max( max_object_height_per_extruder[support_extruder_nr] , storage.support.layer_nr_max_filled_layer ); } { // // compute max_object_height_second_to_last_extruder int extruder_max_object_height = 0; for (unsigned int extruder_nr = 1; extruder_nr < MAX_EXTRUDERS; extruder_nr++) { if (max_object_height_per_extruder[extruder_nr] > max_object_height_per_extruder[extruder_max_object_height]) { extruder_max_object_height = extruder_nr; } } int extruder_second_max_object_height = -1; for (int extruder_nr = 0; extruder_nr < MAX_EXTRUDERS; extruder_nr++) { if (extruder_nr == extruder_max_object_height) { continue; } if (max_object_height_per_extruder[extruder_nr] > max_object_height_per_extruder[extruder_second_max_object_height]) { extruder_second_max_object_height = extruder_nr; } } if (extruder_second_max_object_height < 0) { storage.max_object_height_second_to_last_extruder = -1; } else { storage.max_object_height_second_to_last_extruder = max_object_height_per_extruder[extruder_second_max_object_height]; } } } if (storage.max_object_height_second_to_last_extruder >= 0 && getSettingInMicrons("wipe_tower_distance") > 0 && getSettingInMicrons("wipe_tower_size") > 0) { PolygonRef p = storage.wipeTower.newPoly(); int tower_size = getSettingInMicrons("wipe_tower_size"); int tower_distance = getSettingInMicrons("wipe_tower_distance"); p.add(Point(storage.model_min.x - tower_distance, storage.model_max.y + tower_distance)); p.add(Point(storage.model_min.x - tower_distance, storage.model_max.y + tower_distance + tower_size)); p.add(Point(storage.model_min.x - tower_distance - tower_size, storage.model_max.y + tower_distance + tower_size)); p.add(Point(storage.model_min.x - tower_distance - tower_size, storage.model_max.y + tower_distance)); storage.wipePoint = Point(storage.model_min.x - tower_distance - tower_size / 2, storage.model_max.y + tower_distance + tower_size / 2); } }
void FffPolygonGenerator::slices2polygons(SliceDataStorage& storage, TimeKeeper& time_keeper) { if (commandSocket) commandSocket->beginSendSlicedObject(); // const unsigned int total_layers = storage.meshes.at(0).layers.size(); //layerparts2HTML(storage, "output/output.html"); for(unsigned int layer_number = 0; layer_number < total_layers; layer_number++) { processInsets(storage, layer_number); Progress::messageProgress(Progress::Stage::INSET, layer_number+1, total_layers, commandSocket); } removeEmptyFirstLayers(storage, getSettingInMicrons("layer_height"), total_layers); if (total_layers < 1) { log("Stopping process because there are no layers.\n"); return; } processOozeShield(storage, total_layers); Progress::messageProgressStage(Progress::Stage::SUPPORT, &time_keeper, commandSocket); for(SliceMeshStorage& mesh : storage.meshes) { generateSupportAreas(storage, &mesh, total_layers, commandSocket); for (unsigned int layer_idx = 0; layer_idx < total_layers; layer_idx++) { Polygons& support = storage.support.supportLayers[layer_idx].supportAreas; sendPolygons(SupportType, layer_idx, support, getSettingInMicrons("support_line_width")); } } if (getSettingBoolean("support_roof_enable")) { generateSupportRoofs(storage, commandSocket, getSettingInMicrons("layer_height"), getSettingInMicrons("support_roof_height")); } Progress::messageProgressStage(Progress::Stage::SKIN, &time_keeper, commandSocket); for(unsigned int layer_number = 0; layer_number < total_layers; layer_number++) { if (!getSettingBoolean("magic_spiralize") || static_cast<int>(layer_number) < getSettingAsCount("bottom_layers")) //Only generate up/downskin and infill for the first X layers when spiralize is choosen. { processSkins(storage, layer_number); } Progress::messageProgress(Progress::Stage::SKIN, layer_number+1, total_layers, commandSocket); } for(unsigned int layer_number = total_layers-1; layer_number > 0; layer_number--) { for(SliceMeshStorage& mesh : storage.meshes) combineSparseLayers(layer_number, mesh, mesh.settings->getSettingAsCount("fill_sparse_combine")); } processWipeTower(storage, total_layers); processDraftShield(storage, total_layers); processPlatformAdhesion(storage); }
void LayerPlanBuffer::flush() { if (buffer.size() > 0) { insertPreheatCommands(); // insert preheat commands of the very last layer } while (!buffer.empty()) { buffer.front().writeGCode(gcode, getSettingBoolean("cool_lift_head"), buffer.front().getLayerNr() > 0 ? getSettingInMicrons("layer_height") : getSettingInMicrons("layer_height_0")); if (CommandSocket::isInstantiated()) { CommandSocket::getInstance()->flushGcode(); } buffer.pop_front(); } }
void FffPolygonGenerator::slices2polygons(SliceDataStorage& storage, TimeKeeper& time_keeper) { size_t total_layers = 0; for (SliceMeshStorage& mesh : storage.meshes) { total_layers = std::max<unsigned int>(total_layers, mesh.layers.size()); } //layerparts2HTML(storage, "output/output.html"); for(unsigned int layer_number = 0; layer_number < total_layers; layer_number++) { processInsets(storage, layer_number); Progress::messageProgress(Progress::Stage::INSET, layer_number+1, total_layers, commandSocket); } removeEmptyFirstLayers(storage, getSettingInMicrons("layer_height"), total_layers); if (total_layers < 1) { log("Stopping process because there are no layers.\n"); return; } Progress::messageProgressStage(Progress::Stage::SUPPORT, &time_keeper, commandSocket); AreaSupport::generateSupportAreas(storage, total_layers, commandSocket); /* if (storage.support.generated) { for (unsigned int layer_idx = 0; layer_idx < total_layers; layer_idx++) { Polygons& support = storage.support.supportLayers[layer_idx].supportAreas; sendPolygons(SupportType, layer_idx, support, getSettingInMicrons("support_line_width")); } } */ Progress::messageProgressStage(Progress::Stage::SKIN, &time_keeper, commandSocket); int mesh_max_bottom_layer_count = 0; if (getSettingBoolean("magic_spiralize")) { for(SliceMeshStorage& mesh : storage.meshes) { mesh_max_bottom_layer_count = std::max(mesh_max_bottom_layer_count, mesh.getSettingAsCount("bottom_layers")); } } for(unsigned int layer_number = 0; layer_number < total_layers; layer_number++) { if (!getSettingBoolean("magic_spiralize") || static_cast<int>(layer_number) < mesh_max_bottom_layer_count) //Only generate up/downskin and infill for the first X layers when spiralize is choosen. { processSkins(storage, layer_number); } Progress::messageProgress(Progress::Stage::SKIN, layer_number+1, total_layers, commandSocket); } for(unsigned int layer_number = total_layers-1; layer_number > 0; layer_number--) { for(SliceMeshStorage& mesh : storage.meshes) combineInfillLayers(layer_number, mesh, mesh.getSettingAsCount("infill_sparse_combine")); } storage.primeTower.computePrimeTowerMax(storage); storage.primeTower.generatePaths(storage, total_layers); processOozeShield(storage, total_layers); processDraftShield(storage, total_layers); processPlatformAdhesion(storage); for(SliceMeshStorage& mesh : storage.meshes) { if (mesh.getSettingBoolean("magic_fuzzy_skin_enabled")) { processFuzzyWalls(mesh); } else { // only send polygon data for (unsigned int layer_nr = 0; layer_nr < total_layers; layer_nr++) { SliceLayer* layer = &mesh.layers[layer_nr]; for(SliceLayerPart& part : layer->parts) { sendPolygons(Inset0Type, layer_nr, (mesh.getSettingAsSurfaceMode("magic_mesh_surface_mode") == ESurfaceMode::SURFACE)? part.outline : part.insets[0], mesh.getSettingInMicrons("wall_line_width_0")); } } } } }
bool FffPolygonGenerator::sliceModel(MeshGroup* meshgroup, TimeKeeper& timeKeeper, SliceDataStorage& storage) /// slices the model { Progress::messageProgressStage(Progress::Stage::SLICING, &timeKeeper); storage.model_min = meshgroup->min(); storage.model_max = meshgroup->max(); storage.model_size = storage.model_max - storage.model_min; log("Slicing model...\n"); int initial_layer_thickness = getSettingInMicrons("layer_height_0"); if(initial_layer_thickness <= 0) //Initial layer height of 0 is not allowed. Negative layer height is nonsense. { logError("Initial layer height %i is disallowed.",initial_layer_thickness); return false; } int layer_thickness = getSettingInMicrons("layer_height"); if(layer_thickness <= 0) //Layer height of 0 is not allowed. Negative layer height is nonsense. { logError("Layer height %i is disallowed.",layer_thickness); return false; } int initial_slice_z = initial_layer_thickness - layer_thickness / 2; int layer_count = (storage.model_max.z - initial_slice_z) / layer_thickness + 1; if(layer_count <= 0) //Model is shallower than layer_height_0, so not even the first layer is sliced. Return an empty model then. { return true; //This is NOT an error state! } std::vector<Slicer*> slicerList; for(unsigned int mesh_idx = 0; mesh_idx < meshgroup->meshes.size(); mesh_idx++) { Mesh& mesh = meshgroup->meshes[mesh_idx]; Slicer* slicer = new Slicer(&mesh, initial_slice_z, layer_thickness, layer_count, mesh.getSettingBoolean("meshfix_keep_open_polygons"), mesh.getSettingBoolean("meshfix_extensive_stitching")); slicerList.push_back(slicer); /* for(SlicerLayer& layer : slicer->layers) { //Reporting the outline here slows down the engine quite a bit, so only do so when debugging. sendPolygons("outline", layer_nr, layer.z, layer.polygonList); sendPolygons("openoutline", layer_nr, layer.openPolygonList); } */ Progress::messageProgress(Progress::Stage::SLICING, mesh_idx + 1, meshgroup->meshes.size()); } log("Layer count: %i\n", layer_count); meshgroup->clear();///Clear the mesh face and vertex data, it is no longer needed after this point, and it saves a lot of memory. Progress::messageProgressStage(Progress::Stage::PARTS, &timeKeeper); //carveMultipleVolumes(storage.meshes); generateMultipleVolumesOverlap(slicerList); // TODO!!! dont generate multi volume overlap with infill meshes! storage.meshes.reserve(slicerList.size()); // causes there to be no resize in meshes so that the pointers in sliceMeshStorage._config to retraction_config don't get invalidated. for(unsigned int meshIdx=0; meshIdx < slicerList.size(); meshIdx++) { storage.meshes.emplace_back(&meshgroup->meshes[meshIdx]); // new mesh in storage had settings from the Mesh SliceMeshStorage& meshStorage = storage.meshes.back(); Mesh& mesh = storage.meshgroup->meshes[meshIdx]; createLayerParts(meshStorage, slicerList[meshIdx], mesh.getSettingBoolean("meshfix_union_all"), mesh.getSettingBoolean("meshfix_union_all_remove_holes")); delete slicerList[meshIdx]; bool has_raft = meshStorage.getSettingAsPlatformAdhesion("adhesion_type") == EPlatformAdhesion::RAFT; //Add the raft offset to each layer. for(unsigned int layer_nr=0; layer_nr<meshStorage.layers.size(); layer_nr++) { SliceLayer& layer = meshStorage.layers[layer_nr]; meshStorage.layers[layer_nr].printZ += getSettingInMicrons("layer_height_0") - initial_slice_z; if (has_raft) { ExtruderTrain* train = storage.meshgroup->getExtruderTrain(getSettingAsIndex("adhesion_extruder_nr")); layer.printZ += train->getSettingInMicrons("raft_base_thickness") + train->getSettingInMicrons("raft_interface_thickness") + train->getSettingAsCount("raft_surface_layers") * getSettingInMicrons("raft_surface_thickness") + train->getSettingInMicrons("raft_airgap") - train->getSettingInMicrons("layer_0_z_overlap"); // shift all layers (except 0) down if (layer_nr == 0) { layer.printZ += train->getSettingInMicrons("layer_0_z_overlap"); // undo shifting down of first layer } } if (layer.parts.size() > 0 || (mesh.getSettingAsSurfaceMode("magic_mesh_surface_mode") != ESurfaceMode::NORMAL && layer.openPolyLines.size() > 0) ) { meshStorage.layer_nr_max_filled_layer = layer_nr; // last set by the highest non-empty layer } if (CommandSocket::isInstantiated()) { CommandSocket::getInstance()->sendLayerInfo(layer_nr, layer.printZ, layer_nr == 0? getSettingInMicrons("layer_height_0") : getSettingInMicrons("layer_height")); } } Progress::messageProgress(Progress::Stage::PARTS, meshIdx + 1, slicerList.size()); } return true; }
void FffPolygonGenerator::slices2polygons(SliceDataStorage& storage, TimeKeeper& time_keeper) { // compute layer count and remove first empty layers // there is no separate progress stage for removeEmptyFisrtLayer (TODO) unsigned int total_layers = 0; for (SliceMeshStorage& mesh : storage.meshes) { if (!mesh.getSettingBoolean("infill_mesh")) { total_layers = std::max<unsigned int>(total_layers, mesh.layers.size()); } } // handle meshes std::vector<double> mesh_timings; for (unsigned int mesh_idx = 0; mesh_idx < storage.meshes.size(); mesh_idx++) { mesh_timings.push_back(1.0); // TODO: have a more accurate estimate of the relative time it takes per mesh, based on the height and number of polygons } ProgressStageEstimator inset_skin_progress_estimate(mesh_timings); Progress::messageProgressStage(Progress::Stage::INSET_SKIN, &time_keeper); std::vector<unsigned int> mesh_order; { // compute mesh order std::multimap<int, unsigned int> order_to_mesh_indices; for (unsigned int mesh_idx = 0; mesh_idx < storage.meshes.size(); mesh_idx++) { order_to_mesh_indices.emplace(storage.meshes[mesh_idx].getSettingAsIndex("infill_mesh_order"), mesh_idx); } for (std::pair<const int, unsigned int>& order_and_mesh_idx : order_to_mesh_indices) { mesh_order.push_back(order_and_mesh_idx.second); } } for (unsigned int mesh_idx : mesh_order) { processBasicWallsSkinInfill(storage, mesh_idx, mesh_order, total_layers, inset_skin_progress_estimate); Progress::messageProgress(Progress::Stage::INSET_SKIN, mesh_idx + 1, storage.meshes.size()); } //layerparts2HTML(storage, "output/output.html"); // we need to remove empty layers after we have procesed the insets // processInsets might throw away parts if they have no wall at all (cause it doesn't fit) // brim depends on the first layer not being empty removeEmptyFirstLayers(storage, getSettingInMicrons("layer_height"), total_layers); // changes total_layers! if (total_layers == 0) { log("Stopping process because there are no non-empty layers.\n"); return; } Progress::messageProgressStage(Progress::Stage::SUPPORT, &time_keeper); AreaSupport::generateSupportAreas(storage, total_layers); /* if (storage.support.generated) { for (unsigned int layer_idx = 0; layer_idx < total_layers; layer_idx++) { Polygons& support = storage.support.supportLayers[layer_idx].supportAreas; if (CommandSocket::isInstantiated()) { CommandSocket::getInstance()->sendPolygons(PrintFeatureType::Infill, layer_idx, support, 100); //getSettingInMicrons("support_line_width")); } } } */ // handle helpers storage.primeTower.computePrimeTowerMax(storage); storage.primeTower.generatePaths(storage, total_layers); processOozeShield(storage, total_layers); processDraftShield(storage, total_layers); processPlatformAdhesion(storage); // meshes post processing for (SliceMeshStorage& mesh : storage.meshes) { processDerivedWallsSkinInfill(mesh, total_layers); } }
void FffPolygonGenerator::processDerivedWallsSkinInfill(SliceMeshStorage& mesh, size_t total_layers) { // combine infill unsigned int combined_infill_layers = mesh.getSettingInMicrons("infill_sparse_thickness") / std::max(getSettingInMicrons("layer_height"), 1); //How many infill layers to combine to obtain the requested sparse thickness. combineInfillLayers(mesh,combined_infill_layers); // fuzzy skin if (mesh.getSettingBoolean("magic_fuzzy_skin_enabled")) { processFuzzyWalls(mesh); } }
void MeshGroup::finalize() { extruder_count = getSettingAsCount("machine_extruder_count"); for (int extruder_nr = 0; extruder_nr < extruder_count; extruder_nr++) { createExtruderTrain(extruder_nr); // create it if it didn't exist yet if (getSettingAsIndex("adhesion_extruder_nr") == extruder_nr && getSettingAsPlatformAdhesion("adhesion_type") != EPlatformAdhesion::NONE) { getExtruderTrain(extruder_nr)->setIsUsed(true); continue; } for (const Mesh& mesh : meshes) { if (mesh.getSettingBoolean("support_enable") && ( getSettingAsIndex("support_infill_extruder_nr") == extruder_nr || getSettingAsIndex("support_extruder_nr_layer_0") == extruder_nr || (getSettingBoolean("support_interface_enable") && getSettingAsIndex("support_interface_extruder_nr") == extruder_nr) ) ) { getExtruderTrain(extruder_nr)->setIsUsed(true); break; } } } for (const Mesh& mesh : meshes) { if (!mesh.getSettingBoolean("anti_overhang_mesh") && !mesh.getSettingBoolean("support_mesh") ) { getExtruderTrain(mesh.getSettingAsIndex("extruder_nr"))->setIsUsed(true); } } //If the machine settings have been supplied, offset the given position vertices to the center of vertices (0,0,0) is at the bed center. Point3 meshgroup_offset(0, 0, 0); if (!getSettingBoolean("machine_center_is_zero")) { meshgroup_offset.x = getSettingInMicrons("machine_width") / 2; meshgroup_offset.y = getSettingInMicrons("machine_depth") / 2; } // If a mesh position was given, put the mesh at this position in 3D space. for(Mesh& mesh : meshes) { Point3 mesh_offset(mesh.getSettingInMicrons("mesh_position_x"), mesh.getSettingInMicrons("mesh_position_y"), mesh.getSettingInMicrons("mesh_position_z")); if (mesh.getSettingBoolean("center_object")) { Point3 object_min = mesh.min(); Point3 object_max = mesh.max(); Point3 object_size = object_max - object_min; mesh_offset += Point3(-object_min.x - object_size.x / 2, -object_min.y - object_size.y / 2, -object_min.z); } mesh.offset(mesh_offset + meshgroup_offset); } }