// Fix of #117: A large fractal pyramid takes ages to slice // The Clipper library has difficulties processing overlapping polygons. // Namely, the function Clipper::JoinCommonEdges() has potentially a terrible time complexity if the output // of the operation is of the PolyTree type. // This function implmenets a following workaround: // 1) Peform the Clipper operation with the output to Paths. This method handles overlaps in a reasonable time. // 2) Run Clipper Union once again to extract the PolyTree from the result of 1). inline ClipperLib::PolyTree _clipper_do_polytree2(const ClipperLib::ClipType clipType, const Polygons &subject, const Polygons &clip, const ClipperLib::PolyFillType fillType, const bool safety_offset_) { // read input ClipperLib::Paths input_subject = Slic3rMultiPoints_to_ClipperPaths(subject); ClipperLib::Paths input_clip = Slic3rMultiPoints_to_ClipperPaths(clip); // perform safety offset if (safety_offset_) safety_offset((clipType == ClipperLib::ctUnion) ? &input_subject : &input_clip); ClipperLib::Clipper clipper; clipper.AddPaths(input_subject, ClipperLib::ptSubject, true); clipper.AddPaths(input_clip, ClipperLib::ptClip, true); // Perform the operation with the output to input_subject. // This pass does not generate a PolyTree, which is a very expensive operation with the current Clipper library // if there are overapping edges. clipper.Execute(clipType, input_subject, fillType, fillType); // Perform an additional Union operation to generate the PolyTree ordering. clipper.Clear(); clipper.AddPaths(input_subject, ClipperLib::ptSubject, true); ClipperLib::PolyTree retval; clipper.Execute(ClipperLib::ctUnion, retval, fillType, fillType); return retval; }
void simplify_polygons(const Slic3r::Polygons &subject, Slic3r::ExPolygons* retval, bool preserve_collinear) { PROFILE_FUNC(); if (!preserve_collinear) { Polygons polygons; simplify_polygons(subject, &polygons, preserve_collinear); union_(polygons, retval); return; } // convert into Clipper polygons ClipperLib::Paths input_subject; Slic3rMultiPoints_to_ClipperPaths(subject, &input_subject); ClipperLib::PolyTree polytree; ClipperLib::Clipper c; c.PreserveCollinear(true); c.StrictlySimple(true); c.AddPaths(input_subject, ClipperLib::ptSubject, true); c.Execute(ClipperLib::ctUnion, polytree, ClipperLib::pftNonZero, ClipperLib::pftNonZero); // convert into ExPolygons PolyTreeToExPolygons(polytree, retval); }
void _clipper_do(const ClipperLib::ClipType clipType, const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, T &retval, const ClipperLib::PolyFillType fillType, const bool safety_offset_) { // read input ClipperLib::Paths* input_subject = new ClipperLib::Paths(); ClipperLib::Paths* input_clip = new ClipperLib::Paths(); Slic3rMultiPoints_to_ClipperPaths(subject, *input_subject); Slic3rMultiPoints_to_ClipperPaths(clip, *input_clip); // perform safety offset if (safety_offset_) { if (clipType == ClipperLib::ctUnion) { safety_offset(input_subject); } else { safety_offset(input_clip); } } // init Clipper ClipperLib::Clipper clipper; clipper.Clear(); // add polygons clipper.AddPaths(*input_subject, ClipperLib::ptSubject, true); delete input_subject; clipper.AddPaths(*input_clip, ClipperLib::ptClip, true); delete input_clip; // perform operation clipper.Execute(clipType, retval, fillType, fillType); }
polygon polygon::createUnion(const std::vector<polygon>& data) { base_int maxDenom = 1; for(auto poly : data) { maxDenom = lcm(maxDenom, poly.highestDenominator()); } maxDenom = std::min(maxDenom, base_int(1000000000L)); //std::cout << "-----" << std::endl; //std::cout << maxDenom << std::endl; polygon base = data[0]; for(unsigned int i = 1; i < data.size(); i++) { ClipperLib::Clipper clipper; clipper.AddPath(base.path(maxDenom), ClipperLib::PolyType::ptSubject, true); clipper.AddPath(data[i].path(maxDenom), ClipperLib::PolyType::ptClip, true); ClipperLib::Paths returnedPaths; clipper.Execute(ClipperLib::ClipType::ctUnion, returnedPaths, ClipperLib::pftNonZero, ClipperLib::pftNonZero); base = polygon::from(returnedPaths, maxDenom)[0]; } return base; }
ClipperLib::PolyTree _clipper_do(const ClipperLib::ClipType clipType, const Polylines &subject, const Polygons &clip, const ClipperLib::PolyFillType fillType, const bool safety_offset_) { // read input ClipperLib::Paths input_subject = Slic3rMultiPoints_to_ClipperPaths(subject); ClipperLib::Paths input_clip = Slic3rMultiPoints_to_ClipperPaths(clip); // perform safety offset if (safety_offset_) safety_offset(&input_clip); // init Clipper ClipperLib::Clipper clipper; clipper.Clear(); // add polygons clipper.AddPaths(input_subject, ClipperLib::ptSubject, false); clipper.AddPaths(input_clip, ClipperLib::ptClip, true); // perform operation ClipperLib::PolyTree retval; clipper.Execute(clipType, retval, fillType, fillType); return retval; }
void _clipper_do(const ClipperLib::ClipType clipType, const Slic3r::Polylines &subject, const Slic3r::Polygons &clip, ClipperLib::PolyTree* retval, const ClipperLib::PolyFillType fillType, const bool safety_offset_) { PROFILE_BLOCK(_clipper_do_polylines); // read input ClipperLib::Paths input_subject, input_clip; Slic3rMultiPoints_to_ClipperPaths(subject, &input_subject); Slic3rMultiPoints_to_ClipperPaths(clip, &input_clip); // perform safety offset if (safety_offset_) safety_offset(&input_clip); // init Clipper ClipperLib::Clipper clipper; clipper.Clear(); // add polygons { PROFILE_BLOCK(_clipper_do_polylines_AddPaths); clipper.AddPaths(input_subject, ClipperLib::ptSubject, false); clipper.AddPaths(input_clip, ClipperLib::ptClip, true); } // perform operation { PROFILE_BLOCK(_clipper_do_polylines_Execute); clipper.Execute(clipType, *retval, fillType, fillType); } }
Vector<Vector2> expand(const Vector<Vector2> &points, const Rect2i &rect, float epsilon = 2.0) { int size = points.size(); ERR_FAIL_COND_V(size < 2, Vector<Vector2>()); ClipperLib::Path subj; ClipperLib::PolyTree solution; ClipperLib::PolyTree out; for (int i = 0; i < points.size(); i++) { subj << ClipperLib::IntPoint(points[i].x * PRECISION, points[i].y * PRECISION); } ClipperLib::ClipperOffset co; co.AddPath(subj, ClipperLib::jtMiter, ClipperLib::etClosedPolygon); co.Execute(solution, epsilon * PRECISION); ClipperLib::PolyNode *p = solution.GetFirst(); ERR_FAIL_COND_V(!p, points); while (p->IsHole()) { p = p->GetNext(); } //turn the result into simply polygon (AKA, fix overlap) //clamp into the specified rect ClipperLib::Clipper cl; cl.StrictlySimple(true); cl.AddPath(p->Contour, ClipperLib::ptSubject, true); //create the clipping rect ClipperLib::Path clamp; clamp.push_back(ClipperLib::IntPoint(0, 0)); clamp.push_back(ClipperLib::IntPoint(rect.size.width * PRECISION, 0)); clamp.push_back(ClipperLib::IntPoint(rect.size.width * PRECISION, rect.size.height * PRECISION)); clamp.push_back(ClipperLib::IntPoint(0, rect.size.height * PRECISION)); cl.AddPath(clamp, ClipperLib::ptClip, true); cl.Execute(ClipperLib::ctIntersection, out); Vector<Vector2> outPoints; ClipperLib::PolyNode *p2 = out.GetFirst(); ERR_FAIL_COND_V(!p2, points); while (p2->IsHole()) { p2 = p2->GetNext(); } int lasti = p2->Contour.size() - 1; Vector2 prev = Vector2(p2->Contour[lasti].X / PRECISION, p2->Contour[lasti].Y / PRECISION); for (unsigned int i = 0; i < p2->Contour.size(); i++) { Vector2 cur = Vector2(p2->Contour[i].X / PRECISION, p2->Contour[i].Y / PRECISION); if (cur.distance_to(prev) > 0.5) { outPoints.push_back(cur); prev = cur; } } return outPoints; }
std::vector<Vec2> AutoPolygon::expand(const std::vector<Vec2>& points, const cocos2d::Rect &rect, const float& epsilon) { auto size = points.size(); // if there are less than 3 points, then we have nothing if(size<3) { log("AUTOPOLYGON: cannot expand points for %s with less than 3 points, e: %f", _filename.c_str(), epsilon); return std::vector<Vec2>(); } ClipperLib::Path subj; ClipperLib::PolyTree solution; ClipperLib::PolyTree out; for(std::vector<Vec2>::const_iterator it = points.begin(); it<points.end(); it++) { subj << ClipperLib::IntPoint(it-> x* PRECISION, it->y * PRECISION); } ClipperLib::ClipperOffset co; co.AddPath(subj, ClipperLib::jtMiter, ClipperLib::etClosedPolygon); co.Execute(solution, epsilon * PRECISION); ClipperLib::PolyNode* p = solution.GetFirst(); if(!p) { log("AUTOPOLYGON: Clipper failed to expand the points"); return points; } while(p->IsHole()){ p = p->GetNext(); } //turn the result into simply polygon (AKA, fix overlap) //clamp into the specified rect ClipperLib::Clipper cl; cl.StrictlySimple(true); cl.AddPath(p->Contour, ClipperLib::ptSubject, true); //create the clipping rect ClipperLib::Path clamp; clamp.push_back(ClipperLib::IntPoint(0, 0)); clamp.push_back(ClipperLib::IntPoint(rect.size.width/_scaleFactor * PRECISION, 0)); clamp.push_back(ClipperLib::IntPoint(rect.size.width/_scaleFactor * PRECISION, rect.size.height/_scaleFactor * PRECISION)); clamp.push_back(ClipperLib::IntPoint(0, rect.size.height/_scaleFactor * PRECISION)); cl.AddPath(clamp, ClipperLib::ptClip, true); cl.Execute(ClipperLib::ctIntersection, out); std::vector<Vec2> outPoints; ClipperLib::PolyNode* p2 = out.GetFirst(); while(p2->IsHole()){ p2 = p2->GetNext(); } auto end = p2->Contour.end(); for(std::vector<ClipperLib::IntPoint>::const_iterator pt = p2->Contour.begin(); pt < end; pt++) { outPoints.push_back(Vec2(pt->X/PRECISION, pt->Y/PRECISION)); } return outPoints; }
// This is a safe variant of the polygon offset, tailored for a single ExPolygon: // a single polygon with multiple non-overlapping holes. // Each contour and hole is offsetted separately, then the holes are subtracted from the outer contours. ClipperLib::Paths _offset(const Slic3r::ExPolygon &expolygon, const float delta, ClipperLib::JoinType joinType, double miterLimit) { // printf("new ExPolygon offset\n"); // 1) Offset the outer contour. const float delta_scaled = delta * float(CLIPPER_OFFSET_SCALE); ClipperLib::Paths contours; { ClipperLib::Path input = Slic3rMultiPoint_to_ClipperPath(expolygon.contour); scaleClipperPolygon(input); ClipperLib::ClipperOffset co; if (joinType == jtRound) co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE); else co.MiterLimit = miterLimit; co.ShortestEdgeLength = double(std::abs(delta_scaled * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR)); co.AddPath(input, joinType, ClipperLib::etClosedPolygon); co.Execute(contours, delta_scaled); } // 2) Offset the holes one by one, collect the results. ClipperLib::Paths holes; { holes.reserve(expolygon.holes.size()); for (Polygons::const_iterator it_hole = expolygon.holes.begin(); it_hole != expolygon.holes.end(); ++ it_hole) { ClipperLib::Path input = Slic3rMultiPoint_to_ClipperPath_reversed(*it_hole); scaleClipperPolygon(input); ClipperLib::ClipperOffset co; if (joinType == jtRound) co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE); else co.MiterLimit = miterLimit; co.ShortestEdgeLength = double(std::abs(delta_scaled * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR)); co.AddPath(input, joinType, ClipperLib::etClosedPolygon); ClipperLib::Paths out; co.Execute(out, - delta_scaled); holes.insert(holes.end(), out.begin(), out.end()); } } // 3) Subtract holes from the contours. ClipperLib::Paths output; if (holes.empty()) { output = std::move(contours); } else { ClipperLib::Clipper clipper; clipper.Clear(); clipper.AddPaths(contours, ClipperLib::ptSubject, true); clipper.AddPaths(holes, ClipperLib::ptClip, true); clipper.Execute(ClipperLib::ctDifference, output, ClipperLib::pftNonZero, ClipperLib::pftNonZero); } // 4) Unscale the output. unscaleClipperPolygons(output); return output; }
bool BooleanTool::executeForObjects(PathObject* subject, PathObjects& in_objects, PathObjects& out_objects) { // Convert the objects to Clipper polygons and // create a hash map, mapping point positions to the PathCoords. // These paths are to be regarded as closed. PolyMap polymap; ClipperLib::Paths subject_polygons; pathObjectToPolygons(subject, subject_polygons, polymap); ClipperLib::Paths clip_polygons; for (PathObject* object : in_objects) { if (object != subject) { pathObjectToPolygons(object, clip_polygons, polymap); } } // Do the operation. ClipperLib::Clipper clipper; clipper.AddPaths(subject_polygons, ClipperLib::ptSubject, true); clipper.AddPaths(clip_polygons, ClipperLib::ptClip, true); ClipperLib::ClipType clip_type; ClipperLib::PolyFillType fill_type = ClipperLib::pftNonZero; switch (op) { case Union: clip_type = ClipperLib::ctUnion; break; case Intersection: clip_type = ClipperLib::ctIntersection; break; case Difference: clip_type = ClipperLib::ctDifference; break; case XOr: clip_type = ClipperLib::ctXor; break; case MergeHoles: clip_type = ClipperLib::ctUnion; fill_type = ClipperLib::pftPositive; break; default: Q_ASSERT(false && "Undefined operation"); return false; } ClipperLib::PolyTree solution; bool success = clipper.Execute(clip_type, solution, fill_type, fill_type); if (success) { // Try to convert the solution polygons to objects again polyTreeToPathObjects(solution, out_objects, subject, polymap); } return success; }
ClipperLib::Polygons NavMesh::_processWalkableObstacleRegions(const ClipperLib::Polygons& walkable, const ClipperLib::Polygons& obstacles) { ClipperLib::Clipper clipper; ClipperLib::Polygons solution; clipper.AddPolygons(walkable, ClipperLib::ptSubject ); clipper.AddPolygons(obstacles, ClipperLib::ptClip); clipper.Execute(ClipperLib::ctDifference, solution, ClipperLib::PolyFillType::pftNonZero, ClipperLib::PolyFillType::pftNonZero ); return solution; }
ExPolygons ClipperPaths_to_Slic3rExPolygons(const ClipperLib::Paths &input) { // init Clipper ClipperLib::Clipper clipper; clipper.Clear(); // perform union clipper.AddPaths(input, ClipperLib::ptSubject, true); ClipperLib::PolyTree polytree; clipper.Execute(ClipperLib::ctUnion, polytree, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd); // offset results work with both EvenOdd and NonZero // write to ExPolygons object return PolyTreeToExPolygons(polytree); }
std::vector<polygon> polygon::subtract(const polygon& subtrahend) const { ClipperLib::Clipper poly; auto maxDenom = lcm(this->highestDenominator(), subtrahend.highestDenominator()); poly.AddPath(this->path(maxDenom), ClipperLib::PolyType::ptSubject, true); poly.AddPath(subtrahend.path(maxDenom), ClipperLib::PolyType::ptClip, true); ClipperLib::Paths returnedPaths; poly.Execute(ClipperLib::ClipType::ctDifference, returnedPaths); return polygon::from(returnedPaths, maxDenom); }
Polygons top_level_islands(const Slic3r::Polygons &polygons) { // init Clipper ClipperLib::Clipper clipper; clipper.Clear(); // perform union clipper.AddPaths(Slic3rMultiPoints_to_ClipperPaths(polygons), ClipperLib::ptSubject, true); ClipperLib::PolyTree polytree; clipper.Execute(ClipperLib::ctUnion, polytree, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd); // Convert only the top level islands to the output. Polygons out; out.reserve(polytree.ChildCount()); for (int i = 0; i < polytree.ChildCount(); ++i) out.emplace_back(ClipperPath_to_Slic3rPolygon(polytree.Childs[i]->Contour)); return out; }
void PlaneExt::ConcaveHullJoinCurrent(pcl::PointCloud<pcl::PointXYZ>::Ptr &plane_hull, tVertices &polygon_indices) { // Join new polygon with current ClipperLib::ExPolygons newPoly = PolygonizeConcaveHull(plane_hull, polygon_indices); ClipperLib::Clipper clipper; // insert all existing polygons for (unsigned int i = 0; i < planePolygonsClipper.size(); ++i) clipper.AddPolygon(planePolygonsClipper[i].outer, ClipperLib::ptSubject); // insert all new polygons for (unsigned int i = 0; i < newPoly.size(); ++i) clipper.AddPolygon(newPoly[i].outer, ClipperLib::ptClip); // execute join operation clipper.Execute(ClipperLib::ctUnion, planePolygonsClipper); }
/* std::vector<Polygon> DecomposePolygonToConvexhulls(const Polygon& polygon) { using VHACD::IVHACD; TriangleMesh mesh = TriangulatePolygon(polygon); std::vector<float> points; points.reserve(2 * mesh.vertices.size()); for (auto& vertex : mesh.vertices) { points.emplace_back(vertex(0)); points.emplace_back(vertex(1)); } std::vector<int> triangle_indices; triangle_indices.reserve(mesh.faces.size() * 3); for (auto& tr_idx : mesh.faces) { triangle_indices.emplace_back(tr_idx[0]); triangle_indices.emplace_back(tr_idx[1]); triangle_indices.emplace_back(tr_idx[2]); } IVHACD::Parameters params; // // params.m_maxNumVerticesPerCH = 8; params.m_oclAcceleration = false; IVHACD* vhacd_interface = VHACD::CreateVHACD(); bool res = vhacd_interface->Compute(points.data(), 2, mesh.vertices.size(), triangle_indices.data(), 3, mesh.faces.size(), params); std::vector<Polygon> polygons; if (res) { size_t num_hulls = vhacd_interface->GetNConvexHulls(); IVHACD::ConvexHull hull; for (size_t p = 0; p < num_hulls; ++p) { vhacd_interface->GetConvexHull(p, hull); for (size_t v = 0; v < hull.m_nPoints; ++v) { std::cout << p << " "; std::cout << hull.m_points[3 * v + 0] << " "; std::cout << hull.m_points[3 * v + 1] << " "; std::cout << hull.m_points[3 * v + 2] << "\n"; } } } else { std::cerr << "convex hull decomposition not successfull! fall back to " "triangulation!\n"; } vhacd_interface->Clean(); vhacd_interface->Release(); exit(0); return polygons; } */ std::vector<Polygon2D> ResolveIntersections(const Polygon2D& polygon) { // the polygon boundary maybe splitted during this process // auto paths = ResolveIntersectionsClosedPath(polygon.path); // auto holes = ResolveIntersectionsClosedPaths(polygon.holes); ClipperLib::Clipper clipper; ClipperLib::Path scaled_path = UScalePathDiaToClipper(polygon.path); clipper.AddPath(scaled_path, ClipperLib::ptSubject, true); /* for (auto& path : paths) { ClipperLib::Path scaled_path = UScalePathDiaToClipper(path); clipper.AddPath(scaled_path, ClipperLib::ptSubject, true); }*/ for (auto& hole : polygon.holes) { ClipperLib::Path scaled_hole = UScalePathDiaToClipper(hole); clipper.AddPath(scaled_hole, ClipperLib::ptClip, true); } ClipperLib::PolyTree path_tree; clipper.StrictlySimple(true); clipper.Execute(ClipperLib::ctDifference, path_tree, ClipperLib::pftNonZero, ClipperLib::pftNonZero); // iterating into the tree std::vector<Polygon2D> polygons; // only store the pointer to outer polygons std::unordered_map<ClipperLib::PolyNode*, size_t> polynode_map; for (ClipperLib::PolyNode* node_ptr = path_tree.GetFirst(); node_ptr; node_ptr = node_ptr->GetNext()) { ClipperLib::PolyNode* poly_ptr = node_ptr; while (poly_ptr && poly_ptr->IsHole()) { poly_ptr = poly_ptr->Parent; } if (polynode_map.find(poly_ptr) == polynode_map.end()) { polygons.emplace_back(Polygon2D()); polygons.back().path = DScalePathClipperToDia(poly_ptr->Contour); polynode_map[poly_ptr] = polygons.size() - 1; } else { polygons[polynode_map[poly_ptr]].holes.emplace_back( DScalePathClipperToDia(node_ptr->Contour)); } } return polygons; }
GeometryCollection fixupPolygons(const GeometryCollection& rings) { ClipperLib::Clipper clipper; clipper.StrictlySimple(true); for (const auto& ring : rings) { clipper.AddPath(toClipperPath(ring), ClipperLib::ptSubject, true); } ClipperLib::PolyTree polygons; clipper.Execute(ClipperLib::ctUnion, polygons, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd); clipper.Clear(); GeometryCollection result; for (auto * polynode : polygons.Childs) { processPolynodeBranch(polynode, result); } return result; }
void ClipperPaths_to_Slic3rExPolygons(const ClipperLib::Paths &input, Slic3r::ExPolygons &output) { // init Clipper ClipperLib::Clipper clipper; clipper.Clear(); // perform union clipper.AddPaths(input, ClipperLib::ptSubject, true); ClipperLib::PolyTree* polytree = new ClipperLib::PolyTree(); clipper.Execute(ClipperLib::ctUnion, *polytree, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd); // offset results work with both EvenOdd and NonZero // write to ExPolygons object output.clear(); PolyTreeToExPolygons(*polytree, output); delete polytree; }
void simplify_polygons(const Slic3r::Polygons &subject, Slic3r::Polygons* retval, bool preserve_collinear) { // convert into Clipper polygons ClipperLib::Paths input_subject, output; Slic3rMultiPoints_to_ClipperPaths(subject, &input_subject); if (preserve_collinear) { ClipperLib::Clipper c; c.PreserveCollinear(true); c.StrictlySimple(true); c.AddPaths(input_subject, ClipperLib::ptSubject, true); c.Execute(ClipperLib::ctUnion, output, ClipperLib::pftNonZero, ClipperLib::pftNonZero); } else { ClipperLib::SimplifyPolygons(input_subject, output, ClipperLib::pftNonZero); } // convert into Slic3r polygons ClipperPaths_to_Slic3rMultiPoints(output, retval); }
ExPolygons simplify_polygons_ex(const Polygons &subject, bool preserve_collinear) { if (! preserve_collinear) return union_ex(simplify_polygons(subject, false)); // convert into Clipper polygons ClipperLib::Paths input_subject = Slic3rMultiPoints_to_ClipperPaths(subject); ClipperLib::PolyTree polytree; ClipperLib::Clipper c; c.PreserveCollinear(true); c.StrictlySimple(true); c.AddPaths(input_subject, ClipperLib::ptSubject, true); c.Execute(ClipperLib::ctUnion, polytree, ClipperLib::pftNonZero, ClipperLib::pftNonZero); // convert into ExPolygons return PolyTreeToExPolygons(polytree); }
EaglePolygon::EaglePolygon(QPolygonF _vertices, qreal _width, int _layer, qreal _spacing) { width = _width; layer = _layer; spacing = _spacing; sourcePoly.resize(_vertices.count()); for (int i = 0; i < _vertices.count(); i++) { ClipperLib::long64 x = (ClipperLib::long64)(_vertices.at(i).x()*RES); ClipperLib::long64 y = (ClipperLib::long64)(_vertices.at(i).y()*RES); sourcePoly[0].push_back(ClipperLib::IntPoint(x,y)); } ClipperLib::Clipper c; c.AddPolygons(sourcePoly, ClipperLib::ptSubject); c.Execute(ClipperLib::ctUnion,sourcePoly); // only makes sure polys orientation is correct ClipperLib::OffsetPolygons(sourcePoly,buffedPoly, width*RES/2, ClipperLib::jtRound); // offset for (unsigned int i = 0; i < buffedPoly[0].size(); i++) { vertices.append(QPointF(buffedPoly[0].at(i).X/RES, buffedPoly[0].at(i).Y/RES)); } }
void _clipper_do(const ClipperLib::ClipType clipType, const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, T* retval, const ClipperLib::PolyFillType fillType, const bool safety_offset_) { PROFILE_BLOCK(_clipper_do_polygons); // read input ClipperLib::Paths input_subject, input_clip; Slic3rMultiPoints_to_ClipperPaths(subject, &input_subject); Slic3rMultiPoints_to_ClipperPaths(clip, &input_clip); // perform safety offset if (safety_offset_) { if (clipType == ClipperLib::ctUnion) { safety_offset(&input_subject); } else { safety_offset(&input_clip); } } // init Clipper ClipperLib::Clipper clipper; clipper.Clear(); // add polygons { PROFILE_BLOCK(_clipper_do_polygons_AddPaths); clipper.AddPaths(input_subject, ClipperLib::ptSubject, true); clipper.AddPaths(input_clip, ClipperLib::ptClip, true); #ifdef CLIPPER_UTILS_DEBUG if (clipper_export_enabled) { static int iRun = 0; export_clipper_input_polygons_bin(debug_out_path("_clipper_do_polygons_AddPaths-polygons-%d", ++iRun).c_str(), input_subject, input_clip); } #endif /* CLIPPER_UTILS_DEBUG */ } // perform operation { PROFILE_BLOCK(_clipper_do_polygons_Execute); clipper.Execute(clipType, *retval, fillType, fillType); } }
// clip infill pattern polys against polys void Infill::addInfill(double z, const vector<Poly> polys, const ClipperLib::Polygons patterncpolys, double offsetDistance) { ClipperLib::Polygons cpolys; // ClipperLib::OffsetPolygons(Clipping::getClipperPolygons(polys), cpolys, 100, // ClipperLib::jtMiter,1); // else cpolys = Clipping::getClipperPolygons(polys); ClipperLib::Clipper clpr; clpr.AddPolygons(patterncpolys,ClipperLib::ptSubject); clpr.AddPolygons(cpolys,ClipperLib::ptClip); ClipperLib::Polygons result; clpr.Execute(ClipperLib::ctIntersection, result, ClipperLib::pftEvenOdd, ClipperLib::pftNonZero); if (type==PolyInfill) { // reversal from evenodd clipping for (uint i = 0; i<result.size(); i+=2) std::reverse(result[i].begin(),result[i].end()); } addInfillPolys(Clipping::getPolys(result, z, extrusionfactor)); }
geo::Polygon<geo::Ring<Vector>> Environment::subtract(geo::Polygon<geo::Ring<Vector>> const& poly, geo::Ring<Vector> const& ring) { ClipperLib::Path subj; ClipperLib::Paths solution; ClipperLib::Clipper c; for (Vector const& v : poly.ering) subj.push_back(ClipperLib::IntPoint((int)v.x, (int)v.y)); c.AddPath(subj, ClipperLib::ptSubject, true); for (Ring const& ring : poly.irings) { subj.clear(); for (Vector const& v : ring) subj.push_back(ClipperLib::IntPoint((int)v.x, (int)v.y)); std::reverse(subj.begin(), subj.end()); c.AddPath(subj, ClipperLib::ptSubject, true); } subj.clear(); for (Vector const& v : ring) subj.push_back(ClipperLib::IntPoint((int)v.x, (int)v.y)); c.AddPath(subj, ClipperLib::ptClip, true); c.Execute(ClipperLib::ctDifference, solution); geo::Polygon<geo::Ring<Vector>> ans; for (ClipperLib::IntPoint const& pt : solution[0]) { ans.ering.push_back({pt.X, pt.Y}); } for (int i = 1; i < solution.size(); ++i) { ClipperLib::Path const& path = solution[i]; geo::Ring<Vector> ring; for (ClipperLib::IntPoint const& pt : path) ring.push_back({pt.X, pt.Y}); ans.irings.push_back(ring); } geo::correct(ans); return ans; }
double poly_intersection(const ContContainer& poly1, const ContContainer& poly2) { /* ************* TEMPORAL ************ * Conversion, we should remove junctions from container * or define it for our containers */ ClipperLib::Paths paths1(poly1.begin(),poly1.end()); ClipperLib::Paths paths2(poly2.begin(),poly2.end()); /* Get the intersection polygon */ ClipperLib::Clipper clpr; clpr.AddPaths(paths1, ClipperLib::ptSubject, true); clpr.AddPaths(paths2, ClipperLib::ptClip , true); ClipperLib::Paths solution; clpr.Execute(ClipperLib::ctIntersection, solution, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd); /* Get its area */ double int_area = 0; for(std::size_t ii=0; ii<solution.size(); ++ii) int_area += std::abs(ClipperLib::Area(solution[ii])); return int_area; }
void _clipper_do(const ClipperLib::ClipType clipType, const Slic3r::Polylines &subject, const Slic3r::Polygons &clip, ClipperLib::PolyTree &retval, const ClipperLib::PolyFillType fillType) { // read input ClipperLib::Paths* input_subject = new ClipperLib::Paths(); ClipperLib::Paths* input_clip = new ClipperLib::Paths(); Slic3rMultiPoints_to_ClipperPaths(subject, *input_subject); Slic3rMultiPoints_to_ClipperPaths(clip, *input_clip); // init Clipper ClipperLib::Clipper clipper; clipper.Clear(); // add polygons clipper.AddPaths(*input_subject, ClipperLib::ptSubject, false); delete input_subject; clipper.AddPaths(*input_clip, ClipperLib::ptClip, true); delete input_clip; // perform operation clipper.Execute(clipType, retval, fillType, fillType); }
void PolyMesh::chopPoly(const Polygon & rect, int pid,ClipperLib::ClipType ct) { ClipperLib::Clipper c; c.AddPolygon(poly[pid][0],ClipperLib::ptSubject); c.AddPolygon(rect,ClipperLib::ptClip); Polygons solution; bool ret = c.Execute(ct,solution); if(solution.size()<1) { std::cout<<"ret "<<ret<<" "<<pid<<" is completely clipped\n"; } else { std::cout<<"plane "<<pid<<"\n"; std::cout<<"soln size "<<solution.size()<<"\n"; size_t maxsize=solution[0].size(); int maxidx=0; for(size_t jj=1; jj<solution.size(); jj++) { if(solution[jj].size()>maxsize) { maxsize=solution[jj].size(); maxidx=jj; } } poly[pid][0]=solution[maxidx]; } }
// This is a safe variant of the polygons offset, tailored for multiple ExPolygons. // It is required, that the input expolygons do not overlap and that the holes of each ExPolygon don't intersect with their respective outer contours. // Each ExPolygon is offsetted separately, then the offsetted ExPolygons are united. ClipperLib::Paths _offset(const Slic3r::ExPolygons &expolygons, const float delta, ClipperLib::JoinType joinType, double miterLimit) { const float delta_scaled = delta * float(CLIPPER_OFFSET_SCALE); // Offsetted ExPolygons before they are united. ClipperLib::Paths contours_cummulative; contours_cummulative.reserve(expolygons.size()); // How many non-empty offsetted expolygons were actually collected into contours_cummulative? // If only one, then there is no need to do a final union. size_t expolygons_collected = 0; for (Slic3r::ExPolygons::const_iterator it_expoly = expolygons.begin(); it_expoly != expolygons.end(); ++ it_expoly) { // 1) Offset the outer contour. ClipperLib::Paths contours; { ClipperLib::Path input = Slic3rMultiPoint_to_ClipperPath(it_expoly->contour); scaleClipperPolygon(input); ClipperLib::ClipperOffset co; if (joinType == jtRound) co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE); else co.MiterLimit = miterLimit; co.ShortestEdgeLength = double(std::abs(delta_scaled * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR)); co.AddPath(input, joinType, ClipperLib::etClosedPolygon); co.Execute(contours, delta_scaled); } if (contours.empty()) // No need to try to offset the holes. continue; if (it_expoly->holes.empty()) { // No need to subtract holes from the offsetted expolygon, we are done. contours_cummulative.insert(contours_cummulative.end(), contours.begin(), contours.end()); ++ expolygons_collected; } else { // 2) Offset the holes one by one, collect the offsetted holes. ClipperLib::Paths holes; { for (Polygons::const_iterator it_hole = it_expoly->holes.begin(); it_hole != it_expoly->holes.end(); ++ it_hole) { ClipperLib::Path input = Slic3rMultiPoint_to_ClipperPath_reversed(*it_hole); scaleClipperPolygon(input); ClipperLib::ClipperOffset co; if (joinType == jtRound) co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE); else co.MiterLimit = miterLimit; co.ShortestEdgeLength = double(std::abs(delta_scaled * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR)); co.AddPath(input, joinType, ClipperLib::etClosedPolygon); ClipperLib::Paths out; co.Execute(out, - delta_scaled); holes.insert(holes.end(), out.begin(), out.end()); } } // 3) Subtract holes from the contours. if (holes.empty()) { // No hole remaining after an offset. Just copy the outer contour. contours_cummulative.insert(contours_cummulative.end(), contours.begin(), contours.end()); ++ expolygons_collected; } else if (delta < 0) { // Negative offset. There is a chance, that the offsetted hole intersects the outer contour. // Subtract the offsetted holes from the offsetted contours. ClipperLib::Clipper clipper; clipper.Clear(); clipper.AddPaths(contours, ClipperLib::ptSubject, true); clipper.AddPaths(holes, ClipperLib::ptClip, true); ClipperLib::Paths output; clipper.Execute(ClipperLib::ctDifference, output, ClipperLib::pftNonZero, ClipperLib::pftNonZero); if (! output.empty()) { contours_cummulative.insert(contours_cummulative.end(), output.begin(), output.end()); ++ expolygons_collected; } else { // The offsetted holes have eaten up the offsetted outer contour. } } else { // Positive offset. As long as the Clipper offset does what one expects it to do, the offsetted hole will have a smaller // area than the original hole or even disappear, therefore there will be no new intersections. // Just collect the reversed holes. contours_cummulative.reserve(contours.size() + holes.size()); contours_cummulative.insert(contours_cummulative.end(), contours.begin(), contours.end()); // Reverse the holes in place. for (size_t i = 0; i < holes.size(); ++ i) std::reverse(holes[i].begin(), holes[i].end()); contours_cummulative.insert(contours_cummulative.end(), holes.begin(), holes.end()); ++ expolygons_collected; } } } // 4) Unite the offsetted expolygons. ClipperLib::Paths output; if (expolygons_collected > 1 && delta > 0) { // There is a chance that the outwards offsetted expolygons may intersect. Perform a union. ClipperLib::Clipper clipper; clipper.Clear(); clipper.AddPaths(contours_cummulative, ClipperLib::ptSubject, true); clipper.Execute(ClipperLib::ctUnion, output, ClipperLib::pftNonZero, ClipperLib::pftNonZero); } else { // Negative offset. The shrunk expolygons shall not mutually intersect. Just copy the output. output = std::move(contours_cummulative); } // 4) Unscale the output. unscaleClipperPolygons(output); return output; }
BOOL GamePhysicsWorld::ClipperPolygonByShape( GameSprite* ptr_gamesprite, const std::string &shape_name, float float_position_x, float float_position_y ) { int num_result = FALSE; int num_ret_code = FALSE; b2Body* ptr_b2body_old = NULL; b2Fixture* ptr_b2fixture = NULL; b2Body* ptr_b2body_new = NULL; b2BodyDef bodyDef; b2Concave b2concave; ClipperLib::Paths clipper_paths_clipper(1); float float_offset_x = 0.0f; float float_offset_y = 0.0f; KGLOG_PROCESS_ERROR(ptr_gamesprite); ptr_b2body_old = ptr_gamesprite->GetB2Body(); KGLOG_PROCESS_ERROR(ptr_b2body_old); bodyDef.position = ptr_b2body_old->GetPosition(); float_offset_x = float_position_x - bodyDef.position.x * PTM_RATIO; float_offset_y = float_position_y - bodyDef.position.y * PTM_RATIO; bodyDef.type = ptr_b2body_old->GetType(); bodyDef.userData = ptr_b2body_old->GetUserData(); ptr_b2body_new = m_ptr_b2world->CreateBody(&bodyDef); ptr_b2fixture = ptr_b2body_old->GetFixtureList(); KGLOG_PROCESS_ERROR(ptr_b2fixture); num_ret_code = getPolygonFromCache(shape_name, &clipper_paths_clipper, float_offset_x, float_offset_y); KGLOG_PROCESS_ERROR(num_ret_code); while (ptr_b2fixture) { ClipperLib::Paths clipper_paths_main(1); ClipperLib::Paths clipper_paths_result; ClipperLib::Clipper clipper; num_ret_code = getPolygonFormBody(ptr_b2fixture, &clipper_paths_main); KGLOG_PROCESS_ERROR(num_ret_code); num_ret_code = clipper.AddPaths(clipper_paths_main, ptSubject, true); KGLOG_PROCESS_ERROR(num_ret_code); num_ret_code = clipper.AddPaths(clipper_paths_clipper, ptClip, true); KGLOG_PROCESS_ERROR(num_ret_code); num_ret_code = clipper.Execute(ClipperLib::ctDifference, clipper_paths_result, pftNonZero, pftNonZero); KGLOG_PROCESS_ERROR(num_ret_code); Paths::iterator it_group = clipper_paths_result.begin(); for(NULL; it_group != clipper_paths_result.end(); ++it_group) { Path::iterator it = it_group->begin(); b2Vec2 vec_vertices[1000]; int count_vertices = 0; b2FixtureDef b2fixturedef_new; b2fixturedef_new.restitution = ptr_b2fixture->GetRestitution(); b2fixturedef_new.friction = ptr_b2fixture->GetFriction(); b2fixturedef_new.density = ptr_b2fixture->GetDensity(); for(NULL; it != it_group->end(); ++it) { vec_vertices[count_vertices++].Set(float(it->X) / (PTM_RATIO * CLIPPER_RATIO), float(it->Y) / (PTM_RATIO * CLIPPER_RATIO)); } num_ret_code = b2concave.Create(ptr_b2body_new, &b2fixturedef_new, vec_vertices, count_vertices); KGLOG_PROCESS_ERROR(num_ret_code); } ptr_b2fixture = ptr_b2fixture->GetNext(); } num_ret_code = ptr_gamesprite->SetB2Body(ptr_b2body_new); KGLOG_PROCESS_ERROR(num_ret_code); m_ptr_b2world->DestroyBody(ptr_b2body_old); ptr_b2body_old = NULL; num_result = TRUE; Exit0: if (!num_result) { if(ptr_b2body_new) { m_ptr_b2world->DestroyBody(ptr_b2body_new); ptr_b2body_new = NULL; } } return num_result; }
// This is a safe variant of the polygon offset, tailored for a single ExPolygon: // a single polygon with multiple non-overlapping holes. // Each contour and hole is offsetted separately, then the holes are subtracted from the outer contours. void offset(const Slic3r::ExPolygons &expolygons, ClipperLib::Paths* retval, const float delta, ClipperLib::JoinType joinType, double miterLimit) { // printf("new ExPolygon offset\n"); const float delta_scaled = delta * float(CLIPPER_OFFSET_SCALE); ClipperLib::Paths contours; ClipperLib::Paths holes; contours.reserve(expolygons.size()); { size_t n_holes = 0; for (size_t i = 0; i < expolygons.size(); ++ i) n_holes += expolygons[i].holes.size(); holes.reserve(n_holes); } for (Slic3r::ExPolygons::const_iterator it_expoly = expolygons.begin(); it_expoly != expolygons.end(); ++ it_expoly) { // 1) Offset the outer contour. { ClipperLib::Path input; Slic3rMultiPoint_to_ClipperPath(it_expoly->contour, &input); scaleClipperPolygon(input); ClipperLib::ClipperOffset co; if (joinType == jtRound) co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE); else co.MiterLimit = miterLimit; co.AddPath(input, joinType, ClipperLib::etClosedPolygon); ClipperLib::Paths out; co.Execute(out, delta_scaled); contours.insert(contours.end(), out.begin(), out.end()); } // 2) Offset the holes one by one, collect the results. { for (Polygons::const_iterator it_hole = it_expoly->holes.begin(); it_hole != it_expoly->holes.end(); ++ it_hole) { ClipperLib::Path input; Slic3rMultiPoint_to_ClipperPath_reversed(*it_hole, &input); scaleClipperPolygon(input); ClipperLib::ClipperOffset co; if (joinType == jtRound) co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE); else co.MiterLimit = miterLimit; co.AddPath(input, joinType, ClipperLib::etClosedPolygon); ClipperLib::Paths out; co.Execute(out, - delta_scaled); holes.insert(holes.end(), out.begin(), out.end()); } } } // 3) Subtract holes from the contours. ClipperLib::Paths output; { ClipperLib::Clipper clipper; clipper.Clear(); clipper.AddPaths(contours, ClipperLib::ptSubject, true); clipper.AddPaths(holes, ClipperLib::ptClip, true); clipper.Execute(ClipperLib::ctDifference, *retval, ClipperLib::pftNonZero, ClipperLib::pftNonZero); } // 4) Unscale the output. unscaleClipperPolygons(*retval); }