void offset2(const Slic3r::Polygons &polygons, ClipperLib::Paths &retval, const float delta1, const float delta2, const double scale, const ClipperLib::JoinType joinType, const double miterLimit) { // read input ClipperLib::Paths input; Slic3rMultiPoints_to_ClipperPaths(polygons, input); // scale input scaleClipperPolygons(input, scale); // prepare ClipperOffset object ClipperLib::ClipperOffset co; if (joinType == jtRound) { co.ArcTolerance = miterLimit; } else { co.MiterLimit = miterLimit; } // perform first offset ClipperLib::Paths output1; co.AddPaths(input, joinType, ClipperLib::etClosedPolygon); co.Execute(output1, (delta1*scale)); // perform second offset co.Clear(); co.AddPaths(output1, joinType, ClipperLib::etClosedPolygon); co.Execute(retval, (delta2*scale)); // unscale output scaleClipperPolygons(retval, 1/scale); }
void offset2(const Slic3r::Polygons &polygons, ClipperLib::Paths* retval, const float delta1, const float delta2, const ClipperLib::JoinType joinType, const double miterLimit) { if (delta1 * delta2 >= 0) { // Both deltas are the same signum offset(polygons, retval, delta1 + delta2, joinType, miterLimit); return; } #ifdef CLIPPER_UTILS_DEBUG BoundingBox bbox = get_extents(polygons); coordf_t stroke_width = scale_(0.005); static int iRun = 0; ++ iRun; bool flipY = false; SVG svg(debug_out_path("offset2-%d.svg", iRun), bbox, scale_(1.), flipY); for (Slic3r::Polygons::const_iterator it = polygons.begin(); it != polygons.end(); ++ it) svg.draw(it->lines(), "gray", stroke_width); #endif /* CLIPPER_UTILS_DEBUG */ // read input ClipperLib::Paths input; Slic3rMultiPoints_to_ClipperPaths(polygons, &input); // scale input scaleClipperPolygons(input); // prepare ClipperOffset object ClipperLib::ClipperOffset co; if (joinType == jtRound) { co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE); } else { co.MiterLimit = miterLimit; } // perform first offset ClipperLib::Paths output1; co.AddPaths(input, joinType, ClipperLib::etClosedPolygon); co.Execute(output1, delta1 * float(CLIPPER_OFFSET_SCALE)); #ifdef CLIPPER_UTILS_DEBUG svg.draw(output1, 1. / double(CLIPPER_OFFSET_SCALE), "red", stroke_width); #endif /* CLIPPER_UTILS_DEBUG */ // perform second offset co.Clear(); co.AddPaths(output1, joinType, ClipperLib::etClosedPolygon); co.Execute(*retval, delta2 * float(CLIPPER_OFFSET_SCALE)); #ifdef CLIPPER_UTILS_DEBUG svg.draw(*retval, 1. / double(CLIPPER_OFFSET_SCALE), "green", stroke_width); #endif /* CLIPPER_UTILS_DEBUG */ // unscale output unscaleClipperPolygons(*retval); }
void safety_offset(ClipperLib::Paths* paths) { PROFILE_FUNC(); // scale input scaleClipperPolygons(*paths); // perform offset (delta = scale 1e-05) ClipperLib::ClipperOffset co; #ifdef CLIPPER_UTILS_DEBUG if (clipper_export_enabled) { static int iRun = 0; export_clipper_input_polygons_bin(debug_out_path("safety_offset-polygons-%d", ++iRun).c_str(), *paths, ClipperLib::Paths()); } #endif /* CLIPPER_UTILS_DEBUG */ ClipperLib::Paths out; for (size_t i = 0; i < paths->size(); ++ i) { ClipperLib::Path &path = (*paths)[i]; co.Clear(); co.MiterLimit = 2; bool ccw = ClipperLib::Orientation(path); if (! ccw) std::reverse(path.begin(), path.end()); { PROFILE_BLOCK(safety_offset_AddPaths); co.AddPath((*paths)[i], ClipperLib::jtMiter, ClipperLib::etClosedPolygon); } { PROFILE_BLOCK(safety_offset_Execute); // offset outside by 10um ClipperLib::Paths out_this; co.Execute(out_this, ccw ? 10.f * float(CLIPPER_OFFSET_SCALE) : -10.f * float(CLIPPER_OFFSET_SCALE)); if (! ccw) { // Reverse the resulting contours once again. for (ClipperLib::Paths::iterator it = out_this.begin(); it != out_this.end(); ++ it) std::reverse(it->begin(), it->end()); } if (out.empty()) out = std::move(out_this); else std::move(std::begin(out_this), std::end(out_this), std::back_inserter(out)); } } *paths = std::move(out); // unscale output unscaleClipperPolygons(*paths); }
ClipperLib::Paths _offset2(const Polygons &polygons, const float delta1, const float delta2, const ClipperLib::JoinType joinType, const double miterLimit) { // read input ClipperLib::Paths input = Slic3rMultiPoints_to_ClipperPaths(polygons); // scale input scaleClipperPolygons(input); // prepare ClipperOffset object ClipperLib::ClipperOffset co; if (joinType == jtRound) { co.ArcTolerance = miterLimit; } else { co.MiterLimit = miterLimit; } float delta_scaled1 = delta1 * float(CLIPPER_OFFSET_SCALE); float delta_scaled2 = delta2 * float(CLIPPER_OFFSET_SCALE); co.ShortestEdgeLength = double(std::max(std::abs(delta_scaled1), std::abs(delta_scaled2)) * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR); // perform first offset ClipperLib::Paths output1; co.AddPaths(input, joinType, ClipperLib::etClosedPolygon); co.Execute(output1, delta_scaled1); // perform second offset co.Clear(); co.AddPaths(output1, joinType, ClipperLib::etClosedPolygon); ClipperLib::Paths retval; co.Execute(retval, delta_scaled2); // unscale output unscaleClipperPolygons(retval); return retval; }