Files
create/src/Mod/Part/App/TopoShapeEdgePyImp.cpp
Markus Reitböck 68114945fa Part: use CMake to generate precompiled headers on all platforms
"Professional CMake" book suggest the following:

"Targets should build successfully with or without compiler support for precompiled headers. It
 should be considered an optimization, not a requirement. In particular, do not explicitly include a
 precompile header (e.g. stdafx.h) in the source code, let CMake force-include an automatically
 generated precompile header on the compiler command line instead. This is more portable across
 the major compilers and is likely to be easier to maintain. It will also avoid warnings being
 generated from certain code checking tools like iwyu (include what you use)."

Therefore, removed the "#include <PreCompiled.h>" from sources, also
there is no need for the "#ifdef _PreComp_" anymore
2025-09-24 20:08:56 +02:00

1097 lines
37 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;
}
}
// 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;
}