diff --git a/src/Mod/Path/App/AppPathPy.cpp b/src/Mod/Path/App/AppPathPy.cpp index 2c4832bfa6..a42721d3c5 100644 --- a/src/Mod/Path/App/AppPathPy.cpp +++ b/src/Mod/Path/App/AppPathPy.cpp @@ -122,7 +122,7 @@ public: "fromShapes(shapes, start=Vector(), return_end=False" PARAM_PY_ARGS_DOC(ARG,AREA_PARAMS_PATH) ")\n" "\nReturns a Path object from a list of shapes\n" "\n* shapes: input list of shapes.\n" - "\n* start (Vector()): optional start position.\n" + "\n* start (Vector()): feed start position, and also serves as a hint of path entry.\n" "\n* return_end (False): if True, returns tuple (path, endPosition).\n" PARAM_PY_DOC(ARG, AREA_PARAMS_PATH) ); @@ -415,7 +415,7 @@ private: try { bool need_arc_plane = arc_plane==Area::ArcPlaneAuto; std::list wires = Area::sortWires(shapes,&pstart, - &pend, &arc_plane, PARAM_PY_FIELDS(PARAM_FARG,AREA_PARAMS_SORT)); + &pend, 0, &arc_plane, PARAM_PY_FIELDS(PARAM_FARG,AREA_PARAMS_SORT)); PyObject *list = PyList_New(0); for(auto &wire : wires) PyList_Append(list,Py::new_reference_to( diff --git a/src/Mod/Path/App/Area.cpp b/src/Mod/Path/App/Area.cpp index d8375abba0..b3f242cfac 100644 --- a/src/Mod/Path/App/Area.cpp +++ b/src/Mod/Path/App/Area.cpp @@ -2435,11 +2435,13 @@ struct ShapeInfo{ return myBestWire->wire; } - std::list sortWires(const gp_Pnt &pstart, gp_Pnt &pend,double min_dist) { + std::list sortWires(const gp_Pnt &pstart, gp_Pnt &pend,double min_dist, gp_Pnt *pentry) { if(pstart.SquareDistance(myStartPt)>Precision::SquareConfusion()) nearest(pstart); + if(pentry) *pentry = myBestPt; + std::list wires; if(min_dist < 0.01) min_dist = 0.01; @@ -2607,7 +2609,7 @@ struct WireOrienter { }; std::list Area::sortWires(const std::list &shapes, - const gp_Pnt *_pstart, gp_Pnt *_pend, short *_parc_plane, + gp_Pnt *_pstart, gp_Pnt *_pend, double *stepdown_hint, short *_parc_plane, PARAM_ARGS(PARAM_FARG,AREA_PARAMS_SORT)) { std::list wires; @@ -2732,7 +2734,12 @@ std::list Area::sortWires(const std::list &shapes, AREA_TRACE("bound (" << xMin<<", "< Area::sortWires(const std::list &shapes, best_d = d; } } - wires.splice(wires.end(),best_it->sortWires(pstart,pend,min_dist)); + gp_Pnt pentry; + wires.splice(wires.end(),best_it->sortWires(pstart,pend,min_dist,&pentry)); + if(use_bound && _pstart) { + use_bound = false; + *_pstart = pentry; + } + if(sort_mode==SortMode2D5 && stepdown_hint) { + if(!best_it->myPlanar) + hint_first = true; + else if(hint_first) + hint_first = false; + else{ + // Calculate distance of two gp_pln. + // + // Can't use gp_pln.Distance(), because it only calculate + // the distance if two plane are parallel. And it checks + // parallelity using tolerance gp::Resolution() which is + // defined as DBL_MIN (min double) in Standard_Real.hxx. + // Really? Is that a bug? + const gp_Pnt& P = pln.Position().Location(); + const gp_Pnt& loc = best_it->myPln.Position().Location (); + const gp_Dir& dir = best_it->myPln.Position().Direction(); + double d = (dir.X() * (P.X() - loc.X()) + + dir.Y() * (P.Y() - loc.Y()) + + dir.Z() * (P.Z() - loc.Z())); + if (d < 0) d = -d; + if(d>hint) + hint = d; + } + pln = best_it->myPln; + } pstart = pend; shape_list.erase(best_it); } + if(stepdown_hint && hint!=0.0) + *stepdown_hint = hint; if(_pend) *_pend = pend; FC_DURATION_LOG(rparams.bd,"rtree build"); FC_DURATION_LOG(rparams.qd,"rtree query"); @@ -2805,24 +2844,22 @@ static void addG0(bool verbose, Toolpath &path, double retraction, double resume_height, double f, double &last_f) { - if(!getter || retraction-(last.*getter)() < Precision::Confusion()) { - addGCode(verbose,path,last,next,"G0"); - return; - } gp_Pnt pt(last); - (pt.*setter)(retraction); - addGCode(verbose,path,last,pt,"G0"); - last = pt; - pt = next; - (pt.*setter)(retraction); - addGCode(verbose,path,last,pt,"G0"); - if(resume_height>Precision::Confusion() && - resume_height+(next.*getter)() < retraction) - { + if(retraction-(last.*getter)() > Precision::Confusion()) { + (pt.*setter)(retraction); + addGCode(verbose,path,last,pt,"G0"); last = pt; pt = next; - (pt.*setter)((next.*getter)()+resume_height); + (pt.*setter)(retraction); addGCode(verbose,path,last,pt,"G0"); + } + if(resume_height>Precision::Confusion()) { + if(resume_height+(next.*getter)() < retraction) { + last = pt; + pt = next; + (pt.*setter)((next.*getter)()+resume_height); + addGCode(verbose,path,last,pt,"G0"); + } addG1(verbose,path,pt,next,f,last_f); }else addGCode(verbose,path,pt,next,"G0"); @@ -2880,11 +2917,15 @@ void Area::setWireOrientation(TopoDS_Wire &wire, const gp_Dir &dir, bool wire_cc } void Area::toPath(Toolpath &path, const std::list &shapes, - const gp_Pnt *pstart, gp_Pnt *pend, PARAM_ARGS(PARAM_FARG,AREA_PARAMS_PATH)) + const gp_Pnt *_pstart, gp_Pnt *pend, PARAM_ARGS(PARAM_FARG,AREA_PARAMS_PATH)) { std::list wires; - wires = sortWires(shapes,pstart,pend, + gp_Pnt pstart; + if(_pstart) pstart = *_pstart; + + double stepdown_hint = 1.0; + wires = sortWires(shapes,&pstart,pend,&stepdown_hint, PARAM_REF(PARAM_FARG,AREA_PARAMS_ARC_PLANE), PARAM_FIELDS(PARAM_FARG,AREA_PARAMS_SORT)); @@ -2903,30 +2944,57 @@ void Area::toPath(Toolpath &path, const std::list &shapes, addGCode(path,"G17"); } + AxisGetter getter; + AxisSetter setter; + switch(retract_axis) { + case RetractAxisX: + getter = &gp_Pnt::X; + setter = &gp_Pnt::SetX; + break; + case RetractAxisY: + getter = &gp_Pnt::Y; + setter = &gp_Pnt::SetY; + break; + default: + getter = &gp_Pnt::Z; + setter = &gp_Pnt::SetZ; + } + threshold = fabs(threshold); if(threshold < Precision::Confusion()) threshold = Precision::Confusion(); threshold *= threshold; - resume_height = fabs(resume_height); - AxisGetter getter = &gp_Pnt::Z; - AxisSetter setter = &gp_Pnt::SetZ; + resume_height = fabs(resume_height); + if(resume_height < Precision::Confusion()) + resume_height = stepdown_hint; + retraction = fabs(retraction); - if(retraction>Precision::Confusion()) { - switch(retract_axis) { - case RetractAxisX: - getter = &gp_Pnt::X; - setter = &gp_Pnt::SetX; - break; - case RetractAxisY: - getter = &gp_Pnt::Y; - setter = &gp_Pnt::SetY; - break; - } - } + if(retraction < Precision::Confusion()) + retraction = (pstart.*getter)()+resume_height; + + // in case the user didn't specify feed start, sortWire() will choose one + // based on the bound. We'll further adjust that according to resume height + if(!_pstart || pstart.SquareDistance(*_pstart)>Precision::SquareConfusion()) + (pstart.*setter)((pstart.*getter)()+resume_height); gp_Pnt plast,p; - if(pstart) plast = *pstart; + // initial vertial rapid pull up to retraction (or start Z height if higher) + (p.*setter)(std::max(retraction,(pstart.*getter)())); + addGCode(false,path,plast,p,"G0"); + plast = p; + p = pstart; + // rapid horizontal move if start Z is below retraction + if(fabs((p.*getter)()-retraction) > Precision::Confusion()) { + (p.*setter)(retraction); + addGCode(false,path,plast,p,"G0"); + plast = p; + p = pstart; + } + // vertial rapid down to feed start + addGCode(false,path,plast,p,"G0"); + + plast = p; bool first = true; bool arcWarned = false; double cur_f = 0.0; // current feed rate @@ -2947,7 +3015,7 @@ void Area::toPath(Toolpath &path, const std::list &shapes, (pTmp.*setter)(0.0); (plastTmp.*setter)(0.0); - if(first||pTmp.SquareDistance(plastTmp)>threshold) + if(!first && pTmp.SquareDistance(plastTmp)>threshold) addG0(verbose,path,plast,p,getter,setter,retraction,resume_height,vf,cur_f); else addG1(verbose,path,plast,p,vf,cur_f); diff --git a/src/Mod/Path/App/Area.h b/src/Mod/Path/App/Area.h index e2a88aa296..9d4d10eb01 100644 --- a/src/Mod/Path/App/Area.h +++ b/src/Mod/Path/App/Area.h @@ -341,6 +341,8 @@ public: * \arg \c shapes: input list of shapes. * \arg \c pstart: optional start point * \arg \c pend: optional output containing the ending point of the returned + * \arg \c stepdown_hint: optional output of a hint of step down as the max + * distance between two sections. * \arg \c arc_plane: optional arc plane selection, if given the found plane * will be returned. See #AREA_PARAMS_ARC_PLANE for more details. * @@ -349,8 +351,8 @@ public: * \return sorted wires */ static std::list sortWires(const std::list &shapes, - const gp_Pnt *pstart=NULL, gp_Pnt *pend=NULL, short *arc_plane = NULL, - PARAM_ARGS_DEF(PARAM_FARG,AREA_PARAMS_SORT)); + gp_Pnt *pstart=NULL, gp_Pnt *pend=NULL, double *stepdown_hint=NULL, + short *arc_plane = NULL, PARAM_ARGS_DEF(PARAM_FARG,AREA_PARAMS_SORT)); /** Convert a list of wires to gcode * diff --git a/src/Mod/Path/App/FeaturePathShape.cpp b/src/Mod/Path/App/FeaturePathShape.cpp index 78e720c295..5d2c79ffad 100644 --- a/src/Mod/Path/App/FeaturePathShape.cpp +++ b/src/Mod/Path/App/FeaturePathShape.cpp @@ -55,7 +55,7 @@ PARAM_ENUM_STRING_DECLARE(static const char *Enums,AREA_PARAMS_PATH) FeatureShape::FeatureShape() { ADD_PROPERTY(Sources,(0)); - ADD_PROPERTY_TYPE(StartPoint,(Base::Vector3d()),"Path",App::Prop_None,"Path start position"); + ADD_PROPERTY_TYPE(StartPoint,(Base::Vector3d()),"Path",App::Prop_None,"Feed start position"); PARAM_PROP_ADD("Path",AREA_PARAMS_PATH); PARAM_PROP_SET_ENUM(Enums,AREA_PARAMS_PATH); }