2366 lines
100 KiB
C++
2366 lines
100 KiB
C++
/***************************************************************************
|
|
* Copyright (c) 2002 Jürgen Riegel <juergen.riegel@web.de> *
|
|
* *
|
|
* 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_
|
|
# include <BRep_Builder.hxx>
|
|
# include <BRep_Tool.hxx>
|
|
# include <BRepAdaptor_Curve.hxx>
|
|
# include <BRepBuilderAPI_MakeEdge.hxx>
|
|
# include <BRepBuilderAPI_MakeFace.hxx>
|
|
# include <BRepBuilderAPI_MakePolygon.hxx>
|
|
# include <BRepBuilderAPI_MakeSolid.hxx>
|
|
# include <BRepCheck_Analyzer.hxx>
|
|
# include <BRepFeat_SplitShape.hxx>
|
|
# include <BRepOffsetAPI_Sewing.hxx>
|
|
# include <BRepPrim_Wedge.hxx>
|
|
# include <BRepPrimAPI_MakeBox.hxx>
|
|
# include <BRepPrimAPI_MakeCone.hxx>
|
|
# include <BRepPrimAPI_MakeCylinder.hxx>
|
|
# include <BRepPrimAPI_MakeRevolution.hxx>
|
|
# include <BRepPrimAPI_MakeSphere.hxx>
|
|
# include <BRepPrimAPI_MakeTorus.hxx>
|
|
# include <BRepFill.hxx>
|
|
# include <BRepFill_Filling.hxx>
|
|
# include <BRepLib.hxx>
|
|
# include <BSplCLib.hxx>
|
|
# include <gp_Ax3.hxx>
|
|
# include <gp_Circ.hxx>
|
|
# include <gp_Pnt.hxx>
|
|
# include <Geom_BSplineSurface.hxx>
|
|
# include <Geom_Circle.hxx>
|
|
# include <Geom_Plane.hxx>
|
|
# include <GeomFill_AppSurf.hxx>
|
|
# include <GeomFill_Generator.hxx>
|
|
# include <GeomFill_Line.hxx>
|
|
# include <GeomFill_SectionGenerator.hxx>
|
|
# include <Interface_Static.hxx>
|
|
# include <NCollection_List.hxx>
|
|
# include <Precision.hxx>
|
|
# include <ShapeFix.hxx>
|
|
# include <ShapeBuild_ReShape.hxx>
|
|
# include <ShapeUpgrade_ShellSewing.hxx>
|
|
# include <Standard_DomainError.hxx>
|
|
# include <Standard_Version.hxx>
|
|
# include <TopExp_Explorer.hxx>
|
|
# include <TopoDS_Compound.hxx>
|
|
# include <TopoDS_Edge.hxx>
|
|
# include <TopoDS_Face.hxx>
|
|
# include <TopoDS_Shell.hxx>
|
|
# include <TopoDS_Solid.hxx>
|
|
# include <TopTools_ListIteratorOfListOfShape.hxx>
|
|
#endif
|
|
# include <BRepFill_Generator.hxx>
|
|
|
|
#include <App/Application.h>
|
|
#include <App/Document.h>
|
|
#include <App/DocumentObjectPy.h>
|
|
#include <App/ElementNamingUtils.h>
|
|
#include <Base/Console.h>
|
|
#include <Base/Exception.h>
|
|
#include <Base/FileInfo.h>
|
|
#include <Base/GeometryPyCXX.h>
|
|
#include <Base/Interpreter.h>
|
|
#include <Base/PyWrapParseTupleAndKeywords.h>
|
|
#include <Base/Tools.h>
|
|
#include <Base/VectorPy.h>
|
|
|
|
#include "BSplineSurfacePy.h"
|
|
#include "edgecluster.h"
|
|
#include "FaceMaker.h"
|
|
#include "GeometryCurvePy.h"
|
|
#include "GeometryPy.h"
|
|
#include "ImportIges.h"
|
|
#include "ImportStep.h"
|
|
#include "Interface.h"
|
|
#include "modelRefine.h"
|
|
#include "OCCError.h"
|
|
#include "PartFeature.h"
|
|
#include "PartPyCXX.h"
|
|
#include "Tools.h"
|
|
#include "TopoShapeCompoundPy.h"
|
|
#include "TopoShapePy.h"
|
|
#include "TopoShapeEdgePy.h"
|
|
#include "TopoShapeFacePy.h"
|
|
#include "TopoShapeShellPy.h"
|
|
#include "TopoShapeSolidPy.h"
|
|
#include "TopoShapeWirePy.h"
|
|
#include "TopoShapeOpCode.h"
|
|
#include "TopoShapeMapper.h"
|
|
|
|
#ifdef FCUseFreeType
|
|
# include "FT2FC.h"
|
|
#endif
|
|
|
|
extern const char* BRepBuilderAPI_FaceErrorText(BRepBuilderAPI_FaceError fe);
|
|
|
|
namespace Part {
|
|
|
|
PartExport void getPyShapes(PyObject* obj, std::vector<TopoShape>& shapes)
|
|
{
|
|
if (!obj) {
|
|
return;
|
|
}
|
|
if (PyObject_TypeCheck(obj, &Part::TopoShapePy::Type)) {
|
|
shapes.push_back(*static_cast<TopoShapePy*>(obj)->getTopoShapePtr());
|
|
}
|
|
else if (PyObject_TypeCheck(obj, &GeometryPy::Type)) {
|
|
shapes.emplace_back(static_cast<GeometryPy*>(obj)->getGeometryPtr()->toShape());
|
|
}
|
|
else if (PySequence_Check(obj)) {
|
|
Py::Sequence list(obj);
|
|
for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
|
|
if (PyObject_TypeCheck((*it).ptr(), &(Part::TopoShapePy::Type))) {
|
|
shapes.push_back(*static_cast<TopoShapePy*>((*it).ptr())->getTopoShapePtr());
|
|
}
|
|
else if (PyObject_TypeCheck((*it).ptr(), &GeometryPy::Type)) {
|
|
shapes.emplace_back(
|
|
static_cast<GeometryPy*>((*it).ptr())->getGeometryPtr()->toShape());
|
|
}
|
|
else {
|
|
throw Py::TypeError("expect shape in sequence");
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
throw Py::TypeError("expect shape or sequence of shapes");
|
|
}
|
|
}
|
|
|
|
PartExport std::vector<TopoShape> getPyShapes(PyObject *obj) {
|
|
std::vector<TopoShape> ret;
|
|
getPyShapes(obj,ret);
|
|
return ret;
|
|
}
|
|
|
|
namespace
|
|
{
|
|
|
|
struct EdgePoints {
|
|
gp_Pnt v1, v2;
|
|
std::list<TopoDS_Edge>::iterator it;
|
|
TopoDS_Edge edge;
|
|
};
|
|
|
|
}
|
|
|
|
PartExport std::list<TopoDS_Edge> sort_Edges(double tol3d, std::list<TopoDS_Edge>& edges)
|
|
{
|
|
tol3d = tol3d * tol3d;
|
|
std::list<EdgePoints> edge_points;
|
|
TopExp_Explorer xp;
|
|
for (std::list<TopoDS_Edge>::iterator it = edges.begin(); it != edges.end(); ++it) {
|
|
EdgePoints ep;
|
|
xp.Init(*it,TopAbs_VERTEX);
|
|
ep.v1 = BRep_Tool::Pnt(TopoDS::Vertex(xp.Current()));
|
|
xp.Next();
|
|
ep.v2 = BRep_Tool::Pnt(TopoDS::Vertex(xp.Current()));
|
|
ep.it = it;
|
|
ep.edge = *it;
|
|
edge_points.push_back(ep);
|
|
}
|
|
|
|
if (edge_points.empty())
|
|
return {};
|
|
|
|
std::list<TopoDS_Edge> sorted;
|
|
gp_Pnt first, last;
|
|
first = edge_points.front().v1;
|
|
last = edge_points.front().v2;
|
|
|
|
sorted.push_back(edge_points.front().edge);
|
|
edges.erase(edge_points.front().it);
|
|
edge_points.erase(edge_points.begin());
|
|
|
|
while (!edge_points.empty()) {
|
|
// search for adjacent edge
|
|
std::list<EdgePoints>::iterator pEI;
|
|
for (pEI = edge_points.begin(); pEI != edge_points.end(); ++pEI) {
|
|
if (pEI->v1.SquareDistance(last) <= tol3d) {
|
|
last = pEI->v2;
|
|
sorted.push_back(pEI->edge);
|
|
edges.erase(pEI->it);
|
|
edge_points.erase(pEI);
|
|
pEI = edge_points.begin();
|
|
break;
|
|
}
|
|
else if (pEI->v2.SquareDistance(first) <= tol3d) {
|
|
first = pEI->v1;
|
|
sorted.push_front(pEI->edge);
|
|
edges.erase(pEI->it);
|
|
edge_points.erase(pEI);
|
|
pEI = edge_points.begin();
|
|
break;
|
|
}
|
|
else if (pEI->v2.SquareDistance(last) <= tol3d) {
|
|
last = pEI->v1;
|
|
Standard_Real first, last;
|
|
const Handle(Geom_Curve) & curve = BRep_Tool::Curve(pEI->edge, first, last);
|
|
first = curve->ReversedParameter(first);
|
|
last = curve->ReversedParameter(last);
|
|
TopoDS_Edge edgeReversed = BRepBuilderAPI_MakeEdge(curve->Reversed(), last, first);
|
|
sorted.push_back(edgeReversed);
|
|
edges.erase(pEI->it);
|
|
edge_points.erase(pEI);
|
|
pEI = edge_points.begin();
|
|
break;
|
|
}
|
|
else if (pEI->v1.SquareDistance(first) <= tol3d) {
|
|
first = pEI->v2;
|
|
Standard_Real first, last;
|
|
const Handle(Geom_Curve) & curve = BRep_Tool::Curve(pEI->edge, first, last);
|
|
first = curve->ReversedParameter(first);
|
|
last = curve->ReversedParameter(last);
|
|
TopoDS_Edge edgeReversed = BRepBuilderAPI_MakeEdge(curve->Reversed(), last, first);
|
|
sorted.push_front(edgeReversed);
|
|
edges.erase(pEI->it);
|
|
edge_points.erase(pEI);
|
|
pEI = edge_points.begin();
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ((pEI == edge_points.end()) || (last.SquareDistance(first) <= tol3d)) {
|
|
// no adjacent edge found or polyline is closed
|
|
return sorted;
|
|
}
|
|
}
|
|
|
|
return sorted;
|
|
}
|
|
}
|
|
|
|
namespace Part {
|
|
class BRepFeatModule : public Py::ExtensionModule<BRepFeatModule>
|
|
{
|
|
public:
|
|
BRepFeatModule() : Py::ExtensionModule<BRepFeatModule>("BRepFeat")
|
|
{
|
|
initialize("This is a module working with the BRepFeat package."); // register with Python
|
|
}
|
|
};
|
|
|
|
class BRepOffsetAPIModule : public Py::ExtensionModule<BRepOffsetAPIModule>
|
|
{
|
|
public:
|
|
BRepOffsetAPIModule() : Py::ExtensionModule<BRepOffsetAPIModule>("BRepOffsetAPI")
|
|
{
|
|
initialize("This is a module working with the BRepOffsetAPI package."); // register with Python
|
|
}
|
|
};
|
|
|
|
class Geom2dModule : public Py::ExtensionModule<Geom2dModule>
|
|
{
|
|
public:
|
|
Geom2dModule() : Py::ExtensionModule<Geom2dModule>("Geom2d")
|
|
{
|
|
initialize("This is a module working with 2d geometries."); // register with Python
|
|
}
|
|
};
|
|
|
|
class GeomPlateModule : public Py::ExtensionModule<GeomPlateModule>
|
|
{
|
|
public:
|
|
GeomPlateModule() : Py::ExtensionModule<GeomPlateModule>("GeomPlate")
|
|
{
|
|
initialize("This is a module working with the GeomPlate framework."); // register with Python
|
|
}
|
|
};
|
|
|
|
class HLRBRepModule : public Py::ExtensionModule<HLRBRepModule>
|
|
{
|
|
public:
|
|
HLRBRepModule() : Py::ExtensionModule<HLRBRepModule>("HLRBRep")
|
|
{
|
|
initialize("This is a module working with the HLRBRep framework."); // register with Python
|
|
}
|
|
};
|
|
|
|
class ShapeFixModule : public Py::ExtensionModule<ShapeFixModule>
|
|
{
|
|
public:
|
|
ShapeFixModule() : Py::ExtensionModule<ShapeFixModule>("ShapeFix")
|
|
{
|
|
add_varargs_method("sameParameter",&ShapeFixModule::sameParameter,
|
|
"sameParameter(shape, enforce, prec=0.0)"
|
|
);
|
|
add_varargs_method("encodeRegularity",&ShapeFixModule::encodeRegularity,
|
|
"encodeRegularity(shape, tolerance = 1e-10)\n"
|
|
);
|
|
add_varargs_method("removeSmallEdges",&ShapeFixModule::removeSmallEdges,
|
|
"removeSmallEdges(shape, tolerance, ReShapeContext)\n"
|
|
"Removes edges which are less than given tolerance from shape"
|
|
);
|
|
add_varargs_method("fixVertexPosition",&ShapeFixModule::fixVertexPosition,
|
|
"fixVertexPosition(shape, tolerance, ReShapeContext)\n"
|
|
"Fix position of the vertices having tolerance more tnan specified one"
|
|
);
|
|
add_varargs_method("leastEdgeSize",&ShapeFixModule::leastEdgeSize,
|
|
"leastEdgeSize(shape)\n"
|
|
"Calculate size of least edge"
|
|
);
|
|
initialize("This is a module working with the ShapeFix framework."); // register with Python
|
|
}
|
|
|
|
private:
|
|
Py::Object sameParameter(const Py::Tuple& args)
|
|
{
|
|
PyObject* shape;
|
|
PyObject* enforce;
|
|
double prec = 0.0;
|
|
if (!PyArg_ParseTuple(args.ptr(), "O!O!|d", &TopoShapePy::Type, &shape, &PyBool_Type, &enforce, &prec))
|
|
throw Py::Exception();
|
|
|
|
TopoDS_Shape sh = static_cast<TopoShapePy*>(shape)->getTopoShapePtr()->getShape();
|
|
bool ok = ShapeFix::SameParameter(sh, Base::asBoolean(enforce), prec);
|
|
return Py::Boolean(ok);
|
|
}
|
|
Py::Object encodeRegularity(const Py::Tuple& args)
|
|
{
|
|
PyObject* shape;
|
|
double tolang = 1.0e-10;
|
|
if (!PyArg_ParseTuple(args.ptr(), "O!|d", &TopoShapePy::Type, &shape, &tolang))
|
|
throw Py::Exception();
|
|
|
|
TopoDS_Shape sh = static_cast<TopoShapePy*>(shape)->getTopoShapePtr()->getShape();
|
|
ShapeFix::EncodeRegularity(sh, tolang);
|
|
return Py::None();
|
|
}
|
|
Py::Object removeSmallEdges(const Py::Tuple& args)
|
|
{
|
|
PyObject* shape;
|
|
double tol;
|
|
if (!PyArg_ParseTuple(args.ptr(), "O!d", &TopoShapePy::Type, &shape, &tol))
|
|
throw Py::Exception();
|
|
|
|
TopoDS_Shape sh = static_cast<TopoShapePy*>(shape)->getTopoShapePtr()->getShape();
|
|
Handle(ShapeBuild_ReShape) reshape = new ShapeBuild_ReShape();
|
|
TopoShape res = ShapeFix::RemoveSmallEdges(sh, tol, reshape);
|
|
return Py::asObject(res.getPyObject());
|
|
}
|
|
Py::Object fixVertexPosition(const Py::Tuple& args)
|
|
{
|
|
PyObject* shape;
|
|
double tol;
|
|
if (!PyArg_ParseTuple(args.ptr(), "O!d", &TopoShapePy::Type, &shape, &tol))
|
|
throw Py::Exception();
|
|
|
|
TopoDS_Shape sh = static_cast<TopoShapePy*>(shape)->getTopoShapePtr()->getShape();
|
|
Handle(ShapeBuild_ReShape) reshape = new ShapeBuild_ReShape();
|
|
bool ok = ShapeFix::FixVertexPosition(sh, tol, reshape);
|
|
return Py::Boolean(ok);
|
|
}
|
|
Py::Object leastEdgeSize(const Py::Tuple& args)
|
|
{
|
|
PyObject* shape;
|
|
if (!PyArg_ParseTuple(args.ptr(), "O!", &TopoShapePy::Type, &shape))
|
|
throw Py::Exception();
|
|
|
|
TopoDS_Shape sh = static_cast<TopoShapePy*>(shape)->getTopoShapePtr()->getShape();
|
|
double len = ShapeFix::LeastEdgeSize(sh);
|
|
return Py::Float(len);
|
|
}
|
|
};
|
|
|
|
class ShapeUpgradeModule : public Py::ExtensionModule<ShapeUpgradeModule>
|
|
{
|
|
public:
|
|
ShapeUpgradeModule() : Py::ExtensionModule<ShapeUpgradeModule>("ShapeUpgrade")
|
|
{
|
|
initialize("This is a module working with the ShapeUpgrade framework."); // register with Python
|
|
}
|
|
};
|
|
|
|
class ChFi2dModule : public Py::ExtensionModule<ChFi2dModule>
|
|
{
|
|
public:
|
|
ChFi2dModule() : Py::ExtensionModule<ChFi2dModule>("ChFi2d")
|
|
{
|
|
initialize("This is a module working with the ChFi2d framework."); // register with Python
|
|
}
|
|
};
|
|
|
|
class Module : public Py::ExtensionModule<Module>
|
|
{
|
|
BRepFeatModule brepFeat;
|
|
BRepOffsetAPIModule brepOffsetApi;
|
|
Geom2dModule geom2d;
|
|
GeomPlateModule geomPlate;
|
|
HLRBRepModule HLRBRep;
|
|
ShapeFixModule shapeFix;
|
|
ShapeUpgradeModule shapeUpgrade;
|
|
ChFi2dModule chFi2d;
|
|
public:
|
|
Module() : Py::ExtensionModule<Module>("Part")
|
|
{
|
|
add_varargs_method("open",&Module::open,
|
|
"open(string) -- Create a new document and load the file into the document."
|
|
);
|
|
add_varargs_method("insert",&Module::insert,
|
|
"insert(string,string) -- Insert the file into the given document."
|
|
);
|
|
add_varargs_method("export",&Module::exporter,
|
|
"export(list,string) -- Export a list of objects into a single file."
|
|
);
|
|
add_varargs_method("read",&Module::read,
|
|
"read(string) -- Load the file and return the shape."
|
|
);
|
|
add_varargs_method("show",&Module::show,
|
|
"show(shape,[string]) -- Add the shape to the active document or create one if no document exists.\n"
|
|
"Returns document object."
|
|
);
|
|
add_varargs_method("getFacets",&Module::getFacets,
|
|
"getFacets(shape): simplified mesh generation"
|
|
);
|
|
add_keyword_method("makeCompound",&Module::makeCompound,
|
|
"makeCompound(list) -- Create a compound out of a list of shapes."
|
|
);
|
|
add_keyword_method("makeShell",&Module::makeShell,
|
|
"makeShell(list) -- Create a shell out of a list of faces."
|
|
);
|
|
add_keyword_method("makeFace",&Module::makeFace,
|
|
"makeFace(list_of_shapes_or_compound, maker_class_name) -- Create a face (faces) using facemaker class.\n"
|
|
"maker_class_name is a string like 'Part::FaceMakerSimple'."
|
|
);
|
|
add_keyword_method("makeFilledSurface",&Module::makeFilledSurface,
|
|
"makeFilledSurface(list of curves, tolerance) -- Create a surface out of a list of curves."
|
|
);
|
|
add_keyword_method("makeFilledFace",&Module::makeFilledFace,
|
|
"makeFilledFace(list) -- Create a face out of a list of edges."
|
|
);
|
|
add_keyword_method("makeSolid",&Module::makeSolid,
|
|
"makeSolid(shape): Create a solid out of shells of shape. If shape is a compsolid, the overall volume solid is created."
|
|
);
|
|
add_varargs_method("makePlane",&Module::makePlane,
|
|
"makePlane(length,width,[pnt,dirZ,dirX]) -- Make a plane\n"
|
|
"By default pnt=Vector(0,0,0) and dirZ=Vector(0,0,1), dirX is ignored in this case"
|
|
);
|
|
add_varargs_method("makeBox",&Module::makeBox,
|
|
"makeBox(length,width,height,[pnt,dir]) -- Make a box located\n"
|
|
"in pnt with the dimensions (length,width,height)\n"
|
|
"By default pnt=Vector(0,0,0) and dir=Vector(0,0,1)"
|
|
);
|
|
add_varargs_method("makeWedge",&Module::makeWedge,
|
|
"makeWedge(xmin, ymin, zmin, z2min, x2min,\n"
|
|
"xmax, ymax, zmax, z2max, x2max,[pnt,dir])\n"
|
|
" -- Make a wedge located in pnt\n"
|
|
"By default pnt=Vector(0,0,0) and dir=Vector(0,0,1)"
|
|
);
|
|
add_varargs_method("makeLine",&Module::makeLine,
|
|
"makeLine(startpnt,endpnt) -- Make a line between two points\n"
|
|
"\n"
|
|
"Args:\n"
|
|
" startpnt (Vector or tuple): Vector or 3 element tuple \n"
|
|
" containing the x,y and z coordinates of the start point,\n"
|
|
" i.e. (x1,y1,z1).\n"
|
|
" endpnt (Vector or tuple): Vector or 3 element tuple \n"
|
|
" containing the x,y and z coordinates of the start point,\n"
|
|
" i.e. (x1,y1,z1).\n"
|
|
"\n"
|
|
"Returns:\n"
|
|
" Edge: Part.Edge object\n"
|
|
);
|
|
add_varargs_method("makePolygon",&Module::makePolygon,
|
|
"makePolygon(pntslist) -- Make a polygon from a list of points\n"
|
|
"\n"
|
|
"Args:\n"
|
|
" pntslist (list(Vector)): list of Vectors representing the \n"
|
|
" points of the polygon.\n"
|
|
"\n"
|
|
"Returns:\n"
|
|
" Wire: Part.Wire object. If the last point in the list is \n"
|
|
" not the same as the first point, the Wire will not be \n"
|
|
" closed and cannot be used to create a face.\n"
|
|
);
|
|
add_varargs_method("makeCircle",&Module::makeCircle,
|
|
"makeCircle(radius,[pnt,dir,angle1,angle2]) -- Make a circle with a given radius\n"
|
|
"By default pnt=Vector(0,0,0), dir=Vector(0,0,1), angle1=0 and angle2=360"
|
|
);
|
|
add_varargs_method("makeSphere",&Module::makeSphere,
|
|
"makeSphere(radius,[pnt, dir, angle1,angle2,angle3]) -- Make a sphere with a given radius\n"
|
|
"By default pnt=Vector(0,0,0), dir=Vector(0,0,1), angle1=0, angle2=90 and angle3=360"
|
|
);
|
|
add_varargs_method("makeCylinder",&Module::makeCylinder,
|
|
"makeCylinder(radius,height,[pnt,dir,angle]) -- Make a cylinder with a given radius and height\n"
|
|
"By default pnt=Vector(0,0,0),dir=Vector(0,0,1) and angle=360"
|
|
);
|
|
add_varargs_method("makeCone",&Module::makeCone,
|
|
"makeCone(radius1,radius2,height,[pnt,dir,angle]) -- Make a cone with given radii and height\n"
|
|
"By default pnt=Vector(0,0,0), dir=Vector(0,0,1) and angle=360"
|
|
);
|
|
add_varargs_method("makeTorus",&Module::makeTorus,
|
|
"makeTorus(radius1,radius2,[pnt,dir,angle1,angle2,angle]) -- Make a torus with a given radii and angles\n"
|
|
"By default pnt=Vector(0,0,0),dir=Vector(0,0,1),angle1=0,angle1=360 and angle=360"
|
|
);
|
|
add_varargs_method("makeHelix",&Module::makeHelix,
|
|
"makeHelix(pitch,height,radius,[angle]) -- Make a helix with a given pitch, height and radius\n"
|
|
"By default a cylindrical surface is used to create the helix. If the fourth parameter is set\n"
|
|
"(the apex given in degree) a conical surface is used instead"
|
|
);
|
|
add_varargs_method("makeLongHelix",&Module::makeLongHelix,
|
|
"makeLongHelix(pitch,height,radius,[angle],[hand]) -- Make a (multi-edge) helix with a given pitch, height and radius\n"
|
|
"By default a cylindrical surface is used to create the helix. If the fourth parameter is set\n"
|
|
"(the apex given in degree) a conical surface is used instead."
|
|
);
|
|
add_varargs_method("makeThread",&Module::makeThread,
|
|
"makeThread(pitch,depth,height,radius) -- Make a thread with a given pitch, depth, height and radius"
|
|
);
|
|
add_varargs_method("makeRevolution",&Module::makeRevolution,
|
|
"makeRevolution(Curve or Edge,[vmin,vmax,angle,pnt,dir,shapetype]) -- Make a revolved shape\n"
|
|
"by rotating the curve or a portion of it around an axis given by (pnt,dir).\n"
|
|
"By default vmin/vmax=bounds of the curve, angle=360, pnt=Vector(0,0,0),\n"
|
|
"dir=Vector(0,0,1) and shapetype=Part.Solid"
|
|
);
|
|
add_keyword_method("makeRuledSurface",&Module::makeRuledSurface,
|
|
"makeRuledSurface(Edge|Wire,Edge|Wire) -- Make a ruled surface\n"
|
|
"Create a ruled surface out of two edges or wires. If wires are used then"
|
|
"these must have the same number of edges."
|
|
);
|
|
add_keyword_method("makeShellFromWires",&Module::makeShellFromWires,
|
|
"makeShellFromWires(Wires) -- Make a shell from wires.\n"
|
|
"The wires must have the same number of edges."
|
|
);
|
|
add_keyword_method("makeLoft",&Module::makeLoft,
|
|
"makeLoft(list of wires,[solid=False,ruled=False,closed=False,maxDegree=5]) -- Create a loft shape."
|
|
);
|
|
add_varargs_method("makeTube",&Module::makeTube,
|
|
"makeTube(edge,radius,[continuity,max degree,max segments]) -- Create a tube.\n"
|
|
"continuity is a string which must be 'C0','C1','C2','C3','CN','G1' or 'G1',"
|
|
);
|
|
add_varargs_method("makeSweepSurface",&Module::makeSweepSurface,
|
|
"makeSweepSurface(edge(path),edge(profile),[float]) -- Create a profile along a path."
|
|
);
|
|
add_varargs_method("makeWireString",&Module::makeWireString,
|
|
"makeWireString(string,fontdir,fontfile,height,[track]) -- Make list of wires in the form of a string's characters."
|
|
);
|
|
add_varargs_method("makeSplitShape",&Module::makeSplitShape,
|
|
"makeSplitShape(shape, list of shape pairs,[check Interior=True]) -> two lists of shapes.\n"
|
|
"The following shape pairs are supported:\n"
|
|
"* Wire, Face\n"
|
|
"* Edge, Face\n"
|
|
"* Compound, Face\n"
|
|
"* Edge, Edge\n"
|
|
"* The face must be part of the specified shape and the edge, wire or compound must\n"
|
|
"lie on the face.\n"
|
|
"Output:\n"
|
|
"The first list contains the faces that are the left of the projected wires.\n"
|
|
"The second list contains the left part on the shape.\n\n"
|
|
"Example:\n"
|
|
"face = ...\n"
|
|
"edges = ...\n"
|
|
"split = [(edges[0],face),(edges[1],face)]\n"
|
|
"r = Part.makeSplitShape(face, split)\n"
|
|
"Part.show(r[0][0])\n"
|
|
"Part.show(r[1][0])\n"
|
|
);
|
|
add_varargs_method("exportUnits",&Module::exportUnits,
|
|
"exportUnits([string=MM|M|INCH|FT|MI|KM|MIL|UM|CM|UIN]) -- Set units for exporting STEP/IGES files and returns the units."
|
|
);
|
|
add_varargs_method("setStaticValue",&Module::setStaticValue,
|
|
"setStaticValue(string,string|int|float) -- Set a name to a value The value can be a string, int or float."
|
|
);
|
|
add_varargs_method("cast_to_shape",&Module::cast_to_shape,
|
|
"cast_to_shape(shape) -- Cast to the actual shape type"
|
|
);
|
|
add_varargs_method("getSortedClusters",&Module::getSortedClusters,
|
|
"getSortedClusters(list of edges) -- Helper method to sort and cluster a variety of edges"
|
|
);
|
|
add_varargs_method("__sortEdges__",&Module::sortEdges,
|
|
"__sortEdges__(list of edges) -- list of edges\n"
|
|
"Helper method to sort an unsorted list of edges so that afterwards\n"
|
|
"the start and end vertex of two consecutive edges are geometrically coincident.\n"
|
|
"It returns a single list of edges and the algorithm stops after the first set of\n"
|
|
"connected edges which means that the output list can be smaller than the input list.\n"
|
|
"The sorted list can be used to create a Wire."
|
|
);
|
|
add_varargs_method("sortEdges",&Module::sortEdges2,
|
|
"sortEdges(list of edges, [tol3d]) -- list of lists of edges\n"
|
|
"It does basically the same as __sortEdges__ but sorts all input edges and thus returns\n"
|
|
"a list of lists of edges\n"
|
|
"optional 3D tolerance defaults to Precision::Confusion"
|
|
);
|
|
add_varargs_method("__toPythonOCC__",&Module::toPythonOCC,
|
|
"__toPythonOCC__(shape) -- Helper method to convert an internal shape to pythonocc shape"
|
|
);
|
|
add_varargs_method("__fromPythonOCC__",&Module::fromPythonOCC,
|
|
"__fromPythonOCC__(occ) -- Helper method to convert a pythonocc shape to an internal shape"
|
|
);
|
|
add_varargs_method("clearShapeCache",&Module::clearShapeCache,
|
|
"clearShapeCache() -- Clears internal shape cache"
|
|
);
|
|
add_keyword_method("getShape",&Module::getShape,
|
|
"getShape(obj,subname=None,mat=None,needSubElement=False,transform=True,retType=0):\n"
|
|
"Obtain the TopoShape of a given object with SubName reference\n\n"
|
|
"* obj: the input object\n"
|
|
"* subname: dot separated sub-object reference\n"
|
|
"* mat: the current transformation matrix\n"
|
|
"* needSubElement: if False, ignore the sub-element (e.g. Face1, Edge1) reference in 'subname'\n"
|
|
"* transform: if False, then skip obj's transformation. Use this if mat already include obj's\n"
|
|
" transformation matrix\n"
|
|
"* retType: 0: return TopoShape,\n"
|
|
" 1: return (shape,mat,subObj), where subObj is the object referenced in 'subname',\n"
|
|
" and 'mat' is the accumulated transformation matrix of that sub-object.\n"
|
|
" 2: same as 1, but make sure 'subObj' is resolved if it is a link.\n"
|
|
"* refine: refine the returned shape"
|
|
);
|
|
add_varargs_method("splitSubname",&Module::splitSubname,
|
|
"splitSubname(subname) -> list(sub,mapped,subElement)\n"
|
|
"Split the given subname into a list\n\n"
|
|
"sub: subname without any sub-element reference\n"
|
|
"mapped: mapped element name, or '' if none\n"
|
|
"subElement: old style element name, or '' if none"
|
|
);
|
|
add_varargs_method("joinSubname",&Module::joinSubname,
|
|
"joinSubname(sub,mapped,subElement) -> subname\n"
|
|
);
|
|
initialize("This is a module working with shapes."); // register with Python
|
|
|
|
PyModule_AddObject(m_module, "BRepFeat", brepFeat.module().ptr());
|
|
PyModule_AddObject(m_module, "BRepOffsetAPI", brepOffsetApi.module().ptr());
|
|
PyModule_AddObject(m_module, "Geom2d", geom2d.module().ptr());
|
|
PyModule_AddObject(m_module, "GeomPlate", geomPlate.module().ptr());
|
|
PyModule_AddObject(m_module, "HLRBRep", HLRBRep.module().ptr());
|
|
PyModule_AddObject(m_module, "ShapeFix", shapeFix.module().ptr());
|
|
PyModule_AddObject(m_module, "ShapeUpgrade", shapeUpgrade.module().ptr());
|
|
PyModule_AddObject(m_module, "ChFi2d", chFi2d.module().ptr());
|
|
}
|
|
|
|
private:
|
|
Py::Object invoke_method_keyword( void *method_def,
|
|
const Py::Tuple &args, const Py::Dict &keywords ) override
|
|
{
|
|
try {
|
|
return Py::ExtensionModule<Module>::invoke_method_keyword(method_def, args, keywords);
|
|
}
|
|
catch (const Standard_Failure &e) {
|
|
std::string str;
|
|
Standard_CString msg = e.GetMessageString();
|
|
str += typeid(e).name();
|
|
str += " ";
|
|
if (msg) {str += msg;}
|
|
else {str += "No OCCT Exception Message";}
|
|
Base::Console().error("%s\n", str.c_str());
|
|
throw Py::Exception(Part::PartExceptionOCCError, str);
|
|
}
|
|
catch (const Base::Exception &e) {
|
|
std::string str;
|
|
str += "FreeCAD exception thrown (";
|
|
str += e.what();
|
|
str += ")";
|
|
e.reportException();
|
|
throw Py::RuntimeError(str);
|
|
}
|
|
catch (const std::exception &e) {
|
|
std::string str;
|
|
str += "C++ exception thrown (";
|
|
str += e.what();
|
|
str += ")";
|
|
Base::Console().error("%s\n", str.c_str());
|
|
throw Py::RuntimeError(str);
|
|
}
|
|
}
|
|
|
|
Py::Object invoke_method_varargs(void *method_def, const Py::Tuple &args) override
|
|
{
|
|
try {
|
|
return Py::ExtensionModule<Module>::invoke_method_varargs(method_def, args);
|
|
}
|
|
catch (const Standard_Failure &e) {
|
|
std::string str;
|
|
Standard_CString msg = e.GetMessageString();
|
|
str += typeid(e).name();
|
|
str += " ";
|
|
if (msg) {str += msg;}
|
|
else {str += "No OCCT Exception Message";}
|
|
Base::Console().error("%s\n", str.c_str());
|
|
throw Py::Exception(Part::PartExceptionOCCError, str);
|
|
}
|
|
catch (const Base::Exception &e) {
|
|
std::string str;
|
|
str += "FreeCAD exception thrown (";
|
|
str += e.what();
|
|
str += ")";
|
|
e.reportException();
|
|
throw Py::RuntimeError(str);
|
|
}
|
|
catch (const std::exception &e) {
|
|
std::string str;
|
|
str += "C++ exception thrown (";
|
|
str += e.what();
|
|
str += ")";
|
|
Base::Console().error("%s\n", str.c_str());
|
|
throw Py::RuntimeError(str);
|
|
}
|
|
}
|
|
|
|
Py::Object open(const Py::Tuple& args)
|
|
{
|
|
char* Name;
|
|
if (!PyArg_ParseTuple(args.ptr(), "et","utf-8",&Name))
|
|
throw Py::Exception();
|
|
std::string EncodedName = std::string(Name);
|
|
PyMem_Free(Name);
|
|
|
|
Base::FileInfo file(EncodedName.c_str());
|
|
|
|
// extract ending
|
|
if (file.extension().empty())
|
|
throw Py::RuntimeError("No file extension");
|
|
|
|
if (file.hasExtension({"stp", "step"})) {
|
|
// create new document and add Import feature
|
|
App::Document *pcDoc = App::GetApplication().newDocument();
|
|
ImportStepParts(pcDoc,EncodedName.c_str());
|
|
|
|
pcDoc->recompute();
|
|
}
|
|
else if (file.hasExtension({"igs", "iges"})) {
|
|
App::Document *pcDoc = App::GetApplication().newDocument();
|
|
ImportIgesParts(pcDoc,EncodedName.c_str());
|
|
pcDoc->recompute();
|
|
}
|
|
else {
|
|
TopoShape shape;
|
|
shape.read(EncodedName.c_str());
|
|
|
|
// create new document set loaded shape
|
|
App::Document *pcDoc = App::GetApplication().newDocument(file.fileNamePure().c_str());
|
|
Part::Feature *object = static_cast<Part::Feature *>(pcDoc->addObject
|
|
("Part::Feature",file.fileNamePure().c_str()));
|
|
object->Shape.setValue(shape);
|
|
pcDoc->recompute();
|
|
}
|
|
|
|
return Py::None();
|
|
}
|
|
Py::Object insert(const Py::Tuple& args)
|
|
{
|
|
char* Name;
|
|
const char* DocName;
|
|
if (!PyArg_ParseTuple(args.ptr(), "ets","utf-8",&Name,&DocName))
|
|
throw Py::Exception();
|
|
|
|
std::string EncodedName = std::string(Name);
|
|
PyMem_Free(Name);
|
|
|
|
//Base::Console().log("Insert in Part with %s",Name);
|
|
Base::FileInfo file(EncodedName.c_str());
|
|
|
|
// extract ending
|
|
if (file.extension().empty())
|
|
throw Py::RuntimeError("No file extension");
|
|
|
|
App::Document *pcDoc = App::GetApplication().getDocument(DocName);
|
|
if (!pcDoc) {
|
|
pcDoc = App::GetApplication().newDocument(DocName);
|
|
}
|
|
|
|
if (file.hasExtension({"stp", "step"})) {
|
|
ImportStepParts(pcDoc,EncodedName.c_str());
|
|
|
|
pcDoc->recompute();
|
|
}
|
|
else if (file.hasExtension({"igs", "iges"})) {
|
|
ImportIgesParts(pcDoc,EncodedName.c_str());
|
|
pcDoc->recompute();
|
|
}
|
|
else {
|
|
TopoShape shape;
|
|
shape.read(EncodedName.c_str());
|
|
|
|
Part::Feature *object = static_cast<Part::Feature *>(pcDoc->addObject
|
|
("Part::Feature",file.fileNamePure().c_str()));
|
|
object->Shape.setValue(shape);
|
|
pcDoc->recompute();
|
|
}
|
|
|
|
return Py::None();
|
|
}
|
|
Py::Object exporter(const Py::Tuple& args)
|
|
{
|
|
PyObject* object;
|
|
char* Name;
|
|
if (!PyArg_ParseTuple(args.ptr(), "Oet",&object,"utf-8",&Name))
|
|
throw Py::Exception();
|
|
|
|
std::string EncodedName = std::string(Name);
|
|
PyMem_Free(Name);
|
|
|
|
BRep_Builder builder;
|
|
TopoDS_Compound comp;
|
|
builder.MakeCompound(comp);
|
|
|
|
Py::Sequence list(object);
|
|
for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
|
|
PyObject* item = (*it).ptr();
|
|
if (PyObject_TypeCheck(item, &(App::DocumentObjectPy::Type))) {
|
|
App::DocumentObject* obj = static_cast<App::DocumentObjectPy*>(item)->getDocumentObjectPtr();
|
|
if (obj->isDerivedFrom<Part::Feature>()) {
|
|
Part::Feature* part = static_cast<Part::Feature*>(obj);
|
|
const TopoDS_Shape& shape = part->Shape.getValue();
|
|
if (!shape.IsNull())
|
|
builder.Add(comp, shape);
|
|
}
|
|
else {
|
|
Base::Console().message("'%s' is not a shape, export will be ignored.\n", obj->Label.getValue());
|
|
}
|
|
}
|
|
}
|
|
|
|
TopoShape shape(comp);
|
|
shape.write(EncodedName.c_str());
|
|
|
|
return Py::None();
|
|
}
|
|
Py::Object read(const Py::Tuple& args)
|
|
{
|
|
char* Name;
|
|
if (!PyArg_ParseTuple(args.ptr(), "et","utf-8",&Name))
|
|
throw Py::Exception();
|
|
|
|
std::string EncodedName = std::string(Name);
|
|
PyMem_Free(Name);
|
|
|
|
TopoShape* shape = new TopoShape();
|
|
shape->read(EncodedName.c_str());
|
|
return Py::asObject(new TopoShapePy(shape));
|
|
}
|
|
Py::Object show(const Py::Tuple& args)
|
|
{
|
|
PyObject *pcObj = nullptr;
|
|
const char *name = "Shape";
|
|
if (!PyArg_ParseTuple(args.ptr(), "O!|s", &(TopoShapePy::Type), &pcObj, &name))
|
|
throw Py::Exception();
|
|
|
|
App::Document *pcDoc = App::GetApplication().getActiveDocument();
|
|
if (!pcDoc)
|
|
pcDoc = App::GetApplication().newDocument();
|
|
TopoShape shape;
|
|
if (PyObject_TypeCheck(pcObj, &TopoShapePy::Type))
|
|
shape = *static_cast<TopoShapePy *>(pcObj)->getTopoShapePtr();
|
|
else if (PyObject_TypeCheck(pcObj, &GeometryPy::Type))
|
|
shape = static_cast<GeometryPy *>(pcObj)->getGeometryPtr()->toShape();
|
|
else if (PyObject_TypeCheck(pcObj, &App::DocumentObjectPy::Type)) {
|
|
auto obj = static_cast<App::DocumentObjectPy *>(pcObj)->getDocumentObjectPtr();
|
|
shape = Feature::getTopoShape(obj);
|
|
} else {
|
|
throw Py::TypeError("Expects argument of type DocumentObject, Shape, or Geometry");
|
|
}
|
|
Part::Feature *pcFeature = pcDoc->addObject<Part::Feature>(name);
|
|
// copy the data
|
|
pcFeature->Shape.setValue(shape);
|
|
pcFeature->purgeTouched();
|
|
return Py::asObject(pcFeature->getPyObject());
|
|
}
|
|
Py::Object getFacets(const Py::Tuple& args)
|
|
{
|
|
PyObject *shape;
|
|
Py::List list;
|
|
if (!PyArg_ParseTuple(args.ptr(), "O", &shape))
|
|
throw Py::Exception();
|
|
auto theShape = static_cast<Part::TopoShapePy*>(shape)->getTopoShapePtr()->getShape();
|
|
for (TopExp_Explorer ex(theShape, TopAbs_FACE); ex.More(); ex.Next()) {
|
|
TopoDS_Face currentFace = TopoDS::Face(ex.Current());
|
|
|
|
std::vector<gp_Pnt> points;
|
|
std::vector<Poly_Triangle> facets;
|
|
if (Tools::getTriangulation(currentFace, points, facets)) {
|
|
for (const auto& it : facets) {
|
|
Standard_Integer n1,n2,n3;
|
|
it.Get(n1, n2, n3);
|
|
|
|
gp_Pnt p1 = points[n1];
|
|
gp_Pnt p2 = points[n2];
|
|
gp_Pnt p3 = points[n3];
|
|
|
|
// TODO: verify if tolerance should be hard coded
|
|
if (!p1.IsEqual(p2, 0.01) && !p2.IsEqual(p3, 0.01) && !p3.IsEqual(p1, 0.01)) {
|
|
PyObject *t1 = PyTuple_Pack(3, PyFloat_FromDouble(p1.X()), PyFloat_FromDouble(p1.Y()), PyFloat_FromDouble(p1.Z()));
|
|
PyObject *t2 = PyTuple_Pack(3, PyFloat_FromDouble(p2.X()), PyFloat_FromDouble(p2.Y()), PyFloat_FromDouble(p2.Z()));
|
|
PyObject *t3 = PyTuple_Pack(3, PyFloat_FromDouble(p3.X()), PyFloat_FromDouble(p3.Y()), PyFloat_FromDouble(p3.Z()));
|
|
list.append(Py::asObject(PyTuple_Pack(3, t1, t2, t3)));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return list;
|
|
}
|
|
Py::Object makeCompound(const Py::Tuple& args, const Py::Dict &kwds)
|
|
{
|
|
PyObject* pcObj;
|
|
PyObject* force = Py_True;
|
|
TopoShape::SingleShapeCompoundCreationPolicy
|
|
policy; // = TopoShape::SingleShapeCompoundCreationPolicy::forceCompound;
|
|
PyObject* module = PyImport_ImportModule("PartEnums");
|
|
PyObject* policyEnum =
|
|
PyObject_GetAttrString(module, (char*)"SingleShapeCompoundCreationPolicy");
|
|
const char* op = nullptr;
|
|
const std::array<const char*, 4> kwd_list = {"shapes", "force", "op", nullptr};
|
|
if (!Base::Wrapped_ParseTupleAndKeywords(args.ptr(),
|
|
kwds.ptr(),
|
|
"O|O!s",
|
|
kwd_list,
|
|
&pcObj,
|
|
policyEnum,
|
|
&force,
|
|
&op)) {
|
|
throw Py::Exception();
|
|
}
|
|
|
|
policy = static_cast<TopoShape::SingleShapeCompoundCreationPolicy>(PyLong_AsLong(force));
|
|
Py_DECREF(policyEnum);
|
|
|
|
return shape2pyshape(Part::TopoShape().makeElementCompound(getPyShapes(pcObj), op, policy));
|
|
}
|
|
Py::Object makeShell(const Py::Tuple& args, const Py::Dict &kwds)
|
|
{
|
|
PyObject* obj;
|
|
const char* op = nullptr;
|
|
const std::array<const char*, 3> kwd_list = {"shapes", "op", nullptr};
|
|
if (!Base::Wrapped_ParseTupleAndKeywords(args.ptr(),
|
|
kwds.ptr(),
|
|
"O|s",
|
|
kwd_list,
|
|
&obj,
|
|
&op)) {
|
|
throw Py::Exception();
|
|
}
|
|
return shape2pyshape(
|
|
Part::TopoShape().makeElementBoolean(Part::OpCodes::Shell, getPyShapes(obj), op));
|
|
}
|
|
Py::Object makeFace(const Py::Tuple& args, const Py::Dict &kwds)
|
|
{
|
|
PyObject* obj;
|
|
const char* className = nullptr;
|
|
const char* op = nullptr;
|
|
const std::array<const char*, 4> kwd_list = {"shapes", "class_name", "op", nullptr};
|
|
if (!Base::Wrapped_ParseTupleAndKeywords(args.ptr(),
|
|
kwds.ptr(),
|
|
"O|ss",
|
|
kwd_list,
|
|
&obj,
|
|
&className,
|
|
&op)) {
|
|
throw Py::Exception();
|
|
}
|
|
return shape2pyshape(TopoShape().makeElementFace(getPyShapes(obj), op, className));
|
|
}
|
|
|
|
template<class F>
|
|
void parseSequence(PyObject *pyObj, const char *err, F f)
|
|
{
|
|
if (pyObj != Py_None) {
|
|
if (!PySequence_Check(pyObj))
|
|
throw Py::TypeError(err);
|
|
Py::Sequence seq(pyObj);
|
|
for (Py::Sequence::iterator it = seq.begin(); it != seq.end(); ++it) {
|
|
if (!PySequence_Check((*it).ptr()))
|
|
throw Py::TypeError(err);
|
|
Py::Sequence tuple((*it).ptr());
|
|
if (tuple.size() != 2)
|
|
throw Py::TypeError(err);
|
|
auto iter = tuple.begin();
|
|
if (!PyObject_TypeCheck((*iter).ptr(), &(Part::TopoShapePy::Type)))
|
|
throw Py::TypeError(err);
|
|
const TopoDS_Shape& sh = static_cast<TopoShapePy*>((*iter).ptr())->getTopoShapePtr()->getShape();
|
|
f(sh, (*iter).ptr(), err);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
Py::Object makeFilledSurface(const Py::Tuple &args, const Py::Dict &kwds)
|
|
{
|
|
TopoShape::BRepFillingParams params;
|
|
PyObject* obj = nullptr;
|
|
PyObject* pySurface = Py_None;
|
|
PyObject* supports = Py_None;
|
|
PyObject* orders = Py_None;
|
|
PyObject* anisotropy = params.anisotropy ? Py_True : Py_False;
|
|
const char* op = nullptr;
|
|
const std::array<const char*, 16> kwd_list = {"shapes",
|
|
"surface",
|
|
"supports",
|
|
"orders",
|
|
"degree",
|
|
"ptsOnCurve",
|
|
"numIter",
|
|
"anisotropy",
|
|
"tol2d",
|
|
"tol3d",
|
|
"tolG1",
|
|
"tolG2",
|
|
"maxDegree",
|
|
"maxSegments",
|
|
"op",
|
|
nullptr};
|
|
if (!Base::Wrapped_ParseTupleAndKeywords(args.ptr(),
|
|
kwds.ptr(),
|
|
"O|O!OOIIIOddddIIs",
|
|
kwd_list,
|
|
&obj,
|
|
&pySurface,
|
|
&orders,
|
|
¶ms.degree,
|
|
¶ms.ptsoncurve,
|
|
¶ms.numiter,
|
|
&anisotropy,
|
|
¶ms.tol2d,
|
|
¶ms.tol3d,
|
|
¶ms.tolG1,
|
|
¶ms.tolG2,
|
|
¶ms.maxdeg,
|
|
¶ms.maxseg,
|
|
&op)) {
|
|
throw Py::Exception();
|
|
}
|
|
params.anisotropy = PyObject_IsTrue(anisotropy);
|
|
TopoShape surface;
|
|
if (pySurface != Py_None) {
|
|
surface = *static_cast<TopoShapePy*>(pySurface)->getTopoShapePtr();
|
|
}
|
|
parseSequence(supports,
|
|
"Expects 'supports' to be a sequence of tuple(shape, shape)",
|
|
[&](const TopoDS_Shape& s, PyObject* value, const char* err) {
|
|
if (!PyObject_TypeCheck(value, &(Part::TopoShapePy::Type))) {
|
|
throw Py::TypeError(err);
|
|
}
|
|
params.supports[s] =
|
|
static_cast<TopoShapePy*>(value)->getTopoShapePtr()->getShape();
|
|
});
|
|
parseSequence(orders,
|
|
"Expects 'orders' to be a sequence of tuple(shape, PartEnums.Shape)",
|
|
[&](const TopoDS_Shape& s, PyObject* value, const char* err) {
|
|
if (!PyLong_Check(value)) {
|
|
throw Py::ValueError(err);
|
|
}
|
|
int order = Py::Long(value);
|
|
params.orders[s] = static_cast<TopoShape::Continuity>(order);
|
|
return;
|
|
});
|
|
auto shapes = getPyShapes(obj);
|
|
if (shapes.empty()) {
|
|
throw Py::ValueError("No input shape");
|
|
}
|
|
return shape2pyshape(
|
|
TopoShape(0, shapes.front().Hasher).makeElementFilledFace(shapes, params, op));
|
|
}
|
|
|
|
Py::Object makeFilledFace(const Py::Tuple& args, const Py::Dict &kwds)
|
|
{
|
|
TopoShape::BRepFillingParams params;
|
|
PyObject* obj = nullptr;
|
|
PyObject* pySurface = Py_None;
|
|
PyObject* supports = Py_None;
|
|
PyObject* orders = Py_None;
|
|
PyObject* anisotropy = params.anisotropy ? Py_True : Py_False;
|
|
const char* op = nullptr;
|
|
const std::array<const char*, 16> kwd_list = {"shapes",
|
|
"surface",
|
|
"supports",
|
|
"orders",
|
|
"degree",
|
|
"ptsOnCurve",
|
|
"numIter",
|
|
"anisotropy",
|
|
"tol2d",
|
|
"tol3d",
|
|
"tolG1",
|
|
"tolG2",
|
|
"maxDegree",
|
|
"maxSegments",
|
|
"op",
|
|
nullptr};
|
|
if (!Base::Wrapped_ParseTupleAndKeywords(args.ptr(),
|
|
kwds.ptr(),
|
|
"O|O!OOIIIOddddIIs",
|
|
kwd_list,
|
|
&obj,
|
|
&pySurface,
|
|
&orders,
|
|
¶ms.degree,
|
|
¶ms.ptsoncurve,
|
|
¶ms.numiter,
|
|
&anisotropy,
|
|
¶ms.tol2d,
|
|
¶ms.tol3d,
|
|
¶ms.tolG1,
|
|
¶ms.tolG2,
|
|
¶ms.maxdeg,
|
|
¶ms.maxseg,
|
|
&op)) {
|
|
throw Py::Exception();
|
|
}
|
|
params.anisotropy = PyObject_IsTrue(anisotropy);
|
|
TopoShape surface;
|
|
if (pySurface != Py_None) {
|
|
surface = *static_cast<TopoShapePy*>(pySurface)->getTopoShapePtr();
|
|
}
|
|
parseSequence(supports,
|
|
"Expects 'supports' to be a sequence of tuple(shape, shape)",
|
|
[&](const TopoDS_Shape& s, PyObject* value, const char* err) {
|
|
if (!PyObject_TypeCheck(value, &(Part::TopoShapePy::Type))) {
|
|
throw Py::TypeError(err);
|
|
}
|
|
params.supports[s] =
|
|
static_cast<TopoShapePy*>(value)->getTopoShapePtr()->getShape();
|
|
});
|
|
parseSequence(orders,
|
|
"Expects 'orders' to be a sequence of tuple(shape, PartEnums.Shape)",
|
|
[&](const TopoDS_Shape& s, PyObject* value, const char* err) {
|
|
if (!PyLong_Check(value)) {
|
|
throw Py::ValueError(err);
|
|
}
|
|
int order = Py::Long(value);
|
|
params.orders[s] = static_cast<TopoShape::Continuity>(order);
|
|
return;
|
|
});
|
|
auto shapes = getPyShapes(obj);
|
|
if (shapes.empty()) {
|
|
throw Py::ValueError("No input shape");
|
|
}
|
|
return shape2pyshape(
|
|
TopoShape(0, shapes.front().Hasher).makeElementFilledFace(shapes, params, op));
|
|
}
|
|
|
|
Py::Object makeSolid(const Py::Tuple& args, const Py::Dict &kwds)
|
|
{
|
|
PyObject* obj;
|
|
const char* op = nullptr;
|
|
const std::array<const char*, 3> kwd_list = {"shape", "op", nullptr};
|
|
if (!Base::Wrapped_ParseTupleAndKeywords(args.ptr(),
|
|
kwds.ptr(),
|
|
"O!|s",
|
|
kwd_list,
|
|
&(TopoShapePy::Type),
|
|
&obj,
|
|
&op)) {
|
|
throw Py::Exception();
|
|
}
|
|
return shape2pyshape(
|
|
TopoShape().makeElementSolid(*static_cast<TopoShapePy*>(obj)->getTopoShapePtr(), op));
|
|
}
|
|
|
|
Py::Object makePlane(const Py::Tuple& args)
|
|
{
|
|
double length, width;
|
|
PyObject *pPnt=nullptr, *pDirZ=nullptr, *pDirX=nullptr;
|
|
if (!PyArg_ParseTuple(args.ptr(), "dd|O!O!O!", &length, &width,
|
|
&(Base::VectorPy::Type), &pPnt,
|
|
&(Base::VectorPy::Type), &pDirZ,
|
|
&(Base::VectorPy::Type), &pDirX))
|
|
throw Py::Exception();
|
|
|
|
if (length < Precision::Confusion()) {
|
|
throw Py::ValueError("length of plane too small");
|
|
}
|
|
if (width < Precision::Confusion()) {
|
|
throw Py::ValueError("width of plane too small");
|
|
}
|
|
|
|
try {
|
|
gp_Pnt p(0,0,0);
|
|
gp_Dir d(0,0,1);
|
|
if (pPnt) {
|
|
Base::Vector3d pnt = static_cast<Base::VectorPy*>(pPnt)->value();
|
|
p.SetCoord(pnt.x, pnt.y, pnt.z);
|
|
}
|
|
if (pDirZ) {
|
|
Base::Vector3d vec = static_cast<Base::VectorPy*>(pDirZ)->value();
|
|
d.SetCoord(vec.x, vec.y, vec.z);
|
|
}
|
|
Handle(Geom_Plane) aPlane;
|
|
if (pDirX) {
|
|
Base::Vector3d vec = static_cast<Base::VectorPy*>(pDirX)->value();
|
|
gp_Dir dx;
|
|
dx.SetCoord(vec.x, vec.y, vec.z);
|
|
aPlane = new Geom_Plane(gp_Ax3(p, d, dx));
|
|
}
|
|
else {
|
|
aPlane = new Geom_Plane(p, d);
|
|
}
|
|
|
|
BRepBuilderAPI_MakeFace Face(aPlane, 0.0, length, 0.0, width, Precision::Confusion() );
|
|
return Py::asObject(new TopoShapeFacePy(new TopoShape((Face.Face()))));
|
|
}
|
|
catch (Standard_DomainError&) {
|
|
throw Py::Exception(PartExceptionOCCDomainError, "creation of plane failed");
|
|
}
|
|
catch (Standard_Failure&) {
|
|
throw Py::Exception(PartExceptionOCCError, "creation of plane failed");
|
|
}
|
|
}
|
|
Py::Object makeBox(const Py::Tuple& args)
|
|
{
|
|
double length, width, height;
|
|
PyObject *pPnt=nullptr, *pDir=nullptr;
|
|
if (!PyArg_ParseTuple(args.ptr(), "ddd|O!O!",
|
|
&length, &width, &height,
|
|
&(Base::VectorPy::Type), &pPnt,
|
|
&(Base::VectorPy::Type), &pDir))
|
|
throw Py::Exception();
|
|
|
|
if (length < Precision::Confusion()) {
|
|
throw Py::ValueError("length of box too small");
|
|
}
|
|
if (width < Precision::Confusion()) {
|
|
throw Py::ValueError("width of box too small");
|
|
}
|
|
if (height < Precision::Confusion()) {
|
|
throw Py::ValueError("height of box too small");
|
|
}
|
|
|
|
try {
|
|
gp_Pnt p(0,0,0);
|
|
gp_Dir d(0,0,1);
|
|
if (pPnt) {
|
|
Base::Vector3d pnt = static_cast<Base::VectorPy*>(pPnt)->value();
|
|
p.SetCoord(pnt.x, pnt.y, pnt.z);
|
|
}
|
|
if (pDir) {
|
|
Base::Vector3d vec = static_cast<Base::VectorPy*>(pDir)->value();
|
|
d.SetCoord(vec.x, vec.y, vec.z);
|
|
}
|
|
BRepPrimAPI_MakeBox mkBox(gp_Ax2(p,d), length, width, height);
|
|
TopoDS_Shape ResultShape = mkBox.Shape();
|
|
return Py::asObject(new TopoShapeSolidPy(new TopoShape(ResultShape)));
|
|
}
|
|
catch (Standard_DomainError&) {
|
|
throw Py::Exception(PartExceptionOCCDomainError, "creation of box failed");
|
|
}
|
|
}
|
|
Py::Object makeWedge(const Py::Tuple& args)
|
|
{
|
|
double xmin, ymin, zmin, z2min, x2min, xmax, ymax, zmax, z2max, x2max;
|
|
PyObject *pPnt=nullptr, *pDir=nullptr;
|
|
if (!PyArg_ParseTuple(args.ptr(), "dddddddddd|O!O!",
|
|
&xmin, &ymin, &zmin, &z2min, &x2min, &xmax, &ymax, &zmax, &z2max, &x2max,
|
|
&(Base::VectorPy::Type), &pPnt, &(Base::VectorPy::Type), &pDir))
|
|
throw Py::Exception();
|
|
|
|
double dx = xmax-xmin;
|
|
double dy = ymax-ymin;
|
|
double dz = zmax-zmin;
|
|
double dz2 = z2max-z2min;
|
|
double dx2 = x2max-x2min;
|
|
if (dx < Precision::Confusion()) {
|
|
throw Py::ValueError("delta x of wedge too small");
|
|
}
|
|
if (dy < Precision::Confusion()) {
|
|
throw Py::ValueError("delta y of wedge too small");
|
|
}
|
|
if (dz < Precision::Confusion()) {
|
|
throw Py::ValueError("delta z of wedge too small");
|
|
}
|
|
if (dz2 < 0) {
|
|
throw Py::ValueError("delta z2 of wedge is negative");
|
|
}
|
|
if (dx2 < 0) {
|
|
throw Py::ValueError("delta x2 of wedge is negative");
|
|
}
|
|
|
|
try {
|
|
gp_Pnt p(0,0,0);
|
|
gp_Dir d(0,0,1);
|
|
if (pPnt) {
|
|
Base::Vector3d pnt = static_cast<Base::VectorPy*>(pPnt)->value();
|
|
p.SetCoord(pnt.x, pnt.y, pnt.z);
|
|
}
|
|
if (pDir) {
|
|
Base::Vector3d vec = static_cast<Base::VectorPy*>(pDir)->value();
|
|
d.SetCoord(vec.x, vec.y, vec.z);
|
|
}
|
|
BRepPrim_Wedge mkWedge(gp_Ax2(p,d), xmin, ymin, zmin, z2min, x2min, xmax, ymax, zmax, z2max, x2max);
|
|
BRepBuilderAPI_MakeSolid mkSolid;
|
|
mkSolid.Add(mkWedge.Shell());
|
|
return Py::asObject(new TopoShapeSolidPy(new TopoShape(mkSolid.Solid())));
|
|
}
|
|
catch (Standard_DomainError&) {
|
|
throw Py::Exception(PartExceptionOCCDomainError, "creation of wedge failed");
|
|
}
|
|
}
|
|
Py::Object makeLine(const Py::Tuple& args)
|
|
{
|
|
PyObject *obj1, *obj2;
|
|
if (!PyArg_ParseTuple(args.ptr(), "OO", &obj1, &obj2))
|
|
throw Py::Exception();
|
|
|
|
Base::Vector3d pnt1, pnt2;
|
|
if (PyObject_TypeCheck(obj1, &(Base::VectorPy::Type))) {
|
|
pnt1 = static_cast<Base::VectorPy*>(obj1)->value();
|
|
}
|
|
else if (PyObject_TypeCheck(obj1, &PyTuple_Type)) {
|
|
pnt1 = Base::getVectorFromTuple<double>(obj1);
|
|
}
|
|
else {
|
|
throw Py::TypeError("first argument must either be vector or tuple");
|
|
}
|
|
if (PyObject_TypeCheck(obj2, &(Base::VectorPy::Type))) {
|
|
pnt2 = static_cast<Base::VectorPy*>(obj2)->value();
|
|
}
|
|
else if (PyObject_TypeCheck(obj2, &PyTuple_Type)) {
|
|
pnt2 = Base::getVectorFromTuple<double>(obj2);
|
|
}
|
|
else {
|
|
throw Py::TypeError("second argument must either be vector or tuple");
|
|
}
|
|
|
|
// Create directly the underlying line geometry
|
|
BRepBuilderAPI_MakeEdge makeEdge(gp_Pnt(pnt1.x, pnt1.y, pnt1.z),
|
|
gp_Pnt(pnt2.x, pnt2.y, pnt2.z));
|
|
|
|
const char *error=nullptr;
|
|
switch (makeEdge.Error())
|
|
{
|
|
case BRepBuilderAPI_EdgeDone:
|
|
break; // ok
|
|
case BRepBuilderAPI_PointProjectionFailed:
|
|
error = "Point projection failed";
|
|
break;
|
|
case BRepBuilderAPI_ParameterOutOfRange:
|
|
error = "Parameter out of range";
|
|
break;
|
|
case BRepBuilderAPI_DifferentPointsOnClosedCurve:
|
|
error = "Different points on closed curve";
|
|
break;
|
|
case BRepBuilderAPI_PointWithInfiniteParameter:
|
|
error = "Point with infinite parameter";
|
|
break;
|
|
case BRepBuilderAPI_DifferentsPointAndParameter:
|
|
error = "Different point and parameter";
|
|
break;
|
|
case BRepBuilderAPI_LineThroughIdenticPoints:
|
|
error = "Line through identical points";
|
|
break;
|
|
}
|
|
// Error
|
|
if (error) {
|
|
throw Py::Exception(PartExceptionOCCError, error);
|
|
}
|
|
|
|
TopoDS_Edge edge = makeEdge.Edge();
|
|
return Py::asObject(new TopoShapeEdgePy(new TopoShape(edge)));
|
|
}
|
|
Py::Object makePolygon(const Py::Tuple& args)
|
|
{
|
|
PyObject *pcObj;
|
|
PyObject *pclosed=Py_False;
|
|
if (!PyArg_ParseTuple(args.ptr(), "O|O!", &pcObj, &(PyBool_Type), &pclosed))
|
|
throw Py::Exception();
|
|
|
|
BRepBuilderAPI_MakePolygon mkPoly;
|
|
try {
|
|
Py::Sequence list(pcObj);
|
|
for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
|
|
if (PyObject_TypeCheck((*it).ptr(), &(Base::VectorPy::Type))) {
|
|
Base::Vector3d v = static_cast<Base::VectorPy*>((*it).ptr())->value();
|
|
mkPoly.Add(gp_Pnt(v.x,v.y,v.z));
|
|
}
|
|
else if (PyObject_TypeCheck((*it).ptr(), &PyTuple_Type)) {
|
|
Base::Vector3d v = Base::getVectorFromTuple<double>((*it).ptr());
|
|
mkPoly.Add(gp_Pnt(v.x,v.y,v.z));
|
|
}
|
|
}
|
|
|
|
if (!mkPoly.IsDone())
|
|
Standard_Failure::Raise("Cannot create polygon because less than two vertices are given");
|
|
|
|
// if the polygon should be closed
|
|
if (Base::asBoolean(pclosed)) {
|
|
if (!mkPoly.FirstVertex().IsSame(mkPoly.LastVertex())) {
|
|
mkPoly.Add(mkPoly.FirstVertex());
|
|
}
|
|
}
|
|
|
|
return Py::asObject(new TopoShapeWirePy(new TopoShape(mkPoly.Wire())));
|
|
}
|
|
catch (Standard_Failure& e) {
|
|
throw Py::Exception(PartExceptionOCCError, e.GetMessageString());
|
|
}
|
|
}
|
|
Py::Object makeCircle(const Py::Tuple& args)
|
|
{
|
|
double radius, angle1=0.0, angle2=360;
|
|
PyObject *pPnt=nullptr, *pDir=nullptr;
|
|
if (!PyArg_ParseTuple(args.ptr(), "d|O!O!dd",
|
|
&radius,
|
|
&(Base::VectorPy::Type), &pPnt,
|
|
&(Base::VectorPy::Type), &pDir,
|
|
&angle1, &angle2))
|
|
throw Py::Exception();
|
|
|
|
try {
|
|
gp_Pnt loc(0,0,0);
|
|
gp_Dir dir(0,0,1);
|
|
if (pPnt) {
|
|
Base::Vector3d pnt = static_cast<Base::VectorPy*>(pPnt)->value();
|
|
loc.SetCoord(pnt.x, pnt.y, pnt.z);
|
|
}
|
|
if (pDir) {
|
|
Base::Vector3d vec = static_cast<Base::VectorPy*>(pDir)->value();
|
|
dir.SetCoord(vec.x, vec.y, vec.z);
|
|
}
|
|
gp_Ax1 axis(loc, dir);
|
|
gp_Circ circle;
|
|
circle.SetAxis(axis);
|
|
circle.SetRadius(radius);
|
|
|
|
Handle(Geom_Circle) hCircle = new Geom_Circle (circle);
|
|
BRepBuilderAPI_MakeEdge aMakeEdge(hCircle,
|
|
Base::toRadians<double>(angle1),
|
|
Base::toRadians<double>(angle2));
|
|
TopoDS_Edge edge = aMakeEdge.Edge();
|
|
return Py::asObject(new TopoShapeEdgePy(new TopoShape(edge)));
|
|
}
|
|
catch (Standard_Failure&) {
|
|
throw Py::Exception(PartExceptionOCCError, "creation of circle failed");
|
|
}
|
|
}
|
|
Py::Object makeSphere(const Py::Tuple& args)
|
|
{
|
|
double radius, angle1=-90, angle2=90, angle3=360;
|
|
PyObject *pPnt=nullptr, *pDir=nullptr;
|
|
if (!PyArg_ParseTuple(args.ptr(), "d|O!O!ddd",
|
|
&radius,
|
|
&(Base::VectorPy::Type), &pPnt,
|
|
&(Base::VectorPy::Type), &pDir,
|
|
&angle1, &angle2, &angle3))
|
|
throw Py::Exception();
|
|
|
|
try {
|
|
gp_Pnt p(0,0,0);
|
|
gp_Dir d(0,0,1);
|
|
if (pPnt) {
|
|
Base::Vector3d pnt = static_cast<Base::VectorPy*>(pPnt)->value();
|
|
p.SetCoord(pnt.x, pnt.y, pnt.z);
|
|
}
|
|
if (pDir) {
|
|
Base::Vector3d vec = static_cast<Base::VectorPy*>(pDir)->value();
|
|
d.SetCoord(vec.x, vec.y, vec.z);
|
|
}
|
|
BRepPrimAPI_MakeSphere mkSphere(gp_Ax2(p,d), radius,
|
|
Base::toRadians<double>(angle1),
|
|
Base::toRadians<double>(angle2),
|
|
Base::toRadians<double>(angle3));
|
|
TopoDS_Shape shape = mkSphere.Shape();
|
|
return Py::asObject(new TopoShapeSolidPy(new TopoShape(shape)));
|
|
}
|
|
catch (Standard_DomainError&) {
|
|
throw Py::Exception(PartExceptionOCCDomainError, "creation of sphere failed");
|
|
}
|
|
}
|
|
Py::Object makeCylinder(const Py::Tuple& args)
|
|
{
|
|
double radius, height, angle=360;
|
|
PyObject *pPnt=nullptr, *pDir=nullptr;
|
|
if (!PyArg_ParseTuple(args.ptr(), "dd|O!O!d",
|
|
&radius, &height,
|
|
&(Base::VectorPy::Type), &pPnt,
|
|
&(Base::VectorPy::Type), &pDir,
|
|
&angle))
|
|
throw Py::Exception();
|
|
|
|
try {
|
|
gp_Pnt p(0,0,0);
|
|
gp_Dir d(0,0,1);
|
|
if (pPnt) {
|
|
Base::Vector3d pnt = static_cast<Base::VectorPy*>(pPnt)->value();
|
|
p.SetCoord(pnt.x, pnt.y, pnt.z);
|
|
}
|
|
if (pDir) {
|
|
Base::Vector3d vec = static_cast<Base::VectorPy*>(pDir)->value();
|
|
d.SetCoord(vec.x, vec.y, vec.z);
|
|
}
|
|
BRepPrimAPI_MakeCylinder mkCyl(gp_Ax2(p,d),radius, height,
|
|
Base::toRadians<double>(angle));
|
|
TopoDS_Shape shape = mkCyl.Shape();
|
|
return Py::asObject(new TopoShapeSolidPy(new TopoShape(shape)));
|
|
}
|
|
catch (Standard_DomainError&) {
|
|
throw Py::Exception(PartExceptionOCCDomainError, "creation of cylinder failed");
|
|
}
|
|
}
|
|
Py::Object makeCone(const Py::Tuple& args)
|
|
{
|
|
double radius1, radius2, height, angle=360;
|
|
PyObject *pPnt=nullptr, *pDir=nullptr;
|
|
if (!PyArg_ParseTuple(args.ptr(), "ddd|O!O!d",
|
|
&radius1, &radius2, &height,
|
|
&(Base::VectorPy::Type), &pPnt,
|
|
&(Base::VectorPy::Type), &pDir,
|
|
&angle))
|
|
throw Py::Exception();
|
|
|
|
try {
|
|
gp_Pnt p(0,0,0);
|
|
gp_Dir d(0,0,1);
|
|
if (pPnt) {
|
|
Base::Vector3d pnt = static_cast<Base::VectorPy*>(pPnt)->value();
|
|
p.SetCoord(pnt.x, pnt.y, pnt.z);
|
|
}
|
|
if (pDir) {
|
|
Base::Vector3d vec = static_cast<Base::VectorPy*>(pDir)->value();
|
|
d.SetCoord(vec.x, vec.y, vec.z);
|
|
}
|
|
BRepPrimAPI_MakeCone mkCone(gp_Ax2(p,d),radius1, radius2, height,
|
|
Base::toRadians<double>(angle));
|
|
TopoDS_Shape shape = mkCone.Shape();
|
|
return Py::asObject(new TopoShapeSolidPy(new TopoShape(shape)));
|
|
}
|
|
catch (Standard_DomainError&) {
|
|
throw Py::Exception(PartExceptionOCCDomainError, "creation of cone failed");
|
|
}
|
|
}
|
|
Py::Object makeTorus(const Py::Tuple& args)
|
|
{
|
|
double radius1, radius2, angle1=0.0, angle2=360, angle=360;
|
|
PyObject *pPnt=nullptr, *pDir=nullptr;
|
|
if (!PyArg_ParseTuple(args.ptr(), "dd|O!O!ddd",
|
|
&radius1, &radius2,
|
|
&(Base::VectorPy::Type), &pPnt,
|
|
&(Base::VectorPy::Type), &pDir,
|
|
&angle1, &angle2, &angle))
|
|
throw Py::Exception();
|
|
|
|
try {
|
|
gp_Pnt p(0,0,0);
|
|
gp_Dir d(0,0,1);
|
|
if (pPnt) {
|
|
Base::Vector3d pnt = static_cast<Base::VectorPy*>(pPnt)->value();
|
|
p.SetCoord(pnt.x, pnt.y, pnt.z);
|
|
}
|
|
if (pDir) {
|
|
Base::Vector3d vec = static_cast<Base::VectorPy*>(pDir)->value();
|
|
d.SetCoord(vec.x, vec.y, vec.z);
|
|
}
|
|
BRepPrimAPI_MakeTorus mkTorus(gp_Ax2(p,d), radius1, radius2,
|
|
Base::toRadians<double>(angle1),
|
|
Base::toRadians<double>(angle2),
|
|
Base::toRadians<double>(angle));
|
|
const TopoDS_Shape& shape = mkTorus.Shape();
|
|
return Py::asObject(new TopoShapeSolidPy(new TopoShape(shape)));
|
|
}
|
|
catch (Standard_DomainError&) {
|
|
throw Py::Exception(PartExceptionOCCDomainError, "creation of torus failed");
|
|
}
|
|
}
|
|
Py::Object makeHelix(const Py::Tuple& args)
|
|
{
|
|
double pitch, height, radius, angle=-1.0;
|
|
PyObject *pleft=Py_False;
|
|
PyObject *pvertHeight=Py_False;
|
|
if (!PyArg_ParseTuple(args.ptr(), "ddd|dO!O!",
|
|
&pitch, &height, &radius, &angle,
|
|
&(PyBool_Type), &pleft,
|
|
&(PyBool_Type), &pvertHeight))
|
|
throw Py::Exception();
|
|
|
|
try {
|
|
TopoShape helix;
|
|
Standard_Boolean anIsLeft = Base::asBoolean(pleft);
|
|
Standard_Boolean anIsVertHeight = Base::asBoolean(pvertHeight);
|
|
TopoDS_Shape wire = helix.makeHelix(pitch, height, radius, angle,
|
|
anIsLeft, anIsVertHeight);
|
|
return Py::asObject(new TopoShapeWirePy(new TopoShape(wire)));
|
|
}
|
|
catch (Standard_Failure& e) {
|
|
throw Py::Exception(PartExceptionOCCError, e.GetMessageString());
|
|
}
|
|
}
|
|
Py::Object makeLongHelix(const Py::Tuple& args)
|
|
{
|
|
double pitch, height, radius, angle=-1.0;
|
|
PyObject *pleft=Py_False;
|
|
if (!PyArg_ParseTuple(args.ptr(), "ddd|dO!", &pitch, &height, &radius, &angle,
|
|
&(PyBool_Type), &pleft)) {
|
|
throw Py::RuntimeError("Part.makeLongHelix fails on parms");
|
|
}
|
|
|
|
try {
|
|
TopoShape helix;
|
|
Standard_Boolean anIsLeft = Base::asBoolean(pleft);
|
|
TopoDS_Shape wire = helix.makeLongHelix(pitch, height, radius, angle, anIsLeft);
|
|
return Py::asObject(new TopoShapeWirePy(new TopoShape(wire)));
|
|
}
|
|
catch (Standard_Failure& e) {
|
|
throw Py::Exception(PartExceptionOCCError, e.GetMessageString());
|
|
}
|
|
}
|
|
Py::Object makeThread(const Py::Tuple& args)
|
|
{
|
|
double pitch, depth, height, radius;
|
|
if (!PyArg_ParseTuple(args.ptr(), "dddd", &pitch, &depth, &height, &radius))
|
|
throw Py::Exception();
|
|
|
|
try {
|
|
TopoShape helix;
|
|
TopoDS_Shape wire = helix.makeThread(pitch, depth, height, radius);
|
|
return Py::asObject(new TopoShapeWirePy(new TopoShape(wire)));
|
|
}
|
|
catch (Standard_Failure& e) {
|
|
throw Py::Exception(PartExceptionOCCError, e.GetMessageString());
|
|
}
|
|
}
|
|
Py::Object makeRevolution(const Py::Tuple& args)
|
|
{
|
|
constexpr double doubleMax = std::numeric_limits<double>::max();
|
|
double vmin = doubleMax, vmax=-doubleMax;
|
|
double angle=360;
|
|
PyObject *pPnt=nullptr, *pDir=nullptr, *pCrv;
|
|
Handle(Geom_Curve) curve;
|
|
PyObject* defaultType = Base::getTypeAsObject(&Part::TopoShapeSolidPy::Type);
|
|
PyObject* type = defaultType;
|
|
|
|
do {
|
|
if (PyArg_ParseTuple(args.ptr(), "O!|dddO!O!O!", &(GeometryPy::Type), &pCrv,
|
|
&vmin, &vmax, &angle,
|
|
&(Base::VectorPy::Type), &pPnt,
|
|
&(Base::VectorPy::Type), &pDir,
|
|
&(PyType_Type), &type)) {
|
|
GeometryPy* pcGeo = static_cast<GeometryPy*>(pCrv);
|
|
curve = Handle(Geom_Curve)::DownCast
|
|
(pcGeo->getGeometryPtr()->handle());
|
|
if (curve.IsNull()) {
|
|
throw Py::Exception(PyExc_TypeError, "geometry is not a curve");
|
|
}
|
|
if (vmin == doubleMax)
|
|
vmin = curve->FirstParameter();
|
|
|
|
if (vmax == -doubleMax)
|
|
vmax = curve->LastParameter();
|
|
break;
|
|
}
|
|
|
|
PyErr_Clear();
|
|
if (PyArg_ParseTuple(args.ptr(), "O!|dddO!O!O!", &(TopoShapePy::Type), &pCrv,
|
|
&vmin, &vmax, &angle,
|
|
&(Base::VectorPy::Type), &pPnt,
|
|
&(Base::VectorPy::Type), &pDir,
|
|
&(PyType_Type), &type)) {
|
|
const TopoDS_Shape& shape = static_cast<TopoShapePy*>(pCrv)->getTopoShapePtr()->getShape();
|
|
if (shape.IsNull()) {
|
|
throw Py::Exception(PartExceptionOCCError, "shape is empty");
|
|
}
|
|
|
|
if (shape.ShapeType() != TopAbs_EDGE) {
|
|
throw Py::Exception(PartExceptionOCCError, "shape is not an edge");
|
|
}
|
|
|
|
const TopoDS_Edge& edge = TopoDS::Edge(shape);
|
|
BRepAdaptor_Curve adapt(edge);
|
|
|
|
const Handle(Geom_Curve)& hCurve = adapt.Curve().Curve();
|
|
// Apply placement of the shape to the curve
|
|
TopLoc_Location loc = edge.Location();
|
|
curve = Handle(Geom_Curve)::DownCast(hCurve->Transformed(loc.Transformation()));
|
|
if (curve.IsNull()) {
|
|
throw Py::Exception(PartExceptionOCCError, "invalid curve in edge");
|
|
}
|
|
|
|
if (vmin == doubleMax)
|
|
vmin = adapt.FirstParameter();
|
|
if (vmax == -doubleMax)
|
|
vmax = adapt.LastParameter();
|
|
break;
|
|
}
|
|
|
|
// invalid arguments
|
|
throw Py::TypeError("Expected arguments are:\n"
|
|
"Curve or Edge, [float, float, float, Vector, Vector, ShapeType]");
|
|
}
|
|
while(false);
|
|
|
|
try {
|
|
gp_Pnt p(0,0,0);
|
|
gp_Dir d(0,0,1);
|
|
if (pPnt) {
|
|
Base::Vector3d pnt = static_cast<Base::VectorPy*>(pPnt)->value();
|
|
p.SetCoord(pnt.x, pnt.y, pnt.z);
|
|
}
|
|
if (pDir) {
|
|
Base::Vector3d vec = static_cast<Base::VectorPy*>(pDir)->value();
|
|
d.SetCoord(vec.x, vec.y, vec.z);
|
|
}
|
|
|
|
PyObject* shellType = Base::getTypeAsObject(&Part::TopoShapeShellPy::Type);
|
|
PyObject* faceType = Base::getTypeAsObject(&Part::TopoShapeFacePy::Type);
|
|
|
|
BRepPrimAPI_MakeRevolution mkRev(gp_Ax2(p,d),curve, vmin, vmax,
|
|
Base::toRadians<double>(angle));
|
|
if (type == defaultType) {
|
|
TopoDS_Shape shape = mkRev.Solid();
|
|
return Py::asObject(new TopoShapeSolidPy(new TopoShape(shape)));
|
|
}
|
|
else if (type == shellType) {
|
|
TopoDS_Shape shape = mkRev.Shell();
|
|
return Py::asObject(new TopoShapeShellPy(new TopoShape(shape)));
|
|
}
|
|
else if (type == faceType) {
|
|
TopoDS_Shape shape = mkRev.Face();
|
|
return Py::asObject(new TopoShapeFacePy(new TopoShape(shape)));
|
|
}
|
|
else {
|
|
TopoDS_Shape shape = mkRev.Shape();
|
|
return Py::asObject(new TopoShapePy(new TopoShape(shape)));
|
|
}
|
|
}
|
|
catch (Standard_DomainError&) {
|
|
throw Py::Exception(PartExceptionOCCDomainError, "creation of revolved shape failed");
|
|
}
|
|
}
|
|
|
|
Py::Object makeRuledSurface(const Py::Tuple& args, const Py::Dict &kwds)
|
|
{
|
|
const char* op = nullptr;
|
|
int orientation = 0;
|
|
PyObject *sh1, *sh2;
|
|
const std::array<const char*, 5> kwd_list = {"path",
|
|
"profile",
|
|
"orientation",
|
|
"op",
|
|
nullptr};
|
|
if (!Base::Wrapped_ParseTupleAndKeywords(args.ptr(),
|
|
kwds.ptr(),
|
|
"O!O!|is",
|
|
kwd_list,
|
|
&(TopoShapePy::Type),
|
|
&sh1,
|
|
&(TopoShapePy::Type),
|
|
&sh2,
|
|
&orientation,
|
|
&op)) {
|
|
throw Py::Exception();
|
|
}
|
|
|
|
std::vector<TopoShape> shapes;
|
|
shapes.push_back(*static_cast<TopoShapePy*>(sh1)->getTopoShapePtr());
|
|
shapes.push_back(*static_cast<TopoShapePy*>(sh2)->getTopoShapePtr());
|
|
return shape2pyshape(TopoShape().makeElementRuledSurface(shapes, orientation, op));
|
|
}
|
|
|
|
Py::Object makeShellFromWires(const Py::Tuple& args, const Py::Dict &kwds)
|
|
{
|
|
PyObject *pylist;
|
|
const char* op = nullptr;
|
|
const std::array<const char*, 3> kwd_list = {"shape", "op", nullptr};
|
|
if (!Base::Wrapped_ParseTupleAndKeywords(args.ptr(),
|
|
kwds.ptr(),
|
|
"O|s",
|
|
kwd_list,
|
|
&pylist,
|
|
&op)) {
|
|
throw Py::Exception();
|
|
}
|
|
try {
|
|
return shape2pyshape(
|
|
TopoShape().makeElementShellFromWires(getPyShapes(pylist), /*silent*/ false, op));
|
|
}
|
|
catch (Standard_Failure&) {
|
|
throw Py::Exception(PartExceptionOCCError, "creation of shell failed");
|
|
}
|
|
}
|
|
|
|
Py::Object makeTube(const Py::Tuple& args)
|
|
{
|
|
PyObject *pshape;
|
|
double radius;
|
|
double tolerance=0.001;
|
|
const char* scont = "C0";
|
|
int maxdegree = 3;
|
|
int maxsegment = 30;
|
|
|
|
// Path + radius
|
|
if (!PyArg_ParseTuple(args.ptr(), "O!d|sii", &(TopoShapePy::Type), &pshape, &radius, &scont, &maxdegree, &maxsegment))
|
|
throw Py::Exception();
|
|
|
|
std::string str_cont = scont;
|
|
int cont;
|
|
if (str_cont == "C0")
|
|
cont = (int)GeomAbs_C0;
|
|
else if (str_cont == "C1")
|
|
cont = (int)GeomAbs_C1;
|
|
else if (str_cont == "C2")
|
|
cont = (int)GeomAbs_C2;
|
|
else if (str_cont == "C3")
|
|
cont = (int)GeomAbs_C3;
|
|
else if (str_cont == "CN")
|
|
cont = (int)GeomAbs_CN;
|
|
else if (str_cont == "G1")
|
|
cont = (int)GeomAbs_G1;
|
|
else if (str_cont == "G2")
|
|
cont = (int)GeomAbs_G2;
|
|
else
|
|
cont = (int)GeomAbs_C0;
|
|
|
|
try {
|
|
const TopoDS_Shape& path_shape = static_cast<TopoShapePy*>(pshape)->getTopoShapePtr()->getShape();
|
|
TopoShape myShape(path_shape);
|
|
TopoDS_Shape face = myShape.makeTube(radius, tolerance, cont, maxdegree, maxsegment);
|
|
return Py::asObject(new TopoShapeFacePy(new TopoShape(face)));
|
|
}
|
|
catch (Standard_Failure& e) {
|
|
throw Py::Exception(PartExceptionOCCError, e.GetMessageString());
|
|
}
|
|
}
|
|
Py::Object makeSweepSurface(const Py::Tuple& args)
|
|
{
|
|
PyObject *path, *profile;
|
|
double tolerance=0.001;
|
|
int fillMode = 0;
|
|
|
|
// Path + profile
|
|
if (!PyArg_ParseTuple(args.ptr(), "O!O!|di", &(TopoShapePy::Type), &path,
|
|
&(TopoShapePy::Type), &profile,
|
|
&tolerance, &fillMode))
|
|
throw Py::Exception();
|
|
|
|
try {
|
|
TopoShape mShape = *static_cast<TopoShapePy*>(path)->getTopoShapePtr();
|
|
// makeSweep uses GeomFill_Pipe which does not support shape
|
|
// history. So use makEPipeShell() as a replacement
|
|
return shape2pyshape(
|
|
TopoShape(0, mShape.Hasher)
|
|
.makeElementPipeShell(
|
|
{mShape, *static_cast<TopoShapePy*>(profile)->getTopoShapePtr()},
|
|
Part::MakeSolid::noSolid,
|
|
Standard_False,
|
|
TransitionMode::Transformed,
|
|
nullptr,
|
|
tolerance));
|
|
}
|
|
catch (Standard_Failure& e) {
|
|
throw Py::Exception(PartExceptionOCCError, e.GetMessageString());
|
|
}
|
|
}
|
|
|
|
Py::Object makeLoft(const Py::Tuple& args, const Py::Dict &kwds)
|
|
{
|
|
PyObject *pcObj;
|
|
PyObject *psolid=Py_False;
|
|
PyObject *pruled=Py_False;
|
|
PyObject *pclosed=Py_False;
|
|
int degMax = 5;
|
|
|
|
const char* op = nullptr;
|
|
const std::array<const char*, 7> kwd_list =
|
|
{"shapes", "solid", "ruled", "closed", "max_degree", "op", nullptr};
|
|
if (!Base::Wrapped_ParseTupleAndKeywords(args.ptr(),
|
|
kwds.ptr(),
|
|
"O!|O!O!O!is",
|
|
kwd_list,
|
|
&(PyList_Type),
|
|
&pcObj,
|
|
&(PyBool_Type),
|
|
&psolid,
|
|
&(PyBool_Type),
|
|
&pruled,
|
|
&(PyBool_Type),
|
|
&pclosed,
|
|
°Max,
|
|
&op)) {
|
|
throw Py::Exception();
|
|
}
|
|
Standard_Boolean anIsSolid = PyObject_IsTrue(psolid) ? Standard_True : Standard_False;
|
|
Standard_Boolean anIsRuled = PyObject_IsTrue(pruled) ? Standard_True : Standard_False;
|
|
Standard_Boolean anIsClosed = PyObject_IsTrue(pclosed) ? Standard_True : Standard_False;
|
|
return shape2pyshape(TopoShape().makeElementLoft(
|
|
getPyShapes(pcObj),
|
|
anIsSolid ? Part::IsSolid::solid : Part::IsSolid::notSolid,
|
|
anIsRuled ? Part::IsRuled::ruled : Part::IsRuled::notRuled,
|
|
anIsClosed ? Part::IsClosed::closed : Part::IsClosed::notClosed,
|
|
degMax,
|
|
op));
|
|
}
|
|
|
|
Py::Object makeSplitShape(const Py::Tuple& args)
|
|
{
|
|
PyObject* shape;
|
|
PyObject* list;
|
|
PyObject* checkInterior = Py_True;
|
|
if (!PyArg_ParseTuple(args.ptr(), "O!O|O!", &(TopoShapePy::Type), &shape, &list,
|
|
&PyBool_Type, &checkInterior))
|
|
throw Py::Exception();
|
|
|
|
try {
|
|
std::vector<TopoShape> sources;
|
|
sources.push_back(*static_cast<TopoShapePy*>(shape)->getTopoShapePtr());
|
|
TopoDS_Shape initShape = static_cast<TopoShapePy*>
|
|
(shape)->getTopoShapePtr()->getShape();
|
|
BRepFeat_SplitShape splitShape(initShape);
|
|
splitShape.SetCheckInterior(Base::asBoolean(checkInterior));
|
|
|
|
Py::Sequence seq(list);
|
|
for (Py::Sequence::iterator it = seq.begin(); it != seq.end(); ++it) {
|
|
Py::Tuple tuple(*it);
|
|
Py::TopoShape sh1(tuple[0]);
|
|
Py::TopoShape sh2(tuple[1]);
|
|
sources.push_back(*sh1.extensionObject()->getTopoShapePtr());
|
|
const TopoDS_Shape& shape1= sh1.extensionObject()->getTopoShapePtr()->getShape();
|
|
const TopoDS_Shape& shape2= sh2.extensionObject()->getTopoShapePtr()->getShape();
|
|
if (shape1.IsNull() || shape2.IsNull())
|
|
throw Py::RuntimeError("Cannot add null shape");
|
|
if (shape2.ShapeType() == TopAbs_FACE) {
|
|
if (shape1.ShapeType() == TopAbs_EDGE) {
|
|
splitShape.Add(TopoDS::Edge(shape1), TopoDS::Face(shape2));
|
|
}
|
|
else if (shape1.ShapeType() == TopAbs_WIRE) {
|
|
splitShape.Add(TopoDS::Wire(shape1), TopoDS::Face(shape2));
|
|
}
|
|
else if (shape1.ShapeType() == TopAbs_COMPOUND) {
|
|
splitShape.Add(TopoDS::Compound(shape1), TopoDS::Face(shape2));
|
|
}
|
|
else {
|
|
throw Py::TypeError("First item in tuple must be Edge, Wire or Compound");
|
|
}
|
|
}
|
|
else if (shape2.ShapeType() == TopAbs_EDGE) {
|
|
if (shape1.ShapeType() == TopAbs_EDGE) {
|
|
splitShape.Add(TopoDS::Edge(shape1), TopoDS::Edge(shape2));
|
|
}
|
|
else {
|
|
throw Py::TypeError("First item in tuple must be Edge");
|
|
}
|
|
}
|
|
else {
|
|
throw Py::TypeError("Second item in tuple must be Face or Edge");
|
|
}
|
|
}
|
|
|
|
splitShape.Build();
|
|
const TopTools_ListOfShape& d = splitShape.DirectLeft();
|
|
const TopTools_ListOfShape& l = splitShape.Left();
|
|
|
|
Py::List list1;
|
|
Py::List list2;
|
|
MapperMaker mapper(splitShape);
|
|
for (TopTools_ListIteratorOfListOfShape it(d); it.More(); it.Next()) {
|
|
TopoShape s(0, sources.front().Hasher);
|
|
list1.append(shape2pyshape(
|
|
s.makeShapeWithElementMap(it.Value(), mapper, sources, Part::OpCodes::Split)));
|
|
}
|
|
for (TopTools_ListIteratorOfListOfShape it(l); it.More(); it.Next()) {
|
|
TopoShape s(0, sources.front().Hasher);
|
|
list2.append(shape2pyshape(
|
|
s.makeShapeWithElementMap(it.Value(), mapper, sources, Part::OpCodes::Split)));
|
|
}
|
|
Py::Tuple tuple(2);
|
|
tuple.setItem(0, list1);
|
|
tuple.setItem(1, list2);
|
|
return tuple;
|
|
}
|
|
catch (Standard_Failure& e) {
|
|
throw Py::Exception(PartExceptionOCCError, e.GetMessageString());
|
|
}
|
|
}
|
|
Py::Object makeWireString(const Py::Tuple& args)
|
|
{
|
|
#ifdef FCUseFreeType
|
|
PyObject *intext;
|
|
const char* dir;
|
|
const char* fontfile;
|
|
const char* fontspec;
|
|
bool useFontSpec = false;
|
|
double height;
|
|
double track = 0;
|
|
|
|
Py_UCS4 *unichars = nullptr;
|
|
Py_ssize_t pysize;
|
|
|
|
PyObject *CharList;
|
|
|
|
if (PyArg_ParseTuple(args.ptr(), "Ossd|d", &intext, // compatibility with old version
|
|
&dir,
|
|
&fontfile,
|
|
&height,
|
|
&track)) {
|
|
useFontSpec = false;
|
|
}
|
|
else {
|
|
PyErr_Clear();
|
|
if (PyArg_ParseTuple(args.ptr(), "Osd|d", &intext,
|
|
&fontspec,
|
|
&height,
|
|
&track)) {
|
|
useFontSpec = true;
|
|
}
|
|
else {
|
|
throw Py::TypeError("** makeWireString bad args.");
|
|
}
|
|
}
|
|
|
|
//FIXME: Test this!
|
|
if (PyBytes_Check(intext)) {
|
|
PyObject *p = Base::PyAsUnicodeObject(PyBytes_AsString(intext));
|
|
if (!p) {
|
|
throw Py::TypeError("** makeWireString can't convert PyString.");
|
|
}
|
|
|
|
pysize = PyUnicode_GetLength(p);
|
|
unichars = PyUnicode_AsUCS4Copy(p);
|
|
}
|
|
else if (PyUnicode_Check(intext)) {
|
|
pysize = PyUnicode_GetLength(intext);
|
|
unichars = PyUnicode_AsUCS4Copy(intext);
|
|
}
|
|
else {
|
|
throw Py::TypeError("** makeWireString bad text parameter");
|
|
}
|
|
|
|
try {
|
|
if (useFontSpec) {
|
|
CharList = FT2FC(unichars,pysize,fontspec,height,track);
|
|
}
|
|
else {
|
|
CharList = FT2FC(unichars,pysize,dir,fontfile,height,track);
|
|
}
|
|
if (unichars) {
|
|
PyMem_Free(unichars);
|
|
}
|
|
}
|
|
catch (Standard_DomainError&) { // Standard_DomainError is OCC error.
|
|
throw Py::Exception(PartExceptionOCCDomainError, "makeWireString failed - Standard_DomainError");
|
|
}
|
|
catch (std::runtime_error& e) { // FT2 or FT2FC errors
|
|
throw Py::Exception(PartExceptionOCCError, e.what());
|
|
}
|
|
|
|
return Py::asObject(CharList);
|
|
#else
|
|
throw Py::RuntimeError("FreeCAD compiled without FreeType support! This method is disabled...");
|
|
#endif
|
|
}
|
|
Py::Object exportUnits(const Py::Tuple& args)
|
|
{
|
|
char* unit=nullptr;
|
|
if (!PyArg_ParseTuple(args.ptr(), "|s", &unit))
|
|
throw Py::Exception();
|
|
|
|
if (unit) {
|
|
if (!Interface::writeIgesUnit(unit)) {
|
|
throw Py::RuntimeError("Failed to set 'write.iges.unit'");
|
|
}
|
|
if (!Interface::writeStepUnit(unit)) {
|
|
throw Py::RuntimeError("Failed to set 'write.step.unit'");
|
|
}
|
|
}
|
|
|
|
Py::Dict dict;
|
|
dict.setItem("write.iges.unit", Py::String(Interface::writeIgesUnit()));
|
|
dict.setItem("write.step.unit", Py::String(Interface::writeStepUnit()));
|
|
return dict;
|
|
}
|
|
Py::Object setStaticValue(const Py::Tuple& args)
|
|
{
|
|
char *name, *cval;
|
|
if (PyArg_ParseTuple(args.ptr(), "ss", &name, &cval)) {
|
|
if (!Interface_Static::SetCVal(name, cval)) {
|
|
std::stringstream str;
|
|
str << "Failed to set '" << name << "'";
|
|
throw Py::RuntimeError(str.str());
|
|
}
|
|
return Py::None();
|
|
}
|
|
|
|
PyErr_Clear();
|
|
PyObject* index_or_value;
|
|
if (PyArg_ParseTuple(args.ptr(), "sO", &name, &index_or_value)) {
|
|
if (PyLong_Check(index_or_value)) {
|
|
int ival = (int)PyLong_AsLong(index_or_value);
|
|
if (!Interface_Static::SetIVal(name, ival)) {
|
|
std::stringstream str;
|
|
str << "Failed to set '" << name << "'";
|
|
throw Py::RuntimeError(str.str());
|
|
}
|
|
return Py::None();
|
|
}
|
|
else if (PyFloat_Check(index_or_value)) {
|
|
double rval = PyFloat_AsDouble(index_or_value);
|
|
if (!Interface_Static::SetRVal(name, rval)) {
|
|
std::stringstream str;
|
|
str << "Failed to set '" << name << "'";
|
|
throw Py::RuntimeError(str.str());
|
|
}
|
|
return Py::None();
|
|
}
|
|
}
|
|
|
|
throw Py::TypeError("First argument must be string and must be either string, int or float");
|
|
}
|
|
Py::Object cast_to_shape(const Py::Tuple& args)
|
|
{
|
|
PyObject *object;
|
|
if (PyArg_ParseTuple(args.ptr(),"O!",&(Part::TopoShapePy::Type), &object)) {
|
|
TopoShape* ptr = static_cast<TopoShapePy*>(object)->getTopoShapePtr();
|
|
return Py::asObject(ptr->getPyObject());
|
|
}
|
|
|
|
throw Py::Exception();
|
|
}
|
|
Py::Object getSortedClusters(const Py::Tuple& args)
|
|
{
|
|
PyObject *obj;
|
|
if (!PyArg_ParseTuple(args.ptr(), "O", &obj)) {
|
|
throw Py::Exception(PartExceptionOCCError, "list of edges expected");
|
|
}
|
|
|
|
Py::Sequence list(obj);
|
|
std::vector<TopoDS_Edge> edges;
|
|
for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
|
|
PyObject* item = (*it).ptr();
|
|
if (PyObject_TypeCheck(item, &(Part::TopoShapePy::Type))) {
|
|
const TopoDS_Shape& sh = static_cast<Part::TopoShapePy*>(item)->getTopoShapePtr()->getShape();
|
|
if (sh.ShapeType() == TopAbs_EDGE)
|
|
edges.push_back(TopoDS::Edge(sh));
|
|
else {
|
|
throw Py::TypeError("shape is not an edge");
|
|
}
|
|
}
|
|
else {
|
|
throw Py::TypeError("item is not a shape");
|
|
}
|
|
}
|
|
|
|
Edgecluster acluster(edges);
|
|
tEdgeClusterVector aclusteroutput = acluster.GetClusters();
|
|
|
|
Py::List root_list;
|
|
for (const auto & it : aclusteroutput) {
|
|
Py::List add_list;
|
|
for (const auto& it1 : it) {
|
|
add_list.append(Py::Object(new TopoShapeEdgePy(new TopoShape(it1)),true));
|
|
}
|
|
root_list.append(add_list);
|
|
}
|
|
|
|
return root_list;
|
|
}
|
|
Py::Object sortEdges(const Py::Tuple& args)
|
|
{
|
|
PyObject *obj;
|
|
if (!PyArg_ParseTuple(args.ptr(), "O", &obj)) {
|
|
throw Py::TypeError("list of edges expected");
|
|
}
|
|
|
|
Py::Sequence list(obj);
|
|
std::list<TopoDS_Edge> edges;
|
|
for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
|
|
PyObject* item = (*it).ptr();
|
|
if (PyObject_TypeCheck(item, &(Part::TopoShapePy::Type))) {
|
|
const TopoDS_Shape& sh = static_cast<Part::TopoShapePy*>(item)->getTopoShapePtr()->getShape();
|
|
if (sh.ShapeType() == TopAbs_EDGE)
|
|
edges.push_back(TopoDS::Edge(sh));
|
|
else {
|
|
throw Py::TypeError("shape is not an edge");
|
|
}
|
|
}
|
|
else {
|
|
throw Py::TypeError("item is not a shape");
|
|
}
|
|
}
|
|
|
|
std::list<TopoDS_Edge> sorted = sort_Edges(Precision::Confusion(), edges);
|
|
Py::List sorted_list;
|
|
for (const auto & it : sorted) {
|
|
sorted_list.append(Py::Object(new TopoShapeEdgePy(new TopoShape(it)),true));
|
|
}
|
|
|
|
return sorted_list;
|
|
}
|
|
Py::Object sortEdges2(const Py::Tuple& args)
|
|
{
|
|
PyObject *obj;
|
|
double tol3d = Precision::Confusion();
|
|
if (!PyArg_ParseTuple(args.ptr(), "O|d", &obj, &tol3d)) {
|
|
throw Py::Exception(PartExceptionOCCError, "list of edges expected");
|
|
}
|
|
|
|
Py::Sequence list(obj);
|
|
std::list<TopoDS_Edge> edges;
|
|
for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
|
|
PyObject* item = (*it).ptr();
|
|
if (PyObject_TypeCheck(item, &(Part::TopoShapePy::Type))) {
|
|
const TopoDS_Shape& sh = static_cast<Part::TopoShapePy*>(item)->getTopoShapePtr()->getShape();
|
|
if (sh.ShapeType() == TopAbs_EDGE)
|
|
edges.push_back(TopoDS::Edge(sh));
|
|
else {
|
|
throw Py::TypeError("shape is not an edge");
|
|
}
|
|
}
|
|
else {
|
|
throw Py::TypeError("item is not a shape");
|
|
}
|
|
}
|
|
|
|
Py::List root_list;
|
|
while(!edges.empty()) {
|
|
std::list<TopoDS_Edge> sorted = sort_Edges(tol3d, edges);
|
|
Py::List sorted_list;
|
|
for (const auto & it : sorted) {
|
|
sorted_list.append(Py::Object(new TopoShapeEdgePy(new TopoShape(it)),true));
|
|
}
|
|
root_list.append(sorted_list);
|
|
}
|
|
return root_list;
|
|
}
|
|
Py::Object toPythonOCC(const Py::Tuple& args)
|
|
{
|
|
PyObject *pcObj;
|
|
if (!PyArg_ParseTuple(args.ptr(), "O!", &(TopoShapePy::Type), &pcObj))
|
|
throw Py::Exception();
|
|
|
|
try {
|
|
TopoDS_Shape* shape = new TopoDS_Shape();
|
|
(*shape) = static_cast<TopoShapePy*>(pcObj)->getTopoShapePtr()->getShape();
|
|
PyObject* proxy = nullptr;
|
|
proxy = Base::Interpreter().createSWIGPointerObj("OCC.TopoDS", "TopoDS_Shape *", static_cast<void*>(shape), 1);
|
|
return Py::asObject(proxy);
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
throw Py::Exception(PartExceptionOCCError, e.what());
|
|
}
|
|
}
|
|
Py::Object fromPythonOCC(const Py::Tuple& args)
|
|
{
|
|
PyObject *proxy;
|
|
if (!PyArg_ParseTuple(args.ptr(), "O", &proxy))
|
|
throw Py::Exception();
|
|
|
|
void* ptr;
|
|
try {
|
|
TopoShape* shape = new TopoShape();
|
|
Base::Interpreter().convertSWIGPointerObj("OCC.TopoDS","TopoDS_Shape *", proxy, &ptr, 0);
|
|
if (!ptr) {
|
|
throw Py::RuntimeError("Conversion of OCC.TopoDS.TopoDS_Shape failed");
|
|
}
|
|
TopoDS_Shape* s = static_cast<TopoDS_Shape*>(ptr);
|
|
shape->setShape(*s);
|
|
return Py::asObject(new TopoShapePy(shape));
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
throw Py::Exception(PartExceptionOCCError, e.what());
|
|
}
|
|
}
|
|
|
|
Py::Object getShape(const Py::Tuple& args, const Py::Dict &kwds) {
|
|
PyObject *pObj;
|
|
const char *subname = nullptr;
|
|
PyObject *pyMat = nullptr;
|
|
PyObject *needSubElement = Py_False;
|
|
PyObject *transform = Py_True;
|
|
PyObject *noElementMap = Py_False;
|
|
PyObject *refine = Py_False;
|
|
short retType = 0;
|
|
static const std::array<const char *, 9> kwd_list{"obj", "subname", "mat",
|
|
"needSubElement", "transform", "retType", "noElementMap",
|
|
"refine", nullptr};
|
|
if (!Base::Wrapped_ParseTupleAndKeywords(args.ptr(), kwds.ptr(), "O!|sO!O!O!hO!O!", kwd_list,
|
|
&App::DocumentObjectPy::Type, &pObj, &subname,
|
|
&Base::MatrixPy::Type, &pyMat,
|
|
&PyBool_Type, &needSubElement,
|
|
&PyBool_Type, &transform, &retType,
|
|
&PyBool_Type, &noElementMap,
|
|
&PyBool_Type, &refine)) {
|
|
throw Py::Exception();
|
|
}
|
|
|
|
App::DocumentObject *obj =
|
|
static_cast<App::DocumentObjectPy*>(pObj)->getDocumentObjectPtr();
|
|
App::DocumentObject *subObj = nullptr;
|
|
Base::Matrix4D mat;
|
|
if(pyMat)
|
|
mat = *static_cast<Base::MatrixPy*>(pyMat)->getMatrixPtr();
|
|
auto shape = Feature::getTopoShape(obj,subname,Base::asBoolean(needSubElement),
|
|
&mat,&subObj,retType==2,Base::asBoolean(transform),
|
|
Base::asBoolean(noElementMap));
|
|
if (Base::asBoolean(refine)) {
|
|
shape = TopoShape(0, shape.Hasher).makeElementRefine(shape);
|
|
}
|
|
Py::Object sret(shape2pyshape(shape));
|
|
if(retType==0)
|
|
return sret;
|
|
|
|
return Py::TupleN(sret,Py::asObject(new Base::MatrixPy(new Base::Matrix4D(mat))),
|
|
subObj?Py::Object(subObj->getPyObject(),true):Py::Object());
|
|
}
|
|
|
|
Py::Object clearShapeCache(const Py::Tuple &args) {
|
|
if (!PyArg_ParseTuple(args.ptr(),""))
|
|
throw Py::Exception();
|
|
Part::Feature::clearShapeCache();
|
|
return Py::Object();
|
|
}
|
|
|
|
Py::Object splitSubname(const Py::Tuple& args) {
|
|
const char *subname;
|
|
if (!PyArg_ParseTuple(args.ptr(), "s",&subname))
|
|
throw Py::Exception();
|
|
auto element = Data::findElementName(subname);
|
|
std::string sub(subname,element-subname);
|
|
Py::List list;
|
|
list.append(Py::String(sub));
|
|
const char *dot = strchr(element,'.');
|
|
if(!dot)
|
|
dot = element+strlen(element);
|
|
const char *mapped = Data::isMappedElement(element);
|
|
if(mapped)
|
|
list.append(Py::String(std::string(mapped,dot-mapped)));
|
|
else
|
|
list.append(Py::String());
|
|
if(*dot=='.')
|
|
list.append(Py::String(dot+1));
|
|
else if(!mapped)
|
|
list.append(Py::String(element));
|
|
else
|
|
list.append(Py::String());
|
|
return list;
|
|
}
|
|
|
|
Py::Object joinSubname(const Py::Tuple& args) {
|
|
const char *sub;
|
|
const char *mapped;
|
|
const char *element;
|
|
if (!PyArg_ParseTuple(args.ptr(), "sss",&sub,&mapped,&element))
|
|
throw Py::Exception();
|
|
std::string subname(sub);
|
|
if (!subname.empty() && subname[subname.size()-1]!='.')
|
|
subname += '.';
|
|
if (!Base::Tools::isNullOrEmpty(mapped)) {
|
|
if (!Data::isMappedElement(mapped))
|
|
subname += Data::ELEMENT_MAP_PREFIX;
|
|
subname += mapped;
|
|
}
|
|
if (!Base::Tools::isNullOrEmpty(element)) {
|
|
if (!subname.empty() && subname[subname.size()-1]!='.')
|
|
subname += '.';
|
|
subname += element;
|
|
}
|
|
return Py::String(subname);
|
|
}
|
|
};
|
|
|
|
PyObject* initModule()
|
|
{
|
|
return Base::Interpreter().addModule(new Module);
|
|
}
|
|
|
|
} // namespace Part
|