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); }
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; }
/* 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 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); }