Path: added Path.Area and Path.FeatureArea
This commit is contained in:
parent
4a0e037893
commit
36423f24de
|
@ -41,6 +41,8 @@
|
|||
#include "PropertyTooltable.h"
|
||||
#include "FeaturePathCompound.h"
|
||||
#include "FeaturePathShape.h"
|
||||
#include "AreaPy.h"
|
||||
#include "FeatureArea.h"
|
||||
|
||||
namespace Path {
|
||||
extern PyObject* initModule();
|
||||
|
@ -49,15 +51,24 @@ extern PyObject* initModule();
|
|||
/* Python entry */
|
||||
PyMODINIT_FUNC initPath()
|
||||
{
|
||||
// load dependent module
|
||||
try {
|
||||
Base::Interpreter().runString("import Part");
|
||||
}
|
||||
catch(const Base::Exception& e) {
|
||||
PyErr_SetString(PyExc_ImportError, e.what());
|
||||
return;
|
||||
}
|
||||
|
||||
PyObject* pathModule = Path::initModule();
|
||||
Base::Console().Log("Loading Path module... done\n");
|
||||
|
||||
|
||||
// Add Types to module
|
||||
Base::Interpreter().addType(&Path::CommandPy ::Type, pathModule, "Command");
|
||||
Base::Interpreter().addType(&Path::PathPy ::Type, pathModule, "Path");
|
||||
Base::Interpreter().addType(&Path::ToolPy ::Type, pathModule, "Tool");
|
||||
Base::Interpreter().addType(&Path::TooltablePy ::Type, pathModule, "Tooltable");
|
||||
Base::Interpreter().addType(&Path::AreaPy ::Type, pathModule, "Area");
|
||||
|
||||
// NOTE: To finish the initialization of our own type objects we must
|
||||
// call PyType_Ready, otherwise we run into a segmentation fault, later on.
|
||||
|
@ -74,4 +85,7 @@ PyMODINIT_FUNC initPath()
|
|||
Path::FeatureCompoundPython ::init();
|
||||
Path::FeatureShape ::init();
|
||||
Path::FeatureShapePython ::init();
|
||||
Path::Area ::init();
|
||||
Path::FeatureArea ::init();
|
||||
Path::FeatureAreaPython ::init();
|
||||
}
|
||||
|
|
592
src/Mod/Path/App/Area.cpp
Normal file
592
src/Mod/Path/App/Area.cpp
Normal file
|
@ -0,0 +1,592 @@
|
|||
/****************************************************************************
|
||||
* Copyright (c) 2017 Zheng, Lei (realthunder) <realthunder.dev@gmail.com>*
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
****************************************************************************/
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#ifndef _PreComp_
|
||||
#endif
|
||||
|
||||
#include <BRepLib.hxx>
|
||||
#include <BRep_Builder.hxx>
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <BRepAdaptor_Curve.hxx>
|
||||
#include <BRepAdaptor_Surface.hxx>
|
||||
#include <BRepBuilderAPI_FindPlane.hxx>
|
||||
#include <BRepLib_FindSurface.hxx>
|
||||
#include <BRepBuilderAPI_MakeEdge.hxx>
|
||||
#include <BRepBuilderAPI_MakeWire.hxx>
|
||||
#include <BRepTools.hxx>
|
||||
#include <BRepTools_WireExplorer.hxx>
|
||||
#include <TopoDS.hxx>
|
||||
#include <TopoDS_Compound.hxx>
|
||||
#include <TopoDS_Solid.hxx>
|
||||
#include <TopoDS_Vertex.hxx>
|
||||
#include <TopExp.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <GeomAbs_JoinType.hxx>
|
||||
#include <Geom_Circle.hxx>
|
||||
#include <Geom_Ellipse.hxx>
|
||||
#include <Geom_Line.hxx>
|
||||
#include <Geom_Plane.hxx>
|
||||
#include <Standard_Failure.hxx>
|
||||
#include <gp_Circ.hxx>
|
||||
#include <gp_GTrsf.hxx>
|
||||
#include <Standard_Version.hxx>
|
||||
#include <GCPnts_UniformDeflection.hxx>
|
||||
|
||||
#include <Base/Exception.h>
|
||||
#include <Base/Tools.h>
|
||||
#include <Base/Console.h>
|
||||
|
||||
#include <Mod/Part/App/TopoShape.h>
|
||||
#include <Mod/Part/App/FaceMakerBullseye.h>
|
||||
#include "Area.h"
|
||||
#include "../libarea/Area.h"
|
||||
|
||||
using namespace Path;
|
||||
|
||||
CAreaParams::CAreaParams()
|
||||
:PARAM_INIT(NAME,AREA_PARAMS_CAREA)
|
||||
{}
|
||||
|
||||
AreaParams::AreaParams()
|
||||
:PARAM_INIT(NAME,AREA_PARAMS_BASE)
|
||||
{}
|
||||
|
||||
CAreaConfig::CAreaConfig(const CAreaParams &p, bool noFitArcs)
|
||||
:params(p)
|
||||
{
|
||||
// Arc fitting is lossy. we shall reduce the number of unecessary fit
|
||||
if(noFitArcs)
|
||||
params.FitArcs=false;
|
||||
|
||||
#define AREA_CONF_SAVE_AND_APPLY(_param) \
|
||||
PARAM_FNAME(_param) = BOOST_PP_CAT(CArea::get_,PARAM_FARG(_param))();\
|
||||
BOOST_PP_CAT(CArea::set_,PARAM_FARG(_param))(params.PARAM_FNAME(_param));
|
||||
|
||||
PARAM_FOREACH(AREA_CONF_SAVE_AND_APPLY,AREA_PARAMS_CAREA)
|
||||
}
|
||||
|
||||
CAreaConfig::~CAreaConfig() {
|
||||
|
||||
#define AREA_CONF_RESTORE(_param) \
|
||||
BOOST_PP_CAT(CArea::set_,PARAM_FARG(_param))(PARAM_FNAME(_param));
|
||||
|
||||
PARAM_FOREACH(AREA_CONF_RESTORE,AREA_PARAMS_CAREA)
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TYPESYSTEM_SOURCE(Path::Area, Base::BaseClass);
|
||||
|
||||
Area::Area(const AreaParams *params)
|
||||
:myArea(NULL)
|
||||
,myAreaOpen(NULL)
|
||||
,myHaveFace(false)
|
||||
{
|
||||
if(params)
|
||||
setParams(*params);
|
||||
}
|
||||
|
||||
Area::~Area() {
|
||||
clean();
|
||||
}
|
||||
|
||||
void Area::setPlane(const TopoDS_Shape &shape) {
|
||||
myWorkPlane = shape;
|
||||
}
|
||||
|
||||
void Area::add(CArea &area, const TopoDS_Shape &shape, const gp_Trsf *trsf,
|
||||
double deflection, CArea *areaOpen, bool to_edges, bool reorder)
|
||||
{
|
||||
bool haveShape = false;
|
||||
|
||||
for (TopExp_Explorer it(shape, TopAbs_FACE); it.More(); it.Next()) {
|
||||
haveShape = true;
|
||||
const TopoDS_Face &face = TopoDS::Face(it.Current());
|
||||
for (TopExp_Explorer it(face, TopAbs_WIRE); it.More(); it.Next())
|
||||
add(area,TopoDS::Wire(it.Current()),trsf,deflection);
|
||||
}
|
||||
|
||||
if(haveShape) return;
|
||||
|
||||
CArea _area;
|
||||
CArea _areaOpen;
|
||||
|
||||
for (TopExp_Explorer it(shape, TopAbs_WIRE); it.More(); it.Next()) {
|
||||
haveShape = true;
|
||||
const TopoDS_Wire &wire = TopoDS::Wire(it.Current());
|
||||
if(BRep_Tool::IsClosed(wire))
|
||||
add(_area,wire,trsf,deflection);
|
||||
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);
|
||||
}else
|
||||
add(_areaOpen,wire,trsf,deflection);
|
||||
}
|
||||
|
||||
if(!haveShape) {
|
||||
for (TopExp_Explorer it(shape, TopAbs_EDGE); it.More(); it.Next()) {
|
||||
add(_areaOpen,BRepBuilderAPI_MakeWire(
|
||||
TopoDS::Edge(it.Current())).Wire(),trsf,deflection);
|
||||
}
|
||||
}
|
||||
|
||||
if(reorder)
|
||||
_area.Reorder();
|
||||
area.m_curves.splice(area.m_curves.end(),_area.m_curves);
|
||||
if(areaOpen)
|
||||
areaOpen->m_curves.splice(areaOpen->m_curves.end(),_areaOpen.m_curves);
|
||||
else
|
||||
area.m_curves.splice(area.m_curves.end(),_areaOpen.m_curves);
|
||||
}
|
||||
|
||||
void Area::add(CArea &area, const TopoDS_Wire& wire,
|
||||
const gp_Trsf *trsf, double deflection)
|
||||
{
|
||||
CCurve ccurve;
|
||||
BRepTools_WireExplorer xp(trsf?TopoDS::Wire(
|
||||
wire.Moved(TopLoc_Location(*trsf))):wire);
|
||||
|
||||
gp_Pnt p = BRep_Tool::Pnt(xp.CurrentVertex());
|
||||
ccurve.append(CVertex(Point(p.X(),p.Y())));
|
||||
|
||||
for (;xp.More();xp.Next()) {
|
||||
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: {
|
||||
ccurve.append(CVertex(Point(p.X(),p.Y())));
|
||||
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()),
|
||||
Point(loc.X(),loc.Y())));
|
||||
}
|
||||
ccurve.append(CVertex(dir,Point(p.X(),p.Y()),
|
||||
Point(loc.X(),loc.Y())));
|
||||
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);
|
||||
ccurve.append(CVertex(Point(pt.X(),pt.Y())));
|
||||
}
|
||||
}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());
|
||||
}
|
||||
area.append(ccurve);
|
||||
}
|
||||
|
||||
|
||||
void Area::clean(bool deleteShapes) {
|
||||
myShape.Nullify();
|
||||
delete myArea;
|
||||
myArea = NULL;
|
||||
delete myAreaOpen;
|
||||
myAreaOpen = NULL;
|
||||
if(deleteShapes)
|
||||
myShapes.clear();
|
||||
}
|
||||
|
||||
void Area::add(const TopoDS_Shape &shape,short op) {
|
||||
#define AREA_SRC_OP(_v) op
|
||||
PARAM_ENUM_CONVERT(AREA_SRC_OP,,PARAM_ENUM_EXCEPT,AREA_PARAMS_OPCODE);
|
||||
TopExp_Explorer it(shape, TopAbs_SHELL);
|
||||
if(it.More())
|
||||
throw Base::ValueError("not a 2D shape");
|
||||
clean();
|
||||
if(myShapes.empty())
|
||||
Operation = ClipperLib::ctUnion;
|
||||
myShapes.push_back(Shape((short)Operation,shape));
|
||||
}
|
||||
|
||||
|
||||
void Area::setParams(const AreaParams ¶ms) {
|
||||
#define AREA_SRC2(_v) params._v
|
||||
// Validate all enum type of parameters
|
||||
PARAM_ENUM_CHECK(AREA_SRC2,PARAM_ENUM_EXCEPT,AREA_PARAMS_CONF);
|
||||
if(params!=myParams)
|
||||
clean();
|
||||
myParams = params;
|
||||
}
|
||||
|
||||
void Area::addToBuild(CArea &area, const TopoDS_Shape &shape) {
|
||||
if(!myHaveFace) {
|
||||
TopExp_Explorer it(shape, TopAbs_FACE);
|
||||
myHaveFace = it.More();
|
||||
}
|
||||
CArea areaOpen;
|
||||
add(area,shape,&myTrsf,myParams.Deflection,&areaOpen,
|
||||
myParams.OpenMode==OpenModeEdges,myParams.Reorder);
|
||||
if(areaOpen.m_curves.size()) {
|
||||
if(&area == myArea || myParams.OpenMode == OpenModeNone)
|
||||
myAreaOpen->m_curves.splice(myAreaOpen->m_curves.end(),areaOpen.m_curves);
|
||||
else
|
||||
Base::Console().Warning("open wires discarded in clipping shapes\n");
|
||||
}
|
||||
}
|
||||
|
||||
void Area::build() {
|
||||
if(myArea) return;
|
||||
|
||||
if(myShapes.empty())
|
||||
throw Base::ValueError("Null shape");
|
||||
|
||||
#define AREA_SRC(_v) myParams._v
|
||||
PARAM_ENUM_CONVERT(AREA_SRC,,PARAM_ENUM_EXCEPT,AREA_PARAMS_CLIPPER_FILL);
|
||||
|
||||
TopoDS_Builder builder;
|
||||
TopoDS_Compound comp;
|
||||
builder.MakeCompound(comp);
|
||||
if(!myWorkPlane.IsNull())
|
||||
builder.Add(comp,myWorkPlane);
|
||||
else {
|
||||
for(const Shape &s : myShapes)
|
||||
builder.Add(comp, s.shape);
|
||||
}
|
||||
BRepLib_FindSurface planeFinder(comp,-1,Standard_True);
|
||||
if (!planeFinder.Found())
|
||||
throw Base::ValueError("shapes are not coplanar");
|
||||
|
||||
myTrsf.SetTransformation(GeomAdaptor_Surface(
|
||||
planeFinder.Surface()).Plane().Position());
|
||||
|
||||
myArea = new CArea();
|
||||
myAreaOpen = new CArea();
|
||||
|
||||
CAreaConfig conf(myParams);
|
||||
CArea areaClip;
|
||||
|
||||
short op = ClipperLib::ctUnion;
|
||||
bool pending = false;
|
||||
for(const Shape &s : myShapes) {
|
||||
if(op!=s.op) {
|
||||
if(myParams.OpenMode!=OpenModeNone)
|
||||
myArea->m_curves.splice(myArea->m_curves.end(),myAreaOpen->m_curves);
|
||||
pending = false;
|
||||
myArea->Clip((ClipperLib::ClipType)op,&areaClip,SubjectFill,ClipFill);
|
||||
areaClip.m_curves.clear();
|
||||
op=s.op;
|
||||
}
|
||||
addToBuild(op==ClipperLib::ctUnion?*myArea:areaClip,s.shape);
|
||||
pending = true;
|
||||
}
|
||||
if(pending){
|
||||
if(myParams.OpenMode!=OpenModeNone)
|
||||
myArea->m_curves.splice(myArea->m_curves.end(),myAreaOpen->m_curves);
|
||||
myArea->Clip((ClipperLib::ClipType)op,&areaClip,SubjectFill,ClipFill);
|
||||
}
|
||||
myArea->m_curves.splice(myArea->m_curves.end(),myAreaOpen->m_curves);
|
||||
}
|
||||
|
||||
TopoDS_Shape Area::toShape(CArea &area, short fill) {
|
||||
gp_Trsf trsf(myTrsf.Inverted());
|
||||
bool bFill;
|
||||
switch(fill){
|
||||
case Area::FillAuto:
|
||||
bFill = myHaveFace;
|
||||
break;
|
||||
case Area::FillFace:
|
||||
bFill = true;
|
||||
break;
|
||||
default:
|
||||
bFill = false;
|
||||
}
|
||||
if(myParams.FitArcs) {
|
||||
if(&area == myArea) {
|
||||
CArea copy(area);
|
||||
copy.FitArcs();
|
||||
return toShape(copy,bFill,&trsf);
|
||||
}
|
||||
area.FitArcs();
|
||||
}
|
||||
return toShape(area,bFill,&trsf);
|
||||
}
|
||||
|
||||
const TopoDS_Shape &Area::getShape() {
|
||||
if(myShape.IsNull()) {
|
||||
build();
|
||||
CAreaConfig conf(myParams);
|
||||
myShape = toShape(*myArea,myParams.Fill);
|
||||
}
|
||||
return myShape;
|
||||
}
|
||||
|
||||
TopoDS_Shape Area::makeOffset(PARAM_ARGS(ARG,AREA_PARAMS_OFFSET)) {
|
||||
std::list<TopoDS_Shape> shapes;
|
||||
makeOffset(shapes,PARAM_FIELDS(ARG,AREA_PARAMS_OFFSET));
|
||||
if(shapes.empty())
|
||||
return TopoDS_Shape();
|
||||
if(shapes.size()==1)
|
||||
return shapes.front();
|
||||
BRep_Builder builder;
|
||||
TopoDS_Compound compound;
|
||||
builder.MakeCompound(compound);
|
||||
for(const TopoDS_Shape &s : shapes)
|
||||
builder.Add(compound,s);
|
||||
return compound;
|
||||
}
|
||||
|
||||
void Area::makeOffset(std::list<TopoDS_Shape> &shapes,
|
||||
PARAM_ARGS(ARG,AREA_PARAMS_OFFSET))
|
||||
{
|
||||
if(fabs(offset)<Precision::Confusion()){
|
||||
shapes.push_back(getShape());
|
||||
return;
|
||||
}
|
||||
|
||||
build();
|
||||
CAreaConfig conf(myParams);
|
||||
|
||||
if(myParams.Thicken) {
|
||||
CArea area(*myArea);
|
||||
area.Thicken(fabs(offset));
|
||||
shapes.push_back(toShape(area,myParams.Fill));
|
||||
return;
|
||||
}
|
||||
|
||||
long count = 1;
|
||||
if(extra_pass) {
|
||||
if(fabs(stepover)<Precision::Confusion())
|
||||
stepover = offset;
|
||||
if(extra_pass > 0) {
|
||||
count += extra_pass;
|
||||
}else{
|
||||
if(stepover>0 || offset>0)
|
||||
throw Base::ValueError("invalid extra count");
|
||||
// In this case, we loop until no outputs from clipper
|
||||
count=-1;
|
||||
}
|
||||
}
|
||||
|
||||
PARAM_ENUM_CONVERT(AREA_SRC,,PARAM_ENUM_EXCEPT,AREA_PARAMS_OFFSET_CONF);
|
||||
#ifdef AREA_OFFSET_ALGO
|
||||
PARAM_ENUM_CONVERT(AREA_SRC,,PARAM_ENUM_EXCEPT,AREA_PARAMS_CLIPPER_FILL);
|
||||
#endif
|
||||
|
||||
for(int i=0;count<0||i<count;++i,offset+=stepover) {
|
||||
CArea area;
|
||||
CArea areaOpen;
|
||||
#ifdef AREA_OFFSET_ALGO
|
||||
if(myParams.Algo == Area::Algolibarea) {
|
||||
for(const CCurve &c : myArea->m_curves) {
|
||||
if(c.IsClosed())
|
||||
area.append(c);
|
||||
else
|
||||
areaOpen.append(c);
|
||||
}
|
||||
}else
|
||||
#endif
|
||||
area = *myArea;
|
||||
|
||||
#ifdef AREA_OFFSET_ALGO
|
||||
switch(myParams.Algo){
|
||||
case Area::Algolibarea:
|
||||
// libarea somehow fails offset without Reorder, but ClipperOffset
|
||||
// works okay. Don't know why
|
||||
area.Reorder();
|
||||
area.Offset(-offset);
|
||||
if(areaOpen.m_curves.size()) {
|
||||
areaOpen.Thicken(offset);
|
||||
area.Clip(ClipperLib::ctUnion,&areaOpen,SubjectFill,ClipFill);
|
||||
}
|
||||
break;
|
||||
case Area::AlgoClipperOffset:
|
||||
#endif
|
||||
area.OffsetWithClipper(offset,JoinType,EndType,
|
||||
myParams.MiterLimit,myParams.RoundPreceision);
|
||||
#ifdef AREA_OFFSET_ALGO
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(area.m_curves.empty())
|
||||
return;
|
||||
|
||||
if(count == 1) {
|
||||
shapes.push_back(toShape(area,myParams.Fill));
|
||||
return;
|
||||
}
|
||||
shapes.push_back(toShape(area,Area::FillNone));
|
||||
}
|
||||
}
|
||||
|
||||
TopoDS_Shape Area::makePocket(PARAM_ARGS(ARG,AREA_PARAMS_POCKET)) {
|
||||
if(tool_radius < Precision::Confusion())
|
||||
throw Base::ValueError("tool radius too small");
|
||||
|
||||
if(stepover == 0.0)
|
||||
stepover = tool_radius;
|
||||
|
||||
if(stepover < Precision::Confusion())
|
||||
throw Base::ValueError("stepover too small");
|
||||
|
||||
if(mode == Area::PocketModeNone)
|
||||
return TopoDS_Shape();
|
||||
|
||||
PocketMode pm;
|
||||
switch(mode) {
|
||||
case Area::PocketModeZigZag:
|
||||
pm = ZigZagPocketMode;
|
||||
break;
|
||||
case Area::PocketModeSpiral:
|
||||
pm = SpiralPocketMode;
|
||||
break;
|
||||
case Area::PocketModeOffset: {
|
||||
PARAM_DECLARE_INIT(NAME,AREA_PARAMS_OFFSET);
|
||||
Offset = -tool_radius-extra_offset;
|
||||
ExtraPass = -1;
|
||||
Stepover = -stepover;
|
||||
return makeOffset(PARAM_FIELDS(NAME,AREA_PARAMS_OFFSET));
|
||||
}case Area::PocketModeZigZagOffset:
|
||||
pm = ZigZagThenSingleOffsetPocketMode;
|
||||
break;
|
||||
default:
|
||||
throw Base::ValueError("unknown poket mode");
|
||||
}
|
||||
|
||||
build();
|
||||
CAreaConfig conf(myParams);
|
||||
CAreaPocketParams params(
|
||||
tool_radius,extra_offset,stepover,from_center,pm,zig_angle);
|
||||
CArea in(*myArea),out;
|
||||
// MakePcoketToolPath internally uses libarea Offset which somehow demands
|
||||
// reorder before input, otherwise nothing is shown.
|
||||
in.Reorder();
|
||||
in.MakePocketToolpath(out.m_curves,params);
|
||||
return toShape(out,FillNone);
|
||||
}
|
||||
|
||||
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_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());
|
||||
}
|
||||
|
||||
if(fill) {
|
||||
try{
|
||||
Part::FaceMakerBullseye mkFace;
|
||||
if(trsf)
|
||||
mkFace.setPlane(gp_Pln().Transformed(*trsf));
|
||||
for(TopExp_Explorer it(compound, TopAbs_WIRE); it.More(); it.Next())
|
||||
mkFace.addWire(TopoDS::Wire(it.Current()));
|
||||
mkFace.Build();
|
||||
if (mkFace.Shape().IsNull())
|
||||
Base::Console().Warning("FaceMakerBullseye returns null shape\n");
|
||||
return mkFace.Shape();
|
||||
}catch (Base::Exception &e){
|
||||
Base::Console().Warning("FaceMakerBullseye failed: %s\n", e.what());
|
||||
}
|
||||
}
|
||||
return compound;
|
||||
}
|
||||
|
238
src/Mod/Path/App/Area.h
Normal file
238
src/Mod/Path/App/Area.h
Normal file
|
@ -0,0 +1,238 @@
|
|||
/****************************************************************************
|
||||
* Copyright (c) 2017 Zheng, Lei (realthunder) <realthunder.dev@gmail.com>*
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef PATH_AREA_H
|
||||
#define PATH_AREA_H
|
||||
|
||||
#include <TopoDS.hxx>
|
||||
#include <gp_Pln.hxx>
|
||||
#include <gp_Circ.hxx>
|
||||
#include <gp_GTrsf.hxx>
|
||||
|
||||
#include "AreaParams.h"
|
||||
|
||||
class CArea;
|
||||
|
||||
namespace Path
|
||||
{
|
||||
|
||||
/** Store libarea algorithm configuration */
|
||||
struct PathExport CAreaParams {
|
||||
PARAM_DECLARE(NAME,AREA_PARAMS_CAREA)
|
||||
CAreaParams();
|
||||
};
|
||||
|
||||
/** Store all Area configurations */
|
||||
struct PathExport AreaParams: CAreaParams {
|
||||
|
||||
PARAM_DECLARE(NAME,AREA_PARAMS_BASE)
|
||||
PARAM_DECLARE(NAME,AREA_PARAMS_OFFSET_CONF)
|
||||
|
||||
bool operator==(const AreaParams &other) const {
|
||||
#define AREA_COMPARE(_param) \
|
||||
if(PARAM_FIELD(NAME,_param)!=other.PARAM_FIELD(NAME,_param)) return false;
|
||||
PARAM_FOREACH(AREA_COMPARE,AREA_PARAMS_CONF)
|
||||
return true;
|
||||
}
|
||||
bool operator!=(const AreaParams &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
AreaParams();
|
||||
};
|
||||
|
||||
/** libarea configurator
|
||||
*
|
||||
* It is kind of troublesome with the fact that libarea uses static variables to
|
||||
* config its algorithm. CAreaConfig makes it easy to safely customize libarea.
|
||||
*/
|
||||
struct PathExport CAreaConfig {
|
||||
|
||||
/** Stores current libarea settings */
|
||||
PARAM_DECLARE(NAME,AREA_PARAMS_CAREA)
|
||||
|
||||
/** Stores user defined setting */
|
||||
CAreaParams params;
|
||||
|
||||
/** The constructor automatically saves current setting and apply user defined ones
|
||||
*
|
||||
* \arg \c p user defined configurations
|
||||
* \arg \c noFitArgs if true, will override and disable arc fitting. Because
|
||||
* arc unfiting and fitting is lossy. And repeatedly perform these operation
|
||||
* may cause shape deformation. So it is best to delay arc fitting until the
|
||||
* final step*/
|
||||
CAreaConfig(const CAreaParams &p, bool noFitArcs=true);
|
||||
|
||||
/** The destructor restores the setting, and thus exception safe. */
|
||||
~CAreaConfig();
|
||||
};
|
||||
|
||||
|
||||
/** Base class for FreeCAD wrapping of libarea */
|
||||
class PathExport Area: public Base::BaseClass {
|
||||
|
||||
TYPESYSTEM_HEADER();
|
||||
|
||||
protected:
|
||||
|
||||
struct Shape {
|
||||
short op;
|
||||
TopoDS_Shape shape;
|
||||
|
||||
Shape(short opCode, const TopoDS_Shape &s)
|
||||
:op(opCode)
|
||||
,shape(s)
|
||||
{}
|
||||
};
|
||||
|
||||
std::list<Shape> myShapes;
|
||||
CArea *myArea;
|
||||
CArea *myAreaOpen;
|
||||
gp_Trsf myTrsf;
|
||||
AreaParams myParams;
|
||||
TopoDS_Shape myWorkPlane;
|
||||
TopoDS_Shape myShape;
|
||||
bool myHaveFace;
|
||||
|
||||
/** Called internally to combine children shapes for further processing */
|
||||
void build();
|
||||
|
||||
/** Called by build() to add children shape
|
||||
*
|
||||
* Mainly for checking if there is any faces for auto fill*/
|
||||
void addToBuild(CArea &area, const TopoDS_Shape &shape);
|
||||
|
||||
/** Called internally to obtain the combained children shapes */
|
||||
TopoDS_Shape toShape(CArea &area, short fill);
|
||||
|
||||
public:
|
||||
/** Declare all parameters defined in #AREA_PARAMS_ALL as member variable */
|
||||
PARAM_ENUM_DECLARE(AREA_PARAMS_ALL)
|
||||
|
||||
public:
|
||||
Area(const AreaParams *params = NULL);
|
||||
virtual ~Area();
|
||||
|
||||
/** 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
|
||||
*
|
||||
* \arg \c shape: a shape defining a working plane
|
||||
*/
|
||||
void setPlane(const TopoDS_Shape &shape);
|
||||
|
||||
/** Add a child shape with given operation code
|
||||
*
|
||||
* No validation is done at this point. Exception will be thrown when asking
|
||||
* for output shape, if any of the children shapes is not valid or not
|
||||
* coplanar
|
||||
*
|
||||
* \arg \c shape: the child shape
|
||||
* \arg \c op: operation code, see #AREA_PARAMS_OPCODE
|
||||
*/
|
||||
void add(const TopoDS_Shape &shape,PARAM_ARGS_DEF(ARG,AREA_PARAMS_OPCODE));
|
||||
|
||||
/** Generate an offset of the combined shape
|
||||
*
|
||||
* See #AREA_PARAMS_OFFSET for description of the arguments.
|
||||
* If more than one offset is requested, a compound shape is return
|
||||
* containing all offset shapes as wires regardless of \c Fill setting.
|
||||
*/
|
||||
TopoDS_Shape makeOffset(PARAM_ARGS_DEF(ARG,AREA_PARAMS_OFFSET));
|
||||
|
||||
/** Obtain a list of offset shapes of the combined shape,
|
||||
*
|
||||
* See #AREA_PARAMS_OFFSET for description of the arguments.
|
||||
*/
|
||||
void makeOffset(std::list<TopoDS_Shape> &shapes,
|
||||
PARAM_ARGS_DEF(ARG,AREA_PARAMS_OFFSET));
|
||||
|
||||
/** Make a pocket of the combined shape
|
||||
*
|
||||
* See #AREA_PARAMS_POCKET for description of the arguments.
|
||||
*/
|
||||
TopoDS_Shape makePocket(PARAM_ARGS_DEF(ARG,AREA_PARAMS_POCKET));
|
||||
|
||||
|
||||
/** Config this Area object */
|
||||
void setParams(const AreaParams ¶ms);
|
||||
|
||||
|
||||
/** Get the current configuration */
|
||||
const AreaParams &getParams() const {
|
||||
return myParams;
|
||||
}
|
||||
|
||||
/** Clean internal caches
|
||||
*
|
||||
* The combained shapes is cached internally to make other operation more
|
||||
* efficient, such as makeOffset() and makePocket()
|
||||
*
|
||||
* \arg \c deleteShapes: if true, delete all children shapes.
|
||||
*/
|
||||
void clean(bool deleteShapes=false);
|
||||
|
||||
/** Get the combined shape */
|
||||
const TopoDS_Shape &getShape();
|
||||
|
||||
/** Add a OCC wire shape to CArea
|
||||
*
|
||||
* \arg \c area: output converted curved object to here
|
||||
* \arg \c wire: input wire object
|
||||
* \arg \c trsf: optional transform matrix to transform the wire shape into
|
||||
* XY0 plane.
|
||||
* \arg \c deflection: for defecting non circular curves
|
||||
* */
|
||||
static void add(CArea &area, const TopoDS_Wire &wire,
|
||||
const gp_Trsf *trsf=NULL,double deflection=0.01);
|
||||
|
||||
/** Add a OCC generic shape to CArea
|
||||
*
|
||||
* \arg \c area: output converted curved object to here
|
||||
* \arg \c shape: input shape object
|
||||
* \arg \c trsf: optional transform matrix to transform the wire shape into
|
||||
* XY0 plane.
|
||||
* \arg \c deflection: for defecting non circular curves
|
||||
* \arg \c 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
|
||||
* */
|
||||
static void add(CArea &area, const TopoDS_Shape &shape, const gp_Trsf *trsf=NULL,
|
||||
double deflection=0.01,CArea *areaOpen=NULL, bool to_edges=false, bool reorder=true);
|
||||
|
||||
/** Convert curves in CArea into an OCC shape
|
||||
*
|
||||
* \arg \c area: input area object
|
||||
* \arg \c fill: if true, create a face object from the wires
|
||||
* \arg \c trsf: optional transform matrix to transform the shape back into
|
||||
* its original position.
|
||||
* */
|
||||
static TopoDS_Shape toShape(const CArea &area, bool fill,
|
||||
const gp_Trsf *trsf=NULL);
|
||||
};
|
||||
|
||||
} //namespace Path
|
||||
|
||||
#endif //PATH_AREA_H
|
129
src/Mod/Path/App/AreaParams.h
Normal file
129
src/Mod/Path/App/AreaParams.h
Normal file
|
@ -0,0 +1,129 @@
|
|||
/****************************************************************************
|
||||
* Copyright (c) 2017 Zheng, Lei (realthunder) <realthunder.dev@gmail.com>*
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef PATH_AreaParams_H
|
||||
#define PATH_AreaParams_H
|
||||
|
||||
// deifne this to enable offset algo selection
|
||||
// #define AREA_OFFSET_ALGO
|
||||
|
||||
/** \file
|
||||
* Parameters definition for Path::Area and its companion
|
||||
* See \ref ParamPage "here" for details of parameter definition.
|
||||
*/
|
||||
|
||||
#include "ParamsHelper.h"
|
||||
|
||||
/** clipper fill type */
|
||||
#define AREA_CLIPPER_FILL_TYPE \
|
||||
(NonZero)(EvenOdd)(Positive)(Negative),(ClipperLib::PolyFillType,ClipperLib::pft)
|
||||
|
||||
/** Paramerters of clipper fill types */
|
||||
#define AREA_PARAMS_CLIPPER_FILL \
|
||||
((enum2,subject_fill,SubjectFill,0,\
|
||||
"ClipperLib subject fill type. \nSee https://goo.gl/5pYQQP",AREA_CLIPPER_FILL_TYPE))\
|
||||
((enum2,clip_fill,ClipFill,0,\
|
||||
"ClipperLib clip fill type. \nSee https://goo.gl/5pYQQP",AREA_CLIPPER_FILL_TYPE))
|
||||
|
||||
/** 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)))\
|
||||
((bool,reorder,Reorder,false,"Re-orient closed wires in wire only shapes so that inner wires become holes."))\
|
||||
((enum,open_mode,OpenMode,0,"Specify how to handle open wires.\n"\
|
||||
"'None' means combin without openeration.\n"\
|
||||
"'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"))
|
||||
|
||||
/** libarea algorithm option parameters */
|
||||
#define AREA_PARAMS_CAREA \
|
||||
((double,tolerance,Tolerance,Precision::Confusion(),"Point coincidence tolerance"))\
|
||||
((bool,fit_arcs,FitArcs,true,"Enable arc fitting"))\
|
||||
((bool,clipper_simple,Simplify,false,\
|
||||
"Simplify polygons after operation. See https://goo.gl/Mh9XK1"))\
|
||||
((double,clipper_clean_distance,CleanDistance,0.0,\
|
||||
"Clean polygon smaller than this distance. See https://goo.gl/jox3JY"))\
|
||||
((double,accuracy,Accuracy,0.01,"Arc fitting accuracy"))\
|
||||
((double,units,Unit,1.0,"Scaling factor for convertion to inch"))\
|
||||
((short,min_arc_points,MinArcPoints,4,"Minimum segments for arc discretization"))\
|
||||
((short,max_arc_points,MaxArcPoints,100,"Maximum segments for arc discretization"))\
|
||||
((double,clipper_scale,ClipperScale,10000.0,\
|
||||
"ClipperLib operate on intergers. This is the scale factor to \nconvert floating points."))
|
||||
|
||||
/** Pocket parameters
|
||||
*
|
||||
* These parameters cooresponds to CAreaPocketParams in libarea
|
||||
* */
|
||||
#define AREA_PARAMS_POCKET \
|
||||
((enum,mode,PocketMode,1,"Selects the pocket toolpath pattern",(None)(ZigZag)(Offset)(Spiral)(ZigZagOffset)))\
|
||||
((double,tool_radius,ToolRadius,1.0,"Tool radius for pocketing"))\
|
||||
((double,extra_offset,PocketExtraOffset,0.0,"Extra offset for pocketing"))\
|
||||
((double,stepover,PocketStepover,0.0,"Cutter diameter to step over on each pass. If =0, use ToolRadius."))\
|
||||
((bool,from_center,FromCenter,true,"Start pocketing from center"))\
|
||||
((double,zig_angle,ZigAngle,45,"Zig angle in degree"))
|
||||
|
||||
/** Operation code */
|
||||
#define AREA_PARAMS_OPCODE \
|
||||
((enum2,op,Operation,0,"Boolean operation",\
|
||||
(Union)(Difference)(Intersection)(Xor),(ClipperLib::ClipType,ClipperLib::ct)))
|
||||
|
||||
/** Offset parameters */
|
||||
#define AREA_PARAMS_OFFSET \
|
||||
((double,offset,Offset,0.0,"Offset value, positive for expansion, negative for shrinking"))\
|
||||
((long,extra_pass,ExtraPass,0,"Number of extra offset pass to generate."))\
|
||||
((double,stepover,Stepover,0.0,"Cutter diameter to step over on each pass. If =0, use Offset"))
|
||||
|
||||
#ifdef AREA_OFFSET_ALGO
|
||||
# define AREA_PARAMS_OFFSET_ALGO \
|
||||
((enum,algo,Algo,0,"Offset algorithm type",(Clipper)(libarea)))
|
||||
#else
|
||||
# define AREA_PARAMS_OFFSET_ALGO
|
||||
#endif
|
||||
|
||||
/** Offset configuration parameters */
|
||||
#define AREA_PARAMS_OFFSET_CONF \
|
||||
AREA_PARAMS_OFFSET_ALGO \
|
||||
((bool,thicken,Thicken,false,"Thicken the resulting wires with Offset"))\
|
||||
((enum2,join_type,JoinType,0,"ClipperOffset join type. \nSee https://goo.gl/4odfQh",\
|
||||
(Round)(Square)(Miter),(ClipperLib::JoinType,ClipperLib::jt)))\
|
||||
((enum2,end_type,EndType,0,"\nClipperOffset end type. See https://goo.gl/tj7gkX",\
|
||||
(OpenRound)(ClosedPolygon)(ClosedLine)(OpenSquare)(OpenButt),(ClipperLib::EndType,ClipperLib::et)))\
|
||||
((double,miter_limit,MiterLimit,2.0,"Miter limit for joint type Miter. See https://goo.gl/K8xX9h"))\
|
||||
((double,round_precision,RoundPreceision,0.0,\
|
||||
"Round joint precision. If =0, it defaults to Accuracy. \nSee https://goo.gl/4odfQh"))
|
||||
|
||||
/** Group of all Area configuration parameters */
|
||||
#define AREA_PARAMS_CONF \
|
||||
AREA_PARAMS_CAREA \
|
||||
AREA_PARAMS_BASE \
|
||||
AREA_PARAMS_OFFSET_CONF
|
||||
|
||||
/** Group of all Area parameters */
|
||||
#define AREA_PARAMS_ALL \
|
||||
AREA_PARAMS_CONF \
|
||||
AREA_PARAMS_OPCODE \
|
||||
AREA_PARAMS_OFFSET \
|
||||
AREA_PARAMS_POCKET
|
||||
|
||||
#endif //PATH_AreaParam_H
|
62
src/Mod/Path/App/AreaPy.xml
Normal file
62
src/Mod/Path/App/AreaPy.xml
Normal file
|
@ -0,0 +1,62 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
|
||||
<PythonExport
|
||||
Father="BaseClassPy"
|
||||
Name="AreaPy"
|
||||
Twin="Area"
|
||||
TwinPointer="Area"
|
||||
Include="Mod/Path/App/Area.h"
|
||||
Namespace="Path"
|
||||
FatherInclude="Base/BaseClassPy.h"
|
||||
FatherNamespace="Base"
|
||||
Constructor="true"
|
||||
Delete="true">
|
||||
<Documentation>
|
||||
<Author Licence="LGPL" Name="Zheng, Lei" EMail="realthunder.dev@gmail.com" />
|
||||
<UserDocu>FreeCAD python wrapper of libarea</UserDocu>
|
||||
</Documentation>
|
||||
<Methode Name="add" Keyword='true'>
|
||||
<Documentation>
|
||||
<UserDocu></UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="setPlane">
|
||||
<Documentation>
|
||||
<UserDocu>setPlane(shape): Set the working plane. The shape will not be used for
|
||||
any operation</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="toShape" Keyword='true'>
|
||||
<Documentation>
|
||||
<UserDocu>toShape(rebuild=False): Return the resulting shape</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="makeOffset" Keyword='true'>
|
||||
<Documentation>
|
||||
<UserDocu></UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="makePocket" Keyword='true'>
|
||||
<Documentation>
|
||||
<UserDocu></UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="setParams" Keyword="true">
|
||||
<Documentation>
|
||||
<UserDocu></UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getParamsDesc" Keyword="true">
|
||||
<Documentation>
|
||||
<UserDocu>getParamsDesc(as_string=True): Returns a list of supported parameters and their descriptions.\n
|
||||
* as_string: if False, then return a dictionary of documents of all supported parameters.
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getParams">
|
||||
<Documentation>
|
||||
<UserDocu>Get current algorithm parameters as a dictionary.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
</PythonExport>
|
||||
</GenerateModel>
|
292
src/Mod/Path/App/AreaPyImp.cpp
Normal file
292
src/Mod/Path/App/AreaPyImp.cpp
Normal file
|
@ -0,0 +1,292 @@
|
|||
/****************************************************************************
|
||||
* Copyright (c) 2017 Zheng, Lei (realthunder) <realthunder.dev@gmail.com>*
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#include <Mod/Part/App/OCCError.h>
|
||||
#include <Mod/Part/App/TopoShapePy.h>
|
||||
|
||||
#include "Mod/Path/App/Area.h"
|
||||
|
||||
// inclusion of the generated files (generated out of AreaPy.xml)
|
||||
#include "AreaPy.h"
|
||||
#include "AreaPy.cpp"
|
||||
|
||||
|
||||
struct AreaDoc {
|
||||
const char *name;
|
||||
const char *doc;
|
||||
};
|
||||
|
||||
/** Generate doc string from parameter definitions
|
||||
* It will generate doc string and replace the one generated from xml
|
||||
* */
|
||||
static const AreaDoc myDocs[] = {
|
||||
{
|
||||
"setParams",
|
||||
"setParam(key=value...): Set algorithm parameters. You can call getParamsDesc() to \n"
|
||||
"get a list of supported parameters and their descriptions.\n"
|
||||
|
||||
PARAM_PY_DOC(NAME,AREA_PARAMS_CONF)
|
||||
},
|
||||
{
|
||||
"add",
|
||||
|
||||
"add((shape...)," PARAM_PY_ARGS_DOC(ARG,AREA_PARAMS_OPCODE) "):\n"
|
||||
"Add TopoShape(s) with given operation code\n"
|
||||
PARAM_PY_DOC(ARG,AREA_PARAMS_OPCODE)
|
||||
"\nThe first shape's wires will be fused together regardless of the op code given.\n"
|
||||
"Subsequent shape's wire will be combined using the op code. All shape wires\n"
|
||||
"shall be coplanar, and are used to determine a working plane for face making and\n"
|
||||
"offseting. You can call setPlane() to supply a reference shape to determin the\n"
|
||||
"working plane in case the added shapes are all colinear lines.\n",
|
||||
},
|
||||
|
||||
{
|
||||
"makeOffset",
|
||||
|
||||
"makeOffset(" PARAM_PY_ARGS_DOC(ARG,AREA_PARAMS_OFFSET) "):\n"
|
||||
"Make an 2D offset of the shape.\n"
|
||||
PARAM_PY_DOC(ARG,AREA_PARAMS_OFFSET),
|
||||
},
|
||||
{
|
||||
"makePocket",
|
||||
|
||||
"makePocket(" PARAM_PY_ARGS_DOC(ARG,AREA_PARAMS_POCKET) "):\n"
|
||||
"Generate pocket toolpath of the shape.\n"
|
||||
PARAM_PY_DOC(ARG,AREA_PARAMS_POCKET),
|
||||
},
|
||||
};
|
||||
|
||||
struct AreaPyDoc {
|
||||
AreaPyDoc() {
|
||||
for(PyMethodDef &method : Path::AreaPy::Methods) {
|
||||
if(!method.ml_name) continue;
|
||||
for(const AreaDoc &doc : myDocs) {
|
||||
if(std::strcmp(method.ml_name,doc.name)==0) {
|
||||
method.ml_doc = doc.doc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static AreaPyDoc doc;
|
||||
|
||||
namespace Part {
|
||||
extern Py::Object shape2pyshape(const TopoDS_Shape &shape);
|
||||
}
|
||||
|
||||
using namespace Path;
|
||||
|
||||
// returns a string which represents the object e.g. when printed in python
|
||||
std::string AreaPy::representation(void) const
|
||||
{
|
||||
std::stringstream str;
|
||||
str << "<Area object at " << getAreaPtr() << ">";
|
||||
return str.str();
|
||||
}
|
||||
|
||||
PyObject *AreaPy::PyMake(struct _typeobject *, PyObject *, PyObject *) // Python wrapper
|
||||
{
|
||||
return new AreaPy(new Area);
|
||||
}
|
||||
|
||||
// constructor method
|
||||
int AreaPy::PyInit(PyObject* /*args*/, PyObject* /*kwd*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyObject* AreaPy::setPlane(PyObject *args) {
|
||||
PyObject *pcObj;
|
||||
if (!PyArg_ParseTuple(args, "O!", &(Part::TopoShapePy::Type), &pcObj))
|
||||
Py_Error(Base::BaseExceptionFreeCADError, "Wrong parameters");
|
||||
|
||||
#define GET_TOPOSHAPE(_p) static_cast<Part::TopoShapePy*>(_p)->getTopoShapePtr()->getShape()
|
||||
getAreaPtr()->setPlane(GET_TOPOSHAPE(pcObj));
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
PyObject* AreaPy::toShape(PyObject *args, PyObject *keywds)
|
||||
{
|
||||
PyObject *pcObj = Py_True;
|
||||
static char *kwlist[] = {"rebuild", NULL};
|
||||
if (!PyArg_ParseTupleAndKeywords(args, keywds,"|O",kwlist,&pcObj))
|
||||
Py_Error(Base::BaseExceptionFreeCADError, "This method accepts no argument");
|
||||
|
||||
try {
|
||||
if(PyObject_IsTrue(pcObj))
|
||||
getAreaPtr()->clean(true);
|
||||
return Py::new_reference_to(Part::shape2pyshape(getAreaPtr()->getShape()));
|
||||
}
|
||||
PY_CATCH_OCC;
|
||||
}
|
||||
|
||||
PyObject* AreaPy::add(PyObject *args, PyObject *keywds)
|
||||
{
|
||||
PARAM_PY_DECLARE_INIT(ARG,AREA_PARAMS_OPCODE)
|
||||
PyObject *pcObj;
|
||||
static char *kwlist[] = {PARAM_FIELD_STRINGS(ARG,AREA_PARAMS_OPCODE), NULL};
|
||||
if (!PyArg_ParseTupleAndKeywords(args, keywds,
|
||||
"O|" PARAM_PY_KWDS(AREA_PARAMS_OPCODE),
|
||||
kwlist,&pcObj,PARAM_REF(ARG,AREA_PARAMS_OPCODE)))
|
||||
Py_Error(Base::BaseExceptionFreeCADError, "Wrong parameters");
|
||||
|
||||
if (PyObject_TypeCheck(pcObj, &(Part::TopoShapePy::Type))) {
|
||||
getAreaPtr()->add(GET_TOPOSHAPE(pcObj),op);
|
||||
return Py_None;
|
||||
}
|
||||
Py::Sequence shapeSeq(pcObj);
|
||||
for (Py::Sequence::iterator it = shapeSeq.begin(); it != shapeSeq.end(); ++it) {
|
||||
PyObject* item = (*it).ptr();
|
||||
if(!PyObject_TypeCheck(item, &(Part::TopoShapePy::Type))) {
|
||||
PyErr_SetString(PyExc_TypeError, "non-shape object in sequence");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
for (Py::Sequence::iterator it = shapeSeq.begin(); it != shapeSeq.end(); ++it){
|
||||
PyObject* item = (*it).ptr();
|
||||
getAreaPtr()->add(GET_TOPOSHAPE(item),
|
||||
PARAM_PY_FIELDS(ARG,AREA_PARAMS_OPCODE));
|
||||
}
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
PyObject* AreaPy::makeOffset(PyObject *args, PyObject *keywds)
|
||||
{
|
||||
//Generate a keyword string defined in the ARG field of OFFSET parameter list
|
||||
static char *kwlist[] = {PARAM_FIELD_STRINGS(ARG,AREA_PARAMS_OFFSET), NULL};
|
||||
|
||||
//Declare variables defined in the ARG field of the OFFSET parameter list with
|
||||
//initialization to defaults
|
||||
PARAM_PY_DECLARE_INIT(ARG,AREA_PARAMS_OFFSET)
|
||||
|
||||
//Parse arguments to overwrite the defaults
|
||||
if (!PyArg_ParseTupleAndKeywords(args, keywds,
|
||||
"|" PARAM_PY_KWDS(AREA_PARAMS_OFFSET), kwlist,
|
||||
PARAM_REF(ARG,AREA_PARAMS_OFFSET)))
|
||||
Py_Error(Base::BaseExceptionFreeCADError, "Wrong parameters");
|
||||
|
||||
try {
|
||||
//Expand the variable as function call arguments
|
||||
TopoDS_Shape resultShape = getAreaPtr()->makeOffset(
|
||||
PARAM_PY_FIELDS(ARG,AREA_PARAMS_OFFSET));
|
||||
return Py::new_reference_to(Part::shape2pyshape(resultShape));
|
||||
}
|
||||
PY_CATCH_OCC;
|
||||
}
|
||||
|
||||
PyObject* AreaPy::makePocket(PyObject *args, PyObject *keywds)
|
||||
{
|
||||
static char *kwlist[] = {PARAM_FIELD_STRINGS(ARG,AREA_PARAMS_POCKET), NULL};
|
||||
|
||||
PARAM_PY_DECLARE_INIT(ARG,AREA_PARAMS_POCKET)
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, keywds,
|
||||
"|" PARAM_PY_KWDS(AREA_PARAMS_POCKET), kwlist,
|
||||
PARAM_REF(ARG,AREA_PARAMS_POCKET)))
|
||||
Py_Error(Base::BaseExceptionFreeCADError, "Wrong parameters");
|
||||
|
||||
try {
|
||||
TopoDS_Shape resultShape = getAreaPtr()->makePocket(
|
||||
PARAM_PY_FIELDS(ARG,AREA_PARAMS_POCKET));
|
||||
return Py::new_reference_to(Part::shape2pyshape(resultShape));
|
||||
}
|
||||
PY_CATCH_OCC;
|
||||
}
|
||||
|
||||
|
||||
PyObject* AreaPy::setParams(PyObject *args, PyObject *keywds)
|
||||
{
|
||||
static char *kwlist[] = {PARAM_FIELD_STRINGS(NAME,AREA_PARAMS_CONF),NULL};
|
||||
|
||||
//Declare variables defined in the NAME field of the CONF parameter list
|
||||
PARAM_PY_DECLARE(NAME,AREA_PARAMS_CONF);
|
||||
|
||||
AreaParams params = getAreaPtr()->getParams();
|
||||
|
||||
#define AREA_SET(_param) \
|
||||
PARAM_FNAME(_param) = \
|
||||
PARAM_TYPED(PARAM_PY_CAST_,_param)(params.PARAM_FNAME(_param));
|
||||
//populate the CONF variables with params
|
||||
PARAM_FOREACH(AREA_SET,AREA_PARAMS_CONF)
|
||||
|
||||
//Parse arguments to overwrite CONF variables
|
||||
if (!PyArg_ParseTupleAndKeywords(args, keywds,
|
||||
"|" PARAM_PY_KWDS(AREA_PARAMS_CONF), kwlist,
|
||||
PARAM_REF(NAME,AREA_PARAMS_CONF)))
|
||||
Py_Error(Base::BaseExceptionFreeCADError,
|
||||
"Wrong parameters, call getParamsDesc() to get supported params");
|
||||
|
||||
#define AREA_GET(_param) \
|
||||
params.PARAM_FNAME(_param) = \
|
||||
PARAM_TYPED(PARAM_CAST_PY_,_param)(PARAM_FNAME(_param));
|
||||
//populate 'params' with the CONF variables
|
||||
PARAM_FOREACH(AREA_GET,AREA_PARAMS_CONF)
|
||||
|
||||
getAreaPtr()->setParams(params);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
PyObject* AreaPy::getParams(PyObject *args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, ""))
|
||||
Py_Error(Base::BaseExceptionFreeCADError, "This method accepts no argument");
|
||||
|
||||
const AreaParams ¶ms =getAreaPtr()->getParams();
|
||||
|
||||
PyObject *dict = PyDict_New();
|
||||
#define AREA_SRC(_v) params._v
|
||||
PARAM_PY_DICT_SET_VALUE(dict,AREA_SRC,AREA_PARAMS_CONF)
|
||||
return dict;
|
||||
}
|
||||
|
||||
PyObject* AreaPy::getParamsDesc(PyObject *args, PyObject *keywds)
|
||||
{
|
||||
PyObject *pcObj = Py_True;
|
||||
static char *kwlist[] = {"as_string", NULL};
|
||||
if (!PyArg_ParseTupleAndKeywords(args, keywds,"|O",kwlist,&pcObj))
|
||||
Py_Error(Base::BaseExceptionFreeCADError, "This method accepts no argument");
|
||||
|
||||
if(PyObject_IsTrue(pcObj))
|
||||
return PyString_FromString(PARAM_PY_DOC(NAME,AREA_PARAMS_CONF));
|
||||
|
||||
PyObject *dict = PyDict_New();
|
||||
PARAM_PY_DICT_SET_DOC(dict,AREA_PARAMS_CONF)
|
||||
return dict;
|
||||
}
|
||||
|
||||
// custom attributes get/set
|
||||
|
||||
PyObject *AreaPy::getCustomAttributes(const char* /*attr*/) const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AreaPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -22,6 +22,7 @@ link_directories(${OCC_LIBRARY_DIR})
|
|||
set(Path_LIBS
|
||||
# Robot
|
||||
Part
|
||||
area-native
|
||||
FreeCADApp
|
||||
)
|
||||
|
||||
|
@ -30,6 +31,7 @@ generate_from_xml(PathPy)
|
|||
generate_from_xml(ToolPy)
|
||||
generate_from_xml(TooltablePy)
|
||||
generate_from_xml(FeaturePathCompoundPy)
|
||||
generate_from_xml(AreaPy)
|
||||
|
||||
SET(Python_SRCS
|
||||
CommandPy.xml
|
||||
|
@ -41,6 +43,8 @@ SET(Python_SRCS
|
|||
TooltablePyImp.cpp
|
||||
FeaturePathCompoundPy.xml
|
||||
FeaturePathCompoundPyImp.cpp
|
||||
AreaPy.xml
|
||||
AreaPyImp.cpp
|
||||
)
|
||||
|
||||
SET(Mod_SRCS
|
||||
|
@ -67,6 +71,12 @@ SET(Path_SRCS
|
|||
FeaturePathCompound.h
|
||||
FeaturePathShape.cpp
|
||||
FeaturePathShape.h
|
||||
Area.cpp
|
||||
Area.h
|
||||
AreaParams.h
|
||||
ParamsHelper.h
|
||||
FeatureArea.cpp
|
||||
FeatureArea.h
|
||||
${Mod_SRCS}
|
||||
${Python_SRCS}
|
||||
)
|
||||
|
|
157
src/Mod/Path/App/FeatureArea.cpp
Normal file
157
src/Mod/Path/App/FeatureArea.cpp
Normal file
|
@ -0,0 +1,157 @@
|
|||
/****************************************************************************
|
||||
* Copyright (c) 2017 Zheng, Lei (realthunder) <realthunder.dev@gmail.com>*
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#ifndef _PreComp_
|
||||
#endif
|
||||
|
||||
#include <BRep_Builder.hxx>
|
||||
#include <TopoDS_Compound.hxx>
|
||||
|
||||
#include "FeatureArea.h"
|
||||
#include <App/DocumentObjectPy.h>
|
||||
#include <Base/Placement.h>
|
||||
#include <Mod/Part/App/PartFeature.h>
|
||||
|
||||
using namespace Path;
|
||||
|
||||
PROPERTY_SOURCE(Path::FeatureArea, Part::Feature)
|
||||
|
||||
PARAM_ENUM_STRING_DECLARE(static const char *Enums,AREA_PARAMS_ALL)
|
||||
|
||||
FeatureArea::FeatureArea()
|
||||
{
|
||||
ADD_PROPERTY(Sources,(0));
|
||||
ADD_PROPERTY(WorkPlane,(TopoDS_Shape()));
|
||||
|
||||
PARAM_PROP_ADD("Area",AREA_PARAMS_OPCODE);
|
||||
PARAM_PROP_ADD("Area",AREA_PARAMS_BASE);
|
||||
PARAM_PROP_ADD("Offset",AREA_PARAMS_OFFSET);
|
||||
PARAM_PROP_ADD("Pocket",AREA_PARAMS_POCKET);
|
||||
PARAM_PROP_ADD("Offset Settings", AREA_PARAMS_OFFSET_CONF);
|
||||
PARAM_PROP_ADD("libarea Settings",AREA_PARAMS_CAREA);
|
||||
|
||||
PARAM_PROP_SET_ENUM(Enums,AREA_PARAMS_ALL);
|
||||
PocketMode.setValue((long)0);
|
||||
}
|
||||
|
||||
FeatureArea::~FeatureArea()
|
||||
{
|
||||
}
|
||||
|
||||
App::DocumentObjectExecReturn *FeatureArea::execute(void)
|
||||
{
|
||||
std::vector<App::DocumentObject*> links = Sources.getValues();
|
||||
if (links.empty())
|
||||
return new App::DocumentObjectExecReturn("No shapes linked");
|
||||
|
||||
for (std::vector<App::DocumentObject*>::iterator it = links.begin(); it != links.end(); ++it) {
|
||||
if (!(*it && (*it)->isDerivedFrom(Part::Feature::getClassTypeId())))
|
||||
return new App::DocumentObjectExecReturn("Linked object is not a Part object (has no Shape).");
|
||||
TopoDS_Shape shape = static_cast<Part::Feature*>(*it)->Shape.getShape().getShape();
|
||||
if (shape.IsNull())
|
||||
return new App::DocumentObjectExecReturn("Linked shape object is empty");
|
||||
}
|
||||
|
||||
AreaParams params;
|
||||
|
||||
#define AREA_PROP_GET(_param) \
|
||||
params.PARAM_FNAME(_param) = PARAM_FNAME(_param).getValue();
|
||||
|
||||
PARAM_FOREACH(AREA_PROP_GET,AREA_PARAMS_CONF)
|
||||
|
||||
Area area(¶ms);
|
||||
|
||||
TopoDS_Shape workPlane = WorkPlane.getShape().getShape();
|
||||
if(!workPlane.IsNull())
|
||||
area.setPlane(workPlane);
|
||||
|
||||
area.clean(true);
|
||||
for (std::vector<App::DocumentObject*>::iterator it = links.begin(); it != links.end(); ++it) {
|
||||
area.add(static_cast<Part::Feature*>(*it)->Shape.getShape().getShape(),
|
||||
PARAM_PROP_ARGS(AREA_PARAMS_OPCODE));
|
||||
}
|
||||
|
||||
std::list<TopoDS_Shape> shapes;
|
||||
if(fabs(Offset.getValue())>Precision::Confusion())
|
||||
area.makeOffset(shapes,PARAM_PROP_ARGS(AREA_PARAMS_OFFSET));
|
||||
|
||||
if(PocketMode.getValue()) {
|
||||
Area areaPocket(¶ms);
|
||||
if(shapes.empty())
|
||||
areaPocket.add(area.getShape());
|
||||
else{
|
||||
bool front = true;
|
||||
if(shapes.size()>1) {
|
||||
double step = Stepover.getValue();
|
||||
if(fabs(step)<Precision::Confusion())
|
||||
step = Offset.getValue();
|
||||
front = step>0;
|
||||
}
|
||||
areaPocket.add(front?shapes.front():shapes.back());
|
||||
}
|
||||
shapes.push_back(areaPocket.makePocket(PARAM_PROP_ARGS(AREA_PARAMS_POCKET)));
|
||||
}
|
||||
|
||||
if(shapes.empty())
|
||||
this->Shape.setValue(area.getShape());
|
||||
else if(shapes.size()==1)
|
||||
this->Shape.setValue(shapes.front());
|
||||
else {
|
||||
BRep_Builder builder;
|
||||
TopoDS_Compound compound;
|
||||
builder.MakeCompound(compound);
|
||||
for(const TopoDS_Shape &s : shapes)
|
||||
builder.Add(compound,s);
|
||||
this->Shape.setValue(compound);
|
||||
}
|
||||
return Part::Feature::execute();
|
||||
}
|
||||
|
||||
short FeatureArea::mustExecute(void) const
|
||||
{
|
||||
if (Sources.isTouched())
|
||||
return 1;
|
||||
if (WorkPlane.isTouched())
|
||||
return 1;
|
||||
|
||||
PARAM_PROP_TOUCHED(AREA_PARAMS_ALL)
|
||||
|
||||
return Part::Feature::mustExecute();
|
||||
}
|
||||
|
||||
// Python Area feature ---------------------------------------------------------
|
||||
|
||||
namespace App {
|
||||
/// @cond DOXERR
|
||||
PROPERTY_SOURCE_TEMPLATE(Path::FeatureAreaPython, Path::FeatureArea)
|
||||
|
||||
template<> const char* Path::FeatureAreaPython::getViewProviderName(void) const {
|
||||
return "PathGui::ViewProviderArea";
|
||||
}
|
||||
/// @endcond
|
||||
|
||||
// explicit template instantiation
|
||||
template class PathExport FeaturePythonT<Path::FeatureArea>;
|
||||
}
|
||||
|
65
src/Mod/Path/App/FeatureArea.h
Normal file
65
src/Mod/Path/App/FeatureArea.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
/****************************************************************************
|
||||
* Copyright (c) 2017 Zheng, Lei (realthunder) <realthunder.dev@gmail.com>*
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef PATH_FeatureArea_H
|
||||
#define PATH_FeatureArea_H
|
||||
|
||||
#include <App/DocumentObject.h>
|
||||
#include <App/GeoFeature.h>
|
||||
#include <App/PropertyFile.h>
|
||||
#include <App/PropertyGeo.h>
|
||||
#include <App/FeaturePython.h>
|
||||
#include "Mod/Part/App/PartFeature.h"
|
||||
|
||||
#include "Area.h"
|
||||
|
||||
namespace Path
|
||||
{
|
||||
|
||||
class PathExport FeatureArea : public Part::Feature
|
||||
{
|
||||
PROPERTY_HEADER(Path::FeatureArea);
|
||||
|
||||
public:
|
||||
/// Constructor
|
||||
FeatureArea(void);
|
||||
virtual ~FeatureArea();
|
||||
|
||||
/// returns the type name of the ViewProvider
|
||||
virtual const char* getViewProviderName(void) const {
|
||||
return "PathGui::ViewProviderArea";
|
||||
}
|
||||
virtual App::DocumentObjectExecReturn *execute(void);
|
||||
virtual short mustExecute(void) const;
|
||||
|
||||
App::PropertyLinkList Sources;
|
||||
Part::PropertyPartShape WorkPlane;
|
||||
|
||||
PARAM_PROP_DECLARE(AREA_PARAMS_ALL)
|
||||
};
|
||||
|
||||
typedef App::FeaturePythonT<FeatureArea> FeatureAreaPython;
|
||||
|
||||
} //namespace Path
|
||||
|
||||
|
||||
#endif // PATH_FeaturePath_H
|
998
src/Mod/Path/App/ParamsHelper.h
Normal file
998
src/Mod/Path/App/ParamsHelper.h
Normal file
|
@ -0,0 +1,998 @@
|
|||
/****************************************************************************
|
||||
* Copyright (c) 2017 Zheng, Lei (realthunder) <realthunder.dev@gmail.com>*
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef PARAMS_HELPER_H
|
||||
#define PARAMS_HELPER_H
|
||||
|
||||
/** \page ParamPage Parameter helper macros
|
||||
* Collections of macros for managing groups of parameters.
|
||||
*
|
||||
* \section Motivation
|
||||
*
|
||||
* For an application like FreeCAD, there are often cases where the same set of
|
||||
* parameters are refered in dozons of different places. The macros here is
|
||||
* designed to help managing those parameters, so that you can define groups of
|
||||
* parameters once, and refer them everywhere in groups with simple macro calls for
|
||||
* all kinds of purposes. Any changing, adding and removing of parameters in the
|
||||
* group become much easier. And by everywhere, I mean \ref ParamCommon
|
||||
* "class definition, impelentation", \ref ParamProperty "document object properties",
|
||||
* \ref ParamPy "python c++ classes", and even \ref ParamDoc "doc string",
|
||||
* pretty much everything except the python code, which although not implemented
|
||||
* yet, is in fact also possible to be done using C preprocessor (No one says C
|
||||
* preprocessor must produce C code :). It is also possible (not implemented
|
||||
* yet) to use macros to generate python wrapper class instead of using
|
||||
* FreeCAD's current xml python export.
|
||||
*
|
||||
* \section Debugging
|
||||
*
|
||||
* Extensive use of macros has one noticable disadvantage, though. If some thing
|
||||
* goes wrong, the compiler error message is kind of cryptic. If so, first
|
||||
* double check your macro definition of the parameter is correctly, not missing
|
||||
* or having extra parathesis or comma. Then, you can use the CMake
|
||||
* intermeidate file target to get the preprocessor output for checking. For
|
||||
* example, for a file located at \c src/Mod/Path/App/Area.cpp,
|
||||
* \code{.sh}
|
||||
* cd <your_build_dir>/src/Mod/Path/App
|
||||
* make Area.cpp.i
|
||||
* \endcode
|
||||
*
|
||||
* The preprocessed intermediate output will be at,
|
||||
* \code{.sh}
|
||||
* <your_build_dir>/src/Mod/Path/App.CMakeFiles/Path.dir/Area.cpp.i
|
||||
* \endcode
|
||||
*
|
||||
* \section Intrudction of Boost.Preprocessor
|
||||
*
|
||||
* The macros here make heavy use of the awsome
|
||||
* [Boost.Preprocessor](http://www.boost.org/libs/preprocessor/) (short for
|
||||
* Boost.PP). Here are some brief introduction on Boost.PP conecept in order to
|
||||
* explain why this marco library is designed the way it is.
|
||||
*
|
||||
* In Boost.PP, a sequence is defined as,
|
||||
* \code{.sh}
|
||||
* (a)(b)(c)...
|
||||
* \endcode
|
||||
*
|
||||
* A sequence cannot be empty. Thus, \c () is not a sequence. And also those
|
||||
* <tt>a, b, c</tt> here cannot directly contain <tt>,</tt>. These restriction
|
||||
* is due to the fact that <tt>( ) ,</tt> are among those very few special
|
||||
* characters recognized by the preprocssor. \c a can itself be a sequence or
|
||||
* other Boost.PP types, so by right, our parameter can be defined as something
|
||||
* like
|
||||
* \code{.sh}
|
||||
* ((type)(name)(default)...)
|
||||
* \endcode
|
||||
*
|
||||
* A bit awkward to write. So another Boost.PP type is chosen, tuple, to define
|
||||
* each individual parameter. A tuple is defined as
|
||||
* \code{.sh}
|
||||
* (a,b,c ...)
|
||||
* \endcode
|
||||
*
|
||||
* This is why the parameter definition requires a double parathesis, as shown
|
||||
* in the following section.
|
||||
*
|
||||
* \section Library Overview
|
||||
*
|
||||
* In this macro library, a parameter is defined using a tuple inside a sequence,
|
||||
* \code{.sh}
|
||||
* ((<type>, <arg>, <name>, <default>, <doc>, <seq>, <info>))
|
||||
* \endcode
|
||||
*
|
||||
* - \c type is the type of the parameter. Currently only five types of
|
||||
* parameters are defined, <tt>short, long, double, bool, enum, enum2</tt>.
|
||||
* \enum2 type is the same as \enum with additional information to be able to
|
||||
* map to a user defined C enum type. To add more types, search this file for
|
||||
* keyword \a _short, and supply all relavant macros. It's quite trivial
|
||||
* actually.
|
||||
*
|
||||
* - \c arg is the agument name. It is intended to be used as function argument.
|
||||
* By convention, the name shall be all small cases, but that's not required.
|
||||
* This \c arg can be repurposed, if the parameter is not going to be used as
|
||||
* function agument. The #AREA_PARAMS_CAREA parameters repurposed this field
|
||||
* to CArea internal setting variables to implement save, apply and restore
|
||||
* function using CAreaConfig class.
|
||||
*
|
||||
* - \c name is normally a %CamelCase name which are used as member variable and
|
||||
* property name. Because of this, make sure the names are unique to avoid
|
||||
* conflicts.
|
||||
*
|
||||
* - \c default is the default value of this parameter. Right now, you must
|
||||
* supply a default value. Boost.PP has trouble dealing with empty values.
|
||||
* Remember that a sequence cannot be empty. Neight can tuple. Only array,
|
||||
* something like <tt>(0,())</tt> for an empty array. It is awkward to write,
|
||||
* and didn't add much functionality I want, hence the restriction of
|
||||
* non-empty defaults here.
|
||||
*
|
||||
* - \c doc is a string to describe the variable.
|
||||
*
|
||||
* - \c seq \anchor ParamSeq. Right now this field is used by \c enum and
|
||||
* \c enum2 type parameter to define its enumerations. As the name suggests,
|
||||
* it must be a sequence. It is not a tuple because looping through tuple is
|
||||
* not as easy as sequence. Other type of parameter do not need to have this
|
||||
* field
|
||||
*
|
||||
* - \c info is used to provide the supplimentery information for \c enum2 type
|
||||
* of parameter, which can be converted to a user defined enum type by
|
||||
* #PARAM_ENUM_CONVERT. \c info must be a tuple, with the user defined enum
|
||||
* type as the first element, and a prefix as the second element. For \c enum2
|
||||
* type of parameter, this field is mandatory.
|
||||
*
|
||||
* The common usage is that you define a macro of a group of parameters. And use
|
||||
* the macro helper here to do operation on each parameter in the group. See
|
||||
* AreaParams.h file for an example of parameter definitions.
|
||||
*
|
||||
* Area.h, Area.cpp, FeatureArea.h, FeatureArea.cpp for usage of variouse macros.
|
||||
*
|
||||
* See struct AreaDoc for an example of doc string generation.
|
||||
*
|
||||
* Each field of the parameter can be refered to with various
|
||||
* \ref ParamAccessor "various accessor macros", and can be easily
|
||||
* \ref ParamStringizer "stringified".
|
||||
*
|
||||
* \anchor ParamField You can also use #PARAM_FIELD(_field,_param) to refer to
|
||||
* each field, where \a _field is one of <tt>TYPE, ARG, NAME, DEF, DOC, or SEQ</tt>.
|
||||
* And #PARAM_FIELD_STR to stringify.
|
||||
*
|
||||
* Here \a _param is the parameter definition described above in the form of a
|
||||
* Boost.PP tuple, and is usally supplied by various \ref ParamLooper "looper macros"
|
||||
*
|
||||
* You can of course directly use various Boost.PP sequence looper to pass
|
||||
* aditional arguments to the operation macro. See #PARAM_PY_DICT_SET_VALUE for
|
||||
* an example of using tuple, and the more complex example #PARAM_ENUM_CONVERT
|
||||
*
|
||||
* Note that when generating comma separated list, the first and last comma are
|
||||
* conveniently ommited, so that the macros can be mixed with others intuitively
|
||||
*/
|
||||
|
||||
#include <boost/preprocessor/cat.hpp>
|
||||
#include <boost/preprocessor/seq/seq.hpp>
|
||||
#include <boost/preprocessor/seq/elem.hpp>
|
||||
#include <boost/preprocessor/seq/for_each.hpp>
|
||||
#include <boost/preprocessor/seq/for_each_i.hpp>
|
||||
#include <boost/preprocessor/seq/pop_front.hpp>
|
||||
#include <boost/preprocessor/stringize.hpp>
|
||||
#include <boost/preprocessor/logical/not.hpp>
|
||||
#include <boost/preprocessor/tuple/elem.hpp>
|
||||
#include <boost/preprocessor/tuple/enum.hpp>
|
||||
#include <boost/preprocessor/punctuation/comma_if.hpp>
|
||||
#include <boost/preprocessor/comparison/greater.hpp>
|
||||
|
||||
/** \defgroup ParamHelper Parameters helper macros
|
||||
* Collections of macros for managing groups of parameters */
|
||||
|
||||
/**
|
||||
* \defgroup ParamAccessor Field accessors
|
||||
* To abstract parameter field details
|
||||
* \ingroup ParamHelper
|
||||
* @{
|
||||
*/
|
||||
#define PARAM_ITYPE 0
|
||||
#define PARAM_IARG 1
|
||||
#define PARAM_INAME 2
|
||||
#define PARAM_IDEF 3
|
||||
#define PARAM_IDOC 4
|
||||
#define PARAM_ISEQ 5
|
||||
#define PARAM_IINFO 6
|
||||
|
||||
#define PARAM_FIELD(_idx,_param) BOOST_PP_TUPLE_ELEM(PARAM_I##_idx,_param)
|
||||
|
||||
#define PARAM_FTYPE(_param) PARAM_FIELD(TYPE,_param)
|
||||
#define PARAM_FARG(_param) PARAM_FIELD(ARG,_param)
|
||||
#define PARAM_FNAME(_param) PARAM_FIELD(NAME,_param)
|
||||
#define PARAM_FDEF(_param) PARAM_FIELD(DEF,_param)
|
||||
#define PARAM_FDOC(_param) PARAM_FIELD(DOC,_param)
|
||||
#define PARAM_FSEQ(_param) PARAM_FIELD(SEQ,_param)
|
||||
#define PARAM_FINFO(_param) PARAM_FIELD(INFO,_param)
|
||||
#define PARAM_FENUM_TYPE(_param) BOOST_PP_TUPLE_ELEM(0,PARAM_FINFO(_param))
|
||||
#define PARAM_FENUM_PREFIX(_param) BOOST_PP_TUPLE_ELEM(1,PARAM_FINFO(_param))
|
||||
/** @} */
|
||||
|
||||
|
||||
/**
|
||||
* \defgroup ParamStringizer Field stringizers
|
||||
* \ingroup ParamHelper
|
||||
* @{ */
|
||||
#define PARAM_FIELD_STR(_idx,_param) \
|
||||
BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(PARAM_I##_idx,_param))
|
||||
|
||||
#define PARAM_FTYPE_STR(_param) PARAM_FIELD_STR(TYPE,_param)
|
||||
#define PARAM_FARG_STR(_param) PARAM_FIELD_STR(ARG,_param)
|
||||
#define PARAM_FNAME_STR(_param) PARAM_FIELD_STR(NAME,_param)
|
||||
#define PARAM_FDEF_STR(_param) PARAM_FIELD_STR(DEF,_param)
|
||||
/** @} */
|
||||
|
||||
/** Helper for #PARAM_FSEQ_STR */
|
||||
#define PARAM_FSEQ_STR_(_i,_elem) \
|
||||
BOOST_PP_COMMA_IF(_i) BOOST_PP_STRINGIZE(_elem)
|
||||
|
||||
/** \c SEQ stringizer will stringify each element separately
|
||||
*
|
||||
* Expands to:
|
||||
* #seq[0], #seq[1] ...
|
||||
* \ingroup ParamHelper
|
||||
*/
|
||||
#define PARAM_FSEQ_STR(_param) \
|
||||
PARAM_FOREACH_I(PARAM_FSEQ_STR_,PARAM_FSEQ(_param))
|
||||
|
||||
|
||||
/** \defgroup ParamLooper Looper macros
|
||||
* Macros for looping through sequence to parameters
|
||||
* \ingroup ParamHelper
|
||||
*/
|
||||
|
||||
/** Helper for #PARAM_FOREACH */
|
||||
#define PARAM_FOREACH_(_,_op,_param) _op(_param)
|
||||
|
||||
/** Apply macro \a _op to each parameter in sequence \a _seq
|
||||
*
|
||||
* Operation macro \a _op shoud be defined as,
|
||||
* \code
|
||||
* _op(_param)
|
||||
* \endcode
|
||||
* \ingroup ParamLooper
|
||||
*/
|
||||
#define PARAM_FOREACH(_op,_seq) \
|
||||
BOOST_PP_SEQ_FOR_EACH(PARAM_FOREACH_,_op,_seq)
|
||||
|
||||
/** Helper for #PARAM_FOREACH_I */
|
||||
#define PARAM_FOREACH_I_(_,_op,_i,_param) _op(_i,_param)
|
||||
|
||||
/** Apply macro \a _op to each parameter in sequence \a _seq with additional index
|
||||
*
|
||||
* Operation macro \a _op shoud be defined as,
|
||||
* \code
|
||||
* _op(_i,_param)
|
||||
* \endcode
|
||||
* \ingroup ParamLooper
|
||||
* */
|
||||
#define PARAM_FOREACH_I(_op,_seq) \
|
||||
BOOST_PP_SEQ_FOR_EACH_I(PARAM_FOREACH_I_,_op,_seq)
|
||||
|
||||
|
||||
/** Helper for #PARAM_TYPED_FOREACH */
|
||||
#define PARAM_TYPED_FOREACH_(_1,_op,_param) \
|
||||
PARAM_TYPED(_op,_param)(_param)
|
||||
|
||||
/** Type depended macro construction
|
||||
*
|
||||
* Convert macro \a _op to \a _op##\<type\>. Note that it only converts the
|
||||
* macro name, not contsucts a macro call. To expand to a macro call, simply
|
||||
* \code
|
||||
* PARAM_TYPED(_op,_param)(_param)
|
||||
* \endcode
|
||||
* \ingroup ParamLooper
|
||||
*/
|
||||
#define PARAM_TYPED(_op,_param) \
|
||||
BOOST_PP_CAT(_op,PARAM_FTYPE(_param))
|
||||
|
||||
/** Apply type dependent macro call to a sequence of parameters
|
||||
*
|
||||
* \a _op will be converted to \a _op##\<type\> for each parameter
|
||||
* \ingroup ParamLooper
|
||||
*/
|
||||
#define PARAM_TYPED_FOREACH(_op,_seq) \
|
||||
BOOST_PP_SEQ_FOR_EACH(PARAM_TYPED_FOREACH_,_op,_seq)
|
||||
|
||||
|
||||
/** \defgroup ParamCommon Common helpers
|
||||
* \ingroup ParamHelper
|
||||
*/
|
||||
|
||||
#define PARAM_TYPE_short short
|
||||
#define PARAM_TYPE_long long
|
||||
#define PARAM_TYPE_double double
|
||||
#define PARAM_TYPE_bool bool
|
||||
#define PARAM_TYPE_enum short
|
||||
#define PARAM_TYPE_enum2 short
|
||||
|
||||
/** Obtain parameter type
|
||||
*
|
||||
* The main purpose is to alias enum type to short
|
||||
* \ingroup ParamCommon
|
||||
*/
|
||||
#define PARAM_TYPE(_param) \
|
||||
PARAM_TYPED(PARAM_TYPE_,_param)
|
||||
|
||||
|
||||
/** Helper for #PARAM_DECLARE */
|
||||
#define PARAM_DECLARE_(_1,_field,_param) \
|
||||
PARAM_TYPE(_param) PARAM_FIELD(_field,_param);
|
||||
|
||||
/**
|
||||
* Delcares parameters using the given field as name
|
||||
*
|
||||
* \arg \c _field: specifies the \ref ParamField "field" to use as name
|
||||
*
|
||||
* Expands to:
|
||||
* \code{.unparsed}
|
||||
* type1 _field1;type2 _field2; ...
|
||||
* \endcode
|
||||
* \ingroup ParamCommon
|
||||
*/
|
||||
#define PARAM_DECLARE(_field,_seq) \
|
||||
BOOST_PP_SEQ_FOR_EACH(PARAM_DECLARE_,_field,_seq)
|
||||
|
||||
|
||||
/** Helper for #PARAM_DECLARE_INIT */
|
||||
#define PARAM_DECLARE_INIT_(_1,_field,_param) \
|
||||
PARAM_TYPE(_param) PARAM_FIELD(_field,_param) = PARAM_FDEF(_param);
|
||||
|
||||
/**
|
||||
* Delcares parameters with initialization to default using the given field as
|
||||
* name
|
||||
*
|
||||
* \arg \c _field: \ref ParamField "field" to use as name
|
||||
*
|
||||
* Expands to:
|
||||
* \code{.unparsed}
|
||||
* type1 _field1=_def1;type2 _field2=_def2; ...
|
||||
* \endcode
|
||||
* \ingroup ParamCommon
|
||||
*/
|
||||
#define PARAM_DECLARE_INIT(_field,_seq) \
|
||||
BOOST_PP_SEQ_FOR_EACH(PARAM_DECLARE_INIT_,_field,_seq)
|
||||
|
||||
|
||||
#define PARAM_ENUM_DECLARE_enum_(_1,_name,_i,_elem) \
|
||||
BOOST_PP_COMMA_IF(_i) BOOST_PP_CAT(_name,_elem)
|
||||
|
||||
#define PARAM_ENUM_DECLARE_enum(_param) \
|
||||
enum {BOOST_PP_SEQ_FOR_EACH_I(PARAM_ENUM_DECLARE_enum_,PARAM_FNAME(_param),PARAM_FSEQ(_param))};
|
||||
|
||||
#define PARAM_ENUM_DECLARE_short(_param)
|
||||
#define PARAM_ENUM_DECLARE_long(_param)
|
||||
#define PARAM_ENUM_DECLARE_double(_param)
|
||||
#define PARAM_ENUM_DECLARE_bool(_param)
|
||||
#define PARAM_ENUM_DECLARE_enum2 PARAM_ENUM_DECLARE_enum
|
||||
|
||||
/** \defgroup ParamEnumHelper Enum convert helpers
|
||||
* \ingroup ParamCommon
|
||||
*/
|
||||
|
||||
/** Make anonymous \c enum type
|
||||
*
|
||||
* Make anonymous \c enum type for \c enum type parameters in \a _seq. All other
|
||||
* types are ignored. The enum member is prefixed with \a _name. Expand to:
|
||||
* \code{.unparsed}
|
||||
* enum {_name1##_seq1[0], _name1##_seq1[1] ...};
|
||||
* enum {_name2##_seq2[0], _name2##_seq2[1] ...};
|
||||
* ...
|
||||
* \endcode
|
||||
* \ingroup ParamEnumHelper*/
|
||||
#define PARAM_ENUM_DECLARE(_seq) \
|
||||
PARAM_TYPED_FOREACH(PARAM_ENUM_DECLARE_,_seq)
|
||||
|
||||
|
||||
/** \addgroup ParamEnumHelper Enum convert helpers
|
||||
* @{ */
|
||||
#define PARAM_ENUM_CONVERT_short(...)
|
||||
#define PARAM_ENUM_CONVERT_long(...)
|
||||
#define PARAM_ENUM_CONVERT_double(...)
|
||||
#define PARAM_ENUM_CONVERT_bool(...)
|
||||
#define PARAM_ENUM_CONVERT_enum(...)
|
||||
#define PARAM_ENUM_CONVERT_enum2 PARAM_ENUM_CONVERT_SINGLE
|
||||
|
||||
#define PARAM_ENUM_CONVERT_enum_(_dst,_name,_prefix,_elem) \
|
||||
case BOOST_PP_CAT(_name,_elem):\
|
||||
_dst(_name) = \
|
||||
BOOST_PP_CAT(_prefix,_elem);\
|
||||
break;
|
||||
|
||||
#define PARAM_ENUM_CONVERT__(_1,_args,_i,_elem) \
|
||||
PARAM_ENUM_CONVERT_enum_(BOOST_PP_TUPLE_ELEM(0,_args),\
|
||||
BOOST_PP_TUPLE_ELEM(1,_args),\
|
||||
BOOST_PP_TUPLE_ELEM(2,_args),\
|
||||
_elem);
|
||||
|
||||
#define PARAM_ENUM_CONVERT_(_1,_args,_param) \
|
||||
PARAM_TYPED(PARAM_ENUM_CONVERT_,_param)(BOOST_PP_TUPLE_ELEM(0,_args),\
|
||||
BOOST_PP_TUPLE_ELEM(1,_args),\
|
||||
BOOST_PP_TUPLE_ELEM(2,_args),\
|
||||
_param)
|
||||
|
||||
/** Convert single enum parameter value into user defined enum type
|
||||
*
|
||||
* This macro is used by #PARAM_ENUM_CONVERT to convert each parameter, but
|
||||
* you can use it directly for a single parameter. Check #PARAM_NUM_CONVERT
|
||||
* for more detail. Make sure the outer parathesis of \c _param is stripped,
|
||||
* i.e. not double but single parathesis
|
||||
*/
|
||||
#define PARAM_ENUM_CONVERT_SINGLE(_src,_dst,_default,_param) \
|
||||
PARAM_FENUM_TYPE(_param) _dst(PARAM_FNAME(_param));\
|
||||
switch(_src(PARAM_FNAME(_param))) {\
|
||||
BOOST_PP_SEQ_FOR_EACH_I(PARAM_ENUM_CONVERT__,\
|
||||
(_dst,PARAM_FNAME(_param),PARAM_FENUM_PREFIX(_param)),PARAM_FSEQ(_param))\
|
||||
default: \
|
||||
_default(_param);\
|
||||
}
|
||||
|
||||
/** Default handling in #PARAM_ENUM_CONVERT and #PARAM_ENUM_CHECK*/
|
||||
#define PARAM_ENUM_EXCEPT(_param) \
|
||||
throw Base::ValueError("invalid value for enum " PARAM_FNAME_STR(_param))
|
||||
|
||||
/** @} */
|
||||
|
||||
/* Convert ParamHelper defined enum type to user defined ones
|
||||
*
|
||||
* This assumes the user defined enum type is given in \ref ParamSeq "seq_type"
|
||||
* of the parameter definition, and it has the same postfix as the ones
|
||||
* speficied in \ref ParamSeq "seq" member of the parameter definition. See
|
||||
* \ref ParamEnumHelper "here" for implementations
|
||||
*
|
||||
* \ingroup ParamEnumHelper
|
||||
*
|
||||
* \arg \c _src: Optional macro to generate source variable. The signature must
|
||||
* be <tt>_src(_name)<\tt>, where \c _name will be the parameters \a name field.
|
||||
* In case you just want \c _name as the source variable name, you can simply
|
||||
* omit this argument, because newer C++ preprocessor allows empty argument.
|
||||
* \arg \c _dst: Optional macro to generate destination variable. Same as above.
|
||||
* \arg \c _default: A macro to call for invalid value. Signature should be
|
||||
* <tt>_default(_param)<\tt>, where \c _param is the parameter definition. You
|
||||
* can use #PARAM_ENUM_EXCEPT to throw Base::ValueError exception in FreeCAD
|
||||
* \arg \c _seq: Parameter sequence
|
||||
*
|
||||
* For example, with the following parameter definition
|
||||
* \code{.unparsed}
|
||||
* #define MY_PARAM_TEST \
|
||||
* ((enum,test1,Test1,0,"it's a test",(Foo)(Bar),(MyEnum1,myEnum1)) \
|
||||
* ((enum,test2,Test2,0,"it's a test",(Foo)(Bar),(MyEnum2,myEnum2)))
|
||||
*
|
||||
* #define MY_DST(_v) BOOST_PP_CAT(my,_v)
|
||||
* \code{.unparsed}
|
||||
*
|
||||
* calling (note that the \c _src macro is omitted)
|
||||
* \code{.unparsed}
|
||||
* PARAM_ENUM_CONVERT(,MY_DST,My,PARAM_ENUM_EXCEP,MY_PARAM_TEST)
|
||||
* \code{.unparsed}
|
||||
*
|
||||
* expands to
|
||||
* \code{.unparsed}
|
||||
* MyEnum1 myTest1;
|
||||
* switch(Test1) {
|
||||
* case Test1Foo:
|
||||
* myTest1 = myEnum1Foo;
|
||||
* break;
|
||||
* case Test1Bar:
|
||||
* myTest1 = myEnum1Bar;
|
||||
* break;
|
||||
* default:
|
||||
* throw Base::ValueError("invalid value for enum Test1");
|
||||
* }
|
||||
* MyEnum2 myTest2;
|
||||
* switch(Test2) {
|
||||
* case Test1Foo:
|
||||
* myTest2 = myEnum2Foo;
|
||||
* break;
|
||||
* case Test2Bar:
|
||||
* myTest2 = myEnum2Bar;
|
||||
* break;
|
||||
* default:
|
||||
* throw Base::ValueError("invalid value for enum Test2");
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
* The above code assumes you've already defined \a Test1 and \a Test2 some
|
||||
* where as the source variable.
|
||||
*/
|
||||
#define PARAM_ENUM_CONVERT(_src,_dst,_default,_seq) \
|
||||
BOOST_PP_SEQ_FOR_EACH(PARAM_ENUM_CONVERT_,(_src,_dst,_default),_seq)
|
||||
|
||||
|
||||
#define PARAM_ENUM_CHECK_short(...)
|
||||
#define PARAM_ENUM_CHECK_long(...)
|
||||
#define PARAM_ENUM_CHECK_double(...)
|
||||
#define PARAM_ENUM_CHECK_bool(...)
|
||||
#define PARAM_ENUM_CHECK_enum PARAM_ENUM_CHECK_SINGLE
|
||||
#define PARAM_ENUM_CHECK_enum2 PARAM_ENUM_CHECK_SINGLE
|
||||
|
||||
#define PARAM_ENUM_CHECK_enum_(_1,_name,_i,_elem) \
|
||||
case BOOST_PP_CAT(_name,_elem): break;
|
||||
|
||||
#define PARAM_ENUM_CHECK_(_1,_args,_param) \
|
||||
PARAM_TYPED(PARAM_ENUM_CHECK_,_param)(BOOST_PP_TUPLE_ELEM(0,_args),\
|
||||
BOOST_PP_TUPLE_ELEM(1,_args),\
|
||||
_param)
|
||||
|
||||
#define PARAM_ENUM_CHECK_SINGLE(_src,_default,_param) \
|
||||
switch(_src(PARAM_FNAME(_param))) {\
|
||||
BOOST_PP_SEQ_FOR_EACH_I(PARAM_ENUM_CHECK_enum_,\
|
||||
PARAM_FNAME(_param),PARAM_FSEQ(_param))\
|
||||
default: \
|
||||
_default(_param);\
|
||||
}
|
||||
|
||||
/* Validate enum type parameters
|
||||
*
|
||||
* This macro validates the value a variable of enum type parameters. See
|
||||
* similar macro #PARAM_ENUM_CONVERT for detail usage.
|
||||
*
|
||||
* \ingroup ParamEnumHelper
|
||||
*
|
||||
* \arg \c _src: Optional macro to generate source variable. The signature must
|
||||
* be <tt>_src(_name)<\tt>, where \c _name will be the parameters \a name field.
|
||||
* In case you just want \c _name as the source variable name, you can simply
|
||||
* omit this argument, because newer C++ preprocessor allows empty argument.
|
||||
*
|
||||
* \arg \c _default: A macro to call for invalid value. Signature should be
|
||||
* <tt>_default(_param)<\tt>, where \c _param is the parameter definition. You
|
||||
* can use #PARAM_ENUM_EXCEPT to throw Base::ValueError exception in FreeCAD
|
||||
*
|
||||
* \arg \c _seq: Parameter sequence
|
||||
*/
|
||||
#define PARAM_ENUM_CHECK(_src,_default,_seq) \
|
||||
BOOST_PP_SEQ_FOR_EACH(PARAM_ENUM_CHECK_,(_src,_default),_seq)
|
||||
|
||||
|
||||
#define PARAM_ENUM_STRING_DECLARE_short(...)
|
||||
#define PARAM_ENUM_STRING_DECLARE_long(...)
|
||||
#define PARAM_ENUM_STRING_DECLARE_double(...)
|
||||
#define PARAM_ENUM_STRING_DECLARE_bool(...)
|
||||
#define PARAM_ENUM_STRING_DECLARE_enum2 PARAM_ENUM_STRING_DECLARE_enum
|
||||
|
||||
/** Helper for #PARAM_ENUM_STRING_DECLARE */
|
||||
#define PARAM_ENUM_STRING_DECLARE_enum(_prefix,_param) \
|
||||
BOOST_PP_CAT(_prefix,PARAM_FNAME(_param))[] = {PARAM_FSEQ_STR(_param),NULL};
|
||||
|
||||
/** Helper for #PARAM_ENUM_STRING_DECLARE */
|
||||
#define PARAM_ENUM_STRING_DECLARE_(_1,_prefix,_param) \
|
||||
PARAM_TYPED(PARAM_ENUM_STRING_DECLARE_,_param)(_prefix,_param)
|
||||
|
||||
/** Make \c enum string list
|
||||
*
|
||||
* Roughly translated:
|
||||
* \code{.unparsed}
|
||||
* _prefix##_name1[] = {#seq1[0], #seq1[1], ...,NULL};
|
||||
* _prefix##_name2[] = {#seq2[0], #seq2[1], ...,NULL};
|
||||
* ...
|
||||
* \endcode
|
||||
* Example usage:
|
||||
* PARAM_ENUM_STRING_DECLARE(static const char *Enum, MyParamsSeq)
|
||||
* \ingroup ParamEnumHelper
|
||||
*/
|
||||
#define PARAM_ENUM_STRING_DECLARE(_prefix,_seq) \
|
||||
BOOST_PP_SEQ_FOR_EACH(PARAM_ENUM_STRING_DECLARE_,_prefix,_seq)
|
||||
|
||||
|
||||
/** Helper for #PARAM_INIT */
|
||||
#define PARAM_INIT_(_,_field,_i,_param) \
|
||||
BOOST_PP_COMMA_IF(_i) PARAM_FIELD(_field,_param)(PARAM_FDEF(_param))
|
||||
|
||||
/** Constructor initialization
|
||||
*
|
||||
* \arg \c _field: specifies the \ref ParamField "field" to use as name
|
||||
*
|
||||
* Expand to,
|
||||
* \code{.unparsed}
|
||||
* field1(def1), field2(def2)...
|
||||
* \endcode
|
||||
* \ingroup ParamCommon
|
||||
*/
|
||||
#define PARAM_INIT(_field,_seq) \
|
||||
BOOST_PP_SEQ_FOR_EACH_I(PARAM_INIT_,_field,_seq)
|
||||
|
||||
|
||||
/** Helper for #PARAM_ARGS_DEF */
|
||||
#define PARAM_ARGS_DEF_(_,_field,_i,_param) \
|
||||
BOOST_PP_COMMA_IF(_i) PARAM_TYPE(_param) PARAM_FIELD(_field,_param)=PARAM_FDEF(_param)
|
||||
|
||||
/** Delcare the parameters as function argument list with defaults.
|
||||
*
|
||||
* \arg \c _field: specifies the \ref ParamField "field" to use as name
|
||||
*
|
||||
* Expand to:
|
||||
* \code{.unparsed}
|
||||
* type1 field1=def1, type2 field2=def2 ...
|
||||
* \endcode
|
||||
* \ingroup ParamCommon
|
||||
*/
|
||||
#define PARAM_ARGS_DEF(_field,_seq) \
|
||||
BOOST_PP_SEQ_FOR_EACH_I(PARAM_ARGS_DEF_,_field,_seq)
|
||||
|
||||
|
||||
/** Helper for #PARAM_ARGS */
|
||||
#define PARAM_ARGS_(_,_field,_i,_param) \
|
||||
BOOST_PP_COMMA_IF(_i) PARAM_TYPE(_param) PARAM_FIELD(_field,_param)
|
||||
|
||||
/** Delcare the parameters as function argument list without defaults.
|
||||
*
|
||||
* \arg \c _field: specifies the \ref ParamField "field" to use as name
|
||||
*
|
||||
* Expand to:
|
||||
* \code{.unparsed}
|
||||
* type1 field1, type2 field2 ...
|
||||
* \endcode
|
||||
* \ingroup ParamCommon
|
||||
*/
|
||||
#define PARAM_ARGS(_field,_seq) \
|
||||
BOOST_PP_SEQ_FOR_EACH_I(PARAM_ARGS_,_field,_seq)
|
||||
|
||||
|
||||
/** \defgroup ParamPy Python helper
|
||||
* Helper macros for Python bindings
|
||||
* \ingroup ParamHelper
|
||||
*/
|
||||
|
||||
/** \defgroup ParamDoc Python doc helper
|
||||
* Generate argument doc string for Python
|
||||
* \ingroup ParamPy
|
||||
*/
|
||||
|
||||
/** Helper for #PARAM_PY_DOC_enum */
|
||||
#define PARAM_PY_DOC_enum_(_i,_elem) \
|
||||
BOOST_PP_IF(_i,","," ") #_i "=" #_elem
|
||||
|
||||
/** Generate doc for an enum parameter */
|
||||
#define PARAM_PY_DOC_enum(_field,_param) \
|
||||
"\n* " PARAM_FIELD_STR(_field,_param) "(" PARAM_FDEF_STR(_param)"):" \
|
||||
PARAM_FOREACH_I(PARAM_PY_DOC_enum_, PARAM_FSEQ(_param)) ". " \
|
||||
PARAM_FDOC(_param) "\n"
|
||||
|
||||
/* Generate doc for other type of parameter */
|
||||
#define PARAM_PY_DOC_short(_field,_param) \
|
||||
"\n* " PARAM_FIELD_STR(_field,_param) "(" PARAM_FDEF_STR(_param)"): " \
|
||||
PARAM_FDOC(_param) "\n"
|
||||
#define PARAM_PY_DOC_long PARAM_PY_DOC_short
|
||||
#define PARAM_PY_DOC_double PARAM_PY_DOC_short
|
||||
#define PARAM_PY_DOC_bool PARAM_PY_DOC_short
|
||||
#define PARAM_PY_DOC_enum2 PARAM_PY_DOC_enum
|
||||
|
||||
#define PARAM_PY_DOC_(_,_field,_param) \
|
||||
PARAM_TYPED(PARAM_PY_DOC_,_param)(_field,_param)
|
||||
|
||||
/* Generate document of a sequence of parameters
|
||||
* \ingroup ParamDoc
|
||||
*/
|
||||
#define PARAM_PY_DOC(_field,_seq) \
|
||||
BOOST_PP_SEQ_FOR_EACH(PARAM_PY_DOC_,_field,_seq)
|
||||
|
||||
|
||||
/** Helper for #PARAM_PY_ARGS_DOC */
|
||||
#define PARAM_PY_ARGS_DOC_(_,_field,_i,_param) \
|
||||
BOOST_PP_IF(_i,", "," ") PARAM_FIELD_STR(_field,_param) "=" PARAM_FDEF_STR(_param)
|
||||
|
||||
/** Generate argument list string
|
||||
* \arg \c _field: specifies the \ref ParamField "field" to use as name
|
||||
*
|
||||
* Expand to a single string:
|
||||
* \code{.unparsed}
|
||||
* "_field1=_def1,_field2=_def2 ..."
|
||||
* \endcode
|
||||
*
|
||||
* \ingroup ParamDoc
|
||||
*/
|
||||
#define PARAM_PY_ARGS_DOC(_field,_seq) \
|
||||
BOOST_PP_SEQ_FOR_EACH_I(PARAM_PY_ARGS_DOC_,_field,_seq)
|
||||
|
||||
|
||||
/** Helper for #PARAM_FIELDS */
|
||||
#define PARAM_FIELDS_(_1,_field,_i,_param) \
|
||||
BOOST_PP_COMMA_IF(_i) PARAM_FIELD(_field,_param)
|
||||
|
||||
/** Expand to a list of the given field in the parameter sequence
|
||||
*
|
||||
* For example, PARAM_FIELDS(ARG, _seq) expands to:
|
||||
* \code{.unparsed}
|
||||
* arg1,arg2 ...
|
||||
* \endcode
|
||||
* \ingroup ParamCommon ParamPy
|
||||
*/
|
||||
#define PARAM_FIELDS(_field,_seq) \
|
||||
BOOST_PP_SEQ_FOR_EACH_I(PARAM_FIELDS_,_field,_seq)
|
||||
|
||||
|
||||
#define PARAM_PY_CAST_short(_v) (_v)
|
||||
#define PARAM_PY_CAST_long(_v) (_v)
|
||||
#define PARAM_PY_CAST_double(_v) (_v)
|
||||
#define PARAM_PY_CAST_bool(_v) ((_v)?Py_True:Py_False)
|
||||
#define PARAM_PY_CAST_enum(_v) (_v)
|
||||
#define PARAM_PY_CAST_enum2(_v) (_v)
|
||||
|
||||
#define PARAM_CAST_PY_short(_v) (_v)
|
||||
#define PARAM_CAST_PY_long(_v) (_v)
|
||||
#define PARAM_CAST_PY_double(_v) (_v)
|
||||
#define PARAM_CAST_PY_bool(_v) (PyObject_IsTrue(_v)?true:false)
|
||||
#define PARAM_CAST_PY_enum(_v) (_v)
|
||||
#define PARAM_CAST_PY_enum2(_v) (_v)
|
||||
|
||||
|
||||
/** Helper for #PARAM_PY_FIELDS */
|
||||
#define PARAM_PY_FIELDS_(_1,_field,_i,_param) \
|
||||
BOOST_PP_COMMA_IF(_i) PARAM_TYPED(PARAM_CAST_PY_,_param)(PARAM_FIELD(_field,_param))
|
||||
|
||||
/** Expand to a list of the given field in the sequence
|
||||
*
|
||||
* The field will be casted from python C to C type
|
||||
* \ingroup ParamCommon ParamPy
|
||||
*/
|
||||
#define PARAM_PY_FIELDS(_field,_seq) \
|
||||
BOOST_PP_SEQ_FOR_EACH_I(PARAM_PY_FIELDS_,_field,_seq)
|
||||
|
||||
|
||||
/** Helper for #PARAM_FIELD_STRINGS */
|
||||
#define PARAM_FIELD_STRINGS_(_1,_field,_i,_param) \
|
||||
BOOST_PP_COMMA_IF(_i) PARAM_FIELD_STR(_field,_param)
|
||||
|
||||
/** Expand to a list of stringified fields
|
||||
* \ingroup ParamCommon ParamPy
|
||||
*/
|
||||
#define PARAM_FIELD_STRINGS(_field,_seq) \
|
||||
BOOST_PP_SEQ_FOR_EACH_I(PARAM_FIELD_STRINGS_,_field,_seq)
|
||||
|
||||
|
||||
#define PARAM_PYARG_short "h"
|
||||
#define PARAM_PYARG_long "l"
|
||||
#define PARAM_PYARG_double "d"
|
||||
#define PARAM_PYARG_bool "O"
|
||||
#define PARAM_PYARG_enum "h"
|
||||
#define PARAM_PYARG_enum2 "h"
|
||||
|
||||
/** Helper for #PARAM_PY_KWDS */
|
||||
#define PARAM_PY_KWDS_(_param) \
|
||||
PARAM_TYPED(PARAM_PYARG_,_param)
|
||||
|
||||
/** Generate a format string for kewords based argument
|
||||
* \ingroup ParamPy
|
||||
*/
|
||||
#define PARAM_PY_KWDS(_seq) \
|
||||
PARAM_FOREACH(PARAM_PY_KWDS_,_seq)
|
||||
|
||||
#define PARAM_PY_TYPE_short short
|
||||
#define PARAM_PY_TYPE_long long
|
||||
#define PARAM_PY_TYPE_double double
|
||||
#define PARAM_PY_TYPE_bool PyObject*
|
||||
#define PARAM_PY_TYPE_enum short
|
||||
#define PARAM_PY_TYPE_enum2 short
|
||||
|
||||
/** Helper for #PARAM_PY_DECLARE */
|
||||
#define PARAM_PY_DECLARE_(_1,_field,_param) \
|
||||
PARAM_TYPED(PARAM_PY_TYPE_,_param) PARAM_FIELD(_field,_param);
|
||||
|
||||
/** Declare field variables for Python C type without initialization
|
||||
* \ingroup ParamPy
|
||||
*/
|
||||
#define PARAM_PY_DECLARE(_field,_seq) \
|
||||
BOOST_PP_SEQ_FOR_EACH(PARAM_PY_DECLARE_,_field,_seq)
|
||||
|
||||
#define PARAM_PY_INIT_short(_v) _v
|
||||
#define PARAM_PY_INIT_long(_v) _v
|
||||
#define PARAM_PY_INIT_double(_v) _v
|
||||
#define PARAM_PY_INIT_bool(_v) ((_v)?Py_True:Py_False)
|
||||
#define PARAM_PY_INIT_enum(_v) _v
|
||||
#define PARAM_PY_INIT_enum2(_v) _v
|
||||
|
||||
/** Helper for #PARAM_PY_DECLARE_INIT */
|
||||
#define PARAM_PY_DECLARE_INIT_(_1,_field,_param) \
|
||||
PARAM_TYPED(PARAM_PY_TYPE_,_param) PARAM_FIELD(_field,_param) = \
|
||||
PARAM_TYPED(PARAM_PY_INIT_,_param)(PARAM_FDEF(_param));
|
||||
|
||||
/** Declare field variables of Python c type with initialization to default
|
||||
* \ingroup ParamPy
|
||||
*/
|
||||
#define PARAM_PY_DECLARE_INIT(_field,_seq) \
|
||||
BOOST_PP_SEQ_FOR_EACH(PARAM_PY_DECLARE_INIT_,_field,_seq)
|
||||
|
||||
|
||||
/** Helper for #PARAM_REF */
|
||||
#define PARAM_REF_(_1,_field,_i,_param) \
|
||||
BOOST_PP_COMMA_IF(_i) &PARAM_FIELD(_field,_param)
|
||||
|
||||
/** Generate a list of field references
|
||||
*
|
||||
* Expand to:
|
||||
* \code{.unparsed}
|
||||
* &_field1, &_field2 ...
|
||||
* \endcode
|
||||
* \ingroup ParamPy
|
||||
*/
|
||||
#define PARAM_REF(_field,_seq) \
|
||||
BOOST_PP_SEQ_FOR_EACH_I(PARAM_REF_,_field,_seq)
|
||||
|
||||
|
||||
#define PARAM_CAST_PYOBJ_short(_v) PyInt_FromLong(_v)
|
||||
#define PARAM_CAST_PYOBJ_long(_v) PyInt_FromLong(_v)
|
||||
#define PARAM_CAST_PYOBJ_double(_v) PyFloat_FromDouble(_v)
|
||||
#define PARAM_CAST_PYOBJ_bool(_v) ((_v)?Py_True:Py_False)
|
||||
#define PARAM_CAST_PYOBJ_enum PARAM_CAST_PYOBJ_short
|
||||
#define PARAM_CAST_PYOBJ_enum2 PARAM_CAST_PYOBJ_short
|
||||
|
||||
|
||||
/** Stringize field to a Python string */
|
||||
#define PARAM_PY_STRINGIZE(_field,_param) \
|
||||
PyString_FromString(PARAM_FIELD_STR(_field,_param))
|
||||
|
||||
/** Helper for #PARAM_PY_DICT_SET_VALUE */
|
||||
#define PARAM_PY_DICT_SET_VALUE_(_1,_args,_param) \
|
||||
PyDict_SetItem(BOOST_PP_TUPLE_ELEM(0,_args), \
|
||||
PARAM_PY_STRINGIZE(NAME,_param),\
|
||||
PARAM_TYPED(PARAM_CAST_PYOBJ_,_param)(\
|
||||
BOOST_PP_TUPLE_ELEM(1,_args)(PARAM_FIELD(NAME,_param))));
|
||||
|
||||
/** Populate a Python dict with a structure variable
|
||||
*
|
||||
* \arg \c _dict: the Python dictionary object
|
||||
* \arg \c _src: Optional macro to generate source variable. The signature must
|
||||
* be <tt>_src(_name)<\tt>, where \c _name will be the parameters \a name field.
|
||||
* In case you just want \c _name as the source variable name, you can simply
|
||||
* omit this argument, because newer C++ preprocessor allows empty argument.
|
||||
*
|
||||
* Roughly translated to:
|
||||
* \code{.unparsed}
|
||||
* PyDict_SetItem(_dict,#name1,_src(name1));
|
||||
* PyDict_SetItem(_dict,#name2,_src(name2));
|
||||
* ...
|
||||
* \endcode
|
||||
* \ingroup ParamPy
|
||||
*/
|
||||
#define PARAM_PY_DICT_SET_VALUE(_dict,_src,_seq) \
|
||||
BOOST_PP_SEQ_FOR_EACH(PARAM_PY_DICT_SET_VALUE_,(_dict,_src),_seq)
|
||||
|
||||
|
||||
#define PARAM_PY_DICT_DOC_enum_(_i,_elem) \
|
||||
BOOST_PP_IF(_i,","," ") #_i "=" #_elem
|
||||
|
||||
/** Generate doc for an enum parameter */
|
||||
#define PARAM_PY_DICT_DOC_enum(_param) \
|
||||
"(" PARAM_FDEF_STR(_param) ") - " \
|
||||
PARAM_FOREACH_I(PARAM_PY_DOC_enum_, PARAM_FSEQ(_param)) ".\n" \
|
||||
PARAM_FDOC(_param) "\n"
|
||||
|
||||
/* Generate doc for other type of parameter */
|
||||
#define PARAM_PY_DICT_DOC_(_param) \
|
||||
"(" PARAM_FDEF_STR(_param) ") - " PARAM_FDOC(_param) "\n"
|
||||
|
||||
|
||||
#define PARAM_PY_DICT_DOC_short PARAM_PY_DICT_DOC_
|
||||
#define PARAM_PY_DICT_DOC_long PARAM_PY_DICT_DOC_
|
||||
#define PARAM_PY_DICT_DOC_double PARAM_PY_DICT_DOC_
|
||||
#define PARAM_PY_DICT_DOC_bool PARAM_PY_DICT_DOC_
|
||||
#define PARAM_PY_DICT_DOC_enum2 PARAM_PY_DICT_DOC_enum
|
||||
|
||||
/** Helper for #PARAM_PY_DICT_SET_DOC */
|
||||
#define PARAM_PY_DICT_SET_DOC_(_1,_dict,_param) \
|
||||
PyDict_SetItem(_dict, PARAM_PY_STRINGIZE(NAME,_param),\
|
||||
PyString_FromString(PARAM_TYPED(PARAM_PY_DICT_DOC_,_param)(_param)));
|
||||
|
||||
/** Populate a Python dict with the doc field of the parameter sequence
|
||||
*
|
||||
* Roughly translated to:
|
||||
* \code{.unparsed}
|
||||
* PyDict_SetItem(_dict,#name1,doc1);
|
||||
* PyDict_SetItem(_dict,#name2,doc2);
|
||||
* ...
|
||||
* \endcode
|
||||
* \ingroup ParamDoc
|
||||
*/
|
||||
#define PARAM_PY_DICT_SET_DOC(_dict,_seq) \
|
||||
BOOST_PP_SEQ_FOR_EACH(PARAM_PY_DICT_SET_DOC_,_dict,_seq)
|
||||
|
||||
|
||||
/** \defgroup ParamProperty Property Macros
|
||||
* Helper macros for FreeCAD properties
|
||||
* \ingroup ParamHelper
|
||||
* @{*/
|
||||
#define PARAM_PROP_bool(_v) App::PropertyBool _v
|
||||
#define PARAM_PROP_double(_v) App::PropertyFloat _v
|
||||
#define PARAM_PROP_short(_v) App::PropertyInteger _v
|
||||
#define PARAM_PROP_long(_v) App::PropertyInteger _v
|
||||
#define PARAM_PROP_enum(_v) App::PropertyEnumeration _v
|
||||
#define PARAM_PROP_enum2(_v) App::PropertyEnumeration _v
|
||||
/** @} */
|
||||
|
||||
/** Helper for #PARAM_PROP_DECLARE */
|
||||
#define PARAM_PROP_DECLARE_(_param) \
|
||||
PARAM_TYPED(PARAM_PROP_,_param)(PARAM_FNAME(_param));
|
||||
|
||||
/** Declare FreeCAD properties
|
||||
* \ingroup ParamProperty
|
||||
*/
|
||||
#define PARAM_PROP_DECLARE(_seq) \
|
||||
PARAM_FOREACH(PARAM_PROP_DECLARE_,_seq)
|
||||
|
||||
/** Replace FreeCAD #ADD_PROPERTY_TYPE to fix singifying macro */
|
||||
#define PARAM_ADD_PROPERTY_TYPE(_prop_, _defaultval_, _group_,_type_,_Docu_) \
|
||||
do { \
|
||||
this->_prop_.setValue _defaultval_;\
|
||||
this->_prop_.setContainer(this); \
|
||||
propertyData.addProperty(static_cast<App::PropertyContainer*>(this), BOOST_PP_STRINGIZE(_prop_), &this->_prop_, (_group_),(_type_),(_Docu_)); \
|
||||
} while (0)
|
||||
|
||||
/** Generic property adding */
|
||||
#define PARAM_PROP_ADD_(_group,_param) \
|
||||
PARAM_ADD_PROPERTY_TYPE(PARAM_FNAME(_param), (PARAM_FDEF(_param)),\
|
||||
_group,App::Prop_None,PARAM_FDOC(_param));
|
||||
|
||||
#define PARAM_PROP_ADD_short PARAM_PROP_ADD_
|
||||
#define PARAM_PROP_ADD_long PARAM_PROP_ADD_
|
||||
#define PARAM_PROP_ADD_double PARAM_PROP_ADD_
|
||||
#define PARAM_PROP_ADD_bool PARAM_PROP_ADD_
|
||||
#define PARAM_PROP_ADD_enum2 PARAM_PROP_ADD_enum
|
||||
|
||||
/** Add \c enum type parameter as property */
|
||||
#define PARAM_PROP_ADD_enum(_group,_param) \
|
||||
PARAM_ADD_PROPERTY_TYPE(PARAM_FNAME(_param), ((long)PARAM_FDEF(_param)),\
|
||||
_group,App::Prop_None,PARAM_FDOC(_param));
|
||||
|
||||
/** Helper for #PARAM_PROP_ADD */
|
||||
#define PARAM_PROP_ADD_TYPED(_1,_group,_i,_param) \
|
||||
PARAM_TYPED(PARAM_PROP_ADD_,_param)(_group,_param)
|
||||
|
||||
/** Add FreeCAD properties
|
||||
* \ingroup ParamProperty
|
||||
*/
|
||||
#define PARAM_PROP_ADD(_group,_seq) \
|
||||
BOOST_PP_SEQ_FOR_EACH_I(PARAM_PROP_ADD_TYPED,_group,_seq)
|
||||
|
||||
#define PARAM_PROP_SET_ENUM_short(...)
|
||||
#define PARAM_PROP_SET_ENUM_long(...)
|
||||
#define PARAM_PROP_SET_ENUM_bool(...)
|
||||
#define PARAM_PROP_SET_ENUM_double(...)
|
||||
#define PARAM_PROP_SET_ENUM_enum2 PARAM_PROP_SET_ENUM_enum
|
||||
|
||||
/** Setup \c enum type parameter */
|
||||
#define PARAM_PROP_SET_ENUM_enum(_prefix,_param) \
|
||||
PARAM_FNAME(_param).setEnums(BOOST_PP_CAT(_prefix,PARAM_FNAME(_param)));
|
||||
|
||||
/** Helper for #PARAM_PROP_SET_ENUM */
|
||||
#define PARAM_PROP_SET_ENUM_TYPED(_1,_prefix,_param) \
|
||||
PARAM_TYPED(PARAM_PROP_SET_ENUM_,_param)(_prefix,_param)
|
||||
|
||||
/* Setup the \c enum string list for \c enum type properties
|
||||
* \ingroup ParamProperty
|
||||
*/
|
||||
#define PARAM_PROP_SET_ENUM(_prefix,_seq) \
|
||||
BOOST_PP_SEQ_FOR_EACH(PARAM_PROP_SET_ENUM_TYPED,_prefix,_seq)
|
||||
|
||||
|
||||
/** Helper for #PARAM_PROP_ARGS */
|
||||
#define PARAM_PROP_ARGS_(_i,_param) \
|
||||
BOOST_PP_COMMA_IF(_i) PARAM_FNAME(_param).getValue()
|
||||
|
||||
/** Expand the property list as function arguments
|
||||
*
|
||||
* Expand to:
|
||||
* \code{.unparsed}
|
||||
* name1.getValue(), name2.getValue() ...
|
||||
* \endcode
|
||||
* \ingroup ParamProperty
|
||||
*/
|
||||
#define PARAM_PROP_ARGS(_seq) \
|
||||
PARAM_FOREACH_I(PARAM_PROP_ARGS_,_seq)
|
||||
|
||||
|
||||
/** Helper for #PARAM_PROP_TOUCHED */
|
||||
#define PARAM_PROP_TOUCHED_(_param) \
|
||||
if(PARAM_FNAME(_param).isTouched()) return 1;
|
||||
|
||||
/** Returns 1 if any properties is touched
|
||||
*
|
||||
* Expand to:
|
||||
* \code{.unparsed}
|
||||
* if(name1.isTouched()) return 1;
|
||||
* if(name2.isTouched()) return 1;
|
||||
* ...
|
||||
* \ingroup ParamProperty
|
||||
*/
|
||||
#define PARAM_PROP_TOUCHED(_seq) \
|
||||
PARAM_FOREACH(PARAM_PROP_TOUCHED_,_seq)
|
||||
|
||||
#endif // PARAMS_HELPER_H
|
|
@ -35,6 +35,7 @@
|
|||
#include "DlgSettingsPathColor.h"
|
||||
#include "ViewProviderPathCompound.h"
|
||||
#include "ViewProviderPathShape.h"
|
||||
#include "ViewProviderArea.h"
|
||||
|
||||
// use a different name to CreateCommand()
|
||||
void CreatePathCommands(void);
|
||||
|
@ -77,6 +78,8 @@ PyMODINIT_FUNC initPathGui()
|
|||
PathGui::ViewProviderPathCompoundPython ::init();
|
||||
PathGui::ViewProviderPathShape ::init();
|
||||
PathGui::ViewProviderPathPython ::init();
|
||||
PathGui::ViewProviderArea ::init();
|
||||
PathGui::ViewProviderAreaPython ::init();
|
||||
|
||||
// add resources and reloads the translators
|
||||
loadPathResource();
|
||||
|
|
|
@ -81,6 +81,8 @@ SET(PathGui_SRCS_ViewProvider
|
|||
ViewProviderPathCompound.h
|
||||
ViewProviderPathShape.cpp
|
||||
ViewProviderPathShape.h
|
||||
ViewProviderArea.cpp
|
||||
ViewProviderArea.h
|
||||
)
|
||||
|
||||
SOURCE_GROUP("ViewProvider" FILES ${PathGui_SRCS_ViewProvider})
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
#ifndef _PreComp_
|
||||
#endif
|
||||
|
||||
#include <TopExp_Explorer.hxx>
|
||||
|
||||
#include <Base/Console.h>
|
||||
#include <App/Application.h>
|
||||
#include <Gui/Application.h>
|
||||
|
@ -39,8 +41,86 @@
|
|||
#include <Mod/Path/App/FeaturePathCompound.h>
|
||||
#include <Mod/Path/App/FeaturePathShape.h>
|
||||
#include <Mod/Part/App/PartFeature.h>
|
||||
#include <Mod/Path/App/FeatureArea.h>
|
||||
|
||||
|
||||
// Path Area #####################################################################################################
|
||||
|
||||
|
||||
DEF_STD_CMD_A(CmdPathArea)
|
||||
|
||||
CmdPathArea::CmdPathArea()
|
||||
:Command("Path_Area")
|
||||
{
|
||||
sAppModule = "Path";
|
||||
sGroup = QT_TR_NOOP("Path");
|
||||
sMenuText = QT_TR_NOOP("Area");
|
||||
sToolTipText = QT_TR_NOOP("Creates a feature area from selected objects");
|
||||
sWhatsThis = "Path_Area";
|
||||
sStatusTip = sToolTipText;
|
||||
sPixmap = "Path-Area";
|
||||
sAccel = "P,A";
|
||||
|
||||
}
|
||||
|
||||
void CmdPathArea::activated(int iMsg)
|
||||
{
|
||||
Q_UNUSED(iMsg);
|
||||
std::vector<Gui::SelectionObject> Sel =
|
||||
getSelection().getSelectionEx(NULL, Part::Feature::getClassTypeId());
|
||||
std::list<std::string> cmds;
|
||||
std::ostringstream sources;
|
||||
if (Sel.size() > 0) {
|
||||
for(const Gui::SelectionObject &selObj : Sel) {
|
||||
const Part::Feature *pcObj = static_cast<const Part::Feature*>(selObj.getObject());
|
||||
if(selObj.getSubNames().empty()) {
|
||||
const TopoDS_Shape &shape = pcObj->Shape.getShape().getShape();
|
||||
TopExp_Explorer it(shape, TopAbs_SHELL);
|
||||
if(it.More()) {
|
||||
Base::Console().Error("Selected shape is not 2D\n");
|
||||
return;
|
||||
}
|
||||
sources << "FreeCAD.activeDocument()." << pcObj->getNameInDocument() << ",";
|
||||
continue;
|
||||
}
|
||||
|
||||
for(const std::string &name : selObj.getSubNames()) {
|
||||
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('Path::Feature','" << sub_fname << "').Shape = " <<
|
||||
pcObj->getNameInDocument() << '.' << name.substr(0,4) << '[' << index-1 << ']';
|
||||
cmds.push_back(cmd.str());
|
||||
sources << "FreeCAD.activeDocument()." << sub_fname << ",";
|
||||
}
|
||||
}
|
||||
}
|
||||
std::string FeatName = getUniqueObjectName("FeatureArea");
|
||||
openCommand("Create Path Area");
|
||||
for(const std::string &cmd : cmds)
|
||||
doCommand(Doc,cmd.c_str());
|
||||
doCommand(Doc,"FreeCAD.activeDocument().addObject('Path::FeatureArea','%s')",FeatName.c_str());
|
||||
doCommand(Doc,"FreeCAD.activeDocument().%s.Sources = [ %s ]",FeatName.c_str(),sources.str().c_str());
|
||||
commitCommand();
|
||||
updateActive();
|
||||
}
|
||||
|
||||
bool CmdPathArea::isActive(void)
|
||||
{
|
||||
return hasActiveDocument();
|
||||
}
|
||||
|
||||
// Path compound #####################################################################################################
|
||||
|
||||
|
||||
|
@ -95,7 +175,6 @@ bool CmdPathCompound::isActive(void)
|
|||
return hasActiveDocument();
|
||||
}
|
||||
|
||||
|
||||
// Path Shape #####################################################################################################
|
||||
|
||||
|
||||
|
@ -149,4 +228,5 @@ void CreatePathCommands(void)
|
|||
Gui::CommandManager &rcCmdMgr = Gui::Application::Instance->commandManager();
|
||||
rcCmdMgr.addCommand(new CmdPathCompound());
|
||||
rcCmdMgr.addCommand(new CmdPathShape());
|
||||
rcCmdMgr.addCommand(new CmdPathArea());
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
<file>icons/Path-ToolChange.svg</file>
|
||||
<file>icons/Path-Toolpath.svg</file>
|
||||
<file>icons/Path-ToolTable.svg</file>
|
||||
<file>icons/Path-Area.svg</file>
|
||||
<file>icons/preferences-path.svg</file>
|
||||
<file>panels/ContourEdit.ui</file>
|
||||
<file>panels/DlgJobChooser.ui</file>
|
||||
|
|
648
src/Mod/Path/Gui/Resources/icons/Path-Area.svg
Normal file
648
src/Mod/Path/Gui/Resources/icons/Path-Area.svg
Normal file
|
@ -0,0 +1,648 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="64px"
|
||||
height="64px"
|
||||
id="svg2816"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="Path-Area.svg">
|
||||
<defs
|
||||
id="defs2818">
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient4066">
|
||||
<stop
|
||||
style="stop-color:#4e9a06;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop4068" />
|
||||
<stop
|
||||
style="stop-color:#8ae234;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop4070" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient4022">
|
||||
<stop
|
||||
style="stop-color:#204a87;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop4024" />
|
||||
<stop
|
||||
style="stop-color:#729fcf;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop4026" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient4513">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop4515" />
|
||||
<stop
|
||||
style="stop-color:#999999;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop4517" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3681">
|
||||
<stop
|
||||
id="stop3697"
|
||||
offset="0"
|
||||
style="stop-color:#fff110;stop-opacity:1;" />
|
||||
<stop
|
||||
style="stop-color:#cf7008;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3685" />
|
||||
</linearGradient>
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 32 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="64 : 32 : 1"
|
||||
inkscape:persp3d-origin="32 : 21.333333 : 1"
|
||||
id="perspective2824" />
|
||||
<inkscape:perspective
|
||||
id="perspective3622"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3622-9"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3653"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3675"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3697"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3720"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3742"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3764"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3785"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3806"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3806-3"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3835"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3614"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3614-8"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3643"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3643-3"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3672"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3672-5"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3701"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3701-8"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3746"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<pattern
|
||||
patternTransform="matrix(0.67643728,-0.81829155,2.4578314,1.8844554,-26.450606,18.294947)"
|
||||
id="pattern5231"
|
||||
xlink:href="#Strips1_1-4"
|
||||
inkscape:collect="always" />
|
||||
<inkscape:perspective
|
||||
id="perspective5224"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<pattern
|
||||
inkscape:stockid="Stripes 1:1"
|
||||
id="Strips1_1-4"
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
|
||||
height="1"
|
||||
width="2"
|
||||
patternUnits="userSpaceOnUse"
|
||||
inkscape:collect="always">
|
||||
<rect
|
||||
id="rect4483-4"
|
||||
height="2"
|
||||
width="1"
|
||||
y="-0.5"
|
||||
x="0"
|
||||
style="fill:black;stroke:none" />
|
||||
</pattern>
|
||||
<inkscape:perspective
|
||||
id="perspective5224-9"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<pattern
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,39.618381,8.9692804)"
|
||||
id="pattern5231-4"
|
||||
xlink:href="#Strips1_1-6"
|
||||
inkscape:collect="always" />
|
||||
<inkscape:perspective
|
||||
id="perspective5224-3"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<pattern
|
||||
inkscape:stockid="Stripes 1:1"
|
||||
id="Strips1_1-6"
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
|
||||
height="1"
|
||||
width="2"
|
||||
patternUnits="userSpaceOnUse"
|
||||
inkscape:collect="always">
|
||||
<rect
|
||||
id="rect4483-0"
|
||||
height="2"
|
||||
width="1"
|
||||
y="-0.5"
|
||||
x="0"
|
||||
style="fill:black;stroke:none" />
|
||||
</pattern>
|
||||
<pattern
|
||||
patternTransform="matrix(0.66513382,-1.0631299,2.4167603,2.4482973,-49.762569,2.9546807)"
|
||||
id="pattern5296"
|
||||
xlink:href="#pattern5231-3"
|
||||
inkscape:collect="always" />
|
||||
<inkscape:perspective
|
||||
id="perspective5288"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<pattern
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,-26.336284,10.887197)"
|
||||
id="pattern5231-3"
|
||||
xlink:href="#Strips1_1-4-3"
|
||||
inkscape:collect="always" />
|
||||
<pattern
|
||||
inkscape:stockid="Stripes 1:1"
|
||||
id="Strips1_1-4-3"
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
|
||||
height="1"
|
||||
width="2"
|
||||
patternUnits="userSpaceOnUse"
|
||||
inkscape:collect="always">
|
||||
<rect
|
||||
id="rect4483-4-6"
|
||||
height="2"
|
||||
width="1"
|
||||
y="-0.5"
|
||||
x="0"
|
||||
style="fill:black;stroke:none" />
|
||||
</pattern>
|
||||
<pattern
|
||||
patternTransform="matrix(0.42844886,-0.62155849,1.5567667,1.431396,27.948414,13.306456)"
|
||||
id="pattern5330"
|
||||
xlink:href="#Strips1_1-9"
|
||||
inkscape:collect="always" />
|
||||
<inkscape:perspective
|
||||
id="perspective5323"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<pattern
|
||||
inkscape:stockid="Stripes 1:1"
|
||||
id="Strips1_1-9"
|
||||
patternTransform="matrix(0.66772843,-1.0037085,2.4261878,2.3114548,3.4760987,3.534923)"
|
||||
height="1"
|
||||
width="2"
|
||||
patternUnits="userSpaceOnUse"
|
||||
inkscape:collect="always">
|
||||
<rect
|
||||
id="rect4483-3"
|
||||
height="2"
|
||||
width="1"
|
||||
y="-0.5"
|
||||
x="0"
|
||||
style="fill:black;stroke:none" />
|
||||
</pattern>
|
||||
<inkscape:perspective
|
||||
id="perspective5361"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective5383"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective5411"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3681"
|
||||
id="linearGradient3687"
|
||||
x1="37.89756"
|
||||
y1="41.087898"
|
||||
x2="4.0605712"
|
||||
y2="40.168594"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(127.27273,-51.272729)" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3681"
|
||||
id="linearGradient3695"
|
||||
x1="37.894287"
|
||||
y1="40.484772"
|
||||
x2="59.811455"
|
||||
y2="43.558987"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(127.27273,-51.272729)" />
|
||||
<linearGradient
|
||||
id="linearGradient3681-3">
|
||||
<stop
|
||||
id="stop3697-3"
|
||||
offset="0"
|
||||
style="stop-color:#fff110;stop-opacity:1;" />
|
||||
<stop
|
||||
style="stop-color:#cf7008;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3685-4" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
y2="43.558987"
|
||||
x2="59.811455"
|
||||
y1="40.484772"
|
||||
x1="37.894287"
|
||||
gradientTransform="translate(-37.00068,-20.487365)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient3608"
|
||||
xlink:href="#linearGradient3681-3"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
id="linearGradient4513-2">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop4515-2" />
|
||||
<stop
|
||||
style="stop-color:#999999;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop4517-4" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
r="23.634638"
|
||||
fy="7.9319997"
|
||||
fx="32.151962"
|
||||
cy="7.9319997"
|
||||
cx="32.151962"
|
||||
gradientTransform="matrix(1,0,0,1.1841158,-8.5173246,-3.4097568)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient4538"
|
||||
xlink:href="#linearGradient4513-2"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
id="linearGradient4513-1">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop4515-8" />
|
||||
<stop
|
||||
style="stop-color:#999999;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop4517-6" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
r="23.634638"
|
||||
fy="7.9319997"
|
||||
fx="32.151962"
|
||||
cy="7.9319997"
|
||||
cx="32.151962"
|
||||
gradientTransform="matrix(1,0,0,1.1841158,-8.5173246,-3.4097568)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient4538-6"
|
||||
xlink:href="#linearGradient4513-1"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
id="linearGradient4513-1-3">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop4515-8-7" />
|
||||
<stop
|
||||
style="stop-color:#999999;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop4517-6-5" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
r="23.634638"
|
||||
fy="35.869175"
|
||||
fx="32.151962"
|
||||
cy="35.869175"
|
||||
cx="32.151962"
|
||||
gradientTransform="matrix(0.39497909,0,0,1.1841158,-2.716491,-26.067007)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient3069"
|
||||
xlink:href="#linearGradient4513-1-3"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
id="linearGradient4513-1-2">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop4515-8-6" />
|
||||
<stop
|
||||
style="stop-color:#999999;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop4517-6-6" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
r="23.634638"
|
||||
fy="35.869175"
|
||||
fx="32.151962"
|
||||
cy="35.869175"
|
||||
cx="32.151962"
|
||||
gradientTransform="matrix(0.39497909,0,0,1.1841158,-2.716491,-26.067007)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient3102"
|
||||
xlink:href="#linearGradient4513-1-2"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4513-1"
|
||||
id="radialGradient3132"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.39497909,0,0,1.1841158,64.952609,-7.0541574)"
|
||||
cx="32.151962"
|
||||
cy="27.950663"
|
||||
fx="32.151962"
|
||||
fy="27.950663"
|
||||
r="23.634638" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4022"
|
||||
id="linearGradient4028"
|
||||
x1="36.538239"
|
||||
y1="45.928013"
|
||||
x2="36.804447"
|
||||
y2="23.332739"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4066"
|
||||
id="linearGradient4072"
|
||||
x1="41.610756"
|
||||
y1="59.853931"
|
||||
x2="32.101425"
|
||||
y2="10.99928"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4031"
|
||||
id="linearGradient4055"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(71.494719,-3.1982556)"
|
||||
x1="30.000002"
|
||||
y1="14"
|
||||
x2="36"
|
||||
y2="54.227272" />
|
||||
<linearGradient
|
||||
id="linearGradient4031">
|
||||
<stop
|
||||
id="stop4033"
|
||||
offset="0"
|
||||
style="stop-color:#d3d7cf;stop-opacity:1" />
|
||||
<stop
|
||||
id="stop4035"
|
||||
offset="1"
|
||||
style="stop-color:#888a85;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="11"
|
||||
inkscape:cx="25.031078"
|
||||
inkscape:cy="28.81298"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:bbox-paths="true"
|
||||
inkscape:bbox-nodes="true"
|
||||
inkscape:snap-bbox-edge-midpoints="true"
|
||||
inkscape:snap-bbox-midpoints="true"
|
||||
inkscape:object-paths="true"
|
||||
inkscape:object-nodes="true"
|
||||
inkscape:window-width="1375"
|
||||
inkscape:window-height="876"
|
||||
inkscape:window-x="65"
|
||||
inkscape:window-y="24"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:snap-global="true">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid3234"
|
||||
empspacing="2"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata2821">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
<dc:title>Path-FaceProfile</dc:title>
|
||||
<dc:date>2016-01-19</dc:date>
|
||||
<dc:relation>http://www.freecadweb.org/wiki/index.php?title=Artwork</dc:relation>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:identifier>FreeCAD/src/Mod/Path/Gui/Resources/icons/Path-</dc:identifier>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD LGPL2+</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title>[agryson] Alexander Gryson</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer">
|
||||
<path
|
||||
style="color:#000000;fill:url(#linearGradient4028);fill-opacity:1;fill-rule:nonzero;stroke:#0b1521;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="M 33,21 17,45 41,49 53,33 49,23 z"
|
||||
id="rect3083"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccccc" />
|
||||
<path
|
||||
style="color:#000000;fill:none;stroke:#172a04;stroke-width:8;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="M 50,13 39,11 c -4,-1 -5.171573,-1.4142136 -8,0 -2,1 -3,2 -5,5 L 7,46 c -3,4 -1,7 3,8 l 28,4 c 5,1 9,-2 12,-6 l 4,-5"
|
||||
id="rect3083-0"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccscccccc" />
|
||||
<path
|
||||
style="color:#000000;fill:none;stroke:#729fcf;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="M 33.965909,23.113636 20.349931,43.571429 40.140486,46.839294 50.710729,32.691101 47.57301,24.842851 z"
|
||||
id="rect3083-3"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccccc" />
|
||||
<path
|
||||
style="color:#000000;fill:none;stroke:url(#linearGradient4072);stroke-width:4;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="M 50,13 39,11 c -4,-1 -5.171573,-1.414214 -8,0 -2,1 -3,2 -5,5 L 7,46 c -3,4 -1,7 3,8 l 28,4 c 5,1 9,-2 12,-6 l 4,-5"
|
||||
id="rect3083-0-6"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccscccccc" />
|
||||
<path
|
||||
style="color:#000000;fill:none;stroke:#8ae234;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="M 50.064283,12 38.517882,9.919647 c -4,-1.0000001 -5.171573,-1.4142141 -8,0 -2,1 -3,2 -5,5 l -19.0000003,30 c -2.9999999,4 -1,7 2.9999998,8 l 28.0000005,4 c 5,1 9,-2 12,-6 L 53,46"
|
||||
id="rect3083-0-6-7"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccscccccc" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 22 KiB |
125
src/Mod/Path/Gui/ViewProviderArea.cpp
Normal file
125
src/Mod/Path/Gui/ViewProviderArea.cpp
Normal file
|
@ -0,0 +1,125 @@
|
|||
/****************************************************************************
|
||||
* Copyright (c) 2017 Zheng, Lei (realthunder) <realthunder.dev@gmail.com>*
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#ifndef _PreComp_
|
||||
#endif
|
||||
|
||||
#include <Gui/Application.h>
|
||||
#include <Mod/Path/App/FeatureArea.h>
|
||||
#include "ViewProviderArea.h"
|
||||
|
||||
using namespace PathGui;
|
||||
|
||||
PROPERTY_SOURCE(PathGui::ViewProviderArea, PartGui::ViewProviderPlaneParametric)
|
||||
|
||||
ViewProviderArea::ViewProviderArea()
|
||||
{
|
||||
sPixmap = "Path-Area.svg";
|
||||
}
|
||||
|
||||
ViewProviderArea::~ViewProviderArea()
|
||||
{
|
||||
}
|
||||
|
||||
std::vector<App::DocumentObject*> ViewProviderArea::claimChildren(void) const
|
||||
{
|
||||
return std::vector<App::DocumentObject*>(
|
||||
static_cast<Path::FeatureArea*>(getObject())->Sources.getValues());
|
||||
}
|
||||
|
||||
bool ViewProviderArea::canDragObjects() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ViewProviderArea::canDragObject(App::DocumentObject* obj) const
|
||||
{
|
||||
return obj && obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId());
|
||||
}
|
||||
|
||||
void ViewProviderArea::dragObject(App::DocumentObject* obj)
|
||||
{
|
||||
Path::FeatureArea* area = static_cast<Path::FeatureArea*>(getObject());
|
||||
std::vector<App::DocumentObject*> sources = area->Sources.getValues();
|
||||
for (std::vector<App::DocumentObject*>::iterator it = sources.begin(); it != sources.end(); ++it) {
|
||||
if (*it == obj) {
|
||||
sources.erase(it);
|
||||
area->Sources.setValues(sources);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ViewProviderArea::canDropObjects() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ViewProviderArea::canDropObject(App::DocumentObject* obj) const
|
||||
{
|
||||
return canDragObject(obj);
|
||||
}
|
||||
|
||||
void ViewProviderArea::dropObject(App::DocumentObject* obj)
|
||||
{
|
||||
Path::FeatureArea* area = static_cast<Path::FeatureArea*>(getObject());
|
||||
std::vector<App::DocumentObject*> sources = area->Sources.getValues();
|
||||
sources.push_back(obj);
|
||||
area->Sources.setValues(sources);
|
||||
}
|
||||
|
||||
void ViewProviderArea::updateData(const App::Property* prop)
|
||||
{
|
||||
PartGui::ViewProviderPart::updateData(prop);
|
||||
if (prop->getTypeId() == App::PropertyLinkList::getClassTypeId()) {
|
||||
std::vector<App::DocumentObject*> pShapes = static_cast<const App::PropertyLinkList*>(prop)->getValues();
|
||||
for (std::vector<App::DocumentObject*>::iterator it = pShapes.begin(); it != pShapes.end(); ++it) {
|
||||
if (*it)
|
||||
Gui::Application::Instance->hideViewProvider(*it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ViewProviderArea::onDelete(const std::vector<std::string> &)
|
||||
{
|
||||
// get the input shapes
|
||||
Path::FeatureArea* area = static_cast<Path::FeatureArea*>(getObject());
|
||||
std::vector<App::DocumentObject*> pShapes =area->Sources.getValues();
|
||||
for (std::vector<App::DocumentObject*>::iterator it = pShapes.begin(); it != pShapes.end(); ++it) {
|
||||
if (*it)
|
||||
Gui::Application::Instance->showViewProvider(*it);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Python object -----------------------------------------------------------------------
|
||||
|
||||
namespace Gui {
|
||||
/// @cond DOXERR
|
||||
PROPERTY_SOURCE_TEMPLATE(PathGui::ViewProviderAreaPython, PathGui::ViewProviderArea)
|
||||
/// @endcond
|
||||
|
||||
// explicit template instantiation
|
||||
template class PathGuiExport ViewProviderPythonFeatureT<PathGui::ViewProviderArea>;
|
||||
}
|
60
src/Mod/Path/Gui/ViewProviderArea.h
Normal file
60
src/Mod/Path/Gui/ViewProviderArea.h
Normal file
|
@ -0,0 +1,60 @@
|
|||
/****************************************************************************
|
||||
* Copyright (c) 2017 Zheng, Lei (realthunder) <realthunder.dev@gmail.com>*
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
#ifndef PATH_ViewProviderArea_H
|
||||
#define PATH_ViewProviderArea_H
|
||||
|
||||
#include <Gui/ViewProviderPythonFeature.h>
|
||||
#include <Mod/Part/Gui/ViewProviderPlaneParametric.h>
|
||||
|
||||
namespace PathGui
|
||||
{
|
||||
|
||||
class PathGuiExport ViewProviderArea : public PartGui::ViewProviderPlaneParametric
|
||||
{
|
||||
PROPERTY_HEADER(PathGui::ViewProviderArea);
|
||||
|
||||
public:
|
||||
ViewProviderArea();
|
||||
virtual ~ViewProviderArea();
|
||||
|
||||
/// grouping handling
|
||||
virtual std::vector<App::DocumentObject*> claimChildren(void) const;
|
||||
virtual void updateData(const App::Property*);
|
||||
virtual bool onDelete(const std::vector<std::string> &);
|
||||
|
||||
/// drag and drop
|
||||
virtual bool canDragObjects() const;
|
||||
virtual bool canDragObject(App::DocumentObject*) const;
|
||||
virtual void dragObject(App::DocumentObject*);
|
||||
virtual bool canDropObjects() const;
|
||||
virtual bool canDropObject(App::DocumentObject*) const;
|
||||
virtual void dropObject(App::DocumentObject*);
|
||||
};
|
||||
|
||||
typedef Gui::ViewProviderPythonFeatureT<ViewProviderArea> ViewProviderAreaPython;
|
||||
|
||||
} //namespace PathGui
|
||||
|
||||
|
||||
#endif // PATH_ViewProviderArea_H
|
|
@ -86,7 +86,7 @@ class PathWorkbench (Workbench):
|
|||
threedopcmdlist = ["Path_Surfacing"]
|
||||
modcmdlist = ["Path_Copy", "Path_CompoundExtended", "Path_Array", "Path_SimpleCopy" ]
|
||||
dressupcmdlist = ["PathDressup_Dogbone", "PathDressup_DragKnife", "PathDressup_HoldingTags"]
|
||||
extracmdlist = ["Path_SelectLoop"]
|
||||
extracmdlist = ["Path_SelectLoop", "Path_Area"]
|
||||
#modcmdmore = ["Path_Hop",]
|
||||
#remotecmdlist = ["Path_Remote"]
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user