int bridgeAngle(Polygons outline, const SliceLayer* prevLayer, Polygons& supportedRegions) { AABB boundaryBox(outline); //To detect if we have a bridge, first calculate the intersection of the current layer with the previous layer. // This gives us the islands that the layer rests on. Polygons islands; for(auto prevLayerPart : prevLayer->parts) { if (!boundaryBox.hit(prevLayerPart.boundaryBox)) continue; islands.add(outline.intersection(prevLayerPart.outline)); } supportedRegions = islands; if (islands.size() > 5 || islands.size() < 1) return -1; //Next find the 2 largest islands that we rest on. double area1 = 0; double area2 = 0; int idx1 = -1; int idx2 = -1; for(unsigned int n=0; n<islands.size(); n++) { //Skip internal holes if (!islands[n].orientation()) continue; double area = fabs(islands[n].area()); if (area > area1) { if (area1 > area2) { area2 = area1; idx2 = idx1; } area1 = area; idx1 = n; }else if (area > area2) { area2 = area; idx2 = n; } } if (idx1 < 0 || idx2 < 0) return -1; Point center1 = islands[idx1].centerOfMass(); Point center2 = islands[idx2].centerOfMass(); return angle(center2 - center1); }
//Expand each layer a bit and then keep the extra overlapping parts that overlap with other volumes. //This generates some overlap in dual extrusion, for better bonding in touching parts. void generateMultipleVolumesOverlap(std::vector<Slicer*> &volumes, int overlap) { if (volumes.size() < 2 || overlap <= 0) return; for(unsigned int layerNr=0; layerNr < volumes[0]->layers.size(); layerNr++) { Polygons fullLayer; for(unsigned int volIdx = 0; volIdx < volumes.size(); volIdx++) { SlicerLayer& layer1 = volumes[volIdx]->layers[layerNr]; fullLayer = fullLayer.unionPolygons(layer1.polygons.offset(20)); // TODO: put hard coded value in a variable with an explanatory name (and make var a parameter, and perhaps even a setting?) } fullLayer = fullLayer.offset(-20); // TODO: put hard coded value in a variable with an explanatory name (and make var a parameter, and perhaps even a setting?) for(unsigned int volIdx = 0; volIdx < volumes.size(); volIdx++) { SlicerLayer& layer1 = volumes[volIdx]->layers[layerNr]; layer1.polygons = fullLayer.intersection(layer1.polygons.offset(overlap / 2)); } } }
void SkinInfillAreaComputation::generateInfillSupport(SliceMeshStorage& mesh) { const coord_t layer_height = mesh.getSettingInMicrons("layer_height"); const double support_angle = mesh.getSettingInAngleRadians("infill_support_angle"); const double tan_angle = tan(support_angle) - 0.01; //The X/Y component of the support angle. 0.01 to make 90 degrees work too. const coord_t max_dist_from_lower_layer = tan_angle * layer_height; //Maximum horizontal distance that can be bridged. for (int layer_idx = mesh.layers.size() - 2; layer_idx >= 0; layer_idx--) { SliceLayer& layer = mesh.layers[layer_idx]; SliceLayer& layer_above = mesh.layers[layer_idx + 1]; Polygons inside_above; Polygons infill_above; for (SliceLayerPart& part_above : layer_above.parts) { inside_above.add(part_above.infill_area); infill_above.add(part_above.getOwnInfillArea()); } for (SliceLayerPart& part : layer.parts) { const Polygons& infill_area = part.infill_area; if (infill_area.empty()) { continue; } const Polygons unsupported = infill_area.offset(-max_dist_from_lower_layer); const Polygons basic_overhang = unsupported.difference(inside_above); const Polygons overhang_extented = basic_overhang.offset(max_dist_from_lower_layer + 50); // +50 for easier joining with support from layer above const Polygons full_overhang = overhang_extented.difference(inside_above); const Polygons infill_support = infill_above.unionPolygons(full_overhang); part.infill_area_own = infill_support.intersection(part.getOwnInfillArea()); } } }
void generateTroctInfill(const Polygons& in_outline, Polygons& result, int extrusionWidth, int lineSpacing, int infillOverlap, double rotation, int posZ) { Polygons outline = in_outline.offset(extrusionWidth * infillOverlap / 100); PointMatrix matrix(rotation); outline.applyMatrix(matrix); AABB boundary(outline); // ignore infill for areas smaller than line spacing if((abs(boundary.min.X - boundary.max.X) + abs(boundary.min.Y - boundary.max.Y)) < lineSpacing){ return; } // fix to normalise against diagonal infill lineSpacing = lineSpacing * 2; uint64_t Zscale = SQRT2MUL(lineSpacing); int offset = abs(posZ % (Zscale) - (Zscale/2)) - (Zscale/4); boundary.min.X = ((boundary.min.X / lineSpacing) - 1) * lineSpacing; boundary.min.Y = ((boundary.min.Y / lineSpacing) - 1) * lineSpacing; unsigned int lineCountX = (boundary.max.X - boundary.min.X + (lineSpacing - 1)) / lineSpacing; unsigned int lineCountY = (boundary.max.Y - boundary.min.Y + (lineSpacing - 1)) / lineSpacing; int rtMod = int(rotation / 90) % 2; // with an odd number of lines, sides need to be swapped around if(rtMod == 1){ rtMod = (lineCountX + int(rotation / 90)) % 2; } // draw non-horizontal walls of octohedrons Polygons po; PolygonRef p = po.newPoly(); for(unsigned int ly=0; ly < lineCountY;){ for(size_t it = 0; it < 2; ly++, it++){ int side = (2*((ly + it + rtMod) % 2) - 1); int y = (ly * lineSpacing) + boundary.min.Y + lineSpacing / 2 - (offset/2 * side); int x = boundary.min.X-(offset/2); if(it == 1){ x = (lineCountX * (lineSpacing)) + boundary.min.X + lineSpacing / 2 - (offset/2); } p.add(Point(x,y)); for(unsigned int lx=0; lx < lineCountX; lx++){ if(it == 1){ side = (2*((lx + ly + it + rtMod + lineCountX) % 2) - 1); y = (ly * lineSpacing) + boundary.min.Y + lineSpacing / 2 + (offset/2 * side); x = ((lineCountX - lx - 1) * lineSpacing) + boundary.min.X + lineSpacing / 2; p.add(Point(x+lineSpacing-abs(offset/2), y)); p.add(Point(x+abs(offset/2), y)); } else { side = (2*((lx + ly + it + rtMod) % 2) - 1); y = (ly * lineSpacing) + boundary.min.Y + lineSpacing / 2 + (offset/2 * side); x = (lx * lineSpacing) + boundary.min.X + lineSpacing / 2; p.add(Point(x+abs(offset/2), y)); p.add(Point(x+lineSpacing-abs(offset/2), y)); } } x = (lineCountX * lineSpacing) + boundary.min.X + lineSpacing / 2 - (offset/2); if(it == 1){ x = boundary.min.X-(offset/2); } y = (ly * lineSpacing) + boundary.min.Y + lineSpacing / 2 - (offset/2 * side); p.add(Point(x,y)); } } // Generate tops / bottoms of octohedrons if(abs((abs(offset) - Zscale/4)) < (extrusionWidth/2)){ uint64_t startLine = (offset < 0) ? 0 : 1; uint64_t coverWidth = OCTSLEN(lineSpacing); vector<Point> points; for(size_t xi = 0; xi < (lineCountX+1); xi++){ for(size_t yi = 0; yi < (lineCountY); yi += 2){ points.push_back(Point(boundary.min.X + OCTDLEN(lineSpacing) + (xi - startLine + rtMod) * lineSpacing, boundary.min.Y + OCTDLEN(lineSpacing) + (yi + (xi%2)) * lineSpacing + extrusionWidth/2)); } } uint64_t order = 0; for(Point pp : points){ PolygonRef p = po.newPoly(); for(size_t yi = 0; yi <= coverWidth; yi += extrusionWidth) { if(order == 0){ p.add(Point(pp.X, pp.Y + yi)); p.add(Point(pp.X + coverWidth + extrusionWidth, pp.Y + yi)); } else { p.add(Point(pp.X + coverWidth + extrusionWidth, pp.Y + yi)); p.add(Point(pp.X, pp.Y + yi)); } order = (order + 1) % 2; } } } // intersect with outline polygon(s) Polygons pi = po.intersection(outline); // Hack to add intersection to result. There doesn't seem // to be a direct way to do this for(unsigned int polyNr=0; polyNr < pi.size(); polyNr++) { PolygonRef p = result.newPoly(); // = result.newPoly() for(unsigned int i=0; i < pi[polyNr].size(); i++) { Point p0 = pi[polyNr][i]; p.add(matrix.unapply(Point(p0.X,p0.Y))); } } }