Path: added Path.fromShapes and Path.sortWires
* Path.fromShapes can now convert any number of shapes to Path with optimzied travel distances. It internally uses Path.sortWires to minimize travel distances, and also sort wires by its Z height in case of sectioned wires. * The above python function is impelmented in Path::Area class. * Path::FeatureShape is rewrote to take advantage of these two functions. * Add Path::FeatureAreaView to partially display a Path::FeatureArea's sections.
This commit is contained in:
parent
79a261e868
commit
a3f46a40e9
|
@ -88,4 +88,6 @@ PyMODINIT_FUNC initPath()
|
|||
Path::Area ::init();
|
||||
Path::FeatureArea ::init();
|
||||
Path::FeatureAreaPython ::init();
|
||||
Path::FeatureAreaView ::init();
|
||||
Path::FeatureAreaViewPython ::init();
|
||||
}
|
||||
|
|
|
@ -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,22 @@ 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, sort=True, start=Vector(), " PARAM_PY_ARGS_DOC(ARG,AREA_PARAMS_PATH) ")\n"
|
||||
"\nReturns a Path object from a list of shapes\n"
|
||||
"\n* shapes: input list of shapes.\n"
|
||||
"\n* start (Vector()): optional start position.\n"
|
||||
PARAM_PY_DOC(ARG, AREA_PARAMS_PATH)
|
||||
);
|
||||
add_keyword_method("sortWires",&Module::sortWires,
|
||||
"sortWires(shapes, start=Vector(), params=None, " PARAM_PY_ARGS_DOC(ARG,AREA_PARAMS_SORT_WIRES) ")\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"
|
||||
"\n* params (None): optional dictionary for configuring Path.Area internally used to sort the wires.\n"
|
||||
PARAM_PY_DOC(ARG, AREA_PARAMS_SORT_WIRES)
|
||||
);
|
||||
initialize("This module is the Path module."); // register with Python
|
||||
}
|
||||
|
||||
|
@ -261,7 +316,119 @@ 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)
|
||||
PyObject *pShapes=NULL;
|
||||
PyObject *start=NULL;
|
||||
static char* kwd_list[] = {"shapes", "start",
|
||||
PARAM_FIELD_STRINGS(ARG,AREA_PARAMS_PATH), NULL};
|
||||
if (!PyArg_ParseTupleAndKeywords(args.ptr(), kwds.ptr(),
|
||||
"O|O!" PARAM_PY_KWDS(AREA_PARAMS_PATH), kwd_list,
|
||||
&pShapes, &(Base::VectorPy::Type), &start,
|
||||
PARAM_REF(PARAM_FARG,AREA_PARAMS_PATH)))
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
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,&pstart,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)
|
||||
{
|
||||
AreaParams params;
|
||||
PARAM_PY_DECLARE_INIT(PARAM_FARG,AREA_PARAMS_SORT_WIRES)
|
||||
PyObject *pShapes=NULL;
|
||||
PyObject *start=NULL;
|
||||
PyObject *pParams=NULL;
|
||||
static char* kwd_list[] = {"shapes", "start", "params",
|
||||
PARAM_FIELD_STRINGS(ARG,AREA_PARAMS_SORT_WIRES), NULL};
|
||||
if (!PyArg_ParseTupleAndKeywords(args.ptr(), kwds.ptr(),
|
||||
"O|O!O!" PARAM_PY_KWDS(AREA_PARAMS_SORT_WIRES), kwd_list,
|
||||
&pShapes, &(Base::VectorPy::Type), &start, &PyDict_Type, &pParams,
|
||||
PARAM_REF(PARAM_FARG,AREA_PARAMS_SORT_WIRES)))
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
if(pParams) {
|
||||
static char *kwlist[] = {PARAM_FIELD_STRINGS(NAME,AREA_PARAMS_CONF),NULL};
|
||||
PARAM_PY_DECLARE(PARAM_FNAME,AREA_PARAMS_CONF);
|
||||
#define AREA_SET(_param) \
|
||||
PARAM_FNAME(_param) = \
|
||||
PARAM_TYPED(PARAM_PY_CAST_,_param)(params.PARAM_FNAME(_param));
|
||||
PARAM_FOREACH(AREA_SET,AREA_PARAMS_CONF)
|
||||
if (!PyArg_ParseTupleAndKeywords(NULL, pParams,
|
||||
"|" PARAM_PY_KWDS(AREA_PARAMS_CONF), kwlist,
|
||||
PARAM_REF(PARAM_FNAME,AREA_PARAMS_CONF)))
|
||||
throw Py::Exception();
|
||||
|
||||
#define AREA_GET(_param) \
|
||||
params.PARAM_FNAME(_param) = \
|
||||
PARAM_TYPED(PARAM_CAST_PY_,_param)(PARAM_FNAME(_param));
|
||||
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_WIRES));
|
||||
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()
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
#ifndef _PreComp_
|
||||
#endif
|
||||
|
||||
#include <boost/range/adaptor/reversed.hpp>
|
||||
|
||||
#include <BRepLib.hxx>
|
||||
#include <BRep_Builder.hxx>
|
||||
#include <BRep_Tool.hxx>
|
||||
|
@ -150,6 +152,7 @@ void Area::setPlane(const TopoDS_Shape &shape) {
|
|||
}
|
||||
|
||||
bool Area::isCoplanar(const TopoDS_Shape &s1, const TopoDS_Shape &s2) {
|
||||
if(s1.IsEqual(s2)) return true;
|
||||
TopoDS_Builder builder;
|
||||
TopoDS_Compound comp;
|
||||
builder.MakeCompound(comp);
|
||||
|
@ -161,7 +164,7 @@ bool Area::isCoplanar(const TopoDS_Shape &s1, const TopoDS_Shape &s2) {
|
|||
|
||||
int Area::add(CArea &area, const TopoDS_Shape &shape, const gp_Trsf *trsf,
|
||||
double deflection, const TopoDS_Shape *plane, bool force_coplanar,
|
||||
CArea *areaOpen, bool to_edges, bool reorder)
|
||||
CArea *areaOpen, bool to_edges, bool reorient)
|
||||
{
|
||||
bool haveShape = false;
|
||||
int skipped = 0;
|
||||
|
@ -193,7 +196,7 @@ int Area::add(CArea &area, const TopoDS_Shape &shape, const gp_Trsf *trsf,
|
|||
else if(to_edges) {
|
||||
for (TopExp_Explorer it(wire, TopAbs_EDGE); it.More(); it.Next())
|
||||
add(_areaOpen,BRepBuilderAPI_MakeWire(
|
||||
TopoDS::Edge(it.Current())).Wire(),trsf,deflection);
|
||||
TopoDS::Edge(it.Current())).Wire(),trsf,deflection,true);
|
||||
}else
|
||||
add(_areaOpen,wire,trsf,deflection);
|
||||
}
|
||||
|
@ -210,7 +213,7 @@ int Area::add(CArea &area, const TopoDS_Shape &shape, const gp_Trsf *trsf,
|
|||
}
|
||||
}
|
||||
|
||||
if(reorder)
|
||||
if(reorient)
|
||||
_area.Reorder();
|
||||
area.m_curves.splice(area.m_curves.end(),_area.m_curves);
|
||||
if(areaOpen)
|
||||
|
@ -221,7 +224,7 @@ int Area::add(CArea &area, const TopoDS_Shape &shape, const gp_Trsf *trsf,
|
|||
}
|
||||
|
||||
void Area::add(CArea &area, const TopoDS_Wire& wire,
|
||||
const gp_Trsf *trsf, double deflection)
|
||||
const gp_Trsf *trsf, double deflection, bool to_edges)
|
||||
{
|
||||
CCurve ccurve;
|
||||
BRepTools_WireExplorer xp(trsf?TopoDS::Wire(
|
||||
|
@ -239,26 +242,32 @@ void Area::add(CArea &area, const TopoDS_Wire& wire,
|
|||
switch (curve.GetType()) {
|
||||
case GeomAbs_Line: {
|
||||
ccurve.append(CVertex(Point(p.X(),p.Y())));
|
||||
if(to_edges) {
|
||||
area.append(ccurve);
|
||||
ccurve.m_vertices.pop_front();
|
||||
}
|
||||
break;
|
||||
} case GeomAbs_Circle:{
|
||||
double first = curve.FirstParameter();
|
||||
double last = curve.LastParameter();
|
||||
gp_Circ circle = curve.Circle();
|
||||
gp_Ax1 axis = circle.Axis();
|
||||
int dir = axis.Direction().Z()<0?-1:1;
|
||||
if(reversed) dir = -dir;
|
||||
gp_Pnt loc = axis.Location();
|
||||
if(fabs(first-last)>M_PI) {
|
||||
// Split arc(circle) larger than half circle. This is
|
||||
// translated from PathUtil code. Not sure why it is
|
||||
// needed.
|
||||
gp_Pnt mid = curve.Value((last-first)*0.5+first);
|
||||
ccurve.append(CVertex(dir,Point(mid.X(),mid.Y()),
|
||||
if(!to_edges) {
|
||||
double first = curve.FirstParameter();
|
||||
double last = curve.LastParameter();
|
||||
gp_Circ circle = curve.Circle();
|
||||
gp_Ax1 axis = circle.Axis();
|
||||
int dir = axis.Direction().Z()<0?-1:1;
|
||||
if(reversed) dir = -dir;
|
||||
gp_Pnt loc = axis.Location();
|
||||
if(fabs(first-last)>M_PI) {
|
||||
// Split arc(circle) larger than half circle. Because gcode
|
||||
// can't handle full circle?
|
||||
gp_Pnt mid = curve.Value((last-first)*0.5+first);
|
||||
ccurve.append(CVertex(dir,Point(mid.X(),mid.Y()),
|
||||
Point(loc.X(),loc.Y())));
|
||||
}
|
||||
ccurve.append(CVertex(dir,Point(p.X(),p.Y()),
|
||||
Point(loc.X(),loc.Y())));
|
||||
break;
|
||||
}
|
||||
ccurve.append(CVertex(dir,Point(p.X(),p.Y()),
|
||||
Point(loc.X(),loc.Y())));
|
||||
break;
|
||||
//fall through
|
||||
} default: {
|
||||
// Discretize all other type of curves
|
||||
GCPnts_UniformDeflection discretizer(curve, deflection,
|
||||
|
@ -268,16 +277,22 @@ void Area::add(CArea &area, const TopoDS_Wire& wire,
|
|||
for (int i=1; i<=nbPoints; i++) {
|
||||
gp_Pnt pt = discretizer.Value (i);
|
||||
ccurve.append(CVertex(Point(pt.X(),pt.Y())));
|
||||
if(to_edges) {
|
||||
area.append(ccurve);
|
||||
ccurve.m_vertices.pop_front();
|
||||
}
|
||||
}
|
||||
}else
|
||||
Standard_Failure::Raise("Curve discretization failed");
|
||||
}}
|
||||
}
|
||||
if(BRep_Tool::IsClosed(wire) && !ccurve.IsClosed()) {
|
||||
Base::Console().Warning("ccurve not closed\n");
|
||||
ccurve.append(ccurve.m_vertices.front());
|
||||
if(!to_edges) {
|
||||
if(BRep_Tool::IsClosed(wire) && !ccurve.IsClosed()) {
|
||||
Base::Console().Warning("ccurve not closed\n");
|
||||
ccurve.append(ccurve.m_vertices.front());
|
||||
}
|
||||
area.append(ccurve);
|
||||
}
|
||||
area.append(ccurve);
|
||||
}
|
||||
|
||||
|
||||
|
@ -296,10 +311,32 @@ void Area::clean(bool deleteShapes) {
|
|||
}
|
||||
|
||||
void Area::add(const TopoDS_Shape &shape,short op) {
|
||||
#define AREA_SRC_OP(_param) op
|
||||
PARAM_ENUM_CONVERT(AREA_SRC_OP,PARAM_FNAME,PARAM_ENUM_EXCEPT,AREA_PARAMS_OPCODE);
|
||||
Q_UNUSED(Operation);
|
||||
#define AREA_CONVERT_OP \
|
||||
ClipperLib::ClipType Operation;\
|
||||
switch(op){\
|
||||
case OperationUnion:\
|
||||
Operation = ClipperLib::ctUnion;\
|
||||
break;\
|
||||
case OperationDifference:\
|
||||
Operation = ClipperLib::ctDifference;\
|
||||
break;\
|
||||
case OperationIntersection:\
|
||||
Operation = ClipperLib::ctIntersection;\
|
||||
break;\
|
||||
case OperationXor:\
|
||||
Operation = ClipperLib::ctXor;\
|
||||
break;\
|
||||
default:\
|
||||
throw Base::ValueError("invalid Operation");\
|
||||
}
|
||||
|
||||
if(shape.IsNull())
|
||||
throw Base::ValueError("null shape");
|
||||
|
||||
if(op!=OperationCompound) {
|
||||
AREA_CONVERT_OP;
|
||||
Q_UNUSED(Operation);
|
||||
}
|
||||
bool haveSolid = false;
|
||||
for(TopExp_Explorer it(shape, TopAbs_SOLID);it.More();) {
|
||||
haveSolid = true;
|
||||
|
@ -313,7 +350,7 @@ void Area::add(const TopoDS_Shape &shape,short op) {
|
|||
myHaveSolid = haveSolid;
|
||||
|
||||
clean();
|
||||
if(myShapes.empty())
|
||||
if(op!=OperationCompound && myShapes.empty())
|
||||
op = OperationUnion;
|
||||
myShapes.push_back(Shape(op,shape));
|
||||
}
|
||||
|
@ -330,7 +367,7 @@ void Area::setParams(const AreaParams ¶ms) {
|
|||
}
|
||||
|
||||
void Area::addToBuild(CArea &area, const TopoDS_Shape &shape) {
|
||||
if(!myHaveFace) {
|
||||
if(myParams.Fill==FillAuto && !myHaveFace) {
|
||||
TopExp_Explorer it(shape, TopAbs_FACE);
|
||||
myHaveFace = it.More();
|
||||
}
|
||||
|
@ -342,7 +379,7 @@ void Area::addToBuild(CArea &area, const TopoDS_Shape &shape) {
|
|||
CArea areaOpen;
|
||||
mySkippedShapes += add(area,shape,&myTrsf,myParams.Deflection,plane,
|
||||
myHaveSolid||myParams.Coplanar==CoplanarForce,&areaOpen,
|
||||
myParams.OpenMode==OpenModeEdges,myParams.Reorder);
|
||||
myParams.OpenMode==OpenModeEdges,myParams.Reorient);
|
||||
if(areaOpen.m_curves.size()) {
|
||||
if(&area == myArea.get() || myParams.OpenMode == OpenModeNone)
|
||||
myAreaOpen->m_curves.splice(myAreaOpen->m_curves.end(),areaOpen.m_curves);
|
||||
|
@ -359,7 +396,7 @@ void Area::build() {
|
|||
if(myArea || mySections.size()) return;
|
||||
|
||||
if(myShapes.empty())
|
||||
throw Base::ValueError("Null shape");
|
||||
throw Base::ValueError("no shape added");
|
||||
|
||||
#define AREA_SRC(_param) myParams.PARAM_FNAME(_param)
|
||||
PARAM_ENUM_CONVERT(AREA_SRC,PARAM_FNAME,PARAM_ENUM_EXCEPT,AREA_PARAMS_CLIPPER_FILL);
|
||||
|
@ -368,24 +405,41 @@ void Area::build() {
|
|||
myShapePlane.Nullify();
|
||||
for(const Shape &s : myShapes) {
|
||||
bool haveShape = false;
|
||||
bool done = false;
|
||||
TopoDS_Shape shapePlane;
|
||||
gp_Trsf trsf;
|
||||
gp_Ax3 pos;
|
||||
#define AREA_CHECK_PLANE(_type) \
|
||||
shapePlane.Nullify();\
|
||||
for(TopExp_Explorer it(s.shape, TopAbs_##_type); it.More(); it.Next()) {\
|
||||
haveShape = true;\
|
||||
BRepLib_FindSurface planeFinder(it.Current(),-1,Standard_True);\
|
||||
if (!planeFinder.Found())\
|
||||
continue;\
|
||||
myShapePlane = it.Current();\
|
||||
myTrsf.SetTransformation(GeomAdaptor_Surface(\
|
||||
planeFinder.Surface()).Plane().Position());\
|
||||
break;\
|
||||
shapePlane = it.Current();\
|
||||
pos = GeomAdaptor_Surface(planeFinder.Surface()).Plane().Position();\
|
||||
trsf.SetTransformation(pos);\
|
||||
gp_Dir dir(pos.Direction());\
|
||||
if(fabs(dir.X())<Precision::Confusion() &&\
|
||||
fabs(dir.Y())<Precision::Confusion()) {\
|
||||
myShapePlane = shapePlane;\
|
||||
myTrsf = trsf;\
|
||||
done = true;\
|
||||
break;\
|
||||
}\
|
||||
if(myShapePlane.IsNull()) {\
|
||||
myShapePlane = shapePlane;\
|
||||
myTrsf = trsf;\
|
||||
}\
|
||||
}\
|
||||
if(!myShapePlane.IsNull()) break;\
|
||||
if(done) break;\
|
||||
if(haveShape) continue;
|
||||
|
||||
//Try to find a plane by iterating through shapes, prefer plane paralell with XY0
|
||||
AREA_CHECK_PLANE(FACE)
|
||||
AREA_CHECK_PLANE(WIRE)
|
||||
AREA_CHECK_PLANE(EDGE)
|
||||
}
|
||||
|
||||
if(myShapePlane.IsNull())
|
||||
throw Base::ValueError("shapes are not planar");
|
||||
}
|
||||
|
@ -412,19 +466,13 @@ void Area::build() {
|
|||
|
||||
int error = 0;
|
||||
int count = myParams.SectionCount;
|
||||
if(count<0 || count*myParams.Stepdown > zMax-zMin)
|
||||
if(count<0 || count*myParams.Stepdown > zMax-zMin) {
|
||||
count = ceil((zMax-zMin)/myParams.Stepdown);
|
||||
if((count-1)*myParams.Stepdown < zMax-zMin)
|
||||
++count;
|
||||
}
|
||||
for(int i=0;i<count;++i,zMax-=myParams.Stepdown) {
|
||||
if(zMax < zMin) zMax = zMin;
|
||||
|
||||
// gp_Pnt p1(xMax,yMin,zMax);
|
||||
// gp_Pnt p2(xMax,yMax,zMax);
|
||||
// gp_Pnt p3(xMin,yMax,zMax);
|
||||
// gp_Pnt p4(xMin,yMin,zMax);
|
||||
// mkWire.Add(BRepBuilderAPI_MakeEdge(p1,p2).Edge());
|
||||
// mkWire.Add(BRepBuilderAPI_MakeEdge(p2,p3).Edge());
|
||||
// mkWire.Add(BRepBuilderAPI_MakeEdge(p3,p4).Edge());
|
||||
// mkWire.Add(BRepBuilderAPI_MakeEdge(p4,p1).Edge());
|
||||
gp_Pln pln(gp_Pnt(0,0,zMax),gp_Dir(0,0,1));
|
||||
BRepLib_MakeFace mkFace(pln,xMin,xMax,yMin,yMax);
|
||||
const TopoDS_Shape &face = mkFace.Face();
|
||||
|
@ -501,14 +549,27 @@ void Area::build() {
|
|||
mySkippedShapes = 0;
|
||||
short op = OperationUnion;
|
||||
bool pending = false;
|
||||
bool explode = myParams.Explode;
|
||||
for(const Shape &s : myShapes) {
|
||||
if(op!=s.op) {
|
||||
if(explode) {
|
||||
explode = false;
|
||||
for (TopExp_Explorer it(s.shape, TopAbs_EDGE); it.More(); it.Next())
|
||||
add(*myArea,BRepBuilderAPI_MakeWire(
|
||||
TopoDS::Edge(it.Current())).Wire(),&myTrsf,myParams.Deflection,true);
|
||||
continue;
|
||||
}else if(op!=s.op) {
|
||||
if(myParams.OpenMode!=OpenModeNone)
|
||||
myArea->m_curves.splice(myArea->m_curves.end(),myAreaOpen->m_curves);
|
||||
pending = false;
|
||||
PARAM_ENUM_CONVERT(AREA_SRC_OP,PARAM_FNAME,PARAM_ENUM_EXCEPT,AREA_PARAMS_OPCODE);
|
||||
myArea->Clip(Operation,&areaClip,SubjectFill,ClipFill);
|
||||
areaClip.m_curves.clear();
|
||||
if(areaClip.m_curves.size()) {
|
||||
if(op == OperationCompound)
|
||||
myArea->m_curves.splice(myArea->m_curves.end(),areaClip.m_curves);
|
||||
else{
|
||||
AREA_CONVERT_OP;
|
||||
myArea->Clip(Operation,&areaClip,SubjectFill,ClipFill);
|
||||
areaClip.m_curves.clear();
|
||||
}
|
||||
}
|
||||
op=s.op;
|
||||
}
|
||||
addToBuild(op==OperationUnion?*myArea:areaClip,s.shape);
|
||||
|
@ -521,17 +582,106 @@ void Area::build() {
|
|||
if(pending){
|
||||
if(myParams.OpenMode!=OpenModeNone)
|
||||
myArea->m_curves.splice(myArea->m_curves.end(),myAreaOpen->m_curves);
|
||||
PARAM_ENUM_CONVERT(AREA_SRC_OP,PARAM_FNAME,PARAM_ENUM_EXCEPT,AREA_PARAMS_OPCODE);
|
||||
myArea->Clip(Operation,&areaClip,SubjectFill,ClipFill);
|
||||
if(op == OperationCompound)
|
||||
myArea->m_curves.splice(myArea->m_curves.end(),areaClip.m_curves);
|
||||
else{
|
||||
AREA_CONVERT_OP;
|
||||
myArea->Clip(Operation,&areaClip,SubjectFill,ClipFill);
|
||||
}
|
||||
}
|
||||
myArea->m_curves.splice(myArea->m_curves.end(),myAreaOpen->m_curves);
|
||||
|
||||
//Reassemble wires after explode
|
||||
if(myParams.Explode) {
|
||||
std::list<TopoDS_Edge> edges;
|
||||
gp_Trsf trsf(myTrsf.Inverted());
|
||||
for(const auto &c : myArea->m_curves) {
|
||||
TopoDS_Wire wire = toShape(c,&trsf);
|
||||
if(wire.IsNull()) continue;
|
||||
TopExp_Explorer it(wire, TopAbs_EDGE);
|
||||
edges.push_back(TopoDS::Edge(it.Current()));
|
||||
}
|
||||
Area area(&myParams);
|
||||
area.myParams.Explode = false;
|
||||
area.myParams.Coplanar = CoplanarNone;
|
||||
area.myWorkPlane = myWorkPlane.IsNull()?myShapePlane:myWorkPlane;
|
||||
area.myTrsf = myTrsf;
|
||||
while(edges.size()) {
|
||||
BRepBuilderAPI_MakeWire mkWire;
|
||||
for(const auto &e : Part::sort_Edges(myParams.Tolerance,edges))
|
||||
mkWire.Add(TopoDS::Edge(e));
|
||||
area.add(mkWire.Wire(),OperationCompound);
|
||||
}
|
||||
area.build();
|
||||
myArea = std::move(area.myArea);
|
||||
}
|
||||
|
||||
}catch(...) {
|
||||
clean();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
list<TopoDS_Shape> Area::sortWires(int index, int count, const gp_Pnt *pstart,
|
||||
gp_Pnt *_pend, PARAM_ARGS(PARAM_FARG,AREA_PARAMS_MIN_DIST))
|
||||
{
|
||||
std::list<TopoDS_Shape> wires;
|
||||
|
||||
build();
|
||||
|
||||
gp_Pnt pend,pt;
|
||||
if(pstart) pt = *pstart;
|
||||
|
||||
pt.Transform(TopLoc_Location(myTrsf));
|
||||
|
||||
if(mySections.size()) {
|
||||
if(index>=(int)mySections.size())
|
||||
throw Base::ValueError("index out of bound");
|
||||
TopLoc_Location loc(myTrsf.Inverted());
|
||||
if(index<0) {
|
||||
index = 0;
|
||||
count = mySections.size();
|
||||
}
|
||||
if(count<=0 || count>(int)mySections.size())
|
||||
count = mySections.size();
|
||||
for(int i=index;i<count;++i) {
|
||||
const std::list<TopoDS_Shape> ws =
|
||||
mySections[i]->sortWires(-1,0,&pt,&pend,
|
||||
PARAM_FIELDS(PARAM_FARG,AREA_PARAMS_MIN_DIST));
|
||||
for(auto &wire : ws)
|
||||
wires.push_back(wire.Moved(loc));
|
||||
pt = pend;
|
||||
}
|
||||
if(_pend)
|
||||
*_pend = pend.Transformed(loc);
|
||||
return wires;
|
||||
}
|
||||
|
||||
if(!myArea || myArea->m_curves.empty()) return wires;
|
||||
|
||||
CArea area(*myArea);
|
||||
Point p(pt.X(),pt.Y());
|
||||
area.ChangeStartToNearest(&p,
|
||||
PARAM_FIELDS(PARAM_FARG,AREA_PARAMS_MIN_DIST));
|
||||
gp_Trsf trsf(myTrsf.Inverted());
|
||||
for(const CCurve &c : area.m_curves) {
|
||||
const TopoDS_Wire &wire = toShape(c,&trsf);
|
||||
if(wire.IsNull()) continue;
|
||||
wires.push_back(toShape(c,&trsf));
|
||||
}
|
||||
if(_pend) {
|
||||
gp_Pnt pend = pt;
|
||||
if(area.m_curves.size() &&
|
||||
area.m_curves.back().m_vertices.size())
|
||||
{
|
||||
const Point &pt = area.m_curves.back().m_vertices.back().m_p;
|
||||
pend.SetCoord(pt.x,pt.y,0.0);
|
||||
}
|
||||
*_pend = pend.Transformed(TopLoc_Location(trsf));
|
||||
}
|
||||
return wires;
|
||||
}
|
||||
|
||||
TopoDS_Shape Area::toShape(CArea &area, short fill) {
|
||||
gp_Trsf trsf(myTrsf.Inverted());
|
||||
bool bFill;
|
||||
|
@ -559,14 +709,17 @@ TopoDS_Shape Area::toShape(CArea &area, short fill) {
|
|||
#define AREA_SECTION(_op,_index,...) do {\
|
||||
if(mySections.size()) {\
|
||||
if(_index>=(int)mySections.size())\
|
||||
throw Base::ValueError("index out of bound");\
|
||||
return TopoDS_Shape();\
|
||||
TopLoc_Location loc(myTrsf.Inverted());\
|
||||
if(_index<0) {\
|
||||
BRep_Builder builder;\
|
||||
TopoDS_Compound compound;\
|
||||
builder.MakeCompound(compound);\
|
||||
for(shared_ptr<Area> area : mySections)\
|
||||
builder.Add(compound,area->_op(-1, ## __VA_ARGS__).Moved(loc));\
|
||||
for(shared_ptr<Area> area : mySections){\
|
||||
const TopoDS_Shape &s = area->_op(-1, ## __VA_ARGS__);\
|
||||
if(s.IsNull()) continue;\
|
||||
builder.Add(compound,s.Moved(loc));\
|
||||
}\
|
||||
return compound;\
|
||||
}\
|
||||
return mySections[_index]->_op(-1, ## __VA_ARGS__).Moved(loc);\
|
||||
|
@ -637,6 +790,7 @@ TopoDS_Shape Area::getShape(int index) {
|
|||
for(shared_ptr<CArea> area : areas) {
|
||||
if(myParams.Thicken)
|
||||
area->Thicken(myParams.ToolRadius);
|
||||
const TopoDS_Shape &shape = toShape(*area,fill);
|
||||
builder.Add(compound,toShape(*area,fill));
|
||||
}
|
||||
builder.Add(compound,areaPocket.makePocket(
|
||||
|
@ -781,7 +935,6 @@ TopoDS_Shape Area::makePocket(int index, PARAM_ARGS(PARAM_FARG,AREA_PARAMS_POCKE
|
|||
throw Base::ValueError("unknown poket mode");
|
||||
}
|
||||
|
||||
build();
|
||||
CAreaConfig conf(myParams);
|
||||
CAreaPocketParams params(
|
||||
tool_radius,extra_offset,stepover,from_center,pm,zig_angle);
|
||||
|
@ -802,75 +955,85 @@ static inline bool IsLeft(const gp_Pnt &a, const gp_Pnt &b, const gp_Pnt &c) {
|
|||
return ((b.X() - a.X())*(c.Y() - a.Y()) - (b.Y() - a.Y())*(c.X() - a.X())) > 0;
|
||||
}
|
||||
|
||||
TopoDS_Wire Area::toShape(const CCurve &c, const gp_Trsf *trsf) {
|
||||
BRepBuilderAPI_MakeWire mkWire;
|
||||
gp_Pnt pstart,pt;
|
||||
bool first = true;
|
||||
for(const CVertex &v : c.m_vertices){
|
||||
if(first){
|
||||
first = false;
|
||||
pstart = pt = gp_Pnt(v.m_p.x,v.m_p.y,0);
|
||||
continue;
|
||||
}
|
||||
gp_Pnt pnext(v.m_p.x,v.m_p.y,0);
|
||||
if(pnext.Distance(pt)<Precision::Confusion())
|
||||
continue;
|
||||
if(v.m_type == 0) {
|
||||
mkWire.Add(BRepBuilderAPI_MakeEdge(pt,pnext).Edge());
|
||||
} else {
|
||||
gp_Pnt center(v.m_c.x,v.m_c.y,0);
|
||||
double r = center.Distance(pt);
|
||||
double r2 = center.Distance(pnext);
|
||||
if(fabs(r-r2) > Precision::Confusion()) {
|
||||
double d = pt.Distance(pnext);
|
||||
double q = sqrt(r*r - d*d*0.25);
|
||||
double x = (pt.X()+pnext.X())*0.5;
|
||||
double y = (pt.Y()+pnext.Y())*0.5;
|
||||
double dx = q*(pt.Y()-pnext.Y())/d;
|
||||
double dy = q*(pnext.X()-pt.X())/d;
|
||||
gp_Pnt newCenter(x + dx, y + dy,0);
|
||||
if(IsLeft(pt,pnext,center) != IsLeft(pt,pnext,newCenter)) {
|
||||
newCenter.SetX(x - dx);
|
||||
newCenter.SetY(y - dy);
|
||||
}
|
||||
Base::Console().Warning(
|
||||
"Arc correction: %lf,%lf, center(%lf,%lf)->(%lf,%lf)\n",
|
||||
r,r2,center.X(),center.Y(),newCenter.X(),newCenter.Y());
|
||||
center = newCenter;
|
||||
}
|
||||
gp_Ax2 axis(center, gp_Dir(0,0,v.m_type));
|
||||
mkWire.Add(BRepBuilderAPI_MakeEdge(gp_Circ(axis,r),pt,pnext).Edge());
|
||||
}
|
||||
pt = pnext;
|
||||
}
|
||||
if(!mkWire.IsDone())
|
||||
return TopoDS_Wire();
|
||||
|
||||
if(c.IsClosed() && !BRep_Tool::IsClosed(mkWire.Wire())){
|
||||
// This should never happen after changing libarea's
|
||||
// Point::tolerance to be the same as Precision::Confusion().
|
||||
// Just leave it here in case.
|
||||
BRepAdaptor_Curve curve(mkWire.Edge());
|
||||
gp_Pnt p1(curve.Value(curve.FirstParameter()));
|
||||
gp_Pnt p2(curve.Value(curve.LastParameter()));
|
||||
std::stringstream str;
|
||||
str<< "warning: patch open wire type " <<
|
||||
c.m_vertices.back().m_type << endl <<
|
||||
'(' << p1.X() << ',' << p1.Y() << ')' << endl <<
|
||||
'(' << p2.X() << ',' << p2.Y() << ')' << endl <<
|
||||
'(' << pt.X() << ',' << pt.Y() << ')' << endl <<
|
||||
'(' << pstart.X() << ',' <<pstart.Y() <<')' <<endl;
|
||||
Base::Console().Warning(str.str().c_str());
|
||||
mkWire.Add(BRepBuilderAPI_MakeEdge(pt,pstart).Edge());
|
||||
}
|
||||
if(trsf)
|
||||
return TopoDS::Wire(mkWire.Wire().Moved(TopLoc_Location(*trsf)));
|
||||
else
|
||||
return mkWire.Wire();
|
||||
}
|
||||
|
||||
TopoDS_Shape Area::toShape(const CArea &area, bool fill, const gp_Trsf *trsf) {
|
||||
BRep_Builder builder;
|
||||
TopoDS_Compound compound;
|
||||
builder.MakeCompound(compound);
|
||||
|
||||
for(const CCurve &c : area.m_curves) {
|
||||
BRepBuilderAPI_MakeWire mkWire;
|
||||
gp_Pnt pstart,pt;
|
||||
bool first = true;
|
||||
for(const CVertex &v : c.m_vertices){
|
||||
if(first){
|
||||
first = false;
|
||||
pstart = pt = gp_Pnt(v.m_p.x,v.m_p.y,0);
|
||||
continue;
|
||||
}
|
||||
gp_Pnt pnext(v.m_p.x,v.m_p.y,0);
|
||||
if(v.m_type == 0) {
|
||||
mkWire.Add(BRepBuilderAPI_MakeEdge(pt,pnext).Edge());
|
||||
} else {
|
||||
gp_Pnt center(v.m_c.x,v.m_c.y,0);
|
||||
double r = center.Distance(pt);
|
||||
double r2 = center.Distance(pnext);
|
||||
if(fabs(r-r2) > Precision::Confusion()) {
|
||||
double d = pt.Distance(pnext);
|
||||
double q = sqrt(r*r - d*d*0.25);
|
||||
double x = (pt.X()+pnext.X())*0.5;
|
||||
double y = (pt.Y()+pnext.Y())*0.5;
|
||||
double dx = q*(pt.Y()-pnext.Y())/d;
|
||||
double dy = q*(pnext.X()-pt.X())/d;
|
||||
gp_Pnt newCenter(x + dx, y + dy,0);
|
||||
if(IsLeft(pt,pnext,center) != IsLeft(pt,pnext,newCenter)) {
|
||||
newCenter.SetX(x - dx);
|
||||
newCenter.SetY(y - dy);
|
||||
}
|
||||
Base::Console().Warning(
|
||||
"Arc correction: %lf,%lf, center(%lf,%lf)->(%lf,%lf)\n",
|
||||
r,r2,center.X(),center.Y(),newCenter.X(),newCenter.Y());
|
||||
center = newCenter;
|
||||
}
|
||||
gp_Ax2 axis(center, gp_Dir(0,0,v.m_type));
|
||||
mkWire.Add(BRepBuilderAPI_MakeEdge(gp_Circ(axis,r),pt,pnext).Edge());
|
||||
}
|
||||
pt = pnext;
|
||||
}
|
||||
if(c.IsClosed() && !BRep_Tool::IsClosed(mkWire.Wire())){
|
||||
// This should never happen after changing libarea's
|
||||
// Point::tolerance to be the same as Precision::Confusion().
|
||||
// Just leave it here in case.
|
||||
BRepAdaptor_Curve curve(mkWire.Edge());
|
||||
gp_Pnt p1(curve.Value(curve.FirstParameter()));
|
||||
gp_Pnt p2(curve.Value(curve.LastParameter()));
|
||||
std::stringstream str;
|
||||
str<< "warning: patch open wire" <<
|
||||
c.m_vertices.back().m_type << endl <<
|
||||
'(' << p1.X() << ',' << p1.Y() << ')' << endl <<
|
||||
'(' << p2.X() << ',' << p2.Y() << ')' << endl <<
|
||||
'(' << pt.X() << ',' << pt.Y() << ')' << endl <<
|
||||
'(' << pstart.X() << ',' <<pstart.Y() <<')' <<endl;
|
||||
Base::Console().Warning(str.str().c_str());
|
||||
mkWire.Add(BRepBuilderAPI_MakeEdge(pt,pstart).Edge());
|
||||
}
|
||||
|
||||
if(trsf)
|
||||
builder.Add(compound,mkWire.Wire().Moved(TopLoc_Location(*trsf)));
|
||||
else
|
||||
builder.Add(compound,mkWire.Wire());
|
||||
const TopoDS_Wire &wire = toShape(c,trsf);
|
||||
if(!wire.IsNull())
|
||||
builder.Add(compound,wire);
|
||||
}
|
||||
|
||||
if(fill) {
|
||||
if(!compound.IsNull() && fill) {
|
||||
try{
|
||||
Part::FaceMakerBullseye mkFace;
|
||||
if(trsf)
|
||||
|
@ -888,3 +1051,186 @@ TopoDS_Shape Area::toShape(const CArea &area, bool fill, const gp_Trsf *trsf) {
|
|||
return compound;
|
||||
}
|
||||
|
||||
std::list<TopoDS_Shape> Area::sortWires(const std::list<TopoDS_Shape> &shapes,
|
||||
const AreaParams *params, const gp_Pnt *_pstart, gp_Pnt *_pend,
|
||||
PARAM_ARGS(PARAM_FARG,AREA_PARAMS_SORT_WIRES))
|
||||
{
|
||||
std::list<TopoDS_Shape> wires;
|
||||
|
||||
//Heristic sorting by shape's vertex Z value. For performance's sake, we don't
|
||||
//perform any planar checking here
|
||||
std::multimap<double,TopoDS_Shape> shape_map;
|
||||
|
||||
for (auto &shape : shapes) {
|
||||
std::list<TopoDS_Shape> subshapes;
|
||||
if(!explode)
|
||||
subshapes.push_back(shape);
|
||||
else{
|
||||
bool haveShape=false;
|
||||
for(TopExp_Explorer it(shape,TopAbs_WIRE);it.More();it.Next()) {
|
||||
haveShape=true;
|
||||
subshapes.push_back(it.Current());
|
||||
}
|
||||
if(!haveShape) {
|
||||
for(TopExp_Explorer it(shape,TopAbs_EDGE);it.More();it.Next())
|
||||
subshapes.push_back(it.Current());
|
||||
}
|
||||
}
|
||||
//Order the shapes by its vertex Z value.
|
||||
for(auto &s : subshapes) {
|
||||
bool first=true;
|
||||
double z=0.0;
|
||||
for(TopExp_Explorer it(s,TopAbs_VERTEX);it.More();) {
|
||||
gp_Pnt p = BRep_Tool::Pnt(TopoDS::Vertex(it.Current()));
|
||||
if(first || z < p.Z()) {
|
||||
first = false;
|
||||
z = p.Z();
|
||||
}
|
||||
if(!top_z) break;
|
||||
}
|
||||
shape_map.insert(std::pair<double,TopoDS_Shape>(z,s));
|
||||
}
|
||||
}
|
||||
if(!shape_map.size())
|
||||
return wires;
|
||||
|
||||
Area area(params);
|
||||
//We'll do planar checking here, so disable Area planar check
|
||||
area.myParams.Coplanar = Area::CoplanarNone;
|
||||
|
||||
gp_Pnt pstart,pend;
|
||||
if(_pstart) pstart = *_pstart;
|
||||
TopoDS_Shape plane = shape_map.rbegin()->second;
|
||||
area.setPlane(plane);
|
||||
for(auto &item : boost::adaptors::reverse(shape_map)) {
|
||||
//do planar checking, and sort wires grouped by plane
|
||||
if(!Area::isCoplanar(plane,item.second)) {
|
||||
wires.splice(wires.end(),area.sortWires(
|
||||
-1,0,&pstart,&pend, PARAM_FIELDS(PARAM_FARG,AREA_PARAMS_MIN_DIST)));
|
||||
pstart = pend;
|
||||
area.clean(true);
|
||||
plane = item.second;
|
||||
area.setPlane(plane);
|
||||
}
|
||||
area.add(item.second,Area::OperationCompound);
|
||||
}
|
||||
wires.splice(wires.end(),area.sortWires(
|
||||
-1,0,&pstart,&pend, PARAM_FIELDS(PARAM_FARG,AREA_PARAMS_MIN_DIST)));
|
||||
if(_pend) *_pend = pend;
|
||||
return wires;
|
||||
}
|
||||
|
||||
static void addCommand(Toolpath &path, const gp_Pnt &p,
|
||||
bool g0=false, double g0height=0.0, double clearance=0.0)
|
||||
{
|
||||
Command cmd;
|
||||
cmd.Name = g0?"G0":"G1";
|
||||
if(g0 && fabs(g0height)>Precision::Confusion()) {
|
||||
cmd.Parameters["Z"] = g0height;
|
||||
path.addCommand(cmd);
|
||||
cmd.Parameters["X"] = p.X();
|
||||
cmd.Parameters["Y"] = p.Y();
|
||||
path.addCommand(cmd);
|
||||
if(fabs(clearance)>Precision::Confusion()) {
|
||||
cmd.Parameters["Z"] = p.Z()+clearance;
|
||||
path.addCommand(cmd);
|
||||
cmd.Name = "G1";
|
||||
}
|
||||
}else
|
||||
cmd.Parameters["X"] = p.X();
|
||||
cmd.Parameters["Y"] = p.Y();
|
||||
cmd.Parameters["Z"] = p.Z();
|
||||
path.addCommand(cmd);
|
||||
}
|
||||
|
||||
static void addCommand(Toolpath &path,
|
||||
const gp_Pnt &pstart, const gp_Pnt &pend,
|
||||
const gp_Pnt ¢er, bool clockwise)
|
||||
{
|
||||
Command cmd;
|
||||
cmd.Name = clockwise?"G2":"G3";
|
||||
cmd.Parameters["I"] = center.X()-pstart.X();
|
||||
cmd.Parameters["J"] = center.Y()-pstart.Y();
|
||||
cmd.Parameters["K"] = center.Z()-pstart.Z();
|
||||
cmd.Parameters["X"] = pend.X();
|
||||
cmd.Parameters["Y"] = pend.Y();
|
||||
cmd.Parameters["Z"] = pend.Z();
|
||||
path.addCommand(cmd);
|
||||
}
|
||||
|
||||
void Area::toPath(Toolpath &path, const std::list<TopoDS_Shape> &shapes,
|
||||
const gp_Pnt *pstart, PARAM_ARGS(PARAM_FARG,AREA_PARAMS_PATH))
|
||||
{
|
||||
std::list<TopoDS_Shape> wires;
|
||||
if(sort)
|
||||
wires = sortWires(shapes,NULL,pstart);
|
||||
else{
|
||||
for(auto &shape : shapes) {
|
||||
if (shape.IsNull())
|
||||
continue;
|
||||
bool haveShape=false;
|
||||
for(TopExp_Explorer it(shape,TopAbs_WIRE);it.More();it.Next()) {
|
||||
haveShape=true;
|
||||
wires.push_back(it.Current());
|
||||
}
|
||||
if(haveShape) continue;
|
||||
for(TopExp_Explorer it(shape,TopAbs_EDGE);it.More();it.Next())
|
||||
wires.push_back(BRepBuilderAPI_MakeWire(TopoDS::Edge(it.Current())).Wire());
|
||||
}
|
||||
}
|
||||
|
||||
if(threshold < Precision::Confusion())
|
||||
threshold = Precision::Confusion();
|
||||
gp_Pnt plast,p;
|
||||
if(pstart) plast = *pstart;
|
||||
bool first = true;
|
||||
for(const TopoDS_Shape &wire : wires) {
|
||||
BRepTools_WireExplorer xp(TopoDS::Wire(wire));
|
||||
p = BRep_Tool::Pnt(xp.CurrentVertex());
|
||||
if(first||(p.Z()>=plast.Z()&&p.Distance(plast)>threshold))
|
||||
addCommand(path,p,true,height,clearance);
|
||||
else
|
||||
addCommand(path,p);
|
||||
plast = p;
|
||||
first = false;
|
||||
for(;xp.More();xp.Next(),plast=p) {
|
||||
BRepAdaptor_Curve curve(xp.Current());
|
||||
bool reversed = (xp.Current().Orientation()==TopAbs_REVERSED);
|
||||
p = curve.Value(reversed?curve.FirstParameter():curve.LastParameter());
|
||||
|
||||
switch (curve.GetType()) {
|
||||
case GeomAbs_Line: {
|
||||
addCommand(path,p);
|
||||
break;
|
||||
} case GeomAbs_Circle:{
|
||||
double first = curve.FirstParameter();
|
||||
double last = curve.LastParameter();
|
||||
gp_Circ circle = curve.Circle();
|
||||
gp_Ax1 axis = circle.Axis();
|
||||
bool clockwise = axis.Direction().Z()<0;
|
||||
if(reversed) clockwise = !clockwise;
|
||||
gp_Pnt center = axis.Location();
|
||||
if(fabs(first-last)>M_PI) {
|
||||
// Split arc(circle) larger than half circle.
|
||||
gp_Pnt mid = curve.Value((last-first)*0.5+first);
|
||||
addCommand(path,plast,mid,center,clockwise);
|
||||
plast = mid;
|
||||
}
|
||||
addCommand(path,plast,p,center,clockwise);
|
||||
break;
|
||||
} default: {
|
||||
// Discretize all other type of curves
|
||||
GCPnts_UniformDeflection discretizer(curve, deflection,
|
||||
curve.FirstParameter(), curve.LastParameter());
|
||||
if (discretizer.IsDone () && discretizer.NbPoints () > 0) {
|
||||
int nbPoints = discretizer.NbPoints ();
|
||||
for (int i=1; i<=nbPoints; i++) {
|
||||
gp_Pnt pt = discretizer.Value (i);
|
||||
addCommand(path,pt);
|
||||
}
|
||||
}else
|
||||
Standard_Failure::Raise("Curve discretization failed");
|
||||
}}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,14 +23,19 @@
|
|||
#ifndef PATH_AREA_H
|
||||
#define PATH_AREA_H
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <TopoDS.hxx>
|
||||
#include <gp_Pln.hxx>
|
||||
#include <gp_Circ.hxx>
|
||||
#include <gp_GTrsf.hxx>
|
||||
|
||||
#include "Path.h"
|
||||
#include "AreaParams.h"
|
||||
|
||||
class CArea;
|
||||
class CCurve;
|
||||
|
||||
namespace Path
|
||||
{
|
||||
|
@ -152,8 +157,12 @@ public:
|
|||
/** Set a working plane
|
||||
*
|
||||
* If no working plane are set, Area will try to find a working plane from
|
||||
* all the added children shapes. The purpose of this function is in case
|
||||
* the child shapes are all colinear edges
|
||||
* individual children faces, wires or edges. By right, we should create a
|
||||
* compound of all shapes and then findplane on it. However, because we
|
||||
* supports solid, and also because OCC may hang for a long time if
|
||||
* something goes a bit off, we opt to find plane on each individual shape.
|
||||
* If you intend to pass individual edges, you must supply a workplane shape
|
||||
* manually
|
||||
*
|
||||
* \arg \c shape: a shape defining a working plane
|
||||
*/
|
||||
|
@ -177,13 +186,13 @@ public:
|
|||
* 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, PARAM_ARGS_DEF(PARAM_FARG,AREA_PARAMS_OFFSET));
|
||||
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, PARAM_ARGS_DEF(PARAM_FARG,AREA_PARAMS_POCKET));
|
||||
TopoDS_Shape makePocket(int index=-1, PARAM_ARGS_DEF(PARAM_FARG,AREA_PARAMS_POCKET));
|
||||
|
||||
|
||||
/** Config this Area object */
|
||||
|
@ -204,8 +213,11 @@ public:
|
|||
*/
|
||||
void clean(bool deleteShapes=false);
|
||||
|
||||
/** Get the combined shape */
|
||||
TopoDS_Shape getShape(int index);
|
||||
/** 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() {
|
||||
|
@ -219,10 +231,30 @@ public:
|
|||
* \arg \c wire: input wire 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 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);
|
||||
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
|
||||
*
|
||||
* See #AREA_PARAMS_MIN_DIST 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_MIN_DIST));
|
||||
|
||||
/** Add a OCC generic shape to CArea
|
||||
*
|
||||
|
@ -236,7 +268,7 @@ public:
|
|||
* \arg \c areaOpen: for collecting open curves. If not supplied, open
|
||||
* curves are added to \c area
|
||||
* \arg \c to_edges: separate open wires to individual edges
|
||||
* \arg \c reorder: reorder closed wires for wire only shape
|
||||
* \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
|
||||
|
@ -244,7 +276,7 @@ public:
|
|||
static int add(CArea &area, const TopoDS_Shape &shape, const gp_Trsf *trsf=NULL,
|
||||
double deflection=0.01,const TopoDS_Shape *plane = NULL,
|
||||
bool force_coplanar=true, CArea *areaOpen=NULL, bool to_edges=false,
|
||||
bool reorder=true);
|
||||
bool reorient=true);
|
||||
|
||||
/** Convert curves in CArea into an OCC shape
|
||||
*
|
||||
|
@ -256,7 +288,48 @@ public:
|
|||
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
|
||||
* maybe broken if the algorithm see fits.
|
||||
*
|
||||
* See #AREA_PARAMS_SORT_WIRES 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_WIRES));
|
||||
|
||||
/** Convert a list of wires to gcode
|
||||
*
|
||||
* \arg \c path: output toolpath
|
||||
* \arg \c shapes: input list of shapes
|
||||
* \arg \c pstart: output start point,
|
||||
*
|
||||
* See #AREA_PARAMS_PATH for other arguments
|
||||
*/
|
||||
static void toPath(Toolpath &path, const std::list<TopoDS_Shape> &shapes,
|
||||
const gp_Pnt *pstart=NULL, PARAM_ARGS_DEF(PARAM_FARG,AREA_PARAMS_PATH));
|
||||
|
||||
};
|
||||
|
||||
} //namespace Path
|
||||
|
|
|
@ -44,20 +44,32 @@
|
|||
((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.\n"\
|
||||
"'Force' will discard non coplaner shapes, but 'Check' only gives warning.",\
|
||||
(None)(Check)(Force)))\
|
||||
((bool,reorder,Reorder,true,"Re-orient closed wires in wire only shapes so that inner wires become holes."))\
|
||||
((enum,open_mode,OpenMode,0,"Specify how to handle open wires.\n"\
|
||||
"'None' means combin without openeration.\n"\
|
||||
"'Edges' means separate to edges before Union.\n"\
|
||||
"ClipperLib seems to have an urge to close open wires.",(None)(Union)(Edges)))\
|
||||
AREA_PARAMS_CLIPPER_FILL \
|
||||
((double,deflection,Deflection,0.01,"Deflection for non circular curve discretization"))
|
||||
((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
|
||||
|
||||
/** libarea algorithm option parameters */
|
||||
#define AREA_PARAMS_CAREA \
|
||||
|
@ -72,7 +84,8 @@
|
|||
((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 \nconvert floating points."))
|
||||
"ClipperLib operate on intergers. This is the scale factor to convert\n"\
|
||||
"floating points."))
|
||||
|
||||
/** Pocket parameters
|
||||
*
|
||||
|
@ -91,8 +104,10 @@
|
|||
|
||||
/** Operation code */
|
||||
#define AREA_PARAMS_OPCODE \
|
||||
((enum2,op,Operation,0,"Boolean operation",\
|
||||
(Union)(Difference)(Intersection)(Xor),(ClipperLib::ClipType,ClipperLib::ct)))
|
||||
((enum,op,Operation,0,\
|
||||
"Boolean operation. For the first four operation, see https://goo.gl/Gj8RUu.\n"\
|
||||
"'Compound' means no operation, normal used to do Area.sortWires().",\
|
||||
(Union)(Difference)(Intersection)(Xor)(Compound)))
|
||||
|
||||
/** Offset parameters */
|
||||
#define AREA_PARAMS_OFFSET \
|
||||
|
@ -124,6 +139,36 @@
|
|||
((double,round_precision,RoundPreceision,0.0,\
|
||||
"Round joint precision. If =0, it defaults to Accuracy. \nSee https://goo.gl/4odfQh"))
|
||||
|
||||
/** Area path generation parameters */
|
||||
#define AREA_PARAMS_PATH \
|
||||
((bool, sort, SortShape, true, \
|
||||
"Whether to sort the shapes to optimize travel distance. You can customize wire\n"\
|
||||
"sorting by calling sortWires() manually."))\
|
||||
((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"))\
|
||||
AREA_PARAMS_DEFLECTION
|
||||
|
||||
#define AREA_PARAMS_MIN_DIST \
|
||||
((double, min_dist, MinDistance, 1.0, \
|
||||
"minimum distance for the generate new wires. Wires maybe broken if the\n"\
|
||||
"algorithm see fits."))\
|
||||
|
||||
/** Area wire sorting parameters */
|
||||
#define AREA_PARAMS_SORT_WIRES \
|
||||
((bool, explode, Explode, true,\
|
||||
"If ture, the input shape will be exploded into wires before doing planar checking.\n"\
|
||||
"Otherwise, and whole shape is considered to be in one plane without checking."))\
|
||||
((bool, top_z, TopZ, false, \
|
||||
"If ture, the planes is ordered by the first the shapes first vertex Z value.\n"\
|
||||
"Otherwise, by the highest Z of all of its vertexes."))\
|
||||
AREA_PARAMS_MIN_DIST
|
||||
|
||||
|
||||
/** Group of all Area configuration parameters except CArea's*/
|
||||
#define AREA_PARAMS_AREA \
|
||||
AREA_PARAMS_BASE \
|
||||
|
|
|
@ -58,6 +58,11 @@ any operation</UserDocu>
|
|||
</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>
|
||||
|
|
|
@ -22,10 +22,10 @@
|
|||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#include <Mod/Part/App/OCCError.h>
|
||||
#include <Mod/Part/App/TopoShapePy.h>
|
||||
#include <Base/VectorPy.h>
|
||||
|
||||
#include "Mod/Path/App/Area.h"
|
||||
#include "Area.h"
|
||||
|
||||
// inclusion of the generated files (generated out of AreaPy.xml)
|
||||
#include "AreaPy.h"
|
||||
|
@ -77,6 +77,16 @@ static const AreaDoc myDocs[] = {
|
|||
"\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),
|
||||
},
|
||||
{
|
||||
"sortWires",
|
||||
|
||||
"sortWires(index=-1, count=0, start=Vector()" PARAM_PY_ARGS_DOC(ARG,AREA_PARAMS_MIN_DIST) "):\n"
|
||||
"Returns a tuple (wires,end): sorted wires with minimized travel distance, and the endpoint 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_MIN_DIST),
|
||||
},
|
||||
};
|
||||
|
||||
struct AreaPyDoc {
|
||||
|
@ -141,12 +151,42 @@ PyObject* AreaPy::getShape(PyObject *args, PyObject *keywds)
|
|||
if (!PyArg_ParseTupleAndKeywords(args, keywds,"|hO",kwlist,&pcObj))
|
||||
return 0;
|
||||
|
||||
try {
|
||||
if(PyObject_IsTrue(pcObj))
|
||||
getAreaPtr()->clean();
|
||||
return Py::new_reference_to(Part::shape2pyshape(getAreaPtr()->getShape(index)));
|
||||
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_MIN_DIST)
|
||||
short index = -1;
|
||||
short count = 0;
|
||||
PyObject *start = NULL;
|
||||
|
||||
static char *kwlist[] = {"index","count","start",
|
||||
PARAM_FIELD_STRINGS(ARG,AREA_PARAMS_MIN_DIST), NULL};
|
||||
if (!PyArg_ParseTupleAndKeywords(args, keywds,
|
||||
"|hhO!" PARAM_PY_KWDS(AREA_PARAMS_MIN_DIST),
|
||||
kwlist,&index,&count,&(Base::VectorPy::Type),&start,
|
||||
PARAM_REF(PARAM_FARG,AREA_PARAMS_MIN_DIST)))
|
||||
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);
|
||||
}
|
||||
PY_CATCH_OCC;
|
||||
std::list<TopoDS_Shape> wires = getAreaPtr()->sortWires(
|
||||
index,count,&pstart,&pend,
|
||||
PARAM_PY_FIELDS(PARAM_FARG,AREA_PARAMS_MIN_DIST));
|
||||
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)
|
||||
|
@ -205,13 +245,10 @@ PyObject* AreaPy::makeOffset(PyObject *args, PyObject *keywds)
|
|||
&index,PARAM_REF(PARAM_FARG,AREA_PARAMS_OFFSET)))
|
||||
return 0;
|
||||
|
||||
try {
|
||||
//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));
|
||||
}
|
||||
PY_CATCH_OCC;
|
||||
//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)
|
||||
|
@ -228,15 +265,11 @@ PyObject* AreaPy::makePocket(PyObject *args, PyObject *keywds)
|
|||
&index,PARAM_REF(PARAM_FARG,AREA_PARAMS_POCKET)))
|
||||
return 0;
|
||||
|
||||
try {
|
||||
TopoDS_Shape resultShape = getAreaPtr()->makePocket(index,
|
||||
PARAM_PY_FIELDS(PARAM_FARG,AREA_PARAMS_POCKET));
|
||||
return Py::new_reference_to(Part::shape2pyshape(resultShape));
|
||||
}
|
||||
PY_CATCH_OCC;
|
||||
TopoDS_Shape resultShape = getAreaPtr()->makePocket(index,
|
||||
PARAM_PY_FIELDS(PARAM_FARG,AREA_PARAMS_POCKET));
|
||||
return Py::new_reference_to(Part::shape2pyshape(resultShape));
|
||||
}
|
||||
|
||||
|
||||
PyObject* AreaPy::setParams(PyObject *args, PyObject *keywds)
|
||||
{
|
||||
static char *kwlist[] = {PARAM_FIELD_STRINGS(NAME,AREA_PARAMS_CONF),NULL};
|
||||
|
|
|
@ -41,6 +41,7 @@ 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()));
|
||||
|
@ -62,6 +63,14 @@ FeatureArea::~FeatureArea()
|
|||
{
|
||||
}
|
||||
|
||||
Area &FeatureArea::getArea() {
|
||||
if(!myBuild) {
|
||||
myBuild = true;
|
||||
execute();
|
||||
}
|
||||
return myArea;
|
||||
}
|
||||
|
||||
App::DocumentObjectExecReturn *FeatureArea::execute(void)
|
||||
{
|
||||
std::vector<App::DocumentObject*> links = Sources.getValues();
|
||||
|
@ -97,6 +106,17 @@ App::DocumentObjectExecReturn *FeatureArea::execute(void)
|
|||
return Part::Feature::execute();
|
||||
}
|
||||
|
||||
std::list<TopoDS_Shape> FeatureArea::getShapes() {
|
||||
std::list<TopoDS_Shape> shapes;
|
||||
Area &area = getArea();
|
||||
if(area.getSectionCount()) {
|
||||
for(int i=0;i<(int)area.getSectionCount();++i)
|
||||
shapes.push_back(area.getShape(i));
|
||||
}else
|
||||
shapes.push_back(area.getShape());
|
||||
return shapes;
|
||||
}
|
||||
|
||||
short FeatureArea::mustExecute(void) const
|
||||
{
|
||||
if (Sources.isTouched())
|
||||
|
@ -119,14 +139,85 @@ PyObject *FeatureArea::getPyObject()
|
|||
}
|
||||
|
||||
|
||||
// Python Area feature ---------------------------------------------------------
|
||||
// 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");
|
||||
ADD_PROPERTY_TYPE(SectionCount,(1),"Section",App::Prop_None,"Number of sections to show");
|
||||
}
|
||||
|
||||
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;
|
||||
Area &area = static_cast<FeatureArea*>(pObj)->getArea();
|
||||
|
||||
int index=SectionIndex.getValue(),count=SectionCount.getValue();
|
||||
if(index<0) {
|
||||
index = 0;
|
||||
count = area.getSectionCount();
|
||||
}
|
||||
if(index >= (int)area.getSectionCount())
|
||||
return shapes;
|
||||
|
||||
if(count<=0)
|
||||
count = (int)area.getSectionCount();
|
||||
if(count==1)
|
||||
shapes.push_back(area.getShape(index));
|
||||
else{
|
||||
count += index;
|
||||
if(count>(int)area.getSectionCount())
|
||||
count = area.getSectionCount();
|
||||
for(int i=index;i<count;++i)
|
||||
shapes.push_back(area.getShape(i));
|
||||
}
|
||||
return 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::ViewProviderArea";
|
||||
return "PathGui::ViewProviderAreaPython";
|
||||
}
|
||||
template<> const char* Path::FeatureAreaViewPython::getViewProviderName(void) const {
|
||||
return "PathGui::ViewProviderAreaViewPython";
|
||||
}
|
||||
/// @endcond
|
||||
|
||||
|
|
|
@ -40,12 +40,13 @@ class PathExport FeatureArea : public Part::Feature
|
|||
PROPERTY_HEADER(Path::FeatureArea);
|
||||
|
||||
public:
|
||||
Area myArea;
|
||||
|
||||
/// Constructor
|
||||
FeatureArea(void);
|
||||
virtual ~FeatureArea();
|
||||
|
||||
Area &getArea();
|
||||
std::list<TopoDS_Shape> getShapes();
|
||||
|
||||
/// returns the type name of the ViewProvider
|
||||
virtual const char* getViewProviderName(void) const {
|
||||
return "PathGui::ViewProviderArea";
|
||||
|
@ -58,10 +59,36 @@ public:
|
|||
Part::PropertyPartShape WorkPlane;
|
||||
|
||||
PARAM_PROP_DECLARE(AREA_PARAMS_ALL)
|
||||
|
||||
private:
|
||||
bool myBuild;
|
||||
Area myArea;
|
||||
};
|
||||
|
||||
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
|
||||
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ PyObject* FeatureAreaPy::getArea(PyObject *args)
|
|||
if (!PyArg_ParseTuple(args, ""))
|
||||
return NULL;
|
||||
|
||||
return new AreaPy(new Area(getFeatureAreaPtr()->myArea));
|
||||
return new AreaPy(new Area(getFeatureAreaPtr()->getArea()));
|
||||
}
|
||||
|
||||
PyObject* FeatureAreaPy::setParams(PyObject *args, PyObject *keywds)
|
||||
|
|
|
@ -19,7 +19,9 @@
|
|||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017 Zheng, Lei <realthunder.dev@gmail.com>
|
||||
*/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
|
@ -32,20 +34,17 @@
|
|||
#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;
|
||||
|
||||
|
@ -54,79 +53,39 @@ PROPERTY_SOURCE(Path::FeatureShape, Path::Feature)
|
|||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
Area::toPath(path,shapes,&pstart,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)
|
||||
|
||||
//@{
|
||||
/// recalculate the feature
|
||||
virtual App::DocumentObjectExecReturn *execute(void);
|
||||
virtual short mustExecute(void) const;
|
||||
//@}
|
||||
|
||||
/// returns the type name of the ViewProvider
|
||||
|
|
|
@ -1,95 +1,95 @@
|
|||
/***************************************************************************
|
||||
* Copyright (c) Yorik van Havre (yorik@uncreated.net) 2014 *
|
||||
* *
|
||||
* 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 *
|
||||
* *
|
||||
***************************************************************************/
|
||||
/***************************************************************************
|
||||
* Copyright (c) Yorik van Havre (yorik@uncreated.net) 2014 *
|
||||
* *
|
||||
* 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_Path_H
|
||||
#define PATH_Path_H
|
||||
|
||||
|
||||
#ifndef PATH_Path_H
|
||||
#define PATH_Path_H
|
||||
|
||||
#include "Command.h"
|
||||
//#include "Mod/Robot/App/kdl_cp/path_composite.hpp"
|
||||
//#include "Mod/Robot/App/kdl_cp/frames_io.hpp"
|
||||
#include <Base/Persistence.h>
|
||||
#include <Base/Vector3D.h>
|
||||
|
||||
namespace Path
|
||||
{
|
||||
|
||||
/** The representation of a CNC Toolpath */
|
||||
|
||||
class PathExport Toolpath : public Base::Persistence
|
||||
{
|
||||
TYPESYSTEM_HEADER();
|
||||
|
||||
public:
|
||||
Toolpath();
|
||||
Toolpath(const Toolpath&);
|
||||
~Toolpath();
|
||||
|
||||
Toolpath &operator=(const Toolpath&);
|
||||
|
||||
// from base class
|
||||
virtual unsigned int getMemSize (void) const;
|
||||
virtual void Save (Base::Writer &/*writer*/) const;
|
||||
virtual void Restore(Base::XMLReader &/*reader*/);
|
||||
void SaveDocFile (Base::Writer &writer) const;
|
||||
void RestoreDocFile(Base::Reader &reader);
|
||||
|
||||
// interface
|
||||
void clear(void); // clears the internal data
|
||||
void addCommand(const Command &Cmd); // adds a command at the end
|
||||
void insertCommand(const Command &Cmd, int); // inserts a command
|
||||
void deleteCommand(int); // deletes a command
|
||||
double getLength(void); // return the Length (mm) of the Path
|
||||
void recalculate(void); // recalculates the points
|
||||
void setFromGCode(const std::string); // sets the path from the contents of the given GCode string
|
||||
std::string toGCode(void) const; // gets a gcode string representation from the Path
|
||||
|
||||
// shortcut functions
|
||||
unsigned int getSize(void) const{return vpcCommands.size();}
|
||||
const std::vector<Command*> &getCommands(void)const{return vpcCommands;}
|
||||
const Command &getCommand(unsigned int pos)const {return *vpcCommands[pos];}
|
||||
|
||||
protected:
|
||||
std::vector<Command*> vpcCommands;
|
||||
//KDL::Path_Composite *pcPath;
|
||||
|
||||
/*
|
||||
inline KDL::Frame toFrame(const Base::Placement &To){
|
||||
return KDL::Frame(KDL::Rotation::Quaternion(To.getRotation()[0],
|
||||
To.getRotation()[1],
|
||||
To.getRotation()[2],
|
||||
To.getRotation()[3]),
|
||||
KDL::Vector(To.getPosition()[0],
|
||||
To.getPosition()[1],
|
||||
To.getPosition()[2]));
|
||||
}
|
||||
inline Base::Placement toPlacement(const KDL::Frame &To){
|
||||
double x,y,z,w;
|
||||
To.M.GetQuaternion(x,y,z,w);
|
||||
return Base::Placement(Base::Vector3d(To.p[0],To.p[1],To.p[2]),Base::Rotation(x,y,z,w));
|
||||
} */
|
||||
};
|
||||
|
||||
} //namespace Path
|
||||
|
||||
|
||||
#endif // PATH_Path_H
|
||||
#include "Command.h"
|
||||
//#include "Mod/Robot/App/kdl_cp/path_composite.hpp"
|
||||
//#include "Mod/Robot/App/kdl_cp/frames_io.hpp"
|
||||
#include <Base/Persistence.h>
|
||||
#include <Base/Vector3D.h>
|
||||
|
||||
namespace Path
|
||||
{
|
||||
|
||||
/** The representation of a CNC Toolpath */
|
||||
|
||||
class PathExport Toolpath : public Base::Persistence
|
||||
{
|
||||
TYPESYSTEM_HEADER();
|
||||
|
||||
public:
|
||||
Toolpath();
|
||||
Toolpath(const Toolpath&);
|
||||
~Toolpath();
|
||||
|
||||
Toolpath &operator=(const Toolpath&);
|
||||
|
||||
// from base class
|
||||
virtual unsigned int getMemSize (void) const;
|
||||
virtual void Save (Base::Writer &/*writer*/) const;
|
||||
virtual void Restore(Base::XMLReader &/*reader*/);
|
||||
void SaveDocFile (Base::Writer &writer) const;
|
||||
void RestoreDocFile(Base::Reader &reader);
|
||||
|
||||
// interface
|
||||
void clear(void); // clears the internal data
|
||||
void addCommand(const Command &Cmd); // adds a command at the end
|
||||
void insertCommand(const Command &Cmd, int); // inserts a command
|
||||
void deleteCommand(int); // deletes a command
|
||||
double getLength(void); // return the Length (mm) of the Path
|
||||
void recalculate(void); // recalculates the points
|
||||
void setFromGCode(const std::string); // sets the path from the contents of the given GCode string
|
||||
std::string toGCode(void) const; // gets a gcode string representation from the Path
|
||||
|
||||
// shortcut functions
|
||||
unsigned int getSize(void) const{return vpcCommands.size();}
|
||||
const std::vector<Command*> &getCommands(void)const{return vpcCommands;}
|
||||
const Command &getCommand(unsigned int pos)const {return *vpcCommands[pos];}
|
||||
|
||||
protected:
|
||||
std::vector<Command*> vpcCommands;
|
||||
//KDL::Path_Composite *pcPath;
|
||||
|
||||
/*
|
||||
inline KDL::Frame toFrame(const Base::Placement &To){
|
||||
return KDL::Frame(KDL::Rotation::Quaternion(To.getRotation()[0],
|
||||
To.getRotation()[1],
|
||||
To.getRotation()[2],
|
||||
To.getRotation()[3]),
|
||||
KDL::Vector(To.getPosition()[0],
|
||||
To.getPosition()[1],
|
||||
To.getPosition()[2]));
|
||||
}
|
||||
inline Base::Placement toPlacement(const KDL::Frame &To){
|
||||
double x,y,z,w;
|
||||
To.M.GetQuaternion(x,y,z,w);
|
||||
return Base::Placement(Base::Vector3d(To.p[0],To.p[1],To.p[2]),Base::Rotation(x,y,z,w));
|
||||
} */
|
||||
};
|
||||
|
||||
} //namespace Path
|
||||
|
||||
|
||||
#endif // PATH_Path_H
|
||||
|
|
|
@ -80,6 +80,8 @@ PyMODINIT_FUNC initPathGui()
|
|||
PathGui::ViewProviderPathPython ::init();
|
||||
PathGui::ViewProviderArea ::init();
|
||||
PathGui::ViewProviderAreaPython ::init();
|
||||
PathGui::ViewProviderAreaView ::init();
|
||||
PathGui::ViewProviderAreaViewPython ::init();
|
||||
|
||||
// add resources and reloads the translators
|
||||
loadPathResource();
|
||||
|
|
|
@ -68,39 +68,55 @@ 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"))
|
||||
{
|
||||
if(name.compare(0,4,"Face") && name.compare(0,4,"Edge")) {
|
||||
Base::Console().Error("Selected shape is not 2D\n");
|
||||
return;
|
||||
}
|
||||
|
||||
int index = atoi(name.substr(4).c_str());
|
||||
|
||||
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 = FreeCAD.activeDocument()." << pcObj->getNameInDocument() << ".Shape." <<
|
||||
name.substr(0,4) << "s[" << index-1 << ']';
|
||||
"').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());
|
||||
|
@ -171,17 +187,12 @@ void CmdPathAreaWorkplane::activated(int iMsg)
|
|||
}
|
||||
|
||||
for(const std::string &name : subnames) {
|
||||
if(!name.compare(0,4,"Face") &&
|
||||
!name.compare(0,4,"Edge"))
|
||||
{
|
||||
if(name.compare(0,4,"Face") && name.compare(0,4,"Edge")) {
|
||||
Base::Console().Error("Selected shape is not 2D\n");
|
||||
return;
|
||||
}
|
||||
|
||||
int index = atoi(name.substr(4).c_str());
|
||||
|
||||
std::ostringstream subname;
|
||||
subname << planeSubname << '.' << name.substr(0,4) << "s[" << index-1 << ']';
|
||||
subname << planeSubname << ",'" << name << "','Wires'";
|
||||
planeSubname = subname.str();
|
||||
}
|
||||
}
|
||||
|
@ -195,10 +206,10 @@ void CmdPathAreaWorkplane::activated(int iMsg)
|
|||
}
|
||||
|
||||
openCommand("Select Workplane for Path Area");
|
||||
doCommand(Doc,"FreeCAD.activeDocument().%s.WorkPlane = FreeCAD.activeDocument().%s",
|
||||
areaName.c_str(),planeSubname.c_str());
|
||||
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());
|
||||
// doCommand(Doc,"FreeCAD.activeDocument().%s.ViewObject.Visibility = False",planeName.c_str());
|
||||
commitCommand();
|
||||
updateActive();
|
||||
}
|
||||
|
@ -284,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)
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
<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>
|
||||
|
|
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
|
@ -0,0 +1,657 @@
|
|||
<?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-View.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="3.8890873"
|
||||
inkscape:cx="-7.4813451"
|
||||
inkscape:cy="10.659623"
|
||||
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
|
||||
id="path3599"
|
||||
d="m 26.202906,1.6813301 c -9.673905,0 -20.9601314,6.2397496 -25.79708379,18.7192689 C 5.2427746,29.76025 14.916679,36 26.202906,36 37.489143,36 47.163048,29.76025 52,20.400599 47.163048,7.9210797 35.876821,1.6813301 26.202906,1.6813301 Z m 0,31.1987859 c -9.673905,0 -17.7354897,-6.23975 -19.3478099,-12.479517 C 8.4674163,14.160848 16.529001,7.9210797 26.202906,7.9210797 c 9.673915,0 17.7355,6.2397683 19.34782,12.4795193 -1.61232,6.239767 -9.673905,12.479517 -19.34782,12.479517 z m 0,-21.839152 c -1.007692,0 -1.914621,0.194993 -2.821549,0.438734 1.662698,0.731222 2.821549,2.339912 2.821549,4.241091 0,2.583655 -2.166544,4.67981 -4.836953,4.67981 -1.965006,0 -3.627715,-1.121208 -4.383483,-2.729881 -0.251923,0.877467 -0.453469,1.754917 -0.453469,2.729881 0,5.167306 4.333107,9.359651 9.673905,9.359651 5.340808,0 9.673915,-4.192345 9.673915,-9.359651 0,-5.167292 -4.333107,-9.359635 -9.673915,-9.359635 z"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="opacity:0.84799972;fill:#ffffff;stroke:#ed1521;stroke-width:0.18025407;stroke-opacity:1"
|
||||
d="M 24.513492,32.743549 C 20.158618,32.279756 16.320657,30.874437 13.101873,28.565038 10.565128,26.744986 8.0555748,23.645238 7.240207,21.324834 6.9310922,20.445146 6.9319596,20.410993 7.289147,19.39655 c 1.39318,-3.956736 5.894877,-8.025327 10.97742,-9.9212893 2.388118,-0.8908503 4.189049,-1.243432 6.954324,-1.3615029 3.700832,-0.1580165 6.748099,0.3948804 10.068295,1.8267941 4.509958,1.9450261 8.541022,5.8276231 9.860413,9.4972421 l 0.343034,0.954079 -0.406823,1.087884 c -1.903008,5.08883 -8.045412,9.656313 -14.648854,10.892867 -1.533211,0.287106 -4.793511,0.491266 -5.923465,0.370925 z m 3.944714,-3.168696 c 3.268532,-0.752696 6.040924,-3.250309 7.009108,-6.314414 0.74188,-2.347903 0.609807,-4.448295 -0.422862,-6.724951 -1.727573,-3.808655 -5.799065,-6.000195 -10.098702,-5.435771 -0.713226,0.09362 -1.36028,0.238742 -1.437897,0.322477 -0.07761,0.08374 0.205724,0.373163 0.629646,0.643172 2.40184,1.529797 2.621108,4.930323 0.448249,6.951712 -2.087088,1.941597 -5.735326,1.528636 -7.161292,-0.810623 -0.190194,-0.312008 -0.397714,-0.56753 -0.461157,-0.567826 -0.184558,-8.66e-4 -0.490195,1.808374 -0.485585,2.874447 0.0097,2.22833 0.762415,4.123494 2.376571,5.983168 2.345137,2.701835 6.063739,3.893862 9.603921,3.078609 z"
|
||||
id="path3630"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 24 KiB |
|
@ -115,11 +115,83 @@ bool ViewProviderArea::onDelete(const std::vector<std::string> &)
|
|||
|
||||
// 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>;
|
||||
}
|
||||
|
||||
|
|
|
@ -54,6 +54,29 @@ public:
|
|||
|
||||
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
|
||||
|
||||
|
||||
|
|
|
@ -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", "Path_Area", "Path_Area_Workplane"]
|
||||
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
|
||||
|
||||
|
||||
|
|
|
@ -73,6 +73,58 @@ Point CArea::NearestPoint(const Point& p)const
|
|||
return best_point;
|
||||
}
|
||||
|
||||
void CArea::ChangeStartToNearest(const Point *point, double min_dist) {
|
||||
|
||||
for(std::list<CCurve>::const_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 = curve.NearestPoint(p);
|
||||
double 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 if(ItBest->m_vertices.back().m_p.dist(best_point)<=min_dist) {
|
||||
ItBest->Reverse();
|
||||
}else if(ItBest->m_vertices.front().m_p.dist(best_point)>min_dist) {
|
||||
ItBest->Break(best_point);
|
||||
m_curves.push_back(*ItBest);
|
||||
m_curves.back().ChangeEnd(best_point);
|
||||
ItBest->ChangeStart(best_point);
|
||||
}
|
||||
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++)
|
||||
|
|
|
@ -85,6 +85,8 @@ public:
|
|||
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 *point=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();\
|
||||
|
|
|
@ -468,16 +468,23 @@ void CArea::Offset(double inwards_value)
|
|||
|
||||
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(type == ptClip && !closed)
|
||||
continue;
|
||||
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,
|
||||
|
|
Loading…
Reference in New Issue
Block a user