diff --git a/src/Mod/Path/libarea/Adaptive.cpp b/src/Mod/Path/libarea/Adaptive.cpp index 2c2069eef0..414ce27211 100644 --- a/src/Mod/Path/libarea/Adaptive.cpp +++ b/src/Mod/Path/libarea/Adaptive.cpp @@ -3,7 +3,8 @@ #include #include #include - +#include +#include namespace ClipperLib { void TranslatePath(const Path& input, Path& output, IntPoint delta); @@ -75,7 +76,7 @@ namespace AdaptivePath { } - // calculates path length for open path + // calculates path length for open path inline double PathLength(const Path & path) { double len=0; if(path.size()<2) return len; @@ -443,40 +444,65 @@ namespace AdaptivePath { ***************************************/ class EngagePoint { public: + struct EngageState { + size_t currentPathIndex; + size_t currentSegmentIndex; + double segmentPos =0; + double totalDistance=0; + double currentPathLength=0; + int passes=0; + + double metric; // engage point metric + + bool operator < (const EngageState& other) const + { + return (metric < other.metric); + } + }; EngagePoint(const Paths & p_toolBoundPaths) { toolBoundPaths=&p_toolBoundPaths; - currentPathIndex=0; - currentSegmentIndex=0; - segmentPos =0; - totalDistance=0; + state.currentPathIndex=0; + state.currentSegmentIndex=0; + state.segmentPos =0; + state.totalDistance=0; calculateCurrentPathLength(); } + EngageState GetState() { + return state; + } + void SetState(const EngageState &new_state ) { + state=new_state; + } + + void ResetPasses() { + state.passes=0; + } void moveToClosestPoint(const IntPoint &pt,double step) { double minDistSq = __DBL_MAX__; - size_t minPathIndex = currentPathIndex; - size_t minSegmentIndex = currentSegmentIndex; - double minSegmentPos = segmentPos; - totalDistance=0; + size_t minPathIndex = state.currentPathIndex; + size_t minSegmentIndex = state.currentSegmentIndex; + double minSegmentPos = state.segmentPos; + state.totalDistance=0; for(;;) { while(moveForward(step)) { double distSqrd = DistanceSqrd(pt,getCurrentPoint()); if(distSqrd1) { + state.passes++; + if(state.passes>1) { Perf_NextEngagePoint.Stop(); return false; // nothin more to cut } @@ -506,46 +532,46 @@ namespace AdaptivePath { } } IntPoint getCurrentPoint() { - const Path * pth = &toolBoundPaths->at(currentPathIndex); - const IntPoint * p1=&pth->at(currentSegmentIndex>0?currentSegmentIndex-1:pth->size()-1); - const IntPoint * p2=&pth->at(currentSegmentIndex); + const Path * pth = &toolBoundPaths->at(state.currentPathIndex); + const IntPoint * p1=&pth->at(state.currentSegmentIndex>0?state.currentSegmentIndex-1:pth->size()-1); + const IntPoint * p2=&pth->at(state.currentSegmentIndex); double segLength =sqrt(DistanceSqrd(*p1,*p2)); - return IntPoint(long(p1->X + segmentPos*double(p2->X-p1->X)/segLength),long(p1->Y + segmentPos*double(p2->Y-p1->Y)/segLength)); + return IntPoint(long(p1->X + state.segmentPos*double(p2->X-p1->X)/segLength),long(p1->Y + state.segmentPos*double(p2->Y-p1->Y)/segLength)); } DoublePoint getCurrentDir() { - const Path * pth = &toolBoundPaths->at(currentPathIndex); - const IntPoint * p1=&pth->at(currentSegmentIndex>0?currentSegmentIndex-1:pth->size()-1); - const IntPoint * p2=&pth->at(currentSegmentIndex); + const Path * pth = &toolBoundPaths->at(state.currentPathIndex); + const IntPoint * p1=&pth->at(state.currentSegmentIndex>0?state.currentSegmentIndex-1:pth->size()-1); + const IntPoint * p2=&pth->at(state.currentSegmentIndex); double segLength =sqrt(DistanceSqrd(*p1,*p2)); return DoublePoint(double(p2->X-p1->X)/segLength,double(p2->Y-p1->Y)/segLength); } bool moveForward(double distance) { - const Path * pth = &toolBoundPaths->at(currentPathIndex); + const Path * pth = &toolBoundPaths->at(state.currentPathIndex); if(distancesegmentLength) { - currentSegmentIndex++; - if(currentSegmentIndex>=pth->size()) { - currentSegmentIndex=0; + while(state.segmentPos+distance>segmentLength) { + state.currentSegmentIndex++; + if(state.currentSegmentIndex>=pth->size()) { + state.currentSegmentIndex=0; } - distance=distance-(segmentLength-segmentPos); - segmentPos =0; + distance=distance-(segmentLength-state.segmentPos); + state.segmentPos =0; segmentLength =currentSegmentLength(); } - segmentPos+=distance; - return totalDistance<=1.2 * currentPathLength; + state.segmentPos+=distance; + return state.totalDistance<=1.2 * state.currentPathLength; } bool nextPath() { - currentPathIndex++; - currentSegmentIndex=0; - segmentPos =0; - totalDistance=0; - if(currentPathIndex>=toolBoundPaths->size()) { - currentPathIndex =0; + state.currentPathIndex++; + state.currentSegmentIndex=0; + state.segmentPos =0; + state.totalDistance=0; + if(state.currentPathIndex>=toolBoundPaths->size()) { + state.currentPathIndex =0; calculateCurrentPathLength(); return false; } @@ -554,30 +580,28 @@ namespace AdaptivePath { return true; } + + + private: const Paths * toolBoundPaths; - size_t currentPathIndex; - size_t currentSegmentIndex; - double segmentPos =0; - double totalDistance=0; - double currentPathLength=0; - int passes=0; + EngageState state; Clipper clip; void calculateCurrentPathLength() { - const Path * pth = &toolBoundPaths->at(currentPathIndex); + const Path * pth = &toolBoundPaths->at(state.currentPathIndex); size_t size=pth->size(); - currentPathLength=0; + state.currentPathLength=0; for(size_t i=0;iat(i>0?i-1:size-1); const IntPoint * p2=&pth->at(i); - currentPathLength += sqrt(DistanceSqrd(*p1,*p2)); + state.currentPathLength += sqrt(DistanceSqrd(*p1,*p2)); } } double currentSegmentLength() { - const Path * pth = &toolBoundPaths->at(currentPathIndex); - const IntPoint * p1=&pth->at(currentSegmentIndex>0?currentSegmentIndex-1:pth->size()-1); - const IntPoint * p2=&pth->at(currentSegmentIndex); + const Path * pth = &toolBoundPaths->at(state.currentPathIndex); + const IntPoint * p1=&pth->at(state.currentSegmentIndex>0?state.currentSegmentIndex-1:pth->size()-1); + const IntPoint * p2=&pth->at(state.currentSegmentIndex); return sqrt(DistanceSqrd(*p1,*p2)); } @@ -665,22 +689,24 @@ namespace AdaptivePath { } } } + result.clear(); // make new path starting with that point Path & closestPath = paths.at(closestPathIndex); for(size_t i=0;i=closestPath.size()) index-=closestPath.size(); + if(index>=long(closestPath.size())) index-=closestPath.size(); result.push_back(closestPath.at(index)); } // remove the closest path paths.erase(paths.begin()+closestPathIndex); + return true; } /**************************************** // Adaptive2d - constructor *****************************************/ - Adaptive2d::Adaptive2d() { + Adaptive2d::Adaptive2d() { } double Adaptive2d::CalcCutArea(Clipper & clip,const IntPoint &c1, const IntPoint &c2, const Paths &cleared_paths) { @@ -1242,7 +1268,7 @@ namespace AdaptivePath { for(auto &p : crossing) { collisionArea += fabs(Area(p)); } - return collisionArea <= NTOL; + return collisionArea <= optimalCutAreaPD*RESOLUTION_FACTOR/2; } void Adaptive2d::AppendToolPath(TPaths &progressPaths,AdaptiveOutput & output,const Path & passToolPath,const Paths & cleared, const Paths & toolBoundPaths, bool close) { @@ -1315,11 +1341,10 @@ namespace AdaptivePath { bool keepDownLinkTooLong = true; for(int i=1;i<10;i++) { clipof.Execute(clearedOff,-toolRadiusScaled-offset/i); - keepDownLinkExists = FindPathBetweenClosestPoints(clearedOff,lastPoint,nextPoint,toolRadiusScaled + 1.2*offset,keepToolDownLinkPath); + keepDownLinkExists = FindPathBetweenClosestPoints(clearedOff,lastPoint,nextPoint,toolRadiusScaled + 2*offset/i ,keepToolDownLinkPath); keepDownLinkTooLong = (PathLength(keepToolDownLinkPath) > 3*linkDistance) && (linkDistance>4*toolRadiusScaled) ; - if(keepDownLinkExists && !keepDownLinkTooLong) break; + if(keepDownLinkExists) break; } - if(keepDownLinkExists) { lastInterimPoint=keepToolDownLinkPath.front(); nextInterimPoint=keepToolDownLinkPath.back(); @@ -1354,7 +1379,39 @@ namespace AdaptivePath { output.AdaptivePaths.push_back(linkPath3); linkFound=true; } + if(!linkFound && keepDownLinkTooLong) { // make link through interim points with tool raise + tp.clear(); + tp << lastPoint; + tp << lastInterimPoint; + if(IsClearPath(tp,cleared)) { + tp.clear(); + tp << nextInterimPoint; + tp << nextPoint; + if(IsClearPath(tp,cleared)) { + // add disengage moves + TPath linkPath1; + linkPath1.first = MotionType::mtCutting; + linkPath1.second.push_back(lastTPoint); + linkPath1.second.push_back(DPoint(double(lastInterimPoint.X)/scaleFactor,double(lastInterimPoint.Y)/scaleFactor)); + output.AdaptivePaths.push_back(linkPath1); + // add linking move at clear height + TPath linkPath2; + linkPath2.first = MotionType::mtLinkNotClear; + linkPath2.second.push_back(DPoint(double(lastInterimPoint.X)/scaleFactor,double(lastInterimPoint.Y)/scaleFactor)); + linkPath2.second.push_back(DPoint(double(nextInterimPoint.X)/scaleFactor,double(nextInterimPoint.Y)/scaleFactor)); + output.AdaptivePaths.push_back(linkPath2); + + // add engage move + TPath linkPath3; + linkPath3.first = MotionType::mtCutting; + linkPath3.second.push_back(DPoint(double(nextInterimPoint.X)/scaleFactor,double(nextInterimPoint.Y)/scaleFactor)); + linkPath3.second.push_back(DPoint(double(nextPoint.X)/scaleFactor,double(nextPoint.Y)/scaleFactor)); + output.AdaptivePaths.push_back(linkPath3); + linkFound=true; + } + } + } if(!linkFound && !keepDownLinkTooLong && !inefficientInterimLink) { // if direct link over interim points not clear tp.clear(); tp << lastPoint; @@ -1384,6 +1441,8 @@ namespace AdaptivePath { linkPath3.second.push_back(DPoint(double(nextPoint.X)/scaleFactor,double(nextPoint.Y)/scaleFactor)); output.AdaptivePaths.push_back(linkPath3); linkFound= true; + } else { + cout << "interim keeptool down link not clear" << endl; } } } @@ -1460,7 +1519,7 @@ namespace AdaptivePath { } - void Adaptive2d::ProcessPolyNode(Paths & boundPaths, Paths & toolBoundPaths) { + void Adaptive2d::ProcessPolyNode(Paths boundPaths, Paths toolBoundPaths) { //cout << " Adaptive2d::ProcessPolyNode" << endl; Perf_ProcessPolyNode.Start(); // node paths are already constrained to tool boundary path for adaptive path before finishing pass @@ -1469,10 +1528,12 @@ namespace AdaptivePath { TPaths progressPaths; progressPaths.reserve(10000); - //SimplifyPolygons(toolBoundPaths); CleanPolygons(toolBoundPaths); - //SimplifyPolygons(boundPaths); - //CleanPolygons(toolBoundPaths); + SimplifyPolygons(toolBoundPaths); + + CleanPolygons(boundPaths); + SimplifyPolygons(boundPaths); + AddPathsToProgress(progressPaths,toolBoundPaths); @@ -1529,6 +1590,7 @@ namespace AdaptivePath { long total_exceeded=0; long total_output_points=0; long over_cut_count =0; + long bad_engage_count=0; unclearLinkingMoveCount=0; //long engage_no_cut_count=0; double prevDistFromStart =0; @@ -1775,13 +1837,18 @@ namespace AdaptivePath { total_output_points+=cleaned.size(); AppendToolPath(progressPaths, output,cleaned,cleared,toolBoundPaths); CheckReportProgress(progressPaths); + bad_engage_count=0; + engage.ResetPasses(); //firstEngagePoint=true; + } else { + bad_engage_count++; } /*****NEXT ENGAGE POINT******/ if(firstEngagePoint) { engage.moveToClosestPoint(newToolPos,stepScaled+1); firstEngagePoint=false; } else { + // check which is better to find next cut from closest point or to continue from current double moveDistance = ENGAGE_SCAN_DISTANCE_FACTOR * RESOLUTION_FACTOR * 8; if(!engage.nextEngagePoint(this, cleared,moveDistance,ENGAGE_AREA_THR_FACTOR*optimalCutAreaPD*RESOLUTION_FACTOR,4*referenceCutArea*stepOverFactor)) break; } @@ -1791,12 +1858,15 @@ namespace AdaptivePath { /**********************************/ /* FINISHING PASS */ /**********************************/ + clipof.Clear(); clipof.AddPaths(boundPaths,JoinType::jtRound,EndType::etClosedPolygon); Paths finishingPaths; clipof.Execute(finishingPaths,-toolRadiusScaled); IntPoint lastPoint = toolPos; Path finShiftedPath; + + while(PopPathWithClosestPoint(finishingPaths,lastPoint,finShiftedPath)) { // skip finishing passes outside the stock boundary - make no sense to cut where is no material bool allPointsOutside=true; diff --git a/src/Mod/Path/libarea/Adaptive.hpp b/src/Mod/Path/libarea/Adaptive.hpp index 6067fb2034..7d5d944e0e 100644 --- a/src/Mod/Path/libarea/Adaptive.hpp +++ b/src/Mod/Path/libarea/Adaptive.hpp @@ -93,7 +93,7 @@ namespace AdaptivePath { std::function * progressCallback=NULL; Path toolGeometry; // tool geometry at coord 0,0, should not be modified - void ProcessPolyNode(Paths & boundPaths, Paths & toolBoundPaths); + void ProcessPolyNode(Paths boundPaths, Paths toolBoundPaths); bool FindEntryPoint(TPaths &progressPaths,const Paths & toolBoundPaths,const Paths &bound, Paths &cleared /*output*/, IntPoint &entryPoint /*output*/, IntPoint & toolPos, DoublePoint & toolDir); bool FindEntryPointOutside(TPaths &progressPaths,const Paths & toolBoundPaths,const Paths &bound, Paths &cleared /*output*/,