Path: Adaptive - feature to clear from outside stock bounday inwards

This commit is contained in:
kreso-t
2018-09-01 17:45:31 +02:00
committed by wmayer
parent 364daff4c7
commit 365227a049
6 changed files with 249 additions and 109 deletions

View File

@@ -160,35 +160,44 @@ def GenerateGCode(op,obj,adaptiveResults, helixDiameter):
lx=region["HelixCenterPoint"][0]
ly=region["HelixCenterPoint"][1]
r = helixRadius - 0.01
#helix ramp
passDepth = (passStartDepth - passEndDepth)
maxfi = passDepth / depthPerOneCircle * 2 * math.pi
fi = 0
offsetFi =-maxfi + startAngle-math.pi/16
helixStart = [region["HelixCenterPoint"][0] + r * math.cos(offsetFi), region["HelixCenterPoint"][1] + r * math.sin(offsetFi)]
op.commandlist.append(Path.Command("(helix to depth: %f)"%passEndDepth))
#if step == 1:
#rapid move to start point
op.commandlist.append(Path.Command(
"G0", {"X": helixStart[0], "Y": helixStart[1], "Z": obj.ClearanceHeight.Value}))
#rapid move to safe height
op.commandlist.append(Path.Command(
"G0", {"X": helixStart[0], "Y": helixStart[1], "Z": obj.SafeHeight.Value}))
#helix ramp
if helixRadius>0.0001:
r = helixRadius - 0.01
maxfi = passDepth / depthPerOneCircle * 2 * math.pi
fi = 0
offsetFi =-maxfi + startAngle-math.pi/16
op.commandlist.append(Path.Command("G1", {
"X": helixStart[0], "Y": helixStart[1], "Z": passStartDepth, "F": op.vertFeed}))
helixStart = [region["HelixCenterPoint"][0] + r * math.cos(offsetFi), region["HelixCenterPoint"][1] + r * math.sin(offsetFi)]
op.commandlist.append(Path.Command("(helix to depth: %f)"%passEndDepth))
#if step == 1:
#rapid move to start point
op.commandlist.append(Path.Command(
"G0", {"X": helixStart[0], "Y": helixStart[1], "Z": obj.ClearanceHeight.Value}))
#rapid move to safe height
op.commandlist.append(Path.Command(
"G0", {"X": helixStart[0], "Y": helixStart[1], "Z": obj.SafeHeight.Value}))
op.commandlist.append(Path.Command("G1", {
"X": helixStart[0], "Y": helixStart[1], "Z": passStartDepth, "F": op.vertFeed}))
while fi<maxfi:
x = region["HelixCenterPoint"][0] + r * math.cos(fi+offsetFi)
y = region["HelixCenterPoint"][1] + r * math.sin(fi+offsetFi)
z = passStartDepth - fi / maxfi * (passStartDepth - passEndDepth)
op.commandlist.append(Path.Command("G1", { "X": x, "Y":y, "Z":z, "F": op.vertFeed}))
lx=x
ly=y
fi=fi+math.pi/16
else: # no helix entry
op.commandlist.append(Path.Command(
"G0", {"X": region["StartPoint"][0], "Y": region["StartPoint"][1], "Z": obj.ClearanceHeight.Value}))
op.commandlist.append(Path.Command("G1", {
"X":region["StartPoint"][0], "Y": region["StartPoint"][1], "Z": passEndDepth,"F": op.vertFeed}))
while fi<maxfi:
x = region["HelixCenterPoint"][0] + r * math.cos(fi+offsetFi)
y = region["HelixCenterPoint"][1] + r * math.sin(fi+offsetFi)
z = passStartDepth - fi / maxfi * (passStartDepth - passEndDepth)
op.commandlist.append(Path.Command("G1", { "X": x, "Y":y, "Z":z, "F": op.vertFeed}))
lx=x
ly=y
fi=fi+math.pi/16
op.commandlist.append(Path.Command("(adaptive - depth: %f)"%passEndDepth))
#add adaptive paths
for pth in region["AdaptivePaths"]:
@@ -245,10 +254,8 @@ def Execute(op,obj):
try:
Console.PrintMessage("Tool diam: %f \n"%op.tool.Diameter)
helixDiameter = min(op.tool.Diameter,1000.0 if obj.HelixDiameterLimit.Value==0.0 else obj.HelixDiameterLimit.Value )
nestingLimit=0
topZ=op.stock.Shape.BoundBox.ZMax
opType = area.AdaptiveOperationType.Clearing
obj.Stopped = False
obj.StopProcessing = False
if obj.Tolerance<0.001: obj.Tolerance=0.001
@@ -262,40 +269,45 @@ def Execute(op,obj):
pathArray=connectEdges(edges)
stockPaths = []
if op.stock.StockType == "CreateCylinder":
stockPaths.append([discretize(op.stock.Shape.Edges[0])])
else:
stockBB = op.stock.Shape.BoundBox
v=[]
v.append(FreeCAD.Vector(stockBB.XMin,stockBB.YMin,0))
v.append(FreeCAD.Vector(stockBB.XMax,stockBB.YMin,0))
v.append(FreeCAD.Vector(stockBB.XMax,stockBB.YMax,0))
v.append(FreeCAD.Vector(stockBB.XMin,stockBB.YMax,0))
v.append(FreeCAD.Vector(stockBB.XMin,stockBB.YMin,0))
stockPaths.append([v])
opType = area.AdaptiveOperationType.ClearingInside
if obj.OperationType == "Clearing":
if obj.Side == "Outside":
if op.stock.StockType == "CreateCylinder":
pathArray.append([discretize(op.stock.Shape.Edges[0])])
else:
stockBB = op.stock.Shape.BoundBox
v=[]
v.append(FreeCAD.Vector(stockBB.XMin,stockBB.YMin,0))
v.append(FreeCAD.Vector(stockBB.XMax,stockBB.YMin,0))
v.append(FreeCAD.Vector(stockBB.XMax,stockBB.YMax,0))
v.append(FreeCAD.Vector(stockBB.XMin,stockBB.YMax,0))
v.append(FreeCAD.Vector(stockBB.XMin,stockBB.YMin,0))
pathArray.append([v])
if not obj.ProcessHoles: nestingLimit = 2
elif not obj.ProcessHoles: nestingLimit = 1
opType = area.AdaptiveOperationType.Clearing
opType = area.AdaptiveOperationType.ClearingOutside
else:
opType = area.AdaptiveOperationType.ClearingInside
else: # profiling
if obj.Side == "Outside":
opType = area.AdaptiveOperationType.ProfilingOutside
else:
opType = area.AdaptiveOperationType.ProfilingInside
if not obj.ProcessHoles: nestingLimit = 1
path2d = convertTo2d(pathArray)
stockPath2d = convertTo2d(stockPaths)
# put here all properties that influence calculation of adaptive base paths,
inputStateObject = {
"tool": float(op.tool.Diameter),
"tolerance": float(obj.Tolerance),
"geometry" : path2d,
"stockGeometry": stockPath2d,
"stepover" : float(obj.StepOver),
"effectiveHelixDiameter": float(helixDiameter),
"operationType": obj.OperationType,
"side": obj.Side,
"processHoles": obj.ProcessHoles,
"forceInsideOut" : obj.ForceInsideOut,
"stockToLeave": float(obj.StockToLeave)
}
@@ -325,10 +337,10 @@ def Execute(op,obj):
a2d.helixRampDiameter = helixDiameter
a2d.stockToLeave =float(obj.StockToLeave)
a2d.tolerance = float(obj.Tolerance)
a2d.forceInsideOut = obj.ForceInsideOut
a2d.opType = opType
a2d.polyTreeNestingLimit = nestingLimit
#EXECUTE
results = a2d.Execute(path2d,progressFn)
results = a2d.Execute(stockPath2d,path2d,progressFn)
#need to convert results to python object to be JSON serializable
adaptiveResults = []
@@ -376,7 +388,9 @@ class PathAdaptive(PathOp.ObjectOp):
obj.addProperty("App::PropertyPercent", "StepOver", "Adaptive", "Percent of cutter diameter to step over on each pass")
obj.addProperty("App::PropertyDistance", "LiftDistance", "Adaptive", "Lift distance for rapid moves")
obj.addProperty("App::PropertyDistance", "StockToLeave", "Adaptive", "How much stock to leave (i.e. for finishing operation)")
obj.addProperty("App::PropertyBool", "ProcessHoles", "Adaptive","Process holes as well as the face outline")
# obj.addProperty("App::PropertyBool", "ProcessHoles", "Adaptive","Process holes as well as the face outline")
obj.addProperty("App::PropertyBool", "ForceInsideOut", "Adaptive","Force plunging into material inside and clearing towards the edges")
obj.addProperty("App::PropertyBool", "Stopped",
"Adaptive", "Stop processing")
obj.setEditorMode('Stopped', 2) #hide this property
@@ -401,7 +415,8 @@ class PathAdaptive(PathOp.ObjectOp):
obj.Tolerance = 0.1
obj.StepOver = 20
obj.LiftDistance=1.0
obj.ProcessHoles = True
# obj.ProcessHoles = True
obj.ForceInsideOut = True
obj.Stopped = False
obj.StopProcessing = False
obj.HelixAngle = 5

View File

@@ -92,10 +92,15 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
form.StockToLeave.setToolTip("How much material to leave (i.e. for finishing operation)")
formLayout.addRow(QtGui.QLabel("Stock to Leave"),form.StockToLeave)
#process holes
form.ProcessHoles = QtGui.QCheckBox()
form.ProcessHoles.setChecked(True)
formLayout.addRow(QtGui.QLabel("Process Holes"),form.ProcessHoles)
# #process holes
# form.ProcessHoles = QtGui.QCheckBox()
# form.ProcessHoles.setChecked(True)
# formLayout.addRow(QtGui.QLabel("Process Holes"),form.ProcessHoles)
#Force inside out
form.ForceInsideOut = QtGui.QCheckBox()
form.ForceInsideOut.setChecked(True)
formLayout.addRow(QtGui.QLabel("Force Clearing Inside-Out"),form.ForceInsideOut)
layout.addLayout(formLayout)
@@ -121,7 +126,8 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
signals.append(self.form.LiftDistance.valueChanged)
signals.append(self.form.StockToLeave.valueChanged)
signals.append(self.form.ProcessHoles.stateChanged)
# signals.append(self.form.ProcessHoles.stateChanged)
signals.append(self.form.ForceInsideOut.stateChanged)
signals.append(self.form.StopButton.toggled)
return signals
@@ -136,7 +142,8 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
if hasattr(obj, 'StockToLeave'):
self.form.StockToLeave.setValue(obj.StockToLeave)
self.form.ProcessHoles.setChecked(obj.ProcessHoles)
# self.form.ProcessHoles.setChecked(obj.ProcessHoles)
self.form.ForceInsideOut.setChecked(obj.ForceInsideOut)
self.setupToolController(obj, self.form.ToolController)
self.form.StopButton.setChecked(obj.Stopped)
obj.setEditorMode('AdaptiveInputState', 2) #hide this property
@@ -159,7 +166,8 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
if hasattr(obj, 'StockToLeave'):
obj.StockToLeave = self.form.StockToLeave.value()
obj.ProcessHoles = self.form.ProcessHoles.isChecked()
# obj.ProcessHoles = self.form.ProcessHoles.isChecked()
obj.ForceInsideOut = self.form.ForceInsideOut.isChecked()
obj.Stopped = self.form.StopButton.isChecked()
if(obj.Stopped):
self.form.StopButton.setChecked(False) #reset the button

View File

@@ -793,7 +793,7 @@ namespace AdaptivePath {
/****************************************
// Adaptive2d - Execute
*****************************************/
std::list<AdaptiveOutput> Adaptive2d::Execute(const DPaths &paths, std::function<bool(TPaths)> progressCallbackFn) {
std::list<AdaptiveOutput> Adaptive2d::Execute(const DPaths &stockPaths, const DPaths &paths, std::function<bool(TPaths)> progressCallbackFn) {
//**********************************
// Initializations
// **********************************
@@ -845,6 +845,7 @@ namespace AdaptivePath {
// **********************
// Convert input paths to clipper
//************************
inputPaths.clear();
for(size_t i=0;i<paths.size();i++) {
Path cpth;
for(size_t j=0;j<paths[i].size();j++) {
@@ -855,6 +856,21 @@ namespace AdaptivePath {
}
SimplifyPolygons(inputPaths);
//************************
// convert stock paths
// *************************
stockInputPaths.clear();
for(size_t i=0;i<stockPaths.size();i++) {
Path cpth;
for(size_t j=0;j<stockPaths[i].size();j++) {
std::pair<double,double> pt = stockPaths[i][j];
cpth.push_back(IntPoint(long(pt.first*scaleFactor),long(pt.second*scaleFactor)));
}
stockInputPaths.push_back(cpth);
}
SimplifyPolygons(stockInputPaths);
if(stockToLeave>NTOL) {
clipof.Clear();
clipof.AddPaths(inputPaths,JoinType::jtRound,EndType::etClosedPolygon);
@@ -874,7 +890,18 @@ namespace AdaptivePath {
// Resolve hierarchy and run processing
// ********************************
if(opType==OperationType::otClearing) {
if(opType==OperationType::otClearingInside || opType==OperationType::otClearingOutside) {
// add stock paths, with overshooting
if(opType==OperationType::otClearingOutside) {
clipof.Clear();
clipof.AddPaths(stockInputPaths,JoinType::jtRound,EndType::etClosedPolygon);
double overshootDistance =2*toolRadiusScaled + toolRadiusScaled*stepOverFactor;
if(forceInsideOut) overshootDistance=0;
Paths stockOvershoot;
clipof.Execute(stockOvershoot,overshootDistance);
ReversePaths(stockOvershoot);
for(auto p : stockOvershoot) inputPaths.push_back(p);
}
clipof.Clear();
clipof.AddPaths(inputPaths,JoinType::jtRound,EndType::etClosedPolygon);
Paths paths;
@@ -942,7 +969,10 @@ namespace AdaptivePath {
return results;
}
bool Adaptive2d::FindEntryPoint(const Paths & toolBoundPaths,const Paths &boundPaths, Paths &cleared /*output-initial cleard area by helix*/, IntPoint &entryPoint /*output*/) {
bool Adaptive2d::FindEntryPoint(TPaths &progressPaths, const Paths & toolBoundPaths,const Paths &boundPaths,
Paths &cleared /*output-initial cleard area by helix*/,
IntPoint &entryPoint /*output*/,
IntPoint & toolPos, DoublePoint & toolDir) {
Paths incOffset;
Paths lastValidOffset;
Clipper clip;
@@ -1018,8 +1048,66 @@ namespace AdaptivePath {
}
//DrawCircle(entryPoint,scaleFactor,10);
if(!found) cerr<<"Start point not found!"<<endl;
if(found) {
// visualize/progress for helix
clipof.Clear();
Path hp;
hp << entryPoint;
clipof.AddPath(hp,JoinType::jtRound,EndType::etOpenRound);
Paths hps;
clipof.Execute(hps,helixRampRadiusScaled);
AddPathsToProgress(progressPaths,hps);
toolPos = IntPoint(entryPoint.X,entryPoint.Y - helixRampRadiusScaled);
toolDir = DoublePoint(1.0,0.0);
}
return found;
}
bool Adaptive2d::FindEntryPointOutside(TPaths &progressPaths, const Paths & toolBoundPaths,const Paths &boundPaths,
Paths &cleared /*output-initial cleard area by helix*/,
IntPoint &entryPoint /*output*/,
IntPoint & toolPos, DoublePoint & toolDir) {
Clipper clip;
ClipperOffset clipof;
// check if boundary shape to cut is outside the stock
// clip.AddPaths(boundPaths,PolyType::ptSubject, true);
// clip.AddPaths(stockInputPaths,PolyType::ptClip, true);
// Paths outsidePaths;
// clip.Execute(ClipType::ctDifference,outsidePaths);
for(const auto & pth : toolBoundPaths) {
for(size_t i=0;i<pth.size();i++) {
IntPoint checkPoint = pth[i];
IntPoint lastPoint = i>0 ? pth[i-1] : pth.back();
// if point is outside the stock
if(PointInPolygon(checkPoint,stockInputPaths.front())==0) {
clipof.Clear();
clipof.AddPaths(toolBoundPaths,JoinType::jtRound,EndType::etClosedPolygon);
Paths sol2;
clipof.Execute(sol2,toolRadiusScaled*stepOverFactor);
clipof.Clear();
clipof.AddPaths(sol2,JoinType::jtRound,EndType::etClosedLine);
clipof.Execute(cleared,toolRadiusScaled);
// trim cleared paths to stock boundary (only outside part remain)
clip.Clear();
clip.AddPaths(cleared,PolyType::ptSubject, true);
clip.AddPaths(stockInputPaths,PolyType::ptClip, true);
clip.Execute(ClipType::ctDifference,cleared);
AddPathsToProgress(progressPaths,cleared);
entryPoint=checkPoint;
toolPos = entryPoint;
// find tool dir
double len=sqrt(DistanceSqrd(lastPoint,checkPoint));
toolDir = DoublePoint((checkPoint.X - lastPoint.X)/len,(checkPoint.Y - lastPoint.Y)/len);
return true;
}
}
}
//AddPathsToProgress(progressPaths,outsidePaths);
return false;
}
/**
* returns true if line from lastPoint to nextPoint is clear from obstacles
@@ -1130,6 +1218,18 @@ namespace AdaptivePath {
while(progressPaths.front().second.size()>0) progressPaths.front().second.pop_back();
progressPaths.front().second.push_back(next);
}
void Adaptive2d::AddPathsToProgress(TPaths &progressPaths,Paths paths) {
for(const auto & pth :paths) {
if(pth.size()>0) {
progressPaths.push_back(TPath());
for(const auto pt: pth)
progressPaths.back().second.push_back(DPoint(double(pt.X)/scaleFactor,double(pt.Y)/scaleFactor));
progressPaths.back().second.push_back(DPoint(double(pth.front().X)/scaleFactor,double(pth.front().Y)/scaleFactor));
}
}
}
void Adaptive2d::ProcessPolyNode(Paths & boundPaths, Paths & toolBoundPaths) {
//cout << " Adaptive2d::ProcessPolyNode" << endl;
Perf_ProcessPolyNode.Start();
@@ -1142,10 +1242,21 @@ namespace AdaptivePath {
//SimplifyPolygons(toolBoundPaths);
CleanPolygons(toolBoundPaths);
//SimplifyPolygons(boundPaths);
CleanPolygons(toolBoundPaths);
//CleanPolygons(toolBoundPaths);
//AddPathsToProgress(progressPaths,toolBoundPaths);
IntPoint toolPos;
DoublePoint toolDir;
Paths cleared;
if(!FindEntryPoint(toolBoundPaths, boundPaths, cleared, entryPoint)) return;
bool outsideEntry = false;
if(FindEntryPointOutside(progressPaths, toolBoundPaths, boundPaths, cleared, entryPoint, toolPos,toolDir)) {
toolPos = IntPoint(entryPoint.X,entryPoint.Y);
toolDir = DoublePoint(1.0,0.0);
outsideEntry=true;
} else {
if(!FindEntryPoint(progressPaths, toolBoundPaths, boundPaths, cleared, entryPoint, toolPos,toolDir)) return;
}
//cout << "Entry point:" << entryPoint << endl;
Clipper clip;
ClipperOffset clipof;
@@ -1156,42 +1267,14 @@ namespace AdaptivePath {
long stepScaled = long(RESOLUTION_FACTOR);
IntPoint engagePoint;
IntPoint toolPos;
DoublePoint toolDir;
IntPoint newToolPos;
DoublePoint newToolDir;
// visualize/progress for boundPath
for(const auto & pth :toolBoundPaths) {
if(pth.size()>0) {
progressPaths.push_back(TPath());
for(const auto pt: pth)
progressPaths.back().second.push_back(DPoint(double(pt.X)/scaleFactor,double(pt.Y)/scaleFactor));
progressPaths.back().second.push_back(DPoint(double(pth.front().X)/scaleFactor,double(pth.front().Y)/scaleFactor));
}
}
CheckReportProgress(progressPaths, true);
// visualize/progress for helix
clipof.Clear();
Path hp;
hp << entryPoint;
clipof.AddPath(hp,JoinType::jtRound,EndType::etOpenRound);
Paths hps;
clipof.Execute(hps,helixRampRadiusScaled);
progressPaths.push_back(TPath());
// show in progress cb
for(auto & pt:hps[0]) {
progressPaths.back().second.push_back(DPoint(double(pt.X)/scaleFactor,double(pt.Y)/scaleFactor));
}
CheckReportProgress(progressPaths);
// find the first tool position and direction
toolPos = IntPoint(entryPoint.X,entryPoint.Y - helixRampRadiusScaled);
toolDir = DoublePoint(1.0,0.0);
output.StartPoint =DPoint(double(toolPos.X)/scaleFactor,double(toolPos.Y)/scaleFactor);
IntPoint startPoint = toolPos;
output.StartPoint =DPoint(double(startPoint.X)/scaleFactor,double(startPoint.Y)/scaleFactor);
bool firstEngagePoint=true;
Path passToolPath; // to store pass toolpath
@@ -1211,6 +1294,8 @@ namespace AdaptivePath {
long over_cut_count =0;
unclearLinkingMoveCount=0;
//long engage_no_cut_count=0;
double prevDistFromStart =0;
bool prevDistTrend = false;
double perf_total_len=0;
#ifdef DEV_MODE
@@ -1247,7 +1332,7 @@ namespace AdaptivePath {
*******************************/
for(long point_index=0;point_index<POINTS_PER_PASS_LIMIT;point_index++) {
if(stopProcessing) break;
//cout<<"Pass:"<< pass << " Point:" << point_index;
//cout<<"Pass:"<< pass << " Point:" << point_index << endl;
total_points++;
AverageDirection(gyro, toolDir);
Perf_DistanceToBoundary.Start();
@@ -1363,11 +1448,12 @@ namespace AdaptivePath {
}
if(firstEngagePoint) { // initial spiral shape need clearing in smaller intervals
double distFromEntry = sqrt(DistanceSqrd(toolPos,entryPoint));
double circ = distFromEntry * M_PI;
//cout << (circ/(16*RESOLUTION_FACTOR)) << endl;
if(toClearPath.size()>circ/(16*RESOLUTION_FACTOR)) {
// update cleared paths when trend of distance from start point changes sign (starts to get closer, or start to get farther)
double distFromStart = sqrt(DistanceSqrd(toolPos,startPoint));
bool distanceTrend = distFromStart > prevDistFromStart ? true : false;
if(distFromStart!=prevDistTrend) {
Perf_ExpandCleared.Start();
// expand cleared
clipof.Clear();
@@ -1381,8 +1467,10 @@ namespace AdaptivePath {
CleanPolygons(cleared);
toClearPath.clear();
Perf_ExpandCleared.Stop();
}
}
prevDistTrend = distanceTrend;
prevDistFromStart = distFromStart;
if(area>0) { // cut is ok - record it
if(toClearPath.size()==0) toClearPath.push_back(toolPos);
@@ -1463,6 +1551,14 @@ namespace AdaptivePath {
IntPoint lastPoint;
for(auto & pth: finishingPaths) {
// trim finishing passes outside the stock boundary - make no sense to cut where is no material
Paths diff;
clip.Clear();
clip.AddPath(pth,PolyType::ptSubject,true);
clip.AddPaths(stockInputPaths,PolyType::ptClip,true);
clip.Execute(ClipType::ctDifference,diff);
if(diff.size()>0) continue;
progressPaths.push_back(TPath());
// show in progress cb
for(auto & pt:pth) {

View File

@@ -29,7 +29,7 @@ namespace AdaptivePath {
enum MotionType { mtCutting = 0, mtLinkClear = 1, mtLinkNotClear = 2, mtLinkClearAtPrevPass = 3 };
enum OperationType { otClearing = 0, otProfilingInside = 1, otProfilingOutside = 2 };
enum OperationType { otClearingInside = 0, otClearingOutside = 1, otProfilingInside = 2, otProfilingOutside = 3 };
typedef std::pair<double,double> DPoint;
typedef std::vector<DPoint> DPath;
@@ -58,12 +58,12 @@ namespace AdaptivePath {
double toolDiameter=5;
double helixRampDiameter=0;
double stepOverFactor = 0.2;
int polyTreeNestingLimit=0;
double tolerance=0.1;
double stockToLeave=0;
OperationType opType = OperationType::otClearing;
bool forceInsideOut = true;
OperationType opType = OperationType::otClearingInside;
std::list<AdaptiveOutput> Execute(const DPaths &paths, std::function<bool(TPaths)> progressCallbackFn);
std::list<AdaptiveOutput> Execute(const DPaths &stockPaths, const DPaths &paths, std::function<bool(TPaths)> progressCallbackFn);
#ifdef DEV_MODE
/*for debugging*/
@@ -75,7 +75,8 @@ namespace AdaptivePath {
private:
std::list<AdaptiveOutput> results;
Paths inputPaths;
Paths stockInputPaths;
int polyTreeNestingLimit=0;
double scaleFactor=100;
long toolRadiusScaled=10;
long finishPassOffsetScaled=0;
@@ -92,14 +93,17 @@ namespace AdaptivePath {
Path toolGeometry; // tool geometry at coord 0,0, should not be modified
void ProcessPolyNode(Paths & boundPaths, Paths & toolBoundPaths);
bool FindEntryPoint(const Paths & toolBoundPaths,const Paths &bound, Paths &cleared /*output*/, IntPoint &entryPoint /*output*/);
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*/,
IntPoint &entryPoint /*output*/, IntPoint & toolPos, DoublePoint & toolDir);
double CalcCutArea(Clipper & clip,const IntPoint &toolPos, const IntPoint &newToolPos, const Paths &cleared_paths);
void AppendToolPath(AdaptiveOutput & output,const Path & passToolPath,const Paths & cleared,const Paths & toolBoundPaths, bool close=false);
bool CheckCollision(const IntPoint &lastPoint,const IntPoint &nextPoint,const Paths & cleared);
friend class EngagePoint; // for CalcCutArea
void CheckReportProgress(TPaths &progressPaths,bool force=false);
void AddPathsToProgress(TPaths &progressPaths,Paths paths);
private: // constants for fine tuning
const bool preventConvetionalMode = true;
const double RESOLUTION_FACTOR = 8.0;

View File

@@ -295,8 +295,21 @@ double AreaGetArea(const CArea& a)
// Adaptive2d.Execute wrapper
bp::list AdaptiveExecute(AdaptivePath::Adaptive2d& ada,const boost::python::list &in_paths, boost::python::object progressCallbackFn) {
bp::list AdaptiveExecute(AdaptivePath::Adaptive2d& ada,const boost::python::list &stock_paths, const boost::python::list &in_paths, boost::python::object progressCallbackFn) {
bp::list out_list;
// convert stock paths
AdaptivePath::DPaths stock_dpaths;
for(bp::ssize_t i=0;i<bp::len(stock_paths);i++) {
bp::list in_path=bp::extract<boost::python::list>(stock_paths[i]);
AdaptivePath::DPath dpath;
for(bp::ssize_t j=0;j<bp::len(in_path);j++) {
bp::list in_point = bp::extract<bp::list>(in_path[j]);
dpath.push_back(pair<double,double>(bp::extract<double>(in_point[0]),bp::extract<double>(in_point[1])));
}
stock_dpaths.push_back(dpath);
}
// convert inputs
AdaptivePath::DPaths dpaths;
for(bp::ssize_t i=0;i<bp::len(in_paths);i++) {
@@ -309,7 +322,7 @@ bp::list AdaptiveExecute(AdaptivePath::Adaptive2d& ada,const boost::python::list
dpaths.push_back(dpath);
}
// Execute with callback
std::list<AdaptivePath::AdaptiveOutput> result=ada.Execute(dpaths,[progressCallbackFn](AdaptivePath::TPaths tp)->bool {
std::list<AdaptivePath::AdaptiveOutput> result=ada.Execute(stock_dpaths,dpaths,[progressCallbackFn](AdaptivePath::TPaths tp)->bool {
bp::list out_paths;
for(const auto & in_pair : tp) {
bp::list path;
@@ -495,7 +508,8 @@ BOOST_PYTHON_MODULE(area) {
.value("LinkClearAtPrevPass", MotionType::mtLinkClearAtPrevPass);
bp::enum_<OperationType>("AdaptiveOperationType")
.value("Clearing", OperationType::otClearing)
.value("ClearingInside", OperationType::otClearingInside)
.value("ClearingOutside", OperationType::otClearingOutside)
.value("ProfilingInside", OperationType::otProfilingInside)
.value("ProfilingOutside", OperationType::otProfilingOutside);
@@ -513,7 +527,8 @@ BOOST_PYTHON_MODULE(area) {
.def_readwrite("toolDiameter", &Adaptive2d::toolDiameter)
.def_readwrite("stockToLeave", &Adaptive2d::stockToLeave)
.def_readwrite("helixRampDiameter", &Adaptive2d::helixRampDiameter)
.def_readwrite("polyTreeNestingLimit", &Adaptive2d::polyTreeNestingLimit)
.def_readwrite("forceInsideOut", &Adaptive2d::forceInsideOut)
//.def_readwrite("polyTreeNestingLimit", &Adaptive2d::polyTreeNestingLimit)
.def_readwrite("tolerance", &Adaptive2d::tolerance)
.def_readwrite("opType", &Adaptive2d::opType);

View File

@@ -369,7 +369,8 @@ void init_pyarea(py::module &m){
.value("LinkClearAtPrevPass", MotionType::mtLinkClearAtPrevPass);
py::enum_<OperationType>(m, "AdaptiveOperationType")
.value("Clearing", OperationType::otClearing)
.value("ClearingInside", OperationType::otClearingInside)
.value("ClearingOutside", OperationType::otClearingOutside)
.value("ProfilingInside", OperationType::otProfilingInside)
.value("ProfilingOutside", OperationType::otProfilingOutside);
@@ -387,7 +388,8 @@ void init_pyarea(py::module &m){
.def_readwrite("toolDiameter", &Adaptive2d::toolDiameter)
.def_readwrite("stockToLeave", &Adaptive2d::stockToLeave)
.def_readwrite("helixRampDiameter", &Adaptive2d::helixRampDiameter)
.def_readwrite("polyTreeNestingLimit", &Adaptive2d::polyTreeNestingLimit)
.def_readwrite("forceInsideOut", &Adaptive2d::forceInsideOut)
//.def_readwrite("polyTreeNestingLimit", &Adaptive2d::polyTreeNestingLimit)
.def_readwrite("tolerance", &Adaptive2d::tolerance)
.def_readwrite("opType", &Adaptive2d::opType);
}