From 13e4a1bafb5963137dcbd89fa51a9da0f517a91f Mon Sep 17 00:00:00 2001 From: "Zheng, Lei" Date: Mon, 3 Apr 2017 17:47:23 +0800 Subject: [PATCH] Path.Area: added orientation param to Path.fromShapes The 'orientation' parameter allows to enforce loop direction --- src/Mod/Path/App/Area.cpp | 93 ++++++++++++++++++++++++++--------- src/Mod/Path/App/Area.h | 3 ++ src/Mod/Path/App/AreaParams.h | 6 ++- 3 files changed, 78 insertions(+), 24 deletions(-) diff --git a/src/Mod/Path/App/Area.cpp b/src/Mod/Path/App/Area.cpp index 96311dc0ca..1e671c778f 100644 --- a/src/Mod/Path/App/Area.cpp +++ b/src/Mod/Path/App/Area.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -1307,9 +1308,10 @@ struct RGetter typedef bgi::linear<16> RParameters; typedef bgi::rtree RTree; -struct RTreeParams { +struct ShapeParams { double abscissa; int k; + short orientation; #ifdef AREA_TIME_ENABLE TIME_DURATION qd; //rtree query duration TIME_DURATION bd; //rtree build duration @@ -1317,8 +1319,8 @@ struct RTreeParams { TIME_DURATION xd; //BRepExtrema_DistShapeShape duration #endif - RTreeParams(double _a, int _k) - :abscissa(_a),k(_k) + ShapeParams(double _a, int _k, short o) + :abscissa(_a),k(_k),orientation(o) #ifdef AREA_TIME_ENABLE ,qd(0),bd(0),rd(0),xd(0) #endif @@ -1333,8 +1335,8 @@ typedef std::map RResults; struct GetWires { Wires &wires; RTree &rtree; - RTreeParams ¶ms; - GetWires(std::list &ws, RTree &rt, RTreeParams &rp) + ShapeParams ¶ms; + GetWires(std::list &ws, RTree &rt, ShapeParams &rp) :wires(ws),rtree(rt),params(rp) {} void operator()(const TopoDS_Shape &shape, int type) { @@ -1346,6 +1348,13 @@ struct GetWires { info.wire = BRepBuilderAPI_MakeWire(TopoDS::Edge(shape)).Wire(); info.isClosed = BRep_Tool::IsClosed(info.wire); + if(info.isClosed && params.orientation != Area::OrientationNone){ + int dir =Area::getWireDirection(info.wire); + if((dir>0&¶ms.orientation==Area::OrientationCW) || + (dir<0&¶ms.orientation==Area::OrientationCCW)) + info.wire.Reverse(); + } + TIME_INIT(t); BRepTools_WireExplorer xp(info.wire); if(params.abscissa &list, RTreeParams ¶ms) + std::list &list, ShapeParams ¶ms) :myList(list) ,myTrsf(trsf) ,myArcPlane(arc_plane) ,myArcPlaneFound(plane_found), myParams(params) {} @@ -1738,6 +1747,27 @@ struct ShapeInfoBuilder { } }; +struct WireOrienter { + std::list &wires; + short orientation; + + WireOrienter(std::list &ws, short o) + :wires(ws),orientation(o) + {} + + void operator()(const TopoDS_Shape &shape, int type) { + if(type == TopAbs_WIRE) + wires.push_back(shape); + else + wires.push_back(BRepBuilderAPI_MakeWire(TopoDS::Edge(shape)).Wire()); + if(orientation!=Area::OrientationNone && BRep_Tool::IsClosed(wires.back())) { + int dir = Area::getWireDirection(wires.back()); + if((dir>0&&orientation==Area::OrientationCW) || + (dir<0&&orientation==Area::OrientationCCW)) + wires.back().Reverse(); + } + } +}; std::list Area::sortWires(const std::list &shapes, const gp_Pnt *_pstart, gp_Pnt *_pend, short *arc_plane, @@ -1749,21 +1779,14 @@ std::list Area::sortWires(const std::list &shapes, if(sort_mode == SortModeNone) { for(auto &shape : shapes) { - if (shape.IsNull()) - continue; - bool haveShape=false; - for(TopExp_Explorer it(shape,TopAbs_WIRE);it.More();it.Next()) { - haveShape=true; - wires.push_back(it.Current()); - } - if(haveShape) continue; - for(TopExp_Explorer it(shape,TopAbs_EDGE);it.More();it.Next()) - wires.push_back(BRepBuilderAPI_MakeWire(TopoDS::Edge(it.Current())).Wire()); + if(!shape.IsNull()) + foreachSubshape(shape, + WireOrienter(wires,orientation), TopAbs_WIRE); } return std::move(wires); } - RTreeParams rparams(abscissa,nearest_k>0?nearest_k:1); + ShapeParams rparams(abscissa,nearest_k>0?nearest_k:1,orientation); std::list shape_list; TIME_INIT2(t,t1); @@ -1957,6 +1980,31 @@ static inline void addCommand(Toolpath &path, const char *name) { path.addCommand(cmd); } +int Area::getWireDirection(const TopoDS_Shape &shape, const gp_Pln *pln) { + gp_Dir dir; + if(pln) + dir = pln->Axis().Direction(); + else{ + BRepLib_FindSurface finder(shape,-1,Standard_True); + if(!finder.Found()) return 0; + dir = GeomAdaptor_Surface(finder.Surface()).Plane().Axis().Direction(); + } + const TopoDS_Wire &wire = TopoDS::Wire(shape); + //make a test face + BRepBuilderAPI_MakeFace mkFace(wire, /*onlyplane=*/Standard_True); + if(!mkFace.IsDone()) return 0; + TopoDS_Face tmpFace = mkFace.Face(); + //compare face surface normal with our plane's one + BRepAdaptor_Surface surf(tmpFace); + bool normal_co = surf.Plane().Axis().Direction().Dot(dir) > 0; + + //unlikely, but just in case OCC decided to reverse our wire for the face... take that into account! + TopoDS_Iterator it(tmpFace, /*CumOri=*/Standard_False); + normal_co ^= it.Value().Orientation() != wire.Orientation(); + + return normal_co ? 1 : -1; +} + void Area::toPath(Toolpath &path, const std::list &shapes, const gp_Pnt *pstart, gp_Pnt *pend, PARAM_ARGS(PARAM_FARG,AREA_PARAMS_PATH)) { @@ -2003,6 +2051,7 @@ void Area::toPath(Toolpath &path, const std::list &shapes, bool first = true; bool arcWarned = false; for(const TopoDS_Shape &wire : wires) { + BRepTools_WireExplorer xp(TopoDS::Wire(wire)); p = BRep_Tool::Pnt(xp.CurrentVertex()); diff --git a/src/Mod/Path/App/Area.h b/src/Mod/Path/App/Area.h index 3bb9670cb1..7ba1ade075 100644 --- a/src/Mod/Path/App/Area.h +++ b/src/Mod/Path/App/Area.h @@ -444,6 +444,8 @@ public: const gp_Pnt *pstart=NULL, gp_Pnt *pend=NULL, PARAM_ARGS_DEF(PARAM_FARG,AREA_PARAMS_PATH)); + static int getWireDirection(const TopoDS_Shape& wire, const gp_Pln *plane=0); + PARAM_ENUM_DECLARE(AREA_PARAMS_PATH) static void abort(bool aborting); @@ -452,6 +454,7 @@ public: static void setDefaultParams(const AreaStaticParams ¶ms); static const AreaStaticParams &getDefaultParams(); + #define AREA_LOG_CHECK_DECLARE(_1,_2,_elem) \ static bool BOOST_PP_CAT(_elem,Enabled)(); BOOST_PP_SEQ_FOR_EACH(AREA_LOG_CHECK_DECLARE,_,AREA_PARAM_LOG_LEVEL) diff --git a/src/Mod/Path/App/AreaParams.h b/src/Mod/Path/App/AreaParams.h index 93d92777e0..4043228837 100644 --- a/src/Mod/Path/App/AreaParams.h +++ b/src/Mod/Path/App/AreaParams.h @@ -195,9 +195,11 @@ AREA_PARAMS_MIN_DIST \ ((double, abscissa, SortAbscissa, 3.0, "Controls vertex sampling on wire for nearest point searching\n"\ "The sampling is dong using OCC GCPnts_UniformAbscissa",App::PropertyLength))\ - ((short, nearest_k, NearestK, 3, "Nearest k sampling vertices are considered during sorting")) + ((short, nearest_k, NearestK, 3, "Nearest k sampling vertices are considered during sorting"))\ + ((enum, orientation, Orientation, 0, "Enforce loop orientation\n"\ + "Note the CW/CCW here specifies the outer wire orientation. For inner wires (holes), the\n"\ + "enforced orientation is reversed", (None)(CW)(CCW))) - /** Area path generation parameters */ #define AREA_PARAMS_PATH \ AREA_PARAMS_ARC_PLANE \