diff --git a/src/Mod/Path/PathScripts/PathAdaptive.py b/src/Mod/Path/PathScripts/PathAdaptive.py index 738caafbc7..766c3a4d1b 100644 --- a/src/Mod/Path/PathScripts/PathAdaptive.py +++ b/src/Mod/Path/PathScripts/PathAdaptive.py @@ -16,75 +16,6 @@ def discretize(edge, flipDirection=False): if flipDirection: pts.reverse() return pts -def IsEqualInXYPlane(e1, e2): - return math.sqrt((e2.x-e1.x)*(e2.x-e1.x) + - (e2.y - e1.y) * (e2.y - e1.y))<0.01 - -def connectEdges(edges): - ''' Makes the list of connected discretized paths ''' - # find edge - lastPoint=None - remaining = [] - pathArray = [] - combined = [] - for edge in edges: - #print edge - p1 = edge.valueAt(edge.FirstParameter) - p2 = edge.valueAt(edge.LastParameter) - m1 = edge.valueAt((edge.LastParameter+edge.LastParameter)/2) - duplicate = False - for ex in remaining: - exp1 = ex.valueAt(ex.FirstParameter) - exp2 = ex.valueAt(ex.LastParameter) - exm1 = ex.valueAt((ex.FirstParameter + ex.LastParameter)/2) - if IsEqualInXYPlane(exp1, p1) and IsEqualInXYPlane(exp2, p2) and IsEqualInXYPlane(exm1, m1): - duplicate = True - #print "duplicate" - if IsEqualInXYPlane(exp1, p2) and IsEqualInXYPlane(exp2, p1) and IsEqualInXYPlane(exm1, m1): - duplicate = True - #print "duplicate" - - if not duplicate: - remaining.append(edge) - - newPath=True - while len(remaining)>0: - if newPath: - edge=remaining[0] - p1 = edge.valueAt(edge.FirstParameter) - p2 = edge.valueAt(edge.LastParameter) - if len(combined)>0: pathArray.append(combined) - combined = [] - combined.append(discretize(edge)) - remaining.remove(edge) - lastPoint=p2 - newPath=False - - anyMatch=False - for e in remaining: - p1 = e.valueAt(e.FirstParameter) - p2 = e.valueAt(e.LastParameter) - if IsEqualInXYPlane(lastPoint,p1): - combined.append(discretize(e)) - remaining.remove(e) - lastPoint=p2 - anyMatch=True - break - elif IsEqualInXYPlane(lastPoint,p2): - combined.append(discretize(e,True)) - remaining.remove(e) - lastPoint=p1 - anyMatch=True - break - if not anyMatch: - newPath=True - - - #make sure last path is appended - if len(combined)>0: pathArray.append(combined) - combined = [] - return pathArray - def convertTo2d(pathArray): output = [] for path in pathArray: @@ -267,14 +198,15 @@ def Execute(op,obj): obj.StopProcessing = False if obj.Tolerance<0.001: obj.Tolerance=0.001 - edges=[] + pathArray=[] for base, subs in obj.Base: for sub in subs: shape=base.Shape.getElement(sub) for edge in shape.Edges: - edges.append(edge) + pathArray.append([discretize(edge)]) - pathArray=connectEdges(edges) + #pathArray=connectEdges(edges) + path2d = convertTo2d(pathArray) stockPaths = [] if op.stock.StockType == "CreateCylinder": @@ -289,6 +221,8 @@ def Execute(op,obj): v.append(FreeCAD.Vector(stockBB.XMin,stockBB.YMin,0)) stockPaths.append([v]) + stockPath2d = convertTo2d(stockPaths) + opType = area.AdaptiveOperationType.ClearingInside if obj.OperationType == "Clearing": if obj.Side == "Outside": @@ -301,8 +235,6 @@ def Execute(op,obj): else: opType = area.AdaptiveOperationType.ProfilingInside - path2d = convertTo2d(pathArray) - stockPath2d = convertTo2d(stockPaths) # put here all properties that influence calculation of adaptive base paths, inputStateObject = { @@ -426,7 +358,7 @@ class PathAdaptive(PathOp.ObjectOp): obj.StepOver = 20 obj.LiftDistance=0 # obj.ProcessHoles = True - obj.ForceInsideOut = True + obj.ForceInsideOut = False obj.Stopped = False obj.StopProcessing = False obj.HelixAngle = 5 diff --git a/src/Mod/Path/libarea/Adaptive.cpp b/src/Mod/Path/libarea/Adaptive.cpp index 30bb9e9aab..db02bc656e 100644 --- a/src/Mod/Path/libarea/Adaptive.cpp +++ b/src/Mod/Path/libarea/Adaptive.cpp @@ -13,7 +13,11 @@ namespace ClipperLib { namespace AdaptivePath { using namespace ClipperLib; using namespace std; + #define SAME_POINT_TOL_SQRD_SCALED 16.0 + /********************************************* + * Utils - inline + ***********************************************/ inline double DistanceSqrd(const IntPoint& pt1, const IntPoint& pt2) { @@ -50,10 +54,8 @@ namespace AdaptivePath { } } } - /********************************************* - * Utils - ***********************************************/ - /* inline util*/ + + inline bool HasAnyPath(const Paths &paths) { for(Paths::size_type i=0;i0) return true; @@ -75,7 +77,6 @@ namespace AdaptivePath { return DoublePoint(c*in.X-s*in.Y,s*in.X + c*in.Y); } - // calculates path length for open path inline double PathLength(const Path & path) { double len=0; @@ -86,7 +87,22 @@ namespace AdaptivePath { return len; } - /* geom utils */ + inline double PointSideOfLine(const IntPoint& p1, const IntPoint& p2,const IntPoint& pt) { + return double((pt.X - p1.X)*(p2.Y-p1.Y) - (pt.Y - p2.Y)*(p2.X-p1.X)); + } + + inline double Angle3Points(const DoublePoint & p1,const DoublePoint& p2, const DoublePoint& p3) { + double t1= atan2(p1.Y-p2.Y,p1.X-p2.X); + double t2=atan2(p3.Y-p2.Y,p3.X-p2.X); + double a = fabs( t2 - t1 ); + return min(a,2*M_PI-a); + } + + /********************************************* + * Utils + ***********************************************/ + + void AverageDirection(const vector &unityVectors, DoublePoint& output) { int size=unityVectors.size(); output.X =0; @@ -198,16 +214,6 @@ namespace AdaptivePath { return true; } - inline double PointSideOfLine(const IntPoint& p1, const IntPoint& p2,const IntPoint& pt) { - return double((pt.X - p1.X)*(p2.Y-p1.Y) - (pt.Y - p2.Y)*(p2.X-p1.X)); - } - - inline double Angle3Points(const DoublePoint & p1,const DoublePoint& p2, const DoublePoint& p3) { - double t1= atan2(p1.Y-p2.Y,p1.X-p2.X); - double t2=atan2(p3.Y-p2.Y,p3.X-p2.X); - double a = fabs( t2 - t1 ); - return min(a,2*M_PI-a); - } bool Line2CircleIntersect(const IntPoint &c, double radius,const IntPoint &p1, const IntPoint &p2, vector & result, bool clamp=true) { @@ -703,6 +709,87 @@ namespace AdaptivePath { return true; } + void DeduplicatePaths(const Paths & inputs,Paths & outputs) { + outputs.clear(); + for(const auto & new_pth :inputs) { + bool duplicate=false; + // aff all points of new path exist on some of the old paths, path is considered duplicate + for(const auto & old_pth :outputs) { + bool all_points_exists=true; + for(const auto pt1:new_pth) { + bool pointExists=false; + for(const auto pt2:old_pth) { + if(DistanceSqrd(pt1,pt2)0) { + outputs.push_back(new_pth); + } + } + } + + void ConnectPaths(Paths input,Paths & output) { + // remove duplicate paths + output.clear(); + bool newPath = true; + Path joined; + while(input.size()>0) { + if(newPath) { + auto p1=input.front().front(); + auto p2=input.front().back(); + if(joined.size()>0) output.push_back(joined); + joined.clear(); + for(auto pt:input.front()) { + joined.push_back(pt); + } + input.erase(input.begin()); + newPath=false; + } + bool anyMatch=false; + for(size_t i=0;i0) output.push_back(joined); + } + /**************************************** // Adaptive2d - constructor *****************************************/ @@ -984,15 +1071,18 @@ namespace AdaptivePath { // ********************** // Convert input paths to clipper //************************ - inputPaths.clear(); + Paths converted; for(size_t i=0;i pt = paths[i][j]; cpth.push_back(IntPoint(long(pt.first*scaleFactor),long(pt.second*scaleFactor))); - } - inputPaths.push_back(cpth); + } + converted.push_back(cpth); } + + DeduplicatePaths(converted,inputPaths); + ConnectPaths(inputPaths,inputPaths); SimplifyPolygons(inputPaths); //************************ @@ -1392,7 +1482,7 @@ namespace AdaptivePath { output.AdaptivePaths.push_back(linkPath3); linkFound=true; } - if(!linkFound && keepDownLinkTooLong) { // if to long make link through interim points with tool raise + if(!linkFound && keepDownLinkTooLong) { // if keeptooldown link too long make link through interim points with tool raise // add disengage moves TPath linkPath1; linkPath1.first = MotionType::mtCutting; @@ -1441,7 +1531,7 @@ namespace AdaptivePath { } } } - if(!linkFound) { // noting clear so far - check direct link with no interim points - either this is clear or we need to raise the tool + if(!linkFound) { // nothing clear so far - check direct link with no interim points - either this is clear or we need to raise the tool //cerr << "keepToolDownLinkPath NOT CLEAR" << endl; Path tp; tp << lastPoint; diff --git a/src/Mod/Path/libarea/Adaptive.hpp b/src/Mod/Path/libarea/Adaptive.hpp index 4b2896f43e..e4d1179b9f 100644 --- a/src/Mod/Path/libarea/Adaptive.hpp +++ b/src/Mod/Path/libarea/Adaptive.hpp @@ -130,6 +130,8 @@ namespace AdaptivePath { const time_t PROGRESS_TICKS = CLOCKS_PER_SEC/20; // progress report interval const long OVERSHOOT_ADDON_DIST=2; + + }; } #endif \ No newline at end of file