std::vector< bool > SliceDataStorage::getExtrudersUsed() { std::vector<bool> ret; ret.resize(meshgroup->getExtruderCount(), false); ret[getSettingAsIndex("adhesion_extruder_nr")] = true; { // process brim/skirt for (int extr_nr = 0; extr_nr < meshgroup->getExtruderCount(); extr_nr++) { if (skirt[extr_nr].size() > 0) { ret[extr_nr] = true; continue; } } } // TODO: ooze shield, draft shield ..? // support // support is presupposed to be present... ret[getSettingAsIndex("support_extruder_nr_layer_0")] = true; ret[getSettingAsIndex("support_extruder_nr")] = true; ret[getSettingAsIndex("support_roof_extruder_nr")] = true; // all meshes are presupposed to actually have content for (SliceMeshStorage& mesh : meshes) { ret[mesh.getSettingAsIndex("extruder_nr")] = true; } return ret; }
std::vector<bool> SliceDataStorage::getExtrudersUsed(int layer_nr) { std::vector<bool> ret; ret.resize(meshgroup->getExtruderCount(), false); if (layer_nr < 0) { ret[getSettingAsIndex("adhesion_extruder_nr")] = true; // raft } else { if (layer_nr == 0) { // process brim/skirt for (int extr_nr = 0; extr_nr < meshgroup->getExtruderCount(); extr_nr++) { if (skirt[extr_nr].size() > 0) { ret[extr_nr] = true; continue; } } } // TODO: ooze shield, draft shield // support if (support.supportLayers[layer_nr].supportAreas.size() > 0) { if (layer_nr == 0) { ret[getSettingAsIndex("support_extruder_nr_layer_0")] = true; } else { ret[getSettingAsIndex("support_extruder_nr")] = true; } } if (support.supportLayers[layer_nr].roofs.size() > 0) { ret[getSettingAsIndex("support_roof_extruder_nr")] = true; } for (SliceMeshStorage& mesh : meshes) { SliceLayer& layer = mesh.layers[layer_nr]; int extr_nr = mesh.getSettingAsIndex("extruder_nr"); if (layer.parts.size() > 0) { ret[extr_nr] = true; } } } return ret; }
SliceDataStorage::SliceDataStorage(MeshGroup* meshgroup) : SettingsMessenger(meshgroup), meshgroup(meshgroup != nullptr ? meshgroup : new MeshGroup(FffProcessor::getInstance())), //If no mesh group is provided, we roll our own. retraction_config_per_extruder(initializeRetractionConfigs()), travel_config_per_extruder(initializeTravelConfigs()), skirt_config(initializeSkirtConfigs()), raft_base_config(&retraction_config_per_extruder[getSettingAsIndex("adhesion_extruder_nr")], PrintFeatureType::Support), raft_interface_config(&retraction_config_per_extruder[getSettingAsIndex("adhesion_extruder_nr")], PrintFeatureType::Support), raft_surface_config(&retraction_config_per_extruder[getSettingAsIndex("adhesion_extruder_nr")], PrintFeatureType::Support), support_config(&retraction_config_per_extruder[getSettingAsIndex("support_infill_extruder_nr")], PrintFeatureType::Support), support_roof_config(&retraction_config_per_extruder[getSettingAsIndex("support_roof_extruder_nr")], PrintFeatureType::Skin), max_object_height_second_to_last_extruder(-1) { }
std::vector<bool> SliceDataStorage::getExtrudersUsed() const { std::vector<bool> ret; ret.resize(meshgroup->getExtruderCount(), false); if (getSettingAsPlatformAdhesion("adhesion_type") != EPlatformAdhesion::NONE) { ret[getSettingAsIndex("adhesion_extruder_nr")] = true; { // process brim/skirt for (int extr_nr = 0; extr_nr < meshgroup->getExtruderCount(); extr_nr++) { if (skirt_brim[extr_nr].size() > 0) { ret[extr_nr] = true; continue; } } } } // TODO: ooze shield, draft shield ..? // support // support is presupposed to be present... ret[getSettingAsIndex("support_extruder_nr_layer_0")] = true; ret[getSettingAsIndex("support_infill_extruder_nr")] = true; ret[getSettingAsIndex("support_interface_extruder_nr")] = true; // all meshes are presupposed to actually have content for (const SliceMeshStorage& mesh : meshes) { if (!mesh.getSettingBoolean("anti_overhang_mesh") && !mesh.getSettingBoolean("support_mesh") ) { ret[mesh.getSettingAsIndex("extruder_nr")] = true; } } return ret; }
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); } }
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; }
std::vector<bool> SliceDataStorage::getExtrudersUsed(int layer_nr) const { std::vector<bool> ret; ret.resize(meshgroup->getExtruderCount(), false); bool include_adhesion = true; bool include_helper_parts = true; bool include_models = true; if (layer_nr < 0) { include_models = false; if (layer_nr < -Raft::getFillerLayerCount(*this)) { include_helper_parts = false; } else { layer_nr = 0; // because the helper parts are copied from the initial layer in the filler layer include_adhesion = false; } } else if (layer_nr > 0 || getSettingAsPlatformAdhesion("adhesion_type") == EPlatformAdhesion::RAFT) { // only include adhesion only for layers where platform adhesion actually occurs // i.e. layers < 0 are for raft, layer 0 is for brim/skirt include_adhesion = false; } if (include_adhesion) { ret[getSettingAsIndex("adhesion_extruder_nr")] = true; { // process brim/skirt for (int extr_nr = 0; extr_nr < meshgroup->getExtruderCount(); extr_nr++) { if (skirt_brim[extr_nr].size() > 0) { ret[extr_nr] = true; continue; } } } } // TODO: ooze shield, draft shield ..? if (include_helper_parts) { // support if (layer_nr < int(support.supportLayers.size())) { const SupportLayer& support_layer = support.supportLayers[layer_nr]; if (layer_nr == 0) { if (support_layer.supportAreas.size() > 0) { ret[getSettingAsIndex("support_extruder_nr_layer_0")] = true; } } else { if (support_layer.supportAreas.size() > 0) { ret[getSettingAsIndex("support_infill_extruder_nr")] = true; } } if (support_layer.skin.size() > 0) { ret[getSettingAsIndex("support_interface_extruder_nr")] = true; } } } if (include_models) { for (const SliceMeshStorage& mesh : meshes) { if (layer_nr >= int(mesh.layers.size())) { continue; } const SliceLayer& layer = mesh.layers[layer_nr]; if (layer.parts.size() > 0) { ret[mesh.getSettingAsIndex("extruder_nr")] = true; } } } return ret; }
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); } }