Path: Adaptive - fix for edge selections
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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;i<paths.size();i++) {
|
||||
if(paths[i].size()>0) 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<DoublePoint> &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<DoublePoint> & 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)<SAME_POINT_TOL_SQRD_SCALED) {
|
||||
pointExists=true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!pointExists) {
|
||||
all_points_exists=false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(all_points_exists) {
|
||||
duplicate=true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!duplicate && new_pth.size()>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;i<input.size();i++) {
|
||||
Path & n= input.at(i);
|
||||
if(DistanceSqrd(n.front(),joined.back())<SAME_POINT_TOL_SQRD_SCALED) {
|
||||
for(auto pt:n) joined.push_back(pt);
|
||||
input.erase(input.begin()+i);
|
||||
anyMatch=true;
|
||||
break;
|
||||
} else if(DistanceSqrd(n.back(),joined.back())<SAME_POINT_TOL_SQRD_SCALED) {
|
||||
ReversePath(n);
|
||||
for(auto pt:n) joined.push_back(pt);
|
||||
input.erase(input.begin()+i);
|
||||
anyMatch=true;
|
||||
break;
|
||||
} else if(DistanceSqrd(n.front(),joined.front())<SAME_POINT_TOL_SQRD_SCALED) {
|
||||
for(auto pt:n) joined.insert(joined.begin(),pt);
|
||||
input.erase(input.begin()+i);
|
||||
anyMatch=true;
|
||||
break;
|
||||
} else if(DistanceSqrd(n.back(),joined.front())<SAME_POINT_TOL_SQRD_SCALED) {
|
||||
ReversePath(n);
|
||||
for(auto pt:n) joined.insert(joined.begin(),pt);
|
||||
input.erase(input.begin()+i);
|
||||
anyMatch=true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!anyMatch) newPath = true;
|
||||
}
|
||||
if(joined.size()>0) 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<paths.size();i++) {
|
||||
Path cpth;
|
||||
for(size_t j=0;j<paths[i].size();j++) {
|
||||
std::pair<double,double> 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;
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user