From 120b37b0c7a5cfb7d2ea84cfbff1fec37247fa4a Mon Sep 17 00:00:00 2001 From: "Zheng, Lei" Date: Tue, 4 Jul 2017 10:37:12 +0800 Subject: [PATCH] Path.Area: change fromShape() 'start' parameter behavior 'start' used to mean the initial resting position of the tool. Now it is changed to mean the feed start position. fromShape() has also improved to automatically guess 'retraction' and 'resume_height' parameters if not given, based on input shape boundary. --- src/Mod/Path/App/AppPathPy.cpp | 4 +- src/Mod/Path/App/Area.cpp | 140 +++++++++++++++++++------- src/Mod/Path/App/Area.h | 6 +- src/Mod/Path/App/FeaturePathShape.cpp | 2 +- 4 files changed, 111 insertions(+), 41 deletions(-) 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); }