Merge pull request #460 from realthunder/PathArea
Added Path.Area and Path::FeatureArea
This commit is contained in:
@@ -98,6 +98,13 @@ if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANGXX)
|
||||
endif()
|
||||
endif(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANGXX)
|
||||
|
||||
if(CMAKE_COMPILER_IS_CLANGXX)
|
||||
# older boost.preprocessor turn off variadics for clang
|
||||
add_definitions(-DBOOST_PP_VARIADICS=1)
|
||||
message(STATUS "Force BOOST_PP_VARIADICS=1 for clang")
|
||||
endif()
|
||||
|
||||
|
||||
# ================================================================================
|
||||
# Output directories for install target
|
||||
|
||||
|
||||
@@ -147,7 +147,7 @@ struct EdgePoints {
|
||||
TopoDS_Edge edge;
|
||||
};
|
||||
|
||||
static std::list<TopoDS_Edge> sort_Edges(double tol3d, std::list<TopoDS_Edge>& edges)
|
||||
PartExport std::list<TopoDS_Edge> sort_Edges(double tol3d, std::list<TopoDS_Edge>& edges)
|
||||
{
|
||||
tol3d = tol3d * tol3d;
|
||||
std::list<EdgePoints> edge_points;
|
||||
|
||||
@@ -105,7 +105,9 @@ PyObject* Curve2dPy::reverse(PyObject * args)
|
||||
return 0;
|
||||
}
|
||||
|
||||
namespace Part {
|
||||
extern Py::Object shape2pyshape(const TopoDS_Shape &shape);
|
||||
}
|
||||
|
||||
PyObject* Curve2dPy::toShape(PyObject *args)
|
||||
{
|
||||
|
||||
@@ -157,8 +157,9 @@ int TopoShapePy::PyInit(PyObject* args, PyObject*)
|
||||
return 0;
|
||||
}
|
||||
|
||||
namespace Part {
|
||||
//common code.. maybe put somewhere else?
|
||||
Py::Object shape2pyshape(const TopoDS_Shape &shape)
|
||||
PartExport Py::Object shape2pyshape(const TopoDS_Shape &shape)
|
||||
{
|
||||
PyObject* ret = 0;
|
||||
if (!shape.IsNull()) {
|
||||
@@ -204,6 +205,7 @@ Py::Object shape2pyshape(const TopoDS_Shape &shape)
|
||||
|
||||
return Py::asObject(ret);
|
||||
}
|
||||
} //namespace Part
|
||||
|
||||
PyObject* TopoShapePy::copy(PyObject *args)
|
||||
{
|
||||
|
||||
@@ -42,6 +42,8 @@
|
||||
#include "PropertyTooltable.h"
|
||||
#include "FeaturePathCompound.h"
|
||||
#include "FeaturePathShape.h"
|
||||
#include "AreaPy.h"
|
||||
#include "FeatureArea.h"
|
||||
|
||||
namespace Path {
|
||||
extern PyObject* initModule();
|
||||
@@ -50,15 +52,24 @@ extern PyObject* initModule();
|
||||
/* Python entry */
|
||||
PyMOD_INIT_FUNC(Path)
|
||||
{
|
||||
// load dependent module
|
||||
try {
|
||||
Base::Interpreter().runString("import Part");
|
||||
}
|
||||
catch(const Base::Exception& e) {
|
||||
PyErr_SetString(PyExc_ImportError, e.what());
|
||||
return;
|
||||
}
|
||||
|
||||
PyObject* pathModule = Path::initModule();
|
||||
Base::Console().Log("Loading Path module... done\n");
|
||||
|
||||
|
||||
// Add Types to module
|
||||
Base::Interpreter().addType(&Path::CommandPy ::Type, pathModule, "Command");
|
||||
Base::Interpreter().addType(&Path::PathPy ::Type, pathModule, "Path");
|
||||
Base::Interpreter().addType(&Path::ToolPy ::Type, pathModule, "Tool");
|
||||
Base::Interpreter().addType(&Path::TooltablePy ::Type, pathModule, "Tooltable");
|
||||
Base::Interpreter().addType(&Path::AreaPy ::Type, pathModule, "Area");
|
||||
|
||||
// NOTE: To finish the initialization of our own type objects we must
|
||||
// call PyType_Ready, otherwise we run into a segmentation fault, later on.
|
||||
@@ -75,6 +86,11 @@ PyMOD_INIT_FUNC(Path)
|
||||
Path::FeatureCompoundPython ::init();
|
||||
Path::FeatureShape ::init();
|
||||
Path::FeatureShapePython ::init();
|
||||
Path::Area ::init();
|
||||
Path::FeatureArea ::init();
|
||||
Path::FeatureAreaPython ::init();
|
||||
Path::FeatureAreaView ::init();
|
||||
Path::FeatureAreaViewPython ::init();
|
||||
|
||||
PyMOD_Return(pathModule);
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include <App/DocumentObjectPy.h>
|
||||
#include <App/Application.h>
|
||||
|
||||
#include <Mod/Part/App/OCCError.h>
|
||||
#include <Mod/Part/App/TopoShape.h>
|
||||
#include <Mod/Part/App/TopoShapePy.h>
|
||||
#include <TopoDS.hxx>
|
||||
@@ -57,7 +58,45 @@
|
||||
#include "Path.h"
|
||||
#include "FeaturePath.h"
|
||||
#include "FeaturePathCompound.h"
|
||||
#include "Area.h"
|
||||
|
||||
#define PATH_CATCH catch (Standard_Failure &e) \
|
||||
{ \
|
||||
std::string str; \
|
||||
Standard_CString msg = e.GetMessageString(); \
|
||||
str += typeid(e).name(); \
|
||||
str += " "; \
|
||||
if (msg) {str += msg;} \
|
||||
else {str += "No OCCT Exception Message";} \
|
||||
Base::Console().Error(str.c_str()); \
|
||||
PyErr_SetString(Part::PartExceptionOCCError,str.c_str()); \
|
||||
} \
|
||||
catch(Base::Exception &e) \
|
||||
{ \
|
||||
std::string str; \
|
||||
str += "FreeCAD exception thrown ("; \
|
||||
str += e.what(); \
|
||||
str += ")"; \
|
||||
e.ReportException(); \
|
||||
PyErr_SetString(Base::BaseExceptionFreeCADError,str.c_str());\
|
||||
} \
|
||||
catch(std::exception &e) \
|
||||
{ \
|
||||
std::string str; \
|
||||
str += "STL exception thrown ("; \
|
||||
str += e.what(); \
|
||||
str += ")"; \
|
||||
Base::Console().Error(str.c_str()); \
|
||||
PyErr_SetString(Base::BaseExceptionFreeCADError,str.c_str());\
|
||||
} \
|
||||
catch(const char *e) \
|
||||
{ \
|
||||
PyErr_SetString(Base::BaseExceptionFreeCADError,e); \
|
||||
} throw Py::Exception();
|
||||
|
||||
namespace Part {
|
||||
extern PartExport Py::Object shape2pyshape(const TopoDS_Shape &shape);
|
||||
}
|
||||
|
||||
namespace Path {
|
||||
class Module : public Py::ExtensionModule<Module>
|
||||
@@ -79,6 +118,23 @@ public:
|
||||
add_varargs_method("fromShape",&Module::fromShape,
|
||||
"fromShape(Shape): Returns a Path object from a Part Shape"
|
||||
);
|
||||
add_keyword_method("fromShapes",&Module::fromShapes,
|
||||
"fromShapes(shapes, start=Vector(), " PARAM_PY_ARGS_DOC(ARG,AREA_PARAMS_PATH) ", key=value...)\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"
|
||||
PARAM_PY_DOC(ARG, AREA_PARAMS_PATH)
|
||||
"\n* <key>: any key supported by Path.Area, see Path.Area.getParamDesc() for description"
|
||||
);
|
||||
add_keyword_method("sortWires",&Module::sortWires,
|
||||
"sortWires(shapes, start=Vector(), " PARAM_PY_ARGS_DOC(ARG,AREA_PARAMS_SORT) ", key=value...)\n"
|
||||
"\nReturns (wires,end), where 'wires' is sorted accross Z value and with optimized travel distance,\n"
|
||||
"and 'end' is the ending position of the whole wires\n"
|
||||
"\n* shapes: input shape list\n"
|
||||
"\n* start (Vector()): optional start position.\n"
|
||||
PARAM_PY_DOC(ARG, AREA_PARAMS_SORT)
|
||||
"\n* <key>: any key supported by Path.Area, see Path.Area.getParamDesc() for description"
|
||||
);
|
||||
initialize("This module is the Path module."); // register with Python
|
||||
}
|
||||
|
||||
@@ -261,7 +317,115 @@ private:
|
||||
throw Py::RuntimeError(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Py::Object fromShapes(const Py::Tuple& args, const Py::Dict &kwds)
|
||||
{
|
||||
PARAM_PY_DECLARE_INIT(PARAM_FARG,AREA_PARAMS_PATH)
|
||||
PARAM_PY_DECLARE_INIT(PARAM_FNAME,AREA_PARAMS_CONF)
|
||||
PyObject *pShapes=NULL;
|
||||
PyObject *start=NULL;
|
||||
static char* kwd_list[] = {"shapes", "start",
|
||||
PARAM_FIELD_STRINGS(ARG,AREA_PARAMS_PATH),
|
||||
PARAM_FIELD_STRINGS(NAME,AREA_PARAMS_CONF), NULL};
|
||||
if (!PyArg_ParseTupleAndKeywords(args.ptr(), kwds.ptr(),
|
||||
"O|O!" PARAM_PY_KWDS(AREA_PARAMS_PATH) PARAM_PY_KWDS(AREA_PARAMS_CONF),
|
||||
kwd_list, &pShapes, &(Base::VectorPy::Type), &start,
|
||||
PARAM_REF(PARAM_FARG,AREA_PARAMS_PATH),
|
||||
PARAM_REF(PARAM_FNAME,AREA_PARAMS_CONF)))
|
||||
throw Py::Exception();
|
||||
|
||||
std::list<TopoDS_Shape> shapes;
|
||||
if (PyObject_TypeCheck(pShapes, &(Part::TopoShapePy::Type)))
|
||||
shapes.push_back(static_cast<Part::TopoShapePy*>(pShapes)->getTopoShapePtr()->getShape());
|
||||
else if (PyObject_TypeCheck(pShapes, &(PyList_Type)) ||
|
||||
PyObject_TypeCheck(pShapes, &(PyTuple_Type)))
|
||||
{
|
||||
Py::Sequence shapeSeq(pShapes);
|
||||
for (Py::Sequence::iterator it = shapeSeq.begin(); it != shapeSeq.end(); ++it) {
|
||||
PyObject* item = (*it).ptr();
|
||||
if(!PyObject_TypeCheck(item, &(Part::TopoShapePy::Type))) {
|
||||
PyErr_SetString(PyExc_TypeError, "non-shape object in sequence");
|
||||
throw Py::Exception();
|
||||
}
|
||||
shapes.push_back(static_cast<Part::TopoShapePy*>(item)->getTopoShapePtr()->getShape());
|
||||
}
|
||||
}
|
||||
|
||||
#define AREA_GET(_param) \
|
||||
params.PARAM_FNAME(_param) = \
|
||||
PARAM_TYPED(PARAM_CAST_PY_,_param)(PARAM_FNAME(_param));
|
||||
AreaParams params;
|
||||
PARAM_FOREACH(AREA_GET,AREA_PARAMS_CONF)
|
||||
|
||||
gp_Pnt pstart;
|
||||
if(start) {
|
||||
Base::Vector3d vec = static_cast<Base::VectorPy*>(start)->value();
|
||||
pstart.SetCoord(vec.x, vec.y, vec.z);
|
||||
}
|
||||
|
||||
try {
|
||||
std::unique_ptr<Toolpath> path(new Toolpath);
|
||||
Area::toPath(*path,shapes,¶ms, &pstart, NULL,
|
||||
PARAM_PY_FIELDS(PARAM_FARG,AREA_PARAMS_PATH));
|
||||
return Py::asObject(new PathPy(path.release()));
|
||||
} PATH_CATCH
|
||||
}
|
||||
|
||||
Py::Object sortWires(const Py::Tuple& args, const Py::Dict &kwds)
|
||||
{
|
||||
PARAM_PY_DECLARE_INIT(PARAM_FARG,AREA_PARAMS_SORT)
|
||||
PARAM_PY_DECLARE_INIT(PARAM_FNAME,AREA_PARAMS_CONF)
|
||||
PyObject *pShapes=NULL;
|
||||
PyObject *start=NULL;
|
||||
static char* kwd_list[] = {"shapes", "start",
|
||||
PARAM_FIELD_STRINGS(ARG,AREA_PARAMS_SORT),
|
||||
PARAM_FIELD_STRINGS(NAME,AREA_PARAMS_CONF), NULL};
|
||||
if (!PyArg_ParseTupleAndKeywords(args.ptr(), kwds.ptr(),
|
||||
"O|O!" PARAM_PY_KWDS(AREA_PARAMS_SORT) PARAM_PY_KWDS(AREA_PARAMS_CONF),
|
||||
kwd_list, &pShapes, &(Base::VectorPy::Type), &start,
|
||||
PARAM_REF(PARAM_FARG,AREA_PARAMS_SORT),
|
||||
PARAM_REF(PARAM_FNAME,AREA_PARAMS_CONF)))
|
||||
throw Py::Exception();
|
||||
|
||||
std::list<TopoDS_Shape> shapes;
|
||||
if (PyObject_TypeCheck(pShapes, &(Part::TopoShapePy::Type)))
|
||||
shapes.push_back(static_cast<Part::TopoShapePy*>(pShapes)->getTopoShapePtr()->getShape());
|
||||
else if (PyObject_TypeCheck(pShapes, &(PyList_Type)) ||
|
||||
PyObject_TypeCheck(pShapes, &(PyTuple_Type))) {
|
||||
Py::Sequence shapeSeq(pShapes);
|
||||
for (Py::Sequence::iterator it = shapeSeq.begin(); it != shapeSeq.end(); ++it) {
|
||||
PyObject* item = (*it).ptr();
|
||||
if(!PyObject_TypeCheck(item, &(Part::TopoShapePy::Type))) {
|
||||
PyErr_SetString(PyExc_TypeError, "non-shape object in sequence");
|
||||
throw Py::Exception();
|
||||
}
|
||||
shapes.push_back(static_cast<Part::TopoShapePy*>(item)->getTopoShapePtr()->getShape());
|
||||
}
|
||||
}
|
||||
|
||||
AreaParams params;
|
||||
PARAM_FOREACH(AREA_GET,AREA_PARAMS_CONF)
|
||||
|
||||
gp_Pnt pstart,pend;
|
||||
if(start) {
|
||||
Base::Vector3d vec = static_cast<Base::VectorPy*>(start)->value();
|
||||
pstart.SetCoord(vec.x, vec.y, vec.z);
|
||||
}
|
||||
|
||||
try {
|
||||
std::list<TopoDS_Shape> wires = Area::sortWires(shapes,¶ms,&pstart,
|
||||
&pend, PARAM_PY_FIELDS(PARAM_FARG,AREA_PARAMS_SORT));
|
||||
PyObject *list = PyList_New(0);
|
||||
for(auto &wire : wires)
|
||||
PyList_Append(list,Py::new_reference_to(
|
||||
Part::shape2pyshape(TopoDS::Wire(wire))));
|
||||
PyObject *ret = PyTuple_New(2);
|
||||
PyTuple_SetItem(ret,0,list);
|
||||
PyTuple_SetItem(ret,1,new Base::VectorPy(
|
||||
Base::Vector3d(pend.X(),pend.Y(),pend.Z())));
|
||||
return Py::asObject(ret);
|
||||
} PATH_CATCH
|
||||
}
|
||||
};
|
||||
|
||||
PyObject* initModule()
|
||||
|
||||
1860
src/Mod/Path/App/Area.cpp
Normal file
1860
src/Mod/Path/App/Area.cpp
Normal file
File diff suppressed because it is too large
Load Diff
465
src/Mod/Path/App/Area.h
Normal file
465
src/Mod/Path/App/Area.h
Normal file
@@ -0,0 +1,465 @@
|
||||
/****************************************************************************
|
||||
* Copyright (c) 2017 Zheng, Lei (realthunder) <realthunder.dev@gmail.com>*
|
||||
* *
|
||||
* 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 <QApplication>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <TopoDS.hxx>
|
||||
#include <gp_Pln.hxx>
|
||||
#include <gp_Circ.hxx>
|
||||
#include <gp_GTrsf.hxx>
|
||||
|
||||
#include <Base/Console.h>
|
||||
#include "Path.h"
|
||||
#include "AreaParams.h"
|
||||
|
||||
#define _AREA_LOG(_l,_msg) do {\
|
||||
if(Area::_l##Enabled()){\
|
||||
std::stringstream str;\
|
||||
str << "Path.Area: " << _msg;\
|
||||
Base::Console()._l("%s\n",str.str().c_str());\
|
||||
}\
|
||||
qApp->sendPostedEvents();\
|
||||
if(Area::aborting()) {\
|
||||
Area::abort(false);\
|
||||
throw Base::AbortException("operation aborted");\
|
||||
}\
|
||||
}while(0)
|
||||
|
||||
#define AREA_LOG(_msg) _AREA_LOG(Log,_msg)
|
||||
#define AREA_WARN(_msg) _AREA_LOG(Warning,_msg)
|
||||
#define AREA_ERR(_msg) _AREA_LOG(Error,_msg)
|
||||
#define AREA_PT(_pt) '('<<(_pt).X()<<", " << (_pt).Y()<<", " << (_pt).Z()<<')'
|
||||
#define AREA_PT2(_pt) '('<<(_pt).x<<", " << (_pt).y<<')'
|
||||
|
||||
#define AREA_TRACE(_msg) do{\
|
||||
if(Area::TraceEnabled()) AREA_LOG('('<<__LINE__<<"): " <<_msg);\
|
||||
}while(0)
|
||||
|
||||
#define AREA_TIME_ENABLE
|
||||
|
||||
#ifdef AREA_TIME_ENABLE
|
||||
#define TIME_UNIT duration<double>
|
||||
#define TIME_CLOCK high_resolution_clock
|
||||
#define TIME_POINT std::chrono::TIME_CLOCK::time_point
|
||||
|
||||
#define TIME_INIT(_t) \
|
||||
auto _t=std::chrono::TIME_CLOCK::now()
|
||||
|
||||
#define TIME_INIT2(_t1,_t2) TIME_INIT(_t1),_t2=_t1
|
||||
#define TIME_INIT3(_t1,_t2,_t3) TIME_INIT(_t1),_t2=_t1,_t3=_t1
|
||||
|
||||
#define _DURATION_PRINT(_l,_d,_msg) \
|
||||
AREA_##_l(_msg<< " time: " << _d.count()<<'s');
|
||||
|
||||
#define DURATION_PRINT(_d,_msg) _DURATION_PRINT(LOG,_d,_msg)
|
||||
|
||||
#define TIME_PRINT(_t,_msg) \
|
||||
DURATION_PRINT(Path::getDuration(_t),_msg);
|
||||
|
||||
#define TIME_TRACE(_t,_msg) \
|
||||
_DURATION_PRINT(TRACE,Path::getDuration(_t),_msg);
|
||||
|
||||
#define DURATION_INIT(_d) \
|
||||
std::chrono::TIME_UNIT _d(0)
|
||||
|
||||
#define DURATION_INIT2(_d1,_d2) DURATION_INIT(_d1),_d2(0)
|
||||
|
||||
namespace Path {
|
||||
inline std::chrono::TIME_UNIT getDuration(TIME_POINT &t)
|
||||
{
|
||||
auto tnow = std::chrono::TIME_CLOCK::now();
|
||||
auto d = std::chrono::duration_cast<std::chrono::TIME_UNIT>(tnow-t);
|
||||
t = tnow;
|
||||
return d;
|
||||
}
|
||||
}
|
||||
|
||||
#define DURATION_PLUS(_d,_t) _d += Path::getDuration(_t)
|
||||
|
||||
#else
|
||||
|
||||
#define TIME_INIT(...) do{}while(0)
|
||||
#define TIME_INIT2(...) do{}while(0)
|
||||
#define TIME_INIT3(...) do{}while(0)
|
||||
#define TIME_PRINT(...) do{}while(0)
|
||||
#define DURATION_PRINT(...) do{}while(0)
|
||||
#define DURATION_INIT(...) do{}while(0)
|
||||
#define DURATION_INIT2(...) do{}while(0)
|
||||
#define DURATION_PLUS(...) do{}while(0)
|
||||
|
||||
#endif
|
||||
|
||||
class CArea;
|
||||
class CCurve;
|
||||
|
||||
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<Shape> myShapes;
|
||||
std::unique_ptr<CArea> myArea;
|
||||
std::unique_ptr<CArea> myAreaOpen;
|
||||
gp_Trsf myTrsf;
|
||||
AreaParams myParams;
|
||||
TopoDS_Shape myShapePlane;
|
||||
TopoDS_Shape myWorkPlane;
|
||||
TopoDS_Shape myShape;
|
||||
std::vector<std::shared_ptr<Area> > mySections;
|
||||
bool myHaveFace;
|
||||
bool myHaveSolid;
|
||||
bool myShapeDone;
|
||||
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);
|
||||
|
||||
/** Obtain a list of offseted areas
|
||||
*
|
||||
* See #AREA_PARAMS_OFFSET for description of the arguments.
|
||||
*/
|
||||
void makeOffset(std::list<std::shared_ptr<CArea> > &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);
|
||||
|
||||
bool isBuilt() const;
|
||||
|
||||
TopoDS_Shape findPlane(const TopoDS_Shape &shape, gp_Trsf &trsf);
|
||||
|
||||
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();
|
||||
|
||||
/** 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 = NULL);
|
||||
|
||||
/** 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));
|
||||
|
||||
/** 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));
|
||||
|
||||
|
||||
std::vector<std::shared_ptr<Area> > makeSections(
|
||||
PARAM_ARGS_DEF(PARAM_FARG,AREA_PARAMS_SECTION_EXTRA),
|
||||
const std::vector<double> &_heights = std::vector<double>(),
|
||||
const TopoDS_Shape &plane = TopoDS_Shape());
|
||||
|
||||
/** Config this Area object */
|
||||
void setParams(const AreaParams ¶ms);
|
||||
|
||||
|
||||
const std::list<Shape> 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 add(CArea &area, const TopoDS_Wire &wire, const gp_Trsf *trsf=NULL,
|
||||
double deflection=0.01, bool to_edges=false);
|
||||
|
||||
/** Output a list or sorted wire with minimize traval distance
|
||||
*
|
||||
* \arg \c index: index of the section, -1 for all sections. No effect on
|
||||
* non-sectioned area.
|
||||
* \arg \c count: number of the sections to return, <=0 for all sections
|
||||
* after \c index. No effect on non-sectioned area.
|
||||
* \arg \c pstart: optional start point
|
||||
* \arg \c pend: optional output containing the ending point of the returned
|
||||
* wires
|
||||
* \arg \c allow_Break: whether allow to break open wires
|
||||
*
|
||||
* See #AREA_PARAMS_SORT for other arguments
|
||||
*
|
||||
* \return sorted wires
|
||||
* */
|
||||
std::list<TopoDS_Shape> sortWires(int index=-1, int count=0,
|
||||
const gp_Pnt *pstart=NULL, gp_Pnt *pend=NULL,
|
||||
PARAM_ARGS_DEF(PARAM_FARG,AREA_PARAMS_SORT));
|
||||
|
||||
/** 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 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 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);
|
||||
|
||||
/** 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);
|
||||
|
||||
/** 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 params: optional Area parameters for the Area object internally
|
||||
* used for sorting
|
||||
* \arg \c pstart: optional start point
|
||||
* \arg \c pend: optional output containing the ending point of the returned
|
||||
*
|
||||
* See #AREA_PARAMS_SORT for other arguments
|
||||
*
|
||||
* \return sorted wires
|
||||
*/
|
||||
static std::list<TopoDS_Shape> sortWires(const std::list<TopoDS_Shape> &shapes,
|
||||
const AreaParams *params = NULL, const gp_Pnt *pstart=NULL,
|
||||
gp_Pnt *pend=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 params: optional Area parameters for the Area object internally
|
||||
* used for sorting
|
||||
* \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<TopoDS_Shape> &shapes,
|
||||
const AreaParams *params=NULL, const gp_Pnt *pstart=NULL, gp_Pnt *pend=NULL,
|
||||
PARAM_ARGS_DEF(PARAM_FARG,AREA_PARAMS_PATH));
|
||||
|
||||
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
|
||||
223
src/Mod/Path/App/AreaParams.h
Normal file
223
src/Mod/Path/App/AreaParams.h
Normal file
@@ -0,0 +1,223 @@
|
||||
/****************************************************************************
|
||||
* Copyright (c) 2017 Zheng, Lei (realthunder) <realthunder.dev@gmail.com>*
|
||||
* *
|
||||
* 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_AreaParams_H
|
||||
#define PATH_AreaParams_H
|
||||
|
||||
// deifne this to enable offset algo selection
|
||||
// #define AREA_OFFSET_ALGO
|
||||
|
||||
/** \file
|
||||
* Parameters definition for Path::Area and its companion
|
||||
* See \ref ParamPage "here" for details of parameter definition.
|
||||
*/
|
||||
|
||||
#include "ParamsHelper.h"
|
||||
|
||||
/** clipper fill type */
|
||||
#define AREA_CLIPPER_FILL_TYPE \
|
||||
(NonZero)(EvenOdd)(Positive)(Negative),(ClipperLib::PolyFillType,ClipperLib::pft)
|
||||
|
||||
/** Paramerters of clipper fill types */
|
||||
#define AREA_PARAMS_CLIPPER_FILL \
|
||||
((enum2,subject_fill,SubjectFill,0,\
|
||||
"ClipperLib subject fill type. \nSee https://goo.gl/5pYQQP",AREA_CLIPPER_FILL_TYPE))\
|
||||
((enum2,clip_fill,ClipFill,0,\
|
||||
"ClipperLib clip fill type. \nSee https://goo.gl/5pYQQP",AREA_CLIPPER_FILL_TYPE))
|
||||
|
||||
/** Deflection parameter */
|
||||
#define AREA_PARAMS_DEFLECTION \
|
||||
((double,deflection,Deflection,0.01,\
|
||||
"Deflection for non circular curve discretization. It also also used for\n"\
|
||||
"discretizing circular wires when you 'Explode' the shape for wire operations"))
|
||||
|
||||
/** Base parameters */
|
||||
#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. 'Force' will discard non coplaner shapes,\n"\
|
||||
"but 'Check' only gives warning.",(None)(Check)(Force)))\
|
||||
((bool,reorient,Reorient,true,\
|
||||
"Re-orient closed wires in wire only shapes so that inner wires become holes."))\
|
||||
((bool,explode,Explode,false,\
|
||||
"If true, Area will explode the first shape into disconnected open edges, \n"\
|
||||
"with all curves discretized, so that later operations like 'Difference' \n"\
|
||||
"behave like wire cutting. Without exploding, 'Difference' in ClipperLib\n"\
|
||||
"behave like face cutting."))\
|
||||
((enum,open_mode,OpenMode,0,\
|
||||
"Specify how to handle open wires. 'None' means combin without openeration.\n"\
|
||||
"'Edges' means separate to edges before Union. ClipperLib seems to have an.\n"\
|
||||
"urge to close open wires.",(None)(Union)(Edges)))\
|
||||
AREA_PARAMS_DEFLECTION \
|
||||
AREA_PARAMS_CLIPPER_FILL
|
||||
|
||||
#define AREA_PARAMS_FIT_ARCS \
|
||||
((bool,fit_arcs,FitArcs,true,"Enable arc fitting"))
|
||||
|
||||
/** libarea algorithm option parameters */
|
||||
#define AREA_PARAMS_CAREA \
|
||||
((double,tolerance,Tolerance,Precision::Confusion(),"Point coincidence tolerance"))\
|
||||
AREA_PARAMS_FIT_ARCS \
|
||||
((bool,clipper_simple,Simplify,false,\
|
||||
"Simplify polygons after operation. See https://goo.gl/Mh9XK1"))\
|
||||
((double,clipper_clean_distance,CleanDistance,0.0,\
|
||||
"Clean polygon smaller than this distance. See https://goo.gl/jox3JY"))\
|
||||
((double,accuracy,Accuracy,0.01,"Arc fitting accuracy"))\
|
||||
((double,units,Unit,1.0,"Scaling factor for convertion to inch"))\
|
||||
((short,min_arc_points,MinArcPoints,4,"Minimum segments for arc discretization"))\
|
||||
((short,max_arc_points,MaxArcPoints,100,"Maximum segments for arc discretization"))\
|
||||
((double,clipper_scale,ClipperScale,10000.0,\
|
||||
"ClipperLib operate on intergers. This is the scale factor to convert\n"\
|
||||
"floating points."))
|
||||
|
||||
/** Pocket parameters
|
||||
*
|
||||
* These parameters cooresponds to CAreaPocketParams in libarea
|
||||
* */
|
||||
#define AREA_PARAMS_POCKET \
|
||||
((enum,mode,PocketMode,0,"Selects the pocket toolpath pattern",(None)(ZigZag)(Offset)(Spiral)(ZigZagOffset)))\
|
||||
((double,tool_radius,ToolRadius,1.0,"Tool radius for pocketing"))\
|
||||
((double,extra_offset,PocketExtraOffset,0.0,"Extra offset for pocketing"))\
|
||||
((double,stepover,PocketStepover,0.0,"Cutter diameter to step over on each pass. If =0, use ToolRadius."))\
|
||||
((bool,from_center,FromCenter,true,"Start pocketing from center"))\
|
||||
((double,zig_angle,ZigAngle,45,"Zig angle in degree"))
|
||||
|
||||
#define AREA_PARAMS_POCKET_CONF \
|
||||
((bool,thicken,Thicken,false,"Thicken the resulting wires with ToolRadius"))
|
||||
|
||||
/** Operation code */
|
||||
#define AREA_PARAMS_OPCODE \
|
||||
((enum,op,Operation,0,"Boolean operation.\n"\
|
||||
"For the first four operations, see https://goo.gl/Gj8RUu.\n"\
|
||||
"'Compound' means no operation, normally used to do Area.sortWires().",\
|
||||
(Union)(Difference)(Intersection)(Xor)(Compound)))
|
||||
|
||||
/** Offset parameters */
|
||||
#define AREA_PARAMS_OFFSET \
|
||||
((double,offset,Offset,0.0,"Offset value, positive for expansion, negative for shrinking"))\
|
||||
((long,extra_pass,ExtraPass,0,"Number of extra offset pass to generate."))\
|
||||
((double,stepover,Stepover,0.0,"Cutter diameter to step over on each pass. If =0, use Offset"))
|
||||
|
||||
#define AREA_PARAMS_SECTION_EXTRA \
|
||||
((enum,mode,SectionMode,2,"Section offset coordinate mode.\n"\
|
||||
"'Absolute' means the absolute Z height to start section.\n"\
|
||||
"'BoundBox' means relative Z height to the bounding box of all the children shape. Only\n"\
|
||||
"positive value is allowed, which specifies the offset below the top Z of the bounding box.\n"\
|
||||
"Note that OCC has trouble getting the minimumi bounding box of some solids, particually\n"\
|
||||
"those with non-planar surface.\n"\
|
||||
"'Workplane' means relative to workplane.",\
|
||||
(Absolute)(BoundBox)(Workplane)))
|
||||
|
||||
/** Section parameters */
|
||||
#define AREA_PARAMS_SECTION \
|
||||
((long,count,SectionCount,0,"Number of sections to generate. -1 means full sections."))\
|
||||
((double,stepdown,Stepdown,1.0,"Step down distance for each section"))\
|
||||
((double,offset,SectionOffset,0.0,"Offset for the first section"))\
|
||||
AREA_PARAMS_SECTION_EXTRA
|
||||
|
||||
#ifdef AREA_OFFSET_ALGO
|
||||
# define AREA_PARAMS_OFFSET_ALGO \
|
||||
((enum,algo,Algo,0,"Offset algorithm type",(Clipper)(libarea)))
|
||||
#else
|
||||
# define AREA_PARAMS_OFFSET_ALGO
|
||||
#endif
|
||||
|
||||
/** Offset configuration parameters */
|
||||
#define AREA_PARAMS_OFFSET_CONF \
|
||||
AREA_PARAMS_OFFSET_ALGO \
|
||||
((enum2,join_type,JoinType,0,"ClipperOffset join type. \nSee https://goo.gl/4odfQh",\
|
||||
(Round)(Square)(Miter),(ClipperLib::JoinType,ClipperLib::jt)))\
|
||||
((enum2,end_type,EndType,0,"\nClipperOffset end type. See https://goo.gl/tj7gkX",\
|
||||
(OpenRound)(ClosedPolygon)(ClosedLine)(OpenSquare)(OpenButt),(ClipperLib::EndType,ClipperLib::et)))\
|
||||
((double,miter_limit,MiterLimit,2.0,"Miter limit for joint type Miter. See https://goo.gl/K8xX9h"))\
|
||||
((double,round_precision,RoundPreceision,0.0,\
|
||||
"Round joint precision. If =0, it defaults to Accuracy. \nSee https://goo.gl/4odfQh"))
|
||||
|
||||
#define AREA_PARAMS_MIN_DIST \
|
||||
((double, min_dist, MinDistance, 0.0, \
|
||||
"minimum distance for the generated new wires. Wires maybe broken if the\n"\
|
||||
"algorithm see fits. Set to zero to disable wire breaking."))
|
||||
|
||||
/** Area wire sorting parameters */
|
||||
#define AREA_PARAMS_SORT \
|
||||
((enum, sort_mode, SortMode, 1, "Wire sorting mode to optimize travel distance.\n"\
|
||||
"'2D5' explode shapes into wires, and groups the shapes by its plane. The 'start' position\n"\
|
||||
"chooses the first plane to start. The algorithm will then sort within the plane and then\n"\
|
||||
"move on to the next nearest plane.\n"\
|
||||
"'3D' makes no assumption of planarity. The sorting is done across 3D space\n",\
|
||||
(None)(2D5)(3D)))\
|
||||
AREA_PARAMS_MIN_DIST
|
||||
|
||||
/** Area path generation parameters */
|
||||
#define AREA_PARAMS_PATH \
|
||||
AREA_PARAMS_SORT \
|
||||
((double, threshold, RetractThreshold, 0.0,\
|
||||
"If two wire's end points are separated within this threshold, they are consider\n"\
|
||||
"as connected. You may want to set this to the tool diameter to keep the tool down."))\
|
||||
((double, height, RetractHeight, 0.0,"Tool retraction absolute height"))\
|
||||
((double, clearance, Clearance, 0.0,\
|
||||
"When return from last retraction, this gives the pause height relative to the Z\n"\
|
||||
"value of the next move"))\
|
||||
((double,segmentation,Segmentation,0.0,\
|
||||
"Break long curves into segments of this length. One use case is for PCB autolevel,\n"\
|
||||
"so that more correction points can be inserted"))
|
||||
|
||||
#define AREA_PARAMS_PATH_EXTRA \
|
||||
AREA_PARAMS_DEFLECTION \
|
||||
AREA_PARAMS_FIT_ARCS
|
||||
|
||||
#define AREA_PARAMS_PATH_CONF \
|
||||
AREA_PARAMS_PATH \
|
||||
AREA_PARAMS_PATH_EXTRA
|
||||
|
||||
/** Group of all Area configuration parameters except CArea's*/
|
||||
#define AREA_PARAMS_AREA \
|
||||
AREA_PARAMS_BASE \
|
||||
AREA_PARAMS_OFFSET \
|
||||
AREA_PARAMS_OFFSET_CONF \
|
||||
AREA_PARAMS_POCKET \
|
||||
AREA_PARAMS_POCKET_CONF \
|
||||
AREA_PARAMS_SECTION
|
||||
|
||||
/** Group of all Area configuration parameters */
|
||||
#define AREA_PARAMS_CONF \
|
||||
AREA_PARAMS_CAREA \
|
||||
AREA_PARAMS_AREA
|
||||
|
||||
/** Group of all Area parameters */
|
||||
#define AREA_PARAMS_ALL \
|
||||
AREA_PARAMS_CONF \
|
||||
AREA_PARAMS_OPCODE
|
||||
|
||||
#define AREA_PARAM_LOG_LEVEL (Error)(Warning)(Log)(Trace)
|
||||
#define AREA_PARAMS_LOG_LEVEL \
|
||||
((enum, log_level, LogLevel, 1, "Area log level", AREA_PARAM_LOG_LEVEL))
|
||||
|
||||
#define AREA_PARAMS_EXTRA_CONF \
|
||||
AREA_PARAMS_LOG_LEVEL
|
||||
|
||||
#define AREA_PARAMS_STATIC_CONF \
|
||||
AREA_PARAMS_CONF \
|
||||
AREA_PARAMS_EXTRA_CONF
|
||||
|
||||
#endif //PATH_AreaParam_H
|
||||
114
src/Mod/Path/App/AreaPy.xml
Normal file
114
src/Mod/Path/App/AreaPy.xml
Normal file
@@ -0,0 +1,114 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
|
||||
<PythonExport
|
||||
Father="BaseClassPy"
|
||||
Name="AreaPy"
|
||||
Twin="Area"
|
||||
TwinPointer="Area"
|
||||
Include="Mod/Path/App/Area.h"
|
||||
Namespace="Path"
|
||||
FatherInclude="Base/BaseClassPy.h"
|
||||
FatherNamespace="Base"
|
||||
Constructor="true"
|
||||
Delete="true">
|
||||
<Documentation>
|
||||
<Author Licence="LGPL" Name="Zheng, Lei" EMail="realthunder.dev@gmail.com" />
|
||||
<UserDocu>FreeCAD python wrapper of libarea\n
|
||||
Path.Area(key=value ...)\n
|
||||
The constuctor accepts the same parameters as setParams(...) to configure the object
|
||||
All arguments are optional.</UserDocu>
|
||||
</Documentation>
|
||||
<Methode Name="add" Keyword='true'>
|
||||
<Documentation>
|
||||
<UserDocu></UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="setPlane">
|
||||
<Documentation>
|
||||
<UserDocu>setPlane(shape): Set the working plane.\n
|
||||
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</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getShape" Keyword='true'>
|
||||
<Documentation>
|
||||
<UserDocu>getShape(index=-1,rebuild=False): Return the resulting shape\n
|
||||
\n* index (-1): the index of the section. -1 means all sections. No effect on planar shape.\n
|
||||
\n* rebuild: clean the internal cache and rebuild</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="makeOffset" Keyword='true'>
|
||||
<Documentation>
|
||||
<UserDocu></UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="makePocket" Keyword='true'>
|
||||
<Documentation>
|
||||
<UserDocu></UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="makeSections" Keyword="true">
|
||||
<Documentation>
|
||||
<UserDocu></UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="setParams" Keyword="true">
|
||||
<Documentation>
|
||||
<UserDocu></UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="setDefaultParams" Keyword="true">
|
||||
<Documentation>
|
||||
<UserDocu></UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getDefaultParams">
|
||||
<Documentation>
|
||||
<UserDocu></UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getParamsDesc" Keyword="true">
|
||||
<Documentation>
|
||||
<UserDocu>getParamsDesc(as_string=True): Returns a list of supported parameters and their descriptions.\n
|
||||
* as_string: if False, then return a dictionary of documents of all supported parameters.
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="sortWires" Keyword="true">
|
||||
<Documentation>
|
||||
<UserDocu></UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getParams">
|
||||
<Documentation>
|
||||
<UserDocu>Get current algorithm parameters as a dictionary.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="abort" Keyword="true">
|
||||
<Documentation>
|
||||
<UserDocu></UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Attribute Name="Sections" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>List of sections in this area.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Sections" Type="List"/>
|
||||
</Attribute>
|
||||
<Attribute Name="Workplane" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>The current workplane. If no plane is set, it is derived from the added shapes.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Workplane" Type="Object"/>
|
||||
</Attribute>
|
||||
<Attribute Name="Shapes" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>A list of tuple: [(shape,op), ...] containing the added shapes together with their operation code</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Shapes" Type="List"/>
|
||||
</Attribute>
|
||||
</PythonExport>
|
||||
</GenerateModel>
|
||||
495
src/Mod/Path/App/AreaPyImp.cpp
Normal file
495
src/Mod/Path/App/AreaPyImp.cpp
Normal file
@@ -0,0 +1,495 @@
|
||||
/****************************************************************************
|
||||
* Copyright (c) 2017 Zheng, Lei (realthunder) <realthunder.dev@gmail.com>*
|
||||
* *
|
||||
* 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 *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#include <Mod/Part/App/TopoShapePy.h>
|
||||
#include <Base/VectorPy.h>
|
||||
|
||||
#include "Area.h"
|
||||
|
||||
// inclusion of the generated files (generated out of AreaPy.xml)
|
||||
#include "AreaPy.h"
|
||||
#include "AreaPy.cpp"
|
||||
|
||||
|
||||
static PyObject * areaAbort(PyObject *, PyObject *args, PyObject *kwd) {
|
||||
static char *kwlist[] = {"aborting", NULL};
|
||||
PyObject *pObj = Py_True;
|
||||
if (!PyArg_ParseTupleAndKeywords(args,kwd,"|O",kwlist,&pObj))
|
||||
return 0;
|
||||
Area::abort(PyObject_IsTrue(pObj));
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject * areaSetParams(PyObject *, PyObject *args, PyObject *kwd) {
|
||||
|
||||
static char *kwlist[] = {PARAM_FIELD_STRINGS(NAME,AREA_PARAMS_STATIC_CONF),NULL};
|
||||
|
||||
//Declare variables defined in the NAME field of the CONF parameter list
|
||||
PARAM_PY_DECLARE(PARAM_FNAME,AREA_PARAMS_STATIC_CONF);
|
||||
|
||||
AreaStaticParams params = Area::getDefaultParams();
|
||||
|
||||
#define AREA_SET(_param) \
|
||||
PARAM_FNAME(_param) = \
|
||||
PARAM_TYPED(PARAM_PY_CAST_,_param)(params.PARAM_FNAME(_param));
|
||||
//populate the CONF variables with params
|
||||
PARAM_FOREACH(AREA_SET,AREA_PARAMS_STATIC_CONF)
|
||||
|
||||
//Parse arguments to overwrite CONF variables
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwd,
|
||||
"|" PARAM_PY_KWDS(AREA_PARAMS_STATIC_CONF), kwlist,
|
||||
PARAM_REF(PARAM_FNAME,AREA_PARAMS_STATIC_CONF)))
|
||||
return 0;
|
||||
|
||||
#define AREA_GET(_param) \
|
||||
params.PARAM_FNAME(_param) = \
|
||||
PARAM_TYPED(PARAM_CAST_PY_,_param)(PARAM_FNAME(_param));
|
||||
//populate 'params' with the CONF variables
|
||||
PARAM_FOREACH(AREA_GET,AREA_PARAMS_STATIC_CONF)
|
||||
|
||||
Area::setDefaultParams(params);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject* areaGetParams(PyObject *, PyObject *args) {
|
||||
if (!PyArg_ParseTuple(args, ""))
|
||||
return 0;
|
||||
|
||||
const AreaStaticParams ¶ms = Area::getDefaultParams();
|
||||
|
||||
PyObject *dict = PyDict_New();
|
||||
#define AREA_SRC(_param) params.PARAM_FNAME(_param)
|
||||
PARAM_PY_DICT_SET_VALUE(dict,NAME,AREA_SRC,AREA_PARAMS_STATIC_CONF)
|
||||
return dict;
|
||||
}
|
||||
|
||||
|
||||
static const PyMethodDef areaOverrides[] = {
|
||||
{
|
||||
"setParams",NULL,0,
|
||||
"setParam(key=value...): Set algorithm parameters. You can call getParamsDesc() to \n"
|
||||
"get a list of supported parameters and their descriptions.\n"
|
||||
PARAM_PY_DOC(NAME,AREA_PARAMS_CONF)
|
||||
},
|
||||
{
|
||||
"add",NULL,0,
|
||||
"add((shape...)," PARAM_PY_ARGS_DOC(ARG,AREA_PARAMS_OPCODE) "):\n"
|
||||
"Add TopoShape(s) with given operation code\n"
|
||||
PARAM_PY_DOC(ARG,AREA_PARAMS_OPCODE)
|
||||
"\nThe first shape's wires will be unioned together regardless of the op code given\n"
|
||||
"(except for 'Compound'). Subsequent shape's wire will be combined using the op code.\n"
|
||||
"All shape wires shall be coplanar, and are used to determine a working plane for face\n"
|
||||
"making and offseting. You can call setPlane() to supply a reference shape to determin\n"
|
||||
"the workplane in case the added shapes are all colinear lines.\n",
|
||||
},
|
||||
|
||||
{
|
||||
"makeOffset",NULL,0,
|
||||
"makeOffset(index=-1, " PARAM_PY_ARGS_DOC(ARG,AREA_PARAMS_OFFSET) "):\n"
|
||||
"Make an 2D offset of the shape.\n"
|
||||
"\n* index (-1): the index of the section. -1 means all sections. No effect on planar shape.\n"
|
||||
PARAM_PY_DOC(ARG,AREA_PARAMS_OFFSET),
|
||||
},
|
||||
{
|
||||
"makePocket",NULL,0,
|
||||
"makePocket(index=-1, " PARAM_PY_ARGS_DOC(ARG,AREA_PARAMS_POCKET) "):\n"
|
||||
"Generate pocket toolpath of the shape.\n"
|
||||
"\n* index (-1): the index of the section. -1 means all sections. No effect on planar shape.\n"
|
||||
PARAM_PY_DOC(ARG,AREA_PARAMS_POCKET),
|
||||
},
|
||||
{
|
||||
"makeSections",NULL,0,
|
||||
"makeSections(" PARAM_PY_ARGS_DOC(ARG,AREA_PARAMS_SECTION_EXTRA) ", heights=[], plane=None):\n"
|
||||
"Make a list of area holding the sectioned children shapes on given heights\n"
|
||||
PARAM_PY_DOC(ARG,AREA_PARAMS_SECTION_EXTRA)
|
||||
"\n* heights ([]): a list of section heights, the meaning of the value is determined by 'mode'.\n"
|
||||
"If not specified, the current SectionCount, and SectionOffset of this Area is used.\n"
|
||||
"\n* plane (None): optional shape to specify a section plane. If not give, the current workplane\n"
|
||||
"of this Area is used.",
|
||||
},
|
||||
{
|
||||
"sortWires",NULL,0,
|
||||
"sortWires(index=-1, count=0, start=Vector(), allow_break=False, " PARAM_PY_ARGS_DOC(ARG,AREA_PARAMS_SORT) "):\n"
|
||||
"Returns a tuple (wires,end): sorted wires with minimized travel distance, and the endpoint\n"
|
||||
"of the wires.\n"
|
||||
"\n* index (-1): the index of the section. -1 means all sections. No effect on planar shape.\n"
|
||||
"\n* count (0): the number of sections to return. <=0 means all sections starting from index.\n"
|
||||
"\n* start (Vector()): a vector specifies the start point.\n"
|
||||
PARAM_PY_DOC(ARG,AREA_PARAMS_SORT),
|
||||
},
|
||||
{
|
||||
"setDefaultParams",(PyCFunction)areaSetParams, METH_VARARGS|METH_KEYWORDS|METH_STATIC,
|
||||
"setDefaultParams(" PARAM_PY_ARGS_DOC(NAME,AREA_PARAMS_EXTRA_CONF) ", key=value...):\n"
|
||||
"Static method to set the default parameters of all following Path.Area, plus the following\n"
|
||||
"additional parameters.\n"
|
||||
PARAM_PY_DOC(NAME,AREA_PARAMS_EXTRA_CONF)
|
||||
},
|
||||
{
|
||||
"getDefaultParams",(PyCFunction)areaGetParams, METH_VARARGS|METH_STATIC,
|
||||
"getDefaultParams(): Static method to return the current default parameters."
|
||||
},
|
||||
{
|
||||
"abort",(PyCFunction)areaAbort, METH_VARARGS|METH_KEYWORDS|METH_STATIC,
|
||||
"abort(aborting=True): Static method to abort any ongoing operation\n"
|
||||
"\nTo ensure no stray abortion is left in the previous operaion, it is advised to manually clear\n"
|
||||
"the aborting flag by calling abort(False) before starting a new operation.",
|
||||
},
|
||||
};
|
||||
|
||||
struct AreaPyModifier {
|
||||
AreaPyModifier() {
|
||||
for(auto &method : Path::AreaPy::Methods) {
|
||||
if(!method.ml_name) continue;
|
||||
for(auto &entry : areaOverrides) {
|
||||
if(std::strcmp(method.ml_name,entry.ml_name)==0) {
|
||||
if(entry.ml_doc)
|
||||
method.ml_doc = entry.ml_doc;
|
||||
if(entry.ml_meth)
|
||||
method.ml_meth = entry.ml_meth;
|
||||
if(entry.ml_flags)
|
||||
method.ml_flags = entry.ml_flags;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static AreaPyModifier mod;
|
||||
|
||||
namespace Part {
|
||||
extern PartExport Py::Object shape2pyshape(const TopoDS_Shape &shape);
|
||||
}
|
||||
|
||||
using namespace Path;
|
||||
|
||||
// returns a string which represents the object e.g. when printed in python
|
||||
std::string AreaPy::representation(void) const
|
||||
{
|
||||
std::stringstream str;
|
||||
str << "<Area object at " << getAreaPtr() << ">";
|
||||
return str.str();
|
||||
}
|
||||
|
||||
PyObject *AreaPy::PyMake(struct _typeobject *, PyObject *args, PyObject *kwd) // Python wrapper
|
||||
{
|
||||
std::unique_ptr<AreaPy> ret(new AreaPy(new Area));
|
||||
if(!ret->setParams(args,kwd))
|
||||
return 0;
|
||||
return ret.release();
|
||||
}
|
||||
|
||||
// constructor method
|
||||
int AreaPy::PyInit(PyObject* , PyObject* )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyObject* AreaPy::setPlane(PyObject *args) {
|
||||
PyObject *pcObj;
|
||||
if (!PyArg_ParseTuple(args, "O!", &(Part::TopoShapePy::Type), &pcObj))
|
||||
return 0;
|
||||
|
||||
#define GET_TOPOSHAPE(_p) static_cast<Part::TopoShapePy*>(_p)->getTopoShapePtr()->getShape()
|
||||
getAreaPtr()->setPlane(GET_TOPOSHAPE(pcObj));
|
||||
Py_INCREF(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
PyObject* AreaPy::getShape(PyObject *args, PyObject *keywds)
|
||||
{
|
||||
PyObject *pcObj = Py_False;
|
||||
short index=-1;
|
||||
static char *kwlist[] = {"index","rebuild", NULL};
|
||||
if (!PyArg_ParseTupleAndKeywords(args, keywds,"|hO",kwlist,&pcObj))
|
||||
return 0;
|
||||
|
||||
if(PyObject_IsTrue(pcObj))
|
||||
getAreaPtr()->clean();
|
||||
return Py::new_reference_to(Part::shape2pyshape(getAreaPtr()->getShape(index)));
|
||||
}
|
||||
|
||||
PyObject* AreaPy::sortWires(PyObject *args, PyObject *keywds){
|
||||
PARAM_PY_DECLARE_INIT(PARAM_FARG,AREA_PARAMS_SORT)
|
||||
short index = -1;
|
||||
short count = 0;
|
||||
PyObject *start = NULL;
|
||||
|
||||
static char *kwlist[] = {"index","count","start",
|
||||
PARAM_FIELD_STRINGS(ARG,AREA_PARAMS_SORT), NULL};
|
||||
if (!PyArg_ParseTupleAndKeywords(args, keywds,
|
||||
"|hhO!" PARAM_PY_KWDS(AREA_PARAMS_SORT),
|
||||
kwlist,&index,&count,&(Base::VectorPy::Type),&start,
|
||||
PARAM_REF(PARAM_FARG,AREA_PARAMS_SORT)))
|
||||
return 0;
|
||||
|
||||
gp_Pnt pstart,pend;
|
||||
if(start) {
|
||||
Base::Vector3d vec = static_cast<Base::VectorPy*>(start)->value();
|
||||
pstart.SetCoord(vec.x, vec.y, vec.z);
|
||||
}
|
||||
std::list<TopoDS_Shape> wires = getAreaPtr()->sortWires(
|
||||
index,count,&pstart,&pend,
|
||||
PARAM_PY_FIELDS(PARAM_FARG,AREA_PARAMS_SORT));
|
||||
PyObject *list = PyList_New(0);
|
||||
for(auto &wire : wires)
|
||||
PyList_Append(list,Py::new_reference_to(
|
||||
Part::shape2pyshape(TopoDS::Wire(wire))));
|
||||
PyObject *ret = PyTuple_New(2);
|
||||
PyTuple_SetItem(ret,0,list);
|
||||
PyTuple_SetItem(ret,1,new Base::VectorPy(
|
||||
Base::Vector3d(pend.X(),pend.Y(),pend.Z())));
|
||||
return ret;
|
||||
}
|
||||
|
||||
PyObject* AreaPy::add(PyObject *args, PyObject *keywds)
|
||||
{
|
||||
PARAM_PY_DECLARE_INIT(PARAM_FARG,AREA_PARAMS_OPCODE)
|
||||
PyObject *pcObj;
|
||||
|
||||
//Strangely, PyArg_ParseTupleAndKeywords requires all arguments to be keyword based,
|
||||
//even non-optional ones? That doesn't make sense in python. Seems only in python 3
|
||||
//they added '$' to address that issue.
|
||||
static char *kwlist[] = {"shape",PARAM_FIELD_STRINGS(ARG,AREA_PARAMS_OPCODE), NULL};
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, keywds,
|
||||
"O|" PARAM_PY_KWDS(AREA_PARAMS_OPCODE),
|
||||
kwlist,&pcObj,PARAM_REF(PARAM_FARG,AREA_PARAMS_OPCODE)))
|
||||
return 0;
|
||||
|
||||
if (PyObject_TypeCheck(pcObj, &(Part::TopoShapePy::Type))) {
|
||||
getAreaPtr()->add(GET_TOPOSHAPE(pcObj),op);
|
||||
Py_INCREF(this);
|
||||
return this;
|
||||
} else if (PyObject_TypeCheck(pcObj, &(PyList_Type)) ||
|
||||
PyObject_TypeCheck(pcObj, &(PyTuple_Type))) {
|
||||
Py::Sequence shapeSeq(pcObj);
|
||||
for (Py::Sequence::iterator it = shapeSeq.begin(); it != shapeSeq.end(); ++it) {
|
||||
PyObject* item = (*it).ptr();
|
||||
if(!PyObject_TypeCheck(item, &(Part::TopoShapePy::Type))) {
|
||||
PyErr_SetString(PyExc_TypeError, "non-shape object in sequence");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
for (Py::Sequence::iterator it = shapeSeq.begin(); it != shapeSeq.end(); ++it){
|
||||
PyObject* item = (*it).ptr();
|
||||
getAreaPtr()->add(GET_TOPOSHAPE(item),
|
||||
PARAM_PY_FIELDS(PARAM_FARG,AREA_PARAMS_OPCODE));
|
||||
}
|
||||
Py_INCREF(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
PyErr_SetString(PyExc_TypeError, "shape must be 'TopoShape' or list of 'TopoShape'");
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyObject* AreaPy::makeOffset(PyObject *args, PyObject *keywds)
|
||||
{
|
||||
//Generate a keyword string defined in the ARG field of OFFSET parameter list
|
||||
static char *kwlist[] = {"index",PARAM_FIELD_STRINGS(ARG,AREA_PARAMS_OFFSET), NULL};
|
||||
short index = -1;
|
||||
|
||||
//Declare variables defined in the ARG field of the OFFSET parameter list with
|
||||
//initialization to defaults
|
||||
PARAM_PY_DECLARE_INIT(PARAM_FARG,AREA_PARAMS_OFFSET)
|
||||
|
||||
//Parse arguments to overwrite the defaults
|
||||
if (!PyArg_ParseTupleAndKeywords(args, keywds,
|
||||
"|h" PARAM_PY_KWDS(AREA_PARAMS_OFFSET), kwlist,
|
||||
&index,PARAM_REF(PARAM_FARG,AREA_PARAMS_OFFSET)))
|
||||
return 0;
|
||||
|
||||
//Expand the variable as function call arguments
|
||||
TopoDS_Shape resultShape = getAreaPtr()->makeOffset(index,
|
||||
PARAM_PY_FIELDS(PARAM_FARG,AREA_PARAMS_OFFSET));
|
||||
return Py::new_reference_to(Part::shape2pyshape(resultShape));
|
||||
}
|
||||
|
||||
PyObject* AreaPy::makePocket(PyObject *args, PyObject *keywds)
|
||||
{
|
||||
static char *kwlist[] = {"index",PARAM_FIELD_STRINGS(ARG,AREA_PARAMS_POCKET), NULL};
|
||||
short index = -1;
|
||||
|
||||
PARAM_PY_DECLARE_INIT(PARAM_FARG,AREA_PARAMS_POCKET)
|
||||
//Override pocket mode default
|
||||
mode = Area::PocketModeZigZagOffset;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, keywds,
|
||||
"|h" PARAM_PY_KWDS(AREA_PARAMS_POCKET), kwlist,
|
||||
&index,PARAM_REF(PARAM_FARG,AREA_PARAMS_POCKET)))
|
||||
return 0;
|
||||
|
||||
TopoDS_Shape resultShape = getAreaPtr()->makePocket(index,
|
||||
PARAM_PY_FIELDS(PARAM_FARG,AREA_PARAMS_POCKET));
|
||||
return Py::new_reference_to(Part::shape2pyshape(resultShape));
|
||||
}
|
||||
|
||||
PyObject* AreaPy::makeSections(PyObject *args, PyObject *keywds)
|
||||
{
|
||||
static char *kwlist[] = {PARAM_FIELD_STRINGS(ARG,AREA_PARAMS_SECTION_EXTRA),
|
||||
"heights", "plane", NULL};
|
||||
PyObject *heights = NULL;
|
||||
PyObject *plane = NULL;
|
||||
|
||||
PARAM_PY_DECLARE_INIT(PARAM_FARG,AREA_PARAMS_SECTION_EXTRA)
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, keywds,
|
||||
"|" PARAM_PY_KWDS(AREA_PARAMS_SECTION_EXTRA) "OO!", kwlist,
|
||||
PARAM_REF(PARAM_FARG,AREA_PARAMS_SECTION_EXTRA),
|
||||
&heights, &(Part::TopoShapePy::Type), &plane))
|
||||
return 0;
|
||||
|
||||
std::vector<double> h;
|
||||
if(heights) {
|
||||
if (PyObject_TypeCheck(heights, &(PyFloat_Type)))
|
||||
h.push_back(PyFloat_AsDouble(heights));
|
||||
else if (PyObject_TypeCheck(heights, &(PyList_Type)) ||
|
||||
PyObject_TypeCheck(heights, &(PyTuple_Type))) {
|
||||
Py::Sequence shapeSeq(heights);
|
||||
h.reserve(shapeSeq.size());
|
||||
for (Py::Sequence::iterator it = shapeSeq.begin(); it != shapeSeq.end(); ++it) {
|
||||
PyObject* item = (*it).ptr();
|
||||
if(!PyObject_TypeCheck(item, &(PyFloat_Type))) {
|
||||
PyErr_SetString(PyExc_TypeError, "heights must only contain float type");
|
||||
return 0;
|
||||
}
|
||||
h.push_back(PyFloat_AsDouble(item));
|
||||
}
|
||||
}else{
|
||||
PyErr_SetString(PyExc_TypeError, "heights must be of type float or list/tuple of float");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<Area> > sections = getAreaPtr()->makeSections(
|
||||
PARAM_PY_FIELDS(PARAM_FARG,AREA_PARAMS_SECTION_EXTRA),
|
||||
h,plane?GET_TOPOSHAPE(plane):TopoDS_Shape());
|
||||
|
||||
Py::List ret;
|
||||
for(auto &area : sections)
|
||||
ret.append(Py::asObject(new AreaPy(new Area(*area,false))));
|
||||
return Py::new_reference_to(ret);
|
||||
}
|
||||
|
||||
PyObject* AreaPy::setDefaultParams(PyObject *, PyObject *)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyObject* AreaPy::setParams(PyObject *args, PyObject *keywds)
|
||||
{
|
||||
static char *kwlist[] = {PARAM_FIELD_STRINGS(NAME,AREA_PARAMS_CONF),NULL};
|
||||
|
||||
//Declare variables defined in the NAME field of the CONF parameter list
|
||||
PARAM_PY_DECLARE(PARAM_FNAME,AREA_PARAMS_CONF);
|
||||
|
||||
AreaParams params = getAreaPtr()->getParams();
|
||||
|
||||
//populate the CONF variables with params
|
||||
PARAM_FOREACH(AREA_SET,AREA_PARAMS_CONF)
|
||||
|
||||
//Parse arguments to overwrite CONF variables
|
||||
if (!PyArg_ParseTupleAndKeywords(args, keywds,
|
||||
"|" PARAM_PY_KWDS(AREA_PARAMS_CONF), kwlist,
|
||||
PARAM_REF(PARAM_FNAME,AREA_PARAMS_CONF)))
|
||||
return 0;
|
||||
|
||||
//populate 'params' with the CONF variables
|
||||
PARAM_FOREACH(AREA_GET,AREA_PARAMS_CONF)
|
||||
|
||||
getAreaPtr()->setParams(params);
|
||||
Py_INCREF(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
PyObject* AreaPy::getParams(PyObject *args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, ""))
|
||||
return 0;
|
||||
|
||||
const AreaParams ¶ms =getAreaPtr()->getParams();
|
||||
|
||||
PyObject *dict = PyDict_New();
|
||||
PARAM_PY_DICT_SET_VALUE(dict,NAME,AREA_SRC,AREA_PARAMS_CONF)
|
||||
return dict;
|
||||
}
|
||||
|
||||
PyObject* AreaPy::getDefaultParams(PyObject *)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyObject* AreaPy::abort(PyObject *, PyObject *) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyObject* AreaPy::getParamsDesc(PyObject *args, PyObject *keywds)
|
||||
{
|
||||
PyObject *pcObj = Py_True;
|
||||
static char *kwlist[] = {"as_string", NULL};
|
||||
if (!PyArg_ParseTupleAndKeywords(args, keywds,"|O",kwlist,&pcObj))
|
||||
return 0;
|
||||
|
||||
if(PyObject_IsTrue(pcObj))
|
||||
return PyString_FromString(PARAM_PY_DOC(NAME,AREA_PARAMS_CONF));
|
||||
|
||||
PyObject *dict = PyDict_New();
|
||||
PARAM_PY_DICT_SET_DOC(dict,NAME,AREA_PARAMS_CONF)
|
||||
return dict;
|
||||
}
|
||||
|
||||
Py::List AreaPy::getSections(void) const {
|
||||
Py::List ret;
|
||||
Area *area = getAreaPtr();
|
||||
for(size_t i=0,count=area->getSectionCount(); i<count;++i)
|
||||
ret.append(Part::shape2pyshape(getAreaPtr()->getShape(i)));
|
||||
return ret;
|
||||
}
|
||||
|
||||
Py::List AreaPy::getShapes(void) const {
|
||||
Py::List ret;
|
||||
Area *area = getAreaPtr();
|
||||
const std::list<Area::Shape> &shapes = area->getChildren();
|
||||
for(auto &s : shapes)
|
||||
ret.append(Py::TupleN(Part::shape2pyshape(s.shape),Py::Int(s.op)));
|
||||
return ret;
|
||||
}
|
||||
|
||||
Py::Object AreaPy::getWorkplane(void) const {
|
||||
return Part::shape2pyshape(getAreaPtr()->getPlane());
|
||||
}
|
||||
|
||||
|
||||
// custom attributes get/set
|
||||
|
||||
PyObject *AreaPy::getCustomAttributes(const char* /*attr*/) const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AreaPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -22,6 +22,7 @@ link_directories(${OCC_LIBRARY_DIR})
|
||||
set(Path_LIBS
|
||||
# Robot
|
||||
Part
|
||||
area-native
|
||||
FreeCADApp
|
||||
)
|
||||
|
||||
@@ -30,6 +31,8 @@ generate_from_xml(PathPy)
|
||||
generate_from_xml(ToolPy)
|
||||
generate_from_xml(TooltablePy)
|
||||
generate_from_xml(FeaturePathCompoundPy)
|
||||
generate_from_xml(AreaPy)
|
||||
generate_from_xml(FeatureAreaPy)
|
||||
|
||||
SET(Python_SRCS
|
||||
CommandPy.xml
|
||||
@@ -41,6 +44,10 @@ SET(Python_SRCS
|
||||
TooltablePyImp.cpp
|
||||
FeaturePathCompoundPy.xml
|
||||
FeaturePathCompoundPyImp.cpp
|
||||
AreaPy.xml
|
||||
AreaPyImp.cpp
|
||||
FeatureAreaPy.xml
|
||||
FeatureAreaPyImp.cpp
|
||||
)
|
||||
|
||||
SET(Mod_SRCS
|
||||
@@ -67,6 +74,12 @@ SET(Path_SRCS
|
||||
FeaturePathCompound.h
|
||||
FeaturePathShape.cpp
|
||||
FeaturePathShape.h
|
||||
Area.cpp
|
||||
Area.h
|
||||
AreaParams.h
|
||||
ParamsHelper.h
|
||||
FeatureArea.cpp
|
||||
FeatureArea.h
|
||||
${Mod_SRCS}
|
||||
${Python_SRCS}
|
||||
)
|
||||
|
||||
247
src/Mod/Path/App/FeatureArea.cpp
Normal file
247
src/Mod/Path/App/FeatureArea.cpp
Normal file
@@ -0,0 +1,247 @@
|
||||
/****************************************************************************
|
||||
* Copyright (c) 2017 Zheng, Lei (realthunder) <realthunder.dev@gmail.com>*
|
||||
* *
|
||||
* 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 *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#ifndef _PreComp_
|
||||
#endif
|
||||
|
||||
#include <BRep_Builder.hxx>
|
||||
#include <TopoDS_Compound.hxx>
|
||||
|
||||
#include "FeatureArea.h"
|
||||
#include "FeatureAreaPy.h"
|
||||
#include <App/DocumentObjectPy.h>
|
||||
#include <Base/Placement.h>
|
||||
#include <Mod/Part/App/PartFeature.h>
|
||||
|
||||
using namespace Path;
|
||||
|
||||
PROPERTY_SOURCE(Path::FeatureArea, Part::Feature)
|
||||
|
||||
PARAM_ENUM_STRING_DECLARE(static const char *Enums,AREA_PARAMS_ALL)
|
||||
|
||||
FeatureArea::FeatureArea()
|
||||
:myBuild(false)
|
||||
{
|
||||
ADD_PROPERTY(Sources,(0));
|
||||
ADD_PROPERTY(WorkPlane,(TopoDS_Shape()));
|
||||
|
||||
PARAM_PROP_ADD("Area",AREA_PARAMS_OPCODE);
|
||||
PARAM_PROP_ADD("Area",AREA_PARAMS_BASE);
|
||||
PARAM_PROP_ADD("Offset",AREA_PARAMS_OFFSET);
|
||||
PARAM_PROP_ADD("Offset", AREA_PARAMS_OFFSET_CONF);
|
||||
PARAM_PROP_ADD("Pocket",AREA_PARAMS_POCKET);
|
||||
PARAM_PROP_ADD("Pocket",AREA_PARAMS_POCKET_CONF);
|
||||
PARAM_PROP_ADD("Section",AREA_PARAMS_SECTION);
|
||||
PARAM_PROP_ADD("libarea",AREA_PARAMS_CAREA);
|
||||
|
||||
PARAM_PROP_SET_ENUM(Enums,AREA_PARAMS_ALL);
|
||||
PocketMode.setValue((long)0);
|
||||
}
|
||||
|
||||
FeatureArea::~FeatureArea()
|
||||
{
|
||||
}
|
||||
|
||||
Area &FeatureArea::getArea() {
|
||||
if(!myBuild)
|
||||
execute();
|
||||
return myArea;
|
||||
}
|
||||
|
||||
App::DocumentObjectExecReturn *FeatureArea::execute(void)
|
||||
{
|
||||
std::vector<App::DocumentObject*> links = Sources.getValues();
|
||||
if (links.empty())
|
||||
return new App::DocumentObjectExecReturn("No shapes linked");
|
||||
|
||||
for (std::vector<App::DocumentObject*>::iterator it = links.begin(); it != links.end(); ++it) {
|
||||
if (!(*it && (*it)->isDerivedFrom(Part::Feature::getClassTypeId())))
|
||||
return new App::DocumentObjectExecReturn("Linked object is not a Part object (has no Shape).");
|
||||
TopoDS_Shape shape = static_cast<Part::Feature*>(*it)->Shape.getShape().getShape();
|
||||
if (shape.IsNull())
|
||||
return new App::DocumentObjectExecReturn("Linked shape object is empty");
|
||||
}
|
||||
|
||||
TIME_INIT(t);
|
||||
|
||||
myBuild = true;
|
||||
AreaParams params;
|
||||
|
||||
#define AREA_PROP_GET(_param) \
|
||||
params.PARAM_FNAME(_param) = PARAM_FNAME(_param).getValue();
|
||||
PARAM_FOREACH(AREA_PROP_GET,AREA_PARAMS_CONF)
|
||||
|
||||
myArea.clean(true);
|
||||
myArea.setParams(params);
|
||||
|
||||
TopoDS_Shape workPlane = WorkPlane.getShape().getShape();
|
||||
myArea.setPlane(workPlane);
|
||||
|
||||
for (std::vector<App::DocumentObject*>::iterator it = links.begin(); it != links.end(); ++it) {
|
||||
myArea.add(static_cast<Part::Feature*>(*it)->Shape.getShape().getShape(),
|
||||
PARAM_PROP_ARGS(AREA_PARAMS_OPCODE));
|
||||
}
|
||||
|
||||
myShapes.clear();
|
||||
if(myArea.getSectionCount()==0)
|
||||
myShapes.push_back(myArea.getShape(-1));
|
||||
else {
|
||||
myShapes.reserve(myArea.getSectionCount());
|
||||
for(int i=0;i<(int)myArea.getSectionCount();++i)
|
||||
myShapes.push_back(myArea.getShape(i));
|
||||
}
|
||||
|
||||
if(myShapes.empty())
|
||||
Shape.setValue(TopoDS_Shape());
|
||||
else if(myShapes.size()==1)
|
||||
Shape.setValue(myShapes.front());
|
||||
else{
|
||||
BRep_Builder builder;
|
||||
TopoDS_Compound compound;
|
||||
builder.MakeCompound(compound);
|
||||
for(auto &shape : myShapes)
|
||||
builder.Add(compound,shape);
|
||||
Shape.setValue(compound);
|
||||
}
|
||||
|
||||
TIME_PRINT(t,"feature execute");
|
||||
return Part::Feature::execute();
|
||||
}
|
||||
|
||||
const std::vector<TopoDS_Shape> &FeatureArea::getShapes() {
|
||||
getArea();
|
||||
return myShapes;
|
||||
}
|
||||
|
||||
short FeatureArea::mustExecute(void) const
|
||||
{
|
||||
if (Sources.isTouched())
|
||||
return 1;
|
||||
if (WorkPlane.isTouched())
|
||||
return 1;
|
||||
|
||||
PARAM_PROP_TOUCHED(AREA_PARAMS_ALL)
|
||||
|
||||
return Part::Feature::mustExecute();
|
||||
}
|
||||
|
||||
PyObject *FeatureArea::getPyObject()
|
||||
{
|
||||
if (PythonObject.is(Py::_None())){
|
||||
// ref counter is set to 1
|
||||
PythonObject = Py::Object(new FeatureAreaPy(this),true);
|
||||
}
|
||||
return Py::new_reference_to(PythonObject);
|
||||
}
|
||||
|
||||
|
||||
// FeatureAreaView -------------------------------------------------------------
|
||||
//
|
||||
PROPERTY_SOURCE(Path::FeatureAreaView, Part::Feature)
|
||||
|
||||
FeatureAreaView::FeatureAreaView()
|
||||
{
|
||||
ADD_PROPERTY(Source,(0));
|
||||
ADD_PROPERTY_TYPE(SectionIndex,(0),"Section",App::Prop_None,"The start index of the section to show, negative value for reverse index from bottom");
|
||||
ADD_PROPERTY_TYPE(SectionCount,(1),"Section",App::Prop_None,"Number of sections to show, 0 to show all section starting from SectionIndex");
|
||||
}
|
||||
|
||||
std::list<TopoDS_Shape> FeatureAreaView::getShapes() {
|
||||
std::list<TopoDS_Shape> shapes;
|
||||
App::DocumentObject* pObj = Source.getValue();
|
||||
if (!pObj) return shapes;
|
||||
if(!pObj->isDerivedFrom(FeatureArea::getClassTypeId()))
|
||||
return shapes;
|
||||
|
||||
auto all_shapes = static_cast<FeatureArea*>(pObj)->getShapes();
|
||||
|
||||
if(all_shapes.empty())
|
||||
return shapes;
|
||||
|
||||
int index=SectionIndex.getValue(),count=SectionCount.getValue();
|
||||
if(index<0) {
|
||||
index += ((int)all_shapes.size());
|
||||
if(index<0) return shapes;
|
||||
if(count<=0 || index+1-count<0) {
|
||||
count = index+1;
|
||||
index = 0;
|
||||
}else
|
||||
index -= count-1;
|
||||
}else if(index >= (int)all_shapes.size())
|
||||
return shapes;
|
||||
|
||||
if(count<=0) count = all_shapes.size();
|
||||
count += index;
|
||||
if(count>(int)all_shapes.size())
|
||||
count = all_shapes.size();
|
||||
for(int i=index;i<count;++i)
|
||||
shapes.push_back(all_shapes[i]);
|
||||
return std::move(shapes);
|
||||
}
|
||||
|
||||
App::DocumentObjectExecReturn *FeatureAreaView::execute(void)
|
||||
{
|
||||
App::DocumentObject* pObj = Source.getValue();
|
||||
if (!pObj)
|
||||
return new App::DocumentObjectExecReturn("No shape linked");
|
||||
|
||||
if(!pObj->isDerivedFrom(FeatureArea::getClassTypeId()))
|
||||
return new App::DocumentObjectExecReturn("Linked object is not a FeatureArea");
|
||||
|
||||
std::list<TopoDS_Shape> shapes = getShapes();
|
||||
if(shapes.empty())
|
||||
Shape.setValue(TopoDS_Shape());
|
||||
else if(shapes.size()==1) {
|
||||
Shape.setValue(shapes.front());
|
||||
}else{
|
||||
BRep_Builder builder;
|
||||
TopoDS_Compound compound;
|
||||
builder.MakeCompound(compound);
|
||||
for(auto &shape : shapes)
|
||||
builder.Add(compound,shape);
|
||||
Shape.setValue(compound);
|
||||
}
|
||||
|
||||
return Part::Feature::execute();
|
||||
}
|
||||
|
||||
// Python feature ---------------------------------------------------------
|
||||
|
||||
namespace App {
|
||||
/// @cond DOXERR
|
||||
PROPERTY_SOURCE_TEMPLATE(Path::FeatureAreaPython, Path::FeatureArea)
|
||||
PROPERTY_SOURCE_TEMPLATE(Path::FeatureAreaViewPython, Path::FeatureAreaView)
|
||||
|
||||
template<> const char* Path::FeatureAreaPython::getViewProviderName(void) const {
|
||||
return "PathGui::ViewProviderAreaPython";
|
||||
}
|
||||
template<> const char* Path::FeatureAreaViewPython::getViewProviderName(void) const {
|
||||
return "PathGui::ViewProviderAreaViewPython";
|
||||
}
|
||||
/// @endcond
|
||||
|
||||
// explicit template instantiation
|
||||
template class PathExport FeaturePythonT<Path::FeatureArea>;
|
||||
}
|
||||
|
||||
96
src/Mod/Path/App/FeatureArea.h
Normal file
96
src/Mod/Path/App/FeatureArea.h
Normal file
@@ -0,0 +1,96 @@
|
||||
/****************************************************************************
|
||||
* Copyright (c) 2017 Zheng, Lei (realthunder) <realthunder.dev@gmail.com>*
|
||||
* *
|
||||
* 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_FeatureArea_H
|
||||
#define PATH_FeatureArea_H
|
||||
|
||||
#include <App/DocumentObject.h>
|
||||
#include <App/GeoFeature.h>
|
||||
#include <App/PropertyFile.h>
|
||||
#include <App/PropertyGeo.h>
|
||||
#include <App/FeaturePython.h>
|
||||
#include "Mod/Part/App/PartFeature.h"
|
||||
|
||||
#include "Area.h"
|
||||
|
||||
namespace Path
|
||||
{
|
||||
|
||||
class PathExport FeatureArea : public Part::Feature
|
||||
{
|
||||
PROPERTY_HEADER(Path::FeatureArea);
|
||||
|
||||
public:
|
||||
/// Constructor
|
||||
FeatureArea(void);
|
||||
virtual ~FeatureArea();
|
||||
|
||||
Area &getArea();
|
||||
const std::vector<TopoDS_Shape> &getShapes();
|
||||
|
||||
/// returns the type name of the ViewProvider
|
||||
virtual const char* getViewProviderName(void) const {
|
||||
return "PathGui::ViewProviderArea";
|
||||
}
|
||||
virtual App::DocumentObjectExecReturn *execute(void);
|
||||
virtual short mustExecute(void) const;
|
||||
virtual PyObject *getPyObject(void);
|
||||
|
||||
App::PropertyLinkList Sources;
|
||||
Part::PropertyPartShape WorkPlane;
|
||||
|
||||
PARAM_PROP_DECLARE(AREA_PARAMS_ALL)
|
||||
|
||||
private:
|
||||
bool myBuild;
|
||||
Area myArea;
|
||||
std::vector<TopoDS_Shape> myShapes;
|
||||
};
|
||||
|
||||
typedef App::FeaturePythonT<FeatureArea> FeatureAreaPython;
|
||||
|
||||
class PathExport FeatureAreaView : public Part::Feature
|
||||
{
|
||||
PROPERTY_HEADER(Path::FeatureAreaView);
|
||||
|
||||
public:
|
||||
/// Constructor
|
||||
FeatureAreaView(void);
|
||||
|
||||
std::list<TopoDS_Shape> getShapes();
|
||||
|
||||
virtual const char* getViewProviderName(void) const {
|
||||
return "PathGui::ViewProviderAreaView";
|
||||
}
|
||||
virtual App::DocumentObjectExecReturn *execute(void);
|
||||
|
||||
App::PropertyLink Source;
|
||||
App::PropertyInteger SectionIndex;
|
||||
App::PropertyInteger SectionCount;
|
||||
};
|
||||
|
||||
typedef App::FeaturePythonT<FeatureAreaView> FeatureAreaViewPython;
|
||||
|
||||
} //namespace Path
|
||||
|
||||
|
||||
#endif // PATH_FeaturePath_H
|
||||
30
src/Mod/Path/App/FeatureAreaPy.xml
Normal file
30
src/Mod/Path/App/FeatureAreaPy.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
|
||||
<PythonExport
|
||||
Father="DocumentObjectPy"
|
||||
Name="FeatureAreaPy"
|
||||
Twin="FeatureArea"
|
||||
TwinPointer="FeatureArea"
|
||||
Include="Mod/Path/App/FeatureArea.h"
|
||||
Namespace="Path"
|
||||
FatherInclude="App/DocumentObjectPy.h"
|
||||
FatherNamespace="App">
|
||||
<Documentation>
|
||||
<Author Licence="LGPL" Name="Zheng, Lei" EMail="realthunder.dev@gmail.com" />
|
||||
<UserDocu>This class handles Path Area features</UserDocu>
|
||||
</Documentation>
|
||||
<Methode Name="getArea">
|
||||
<Documentation>
|
||||
<UserDocu>Return a copy of the encapsulated Python Area object.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="setParams" Keyword="true">
|
||||
<Documentation>
|
||||
<UserDocu>setParams(key=value...): Convenient function to configure this feature.\n
|
||||
Same usage as Path.Area.setParams(). This function stores the parameters in the properties.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<CustomAttributes />
|
||||
</PythonExport>
|
||||
</GenerateModel>
|
||||
|
||||
93
src/Mod/Path/App/FeatureAreaPyImp.cpp
Normal file
93
src/Mod/Path/App/FeatureAreaPyImp.cpp
Normal file
@@ -0,0 +1,93 @@
|
||||
/****************************************************************************
|
||||
* Copyright (c) 2017 Zheng, Lei (realthunder) <realthunder.dev@gmail.com>*
|
||||
* *
|
||||
* 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 *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#include <CXX/Objects.hxx>
|
||||
#include "FeatureArea.h"
|
||||
|
||||
// inclusion of the generated files (generated out of FeatureAreaPy.xml)
|
||||
#include "FeatureAreaPy.h"
|
||||
#include "FeatureAreaPy.cpp"
|
||||
|
||||
#include "AreaPy.h"
|
||||
|
||||
using namespace Path;
|
||||
|
||||
|
||||
// returns a string which represent the object e.g. when printed in python
|
||||
std::string FeatureAreaPy::representation(void) const
|
||||
{
|
||||
return std::string("<Path::FeatureArea>");
|
||||
}
|
||||
|
||||
|
||||
PyObject* FeatureAreaPy::getArea(PyObject *args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, ""))
|
||||
return NULL;
|
||||
|
||||
return new AreaPy(new Area(getFeatureAreaPtr()->getArea()));
|
||||
}
|
||||
|
||||
PyObject* FeatureAreaPy::setParams(PyObject *args, PyObject *keywds)
|
||||
{
|
||||
static char *kwlist[] = {PARAM_FIELD_STRINGS(NAME,AREA_PARAMS_CONF),NULL};
|
||||
|
||||
//Declare variables defined in the NAME field of the CONF parameter list
|
||||
PARAM_PY_DECLARE(PARAM_FNAME,AREA_PARAMS_CONF);
|
||||
|
||||
FeatureArea *feature = getFeatureAreaPtr();
|
||||
|
||||
#define AREA_SET(_param) \
|
||||
PARAM_FNAME(_param) = \
|
||||
PARAM_TYPED(PARAM_PY_CAST_,_param)(feature->PARAM_FNAME(_param).getValue());
|
||||
//populate the CONF variables with values in properties
|
||||
PARAM_FOREACH(AREA_SET,AREA_PARAMS_CONF)
|
||||
|
||||
//Parse arguments to overwrite CONF variables
|
||||
if (!PyArg_ParseTupleAndKeywords(args, keywds,
|
||||
"|" PARAM_PY_KWDS(AREA_PARAMS_CONF), kwlist,
|
||||
PARAM_REF(PARAM_FNAME,AREA_PARAMS_CONF)))
|
||||
Py_Error(Base::BaseExceptionFreeCADError,
|
||||
"Wrong parameters, call getParamsDesc() to get supported params");
|
||||
|
||||
#define AREA_GET(_param) \
|
||||
feature->PARAM_FNAME(_param).setValue(\
|
||||
PARAM_TYPED(PARAM_CAST_PY_,_param)(PARAM_FNAME(_param)));
|
||||
//populate properties with the CONF variables
|
||||
PARAM_FOREACH(AREA_GET,AREA_PARAMS_CONF)
|
||||
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
PyObject *FeatureAreaPy::getCustomAttributes(const char* /*attr*/) const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int FeatureAreaPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,9 @@
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017 Zheng, Lei <realthunder.dev@gmail.com>
|
||||
*/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
@@ -32,101 +34,66 @@
|
||||
#include <App/DocumentObjectPy.h>
|
||||
#include <Base/Placement.h>
|
||||
#include <Mod/Part/App/TopoShape.h>
|
||||
#include <Mod/Part/App/PartFeature.h>
|
||||
|
||||
#include <TopoDS.hxx>
|
||||
#include <TopoDS_Shape.hxx>
|
||||
#include <TopoDS_Edge.hxx>
|
||||
#include <TopoDS_Vertex.hxx>
|
||||
#include <TopoDS_Iterator.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <gp_Lin.hxx>
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <BRepAdaptor_CompCurve.hxx>
|
||||
#include <BRepAdaptor_HCompCurve.hxx>
|
||||
#include <Approx_Curve3d.hxx>
|
||||
#include <BRepAdaptor_HCurve.hxx>
|
||||
#include <Standard_Failure.hxx>
|
||||
#include <Standard_Version.hxx>
|
||||
#include <BRepBuilderAPI_MakeWire.hxx>
|
||||
|
||||
#include "FeatureArea.h"
|
||||
|
||||
using namespace Path;
|
||||
|
||||
PROPERTY_SOURCE(Path::FeatureShape, Path::Feature)
|
||||
|
||||
PARAM_ENUM_STRING_DECLARE(static const char *Enums,AREA_PARAMS_PATH)
|
||||
|
||||
FeatureShape::FeatureShape()
|
||||
{
|
||||
ADD_PROPERTY_TYPE(Shape,(TopoDS_Shape()),"Path",App::Prop_None,"The shape data of this feature");
|
||||
ADD_PROPERTY(Sources,(0));
|
||||
ADD_PROPERTY_TYPE(StartPoint,(Base::Vector3d()),"Path",App::Prop_None,"Path start position");
|
||||
PARAM_PROP_ADD("Path",AREA_PARAMS_PATH_CONF);
|
||||
PARAM_PROP_SET_ENUM(Enums,AREA_PARAMS_PATH_CONF);
|
||||
}
|
||||
|
||||
FeatureShape::~FeatureShape()
|
||||
{
|
||||
}
|
||||
|
||||
short FeatureShape::mustExecute(void) const
|
||||
{
|
||||
return Path::Feature::mustExecute();
|
||||
}
|
||||
|
||||
App::DocumentObjectExecReturn *FeatureShape::execute(void)
|
||||
{
|
||||
TopoDS_Shape shape = Shape.getValue();
|
||||
if (!shape.IsNull()) {
|
||||
if (shape.ShapeType() == TopAbs_WIRE) {
|
||||
Path::Toolpath result;
|
||||
bool first = true;
|
||||
Base::Placement last;
|
||||
|
||||
TopExp_Explorer ExpEdges (shape,TopAbs_EDGE);
|
||||
while (ExpEdges.More()) {
|
||||
const TopoDS_Edge& edge = TopoDS::Edge(ExpEdges.Current());
|
||||
TopExp_Explorer ExpVerts(edge,TopAbs_VERTEX);
|
||||
bool vfirst = true;
|
||||
while (ExpVerts.More()) {
|
||||
const TopoDS_Vertex& vert = TopoDS::Vertex(ExpVerts.Current());
|
||||
gp_Pnt pnt = BRep_Tool::Pnt(vert);
|
||||
Base::Placement tpl;
|
||||
tpl.setPosition(Base::Vector3d(pnt.X(),pnt.Y(),pnt.Z()));
|
||||
if (first) {
|
||||
// add first point as a G0 move
|
||||
Path::Command cmd;
|
||||
std::ostringstream ctxt;
|
||||
ctxt << "G0 X" << tpl.getPosition().x << " Y" << tpl.getPosition().y << " Z" << tpl.getPosition().z;
|
||||
cmd.setFromGCode(ctxt.str());
|
||||
result.addCommand(cmd);
|
||||
first = false;
|
||||
vfirst = false;
|
||||
} else {
|
||||
if (vfirst)
|
||||
vfirst = false;
|
||||
else {
|
||||
Path::Command cmd;
|
||||
cmd.setFromPlacement(tpl);
|
||||
|
||||
// write arc data if needed
|
||||
BRepAdaptor_Curve adapt(edge);
|
||||
if (adapt.GetType() == GeomAbs_Circle) {
|
||||
gp_Circ circ = adapt.Circle();
|
||||
gp_Pnt c = circ.Location();
|
||||
bool clockwise = false;
|
||||
gp_Dir n = circ.Axis().Direction();
|
||||
if (n.Z() < 0)
|
||||
clockwise = true;
|
||||
Base::Vector3d center = Base::Vector3d(c.X(),c.Y(),c.Z());
|
||||
// center coords must be relative to last point
|
||||
center -= last.getPosition();
|
||||
cmd.setCenter(center,clockwise);
|
||||
}
|
||||
result.addCommand(cmd);
|
||||
}
|
||||
}
|
||||
ExpVerts.Next();
|
||||
last = tpl;
|
||||
}
|
||||
ExpEdges.Next();
|
||||
}
|
||||
|
||||
Path.setValue(result);
|
||||
}
|
||||
Toolpath path;
|
||||
std::vector<App::DocumentObject*> links = Sources.getValues();
|
||||
if (links.empty()) {
|
||||
Path.setValue(path);
|
||||
return new App::DocumentObjectExecReturn("No shapes linked");
|
||||
}
|
||||
|
||||
const Base::Vector3d &v = StartPoint.getValue();
|
||||
gp_Pnt pstart(v.x,v.y,v.z);
|
||||
|
||||
std::list<TopoDS_Shape> shapes;
|
||||
for (std::vector<App::DocumentObject*>::iterator it = links.begin(); it != links.end(); ++it) {
|
||||
if (!(*it && (*it)->isDerivedFrom(Part::Feature::getClassTypeId())))
|
||||
continue;
|
||||
const TopoDS_Shape &shape = static_cast<Part::Feature*>(*it)->Shape.getShape().getShape();
|
||||
if (shape.IsNull())
|
||||
continue;
|
||||
shapes.push_back(shape);
|
||||
}
|
||||
|
||||
AreaParams params;
|
||||
#define AREA_PROP_GET(_param) \
|
||||
params.PARAM_FNAME(_param) = PARAM_FNAME(_param).getValue();
|
||||
PARAM_FOREACH(AREA_PROP_GET,AREA_PARAMS_PATH_EXTRA)
|
||||
|
||||
Area::toPath(path,shapes,¶ms,&pstart,NULL,PARAM_PROP_ARGS(AREA_PARAMS_PATH));
|
||||
|
||||
Path.setValue(path);
|
||||
return App::DocumentObject::StdReturn;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
/*
|
||||
* Copyright (c) 2017 Zheng, Lei <realthunder.dev@gmail.com>
|
||||
*/
|
||||
|
||||
|
||||
#ifndef PATH_FeaturePathShape_H
|
||||
@@ -26,14 +29,13 @@
|
||||
|
||||
#include <App/DocumentObject.h>
|
||||
#include <App/GeoFeature.h>
|
||||
#include <App/PropertyFile.h>
|
||||
#include <App/PropertyGeo.h>
|
||||
#include <App/FeaturePython.h>
|
||||
#include "Mod/Part/App/PropertyTopoShape.h"
|
||||
|
||||
#include "Path.h"
|
||||
#include "PropertyPath.h"
|
||||
#include "FeaturePath.h"
|
||||
#include "Area.h"
|
||||
|
||||
namespace Path
|
||||
{
|
||||
@@ -47,12 +49,14 @@ public:
|
||||
FeatureShape(void);
|
||||
virtual ~FeatureShape();
|
||||
|
||||
Part::PropertyPartShape Shape;
|
||||
// Part::PropertyPartShape Shape;
|
||||
App::PropertyLinkList Sources;
|
||||
App::PropertyVector StartPoint;
|
||||
PARAM_PROP_DECLARE(AREA_PARAMS_PATH_CONF)
|
||||
|
||||
//@{
|
||||
/// recalculate the feature
|
||||
virtual App::DocumentObjectExecReturn *execute(void);
|
||||
virtual short mustExecute(void) const;
|
||||
//@}
|
||||
|
||||
/// returns the type name of the ViewProvider
|
||||
|
||||
1052
src/Mod/Path/App/ParamsHelper.h
Normal file
1052
src/Mod/Path/App/ParamsHelper.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -23,10 +23,10 @@
|
||||
|
||||
#ifndef PATH_Path_H
|
||||
#define PATH_Path_H
|
||||
|
||||
#include "Command.h"
|
||||
|
||||
#include "Command.h"
|
||||
//#include "Mod/Robot/App/kdl_cp/path_composite.hpp"
|
||||
//#include "Mod/Robot/App/kdl_cp/frames_io.hpp"
|
||||
//#include "Mod/Robot/App/kdl_cp/frames_io.hpp"
|
||||
#include <Base/Persistence.h>
|
||||
#include <Base/Vector3D.h>
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "DlgSettingsPathColor.h"
|
||||
#include "ViewProviderPathCompound.h"
|
||||
#include "ViewProviderPathShape.h"
|
||||
#include "ViewProviderArea.h"
|
||||
|
||||
// use a different name to CreateCommand()
|
||||
void CreatePathCommands(void);
|
||||
@@ -77,6 +78,10 @@ PyMOD_INIT_FUNC(PathGui)
|
||||
PathGui::ViewProviderPathCompoundPython ::init();
|
||||
PathGui::ViewProviderPathShape ::init();
|
||||
PathGui::ViewProviderPathPython ::init();
|
||||
PathGui::ViewProviderArea ::init();
|
||||
PathGui::ViewProviderAreaPython ::init();
|
||||
PathGui::ViewProviderAreaView ::init();
|
||||
PathGui::ViewProviderAreaViewPython ::init();
|
||||
|
||||
// add resources and reloads the translators
|
||||
loadPathResource();
|
||||
|
||||
@@ -81,6 +81,8 @@ SET(PathGui_SRCS_ViewProvider
|
||||
ViewProviderPathCompound.h
|
||||
ViewProviderPathShape.cpp
|
||||
ViewProviderPathShape.h
|
||||
ViewProviderArea.cpp
|
||||
ViewProviderArea.h
|
||||
)
|
||||
|
||||
SOURCE_GROUP("ViewProvider" FILES ${PathGui_SRCS_ViewProvider})
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
#ifndef _PreComp_
|
||||
#endif
|
||||
|
||||
#include <TopExp_Explorer.hxx>
|
||||
|
||||
#include <Base/Console.h>
|
||||
#include <App/Application.h>
|
||||
#include <Gui/Application.h>
|
||||
@@ -39,6 +41,183 @@
|
||||
#include <Mod/Path/App/FeaturePathCompound.h>
|
||||
#include <Mod/Path/App/FeaturePathShape.h>
|
||||
#include <Mod/Part/App/PartFeature.h>
|
||||
#include <Mod/Path/App/FeatureArea.h>
|
||||
|
||||
|
||||
// Path Area #####################################################################################################
|
||||
|
||||
|
||||
DEF_STD_CMD_A(CmdPathArea)
|
||||
|
||||
CmdPathArea::CmdPathArea()
|
||||
:Command("Path_Area")
|
||||
{
|
||||
sAppModule = "Path";
|
||||
sGroup = QT_TR_NOOP("Path");
|
||||
sMenuText = QT_TR_NOOP("Area");
|
||||
sToolTipText = QT_TR_NOOP("Creates a feature area from selected objects");
|
||||
sWhatsThis = "Path_Area";
|
||||
sStatusTip = sToolTipText;
|
||||
sPixmap = "Path-Area";
|
||||
sAccel = "P,A";
|
||||
|
||||
}
|
||||
|
||||
void CmdPathArea::activated(int iMsg)
|
||||
{
|
||||
Q_UNUSED(iMsg);
|
||||
std::list<std::string> cmds;
|
||||
std::ostringstream sources;
|
||||
std::string areaName;
|
||||
bool addView = true;
|
||||
for(const Gui::SelectionObject &selObj :
|
||||
getSelection().getSelectionEx(NULL, Part::Feature::getClassTypeId()))
|
||||
{
|
||||
const Part::Feature *pcObj = static_cast<const Part::Feature*>(selObj.getObject());
|
||||
const std::vector<std::string> &subnames = selObj.getSubNames();
|
||||
if(addView && areaName.size()) addView = false;
|
||||
|
||||
if(subnames.empty()) {
|
||||
if(addView && pcObj->getTypeId().isDerivedFrom(Path::FeatureArea::getClassTypeId()))
|
||||
areaName = pcObj->getNameInDocument();
|
||||
sources << "FreeCAD.activeDocument()." << pcObj->getNameInDocument() << ",";
|
||||
continue;
|
||||
}
|
||||
for(const std::string &name : subnames) {
|
||||
if(name.compare(0,4,"Face") && name.compare(0,4,"Edge")) {
|
||||
Base::Console().Error("Selected shape is not 2D\n");
|
||||
return;
|
||||
}
|
||||
|
||||
std::ostringstream subname;
|
||||
subname << pcObj->getNameInDocument() << '_' << name;
|
||||
std::string sub_fname = getUniqueObjectName(subname.str().c_str());
|
||||
|
||||
std::ostringstream cmd;
|
||||
cmd << "FreeCAD.activeDocument().addObject('Part::Feature','" << sub_fname <<
|
||||
"').Shape = PathCommands.findShape(FreeCAD.activeDocument()." <<
|
||||
pcObj->getNameInDocument() << ".Shape,'" << name << "'";
|
||||
if(!name.compare(0,4,"Edge"))
|
||||
cmd << ",'Wires'";
|
||||
cmd << ')';
|
||||
cmds.push_back(cmd.str());
|
||||
sources << "FreeCAD.activeDocument()." << sub_fname << ",";
|
||||
}
|
||||
}
|
||||
if(addView && areaName.size()) {
|
||||
std::string FeatName = getUniqueObjectName("FeatureAreaView");
|
||||
openCommand("Create Path Area View");
|
||||
doCommand(Doc,"FreeCAD.activeDocument().addObject('Path::FeatureAreaView','%s')",FeatName.c_str());
|
||||
doCommand(Doc,"FreeCAD.activeDocument().%s.Source = FreeCAD.activeDocument().%s",
|
||||
FeatName.c_str(),areaName.c_str());
|
||||
commitCommand();
|
||||
updateActive();
|
||||
return;
|
||||
}
|
||||
std::string FeatName = getUniqueObjectName("FeatureArea");
|
||||
openCommand("Create Path Area");
|
||||
doCommand(Doc,"import PathCommands");
|
||||
for(const std::string &cmd : cmds)
|
||||
doCommand(Doc,cmd.c_str());
|
||||
doCommand(Doc,"FreeCAD.activeDocument().addObject('Path::FeatureArea','%s')",FeatName.c_str());
|
||||
doCommand(Doc,"FreeCAD.activeDocument().%s.Sources = [ %s ]",FeatName.c_str(),sources.str().c_str());
|
||||
commitCommand();
|
||||
updateActive();
|
||||
}
|
||||
|
||||
bool CmdPathArea::isActive(void)
|
||||
{
|
||||
return hasActiveDocument();
|
||||
}
|
||||
|
||||
|
||||
DEF_STD_CMD_A(CmdPathAreaWorkplane)
|
||||
|
||||
CmdPathAreaWorkplane::CmdPathAreaWorkplane()
|
||||
:Command("Path_Area_Workplane")
|
||||
{
|
||||
sAppModule = "Path";
|
||||
sGroup = QT_TR_NOOP("Path");
|
||||
sMenuText = QT_TR_NOOP("Area workplane");
|
||||
sToolTipText = QT_TR_NOOP("Select a workplane for a FeatureArea");
|
||||
sWhatsThis = "Path_Area_Workplane";
|
||||
sStatusTip = sToolTipText;
|
||||
sPixmap = "Path-Area-Workplane";
|
||||
sAccel = "P,W";
|
||||
|
||||
}
|
||||
|
||||
void CmdPathAreaWorkplane::activated(int iMsg)
|
||||
{
|
||||
Q_UNUSED(iMsg);
|
||||
|
||||
std::string areaName;
|
||||
std::string planeSubname;
|
||||
std::string planeName;
|
||||
|
||||
for(Gui::SelectionObject &selObj :
|
||||
getSelection().getSelectionEx(NULL, Part::Feature::getClassTypeId()))
|
||||
{
|
||||
const std::vector<std::string> &subnames = selObj.getSubNames();
|
||||
if(subnames.size()>1) {
|
||||
Base::Console().Error("Please select one sub shape object for plane only\n");
|
||||
return;
|
||||
}
|
||||
const Part::Feature *pcObj = static_cast<Part::Feature*>(selObj.getObject());
|
||||
if(subnames.empty()) {
|
||||
if(pcObj->getTypeId().isDerivedFrom(Path::FeatureArea::getClassTypeId())) {
|
||||
if(areaName.size()){
|
||||
Base::Console().Error("Please select one FeatureArea only\n");
|
||||
return;
|
||||
}
|
||||
areaName = pcObj->getNameInDocument();
|
||||
continue;
|
||||
}
|
||||
for (TopExp_Explorer it(pcObj->Shape.getShape().getShape(), TopAbs_SHELL); it.More(); it.Next()) {
|
||||
Base::Console().Error("Selected shape is not 2D\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(planeName.size()){
|
||||
Base::Console().Error("Please select one shape object for plane only\n");
|
||||
return;
|
||||
}else{
|
||||
planeSubname = planeName = pcObj->getNameInDocument();
|
||||
planeSubname += ".Shape";
|
||||
}
|
||||
|
||||
for(const std::string &name : subnames) {
|
||||
if(name.compare(0,4,"Face") && name.compare(0,4,"Edge")) {
|
||||
Base::Console().Error("Selected shape is not 2D\n");
|
||||
return;
|
||||
}
|
||||
std::ostringstream subname;
|
||||
subname << planeSubname << ",'" << name << "','Wires'";
|
||||
planeSubname = subname.str();
|
||||
}
|
||||
}
|
||||
if(areaName.empty()) {
|
||||
Base::Console().Error("Please select one FeatureArea\n");
|
||||
return;
|
||||
}
|
||||
if(planeName.empty()) {
|
||||
Base::Console().Error("Please select one shape object\n");
|
||||
return;
|
||||
}
|
||||
|
||||
openCommand("Select Workplane for Path Area");
|
||||
doCommand(Doc,"import PathCommands");
|
||||
doCommand(Doc,"FreeCAD.activeDocument().%s.WorkPlane = PathCommands.findShape("
|
||||
"FreeCAD.activeDocument().%s)", areaName.c_str(),planeSubname.c_str());
|
||||
doCommand(Doc,"FreeCAD.activeDocument().%s.ViewObject.Visibility = True",areaName.c_str());
|
||||
commitCommand();
|
||||
updateActive();
|
||||
}
|
||||
|
||||
bool CmdPathAreaWorkplane::isActive(void)
|
||||
{
|
||||
return !getSelection().getSelectionEx(NULL, Path::FeatureArea::getClassTypeId()).empty();
|
||||
}
|
||||
|
||||
|
||||
// Path compound #####################################################################################################
|
||||
@@ -95,7 +274,6 @@ bool CmdPathCompound::isActive(void)
|
||||
return hasActiveDocument();
|
||||
}
|
||||
|
||||
|
||||
// Path Shape #####################################################################################################
|
||||
|
||||
|
||||
@@ -117,24 +295,48 @@ CmdPathShape::CmdPathShape()
|
||||
void CmdPathShape::activated(int iMsg)
|
||||
{
|
||||
Q_UNUSED(iMsg);
|
||||
std::vector<Gui::SelectionSingleton::SelObj> Sel = getSelection().getSelection();
|
||||
if (Sel.size() == 1) {
|
||||
if (Sel[0].pObject->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) {
|
||||
Part::Feature *pcPartObject = static_cast<Part::Feature*>(Sel[0].pObject);
|
||||
std::string FeatName = getUniqueObjectName("PathShape");
|
||||
openCommand("Create Path Compound");
|
||||
doCommand(Doc,"FreeCAD.activeDocument().addObject('Path::FeatureShape','%s')",FeatName.c_str());
|
||||
doCommand(Doc,"FreeCAD.activeDocument().%s.Shape = FreeCAD.activeDocument().%s.Shape.copy()",FeatName.c_str(),pcPartObject->getNameInDocument());
|
||||
commitCommand();
|
||||
updateActive();
|
||||
} else {
|
||||
Base::Console().Error("Exactly one shape object must be selected\n");
|
||||
return;
|
||||
std::list<std::string> cmds;
|
||||
std::ostringstream sources;
|
||||
for(const Gui::SelectionObject &selObj :
|
||||
getSelection().getSelectionEx(NULL, Part::Feature::getClassTypeId()))
|
||||
{
|
||||
const Part::Feature *pcObj = static_cast<const Part::Feature*>(selObj.getObject());
|
||||
const std::vector<std::string> &subnames = selObj.getSubNames();
|
||||
if(subnames.empty()) {
|
||||
sources << "FreeCAD.activeDocument()." << pcObj->getNameInDocument() << ",";
|
||||
continue;
|
||||
}
|
||||
for(const std::string &name : subnames) {
|
||||
if(name.compare(0,4,"Face") && name.compare(0,4,"Edge")) {
|
||||
Base::Console().Warning("Ignored shape %s %s\n",
|
||||
pcObj->getNameInDocument(), name.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
std::ostringstream subname;
|
||||
subname << pcObj->getNameInDocument() << '_' << name;
|
||||
std::string sub_fname = getUniqueObjectName(subname.str().c_str());
|
||||
|
||||
std::ostringstream cmd;
|
||||
cmd << "FreeCAD.activeDocument().addObject('Part::Feature','" << sub_fname <<
|
||||
"').Shape = PathCommands.findShape(FreeCAD.activeDocument()." <<
|
||||
pcObj->getNameInDocument() << ".Shape,'" << name << "'";
|
||||
if(!name.compare(0,4,"Edge"))
|
||||
cmd << ",'Wires'";
|
||||
cmd << ')';
|
||||
cmds.push_back(cmd.str());
|
||||
sources << "FreeCAD.activeDocument()." << sub_fname << ",";
|
||||
}
|
||||
} else {
|
||||
Base::Console().Error("Exactly one shape object must be selected\n");
|
||||
return;
|
||||
}
|
||||
std::string FeatName = getUniqueObjectName("PathShape");
|
||||
openCommand("Create Path Shape");
|
||||
doCommand(Doc,"import PathCommands");
|
||||
for(const std::string &cmd : cmds)
|
||||
doCommand(Doc,cmd.c_str());
|
||||
doCommand(Doc,"FreeCAD.activeDocument().addObject('Path::FeatureShape','%s')",FeatName.c_str());
|
||||
doCommand(Doc,"FreeCAD.activeDocument().%s.Sources = [ %s ]",FeatName.c_str(),sources.str().c_str());
|
||||
commitCommand();
|
||||
updateActive();
|
||||
}
|
||||
|
||||
bool CmdPathShape::isActive(void)
|
||||
@@ -149,4 +351,6 @@ void CreatePathCommands(void)
|
||||
Gui::CommandManager &rcCmdMgr = Gui::Application::Instance->commandManager();
|
||||
rcCmdMgr.addCommand(new CmdPathCompound());
|
||||
rcCmdMgr.addCommand(new CmdPathShape());
|
||||
rcCmdMgr.addCommand(new CmdPathArea());
|
||||
rcCmdMgr.addCommand(new CmdPathAreaWorkplane());
|
||||
}
|
||||
|
||||
@@ -46,6 +46,9 @@
|
||||
<file>icons/Path-ToolChange.svg</file>
|
||||
<file>icons/Path-Toolpath.svg</file>
|
||||
<file>icons/Path-ToolTable.svg</file>
|
||||
<file>icons/Path-Area.svg</file>
|
||||
<file>icons/Path-Area-View.svg</file>
|
||||
<file>icons/Path-Area-Workplane.svg</file>
|
||||
<file>icons/preferences-path.svg</file>
|
||||
<file>panels/ContourEdit.ui</file>
|
||||
<file>panels/DlgJobChooser.ui</file>
|
||||
|
||||
657
src/Mod/Path/Gui/Resources/icons/Path-Area-View.svg
Normal file
657
src/Mod/Path/Gui/Resources/icons/Path-Area-View.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 24 KiB |
676
src/Mod/Path/Gui/Resources/icons/Path-Area-Workplane.svg
Normal file
676
src/Mod/Path/Gui/Resources/icons/Path-Area-Workplane.svg
Normal file
@@ -0,0 +1,676 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="64px"
|
||||
height="64px"
|
||||
id="svg2816"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="Path-Area-Workplane.svg">
|
||||
<defs
|
||||
id="defs2818">
|
||||
<linearGradient
|
||||
id="linearGradient4022-3"
|
||||
inkscape:collect="always">
|
||||
<stop
|
||||
id="stop4316"
|
||||
offset="0"
|
||||
style="stop-color:#ff0000;stop-opacity:1" />
|
||||
<stop
|
||||
id="stop4318"
|
||||
offset="1"
|
||||
style="stop-color:#ff8080;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient4066">
|
||||
<stop
|
||||
style="stop-color:#4e9a06;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop4068" />
|
||||
<stop
|
||||
style="stop-color:#8ae234;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop4070" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient4022">
|
||||
<stop
|
||||
style="stop-color:#204a87;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop4024" />
|
||||
<stop
|
||||
style="stop-color:#729fcf;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop4026" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient4513">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop4515" />
|
||||
<stop
|
||||
style="stop-color:#999999;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop4517" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3681">
|
||||
<stop
|
||||
id="stop3697"
|
||||
offset="0"
|
||||
style="stop-color:#fff110;stop-opacity:1;" />
|
||||
<stop
|
||||
style="stop-color:#cf7008;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3685" />
|
||||
</linearGradient>
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 32 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="64 : 32 : 1"
|
||||
inkscape:persp3d-origin="32 : 21.333333 : 1"
|
||||
id="perspective2824" />
|
||||
<inkscape:perspective
|
||||
id="perspective3622"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3622-9"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3653"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3675"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3697"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3720"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3742"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3764"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3785"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3806"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3806-3"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3835"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3614"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3614-8"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3643"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3643-3"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3672"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3672-5"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3701"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3701-8"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3746"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<pattern
|
||||
patternTransform="matrix(0.67643728,-0.81829155,2.4578314,1.8844554,-26.450606,18.294947)"
|
||||
id="pattern5231"
|
||||
xlink:href="#Strips1_1-4"
|
||||
inkscape:collect="always" />
|
||||
<inkscape:perspective
|
||||
id="perspective5224"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<pattern
|
||||
inkscape:stockid="Stripes 1:1"
|
||||
id="Strips1_1-4"
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
|
||||
height="1"
|
||||
width="2"
|
||||
patternUnits="userSpaceOnUse"
|
||||
inkscape:collect="always">
|
||||
<rect
|
||||
id="rect4483-4"
|
||||
height="2"
|
||||
width="1"
|
||||
y="-0.5"
|
||||
x="0"
|
||||
style="fill:black;stroke:none" />
|
||||
</pattern>
|
||||
<inkscape:perspective
|
||||
id="perspective5224-9"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<pattern
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,39.618381,8.9692804)"
|
||||
id="pattern5231-4"
|
||||
xlink:href="#Strips1_1-6"
|
||||
inkscape:collect="always" />
|
||||
<inkscape:perspective
|
||||
id="perspective5224-3"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<pattern
|
||||
inkscape:stockid="Stripes 1:1"
|
||||
id="Strips1_1-6"
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
|
||||
height="1"
|
||||
width="2"
|
||||
patternUnits="userSpaceOnUse"
|
||||
inkscape:collect="always">
|
||||
<rect
|
||||
id="rect4483-0"
|
||||
height="2"
|
||||
width="1"
|
||||
y="-0.5"
|
||||
x="0"
|
||||
style="fill:black;stroke:none" />
|
||||
</pattern>
|
||||
<pattern
|
||||
patternTransform="matrix(0.66513382,-1.0631299,2.4167603,2.4482973,-49.762569,2.9546807)"
|
||||
id="pattern5296"
|
||||
xlink:href="#pattern5231-3"
|
||||
inkscape:collect="always" />
|
||||
<inkscape:perspective
|
||||
id="perspective5288"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<pattern
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,-26.336284,10.887197)"
|
||||
id="pattern5231-3"
|
||||
xlink:href="#Strips1_1-4-3"
|
||||
inkscape:collect="always" />
|
||||
<pattern
|
||||
inkscape:stockid="Stripes 1:1"
|
||||
id="Strips1_1-4-3"
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
|
||||
height="1"
|
||||
width="2"
|
||||
patternUnits="userSpaceOnUse"
|
||||
inkscape:collect="always">
|
||||
<rect
|
||||
id="rect4483-4-6"
|
||||
height="2"
|
||||
width="1"
|
||||
y="-0.5"
|
||||
x="0"
|
||||
style="fill:black;stroke:none" />
|
||||
</pattern>
|
||||
<pattern
|
||||
patternTransform="matrix(0.42844886,-0.62155849,1.5567667,1.431396,27.948414,13.306456)"
|
||||
id="pattern5330"
|
||||
xlink:href="#Strips1_1-9"
|
||||
inkscape:collect="always" />
|
||||
<inkscape:perspective
|
||||
id="perspective5323"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<pattern
|
||||
inkscape:stockid="Stripes 1:1"
|
||||
id="Strips1_1-9"
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
|
||||
height="1"
|
||||
width="2"
|
||||
patternUnits="userSpaceOnUse"
|
||||
inkscape:collect="always">
|
||||
<rect
|
||||
id="rect4483-3"
|
||||
height="2"
|
||||
width="1"
|
||||
y="-0.5"
|
||||
x="0"
|
||||
style="fill:black;stroke:none" />
|
||||
</pattern>
|
||||
<inkscape:perspective
|
||||
id="perspective5361"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective5383"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective5411"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3681"
|
||||
id="linearGradient3687"
|
||||
x1="37.89756"
|
||||
y1="41.087898"
|
||||
x2="4.0605712"
|
||||
y2="40.168594"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(127.27273,-51.272729)" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3681"
|
||||
id="linearGradient3695"
|
||||
x1="37.894287"
|
||||
y1="40.484772"
|
||||
x2="59.811455"
|
||||
y2="43.558987"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(127.27273,-51.272729)" />
|
||||
<linearGradient
|
||||
id="linearGradient3681-3">
|
||||
<stop
|
||||
id="stop3697-3"
|
||||
offset="0"
|
||||
style="stop-color:#fff110;stop-opacity:1;" />
|
||||
<stop
|
||||
style="stop-color:#cf7008;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3685-4" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
y2="43.558987"
|
||||
x2="59.811455"
|
||||
y1="40.484772"
|
||||
x1="37.894287"
|
||||
gradientTransform="translate(-37.00068,-20.487365)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient3608"
|
||||
xlink:href="#linearGradient3681-3"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
id="linearGradient4513-2">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop4515-2" />
|
||||
<stop
|
||||
style="stop-color:#999999;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop4517-4" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
r="23.634638"
|
||||
fy="7.9319997"
|
||||
fx="32.151962"
|
||||
cy="7.9319997"
|
||||
cx="32.151962"
|
||||
gradientTransform="matrix(1,0,0,1.1841158,-8.5173246,-3.4097568)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient4538"
|
||||
xlink:href="#linearGradient4513-2"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
id="linearGradient4513-1">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop4515-8" />
|
||||
<stop
|
||||
style="stop-color:#999999;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop4517-6" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
r="23.634638"
|
||||
fy="7.9319997"
|
||||
fx="32.151962"
|
||||
cy="7.9319997"
|
||||
cx="32.151962"
|
||||
gradientTransform="matrix(1,0,0,1.1841158,-8.5173246,-3.4097568)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient4538-6"
|
||||
xlink:href="#linearGradient4513-1"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
id="linearGradient4513-1-3">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop4515-8-7" />
|
||||
<stop
|
||||
style="stop-color:#999999;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop4517-6-5" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
r="23.634638"
|
||||
fy="35.869175"
|
||||
fx="32.151962"
|
||||
cy="35.869175"
|
||||
cx="32.151962"
|
||||
gradientTransform="matrix(0.39497909,0,0,1.1841158,-2.716491,-26.067007)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient3069"
|
||||
xlink:href="#linearGradient4513-1-3"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
id="linearGradient4513-1-2">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop4515-8-6" />
|
||||
<stop
|
||||
style="stop-color:#999999;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop4517-6-6" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
r="23.634638"
|
||||
fy="35.869175"
|
||||
fx="32.151962"
|
||||
cy="35.869175"
|
||||
cx="32.151962"
|
||||
gradientTransform="matrix(0.39497909,0,0,1.1841158,-2.716491,-26.067007)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient3102"
|
||||
xlink:href="#linearGradient4513-1-2"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4513-1"
|
||||
id="radialGradient3132"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.39497909,0,0,1.1841158,64.952609,-7.0541574)"
|
||||
cx="32.151962"
|
||||
cy="27.950663"
|
||||
fx="32.151962"
|
||||
fy="27.950663"
|
||||
r="23.634638" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4022"
|
||||
id="linearGradient4028"
|
||||
x1="36.538239"
|
||||
y1="45.928013"
|
||||
x2="36.804447"
|
||||
y2="23.332739"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4066"
|
||||
id="linearGradient4072"
|
||||
x1="41.610756"
|
||||
y1="59.853931"
|
||||
x2="32.101425"
|
||||
y2="10.99928"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4031"
|
||||
id="linearGradient4055"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(71.494719,-3.1982556)"
|
||||
x1="30.000002"
|
||||
y1="14"
|
||||
x2="36"
|
||||
y2="54.227272" />
|
||||
<linearGradient
|
||||
id="linearGradient4031">
|
||||
<stop
|
||||
id="stop4033"
|
||||
offset="0"
|
||||
style="stop-color:#d3d7cf;stop-opacity:1" />
|
||||
<stop
|
||||
id="stop4035"
|
||||
offset="1"
|
||||
style="stop-color:#888a85;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
gradientTransform="matrix(1.2000004,0,0,1.2000004,-14.000047,-24.000012)"
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4022-3"
|
||||
id="linearGradient4028-3"
|
||||
x1="36.538239"
|
||||
y1="45.928013"
|
||||
x2="36.804447"
|
||||
y2="23.332739"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="3.8890873"
|
||||
inkscape:cx="21.739458"
|
||||
inkscape:cy="37.036095"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:bbox-paths="true"
|
||||
inkscape:bbox-nodes="true"
|
||||
inkscape:snap-bbox-edge-midpoints="true"
|
||||
inkscape:snap-bbox-midpoints="true"
|
||||
inkscape:object-paths="true"
|
||||
inkscape:object-nodes="true"
|
||||
inkscape:window-width="1375"
|
||||
inkscape:window-height="876"
|
||||
inkscape:window-x="65"
|
||||
inkscape:window-y="24"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:snap-global="true">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid3234"
|
||||
empspacing="2"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata2821">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
<dc:title>Path-FaceProfile</dc:title>
|
||||
<dc:date>2016-01-19</dc:date>
|
||||
<dc:relation>http://www.freecadweb.org/wiki/index.php?title=Artwork</dc:relation>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:identifier>FreeCAD/src/Mod/Path/Gui/Resources/icons/Path-</dc:identifier>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD LGPL2+</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title>[agryson] Alexander Gryson</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer">
|
||||
<path
|
||||
style="color:#000000;fill:url(#linearGradient4028);fill-opacity:1;fill-rule:nonzero;stroke:#0b1521;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="M 33,21 17,45 41,49 53,33 49,23 z"
|
||||
id="rect3083"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccccc" />
|
||||
<path
|
||||
style="color:#000000;fill:none;stroke:#172a04;stroke-width:8;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="M 50,13 39,11 c -4,-1 -5.171573,-1.4142136 -8,0 -2,1 -3,2 -5,5 L 7,46 c -3,4 -1,7 3,8 l 28,4 c 5,1 9,-2 12,-6 l 4,-5"
|
||||
id="rect3083-0"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccscccccc" />
|
||||
<path
|
||||
style="color:#000000;fill:none;stroke:#729fcf;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="M 33.965909,23.113636 20.349931,43.571429 40.140486,46.839294 50.710729,32.691101 47.57301,24.842851 z"
|
||||
id="rect3083-3"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccccc" />
|
||||
<path
|
||||
style="color:#000000;fill:none;stroke:url(#linearGradient4072);stroke-width:4;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="M 50,13 39,11 c -4,-1 -5.171573,-1.414214 -8,0 -2,1 -3,2 -5,5 L 7,46 c -3,4 -1,7 3,8 l 28,4 c 5,1 9,-2 12,-6 l 4,-5"
|
||||
id="rect3083-0-6"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccscccccc" />
|
||||
<path
|
||||
style="color:#000000;fill:none;stroke:#8ae234;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="M 50.064283,12 38.517882,9.919647 c -4,-1.0000001 -5.171573,-1.4142141 -8,0 -2,1 -3,2 -5,5 l -19.0000003,30 c -2.9999999,4 -1,7 2.9999998,8 l 28.0000005,4 c 5,1 9,-2 12,-6 L 53,46"
|
||||
id="rect3083-0-6-7"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccscccccc" />
|
||||
<path
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.84799978;fill:url(#linearGradient4028-3);fill-opacity:1.0;fill-rule:nonzero;stroke:#0b1521;stroke-width:2.40000081;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
|
||||
d="M 25.599966,1.1999953 6.3999597,30.000005 35.199969,34.800007 49.599974,15.600001 44.799972,3.5999961 Z"
|
||||
id="rect3083-5"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccccc" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 23 KiB |
648
src/Mod/Path/Gui/Resources/icons/Path-Area.svg
Normal file
648
src/Mod/Path/Gui/Resources/icons/Path-Area.svg
Normal file
@@ -0,0 +1,648 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="64px"
|
||||
height="64px"
|
||||
id="svg2816"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="Path-Area.svg">
|
||||
<defs
|
||||
id="defs2818">
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient4066">
|
||||
<stop
|
||||
style="stop-color:#4e9a06;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop4068" />
|
||||
<stop
|
||||
style="stop-color:#8ae234;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop4070" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient4022">
|
||||
<stop
|
||||
style="stop-color:#204a87;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop4024" />
|
||||
<stop
|
||||
style="stop-color:#729fcf;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop4026" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient4513">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop4515" />
|
||||
<stop
|
||||
style="stop-color:#999999;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop4517" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3681">
|
||||
<stop
|
||||
id="stop3697"
|
||||
offset="0"
|
||||
style="stop-color:#fff110;stop-opacity:1;" />
|
||||
<stop
|
||||
style="stop-color:#cf7008;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3685" />
|
||||
</linearGradient>
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 32 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="64 : 32 : 1"
|
||||
inkscape:persp3d-origin="32 : 21.333333 : 1"
|
||||
id="perspective2824" />
|
||||
<inkscape:perspective
|
||||
id="perspective3622"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3622-9"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3653"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3675"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3697"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3720"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3742"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3764"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3785"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3806"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3806-3"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3835"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3614"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3614-8"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3643"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3643-3"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3672"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3672-5"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3701"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3701-8"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3746"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<pattern
|
||||
patternTransform="matrix(0.67643728,-0.81829155,2.4578314,1.8844554,-26.450606,18.294947)"
|
||||
id="pattern5231"
|
||||
xlink:href="#Strips1_1-4"
|
||||
inkscape:collect="always" />
|
||||
<inkscape:perspective
|
||||
id="perspective5224"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<pattern
|
||||
inkscape:stockid="Stripes 1:1"
|
||||
id="Strips1_1-4"
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
|
||||
height="1"
|
||||
width="2"
|
||||
patternUnits="userSpaceOnUse"
|
||||
inkscape:collect="always">
|
||||
<rect
|
||||
id="rect4483-4"
|
||||
height="2"
|
||||
width="1"
|
||||
y="-0.5"
|
||||
x="0"
|
||||
style="fill:black;stroke:none" />
|
||||
</pattern>
|
||||
<inkscape:perspective
|
||||
id="perspective5224-9"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<pattern
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,39.618381,8.9692804)"
|
||||
id="pattern5231-4"
|
||||
xlink:href="#Strips1_1-6"
|
||||
inkscape:collect="always" />
|
||||
<inkscape:perspective
|
||||
id="perspective5224-3"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<pattern
|
||||
inkscape:stockid="Stripes 1:1"
|
||||
id="Strips1_1-6"
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
|
||||
height="1"
|
||||
width="2"
|
||||
patternUnits="userSpaceOnUse"
|
||||
inkscape:collect="always">
|
||||
<rect
|
||||
id="rect4483-0"
|
||||
height="2"
|
||||
width="1"
|
||||
y="-0.5"
|
||||
x="0"
|
||||
style="fill:black;stroke:none" />
|
||||
</pattern>
|
||||
<pattern
|
||||
patternTransform="matrix(0.66513382,-1.0631299,2.4167603,2.4482973,-49.762569,2.9546807)"
|
||||
id="pattern5296"
|
||||
xlink:href="#pattern5231-3"
|
||||
inkscape:collect="always" />
|
||||
<inkscape:perspective
|
||||
id="perspective5288"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<pattern
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,-26.336284,10.887197)"
|
||||
id="pattern5231-3"
|
||||
xlink:href="#Strips1_1-4-3"
|
||||
inkscape:collect="always" />
|
||||
<pattern
|
||||
inkscape:stockid="Stripes 1:1"
|
||||
id="Strips1_1-4-3"
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
|
||||
height="1"
|
||||
width="2"
|
||||
patternUnits="userSpaceOnUse"
|
||||
inkscape:collect="always">
|
||||
<rect
|
||||
id="rect4483-4-6"
|
||||
height="2"
|
||||
width="1"
|
||||
y="-0.5"
|
||||
x="0"
|
||||
style="fill:black;stroke:none" />
|
||||
</pattern>
|
||||
<pattern
|
||||
patternTransform="matrix(0.42844886,-0.62155849,1.5567667,1.431396,27.948414,13.306456)"
|
||||
id="pattern5330"
|
||||
xlink:href="#Strips1_1-9"
|
||||
inkscape:collect="always" />
|
||||
<inkscape:perspective
|
||||
id="perspective5323"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<pattern
|
||||
inkscape:stockid="Stripes 1:1"
|
||||
id="Strips1_1-9"
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
|
||||
height="1"
|
||||
width="2"
|
||||
patternUnits="userSpaceOnUse"
|
||||
inkscape:collect="always">
|
||||
<rect
|
||||
id="rect4483-3"
|
||||
height="2"
|
||||
width="1"
|
||||
y="-0.5"
|
||||
x="0"
|
||||
style="fill:black;stroke:none" />
|
||||
</pattern>
|
||||
<inkscape:perspective
|
||||
id="perspective5361"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective5383"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective5411"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3681"
|
||||
id="linearGradient3687"
|
||||
x1="37.89756"
|
||||
y1="41.087898"
|
||||
x2="4.0605712"
|
||||
y2="40.168594"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(127.27273,-51.272729)" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3681"
|
||||
id="linearGradient3695"
|
||||
x1="37.894287"
|
||||
y1="40.484772"
|
||||
x2="59.811455"
|
||||
y2="43.558987"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(127.27273,-51.272729)" />
|
||||
<linearGradient
|
||||
id="linearGradient3681-3">
|
||||
<stop
|
||||
id="stop3697-3"
|
||||
offset="0"
|
||||
style="stop-color:#fff110;stop-opacity:1;" />
|
||||
<stop
|
||||
style="stop-color:#cf7008;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3685-4" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
y2="43.558987"
|
||||
x2="59.811455"
|
||||
y1="40.484772"
|
||||
x1="37.894287"
|
||||
gradientTransform="translate(-37.00068,-20.487365)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient3608"
|
||||
xlink:href="#linearGradient3681-3"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
id="linearGradient4513-2">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop4515-2" />
|
||||
<stop
|
||||
style="stop-color:#999999;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop4517-4" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
r="23.634638"
|
||||
fy="7.9319997"
|
||||
fx="32.151962"
|
||||
cy="7.9319997"
|
||||
cx="32.151962"
|
||||
gradientTransform="matrix(1,0,0,1.1841158,-8.5173246,-3.4097568)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient4538"
|
||||
xlink:href="#linearGradient4513-2"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
id="linearGradient4513-1">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop4515-8" />
|
||||
<stop
|
||||
style="stop-color:#999999;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop4517-6" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
r="23.634638"
|
||||
fy="7.9319997"
|
||||
fx="32.151962"
|
||||
cy="7.9319997"
|
||||
cx="32.151962"
|
||||
gradientTransform="matrix(1,0,0,1.1841158,-8.5173246,-3.4097568)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient4538-6"
|
||||
xlink:href="#linearGradient4513-1"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
id="linearGradient4513-1-3">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop4515-8-7" />
|
||||
<stop
|
||||
style="stop-color:#999999;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop4517-6-5" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
r="23.634638"
|
||||
fy="35.869175"
|
||||
fx="32.151962"
|
||||
cy="35.869175"
|
||||
cx="32.151962"
|
||||
gradientTransform="matrix(0.39497909,0,0,1.1841158,-2.716491,-26.067007)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient3069"
|
||||
xlink:href="#linearGradient4513-1-3"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
id="linearGradient4513-1-2">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop4515-8-6" />
|
||||
<stop
|
||||
style="stop-color:#999999;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop4517-6-6" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
r="23.634638"
|
||||
fy="35.869175"
|
||||
fx="32.151962"
|
||||
cy="35.869175"
|
||||
cx="32.151962"
|
||||
gradientTransform="matrix(0.39497909,0,0,1.1841158,-2.716491,-26.067007)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient3102"
|
||||
xlink:href="#linearGradient4513-1-2"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4513-1"
|
||||
id="radialGradient3132"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.39497909,0,0,1.1841158,64.952609,-7.0541574)"
|
||||
cx="32.151962"
|
||||
cy="27.950663"
|
||||
fx="32.151962"
|
||||
fy="27.950663"
|
||||
r="23.634638" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4022"
|
||||
id="linearGradient4028"
|
||||
x1="36.538239"
|
||||
y1="45.928013"
|
||||
x2="36.804447"
|
||||
y2="23.332739"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4066"
|
||||
id="linearGradient4072"
|
||||
x1="41.610756"
|
||||
y1="59.853931"
|
||||
x2="32.101425"
|
||||
y2="10.99928"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4031"
|
||||
id="linearGradient4055"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(71.494719,-3.1982556)"
|
||||
x1="30.000002"
|
||||
y1="14"
|
||||
x2="36"
|
||||
y2="54.227272" />
|
||||
<linearGradient
|
||||
id="linearGradient4031">
|
||||
<stop
|
||||
id="stop4033"
|
||||
offset="0"
|
||||
style="stop-color:#d3d7cf;stop-opacity:1" />
|
||||
<stop
|
||||
id="stop4035"
|
||||
offset="1"
|
||||
style="stop-color:#888a85;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="11"
|
||||
inkscape:cx="25.031078"
|
||||
inkscape:cy="28.81298"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:bbox-paths="true"
|
||||
inkscape:bbox-nodes="true"
|
||||
inkscape:snap-bbox-edge-midpoints="true"
|
||||
inkscape:snap-bbox-midpoints="true"
|
||||
inkscape:object-paths="true"
|
||||
inkscape:object-nodes="true"
|
||||
inkscape:window-width="1375"
|
||||
inkscape:window-height="876"
|
||||
inkscape:window-x="65"
|
||||
inkscape:window-y="24"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:snap-global="true">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid3234"
|
||||
empspacing="2"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata2821">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
<dc:title>Path-FaceProfile</dc:title>
|
||||
<dc:date>2016-01-19</dc:date>
|
||||
<dc:relation>http://www.freecadweb.org/wiki/index.php?title=Artwork</dc:relation>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:identifier>FreeCAD/src/Mod/Path/Gui/Resources/icons/Path-</dc:identifier>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD LGPL2+</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title>[agryson] Alexander Gryson</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer">
|
||||
<path
|
||||
style="color:#000000;fill:url(#linearGradient4028);fill-opacity:1;fill-rule:nonzero;stroke:#0b1521;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="M 33,21 17,45 41,49 53,33 49,23 z"
|
||||
id="rect3083"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccccc" />
|
||||
<path
|
||||
style="color:#000000;fill:none;stroke:#172a04;stroke-width:8;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="M 50,13 39,11 c -4,-1 -5.171573,-1.4142136 -8,0 -2,1 -3,2 -5,5 L 7,46 c -3,4 -1,7 3,8 l 28,4 c 5,1 9,-2 12,-6 l 4,-5"
|
||||
id="rect3083-0"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccscccccc" />
|
||||
<path
|
||||
style="color:#000000;fill:none;stroke:#729fcf;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="M 33.965909,23.113636 20.349931,43.571429 40.140486,46.839294 50.710729,32.691101 47.57301,24.842851 z"
|
||||
id="rect3083-3"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccccc" />
|
||||
<path
|
||||
style="color:#000000;fill:none;stroke:url(#linearGradient4072);stroke-width:4;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="M 50,13 39,11 c -4,-1 -5.171573,-1.414214 -8,0 -2,1 -3,2 -5,5 L 7,46 c -3,4 -1,7 3,8 l 28,4 c 5,1 9,-2 12,-6 l 4,-5"
|
||||
id="rect3083-0-6"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccscccccc" />
|
||||
<path
|
||||
style="color:#000000;fill:none;stroke:#8ae234;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="M 50.064283,12 38.517882,9.919647 c -4,-1.0000001 -5.171573,-1.4142141 -8,0 -2,1 -3,2 -5,5 l -19.0000003,30 c -2.9999999,4 -1,7 2.9999998,8 l 28.0000005,4 c 5,1 9,-2 12,-6 L 53,46"
|
||||
id="rect3083-0-6-7"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccscccccc" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 22 KiB |
197
src/Mod/Path/Gui/ViewProviderArea.cpp
Normal file
197
src/Mod/Path/Gui/ViewProviderArea.cpp
Normal file
@@ -0,0 +1,197 @@
|
||||
/****************************************************************************
|
||||
* Copyright (c) 2017 Zheng, Lei (realthunder) <realthunder.dev@gmail.com>*
|
||||
* *
|
||||
* 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 *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#ifndef _PreComp_
|
||||
#endif
|
||||
|
||||
#include <Gui/Application.h>
|
||||
#include <Mod/Path/App/FeatureArea.h>
|
||||
#include "ViewProviderArea.h"
|
||||
|
||||
using namespace PathGui;
|
||||
|
||||
PROPERTY_SOURCE(PathGui::ViewProviderArea, PartGui::ViewProviderPlaneParametric)
|
||||
|
||||
ViewProviderArea::ViewProviderArea()
|
||||
{
|
||||
sPixmap = "Path-Area.svg";
|
||||
}
|
||||
|
||||
ViewProviderArea::~ViewProviderArea()
|
||||
{
|
||||
}
|
||||
|
||||
std::vector<App::DocumentObject*> ViewProviderArea::claimChildren(void) const
|
||||
{
|
||||
return std::vector<App::DocumentObject*>(
|
||||
static_cast<Path::FeatureArea*>(getObject())->Sources.getValues());
|
||||
}
|
||||
|
||||
bool ViewProviderArea::canDragObjects() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ViewProviderArea::canDragObject(App::DocumentObject* obj) const
|
||||
{
|
||||
return obj && obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId());
|
||||
}
|
||||
|
||||
void ViewProviderArea::dragObject(App::DocumentObject* obj)
|
||||
{
|
||||
Path::FeatureArea* area = static_cast<Path::FeatureArea*>(getObject());
|
||||
std::vector<App::DocumentObject*> sources = area->Sources.getValues();
|
||||
for (std::vector<App::DocumentObject*>::iterator it = sources.begin(); it != sources.end(); ++it) {
|
||||
if (*it == obj) {
|
||||
sources.erase(it);
|
||||
area->Sources.setValues(sources);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ViewProviderArea::canDropObjects() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ViewProviderArea::canDropObject(App::DocumentObject* obj) const
|
||||
{
|
||||
return canDragObject(obj);
|
||||
}
|
||||
|
||||
void ViewProviderArea::dropObject(App::DocumentObject* obj)
|
||||
{
|
||||
Path::FeatureArea* area = static_cast<Path::FeatureArea*>(getObject());
|
||||
std::vector<App::DocumentObject*> sources = area->Sources.getValues();
|
||||
sources.push_back(obj);
|
||||
area->Sources.setValues(sources);
|
||||
}
|
||||
|
||||
void ViewProviderArea::updateData(const App::Property* prop)
|
||||
{
|
||||
PartGui::ViewProviderPart::updateData(prop);
|
||||
if (prop->getTypeId() == App::PropertyLinkList::getClassTypeId()) {
|
||||
std::vector<App::DocumentObject*> pShapes = static_cast<const App::PropertyLinkList*>(prop)->getValues();
|
||||
for (std::vector<App::DocumentObject*>::iterator it = pShapes.begin(); it != pShapes.end(); ++it) {
|
||||
if (*it)
|
||||
Gui::Application::Instance->hideViewProvider(*it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ViewProviderArea::onDelete(const std::vector<std::string> &)
|
||||
{
|
||||
// get the input shapes
|
||||
Path::FeatureArea* area = static_cast<Path::FeatureArea*>(getObject());
|
||||
std::vector<App::DocumentObject*> pShapes =area->Sources.getValues();
|
||||
for (std::vector<App::DocumentObject*>::iterator it = pShapes.begin(); it != pShapes.end(); ++it) {
|
||||
if (*it)
|
||||
Gui::Application::Instance->showViewProvider(*it);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Python object -----------------------------------------------------------------------
|
||||
|
||||
PROPERTY_SOURCE(PathGui::ViewProviderAreaView, PartGui::ViewProviderPlaneParametric)
|
||||
|
||||
ViewProviderAreaView::ViewProviderAreaView()
|
||||
{
|
||||
sPixmap = "Path-Area-View.svg";
|
||||
}
|
||||
|
||||
ViewProviderAreaView::~ViewProviderAreaView()
|
||||
{
|
||||
}
|
||||
|
||||
std::vector<App::DocumentObject*> ViewProviderAreaView::claimChildren(void) const
|
||||
{
|
||||
std::vector<App::DocumentObject*> ret;
|
||||
Path::FeatureAreaView* feature = static_cast<Path::FeatureAreaView*>(getObject());
|
||||
if(feature->Source.getValue())
|
||||
ret.push_back(feature->Source.getValue());
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ViewProviderAreaView::canDragObjects() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ViewProviderAreaView::canDragObject(App::DocumentObject* obj) const
|
||||
{
|
||||
return obj && obj->getTypeId().isDerivedFrom(Path::FeatureArea::getClassTypeId());
|
||||
}
|
||||
|
||||
void ViewProviderAreaView::dragObject(App::DocumentObject* )
|
||||
{
|
||||
Path::FeatureAreaView* feature = static_cast<Path::FeatureAreaView*>(getObject());
|
||||
feature->Source.setValue(NULL);
|
||||
}
|
||||
|
||||
bool ViewProviderAreaView::canDropObjects() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ViewProviderAreaView::canDropObject(App::DocumentObject* obj) const
|
||||
{
|
||||
return canDragObject(obj);
|
||||
}
|
||||
|
||||
void ViewProviderAreaView::dropObject(App::DocumentObject* obj)
|
||||
{
|
||||
Path::FeatureAreaView* feature = static_cast<Path::FeatureAreaView*>(getObject());
|
||||
feature->Source.setValue(obj);
|
||||
}
|
||||
|
||||
void ViewProviderAreaView::updateData(const App::Property* prop)
|
||||
{
|
||||
PartGui::ViewProviderPlaneParametric::updateData(prop);
|
||||
if (prop->getTypeId() == App::PropertyLink::getClassTypeId())
|
||||
Gui::Application::Instance->hideViewProvider(
|
||||
static_cast<const App::PropertyLink*>(prop)->getValue());
|
||||
}
|
||||
|
||||
bool ViewProviderAreaView::onDelete(const std::vector<std::string> &)
|
||||
{
|
||||
Path::FeatureAreaView* feature = static_cast<Path::FeatureAreaView*>(getObject());
|
||||
Gui::Application::Instance->showViewProvider(feature->Source.getValue());
|
||||
return true;
|
||||
}
|
||||
|
||||
// Python object -----------------------------------------------------------------------
|
||||
|
||||
namespace Gui {
|
||||
/// @cond DOXERR
|
||||
PROPERTY_SOURCE_TEMPLATE(PathGui::ViewProviderAreaPython, PathGui::ViewProviderArea)
|
||||
PROPERTY_SOURCE_TEMPLATE(PathGui::ViewProviderAreaViewPython, PathGui::ViewProviderAreaView)
|
||||
/// @endcond
|
||||
|
||||
// explicit template instantiation
|
||||
template class PathGuiExport ViewProviderPythonFeatureT<PathGui::ViewProviderArea>;
|
||||
template class PathGuiExport ViewProviderPythonFeatureT<PathGui::ViewProviderAreaView>;
|
||||
}
|
||||
|
||||
83
src/Mod/Path/Gui/ViewProviderArea.h
Normal file
83
src/Mod/Path/Gui/ViewProviderArea.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/****************************************************************************
|
||||
* Copyright (c) 2017 Zheng, Lei (realthunder) <realthunder.dev@gmail.com>*
|
||||
* *
|
||||
* 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_ViewProviderArea_H
|
||||
#define PATH_ViewProviderArea_H
|
||||
|
||||
#include <Gui/ViewProviderPythonFeature.h>
|
||||
#include <Mod/Part/Gui/ViewProviderPlaneParametric.h>
|
||||
|
||||
namespace PathGui
|
||||
{
|
||||
|
||||
class PathGuiExport ViewProviderArea : public PartGui::ViewProviderPlaneParametric
|
||||
{
|
||||
PROPERTY_HEADER(PathGui::ViewProviderArea);
|
||||
|
||||
public:
|
||||
ViewProviderArea();
|
||||
virtual ~ViewProviderArea();
|
||||
|
||||
/// grouping handling
|
||||
virtual std::vector<App::DocumentObject*> claimChildren(void) const;
|
||||
virtual void updateData(const App::Property*);
|
||||
virtual bool onDelete(const std::vector<std::string> &);
|
||||
|
||||
/// drag and drop
|
||||
virtual bool canDragObjects() const;
|
||||
virtual bool canDragObject(App::DocumentObject*) const;
|
||||
virtual void dragObject(App::DocumentObject*);
|
||||
virtual bool canDropObjects() const;
|
||||
virtual bool canDropObject(App::DocumentObject*) const;
|
||||
virtual void dropObject(App::DocumentObject*);
|
||||
};
|
||||
|
||||
typedef Gui::ViewProviderPythonFeatureT<ViewProviderArea> ViewProviderAreaPython;
|
||||
|
||||
|
||||
class PathGuiExport ViewProviderAreaView : public PartGui::ViewProviderPlaneParametric
|
||||
{
|
||||
PROPERTY_HEADER(PathGui::ViewProviderAreaView);
|
||||
|
||||
public:
|
||||
ViewProviderAreaView();
|
||||
virtual ~ViewProviderAreaView();
|
||||
virtual std::vector<App::DocumentObject*> claimChildren(void) const;
|
||||
virtual void updateData(const App::Property*);
|
||||
virtual bool onDelete(const std::vector<std::string> &);
|
||||
|
||||
/// drag and drop
|
||||
virtual bool canDragObjects() const;
|
||||
virtual bool canDragObject(App::DocumentObject*) const;
|
||||
virtual void dragObject(App::DocumentObject*);
|
||||
virtual bool canDropObjects() const;
|
||||
virtual bool canDropObject(App::DocumentObject*) const;
|
||||
virtual void dropObject(App::DocumentObject*);
|
||||
};
|
||||
|
||||
typedef Gui::ViewProviderPythonFeatureT<ViewProviderAreaView> ViewProviderAreaViewPython;
|
||||
|
||||
} //namespace PathGui
|
||||
|
||||
|
||||
#endif // PATH_ViewProviderArea_H
|
||||
@@ -26,8 +26,11 @@
|
||||
#ifndef _PreComp_
|
||||
#endif
|
||||
|
||||
#include "ViewProviderPathShape.h"
|
||||
#include <Gui/BitmapFactory.h>
|
||||
#include <Gui/Application.h>
|
||||
#include <Mod/Part/App/PartFeature.h>
|
||||
#include <Mod/Path/App/FeaturePathShape.h>
|
||||
#include "ViewProviderPathShape.h"
|
||||
|
||||
using namespace Gui;
|
||||
using namespace PathGui;
|
||||
@@ -38,3 +41,74 @@ QIcon ViewProviderPathShape::getIcon() const
|
||||
{
|
||||
return Gui::BitmapFactory().pixmap("Path-Shape");
|
||||
}
|
||||
|
||||
std::vector<App::DocumentObject*> ViewProviderPathShape::claimChildren(void) const
|
||||
{
|
||||
return std::vector<App::DocumentObject*>(
|
||||
static_cast<Path::FeatureShape*>(getObject())->Sources.getValues());
|
||||
}
|
||||
|
||||
bool ViewProviderPathShape::canDragObjects() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ViewProviderPathShape::canDragObject(App::DocumentObject* obj) const
|
||||
{
|
||||
return obj && obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId());
|
||||
}
|
||||
|
||||
void ViewProviderPathShape::dragObject(App::DocumentObject* obj)
|
||||
{
|
||||
Path::FeatureShape *feature = static_cast<Path::FeatureShape*>(getObject());
|
||||
std::vector<App::DocumentObject*> sources = feature->Sources.getValues();
|
||||
for (std::vector<App::DocumentObject*>::iterator it = sources.begin(); it != sources.end(); ++it) {
|
||||
if (*it == obj) {
|
||||
sources.erase(it);
|
||||
feature->Sources.setValues(sources);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ViewProviderPathShape::canDropObjects() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ViewProviderPathShape::canDropObject(App::DocumentObject* obj) const
|
||||
{
|
||||
return canDragObject(obj);
|
||||
}
|
||||
|
||||
void ViewProviderPathShape::dropObject(App::DocumentObject* obj)
|
||||
{
|
||||
Path::FeatureShape *feature = static_cast<Path::FeatureShape*>(getObject());
|
||||
std::vector<App::DocumentObject*> sources = feature->Sources.getValues();
|
||||
sources.push_back(obj);
|
||||
feature->Sources.setValues(sources);
|
||||
}
|
||||
|
||||
void ViewProviderPathShape::updateData(const App::Property* prop)
|
||||
{
|
||||
PathGui::ViewProviderPath::updateData(prop);
|
||||
if (prop->getTypeId() == App::PropertyLinkList::getClassTypeId()) {
|
||||
std::vector<App::DocumentObject*> pShapes = static_cast<const App::PropertyLinkList*>(prop)->getValues();
|
||||
for (std::vector<App::DocumentObject*>::iterator it = pShapes.begin(); it != pShapes.end(); ++it) {
|
||||
if (*it)
|
||||
Gui::Application::Instance->hideViewProvider(*it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ViewProviderPathShape::onDelete(const std::vector<std::string> &)
|
||||
{
|
||||
// get the input shapes
|
||||
Path::FeatureShape *feature = static_cast<Path::FeatureShape*>(getObject());
|
||||
std::vector<App::DocumentObject*> pShapes =feature->Sources.getValues();
|
||||
for (std::vector<App::DocumentObject*>::iterator it = pShapes.begin(); it != pShapes.end(); ++it) {
|
||||
if (*it)
|
||||
Gui::Application::Instance->showViewProvider(*it);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -34,6 +34,19 @@ class PathGuiExport ViewProviderPathShape: public ViewProviderPath
|
||||
PROPERTY_HEADER(PathGui::ViewProviderPathShape);
|
||||
|
||||
public:
|
||||
|
||||
/// grouping handling
|
||||
virtual std::vector<App::DocumentObject*> claimChildren(void) const;
|
||||
virtual void updateData(const App::Property*);
|
||||
virtual bool onDelete(const std::vector<std::string> &);
|
||||
|
||||
/// drag and drop
|
||||
virtual bool canDragObjects() const;
|
||||
virtual bool canDragObject(App::DocumentObject*) const;
|
||||
virtual void dragObject(App::DocumentObject*);
|
||||
virtual bool canDropObjects() const;
|
||||
virtual bool canDropObject(App::DocumentObject*) const;
|
||||
virtual void dropObject(App::DocumentObject*);
|
||||
|
||||
QIcon getIcon(void) const;
|
||||
};
|
||||
|
||||
@@ -81,12 +81,12 @@ class PathWorkbench (Workbench):
|
||||
# build commands list
|
||||
projcmdlist = ["Path_Job", "Path_Post", "Path_Inspect", "Path_Sanity"]
|
||||
toolcmdlist = ["Path_ToolLibraryEdit", "Path_LoadTool"]
|
||||
prepcmdlist = ["Path_Plane", "Path_Fixture", "Path_ToolLenOffset", "Path_Comment", "Path_Stop", "Path_FaceProfile", "Path_FacePocket", "Path_Custom", "Path_FromShape"]
|
||||
prepcmdlist = ["Path_Plane", "Path_Fixture", "Path_ToolLenOffset", "Path_Comment", "Path_Stop", "Path_FaceProfile", "Path_FacePocket", "Path_Custom", "Path_Shape"]
|
||||
twodopcmdlist = ["Path_Contour", "Path_Profile", "Path_Profile_Edges", "Path_Pocket", "Path_Drilling", "Path_Engrave", "Path_MillFace", "Path_Helix"]
|
||||
threedopcmdlist = ["Path_Surfacing"]
|
||||
modcmdlist = ["Path_Copy", "Path_CompoundExtended", "Path_Array", "Path_SimpleCopy" ]
|
||||
dressupcmdlist = ["PathDressup_Dogbone", "PathDressup_DragKnife", "PathDressup_HoldingTags"]
|
||||
extracmdlist = ["Path_SelectLoop"]
|
||||
extracmdlist = ["Path_SelectLoop", "Path_Shape", "Path_Area", "Path_Area_Workplane"]
|
||||
#modcmdmore = ["Path_Hop",]
|
||||
#remotecmdlist = ["Path_Remote"]
|
||||
|
||||
|
||||
@@ -78,3 +78,28 @@ class _CommandSelectLoop:
|
||||
if FreeCAD.GuiUp:
|
||||
FreeCADGui.addCommand('Path_SelectLoop',_CommandSelectLoop())
|
||||
|
||||
def findShape(shape,subname=None,subtype=None):
|
||||
'''To find a higher oder shape containing the subshape with subname.
|
||||
E.g. to find the wire containing 'Edge1' in shape,
|
||||
findShape(shape,'Edge1','Wires')
|
||||
'''
|
||||
if not subname:
|
||||
return shape
|
||||
ret = shape.getElement(subname)
|
||||
if not subtype or not ret or ret.isNull():
|
||||
return ret;
|
||||
if subname.startswith('Face'):
|
||||
tp = 'Faces'
|
||||
elif subname.startswith('Edge'):
|
||||
tp = 'Edges'
|
||||
elif subname.startswith('Vertex'):
|
||||
tp = 'Vertex'
|
||||
else:
|
||||
return ret
|
||||
for obj in getattr(shape,subtype):
|
||||
for sobj in getattr(obj,tp):
|
||||
if sobj.isEqual(ret):
|
||||
return obj
|
||||
return ret
|
||||
|
||||
|
||||
|
||||
@@ -10,7 +10,11 @@
|
||||
|
||||
double CArea::m_accuracy = 0.01;
|
||||
double CArea::m_units = 1.0;
|
||||
bool CArea::m_clipper_simple = false;
|
||||
double CArea::m_clipper_clean_distance = 0.0;
|
||||
bool CArea::m_fit_arcs = true;
|
||||
int CArea::m_min_arc_points = 4;
|
||||
int CArea::m_max_arc_points = 100;
|
||||
double CArea::m_single_area_processing_length = 0.0;
|
||||
double CArea::m_processing_done = 0.0;
|
||||
bool CArea::m_please_abort = false;
|
||||
@@ -20,6 +24,24 @@ bool CArea::m_set_processing_length_in_split = false;
|
||||
double CArea::m_after_MakeOffsets_length = 0.0;
|
||||
//static const double PI = 3.1415926535897932;
|
||||
|
||||
#define _CAREA_PARAM_DEFINE(_class,_type,_name) \
|
||||
_type CArea::get_##_name() {return _class::_name;}\
|
||||
void CArea::set_##_name(_type _name) {_class::_name = _name;}
|
||||
|
||||
#define CAREA_PARAM_DEFINE(_type,_name) \
|
||||
_type CArea::get_##_name() {return m_##_name;}\
|
||||
void CArea::set_##_name(_type _name) {m_##_name = _name;}
|
||||
|
||||
_CAREA_PARAM_DEFINE(Point,double,tolerance);
|
||||
CAREA_PARAM_DEFINE(bool,fit_arcs)
|
||||
CAREA_PARAM_DEFINE(bool,clipper_simple);
|
||||
CAREA_PARAM_DEFINE(double,clipper_clean_distance);
|
||||
CAREA_PARAM_DEFINE(double,accuracy);
|
||||
CAREA_PARAM_DEFINE(double,units);
|
||||
CAREA_PARAM_DEFINE(short,min_arc_points);
|
||||
CAREA_PARAM_DEFINE(short,max_arc_points);
|
||||
CAREA_PARAM_DEFINE(double,clipper_scale);
|
||||
|
||||
void CArea::append(const CCurve& curve)
|
||||
{
|
||||
m_curves.push_back(curve);
|
||||
@@ -51,6 +73,75 @@ Point CArea::NearestPoint(const Point& p)const
|
||||
return best_point;
|
||||
}
|
||||
|
||||
void CArea::ChangeStartToNearest(const Point *point, double min_dist)
|
||||
{
|
||||
for(std::list<CCurve>::iterator It=m_curves.begin(),ItNext=It;
|
||||
It != m_curves.end(); It=ItNext)
|
||||
{
|
||||
++ItNext;
|
||||
if(It->m_vertices.size()<=1)
|
||||
m_curves.erase(It);
|
||||
}
|
||||
|
||||
if(m_curves.empty()) return;
|
||||
|
||||
std::list<CCurve> curves;
|
||||
Point p;
|
||||
if(point) p =*point;
|
||||
if(min_dist < Point::tolerance)
|
||||
min_dist = Point::tolerance;
|
||||
|
||||
while(m_curves.size()) {
|
||||
std::list<CCurve>::iterator It=m_curves.begin();
|
||||
std::list<CCurve>::iterator ItBest=It++;
|
||||
Point best_point = ItBest->NearestPoint(p);
|
||||
double best_dist = p.dist(best_point);
|
||||
for(; It != m_curves.end(); ++It)
|
||||
{
|
||||
const CCurve& curve = *It;
|
||||
Point near_point;
|
||||
double dist;
|
||||
if(min_dist>Point::tolerance && !curve.IsClosed()) {
|
||||
double d1 = curve.m_vertices.front().m_p.dist(p);
|
||||
double d2 = curve.m_vertices.back().m_p.dist(p);
|
||||
if(d1<d2) {
|
||||
dist = d1;
|
||||
near_point = curve.m_vertices.front().m_p;
|
||||
}else{
|
||||
dist = d2;
|
||||
near_point = curve.m_vertices.back().m_p;
|
||||
}
|
||||
}else{
|
||||
near_point = curve.NearestPoint(p);
|
||||
dist = near_point.dist(p);
|
||||
}
|
||||
if(dist < best_dist)
|
||||
{
|
||||
best_dist = dist;
|
||||
best_point = near_point;
|
||||
ItBest = It;
|
||||
}
|
||||
}
|
||||
if(ItBest->IsClosed()) {
|
||||
ItBest->ChangeStart(best_point);
|
||||
}else{
|
||||
double dfront = ItBest->m_vertices.front().m_p.dist(best_point);
|
||||
double dback = ItBest->m_vertices.back().m_p.dist(best_point);
|
||||
if(min_dist>Point::tolerance && dfront>min_dist && dback>min_dist) {
|
||||
ItBest->Break(best_point);
|
||||
m_curves.push_back(*ItBest);
|
||||
m_curves.back().ChangeEnd(best_point);
|
||||
ItBest->ChangeStart(best_point);
|
||||
}else if(dfront>dback)
|
||||
ItBest->Reverse();
|
||||
}
|
||||
curves.splice(curves.end(),m_curves,ItBest);
|
||||
p = curves.back().m_vertices.back().m_p;
|
||||
}
|
||||
m_curves.splice(m_curves.end(),curves);
|
||||
}
|
||||
|
||||
|
||||
void CArea::GetBox(CBox2D &box)
|
||||
{
|
||||
for(std::list<CCurve>::iterator It = m_curves.begin(); It != m_curves.end(); It++)
|
||||
@@ -70,17 +161,22 @@ void CArea::Reorder()
|
||||
// returns 1, if the curves are overlapping
|
||||
|
||||
CAreaOrderer ao;
|
||||
for(std::list<CCurve>::iterator It = m_curves.begin(); It != m_curves.end(); It++)
|
||||
for(std::list<CCurve>::iterator It = m_curves.begin(), ItNext=It; It != m_curves.end(); It=ItNext)
|
||||
{
|
||||
++ItNext;
|
||||
CCurve& curve = *It;
|
||||
ao.Insert(&curve);
|
||||
if(!It->IsClosed())
|
||||
continue;
|
||||
ao.Insert(make_shared<CCurve>(curve));
|
||||
if(m_set_processing_length_in_split)
|
||||
{
|
||||
CArea::m_processing_done += (m_split_processing_length / m_curves.size());
|
||||
}
|
||||
m_curves.erase(It);
|
||||
}
|
||||
|
||||
*this = ao.ResultArea();
|
||||
if(ao.m_top_level)
|
||||
ao.m_top_level->GetArea(*this);
|
||||
}
|
||||
|
||||
class ZigZag
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#define AREA_HEADER
|
||||
|
||||
#include "Curve.h"
|
||||
#include "clipper.hpp"
|
||||
|
||||
enum PocketMode
|
||||
{
|
||||
@@ -42,7 +43,11 @@ public:
|
||||
std::list<CCurve> m_curves;
|
||||
static double m_accuracy;
|
||||
static double m_units; // 1.0 for mm, 25.4 for inches. All points are multiplied by this before going to the engine
|
||||
static bool m_clipper_simple;
|
||||
static double m_clipper_clean_distance;
|
||||
static bool m_fit_arcs;
|
||||
static int m_min_arc_points;
|
||||
static int m_max_arc_points;
|
||||
static double m_processing_done; // 0.0 to 100.0, set inside MakeOnePocketCurve
|
||||
static double m_single_area_processing_length;
|
||||
static double m_after_MakeOffsets_length;
|
||||
@@ -50,6 +55,7 @@ public:
|
||||
static double m_split_processing_length;
|
||||
static bool m_set_processing_length_in_split;
|
||||
static bool m_please_abort; // the user sets this from another thread, to tell MakeOnePocketCurve to finish with no result.
|
||||
static double m_clipper_scale;
|
||||
|
||||
void append(const CCurve& curve);
|
||||
void Subtract(const CArea& a2);
|
||||
@@ -58,6 +64,11 @@ public:
|
||||
static CArea UniteCurves(std::list<CCurve> &curves);
|
||||
void Xor(const CArea& a2);
|
||||
void Offset(double inwards_value);
|
||||
void OffsetWithClipper(double offset,
|
||||
ClipperLib::JoinType joinType=ClipperLib::jtRound,
|
||||
ClipperLib::EndType endType=ClipperLib::etOpenRound,
|
||||
double miterLimit = 5.0,
|
||||
double roundPrecision = 0.0);
|
||||
void Thicken(double value);
|
||||
void FitArcs();
|
||||
unsigned int num_curves(){return static_cast<int>(m_curves.size());}
|
||||
@@ -73,6 +84,30 @@ public:
|
||||
void SpanIntersections(const Span& span, std::list<Point> &pts)const;
|
||||
void CurveIntersections(const CCurve& curve, std::list<Point> &pts)const;
|
||||
void InsideCurves(const CCurve& curve, std::list<CCurve> &curves_inside)const;
|
||||
|
||||
void ChangeStartToNearest(const Point *pstart=NULL, double min_dist=1.0);
|
||||
|
||||
//Avoid outside direct accessing static member variable because of Windows DLL issue
|
||||
#define CAREA_PARAM_DECLARE(_type,_name) \
|
||||
static _type get_##_name();\
|
||||
static void set_##_name(_type _name);
|
||||
|
||||
CAREA_PARAM_DECLARE(double,tolerance);
|
||||
CAREA_PARAM_DECLARE(bool,fit_arcs)
|
||||
CAREA_PARAM_DECLARE(bool,clipper_simple);
|
||||
CAREA_PARAM_DECLARE(double,clipper_clean_distance);
|
||||
CAREA_PARAM_DECLARE(double,accuracy);
|
||||
CAREA_PARAM_DECLARE(double,units);
|
||||
CAREA_PARAM_DECLARE(short,min_arc_points);
|
||||
CAREA_PARAM_DECLARE(short,max_arc_points);
|
||||
CAREA_PARAM_DECLARE(double,clipper_scale);
|
||||
|
||||
// Following functions is add to operate on possible open curves
|
||||
void PopulateClipper(ClipperLib::Clipper &c, ClipperLib::PolyType type) const;
|
||||
void Clip(ClipperLib::ClipType op,
|
||||
const CArea *a,
|
||||
ClipperLib::PolyFillType subjFillType = ClipperLib::pftEvenOdd,
|
||||
ClipperLib::PolyFillType clipFillType = ClipperLib::pftEvenOdd);
|
||||
};
|
||||
|
||||
enum eOverlapType
|
||||
|
||||
@@ -12,7 +12,7 @@ using namespace ClipperLib;
|
||||
bool CArea::HolesLinked(){ return false; }
|
||||
|
||||
//static const double PI = 3.1415926535897932;
|
||||
static double Clipper4Factor = 10000.0;
|
||||
double CArea::m_clipper_scale = 10000.0;
|
||||
|
||||
class DoubleAreaPoint
|
||||
{
|
||||
@@ -20,8 +20,8 @@ public:
|
||||
double X, Y;
|
||||
|
||||
DoubleAreaPoint(double x, double y){X = x; Y = y;}
|
||||
DoubleAreaPoint(const IntPoint& p){X = (double)(p.X) / Clipper4Factor; Y = (double)(p.Y) / Clipper4Factor;}
|
||||
IntPoint int_point(){return IntPoint((long64)(X * Clipper4Factor), (long64)(Y * Clipper4Factor));}
|
||||
DoubleAreaPoint(const IntPoint& p){X = (double)(p.X) / CArea::m_clipper_scale; Y = (double)(p.Y) / CArea::m_clipper_scale;}
|
||||
IntPoint int_point(){return IntPoint((long64)(X * CArea::m_clipper_scale), (long64)(Y * CArea::m_clipper_scale));}
|
||||
};
|
||||
|
||||
static std::list<DoubleAreaPoint> pts_for_AddVertex;
|
||||
@@ -81,10 +81,10 @@ static void AddVertex(const CVertex& vertex, const CVertex* prev_vertex)
|
||||
else
|
||||
Segments=(int)ceil(-phit/dphi);
|
||||
|
||||
if (Segments < 1)
|
||||
Segments=1;
|
||||
if (Segments > 100)
|
||||
Segments=100;
|
||||
if (Segments < CArea::m_min_arc_points)
|
||||
Segments = CArea::m_min_arc_points;
|
||||
if (Segments > CArea::m_max_arc_points)
|
||||
Segments=CArea::m_max_arc_points;
|
||||
|
||||
dphi=phit/(Segments);
|
||||
|
||||
@@ -139,6 +139,7 @@ static void MakeLoop(const DoubleAreaPoint &pt0, const DoubleAreaPoint &pt1, con
|
||||
static void OffsetWithLoops(const TPolyPolygon &pp, TPolyPolygon &pp_new, double inwards_value)
|
||||
{
|
||||
Clipper c;
|
||||
c.StrictlySimple(CArea::m_clipper_simple);
|
||||
|
||||
bool inwards = (inwards_value > 0);
|
||||
bool reverse = false;
|
||||
@@ -251,6 +252,7 @@ static void MakeObround(const Point &pt0, const CVertex &vt1, double radius)
|
||||
static void OffsetSpansWithObrounds(const CArea& area, TPolyPolygon &pp_new, double radius)
|
||||
{
|
||||
Clipper c;
|
||||
c.StrictlySimple(CArea::m_clipper_simple);
|
||||
|
||||
|
||||
for(std::list<CCurve>::const_iterator It = area.m_curves.begin(); It != area.m_curves.end(); It++)
|
||||
@@ -296,48 +298,14 @@ static void OffsetSpansWithObrounds(const CArea& area, TPolyPolygon &pp_new, dou
|
||||
}
|
||||
}
|
||||
|
||||
static void MakePolyPoly( const CArea& area, TPolyPolygon &pp, bool reverse = true ){
|
||||
pp.clear();
|
||||
|
||||
for(std::list<CCurve>::const_iterator It = area.m_curves.begin(); It != area.m_curves.end(); It++)
|
||||
{
|
||||
pts_for_AddVertex.clear();
|
||||
const CCurve& curve = *It;
|
||||
const CVertex* prev_vertex = NULL;
|
||||
for(std::list<CVertex>::const_iterator It2 = curve.m_vertices.begin(); It2 != curve.m_vertices.end(); It2++)
|
||||
{
|
||||
const CVertex& vertex = *It2;
|
||||
if(prev_vertex)AddVertex(vertex, prev_vertex);
|
||||
prev_vertex = &vertex;
|
||||
}
|
||||
|
||||
TPolygon p;
|
||||
p.resize(pts_for_AddVertex.size());
|
||||
if(reverse)
|
||||
{
|
||||
std::size_t i = pts_for_AddVertex.size() - 1;// clipper wants them the opposite way to CArea
|
||||
for(std::list<DoubleAreaPoint>::iterator It = pts_for_AddVertex.begin(); It != pts_for_AddVertex.end(); It++, i--)
|
||||
{
|
||||
p[i] = It->int_point();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int i = 0;
|
||||
for(std::list<DoubleAreaPoint>::iterator It = pts_for_AddVertex.begin(); It != pts_for_AddVertex.end(); It++, i++)
|
||||
{
|
||||
p[i] = It->int_point();
|
||||
}
|
||||
}
|
||||
|
||||
pp.push_back(p);
|
||||
}
|
||||
}
|
||||
|
||||
static void MakePoly(const CCurve& curve, TPolygon &p)
|
||||
static void MakePoly(const CCurve& curve, TPolygon &p, bool reverse = false)
|
||||
{
|
||||
pts_for_AddVertex.clear();
|
||||
const CVertex* prev_vertex = NULL;
|
||||
|
||||
if(!curve.m_vertices.size()) return;
|
||||
if(!curve.IsClosed()) AddVertex(curve.m_vertices.front(),NULL);
|
||||
|
||||
for (std::list<CVertex>::const_iterator It2 = curve.m_vertices.begin(); It2 != curve.m_vertices.end(); It2++)
|
||||
{
|
||||
const CVertex& vertex = *It2;
|
||||
@@ -346,6 +314,15 @@ static void MakePoly(const CCurve& curve, TPolygon &p)
|
||||
}
|
||||
|
||||
p.resize(pts_for_AddVertex.size());
|
||||
if(reverse)
|
||||
{
|
||||
std::size_t i = pts_for_AddVertex.size() - 1;// clipper wants them the opposite way to CArea
|
||||
for(std::list<DoubleAreaPoint>::iterator It = pts_for_AddVertex.begin(); It != pts_for_AddVertex.end(); It++, i--)
|
||||
{
|
||||
p[i] = It->int_point();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int i = 0;
|
||||
for (std::list<DoubleAreaPoint>::iterator It = pts_for_AddVertex.begin(); It != pts_for_AddVertex.end(); It++, i++)
|
||||
@@ -355,8 +332,21 @@ static void MakePoly(const CCurve& curve, TPolygon &p)
|
||||
}
|
||||
}
|
||||
|
||||
static void SetFromResult( CCurve& curve, const TPolygon& p, bool reverse = true )
|
||||
static void MakePolyPoly( const CArea& area, TPolyPolygon &pp, bool reverse = true ){
|
||||
pp.clear();
|
||||
|
||||
for(std::list<CCurve>::const_iterator It = area.m_curves.begin(); It != area.m_curves.end(); It++)
|
||||
{
|
||||
pp.push_back(TPolygon());
|
||||
MakePoly(*It,pp.back(),reverse);
|
||||
}
|
||||
}
|
||||
|
||||
static void SetFromResult( CCurve& curve, TPolygon& p, bool reverse = true )
|
||||
{
|
||||
if(CArea::m_clipper_clean_distance >= Point::tolerance)
|
||||
CleanPolygon(p,CArea::m_clipper_clean_distance);
|
||||
|
||||
for(unsigned int j = 0; j < p.size(); j++)
|
||||
{
|
||||
const IntPoint &pt = p[j];
|
||||
@@ -372,14 +362,14 @@ static void SetFromResult( CCurve& curve, const TPolygon& p, bool reverse = true
|
||||
if(CArea::m_fit_arcs)curve.FitArcs();
|
||||
}
|
||||
|
||||
static void SetFromResult( CArea& area, const TPolyPolygon& pp, bool reverse = true )
|
||||
static void SetFromResult( CArea& area, TPolyPolygon& pp, bool reverse = true )
|
||||
{
|
||||
// delete existing geometry
|
||||
area.m_curves.clear();
|
||||
|
||||
for(unsigned int i = 0; i < pp.size(); i++)
|
||||
{
|
||||
const TPolygon& p = pp[i];
|
||||
TPolygon& p = pp[i];
|
||||
|
||||
area.m_curves.push_back(CCurve());
|
||||
CCurve &curve = area.m_curves.back();
|
||||
@@ -390,6 +380,7 @@ static void SetFromResult( CArea& area, const TPolyPolygon& pp, bool reverse = t
|
||||
void CArea::Subtract(const CArea& a2)
|
||||
{
|
||||
Clipper c;
|
||||
c.StrictlySimple(CArea::m_clipper_simple);
|
||||
TPolyPolygon pp1, pp2;
|
||||
MakePolyPoly(*this, pp1);
|
||||
MakePolyPoly(a2, pp2);
|
||||
@@ -403,6 +394,7 @@ void CArea::Subtract(const CArea& a2)
|
||||
void CArea::Intersect(const CArea& a2)
|
||||
{
|
||||
Clipper c;
|
||||
c.StrictlySimple(CArea::m_clipper_simple);
|
||||
TPolyPolygon pp1, pp2;
|
||||
MakePolyPoly(*this, pp1);
|
||||
MakePolyPoly(a2, pp2);
|
||||
@@ -416,6 +408,7 @@ void CArea::Intersect(const CArea& a2)
|
||||
void CArea::Union(const CArea& a2)
|
||||
{
|
||||
Clipper c;
|
||||
c.StrictlySimple(CArea::m_clipper_simple);
|
||||
TPolyPolygon pp1, pp2;
|
||||
MakePolyPoly(*this, pp1);
|
||||
MakePolyPoly(a2, pp2);
|
||||
@@ -430,6 +423,7 @@ void CArea::Union(const CArea& a2)
|
||||
CArea CArea::UniteCurves(std::list<CCurve> &curves)
|
||||
{
|
||||
Clipper c;
|
||||
c.StrictlySimple(CArea::m_clipper_simple);
|
||||
|
||||
TPolyPolygon pp;
|
||||
|
||||
@@ -452,6 +446,7 @@ CArea CArea::UniteCurves(std::list<CCurve> &curves)
|
||||
void CArea::Xor(const CArea& a2)
|
||||
{
|
||||
Clipper c;
|
||||
c.StrictlySimple(CArea::m_clipper_simple);
|
||||
TPolyPolygon pp1, pp2;
|
||||
MakePolyPoly(*this, pp1);
|
||||
MakePolyPoly(a2, pp2);
|
||||
@@ -471,6 +466,73 @@ void CArea::Offset(double inwards_value)
|
||||
this->Reorder();
|
||||
}
|
||||
|
||||
void CArea::PopulateClipper(Clipper &c, PolyType type) const
|
||||
{
|
||||
int skipped = 0;
|
||||
for (std::list<CCurve>::const_iterator It = m_curves.begin(); It != m_curves.end(); It++)
|
||||
{
|
||||
const CCurve &curve = *It;
|
||||
bool closed = curve.IsClosed();
|
||||
if(!closed) {
|
||||
if(type == ptClip){
|
||||
++skipped;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
TPolygon p;
|
||||
MakePoly(curve, p, false);
|
||||
c.AddPath(p, type, closed);
|
||||
}
|
||||
if(skipped)
|
||||
std::cout << "libarea: warning skipped " << skipped << " open wires" << std::endl;
|
||||
}
|
||||
|
||||
void CArea::Clip(ClipType op, const CArea *a,
|
||||
PolyFillType subjFillType,
|
||||
PolyFillType clipFillType)
|
||||
{
|
||||
Clipper c;
|
||||
c.StrictlySimple(CArea::m_clipper_simple);
|
||||
PopulateClipper(c,ptSubject);
|
||||
if(a) a->PopulateClipper(c,ptClip);
|
||||
PolyTree tree;
|
||||
c.Execute(op, tree, subjFillType,clipFillType);
|
||||
TPolyPolygon solution;
|
||||
PolyTreeToPaths(tree,solution);
|
||||
SetFromResult(*this, solution);
|
||||
}
|
||||
|
||||
void CArea::OffsetWithClipper(double offset,
|
||||
JoinType joinType/* =jtRound */,
|
||||
EndType endType/* =etOpenRound */,
|
||||
double miterLimit/* = 5.0 */,
|
||||
double roundPrecision/* = 0.0 */)
|
||||
{
|
||||
offset *= m_units*m_clipper_scale;
|
||||
if(roundPrecision == 0.0) {
|
||||
// Clipper roundPrecision definition: https://goo.gl/4odfQh
|
||||
double dphi=acos(1.0-m_accuracy*m_clipper_scale/fabs(offset));
|
||||
int Segments=(int)ceil(PI/dphi);
|
||||
if (Segments < 2*CArea::m_min_arc_points)
|
||||
Segments = 2*CArea::m_min_arc_points;
|
||||
if (Segments > CArea::m_max_arc_points)
|
||||
Segments=CArea::m_max_arc_points;
|
||||
dphi = PI/Segments;
|
||||
roundPrecision = (1.0-cos(dphi))*fabs(offset);
|
||||
}else
|
||||
roundPrecision *= m_clipper_scale;
|
||||
|
||||
ClipperOffset clipper(miterLimit,roundPrecision);
|
||||
TPolyPolygon pp, pp2;
|
||||
MakePolyPoly(*this, pp, false);
|
||||
int i=0;
|
||||
for(const CCurve &c : m_curves)
|
||||
clipper.AddPath(pp[i++],joinType,c.IsClosed()?etClosedPolygon:endType);
|
||||
clipper.Execute(pp2,(long64)(offset));
|
||||
SetFromResult(*this, pp2, false);
|
||||
this->Reorder();
|
||||
}
|
||||
|
||||
void CArea::Thicken(double value)
|
||||
{
|
||||
TPolyPolygon pp;
|
||||
|
||||
@@ -30,29 +30,27 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "AreaOrderer.h"
|
||||
#include "Area.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
CAreaOrderer* CInnerCurves::area_orderer = NULL;
|
||||
|
||||
CInnerCurves::CInnerCurves(CInnerCurves* pOuter, const CCurve* curve)
|
||||
CInnerCurves::CInnerCurves(shared_ptr<CInnerCurves> pOuter, shared_ptr<CCurve> curve)
|
||||
:m_pOuter(pOuter)
|
||||
,m_curve(curve)
|
||||
{
|
||||
m_pOuter = pOuter;
|
||||
m_curve = curve;
|
||||
m_unite_area = NULL;
|
||||
}
|
||||
|
||||
CInnerCurves::~CInnerCurves()
|
||||
{
|
||||
delete m_unite_area;
|
||||
}
|
||||
|
||||
void CInnerCurves::Insert(const CCurve* pcurve)
|
||||
void CInnerCurves::Insert(shared_ptr<CCurve> pcurve)
|
||||
{
|
||||
std::list<CInnerCurves*> outside_of_these;
|
||||
std::list<CInnerCurves*> crossing_these;
|
||||
std::list<shared_ptr<CInnerCurves> > outside_of_these;
|
||||
std::list<shared_ptr<CInnerCurves> > crossing_these;
|
||||
|
||||
// check all inner curves
|
||||
for(std::set<CInnerCurves*>::iterator It = m_inner_curves.begin(); It != m_inner_curves.end(); It++)
|
||||
{
|
||||
CInnerCurves* c = *It;
|
||||
for(shared_ptr<CInnerCurves> c : m_inner_curves) {
|
||||
|
||||
switch(GetOverlapType(*pcurve, *(c->m_curve)))
|
||||
{
|
||||
@@ -75,28 +73,24 @@ void CInnerCurves::Insert(const CCurve* pcurve)
|
||||
}
|
||||
|
||||
// add as a new inner
|
||||
CInnerCurves* new_item = new CInnerCurves(this, pcurve);
|
||||
shared_ptr<CInnerCurves> new_item(new CInnerCurves(shared_from_this(), pcurve));
|
||||
this->m_inner_curves.insert(new_item);
|
||||
|
||||
for(std::list<CInnerCurves*>::iterator It = outside_of_these.begin(); It != outside_of_these.end(); It++)
|
||||
{
|
||||
for(shared_ptr<CInnerCurves> c : outside_of_these) {
|
||||
// move items
|
||||
CInnerCurves* c = *It;
|
||||
c->m_pOuter = new_item;
|
||||
new_item->m_inner_curves.insert(c);
|
||||
this->m_inner_curves.erase(c);
|
||||
}
|
||||
|
||||
for(std::list<CInnerCurves*>::iterator It = crossing_these.begin(); It != crossing_these.end(); It++)
|
||||
{
|
||||
for(shared_ptr<CInnerCurves> c : crossing_these) {
|
||||
// unite these
|
||||
CInnerCurves* c = *It;
|
||||
new_item->Unite(c);
|
||||
this->m_inner_curves.erase(c);
|
||||
}
|
||||
}
|
||||
|
||||
void CInnerCurves::GetArea(CArea &area, bool outside, bool use_curve)const
|
||||
void CInnerCurves::GetArea(CArea &area, bool outside, bool use_curve)
|
||||
{
|
||||
if(use_curve && m_curve)
|
||||
{
|
||||
@@ -104,11 +98,9 @@ void CInnerCurves::GetArea(CArea &area, bool outside, bool use_curve)const
|
||||
outside = !outside;
|
||||
}
|
||||
|
||||
std::list<const CInnerCurves*> do_after;
|
||||
std::list<shared_ptr<CInnerCurves> > do_after;
|
||||
|
||||
for(std::set<CInnerCurves*>::const_iterator It = m_inner_curves.begin(); It != m_inner_curves.end(); It++)
|
||||
{
|
||||
const CInnerCurves* c = *It;
|
||||
for(shared_ptr<CInnerCurves> c: m_inner_curves) {
|
||||
area.m_curves.push_back(*c->m_curve);
|
||||
if(!outside)area.m_curves.back().Reverse();
|
||||
|
||||
@@ -116,20 +108,16 @@ void CInnerCurves::GetArea(CArea &area, bool outside, bool use_curve)const
|
||||
else do_after.push_back(c);
|
||||
}
|
||||
|
||||
for(std::list<const CInnerCurves*>::iterator It = do_after.begin(); It != do_after.end(); It++)
|
||||
{
|
||||
const CInnerCurves* c = *It;
|
||||
for(shared_ptr<CInnerCurves> c : do_after)
|
||||
c->GetArea(area, !outside, false);
|
||||
}
|
||||
}
|
||||
|
||||
void CInnerCurves::Unite(const CInnerCurves* c)
|
||||
void CInnerCurves::Unite(shared_ptr<CInnerCurves> c)
|
||||
{
|
||||
// unite all the curves in c, with this one
|
||||
CArea* new_area = new CArea();
|
||||
shared_ptr<CArea> new_area(new CArea());
|
||||
new_area->m_curves.push_back(*m_curve);
|
||||
delete m_unite_area;
|
||||
m_unite_area = new_area;
|
||||
m_unite_area = new_area;
|
||||
|
||||
CArea a2;
|
||||
c->GetArea(a2);
|
||||
@@ -140,21 +128,21 @@ void CInnerCurves::Unite(const CInnerCurves* c)
|
||||
{
|
||||
CCurve &curve = *It;
|
||||
if(It == m_unite_area->m_curves.begin())
|
||||
m_curve = &curve;
|
||||
m_curve = make_shared<CCurve>(curve);
|
||||
else
|
||||
{
|
||||
if(curve.IsClockwise())curve.Reverse();
|
||||
Insert(&curve);
|
||||
Insert(shared_ptr<CCurve>(new CCurve(curve)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CAreaOrderer::CAreaOrderer()
|
||||
:m_top_level(make_shared<CInnerCurves>())
|
||||
{
|
||||
m_top_level = new CInnerCurves(NULL, NULL);
|
||||
}
|
||||
|
||||
void CAreaOrderer::Insert(CCurve* pcurve)
|
||||
void CAreaOrderer::Insert(shared_ptr<CCurve> pcurve)
|
||||
{
|
||||
CInnerCurves::area_orderer = this;
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include <list>
|
||||
#include <set>
|
||||
|
||||
@@ -36,30 +37,31 @@ class CCurve;
|
||||
|
||||
class CAreaOrderer;
|
||||
|
||||
class CInnerCurves
|
||||
class CInnerCurves: public std::enable_shared_from_this<CInnerCurves>
|
||||
{
|
||||
CInnerCurves* m_pOuter;
|
||||
const CCurve* m_curve; // always empty if top level
|
||||
std::set<CInnerCurves*> m_inner_curves;
|
||||
CArea *m_unite_area; // new curves made by uniting are stored here
|
||||
std::shared_ptr<CInnerCurves> m_pOuter;
|
||||
std::shared_ptr<CCurve> m_curve; // always empty if top level
|
||||
std::set<std::shared_ptr<CInnerCurves> > m_inner_curves;
|
||||
std::shared_ptr<CArea> m_unite_area; // new curves made by uniting are stored here
|
||||
|
||||
public:
|
||||
static CAreaOrderer* area_orderer;
|
||||
CInnerCurves(CInnerCurves* pOuter, const CCurve* curve);
|
||||
CInnerCurves(std::shared_ptr<CInnerCurves> pOuter, std::shared_ptr<CCurve> curve);
|
||||
CInnerCurves(){}
|
||||
~CInnerCurves();
|
||||
|
||||
void Insert(const CCurve* pcurve);
|
||||
void GetArea(CArea &area, bool outside = true, bool use_curve = true)const;
|
||||
void Unite(const CInnerCurves* c);
|
||||
void Insert(std::shared_ptr<CCurve> pcurve);
|
||||
void GetArea(CArea &area, bool outside = true, bool use_curve = true);
|
||||
void Unite(std::shared_ptr<CInnerCurves> c);
|
||||
};
|
||||
|
||||
class CAreaOrderer
|
||||
{
|
||||
public:
|
||||
CInnerCurves* m_top_level;
|
||||
std::shared_ptr<CInnerCurves> m_top_level;
|
||||
|
||||
CAreaOrderer();
|
||||
|
||||
void Insert(CCurve* pcurve);
|
||||
void Insert(std::shared_ptr<CCurve> pcurve);
|
||||
CArea ResultArea()const;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -65,37 +65,52 @@ file(GLOB headers "${CMAKE_CURRENT_SOURCE_DIR}/*.h")
|
||||
|
||||
# this makes the Python module
|
||||
add_library(
|
||||
area
|
||||
MODULE
|
||||
area-native
|
||||
SHARED
|
||||
${AREA_SRC_COMMON}
|
||||
${AREA_SRC_CLIPPER}
|
||||
${PYAREA_SRC}
|
||||
)
|
||||
|
||||
add_library(
|
||||
area
|
||||
MODULE
|
||||
${PYAREA_SRC}
|
||||
)
|
||||
|
||||
if(MSVC)
|
||||
set(area_LIBS
|
||||
${Boost_LIBRARIES}
|
||||
${PYTHON_LIBRARIES}
|
||||
set(area_native_LIBS
|
||||
debug MSVCRTD.LIB
|
||||
debug MSVCPRTD.LIB
|
||||
optimized MSVCRT.LIB
|
||||
optimized MSVCPRT.LIB
|
||||
)
|
||||
elseif(MINGW)
|
||||
set(area_LIBS
|
||||
${Boost_LIBRARIES}
|
||||
${PYTHON_LIBRARIES}
|
||||
${area_native_LIBS}
|
||||
)
|
||||
elseif(MINGW)
|
||||
set(area_native_LIBS
|
||||
Rpcrt4.lib
|
||||
)
|
||||
set(area_LIBS
|
||||
${Boost_LIBRARIES}
|
||||
${PYTHON_LIBRARIES}
|
||||
${area_native_LIBS}
|
||||
)
|
||||
else(MSVC)
|
||||
set(area_native_LIBS
|
||||
)
|
||||
set(area_LIBS
|
||||
${Boost_LIBRARIES}
|
||||
${PYTHON_LIBRARIES}
|
||||
)
|
||||
endif(MSVC)
|
||||
|
||||
target_link_libraries(area ${area_LIBS})
|
||||
target_link_libraries(area-native ${area_native_LIBS})
|
||||
SET_BIN_DIR(area-native area-native)
|
||||
|
||||
target_link_libraries(area area-native ${area_LIBS} ${area_native_LIBS})
|
||||
SET_BIN_DIR(area area)
|
||||
SET_PYTHON_PREFIX_SUFFIX(area)
|
||||
|
||||
@@ -108,8 +123,20 @@ execute_process(
|
||||
|
||||
message(STATUS "area module (for Path Workbench) will be installed to: " ${CMAKE_INSTALL_LIBDIR})
|
||||
|
||||
if(WIN32)
|
||||
set_target_properties(area-native PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
|
||||
INSTALL(TARGETS area-native
|
||||
RUNTIME DESTINATION bin
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
)
|
||||
else(WIN32)
|
||||
INSTALL(TARGETS area-native
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
)
|
||||
endif(WIN32)
|
||||
|
||||
# this installs the python library
|
||||
install(
|
||||
TARGETS area
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
)
|
||||
|
||||
@@ -13,6 +13,12 @@ double Point::tolerance = 0.001;
|
||||
|
||||
//static const double PI = 3.1415926535897932; duplicated in kurve/geometry.h
|
||||
|
||||
//This function is moved from header here to solve windows DLL not export
|
||||
//static variable problem
|
||||
bool Point::operator==(const Point& p)const{
|
||||
return fabs(x-p.x)<tolerance && fabs(y-p.y)<tolerance;
|
||||
}
|
||||
|
||||
double Point::length()const
|
||||
{
|
||||
return sqrt( x*x + y*y );
|
||||
|
||||
@@ -48,7 +48,7 @@ public:
|
||||
const Point operator-(const Point& p)const{return Point(x - p.x, y - p.y);}
|
||||
const Point operator*(double d)const{return Point(x * d, y * d);}
|
||||
const Point operator/(double d)const{return Point(x / d, y / d);}
|
||||
bool operator==(const Point& p)const{return fabs(x-p.x)<tolerance && fabs(y-p.y)<tolerance;}
|
||||
bool operator==(const Point& p)const;
|
||||
bool operator!=(const Point &p)const{ return !(*this == p);}
|
||||
double dist(const Point &p)const{double dx = p.x - x; double dy = p.y - y; return sqrt(dx*dx + dy*dy);}
|
||||
double length()const;
|
||||
|
||||
@@ -80,8 +80,8 @@ static void print_curve(const CCurve& c)
|
||||
for(std::list<CVertex>::const_iterator It = c.m_vertices.begin(); It != c.m_vertices.end(); It++, i++)
|
||||
{
|
||||
const CVertex& vertex = *It;
|
||||
printf("vertex %d type = %d, x = %g, y = %g", i+1, vertex.m_type, vertex.m_p.x / CArea::m_units, vertex.m_p.y / CArea::m_units);
|
||||
if(vertex.m_type)printf(", xc = %g, yc = %g", vertex.m_c.x / CArea::m_units, vertex.m_c.y / CArea::m_units);
|
||||
printf("vertex %d type = %d, x = %g, y = %g", i+1, vertex.m_type, vertex.m_p.x / CArea::get_units(), vertex.m_p.y / CArea::get_units());
|
||||
if(vertex.m_type)printf(", xc = %g, yc = %g", vertex.m_c.x / CArea::get_units(), vertex.m_c.y / CArea::get_units());
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
@@ -112,12 +112,12 @@ static CVertex LastVertex(const CCurve& curve)
|
||||
|
||||
static void set_units(double units)
|
||||
{
|
||||
CArea::m_units = units;
|
||||
CArea::set_units(units);
|
||||
}
|
||||
|
||||
static double get_units()
|
||||
{
|
||||
return CArea::m_units;
|
||||
return CArea::get_units();
|
||||
}
|
||||
|
||||
static bool holes_linked()
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
//#define use_xyz
|
||||
|
||||
//use_lines: Enables line clipping. Adds a very minor cost to performance.
|
||||
//#define use_lines
|
||||
#define use_lines
|
||||
|
||||
//use_deprecated: Enables temporary support for the obsolete functions
|
||||
//#define use_deprecated
|
||||
|
||||
Reference in New Issue
Block a user