void FffPolygonGenerator::processInsets(SliceDataStorage& storage, unsigned int layer_nr) { for(SliceMeshStorage& mesh : storage.meshes) { int inset_count = mesh.settings->getSettingAsCount("wall_line_count"); if (mesh.settings->getSettingBoolean("magic_spiralize") && static_cast<int>(layer_nr) < mesh.settings->getSettingAsCount("bottom_layers") && layer_nr % 2 == 1)//Add extra insets every 2 layers when spiralizing, this makes bottoms of cups watertight. inset_count += 5; SliceLayer* layer = &mesh.layers[layer_nr]; int line_width_x = mesh.settings->getSettingInMicrons("wall_line_width_x"); int line_width_0 = mesh.settings->getSettingInMicrons("wall_line_width_0"); if (mesh.settings->getSettingBoolean("alternate_extra_perimeter")) inset_count += layer_nr % 2; generateInsets(layer, line_width_0, line_width_x, inset_count, mesh.settings->getSettingBoolean("remove_overlapping_walls_0_enabled"), mesh.settings->getSettingBoolean("remove_overlapping_walls_x_enabled")); for(unsigned int partNr=0; partNr<layer->parts.size(); partNr++) { if (layer->parts[partNr].insets.size() > 0) { sendPolygons(Inset0Type, layer_nr, layer->parts[partNr].insets[0], line_width_0); for(unsigned int inset=1; inset<layer->parts[partNr].insets.size(); inset++) sendPolygons(InsetXType, layer_nr, layer->parts[partNr].insets[inset], line_width_x); } } } }
void FffPolygonGenerator::processSkins(SliceDataStorage& storage, unsigned int layer_nr) { for(SliceMeshStorage& mesh : storage.meshes) { int extrusionWidth = mesh.settings->getSettingInMicrons("wall_line_width_x"); generateSkins(layer_nr, mesh, extrusionWidth, mesh.settings->getSettingAsCount("bottom_layers"), mesh.settings->getSettingAsCount("top_layers"), mesh.settings->getSettingAsCount("skin_outline_count"), mesh.settings->getSettingBoolean("remove_overlapping_walls_0_enabled"), mesh.settings->getSettingBoolean("remove_overlapping_walls_x_enabled")); if (mesh.settings->getSettingInMicrons("infill_line_distance") > 0) { int infill_skin_overlap = 0; if (mesh.settings->getSettingInMicrons("infill_line_distance") > mesh.settings->getSettingInMicrons("infill_line_width") + 10) { infill_skin_overlap = extrusionWidth / 2; } generateSparse(layer_nr, mesh, extrusionWidth, infill_skin_overlap); if (mesh.settings->getSettingString("fill_perimeter_gaps") == "Skin") { generatePerimeterGaps(layer_nr, mesh, extrusionWidth, mesh.settings->getSettingAsCount("bottom_layers"), mesh.settings->getSettingAsCount("top_layers")); } else if (mesh.settings->getSettingString("fill_perimeter_gaps") == "Everywhere") { generatePerimeterGaps(layer_nr, mesh, extrusionWidth, 0, 0); } } SliceLayer& layer = mesh.layers[layer_nr]; for(SliceLayerPart& part : layer.parts) { for (SkinPart& skin_part : part.skin_parts) { sendPolygons(SkinType, layer_nr, skin_part.outline, extrusionWidth); } } } }
void FffPolygonGenerator::processFuzzyWalls(SliceMeshStorage& mesh) { int64_t fuzziness = mesh.getSettingInMicrons("magic_fuzzy_skin_thickness"); int64_t avg_dist_between_points = mesh.getSettingInMicrons("magic_fuzzy_skin_point_dist"); int64_t min_dist_between_points = avg_dist_between_points * 3 / 4; // hardcoded: the point distance may vary between 3/4 and 5/4 the supplied value int64_t range_random_point_dist = avg_dist_between_points / 2; for (unsigned int layer_nr = 0; layer_nr < mesh.layers.size(); layer_nr++) { SliceLayer& layer = mesh.layers[layer_nr]; for (SliceLayerPart& part : layer.parts) { Polygons results; Polygons& skin = (mesh.getSettingAsSurfaceMode("magic_mesh_surface_mode") == ESurfaceMode::SURFACE)? part.outline : part.insets[0]; for (PolygonRef poly : skin) { // generate points in between p0 and p1 PolygonRef result = results.newPoly(); int64_t dist_left_over = rand() % (min_dist_between_points / 2); // the distance to be traversed on the line before making the first new point Point* p0 = &poly.back(); for (Point& p1 : poly) { // 'a' is the (next) new point between p0 and p1 Point p0p1 = p1 - *p0; int64_t p0p1_size = vSize(p0p1); int64_t dist_last_point = dist_left_over + p0p1_size * 2; // so that p0p1_size - dist_last_point evaulates to dist_left_over - p0p1_size for (int64_t p0pa_dist = dist_left_over; p0pa_dist < p0p1_size; p0pa_dist += min_dist_between_points + rand() % range_random_point_dist) { int r = rand() % (fuzziness * 2) - fuzziness; Point perp_to_p0p1 = crossZ(p0p1); Point fuzz = normal(perp_to_p0p1, r); Point pa = *p0 + normal(p0p1, p0pa_dist) + fuzz; result.add(pa); dist_last_point = p0pa_dist; } dist_left_over = p0p1_size - dist_last_point; p0 = &p1; } while (result.size() < 3 ) { unsigned int point_idx = poly.size() - 2; result.add(poly[point_idx]); if (point_idx == 0) { break; } point_idx--; } if (result.size() < 3) { result.clear(); for (Point& p : poly) result.add(p); } } skin = results; sendPolygons(Inset0Type, layer_nr, skin, mesh.getSettingInMicrons("wall_line_width_0")); } } }
void FffPolygonGenerator::processInsets(SliceDataStorage& storage, unsigned int layer_nr) { for(SliceMeshStorage& mesh : storage.meshes) { SliceLayer* layer = &mesh.layers[layer_nr]; if (mesh.getSettingAsSurfaceMode("magic_mesh_surface_mode") != ESurfaceMode::SURFACE) { int inset_count = mesh.getSettingAsCount("wall_line_count"); if (mesh.getSettingBoolean("magic_spiralize") && static_cast<int>(layer_nr) < mesh.getSettingAsCount("bottom_layers") && layer_nr % 2 == 1)//Add extra insets every 2 layers when spiralizing, this makes bottoms of cups watertight. inset_count += 5; int line_width_x = mesh.getSettingInMicrons("wall_line_width_x"); int line_width_0 = mesh.getSettingInMicrons("wall_line_width_0"); if (mesh.getSettingBoolean("alternate_extra_perimeter")) inset_count += layer_nr % 2; generateInsets(layer, mesh.getSettingInMicrons("machine_nozzle_size"), line_width_0, line_width_x, inset_count, mesh.getSettingBoolean("remove_overlapping_walls_0_enabled"), mesh.getSettingBoolean("remove_overlapping_walls_x_enabled")); for(unsigned int partNr=0; partNr<layer->parts.size(); partNr++) { if (layer->parts[partNr].insets.size() > 0) { // sendPolygons(Inset0Type, layer_nr, layer->parts[partNr].insets[0], line_width_0); // done after processing fuzzy skin for(unsigned int inset=1; inset<layer->parts[partNr].insets.size(); inset++) sendPolygons(InsetXType, layer_nr, layer->parts[partNr].insets[inset], line_width_x); } } } if (mesh.getSettingAsSurfaceMode("magic_mesh_surface_mode") != ESurfaceMode::NORMAL) { for (PolygonRef polyline : layer->openPolyLines) { Polygons segments; for (unsigned int point_idx = 1; point_idx < polyline.size(); point_idx++) { PolygonRef segment = segments.newPoly(); segment.add(polyline[point_idx-1]); segment.add(polyline[point_idx]); } sendPolygons(Inset0Type, layer_nr, segments, mesh.getSettingInMicrons("wall_line_width_0")); } } } }
void FffPolygonGenerator::slices2polygons_magicPolygonMode(SliceDataStorage& storage, TimeKeeper& timeKeeper) { // const unsigned int totalLayers = storage.meshes[0].layers.size(); for(unsigned int layer_nr=0; layer_nr<totalLayers; layer_nr++) { for(SliceMeshStorage& mesh : storage.meshes) { SliceLayer* layer = &mesh.layers[layer_nr]; for(SliceLayerPart& part : layer->parts) { sendPolygons(Inset0Type, layer_nr, part.outline, mesh.settings->getSettingInMicrons("wall_line_width_0")); } } } }
void FffPolygonGenerator::processSkins(SliceDataStorage& storage, unsigned int layer_nr) { for(SliceMeshStorage& mesh : storage.meshes) { if (mesh.getSettingAsSurfaceMode("magic_mesh_surface_mode") == ESurfaceMode::SURFACE) { continue; } int skin_extrusion_width = mesh.getSettingInMicrons("skin_line_width"); int innermost_wall_extrusion_width = mesh.getSettingInMicrons("wall_line_width_x"); int extrusionWidth_infill = mesh.getSettingInMicrons("infill_line_width"); generateSkins(layer_nr, mesh, skin_extrusion_width, mesh.getSettingAsCount("bottom_layers"), mesh.getSettingAsCount("top_layers"), innermost_wall_extrusion_width, mesh.getSettingAsCount("skin_outline_count"), mesh.getSettingBoolean("skin_no_small_gaps_heuristic"), mesh.getSettingBoolean("remove_overlapping_walls_0_enabled"), mesh.getSettingBoolean("remove_overlapping_walls_x_enabled")); if (mesh.getSettingInMicrons("infill_line_distance") > 0) { int infill_skin_overlap = 0; if (mesh.getSettingInMicrons("infill_line_distance") > mesh.getSettingInMicrons("infill_line_width") + 10) { infill_skin_overlap = skin_extrusion_width / 2; } generateInfill(layer_nr, mesh, extrusionWidth_infill, infill_skin_overlap); if (mesh.getSettingAsFillPerimeterGapMode("fill_perimeter_gaps") == FillPerimeterGapMode::SKIN) { generatePerimeterGaps(layer_nr, mesh, skin_extrusion_width, mesh.getSettingAsCount("bottom_layers"), mesh.getSettingAsCount("top_layers")); } else if (mesh.getSettingAsFillPerimeterGapMode("fill_perimeter_gaps") == FillPerimeterGapMode::EVERYWHERE) { generatePerimeterGaps(layer_nr, mesh, skin_extrusion_width, 0, 0); } } bool frontend_can_show_polygon_as_filled_polygon = false; if (frontend_can_show_polygon_as_filled_polygon) { SliceLayer& layer = mesh.layers[layer_nr]; for(SliceLayerPart& part : layer.parts) { // sendPolygons(InfillType, layer_nr, part.infill_area[0], extrusionWidth_infill); // sends the outline, not the actual infill for (SkinPart& skin_part : part.skin_parts) { sendPolygons(SkinType, layer_nr, skin_part.outline, innermost_wall_extrusion_width); } } } } }
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")); }
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]); sendPolygons(SkirtType, 0, skirt_sent, getSettingInMicrons("skirt_line_width")); }
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")); } } } } }