1188 lines
39 KiB
C++
1188 lines
39 KiB
C++
/***************************************************************************
|
|
* Copyright (c) 2008 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 <limits>
|
|
|
|
#include <BRep_Builder.hxx>
|
|
#include <BRep_Tool.hxx>
|
|
#include <BRepAdaptor_Curve.hxx>
|
|
#include <BRepBuilderAPI_MakeEdge.hxx>
|
|
#include <BRepBuilderAPI_MakeWire.hxx>
|
|
#include <BRepGProp.hxx>
|
|
#include <BRepLProp_CLProps.hxx>
|
|
#include <BRepLProp_CurveTool.hxx>
|
|
#include <GProp_GProps.hxx>
|
|
#include <GProp_PrincipalProps.hxx>
|
|
#include <Geom_Circle.hxx>
|
|
#include <Geom_Curve.hxx>
|
|
#include <Geom_Ellipse.hxx>
|
|
#include <Geom_Hyperbola.hxx>
|
|
#include <Geom_Parabola.hxx>
|
|
#include <Geom_Line.hxx>
|
|
#include <Geom_OffsetCurve.hxx>
|
|
#include <Geom_Surface.hxx>
|
|
#include <Geom2d_Curve.hxx>
|
|
#include <TopLoc_Location.hxx>
|
|
#include <Poly_Polygon3D.hxx>
|
|
#include <Poly_Triangulation.hxx>
|
|
#include <Poly_PolygonOnTriangulation.hxx>
|
|
#include <TColStd_Array1OfReal.hxx>
|
|
#include <TopExp.hxx>
|
|
#include <TopoDS.hxx>
|
|
#include <TopoDS_Edge.hxx>
|
|
#include <TopoDS_Shape.hxx>
|
|
#include <TopoDS_Vertex.hxx>
|
|
#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
|
|
#include <ShapeAnalysis_Edge.hxx>
|
|
#include <Standard_Failure.hxx>
|
|
#include <Standard_Version.hxx>
|
|
#include <GProp_GProps.hxx>
|
|
#include <GCPnts_AbscissaPoint.hxx>
|
|
#include <GCPnts_QuasiUniformAbscissa.hxx>
|
|
#include <GCPnts_QuasiUniformDeflection.hxx>
|
|
#include <GCPnts_TangentialDeflection.hxx>
|
|
#include <GCPnts_UniformAbscissa.hxx>
|
|
#include <GCPnts_UniformDeflection.hxx>
|
|
|
|
#include <Base/GeometryPyCXX.h>
|
|
#include <Base/PyWrapParseTupleAndKeywords.h>
|
|
#include <Base/Vector3D.h>
|
|
#include <Base/VectorPy.h>
|
|
|
|
#include <Mod/Part/App/BezierCurvePy.h>
|
|
#include <Mod/Part/App/BSplineCurvePy.h>
|
|
#include <Mod/Part/App/CirclePy.h>
|
|
#include <Mod/Part/App/EllipsePy.h>
|
|
#include <Mod/Part/App/GeometryPy.h>
|
|
#include <Mod/Part/App/HyperbolaPy.h>
|
|
#include <Mod/Part/App/LinePy.h>
|
|
#include <Mod/Part/App/OffsetCurvePy.h>
|
|
#include <Mod/Part/App/ParabolaPy.h>
|
|
#include <Mod/Part/App/TopoShapeEdgePy.h>
|
|
#include <Mod/Part/App/TopoShapeEdgePy.cpp>
|
|
#include <Mod/Part/App/TopoShapeFacePy.h>
|
|
#include <Mod/Part/App/TopoShapeVertexPy.h>
|
|
#include <Mod/Part/App/TopoShapeWirePy.h>
|
|
|
|
#include "Geometry2d.h"
|
|
#include "OCCError.h"
|
|
#include "Tools.h"
|
|
|
|
|
|
using namespace Part;
|
|
|
|
namespace
|
|
{
|
|
const TopoDS_Edge& getTopoDSEdge(const TopoShapeEdgePy* theEdge)
|
|
{
|
|
const TopoDS_Edge& e = TopoDS::Edge(theEdge->getTopoShapePtr()->getShape());
|
|
if (e.IsNull()) {
|
|
throw Py::ValueError("Edge is null");
|
|
}
|
|
return e;
|
|
}
|
|
} // namespace
|
|
|
|
// returns a string which represents the object e.g. when printed in python
|
|
std::string TopoShapeEdgePy::representation() const
|
|
{
|
|
std::stringstream str;
|
|
str << "<Edge object at " << getTopoShapePtr() << ">";
|
|
|
|
return str.str();
|
|
}
|
|
|
|
PyObject* TopoShapeEdgePy::PyMake(struct _typeobject*, PyObject*, PyObject*) // Python wrapper
|
|
{
|
|
// create a new instance of TopoShapeEdgePy and the Twin object
|
|
return new TopoShapeEdgePy(new TopoShape);
|
|
}
|
|
|
|
// constructor method
|
|
int TopoShapeEdgePy::PyInit(PyObject* args, PyObject* /*kwd*/)
|
|
{
|
|
if (PyArg_ParseTuple(args, "")) {
|
|
// Undefined Edge
|
|
getTopoShapePtr()->setShape(TopoDS_Edge());
|
|
return 0;
|
|
}
|
|
|
|
PyErr_Clear();
|
|
PyObject *pcObj, *pcObj2;
|
|
double first = std::numeric_limits<double>::max();
|
|
double last = std::numeric_limits<double>::max();
|
|
if (PyArg_ParseTuple(args, "O!|dd", &(Part::GeometryPy::Type), &pcObj, &first, &last)) {
|
|
Geometry* geom = static_cast<GeometryPy*>(pcObj)->getGeometryPtr();
|
|
Handle(Geom_Curve) curve = Handle(Geom_Curve)::DownCast(geom->handle());
|
|
if (curve.IsNull()) {
|
|
PyErr_SetString(PartExceptionOCCError, "geometry is not a curve type");
|
|
return -1;
|
|
}
|
|
|
|
if (first == std::numeric_limits<double>::max()) {
|
|
first = curve->FirstParameter();
|
|
}
|
|
if (last == std::numeric_limits<double>::max()) {
|
|
last = curve->LastParameter();
|
|
}
|
|
|
|
try {
|
|
BRepBuilderAPI_MakeEdge mkEdge(curve, first, last);
|
|
getTopoShapePtr()->setShape(mkEdge.Edge());
|
|
return 0;
|
|
}
|
|
catch (Standard_Failure& e) {
|
|
|
|
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
PyErr_Clear();
|
|
if (PyArg_ParseTuple(args, "O!", &(Part::TopoShapePy::Type), &pcObj)) {
|
|
TopoShape* shape = static_cast<TopoShapePy*>(pcObj)->getTopoShapePtr();
|
|
if (shape && !shape->getShape().IsNull() && shape->getShape().ShapeType() == TopAbs_EDGE) {
|
|
this->getTopoShapePtr()->setShape(shape->getShape());
|
|
return 0;
|
|
}
|
|
else {
|
|
PyErr_SetString(PyExc_TypeError, "Shape is not an edge");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
PyErr_Clear();
|
|
if (PyArg_ParseTuple(
|
|
args,
|
|
"O!O!",
|
|
&(Part::TopoShapeVertexPy::Type),
|
|
&pcObj,
|
|
&(Part::TopoShapeVertexPy::Type),
|
|
&pcObj2
|
|
)) {
|
|
TopoShape* shape1 = static_cast<TopoShapePy*>(pcObj)->getTopoShapePtr();
|
|
TopoShape* shape2 = static_cast<TopoShapePy*>(pcObj2)->getTopoShapePtr();
|
|
const TopoDS_Vertex& v1 = TopoDS::Vertex(shape1->getShape());
|
|
const TopoDS_Vertex& v2 = TopoDS::Vertex(shape2->getShape());
|
|
|
|
try {
|
|
BRepBuilderAPI_MakeEdge mkEdge(v1, v2);
|
|
getTopoShapePtr()->setShape(mkEdge.Edge());
|
|
return 0;
|
|
}
|
|
catch (Standard_Failure& e) {
|
|
|
|
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
PyErr_SetString(PartExceptionOCCError, "Curve or shape expected");
|
|
return -1;
|
|
}
|
|
|
|
// ====== Methods ======================================================================
|
|
|
|
PyObject* TopoShapeEdgePy::getParameterByLength(PyObject* args) const
|
|
{
|
|
double u;
|
|
double t = Precision::Confusion();
|
|
if (!PyArg_ParseTuple(args, "d|d", &u, &t)) {
|
|
return nullptr;
|
|
}
|
|
|
|
auto e = getTopoDSEdge(this);
|
|
BRepAdaptor_Curve adapt(e);
|
|
|
|
// transform value of [0,Length] to [First,Last]
|
|
double first = BRepLProp_CurveTool::FirstParameter(adapt);
|
|
double last = BRepLProp_CurveTool::LastParameter(adapt);
|
|
if (!Precision::IsInfinite(first) && !Precision::IsInfinite(last)) {
|
|
double length = GCPnts_AbscissaPoint::Length(adapt, t);
|
|
|
|
if (u < -length || u > length) {
|
|
PyErr_SetString(PyExc_ValueError, "value out of range");
|
|
return nullptr;
|
|
}
|
|
if (u < 0) {
|
|
u = length + u;
|
|
}
|
|
GCPnts_AbscissaPoint abscissaPoint(t, adapt, u, first);
|
|
double parm = abscissaPoint.Parameter();
|
|
return PyFloat_FromDouble(parm);
|
|
}
|
|
|
|
return PyFloat_FromDouble(u);
|
|
}
|
|
|
|
PyObject* TopoShapeEdgePy::valueAt(PyObject* args) const
|
|
{
|
|
double u;
|
|
if (!PyArg_ParseTuple(args, "d", &u)) {
|
|
return nullptr;
|
|
}
|
|
|
|
auto e = getTopoDSEdge(this);
|
|
BRepAdaptor_Curve adapt(e);
|
|
|
|
// Check now the orientation of the edge to make
|
|
// sure that we get the right wanted point!
|
|
BRepLProp_CLProps prop(adapt, u, 0, Precision::Confusion());
|
|
const gp_Pnt& V = prop.Value();
|
|
return new Base::VectorPy(new Base::Vector3d(V.X(), V.Y(), V.Z()));
|
|
}
|
|
|
|
PyObject* TopoShapeEdgePy::parameters(PyObject* args) const
|
|
{
|
|
PyObject* pyface = nullptr;
|
|
if (!PyArg_ParseTuple(args, "|O!", &(TopoShapeFacePy::Type), &pyface)) {
|
|
return nullptr;
|
|
}
|
|
|
|
auto e = getTopoDSEdge(this);
|
|
TopLoc_Location aLoc;
|
|
Handle(Poly_Polygon3D) aPoly = BRep_Tool::Polygon3D(e, aLoc);
|
|
if (!aPoly.IsNull()) {
|
|
Py::List list;
|
|
if (!aPoly->HasParameters()) {
|
|
return Py::new_reference_to(list);
|
|
}
|
|
|
|
const TColStd_Array1OfReal& aNodes = aPoly->Parameters();
|
|
for (int i = aNodes.Lower(); i <= aNodes.Upper(); i++) {
|
|
list.append(Py::Float(aNodes(i)));
|
|
}
|
|
|
|
return Py::new_reference_to(list);
|
|
}
|
|
else if (pyface) {
|
|
// build up map edge->face
|
|
const TopoDS_Shape& face = static_cast<TopoShapeFacePy*>(pyface)->getTopoShapePtr()->getShape();
|
|
TopTools_IndexedDataMapOfShapeListOfShape edge2Face;
|
|
TopExp::MapShapesAndAncestors(TopoDS::Face(face), TopAbs_EDGE, TopAbs_FACE, edge2Face);
|
|
if (edge2Face.Contains(e)) {
|
|
Handle(Poly_Triangulation) aPolyTria = BRep_Tool::Triangulation(TopoDS::Face(face), aLoc);
|
|
if (!aPolyTria.IsNull()) {
|
|
Handle(Poly_PolygonOnTriangulation) aPoly
|
|
= BRep_Tool::PolygonOnTriangulation(e, aPolyTria, aLoc);
|
|
if (!aPoly.IsNull()) {
|
|
if (!aPoly->HasParameters()) {
|
|
Py::List list;
|
|
return Py::new_reference_to(list);
|
|
}
|
|
|
|
Handle(TColStd_HArray1OfReal) aNodes = aPoly->Parameters();
|
|
if (!aNodes.IsNull()) {
|
|
Py::List list;
|
|
for (int i = aNodes->Lower(); i <= aNodes->Upper(); i++) {
|
|
list.append(Py::Float(aNodes->Value(i)));
|
|
}
|
|
|
|
return Py::new_reference_to(list);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
PyErr_SetString(PyExc_ValueError, "Edge is not part of the face");
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
PyErr_SetString(PyExc_RuntimeError, "Edge has no polygon");
|
|
return nullptr;
|
|
}
|
|
|
|
PyObject* TopoShapeEdgePy::parameterAt(PyObject* args) const
|
|
{
|
|
PyObject* pnt;
|
|
PyObject* face = nullptr;
|
|
if (!PyArg_ParseTuple(args, "O!|O!", &TopoShapeVertexPy::Type, &pnt, &TopoShapeFacePy::Type, &face)) {
|
|
return nullptr;
|
|
}
|
|
|
|
try {
|
|
const TopoDS_Shape& v = static_cast<TopoShapePy*>(pnt)->getTopoShapePtr()->getShape();
|
|
auto e = getTopoDSEdge(this);
|
|
|
|
if (face) {
|
|
const TopoDS_Shape& f = static_cast<TopoShapeFacePy*>(face)->getTopoShapePtr()->getShape();
|
|
Standard_Real par = BRep_Tool::Parameter(TopoDS::Vertex(v), e, TopoDS::Face(f));
|
|
return PyFloat_FromDouble(par);
|
|
}
|
|
else {
|
|
Standard_Real par = BRep_Tool::Parameter(TopoDS::Vertex(v), e);
|
|
return PyFloat_FromDouble(par);
|
|
}
|
|
}
|
|
catch (Standard_Failure& e) {
|
|
|
|
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
PyObject* TopoShapeEdgePy::tangentAt(PyObject* args) const
|
|
{
|
|
double u;
|
|
if (!PyArg_ParseTuple(args, "d", &u)) {
|
|
return nullptr;
|
|
}
|
|
|
|
auto e = getTopoDSEdge(this);
|
|
BRepAdaptor_Curve adapt(e);
|
|
|
|
BRepLProp_CLProps prop(adapt, u, 2, Precision::Confusion());
|
|
if (prop.IsTangentDefined()) {
|
|
gp_Dir dir;
|
|
prop.Tangent(dir);
|
|
return new Base::VectorPy(new Base::Vector3d(dir.X(), dir.Y(), dir.Z()));
|
|
}
|
|
else {
|
|
PyErr_SetString(PyExc_NotImplementedError, "Tangent not defined at this position!");
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
PyObject* TopoShapeEdgePy::normalAt(PyObject* args) const
|
|
{
|
|
double u;
|
|
if (!PyArg_ParseTuple(args, "d", &u)) {
|
|
return nullptr;
|
|
}
|
|
|
|
auto e = getTopoDSEdge(this);
|
|
BRepAdaptor_Curve adapt(e);
|
|
|
|
try {
|
|
BRepLProp_CLProps prop(adapt, u, 2, Precision::Confusion());
|
|
gp_Dir V;
|
|
prop.Normal(V);
|
|
return new Base::VectorPy(new Base::Vector3d(V.X(), V.Y(), V.Z()));
|
|
}
|
|
catch (Standard_Failure& e) {
|
|
|
|
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
PyObject* TopoShapeEdgePy::curvatureAt(PyObject* args) const
|
|
{
|
|
double u;
|
|
if (!PyArg_ParseTuple(args, "d", &u)) {
|
|
return nullptr;
|
|
}
|
|
|
|
auto e = getTopoDSEdge(this);
|
|
BRepAdaptor_Curve adapt(e);
|
|
|
|
try {
|
|
BRepLProp_CLProps prop(adapt, u, 2, Precision::Confusion());
|
|
double C = prop.Curvature();
|
|
return Py::new_reference_to(Py::Float(C));
|
|
}
|
|
catch (Standard_Failure& e) {
|
|
|
|
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
PyObject* TopoShapeEdgePy::centerOfCurvatureAt(PyObject* args) const
|
|
{
|
|
double u;
|
|
if (!PyArg_ParseTuple(args, "d", &u)) {
|
|
return nullptr;
|
|
}
|
|
|
|
auto e = getTopoDSEdge(this);
|
|
BRepAdaptor_Curve adapt(e);
|
|
|
|
try {
|
|
BRepLProp_CLProps prop(adapt, u, 2, Precision::Confusion());
|
|
gp_Pnt V;
|
|
prop.CentreOfCurvature(V);
|
|
return new Base::VectorPy(new Base::Vector3d(V.X(), V.Y(), V.Z()));
|
|
}
|
|
catch (Standard_Failure& e) {
|
|
|
|
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
PyObject* TopoShapeEdgePy::derivative1At(PyObject* args) const
|
|
{
|
|
double u;
|
|
if (!PyArg_ParseTuple(args, "d", &u)) {
|
|
return nullptr;
|
|
}
|
|
|
|
auto e = getTopoDSEdge(this);
|
|
BRepAdaptor_Curve adapt(e);
|
|
|
|
try {
|
|
BRepLProp_CLProps prop(adapt, u, 1, Precision::Confusion());
|
|
const gp_Vec& V = prop.D1();
|
|
return new Base::VectorPy(new Base::Vector3d(V.X(), V.Y(), V.Z()));
|
|
}
|
|
catch (Standard_Failure& e) {
|
|
|
|
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
PyObject* TopoShapeEdgePy::derivative2At(PyObject* args) const
|
|
{
|
|
double u;
|
|
if (!PyArg_ParseTuple(args, "d", &u)) {
|
|
return nullptr;
|
|
}
|
|
|
|
auto e = getTopoDSEdge(this);
|
|
BRepAdaptor_Curve adapt(e);
|
|
|
|
try {
|
|
BRepLProp_CLProps prop(adapt, u, 2, Precision::Confusion());
|
|
const gp_Vec& V = prop.D2();
|
|
return new Base::VectorPy(new Base::Vector3d(V.X(), V.Y(), V.Z()));
|
|
}
|
|
catch (Standard_Failure& e) {
|
|
|
|
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
PyObject* TopoShapeEdgePy::derivative3At(PyObject* args) const
|
|
{
|
|
double u;
|
|
if (!PyArg_ParseTuple(args, "d", &u)) {
|
|
return nullptr;
|
|
}
|
|
|
|
auto e = getTopoDSEdge(this);
|
|
BRepAdaptor_Curve adapt(e);
|
|
|
|
try {
|
|
BRepLProp_CLProps prop(adapt, u, 3, Precision::Confusion());
|
|
const gp_Vec& V = prop.D3();
|
|
return new Base::VectorPy(new Base::Vector3d(V.X(), V.Y(), V.Z()));
|
|
}
|
|
catch (Standard_Failure& e) {
|
|
|
|
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
PyObject* TopoShapeEdgePy::discretize(PyObject* args, PyObject* kwds) const
|
|
{
|
|
try {
|
|
BRepAdaptor_Curve adapt(TopoDS::Edge(getTopoShapePtr()->getShape()));
|
|
bool uniformAbscissaPoints = false;
|
|
bool uniformAbscissaDistance = false;
|
|
int numPoints = -1;
|
|
double distance = -1;
|
|
double first = adapt.FirstParameter();
|
|
double last = adapt.LastParameter();
|
|
|
|
// use no kwds
|
|
PyObject* dist_or_num;
|
|
if (PyArg_ParseTuple(args, "O", &dist_or_num)) {
|
|
if (PyLong_Check(dist_or_num)) {
|
|
numPoints = PyLong_AsLong(dist_or_num);
|
|
uniformAbscissaPoints = true;
|
|
}
|
|
else if (PyFloat_Check(dist_or_num)) {
|
|
distance = PyFloat_AsDouble(dist_or_num);
|
|
uniformAbscissaDistance = true;
|
|
}
|
|
else {
|
|
PyErr_SetString(PyExc_TypeError, "Either int or float expected");
|
|
return nullptr;
|
|
}
|
|
}
|
|
else {
|
|
// use Number kwds
|
|
static const std::array<const char*, 4> kwds_numPoints {"Number", "First", "Last", nullptr};
|
|
PyErr_Clear();
|
|
if (Base::Wrapped_ParseTupleAndKeywords(
|
|
args,
|
|
kwds,
|
|
"i|dd",
|
|
kwds_numPoints,
|
|
&numPoints,
|
|
&first,
|
|
&last
|
|
)) {
|
|
uniformAbscissaPoints = true;
|
|
}
|
|
else {
|
|
// use Abscissa kwds
|
|
static const std::array<const char*, 4> kwds_Distance {
|
|
"Distance",
|
|
"First",
|
|
"Last",
|
|
nullptr
|
|
};
|
|
PyErr_Clear();
|
|
if (Base::Wrapped_ParseTupleAndKeywords(
|
|
args,
|
|
kwds,
|
|
"d|dd",
|
|
kwds_Distance,
|
|
&distance,
|
|
&first,
|
|
&last
|
|
)) {
|
|
uniformAbscissaDistance = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (uniformAbscissaPoints || uniformAbscissaDistance) {
|
|
GCPnts_UniformAbscissa discretizer;
|
|
if (uniformAbscissaPoints) {
|
|
discretizer.Initialize(adapt, numPoints, first, last);
|
|
}
|
|
else {
|
|
discretizer.Initialize(adapt, distance, first, last);
|
|
}
|
|
|
|
if (discretizer.IsDone() && discretizer.NbPoints() > 0) {
|
|
Py::List points;
|
|
int nbPoints = discretizer.NbPoints();
|
|
for (int i = 1; i <= nbPoints; i++) {
|
|
gp_Pnt p = adapt.Value(discretizer.Parameter(i));
|
|
points.append(Py::Vector(Base::Vector3d(p.X(), p.Y(), p.Z())));
|
|
}
|
|
|
|
return Py::new_reference_to(points);
|
|
}
|
|
else {
|
|
PyErr_SetString(PartExceptionOCCError, "Discretization of edge failed");
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
// use Deflection kwds
|
|
static const std::array<const char*, 4> kwds_Deflection {"Deflection", "First", "Last", nullptr};
|
|
PyErr_Clear();
|
|
double deflection;
|
|
if (Base::Wrapped_ParseTupleAndKeywords(
|
|
args,
|
|
kwds,
|
|
"d|dd",
|
|
kwds_Deflection,
|
|
&deflection,
|
|
&first,
|
|
&last
|
|
)) {
|
|
GCPnts_UniformDeflection discretizer(adapt, deflection, first, last);
|
|
if (discretizer.IsDone() && discretizer.NbPoints() > 0) {
|
|
Py::List points;
|
|
int nbPoints = discretizer.NbPoints();
|
|
for (int i = 1; i <= nbPoints; i++) {
|
|
gp_Pnt p = discretizer.Value(i);
|
|
points.append(Py::Vector(Base::Vector3d(p.X(), p.Y(), p.Z())));
|
|
}
|
|
|
|
return Py::new_reference_to(points);
|
|
}
|
|
else {
|
|
PyErr_SetString(PartExceptionOCCError, "Discretization of edge failed");
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
// use TangentialDeflection kwds
|
|
static const std::array<const char*, 6>
|
|
kwds_TangentialDeflection {"Angular", "Curvature", "First", "Last", "Minimum", nullptr};
|
|
PyErr_Clear();
|
|
double angular;
|
|
double curvature;
|
|
int minimumPoints = 2;
|
|
if (Base::Wrapped_ParseTupleAndKeywords(
|
|
args,
|
|
kwds,
|
|
"dd|ddi",
|
|
kwds_TangentialDeflection,
|
|
&angular,
|
|
&curvature,
|
|
&first,
|
|
&last,
|
|
&minimumPoints
|
|
)) {
|
|
GCPnts_TangentialDeflection discretizer(adapt, first, last, angular, curvature, minimumPoints);
|
|
if (discretizer.NbPoints() > 0) {
|
|
Py::List points;
|
|
int nbPoints = discretizer.NbPoints();
|
|
for (int i = 1; i <= nbPoints; i++) {
|
|
gp_Pnt p = discretizer.Value(i);
|
|
points.append(Py::Vector(Base::Vector3d(p.X(), p.Y(), p.Z())));
|
|
}
|
|
|
|
return Py::new_reference_to(points);
|
|
}
|
|
else {
|
|
PyErr_SetString(PartExceptionOCCError, "Discretization of edge failed");
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
// use QuasiNumber kwds
|
|
static const std::array<const char*, 4> kwds_QuasiNumPoints {
|
|
"QuasiNumber",
|
|
"First",
|
|
"Last",
|
|
nullptr
|
|
};
|
|
PyErr_Clear();
|
|
int quasiNumPoints;
|
|
if (Base::Wrapped_ParseTupleAndKeywords(
|
|
args,
|
|
kwds,
|
|
"i|dd",
|
|
kwds_QuasiNumPoints,
|
|
&quasiNumPoints,
|
|
&first,
|
|
&last
|
|
)) {
|
|
GCPnts_QuasiUniformAbscissa discretizer(adapt, quasiNumPoints, first, last);
|
|
if (discretizer.NbPoints() > 0) {
|
|
Py::List points;
|
|
int nbPoints = discretizer.NbPoints();
|
|
for (int i = 1; i <= nbPoints; i++) {
|
|
gp_Pnt p = adapt.Value(discretizer.Parameter(i));
|
|
points.append(Py::Vector(Base::Vector3d(p.X(), p.Y(), p.Z())));
|
|
}
|
|
|
|
return Py::new_reference_to(points);
|
|
}
|
|
else {
|
|
PyErr_SetString(PartExceptionOCCError, "Discretization of edge failed");
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
// use QuasiDeflection kwds
|
|
static const std::array<const char*, 4> kwds_QuasiDeflection {
|
|
"QuasiDeflection",
|
|
"First",
|
|
"Last",
|
|
nullptr
|
|
};
|
|
PyErr_Clear();
|
|
double quasiDeflection;
|
|
if (Base::Wrapped_ParseTupleAndKeywords(
|
|
args,
|
|
kwds,
|
|
"d|dd",
|
|
kwds_QuasiDeflection,
|
|
&quasiDeflection,
|
|
&first,
|
|
&last
|
|
)) {
|
|
GCPnts_QuasiUniformDeflection discretizer(adapt, quasiDeflection, first, last);
|
|
if (discretizer.NbPoints() > 0) {
|
|
Py::List points;
|
|
int nbPoints = discretizer.NbPoints();
|
|
for (int i = 1; i <= nbPoints; i++) {
|
|
gp_Pnt p = discretizer.Value(i);
|
|
points.append(Py::Vector(Base::Vector3d(p.X(), p.Y(), p.Z())));
|
|
}
|
|
|
|
return Py::new_reference_to(points);
|
|
}
|
|
else {
|
|
PyErr_SetString(PartExceptionOCCError, "Discretization of edge failed");
|
|
return nullptr;
|
|
}
|
|
}
|
|
}
|
|
catch (const Base::Exception& e) {
|
|
PyErr_SetString(PartExceptionOCCError, e.what());
|
|
return nullptr;
|
|
}
|
|
|
|
PyErr_SetString(PartExceptionOCCError, "Wrong arguments");
|
|
return nullptr;
|
|
}
|
|
|
|
PyObject* TopoShapeEdgePy::countNodes(PyObject* args) const
|
|
{
|
|
if (!PyArg_ParseTuple(args, "")) {
|
|
return nullptr;
|
|
}
|
|
|
|
const TopoDS_Shape& shape = this->getTopoShapePtr()->getShape();
|
|
TopoDS_Edge aEdge = TopoDS::Edge(shape);
|
|
TopLoc_Location aLoc;
|
|
const Handle(Poly_Polygon3D) & aPoly = BRep_Tool::Polygon3D(aEdge, aLoc);
|
|
int count = 0;
|
|
if (!aPoly.IsNull()) {
|
|
count = aPoly->NbNodes();
|
|
}
|
|
|
|
return Py::new_reference_to(Py::Long(count));
|
|
}
|
|
|
|
PyObject* TopoShapeEdgePy::split(PyObject* args) const
|
|
{
|
|
PyObject* float_or_list;
|
|
if (!PyArg_ParseTuple(args, "O", &float_or_list)) {
|
|
return nullptr;
|
|
}
|
|
|
|
try {
|
|
BRepAdaptor_Curve adapt(TopoDS::Edge(getTopoShapePtr()->getShape()));
|
|
Standard_Real f = adapt.FirstParameter();
|
|
Standard_Real l = adapt.LastParameter();
|
|
|
|
std::vector<Standard_Real> par;
|
|
par.push_back(f);
|
|
if (PyFloat_Check(float_or_list)) {
|
|
double val = PyFloat_AsDouble(float_or_list);
|
|
if (val == f || val == l) {
|
|
PyErr_SetString(PyExc_ValueError, "Cannot split edge at start or end point");
|
|
return nullptr;
|
|
}
|
|
else if (val < f || val > l) {
|
|
PyErr_SetString(PyExc_ValueError, "Value out of parameter range");
|
|
return nullptr;
|
|
}
|
|
par.push_back(val);
|
|
}
|
|
else if (PySequence_Check(float_or_list)) {
|
|
Py::Sequence list(float_or_list);
|
|
for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
|
|
double val = (double)Py::Float(*it);
|
|
if (val == f || val == l) {
|
|
PyErr_SetString(PyExc_ValueError, "Cannot split edge at start or end point");
|
|
return nullptr;
|
|
}
|
|
else if (val < f || val > l) {
|
|
PyErr_SetString(PyExc_ValueError, "Value out of parameter range");
|
|
return nullptr;
|
|
}
|
|
par.push_back(val);
|
|
}
|
|
}
|
|
else {
|
|
PyErr_SetString(PyExc_TypeError, "Either float or list of floats expected");
|
|
return nullptr;
|
|
}
|
|
|
|
par.push_back(l);
|
|
std::sort(par.begin(), par.end());
|
|
|
|
BRepBuilderAPI_MakeWire mkWire;
|
|
Handle(Geom_Curve) c = adapt.Curve().Curve();
|
|
const TopoDS_Edge& edge = TopoDS::Edge(this->getTopoShapePtr()->getShape());
|
|
BRep_Builder builder;
|
|
TopoDS_Edge e;
|
|
std::vector<Standard_Real>::iterator end = par.end() - 1;
|
|
for (std::vector<Standard_Real>::iterator it = par.begin(); it != end; ++it) {
|
|
BRepBuilderAPI_MakeEdge mke(c, it[0], it[1]);
|
|
e = mke.Edge();
|
|
builder.Transfert(edge, e);
|
|
builder.Range(e, it[0], it[1], false);
|
|
mkWire.Add(e);
|
|
}
|
|
|
|
return new TopoShapeWirePy(new TopoShape(mkWire.Shape()));
|
|
}
|
|
catch (Standard_Failure& e) {
|
|
|
|
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
PyObject* TopoShapeEdgePy::isSeam(PyObject* args) const
|
|
{
|
|
PyObject* face;
|
|
if (!PyArg_ParseTuple(args, "O!", &TopoShapeFacePy::Type, &face)) {
|
|
return nullptr;
|
|
}
|
|
|
|
try {
|
|
const TopoDS_Edge& e = TopoDS::Edge(this->getTopoShapePtr()->getShape());
|
|
const TopoDS_Face& f = TopoDS::Face(
|
|
static_cast<TopoShapeFacePy*>(face)->getTopoShapePtr()->getShape()
|
|
);
|
|
|
|
ShapeAnalysis_Edge sa;
|
|
Standard_Boolean ok = sa.IsSeam(e, f);
|
|
return PyBool_FromLong(ok ? 1 : 0);
|
|
}
|
|
catch (Standard_Failure& e) {
|
|
|
|
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
PyObject* TopoShapeEdgePy::firstVertex(PyObject* args) const
|
|
{
|
|
PyObject* orient = Py_False;
|
|
if (!PyArg_ParseTuple(args, "|O!", &PyBool_Type, &orient)) {
|
|
return nullptr;
|
|
}
|
|
auto e = getTopoDSEdge(this);
|
|
TopoDS_Vertex v = TopExp::FirstVertex(e, Base::asBoolean(orient));
|
|
return new TopoShapeVertexPy(new TopoShape(v));
|
|
}
|
|
|
|
PyObject* TopoShapeEdgePy::lastVertex(PyObject* args) const
|
|
{
|
|
PyObject* orient = Py_False;
|
|
if (!PyArg_ParseTuple(args, "|O!", &PyBool_Type, &orient)) {
|
|
return nullptr;
|
|
}
|
|
auto e = getTopoDSEdge(this);
|
|
TopoDS_Vertex v = TopExp::LastVertex(e, Base::asBoolean(orient));
|
|
return new TopoShapeVertexPy(new TopoShape(v));
|
|
}
|
|
|
|
// ====== Attributes ======================================================================
|
|
|
|
Py::String TopoShapeEdgePy::getContinuity() const
|
|
{
|
|
BRepAdaptor_Curve adapt(TopoDS::Edge(getTopoShapePtr()->getShape()));
|
|
std::string cont;
|
|
switch (adapt.Continuity()) {
|
|
case GeomAbs_C0:
|
|
cont = "C0";
|
|
break;
|
|
case GeomAbs_G1:
|
|
cont = "G1";
|
|
break;
|
|
case GeomAbs_C1:
|
|
cont = "C1";
|
|
break;
|
|
case GeomAbs_G2:
|
|
cont = "G2";
|
|
break;
|
|
case GeomAbs_C2:
|
|
cont = "C2";
|
|
break;
|
|
case GeomAbs_C3:
|
|
cont = "C3";
|
|
break;
|
|
case GeomAbs_CN:
|
|
cont = "CN";
|
|
break;
|
|
}
|
|
|
|
return Py::String(cont);
|
|
}
|
|
|
|
Py::Float TopoShapeEdgePy::getTolerance() const
|
|
{
|
|
auto e = getTopoDSEdge(this);
|
|
return Py::Float(BRep_Tool::Tolerance(e));
|
|
}
|
|
|
|
void TopoShapeEdgePy::setTolerance(Py::Float tol)
|
|
{
|
|
BRep_Builder aBuilder;
|
|
auto e = getTopoDSEdge(this);
|
|
aBuilder.UpdateEdge(e, (double)tol);
|
|
}
|
|
|
|
Py::Float TopoShapeEdgePy::getLength() const
|
|
{
|
|
auto e = getTopoDSEdge(this);
|
|
BRepAdaptor_Curve adapt(e);
|
|
return Py::Float(GCPnts_AbscissaPoint::Length(adapt, Precision::Confusion()));
|
|
}
|
|
|
|
#include <App/Application.h>
|
|
#include <Mod/Part/App/LineSegmentPy.h>
|
|
|
|
Py::Object TopoShapeEdgePy::getCurve() const
|
|
{
|
|
auto e = getTopoDSEdge(this);
|
|
BRepAdaptor_Curve adapt(e);
|
|
Base::PyObjectBase* curve = nullptr;
|
|
switch (adapt.GetType()) {
|
|
case GeomAbs_Line: {
|
|
GeomLine* line = new GeomLine();
|
|
Handle(Geom_Line) this_curv = Handle(Geom_Line)::DownCast(line->handle());
|
|
this_curv->SetLin(adapt.Line());
|
|
curve = new LinePy(line);
|
|
break;
|
|
}
|
|
case GeomAbs_Circle: {
|
|
GeomCircle* circle = new GeomCircle();
|
|
Handle(Geom_Circle) this_curv = Handle(Geom_Circle)::DownCast(circle->handle());
|
|
this_curv->SetCirc(adapt.Circle());
|
|
// Standard_Real dd = adapt.FirstParameter();
|
|
// Standard_Real ee = adapt.LastParameter();
|
|
curve = new CirclePy(circle);
|
|
break;
|
|
}
|
|
case GeomAbs_Ellipse: {
|
|
GeomEllipse* elips = new GeomEllipse();
|
|
Handle(Geom_Ellipse) this_curv = Handle(Geom_Ellipse)::DownCast(elips->handle());
|
|
this_curv->SetElips(adapt.Ellipse());
|
|
curve = new EllipsePy(elips);
|
|
break;
|
|
}
|
|
case GeomAbs_Hyperbola: {
|
|
GeomHyperbola* hypr = new GeomHyperbola();
|
|
Handle(Geom_Hyperbola) this_curv = Handle(Geom_Hyperbola)::DownCast(hypr->handle());
|
|
this_curv->SetHypr(adapt.Hyperbola());
|
|
curve = new HyperbolaPy(hypr);
|
|
break;
|
|
}
|
|
case GeomAbs_Parabola: {
|
|
GeomParabola* parab = new GeomParabola();
|
|
Handle(Geom_Parabola) this_curv = Handle(Geom_Parabola)::DownCast(parab->handle());
|
|
this_curv->SetParab(adapt.Parabola());
|
|
curve = new ParabolaPy(parab);
|
|
break;
|
|
}
|
|
case GeomAbs_BezierCurve: {
|
|
GeomBezierCurve* bezier = new GeomBezierCurve(adapt.Bezier());
|
|
curve = new BezierCurvePy(bezier);
|
|
break;
|
|
}
|
|
case GeomAbs_BSplineCurve: {
|
|
GeomBSplineCurve* bspline = new GeomBSplineCurve(adapt.BSpline());
|
|
curve = new BSplineCurvePy(bspline);
|
|
break;
|
|
}
|
|
case GeomAbs_OffsetCurve: {
|
|
Standard_Real first, last;
|
|
Handle(Geom_Curve) c = BRep_Tool::Curve(e, first, last);
|
|
Handle(Geom_OffsetCurve) off = Handle(Geom_OffsetCurve)::DownCast(c);
|
|
if (!off.IsNull()) {
|
|
GeomOffsetCurve* offset = new GeomOffsetCurve(off);
|
|
curve = new OffsetCurvePy(offset);
|
|
break;
|
|
}
|
|
else {
|
|
throw Py::RuntimeError("Failed to convert to offset curve");
|
|
}
|
|
}
|
|
case GeomAbs_OtherCurve:
|
|
break;
|
|
}
|
|
|
|
if (curve) {
|
|
curve->setNotTracking();
|
|
return Py::asObject(curve);
|
|
}
|
|
|
|
throw Py::TypeError("undefined curve type");
|
|
}
|
|
|
|
Py::Tuple TopoShapeEdgePy::getParameterRange() const
|
|
{
|
|
auto e = getTopoDSEdge(this);
|
|
BRepAdaptor_Curve adapt(e);
|
|
double u = adapt.FirstParameter();
|
|
double v = adapt.LastParameter();
|
|
|
|
Py::Tuple t(2);
|
|
t.setItem(0, Py::Float(u));
|
|
t.setItem(1, Py::Float(v));
|
|
return t;
|
|
}
|
|
|
|
Py::Float TopoShapeEdgePy::getFirstParameter() const
|
|
{
|
|
auto e = getTopoDSEdge(this);
|
|
BRepAdaptor_Curve adapt(e);
|
|
double t = adapt.FirstParameter();
|
|
return Py::Float(t);
|
|
}
|
|
|
|
Py::Float TopoShapeEdgePy::getLastParameter() const
|
|
{
|
|
auto e = getTopoDSEdge(this);
|
|
BRepAdaptor_Curve adapt(e);
|
|
double t = adapt.LastParameter();
|
|
return Py::Float(t);
|
|
}
|
|
|
|
Py::Object TopoShapeEdgePy::getMass() const
|
|
{
|
|
GProp_GProps props;
|
|
BRepGProp::LinearProperties(getTopoShapePtr()->getShape(), props);
|
|
double c = props.Mass();
|
|
return Py::Float(c);
|
|
}
|
|
|
|
Py::Object TopoShapeEdgePy::getCenterOfMass() const
|
|
{
|
|
GProp_GProps props;
|
|
BRepGProp::LinearProperties(getTopoShapePtr()->getShape(), props);
|
|
gp_Pnt c = props.CentreOfMass();
|
|
return Py::Vector(Base::Vector3d(c.X(), c.Y(), c.Z()));
|
|
}
|
|
|
|
Py::Object TopoShapeEdgePy::getMatrixOfInertia() const
|
|
{
|
|
GProp_GProps props;
|
|
BRepGProp::LinearProperties(getTopoShapePtr()->getShape(), props);
|
|
gp_Mat m = props.MatrixOfInertia();
|
|
Base::Matrix4D mat;
|
|
for (int i = 0; i < 3; i++) {
|
|
for (int j = 0; j < 3; j++) {
|
|
mat[i][j] = m(i + 1, j + 1);
|
|
}
|
|
}
|
|
return Py::Matrix(mat);
|
|
}
|
|
|
|
Py::Object TopoShapeEdgePy::getStaticMoments() const
|
|
{
|
|
GProp_GProps props;
|
|
BRepGProp::LinearProperties(getTopoShapePtr()->getShape(), props);
|
|
Standard_Real lx, ly, lz;
|
|
props.StaticMoments(lx, ly, lz);
|
|
Py::Tuple tuple(3);
|
|
tuple.setItem(0, Py::Float(lx));
|
|
tuple.setItem(1, Py::Float(ly));
|
|
tuple.setItem(2, Py::Float(lz));
|
|
return tuple;
|
|
}
|
|
|
|
Py::Dict TopoShapeEdgePy::getPrincipalProperties() const
|
|
{
|
|
GProp_GProps props;
|
|
BRepGProp::LinearProperties(getTopoShapePtr()->getShape(), props);
|
|
GProp_PrincipalProps pprops = props.PrincipalProperties();
|
|
|
|
Py::Dict dict;
|
|
dict.setItem("SymmetryAxis", Py::Boolean(pprops.HasSymmetryAxis() ? true : false));
|
|
dict.setItem("SymmetryPoint", Py::Boolean(pprops.HasSymmetryPoint() ? true : false));
|
|
Standard_Real lx, ly, lz;
|
|
pprops.Moments(lx, ly, lz);
|
|
Py::Tuple tuple(3);
|
|
tuple.setItem(0, Py::Float(lx));
|
|
tuple.setItem(1, Py::Float(ly));
|
|
tuple.setItem(2, Py::Float(lz));
|
|
dict.setItem("Moments", tuple);
|
|
dict.setItem(
|
|
"FirstAxisOfInertia",
|
|
Py::Vector(Base::convertTo<Base::Vector3d>(pprops.FirstAxisOfInertia()))
|
|
);
|
|
dict.setItem(
|
|
"SecondAxisOfInertia",
|
|
Py::Vector(Base::convertTo<Base::Vector3d>(pprops.SecondAxisOfInertia()))
|
|
);
|
|
dict.setItem(
|
|
"ThirdAxisOfInertia",
|
|
Py::Vector(Base::convertTo<Base::Vector3d>(pprops.ThirdAxisOfInertia()))
|
|
);
|
|
|
|
Standard_Real Rxx, Ryy, Rzz;
|
|
pprops.RadiusOfGyration(Rxx, Ryy, Rzz);
|
|
Py::Tuple rog(3);
|
|
rog.setItem(0, Py::Float(Rxx));
|
|
rog.setItem(1, Py::Float(Ryy));
|
|
rog.setItem(2, Py::Float(Rzz));
|
|
dict.setItem("RadiusOfGyration", rog);
|
|
return dict;
|
|
}
|
|
|
|
Py::Boolean TopoShapeEdgePy::getClosed() const
|
|
{
|
|
if (getTopoShapePtr()->getShape().IsNull()) {
|
|
throw Py::RuntimeError("Cannot determine the 'Closed'' flag of an empty shape");
|
|
}
|
|
Standard_Boolean ok = BRep_Tool::IsClosed(getTopoShapePtr()->getShape());
|
|
return Py::Boolean(ok ? true : false);
|
|
}
|
|
|
|
Py::Boolean TopoShapeEdgePy::getDegenerated() const
|
|
{
|
|
Standard_Boolean ok = BRep_Tool::Degenerated(TopoDS::Edge(getTopoShapePtr()->getShape()));
|
|
return Py::Boolean(ok ? true : false);
|
|
}
|
|
|
|
PyObject* TopoShapeEdgePy::curveOnSurface(PyObject* args) const
|
|
{
|
|
int idx;
|
|
if (!PyArg_ParseTuple(args, "i", &idx)) {
|
|
return nullptr;
|
|
}
|
|
|
|
try {
|
|
TopoDS_Edge edge = TopoDS::Edge(getTopoShapePtr()->getShape());
|
|
Handle(Geom2d_Curve) curve;
|
|
Handle(Geom_Surface) surf;
|
|
TopLoc_Location loc;
|
|
Standard_Real first, last;
|
|
|
|
BRep_Tool::CurveOnSurface(edge, curve, surf, loc, first, last, idx + 1);
|
|
if (curve.IsNull()) {
|
|
Py_Return;
|
|
}
|
|
std::unique_ptr<Part::Geom2dCurve> geo2d(makeFromCurve2d(curve));
|
|
if (!geo2d) {
|
|
Py_Return;
|
|
}
|
|
std::unique_ptr<Part::GeomSurface> geosurf(makeFromSurface(surf));
|
|
if (!geosurf) {
|
|
Py_Return;
|
|
}
|
|
|
|
gp_Trsf trsf = loc.Transformation();
|
|
gp_XYZ pos = trsf.TranslationPart();
|
|
gp_XYZ axis;
|
|
Standard_Real angle;
|
|
trsf.GetRotation(axis, angle);
|
|
Base::Rotation rot(Base::Vector3d(axis.X(), axis.Y(), axis.Z()), angle);
|
|
Base::Placement placement(Base::Vector3d(pos.X(), pos.Y(), pos.Z()), rot);
|
|
|
|
Py::Tuple tuple(5);
|
|
tuple.setItem(0, Py::asObject(geo2d->getPyObject()));
|
|
tuple.setItem(1, Py::asObject(geosurf->getPyObject()));
|
|
tuple.setItem(2, Py::asObject(new Base::PlacementPy(placement)));
|
|
tuple.setItem(3, Py::Float(first));
|
|
tuple.setItem(4, Py::Float(last));
|
|
return Py::new_reference_to(tuple);
|
|
}
|
|
catch (Standard_Failure& e) {
|
|
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
PyObject* TopoShapeEdgePy::getCustomAttributes(const char* /*attr*/) const
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
int TopoShapeEdgePy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
|
|
{
|
|
return 0;
|
|
}
|