Merge remote-tracking branch 'realthunder/PathArea'

This commit is contained in:
sliptonic
2017-07-07 16:42:14 -05:00
4 changed files with 124 additions and 46 deletions

View File

@@ -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<TopoDS_Shape> 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(

View File

@@ -285,6 +285,11 @@ void Area::addWire(CArea &area, const TopoDS_Wire& wire,
BRepTools_WireExplorer xp(trsf?TopoDS::Wire(
wire.Moved(TopLoc_Location(*trsf))):wire);
if(!xp.More()) {
AREA_TRACE("empty wire");
return;
}
gp_Pnt p = BRep_Tool::Pnt(xp.CurrentVertex());
ccurve.append(CVertex(Point(p.X(),p.Y())));
@@ -2060,13 +2065,14 @@ TopoDS_Shape Area::toShape(const CArea &area, bool fill, const gp_Trsf *trsf, in
struct WireInfo {
TopoDS_Wire wire;
std::deque<gp_Pnt> points;
gp_Pnt pt_end;
bool isClosed;
inline const gp_Pnt &pstart() const{
return points.front();
}
inline const gp_Pnt &pend() const{
return isClosed?pstart():points.back();
return isClosed?pstart():pt_end;
}
};
@@ -2156,8 +2162,9 @@ struct GetWires {
// We don't add in-between vertices of an open wire, because we
// haven't implemented open wire breaking yet.
info.points.push_back(p1);
if(params.direction!=Area::DirectionNone)
if(!info.isClosed && params.direction==Area::DirectionNone)
info.points.push_back(p2);
info.pt_end = p2;
} else {
// For closed wires, we are can easily rebase the wire, so we
// discretize the wires to spatial index it in order to accelerate
@@ -2188,7 +2195,7 @@ struct GetWires {
}
auto it = wires.end();
--it;
for(size_t i=0,count=info.points.size();i<count;++i)
for(size_t i=0,count=it->points.size();i<count;++i)
rtree.insert(RValue(it,i));
FC_DURATION_PLUS(params.bd,t);
}
@@ -2267,7 +2274,7 @@ struct ShapeInfo{
}
if(!done){
double d1 = pt.SquareDistance(it->pstart());
if(myParams.direction==Area::DirectionNone) {
if(myParams.direction!=Area::DirectionNone) {
d = d1;
p = it->pstart();
is_start = true;
@@ -2430,11 +2437,14 @@ struct ShapeInfo{
return myBestWire->wire;
}
std::list<TopoDS_Shape> sortWires(const gp_Pnt &pstart, gp_Pnt &pend,double min_dist) {
std::list<TopoDS_Shape> sortWires(const gp_Pnt &pstart, gp_Pnt &pend,double min_dist, gp_Pnt *pentry) {
if(pstart.SquareDistance(myStartPt)>Precision::SquareConfusion())
if(myWires.empty() ||
pstart.SquareDistance(myStartPt)>Precision::SquareConfusion())
nearest(pstart);
if(pentry) *pentry = myBestPt;
std::list<TopoDS_Shape> wires;
if(min_dist < 0.01)
min_dist = 0.01;
@@ -2602,7 +2612,7 @@ struct WireOrienter {
};
std::list<TopoDS_Shape> Area::sortWires(const std::list<TopoDS_Shape> &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<TopoDS_Shape> wires;
@@ -2727,7 +2737,12 @@ std::list<TopoDS_Shape> Area::sortWires(const std::list<TopoDS_Shape> &shapes,
AREA_TRACE("bound (" << xMin<<", "<<xMax<<"), ("<<
yMin<<", "<<yMax<<"), ("<<zMin<<", "<<zMax<<')');
pstart.SetCoord(xMax,yMax,zMax);
if(_pstart) *_pstart = pstart;
}
gp_Pln pln;
double hint = 0.0;
bool hint_first = true;
while(shape_list.size()) {
AREA_TRACE("sorting " << shape_list.size() << ' ' << AREA_XYZ(pstart));
double best_d;
@@ -2746,10 +2761,42 @@ std::list<TopoDS_Shape> Area::sortWires(const std::list<TopoDS_Shape> &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");
@@ -2800,24 +2847,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");
@@ -2875,11 +2920,15 @@ void Area::setWireOrientation(TopoDS_Wire &wire, const gp_Dir &dir, bool wire_cc
}
void Area::toPath(Toolpath &path, const std::list<TopoDS_Shape> &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<TopoDS_Shape> 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));
@@ -2898,30 +2947,57 @@ void Area::toPath(Toolpath &path, const std::list<TopoDS_Shape> &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
@@ -2942,7 +3018,7 @@ void Area::toPath(Toolpath &path, const std::list<TopoDS_Shape> &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);

View File

@@ -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<TopoDS_Shape> sortWires(const std::list<TopoDS_Shape> &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
*

View File

@@ -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);
}