From 1517418ba031fe8922285f883b708df2f2c46d03 Mon Sep 17 00:00:00 2001 From: "Zheng, Lei" Date: Fri, 20 Jan 2017 02:36:59 +0800 Subject: [PATCH] Path.Area added coplanar check parameter --- src/Mod/Path/App/Area.cpp | 149 ++++++++++++++++++++++++---------- src/Mod/Path/App/Area.h | 17 +++- src/Mod/Path/App/AreaParams.h | 3 + 3 files changed, 125 insertions(+), 44 deletions(-) diff --git a/src/Mod/Path/App/Area.cpp b/src/Mod/Path/App/Area.cpp index 45564e960..36a31371f 100644 --- a/src/Mod/Path/App/Area.cpp +++ b/src/Mod/Path/App/Area.cpp @@ -111,22 +111,47 @@ Area::~Area() { } void Area::setPlane(const TopoDS_Shape &shape) { + if(shape.IsNull()) { + myWorkPlane.Nullify(); + return; + } + BRepLib_FindSurface planeFinder(shape,-1,Standard_True); + if (!planeFinder.Found()) + throw Base::ValueError("shape is not coplanar"); myWorkPlane = shape; + myTrsf.SetTransformation(GeomAdaptor_Surface( + planeFinder.Surface()).Plane().Position()); + clean(); } -void Area::add(CArea &area, const TopoDS_Shape &shape, const gp_Trsf *trsf, - double deflection, CArea *areaOpen, bool to_edges, bool reorder) +bool Area::isCoplanar(const TopoDS_Shape &s1, const TopoDS_Shape &s2) { + TopoDS_Builder builder; + TopoDS_Compound comp; + builder.MakeCompound(comp); + builder.Add(comp,s1); + builder.Add(comp,s2); + BRepLib_FindSurface planeFinder(comp,-1,Standard_True); + return planeFinder.Found(); +} + +int Area::add(CArea &area, const TopoDS_Shape &shape, const gp_Trsf *trsf, + double deflection, const TopoDS_Shape *plane, bool force_coplanar, + CArea *areaOpen, bool to_edges, bool reorder) { bool haveShape = false; - + int skipped = 0; for (TopExp_Explorer it(shape, TopAbs_FACE); it.More(); it.Next()) { haveShape = true; const TopoDS_Face &face = TopoDS::Face(it.Current()); + if(plane && !isCoplanar(face,*plane)) { + ++skipped; + if(force_coplanar) continue; + } for (TopExp_Explorer it(face, TopAbs_WIRE); it.More(); it.Next()) add(area,TopoDS::Wire(it.Current()),trsf,deflection); } - if(haveShape) return; + if(haveShape) return skipped; CArea _area; CArea _areaOpen; @@ -134,6 +159,10 @@ void Area::add(CArea &area, const TopoDS_Shape &shape, const gp_Trsf *trsf, for (TopExp_Explorer it(shape, TopAbs_WIRE); it.More(); it.Next()) { haveShape = true; const TopoDS_Wire &wire = TopoDS::Wire(it.Current()); + if(plane && !isCoplanar(wire,*plane)) { + ++skipped; + if(force_coplanar) continue; + } if(BRep_Tool::IsClosed(wire)) add(_area,wire,trsf,deflection); else if(to_edges) { @@ -146,6 +175,10 @@ void Area::add(CArea &area, const TopoDS_Shape &shape, const gp_Trsf *trsf, if(!haveShape) { for (TopExp_Explorer it(shape, TopAbs_EDGE); it.More(); it.Next()) { + if(plane && !isCoplanar(it.Current(),*plane)) { + ++skipped; + if(force_coplanar) continue; + } add(_areaOpen,BRepBuilderAPI_MakeWire( TopoDS::Edge(it.Current())).Wire(),trsf,deflection); } @@ -158,6 +191,7 @@ void Area::add(CArea &area, const TopoDS_Shape &shape, const gp_Trsf *trsf, areaOpen->m_curves.splice(areaOpen->m_curves.end(),_areaOpen.m_curves); else area.m_curves.splice(area.m_curves.end(),_areaOpen.m_curves); + return skipped; } void Area::add(CArea &area, const TopoDS_Wire& wire, @@ -227,16 +261,16 @@ void Area::clean(bool deleteShapes) { myArea = NULL; delete myAreaOpen; myAreaOpen = NULL; - if(deleteShapes) + if(deleteShapes){ + myShapePlane.Nullify(); myShapes.clear(); + myHaveFace = false; + } } void Area::add(const TopoDS_Shape &shape,short op) { #define AREA_SRC_OP(_v) op PARAM_ENUM_CONVERT(AREA_SRC_OP,,PARAM_ENUM_EXCEPT,AREA_PARAMS_OPCODE); - TopExp_Explorer it(shape, TopAbs_SHELL); - if(it.More()) - throw Base::ValueError("not a 2D shape"); clean(); if(myShapes.empty()) Operation = ClipperLib::ctUnion; @@ -258,8 +292,14 @@ void Area::addToBuild(CArea &area, const TopoDS_Shape &shape) { TopExp_Explorer it(shape, TopAbs_FACE); myHaveFace = it.More(); } + const TopoDS_Shape *plane; + if(myParams.Coplanar == CoplanarNone) + plane = NULL; + else + plane = myWorkPlane.IsNull()?&myShapePlane:&myWorkPlane; CArea areaOpen; - add(area,shape,&myTrsf,myParams.Deflection,&areaOpen, + mySkippedShapes += add(area,shape,&myTrsf,myParams.Deflection,plane, + myParams.Coplanar==CoplanarForce,&areaOpen, myParams.OpenMode==OpenModeEdges,myParams.Reorder); if(areaOpen.m_curves.size()) { if(&area == myArea || myParams.OpenMode == OpenModeNone) @@ -278,48 +318,75 @@ void Area::build() { #define AREA_SRC(_v) myParams._v PARAM_ENUM_CONVERT(AREA_SRC,,PARAM_ENUM_EXCEPT,AREA_PARAMS_CLIPPER_FILL); - TopoDS_Builder builder; - TopoDS_Compound comp; - builder.MakeCompound(comp); - if(!myWorkPlane.IsNull()) - builder.Add(comp,myWorkPlane); - else { - for(const Shape &s : myShapes) - builder.Add(comp, s.shape); + if(myWorkPlane.IsNull()) { + myShapePlane.Nullify(); + for(const Shape &s : myShapes) { + bool haveFace = false; + for(TopExp_Explorer it(s.shape, TopAbs_FACE); it.More(); it.Next()) { + haveFace = true; + BRepLib_FindSurface planeFinder(it.Current(),-1,Standard_True); + if (!planeFinder.Found()) + continue; + myShapePlane = it.Current(); + myTrsf.SetTransformation(GeomAdaptor_Surface( + planeFinder.Surface()).Plane().Position()); + break; + } + if(!myShapePlane.IsNull()) break; + if(haveFace) continue; + for(TopExp_Explorer it(s.shape, TopAbs_WIRE); it.More(); it.Next()) { + BRepLib_FindSurface planeFinder(it.Current(),-1,Standard_True); + if (!planeFinder.Found()) + continue; + myShapePlane = it.Current(); + myTrsf.SetTransformation(GeomAdaptor_Surface( + planeFinder.Surface()).Plane().Position()); + break; + } + if(!myShapePlane.IsNull()) break; + } + + if(myShapePlane.IsNull()) + throw Base::ValueError("shapes are not planar"); } - BRepLib_FindSurface planeFinder(comp,-1,Standard_True); - if (!planeFinder.Found()) - throw Base::ValueError("shapes are not coplanar"); - myTrsf.SetTransformation(GeomAdaptor_Surface( - planeFinder.Surface()).Plane().Position()); + try { + myArea = new CArea(); + myAreaOpen = new CArea(); - myArea = new CArea(); - myAreaOpen = new CArea(); + CAreaConfig conf(myParams); + CArea areaClip; - CAreaConfig conf(myParams); - CArea areaClip; + mySkippedShapes = 0; + short op = ClipperLib::ctUnion; + bool pending = false; + for(const Shape &s : myShapes) { + if(op!=s.op) { + if(myParams.OpenMode!=OpenModeNone) + myArea->m_curves.splice(myArea->m_curves.end(),myAreaOpen->m_curves); + pending = false; + myArea->Clip((ClipperLib::ClipType)op,&areaClip,SubjectFill,ClipFill); + areaClip.m_curves.clear(); + op=s.op; + } + addToBuild(op==ClipperLib::ctUnion?*myArea:areaClip,s.shape); + pending = true; + } + if(mySkippedShapes) + Base::Console().Warning("%s %d non coplanar shapes\n", + myParams.Coplanar==CoplanarForce?"Skipped":"Found",mySkippedShapes); - short op = ClipperLib::ctUnion; - bool pending = false; - for(const Shape &s : myShapes) { - if(op!=s.op) { + if(pending){ if(myParams.OpenMode!=OpenModeNone) myArea->m_curves.splice(myArea->m_curves.end(),myAreaOpen->m_curves); - pending = false; myArea->Clip((ClipperLib::ClipType)op,&areaClip,SubjectFill,ClipFill); - areaClip.m_curves.clear(); - op=s.op; } - addToBuild(op==ClipperLib::ctUnion?*myArea:areaClip,s.shape); - pending = true; + myArea->m_curves.splice(myArea->m_curves.end(),myAreaOpen->m_curves); + + }catch(...) { + clean(); + throw; } - if(pending){ - if(myParams.OpenMode!=OpenModeNone) - myArea->m_curves.splice(myArea->m_curves.end(),myAreaOpen->m_curves); - myArea->Clip((ClipperLib::ClipType)op,&areaClip,SubjectFill,ClipFill); - } - myArea->m_curves.splice(myArea->m_curves.end(),myAreaOpen->m_curves); } TopoDS_Shape Area::toShape(CArea &area, short fill) { diff --git a/src/Mod/Path/App/Area.h b/src/Mod/Path/App/Area.h index 40f4fffb8..78b89aa01 100644 --- a/src/Mod/Path/App/Area.h +++ b/src/Mod/Path/App/Area.h @@ -109,9 +109,11 @@ protected: CArea *myAreaOpen; gp_Trsf myTrsf; AreaParams myParams; + TopoDS_Shape myShapePlane; TopoDS_Shape myWorkPlane; TopoDS_Shape myShape; bool myHaveFace; + int mySkippedShapes; /** Called internally to combine children shapes for further processing */ void build(); @@ -205,7 +207,7 @@ public: * \arg \c deflection: for defecting non circular curves * */ static void add(CArea &area, const TopoDS_Wire &wire, - const gp_Trsf *trsf=NULL,double deflection=0.01); + const gp_Trsf *trsf=NULL, double deflection=0.01); /** Add a OCC generic shape to CArea * @@ -214,13 +216,20 @@ public: * \arg \c trsf: optional transform matrix to transform the wire shape into * XY0 plane. * \arg \c deflection: for defecting non circular curves + * \arg \c plane: a shape for testing coplanar + * \arg \c force_coplaner: if true, discard non-coplanar shapes. * \arg \c areaOpen: for collecting open curves. If not supplied, open * curves are added to \c area * \arg \c to_edges: separate open wires to individual edges * \arg \c reorder: reorder closed wires for wire only shape + * + * \return Returns the number of non coplaner. Planar testing only happens + * if \c plane is supplied * */ - static void add(CArea &area, const TopoDS_Shape &shape, const gp_Trsf *trsf=NULL, - double deflection=0.01,CArea *areaOpen=NULL, bool to_edges=false, bool reorder=true); + static int add(CArea &area, const TopoDS_Shape &shape, const gp_Trsf *trsf=NULL, + double deflection=0.01,const TopoDS_Shape *plane = NULL, + bool force_coplanar=true, CArea *areaOpen=NULL, bool to_edges=false, + bool reorder=true); /** Convert curves in CArea into an OCC shape * @@ -231,6 +240,8 @@ public: * */ static TopoDS_Shape toShape(const CArea &area, bool fill, const gp_Trsf *trsf=NULL); + + static bool isCoplanar(const TopoDS_Shape &s1, const TopoDS_Shape &s2); }; } //namespace Path diff --git a/src/Mod/Path/App/AreaParams.h b/src/Mod/Path/App/AreaParams.h index 01b153676..8d16623de 100644 --- a/src/Mod/Path/App/AreaParams.h +++ b/src/Mod/Path/App/AreaParams.h @@ -48,6 +48,9 @@ #define AREA_PARAMS_BASE \ ((enum,fill,Fill,2,"Fill the output wires to make a face. \n"\ "Auto means make a face if any of the children has a face.",(None)(Face)(Auto)))\ + ((enum,coplanar,Coplanar,2,"Specifies the way to check coplanar.\n"\ + "'Force' will discard non coplaner shapes, but 'Check' only gives warning.",\ + (None)(Check)(Force)))\ ((bool,reorder,Reorder,false,"Re-orient closed wires in wire only shapes so that inner wires become holes."))\ ((enum,open_mode,OpenMode,0,"Specify how to handle open wires.\n"\ "'None' means combin without openeration.\n"\