void FffPolygonGenerator::processBasicWallsSkinInfill(SliceDataStorage& storage, unsigned int mesh_idx, std::vector<unsigned int>& mesh_order, size_t total_layers, ProgressStageEstimator& inset_skin_progress_estimate) { SliceMeshStorage& mesh = storage.meshes[mesh_idx]; if (mesh.getSettingBoolean("infill_mesh")) { processInfillMesh(storage, mesh_idx, mesh_order, total_layers); } // TODO: make progress more accurate!! // note: estimated time for insets : skins = 22.953 : 48.858 std::vector<double> walls_vs_skin_timing({22.953, 48.858}); ProgressStageEstimator* mesh_inset_skin_progress_estimator = new ProgressStageEstimator(walls_vs_skin_timing); inset_skin_progress_estimate.nextStage(mesh_inset_skin_progress_estimator); // the stage of this function call ProgressEstimatorLinear* inset_estimator = new ProgressEstimatorLinear(total_layers); mesh_inset_skin_progress_estimator->nextStage(inset_estimator); // walls for(unsigned int layer_number = 0; layer_number < total_layers; layer_number++) { processInsets(mesh, layer_number); double progress = inset_skin_progress_estimate.progress(layer_number); Progress::messageProgress(Progress::Stage::INSET_SKIN, progress * 100, 100); } ProgressEstimatorLinear* skin_estimator = new ProgressEstimatorLinear(total_layers); mesh_inset_skin_progress_estimator->nextStage(skin_estimator); // skin & infill // Progress::messageProgressStage(Progress::Stage::SKIN, &time_keeper); int mesh_max_bottom_layer_count = 0; if (getSettingBoolean("magic_spiralize")) { 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. { processSkinsAndInfill(mesh, layer_number); } double progress = inset_skin_progress_estimate.progress(layer_number); Progress::messageProgress(Progress::Stage::INSET_SKIN, progress * 100, 100); } }
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::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 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(); } }
bool FffPolygonGenerator::generateAreas(SliceDataStorage& storage, PrintObject* object, TimeKeeper& timeKeeper) { if (!sliceModel(object, timeKeeper, storage)) { return false; } if (getSettingBoolean("magic_mesh_surface_mode")) { slices2polygons_magicPolygonMode(storage, timeKeeper); } else { slices2polygons(storage, timeKeeper); } return true; }
void FffPolygonGenerator::processPlatformAdhesion(SliceDataStorage& storage) { SettingsBaseVirtual* train = storage.meshgroup->getExtruderTrain(getSettingBoolean("adhesion_extruder_nr")); switch(getSettingAsPlatformAdhesion("adhesion_type")) { case EPlatformAdhesion::SKIRT: if (train->getSettingInMicrons("draft_shield_height") == 0) { // draft screen replaces skirt generateSkirt(storage, train->getSettingInMicrons("skirt_gap"), train->getSettingAsCount("skirt_line_count"), train->getSettingInMicrons("skirt_minimal_length")); } break; case EPlatformAdhesion::BRIM: generateSkirt(storage, 0, train->getSettingAsCount("brim_line_count"), train->getSettingInMicrons("skirt_minimal_length")); break; case EPlatformAdhesion::RAFT: generateRaft(storage, train->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::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 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")); } } } } }
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); } }