diff --git a/src/Mod/Path/libarea/Area.cpp b/src/Mod/Path/libarea/Area.cpp index f33e338c0427..4755f9effd6b 100644 --- a/src/Mod/Path/libarea/Area.cpp +++ b/src/Mod/Path/libarea/Area.cpp @@ -10,7 +10,11 @@ double CArea::m_accuracy = 0.01; double CArea::m_units = 1.0; +bool CArea::m_clipper_simple = false; +double CArea::m_clipper_clean_distance = 0.0; bool CArea::m_fit_arcs = true; +int CArea::m_min_arc_points = 4; +int CArea::m_max_arc_points = 100; double CArea::m_single_area_processing_length = 0.0; double CArea::m_processing_done = 0.0; bool CArea::m_please_abort = false; diff --git a/src/Mod/Path/libarea/Area.h b/src/Mod/Path/libarea/Area.h index 23937196c15d..56c221e043c9 100644 --- a/src/Mod/Path/libarea/Area.h +++ b/src/Mod/Path/libarea/Area.h @@ -7,6 +7,7 @@ #define AREA_HEADER #include "Curve.h" +#include "clipper.hpp" enum PocketMode { @@ -42,7 +43,11 @@ class CArea std::list m_curves; static double m_accuracy; static double m_units; // 1.0 for mm, 25.4 for inches. All points are multiplied by this before going to the engine + static bool m_clipper_simple; + static double m_clipper_clean_distance; static bool m_fit_arcs; + static int m_min_arc_points; + static int m_max_arc_points; static double m_processing_done; // 0.0 to 100.0, set inside MakeOnePocketCurve static double m_single_area_processing_length; static double m_after_MakeOffsets_length; @@ -50,6 +55,7 @@ class CArea static double m_split_processing_length; static bool m_set_processing_length_in_split; static bool m_please_abort; // the user sets this from another thread, to tell MakeOnePocketCurve to finish with no result. + static double m_clipper_scale; void append(const CCurve& curve); void Subtract(const CArea& a2); @@ -58,6 +64,11 @@ class CArea static CArea UniteCurves(std::list &curves); void Xor(const CArea& a2); void Offset(double inwards_value); + void OffsetWithClipper(double offset, + ClipperLib::JoinType joinType=ClipperLib::jtRound, + ClipperLib::EndType endType=ClipperLib::etOpenRound, + double miterLimit = 5.0, + double roundPrecision = 0.0); void Thicken(double value); void FitArcs(); unsigned int num_curves(){return static_cast(m_curves.size());} diff --git a/src/Mod/Path/libarea/AreaClipper.cpp b/src/Mod/Path/libarea/AreaClipper.cpp index ec5e63730df8..c8c7c7c50f48 100644 --- a/src/Mod/Path/libarea/AreaClipper.cpp +++ b/src/Mod/Path/libarea/AreaClipper.cpp @@ -12,7 +12,7 @@ using namespace ClipperLib; bool CArea::HolesLinked(){ return false; } //static const double PI = 3.1415926535897932; -static double Clipper4Factor = 10000.0; +double CArea::m_clipper_scale = 10000.0; class DoubleAreaPoint { @@ -20,8 +20,8 @@ class DoubleAreaPoint double X, Y; DoubleAreaPoint(double x, double y){X = x; Y = y;} - DoubleAreaPoint(const IntPoint& p){X = (double)(p.X) / Clipper4Factor; Y = (double)(p.Y) / Clipper4Factor;} - IntPoint int_point(){return IntPoint((long64)(X * Clipper4Factor), (long64)(Y * Clipper4Factor));} + DoubleAreaPoint(const IntPoint& p){X = (double)(p.X) / CArea::m_clipper_scale; Y = (double)(p.Y) / CArea::m_clipper_scale;} + IntPoint int_point(){return IntPoint((long64)(X * CArea::m_clipper_scale), (long64)(Y * CArea::m_clipper_scale));} }; static std::list pts_for_AddVertex; @@ -81,10 +81,10 @@ static void AddVertex(const CVertex& vertex, const CVertex* prev_vertex) else Segments=(int)ceil(-phit/dphi); - if (Segments < 1) - Segments=1; - if (Segments > 100) - Segments=100; + if (Segments < CArea::m_min_arc_points) + Segments = CArea::m_min_arc_points; + if (Segments > CArea::m_max_arc_points) + Segments=CArea::m_max_arc_points; dphi=phit/(Segments); @@ -139,6 +139,7 @@ static void MakeLoop(const DoubleAreaPoint &pt0, const DoubleAreaPoint &pt1, con static void OffsetWithLoops(const TPolyPolygon &pp, TPolyPolygon &pp_new, double inwards_value) { Clipper c; + c.StrictlySimple(CArea::m_clipper_simple); bool inwards = (inwards_value > 0); bool reverse = false; @@ -251,6 +252,7 @@ static void MakeObround(const Point &pt0, const CVertex &vt1, double radius) static void OffsetSpansWithObrounds(const CArea& area, TPolyPolygon &pp_new, double radius) { Clipper c; + c.StrictlySimple(CArea::m_clipper_simple); for(std::list::const_iterator It = area.m_curves.begin(); It != area.m_curves.end(); It++) @@ -355,8 +357,11 @@ static void MakePoly(const CCurve& curve, TPolygon &p) } } -static void SetFromResult( CCurve& curve, const TPolygon& p, bool reverse = true ) +static void SetFromResult( CCurve& curve, TPolygon& p, bool reverse = true ) { + if(CArea::m_clipper_clean_distance >= Point::tolerance) + CleanPolygon(p,CArea::m_clipper_clean_distance); + for(unsigned int j = 0; j < p.size(); j++) { const IntPoint &pt = p[j]; @@ -372,14 +377,14 @@ static void SetFromResult( CCurve& curve, const TPolygon& p, bool reverse = true if(CArea::m_fit_arcs)curve.FitArcs(); } -static void SetFromResult( CArea& area, const TPolyPolygon& pp, bool reverse = true ) +static void SetFromResult( CArea& area, TPolyPolygon& pp, bool reverse = true ) { // delete existing geometry area.m_curves.clear(); for(unsigned int i = 0; i < pp.size(); i++) { - const TPolygon& p = pp[i]; + TPolygon& p = pp[i]; area.m_curves.push_back(CCurve()); CCurve &curve = area.m_curves.back(); @@ -390,6 +395,7 @@ static void SetFromResult( CArea& area, const TPolyPolygon& pp, bool reverse = t void CArea::Subtract(const CArea& a2) { Clipper c; + c.StrictlySimple(CArea::m_clipper_simple); TPolyPolygon pp1, pp2; MakePolyPoly(*this, pp1); MakePolyPoly(a2, pp2); @@ -403,6 +409,7 @@ void CArea::Subtract(const CArea& a2) void CArea::Intersect(const CArea& a2) { Clipper c; + c.StrictlySimple(CArea::m_clipper_simple); TPolyPolygon pp1, pp2; MakePolyPoly(*this, pp1); MakePolyPoly(a2, pp2); @@ -416,6 +423,7 @@ void CArea::Intersect(const CArea& a2) void CArea::Union(const CArea& a2) { Clipper c; + c.StrictlySimple(CArea::m_clipper_simple); TPolyPolygon pp1, pp2; MakePolyPoly(*this, pp1); MakePolyPoly(a2, pp2); @@ -430,6 +438,7 @@ void CArea::Union(const CArea& a2) CArea CArea::UniteCurves(std::list &curves) { Clipper c; + c.StrictlySimple(CArea::m_clipper_simple); TPolyPolygon pp; @@ -452,6 +461,7 @@ CArea CArea::UniteCurves(std::list &curves) void CArea::Xor(const CArea& a2) { Clipper c; + c.StrictlySimple(CArea::m_clipper_simple); TPolyPolygon pp1, pp2; MakePolyPoly(*this, pp1); MakePolyPoly(a2, pp2); @@ -471,6 +481,37 @@ void CArea::Offset(double inwards_value) this->Reorder(); } +void CArea::OffsetWithClipper(double offset, + JoinType joinType/* =jtRound */, + EndType endType/* =etOpenRound */, + double miterLimit/* = 5.0 */, + double roundPrecision/* = 0.0 */) +{ + offset *= m_units*m_clipper_scale; + if(roundPrecision == 0.0) { + // Clipper roundPrecision definition: https://goo.gl/4odfQh + double dphi=acos(1.0-m_accuracy*m_clipper_scale/fabs(offset)); + int Segments=(int)ceil(PI/dphi); + if (Segments < 2*CArea::m_min_arc_points) + Segments = 2*CArea::m_min_arc_points; + if (Segments > CArea::m_max_arc_points) + Segments=CArea::m_max_arc_points; + dphi = PI/Segments; + roundPrecision = (1.0-cos(dphi))*fabs(offset); + }else + roundPrecision *= m_clipper_scale; + + ClipperOffset clipper(miterLimit,roundPrecision); + TPolyPolygon pp, pp2; + MakePolyPoly(*this, pp, false); + int i=0; + for(const CCurve &c : m_curves) + clipper.AddPath(pp[i++],joinType,c.IsClosed()?etClosedPolygon:endType); + clipper.Execute(pp2,(long64)(offset)); + SetFromResult(*this, pp2, false); + this->Reorder(); +} + void CArea::Thicken(double value) { TPolyPolygon pp;