/**************************************************************************** * Copyright (c) 2017 Zheng, Lei (realthunder) * * * * This file is part of the FreeCAD CAx development system. * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Library General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Library General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this library; see the file COPYING.LIB. If not, * * write to the Free Software Foundation, Inc., 59 Temple Place, * * Suite 330, Boston, MA 02111-1307, USA * * * ****************************************************************************/ #ifndef PATH_AREA_H #define PATH_AREA_H #include #include #include #include #include #include #include #include #include #include #include #include "Path.h" #include "AreaParams.h" namespace Part { extern PartExport Py::Object shape2pyshape(const TopoDS_Shape &shape); } class CArea; class CCurve; class Bnd_Box; namespace Path { /** Store libarea algorithm configuration */ struct PathExport CAreaParams { PARAM_DECLARE(PARAM_FNAME,AREA_PARAMS_CAREA) CAreaParams(); }; /** Store all Area configurations */ struct PathExport AreaParams: CAreaParams { PARAM_DECLARE(PARAM_FNAME,AREA_PARAMS_AREA) bool operator==(const AreaParams &other) const { #define AREA_COMPARE(_param) \ if(PARAM_FIELD(NAME,_param)!=other.PARAM_FIELD(NAME,_param)) return false; PARAM_FOREACH(AREA_COMPARE,AREA_PARAMS_CAREA) PARAM_FOREACH(AREA_COMPARE,AREA_PARAMS_AREA) return true; } bool operator!=(const AreaParams &other) const { return !(*this == other); } AreaParams(); }; struct PathExport AreaStaticParams: AreaParams { PARAM_DECLARE(PARAM_FNAME,AREA_PARAMS_EXTRA_CONF); AreaStaticParams(); }; /** libarea configurator * * It is kind of troublesome with the fact that libarea uses static variables to * config its algorithm. CAreaConfig makes it easy to safely customize libarea. */ struct PathExport CAreaConfig { /** For saving current libarea settings */ PARAM_DECLARE(PARAM_FNAME,AREA_PARAMS_CAREA) /** The constructor automatically saves current setting and apply user defined ones * * \arg \c p user defined configurations * \arg \c noFitArgs if true, will override and disable arc fitting. Because * arc unfiting and fitting is lossy. And repeatedly perform these operation * may cause shape deformation. So it is best to delay arc fitting until the * final step*/ CAreaConfig(const CAreaParams &p, bool noFitArcs=true); /** The destructor restores the setting, and thus exception safe. */ ~CAreaConfig(); }; /** Base class for FreeCAD wrapping of libarea */ class PathExport Area: public Base::BaseClass { TYPESYSTEM_HEADER(); public: struct Shape { short op; TopoDS_Shape shape; Shape(short opCode, const TopoDS_Shape &s) :op(opCode) ,shape(s) {} }; protected: std::list myShapes; std::unique_ptr myArea; std::unique_ptr myAreaOpen; gp_Trsf myTrsf; AreaParams myParams; TopoDS_Shape myShapePlane; TopoDS_Shape myWorkPlane; TopoDS_Shape myShape; std::vector > mySections; bool myHaveFace; bool myHaveSolid; bool myShapeDone; bool myProjecting; mutable int mySkippedShapes; static bool s_aborting; static AreaStaticParams s_params; /** Called internally to combine children shapes for further processing */ void build(); /** Called by build() to add children shape * * Mainly for checking if there is any faces for auto fill*/ void addToBuild(CArea &area, const TopoDS_Shape &shape); /** Called internally to obtain the combained children shapes */ TopoDS_Shape toShape(CArea &area, short fill, int reorient=0); /** Obtain a list of offseted areas * * See #AREA_PARAMS_OFFSET for description of the arguments. */ void makeOffset(std::list > &areas, PARAM_ARGS_DEF(PARAM_FARG,AREA_PARAMS_OFFSET)); /** Make a pocket of the combined shape * * User #AREA_PARAMS_POCKET setting in myParams. */ TopoDS_Shape makePocket(); void explode(const TopoDS_Shape &shape); TopoDS_Shape findPlane(const TopoDS_Shape &shape, gp_Trsf &trsf); std::list getProjectedShapes(const gp_Trsf &trsf, bool inverse=true) const; public: /** Declare all parameters defined in #AREA_PARAMS_ALL as member variable */ PARAM_ENUM_DECLARE(AREA_PARAMS_ALL) Area(const AreaParams *params = NULL); Area(const Area &other, bool deep_copy=true); virtual ~Area(); bool isBuilt() const; /** Set a working plane * * \arg \c shape: a shape defining a working plane. * * The supplied shape does not need to be planar. Area will try to find planar * sub-shape (face, wire or edge). If more than one planar sub-shape is found, * it will prefer the top plane parallel to XY0 plane. * * If no working plane are set, Area will try to find a working plane from * the added children shape using the same algorithm */ void setPlane(const TopoDS_Shape &shape); /** Return the current active workplane * * \arg \c trsf: optional return of a transformation matrix that will bring the * found plane to XY0 plane. * * If no workplane is set using setPlane(), the active workplane is derived from * the added children shapes using the same algorithm empolyed by setPlane(). */ TopoDS_Shape getPlane(gp_Trsf *trsf=0); /** Add a child shape with given operation code * * No validation is done at this point. Exception will be thrown when asking * for output shape, if any of the children shapes is not valid or not * coplanar * * \arg \c shape: the child shape * \arg \c op: operation code, see #AREA_PARAMS_OPCODE */ void add(const TopoDS_Shape &shape,PARAM_ARGS_DEF(PARAM_FARG,AREA_PARAMS_OPCODE)); /** Generate an offset of the combined shape * * See #AREA_PARAMS_OFFSET for description of the arguments. * If more than one offset is requested, a compound shape is return * containing all offset shapes as wires regardless of \c Fill setting. */ TopoDS_Shape makeOffset(int index=-1, PARAM_ARGS_DEF(PARAM_FARG,AREA_PARAMS_OFFSET), int reoirent=0); /** Make a pocket of the combined shape * * See #AREA_PARAMS_POCKET for description of the arguments. */ TopoDS_Shape makePocket(int index=-1, PARAM_ARGS_DEF(PARAM_FARG,AREA_PARAMS_POCKET)); /** Make a pocket of the combined shape * * \arg \c heights: optional customized heights of each section. The * meaning of each height depends on section mode. If none is given, * the section heights is determined by the section settings in this * Area object (configured through setParams()). * \arg \c plane: the section plane if the section mode is * SectionModeWorkplane, otherwise ignored * * See #AREA_PARAMS_EXTRA for description of the arguments. Currently, there * is only one argument, namely \c mode for section mode. */ std::vector > makeSections( PARAM_ARGS_DEF(PARAM_FARG,AREA_PARAMS_SECTION_EXTRA), const std::vector &heights = std::vector(), const TopoDS_Shape &plane = TopoDS_Shape()); /** Config this Area object */ void setParams(const AreaParams ¶ms); const std::list getChildren() const { return myShapes; } /** Get the current configuration */ const AreaParams &getParams() const { return myParams; } /** Clean internal caches * * The combained shapes is cached internally to make other operation more * efficient, such as makeOffset() and makePocket() * * \arg \c deleteShapes: if true, delete all children shapes. */ void clean(bool deleteShapes=false); /** Get the combined shape * \arg \c index: index of the section, -1 for all sections. No effect on * non-sectioned area. */ TopoDS_Shape getShape(int index=-1); /** Return the number of sections */ std::size_t getSectionCount() { build(); return mySections.size(); } /** Add a OCC wire shape to CArea * * \arg \c area: output converted curved object to here * \arg \c wire: input wire object * \arg \c trsf: optional transform matrix to transform the wire shape into * XY0 plane. * \arg \c deflection: for discretizing non circular curves * \arg \c to_edges: if true, discretize all curves, and insert as open * line segments * */ static void addWire(CArea &area, const TopoDS_Wire &wire, const gp_Trsf *trsf=NULL, double deflection=0.01, bool to_edges=false); /** Add a OCC generic shape to CArea * * \arg \c area: output converted curved object to here * \arg \c shape: input shape object * \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 reorient: reorient closed wires for wire only shape * * \return Returns the number of non coplaner. Planar testing only happens * if \c plane is supplied * */ static int addShape(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 reorient=true); /** Convert curves in CArea into an OCC shape * * \arg \c area: input area object * \arg \c fill: if true, create a face object from the wires * \arg \c trsf: optional transform matrix to transform the shape back into * its original position. * */ static TopoDS_Shape toShape(const CArea &area, bool fill, const gp_Trsf *trsf=NULL, int reoirent=0); /** Convert a single curve into an OCC wire * * \arg \c curve: input curve object * \arg \c trsf: optional transform matrix to transform the shape back into * its original position. * */ static TopoDS_Wire toShape(const CCurve &curve, const gp_Trsf *trsf=NULL, int reorient=0); /** Check if two OCC shape is coplanar */ static bool isCoplanar(const TopoDS_Shape &s1, const TopoDS_Shape &s2); /** Group shapes by their plane, and return a list of sorted wires * * The output wires is ordered by its occupied plane, and sorted to * minimize traval distance * * \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 arc_plane: optional arc plane selection, if given the found plane * will be returned. See #AREA_PARAMS_ARC_PLANE for more details. * * See #AREA_PARAMS_SORT for other arguments * * \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)); /** Convert a list of wires to gcode * * \arg \c path: output toolpath * \arg \c shapes: input list of shapes * \arg \c pstart: output start point, * \arg \c pend: optional output containing the ending point of the returned * * See #AREA_PARAMS_PATH for other arguments */ static void toPath(Toolpath &path, const std::list &shapes, const gp_Pnt *pstart=NULL, gp_Pnt *pend=NULL, PARAM_ARGS_DEF(PARAM_FARG,AREA_PARAMS_PATH)); static int project(TopoDS_Shape &out, const TopoDS_Shape &in, const AreaParams *params=0); static void setWireOrientation(TopoDS_Wire& wire, const gp_Dir &dir, bool ccw); PARAM_ENUM_DECLARE(AREA_PARAMS_PATH) static void abort(bool aborting); static bool aborting(); 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) PARAM_ENUM_DECLARE(AREA_PARAMS_LOG_LEVEL) }; } //namespace Path #endif //PATH_AREA_H