Files
create/src/Mod/Part/App/BSplineCurvePyImp.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

1433 lines
49 KiB
C++

/***************************************************************************
* Copyright (c) 2008 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* 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 <cmath>
# include <Geom_BSplineCurve.hxx>
# include <GeomAPI_Interpolate.hxx>
# include <GeomAPI_PointsToBSpline.hxx>
# include <GeomConvert_BSplineCurveToBezierCurve.hxx>
# include <gp_Pnt.hxx>
# include <Precision.hxx>
# include <TColgp_Array1OfPnt.hxx>
# include <TColgp_Array1OfVec.hxx>
# include <TColgp_HArray1OfPnt.hxx>
# include <TColStd_Array1OfInteger.hxx>
# include <TColStd_Array1OfReal.hxx>
# include <TColStd_HArray1OfBoolean.hxx>
# include <TColStd_HArray1OfReal.hxx>
#include <Base/GeometryPyCXX.h>
#include <Base/PyWrapParseTupleAndKeywords.h>
#include <Base/VectorPy.h>
#include "BSplineCurvePy.h"
#include "BSplineCurvePy.cpp"
#include "BezierCurvePy.h"
#include "OCCError.h"
using namespace Part;
// returns a string which represents the object e.g. when printed in python
std::string BSplineCurvePy::representation() const
{
return "<BSplineCurve object>";
}
PyObject *BSplineCurvePy::PyMake(struct _typeobject *, PyObject *, PyObject *) // Python wrapper
{
// create a new instance of BSplineCurvePy and the Twin object
return new BSplineCurvePy(new GeomBSplineCurve);
}
// constructor method
int BSplineCurvePy::PyInit(PyObject* args, PyObject* kwd)
{
if (PyArg_ParseTuple(args, "")) {
return 0;
}
PyErr_Clear();
PyObject* obj;
// poles, [ periodic, degree, interpolate ]
// {"poles", "mults", "knots", "periodic", "degree", "weights", "CheckRational", NULL};
obj = buildFromPolesMultsKnots(args, kwd);
if (obj) {
Py_DECREF(obj);
return 0;
}
else if (PyErr_ExceptionMatches(PartExceptionOCCError)) {
return -1;
}
PyErr_SetString(PyExc_TypeError, "B-spline constructor accepts:\n"
"-- poles, [ periodic, degree, interpolate ]\n"
"-- empty parameter list\n");
return -1;
}
PyObject* BSplineCurvePy::__reduce__(PyObject *args) const
{
if (!PyArg_ParseTuple(args, ""))
return nullptr;
Py::Tuple tuple(2);
// type object to create an instance
Py::Object type(Base::getTypeAsObject(&BSplineCurvePy::Type));
tuple.setItem(0, type);
// create an argument tuple to create a copy
Py::Object self(const_cast<BSplineCurvePy*>(this));
Py::Tuple data(7);
data.setItem(0, Py::Callable(self.getAttr("getPoles")).apply());
data.setItem(1, Py::Callable(self.getAttr("getMultiplicities")).apply());
data.setItem(2, Py::Callable(self.getAttr("getKnots")).apply());
data.setItem(3, Py::Callable(self.getAttr("isPeriodic")).apply());
data.setItem(4, self.getAttr("Degree"));
data.setItem(5, Py::Callable(self.getAttr("getWeights")).apply());
data.setItem(6, Py::Callable(self.getAttr("isRational")).apply());
tuple.setItem(1, data);
return Py::new_reference_to(tuple);
}
PyObject* BSplineCurvePy::isRational(PyObject *args) const
{
if (!PyArg_ParseTuple(args, ""))
return nullptr;
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
(getGeometryPtr()->handle());
Standard_Boolean val = curve->IsRational();
return PyBool_FromLong(val ? 1 : 0);
}
PyObject* BSplineCurvePy::isPeriodic(PyObject *args) const
{
if (!PyArg_ParseTuple(args, ""))
return nullptr;
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
(getGeometryPtr()->handle());
Standard_Boolean val = curve->IsPeriodic();
return PyBool_FromLong(val ? 1 : 0);
}
PyObject* BSplineCurvePy::isClosed(PyObject *args) const
{
if (!PyArg_ParseTuple(args, ""))
return nullptr;
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
(getGeometryPtr()->handle());
Standard_Boolean val = curve->IsClosed();
return PyBool_FromLong(val ? 1 : 0);
}
PyObject* BSplineCurvePy::increaseDegree(PyObject * args)
{
int degree;
if (!PyArg_ParseTuple(args, "i", &degree))
return nullptr;
PY_TRY {
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
(getGeometryPtr()->handle());
curve->IncreaseDegree(degree);
Py_Return;
} PY_CATCH_OCC;
}
PyObject* BSplineCurvePy::increaseMultiplicity(PyObject * args)
{
int mult=-1;
int start, end;
if (!PyArg_ParseTuple(args, "ii|i", &start, &end, &mult))
return nullptr;
try {
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
(getGeometryPtr()->handle());
if (mult == -1) {
mult = end;
curve->IncreaseMultiplicity(start, mult);
}
else {
curve->IncreaseMultiplicity(start, end, mult);
}
Py_Return;
}
catch (Standard_Failure& e) {
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
return nullptr;
}
}
PyObject* BSplineCurvePy::incrementMultiplicity(PyObject * args)
{
int start, end, mult;
if (!PyArg_ParseTuple(args, "iii", &start, &end, &mult))
return nullptr;
try {
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
(getGeometryPtr()->handle());
curve->IncrementMultiplicity(start, end, mult);
}
catch (Standard_Failure& e) {
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
return nullptr;
}
Py_Return;
}
PyObject* BSplineCurvePy::insertKnot(PyObject * args)
{
double U, tol = 0.0;
int M=1;
PyObject* add = Py_True;
if (!PyArg_ParseTuple(args, "d|idO!", &U, &M, &tol, &PyBool_Type, &add))
return nullptr;
try {
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
(getGeometryPtr()->handle());
curve->InsertKnot(U, M, tol, Base::asBoolean(add));
}
catch (Standard_Failure& e) {
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
return nullptr;
}
Py_Return;
}
PyObject* BSplineCurvePy::insertKnots(PyObject * args)
{
double tol = 0.0;
PyObject* add = Py_True;
PyObject* obj1;
PyObject* obj2;
if (!PyArg_ParseTuple(args, "OO|dO!", &obj1,
&obj2,
&tol, &PyBool_Type, &add))
return nullptr;
try {
Py::Sequence knots(obj1);
TColStd_Array1OfReal k(1, knots.size());
int index=1;
for (Py::Sequence::iterator it = knots.begin(); it != knots.end(); ++it) {
Py::Float val(*it);
k(index++) = (double)val;
}
Py::Sequence mults(obj2);
TColStd_Array1OfInteger m(1, mults.size());
index=1;
for (Py::Sequence::iterator it = mults.begin(); it != mults.end(); ++it) {
Py::Long val(*it);
m(index++) = (int)val;
}
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
(getGeometryPtr()->handle());
curve->InsertKnots(k, m, tol, Base::asBoolean(add));
Py_Return;
}
catch (Standard_Failure& e) {
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
return nullptr;
}
Py_Return;
}
PyObject* BSplineCurvePy::removeKnot(PyObject * args)
{
double tol;
int Index, M;
if (!PyArg_ParseTuple(args, "iid", &Index, &M, &tol))
return nullptr;
try {
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
(getGeometryPtr()->handle());
Standard_Boolean ok = curve->RemoveKnot(Index, M, tol);
return PyBool_FromLong(ok ? 1 : 0);
}
catch (Standard_Failure& e) {
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
return nullptr;
}
}
PyObject* BSplineCurvePy::segment(PyObject * args)
{
double u1, u2;
if (!PyArg_ParseTuple(args, "dd", &u1, &u2))
return nullptr;
try {
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
(getGeometryPtr()->handle());
Handle(Geom_BSplineCurve) tempCurve = Handle(Geom_BSplineCurve)::DownCast
(curve->Copy());
tempCurve->Segment(u1, u2);
if (std::abs(tempCurve->FirstParameter()-u1) > Precision::Approximation() ||
std::abs(tempCurve->LastParameter()-u2) > Precision::Approximation()) {
Standard_Failure::Raise("Failed to segment BSpline curve");
return nullptr;
}
else {
curve->Segment(u1, u2);
}
Py_Return;
}
catch (Standard_Failure& e) {
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
return nullptr;
}
}
PyObject* BSplineCurvePy::setKnot(PyObject * args)
{
int Index, M=-1;
double K;
if (!PyArg_ParseTuple(args, "id|i", &Index, &K, &M))
return nullptr;
try {
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
(getGeometryPtr()->handle());
if (M == -1) {
curve->SetKnot(Index, K);
}
else {
curve->SetKnot(Index, K, M);
}
Py_Return;
}
catch (Standard_Failure& e) {
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
return nullptr;
}
}
PyObject* BSplineCurvePy::getKnot(PyObject * args) const
{
int Index;
if (!PyArg_ParseTuple(args, "i", &Index))
return nullptr;
try {
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
(getGeometryPtr()->handle());
double M = curve->Knot(Index);
return Py_BuildValue("d",M);
}
catch (Standard_Failure& e) {
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
return nullptr;
}
}
PyObject* BSplineCurvePy::setKnots(PyObject * args)
{
PyObject* obj;
if (!PyArg_ParseTuple(args, "O", &obj))
return nullptr;
try {
Py::Sequence list(obj);
TColStd_Array1OfReal k(1,list.size());
int index=1;
for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
Py::Float val(*it);
k(index++) = (double)val;
}
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
(getGeometryPtr()->handle());
curve->SetKnots(k);
Py_Return;
}
catch (Standard_Failure& e) {
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
return nullptr;
}
}
PyObject* BSplineCurvePy::getKnots(PyObject * args) const
{
if (!PyArg_ParseTuple(args, ""))
return nullptr;
try {
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
(getGeometryPtr()->handle());
TColStd_Array1OfReal w(1,curve->NbKnots());
curve->Knots(w);
Py::List knots;
for (Standard_Integer i=w.Lower(); i<=w.Upper(); i++) {
knots.append(Py::Float(w(i)));
}
return Py::new_reference_to(knots);
}
catch (Standard_Failure& e) {
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
return nullptr;
}
}
PyObject* BSplineCurvePy::setPole(PyObject * args)
{
int index;
double weight=-1.0;
PyObject* p;
if (!PyArg_ParseTuple(args, "iO!|d", &index, &(Base::VectorPy::Type), &p, &weight))
return nullptr;
Base::Vector3d vec = static_cast<Base::VectorPy*>(p)->value();
gp_Pnt pnt(vec.x, vec.y, vec.z);
try {
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
(getGeometryPtr()->handle());
if (weight < 0.0)
curve->SetPole(index,pnt);
else
curve->SetPole(index,pnt,weight);
Py_Return;
}
catch (Standard_Failure& e) {
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
return nullptr;
}
}
PyObject* BSplineCurvePy::getPole(PyObject * args) const
{
int index;
if (!PyArg_ParseTuple(args, "i", &index))
return nullptr;
try {
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
(getGeometryPtr()->handle());
Standard_OutOfRange_Raise_if
(index < 1 || index > curve->NbPoles(), "Pole index out of range");
gp_Pnt pnt = curve->Pole(index);
Base::VectorPy* vec = new Base::VectorPy(Base::Vector3d(
pnt.X(), pnt.Y(), pnt.Z()));
return vec;
}
catch (Standard_Failure& e) {
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
return nullptr;
}
}
PyObject* BSplineCurvePy::getPoles(PyObject * args) const
{
if (!PyArg_ParseTuple(args, ""))
return nullptr;
try {
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
(getGeometryPtr()->handle());
TColgp_Array1OfPnt p(1,curve->NbPoles());
curve->Poles(p);
Py::List poles;
for (Standard_Integer i=p.Lower(); i<=p.Upper(); i++) {
gp_Pnt pnt = p(i);
Base::VectorPy* vec = new Base::VectorPy(Base::Vector3d(
pnt.X(), pnt.Y(), pnt.Z()));
poles.append(Py::asObject(vec));
}
return Py::new_reference_to(poles);
}
catch (Standard_Failure& e) {
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
return nullptr;
}
}
PyObject* BSplineCurvePy::getPolesAndWeights(PyObject * args) const
{
if (!PyArg_ParseTuple(args, ""))
return nullptr;
try {
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
(getGeometryPtr()->handle());
TColgp_Array1OfPnt p(1,curve->NbPoles());
curve->Poles(p);
TColStd_Array1OfReal w(1,curve->NbPoles());
curve->Weights(w);
Py::List poles;
for (Standard_Integer i=p.Lower(); i<=p.Upper(); i++) {
gp_Pnt pnt = p(i);
double weight = w(i);
Py::Tuple t(4);
t.setItem(0, Py::Float(pnt.X()));
t.setItem(1, Py::Float(pnt.Y()));
t.setItem(2, Py::Float(pnt.Z()));
t.setItem(3, Py::Float(weight));
poles.append(t);
}
return Py::new_reference_to(poles);
}
catch (Standard_Failure& e) {
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
return nullptr;
}
}
PyObject* BSplineCurvePy::setWeight(PyObject * args)
{
int index;
double weight;
if (!PyArg_ParseTuple(args, "id", &index,&weight))
return nullptr;
try {
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
(getGeometryPtr()->handle());
curve->SetWeight(index,weight);
Py_Return;
}
catch (Standard_Failure& e) {
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
return nullptr;
}
}
PyObject* BSplineCurvePy::getWeight(PyObject * args) const
{
int index;
if (!PyArg_ParseTuple(args, "i", &index))
return nullptr;
try {
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
(getGeometryPtr()->handle());
Standard_OutOfRange_Raise_if
(index < 1 || index > curve->NbPoles() , "Weight index out of range");
double weight = curve->Weight(index);
return Py_BuildValue("d", weight);
}
catch (Standard_Failure& e) {
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
return nullptr;
}
}
PyObject* BSplineCurvePy::getWeights(PyObject * args) const
{
if (!PyArg_ParseTuple(args, ""))
return nullptr;
try {
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
(getGeometryPtr()->handle());
TColStd_Array1OfReal w(1,curve->NbPoles());
curve->Weights(w);
Py::List weights;
for (Standard_Integer i=w.Lower(); i<=w.Upper(); i++) {
weights.append(Py::Float(w(i)));
}
return Py::new_reference_to(weights);
}
catch (Standard_Failure& e) {
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
return nullptr;
}
}
PyObject* BSplineCurvePy::getResolution(PyObject * args) const
{
double tol;
if (!PyArg_ParseTuple(args, "d", &tol))
return nullptr;
try {
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
(getGeometryPtr()->handle());
double utol;
curve->Resolution(tol,utol);
return Py_BuildValue("d",utol);
}
catch (Standard_Failure& e) {
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
return nullptr;
}
}
PyObject* BSplineCurvePy::movePoint(PyObject * args)
{
double U;
int index1, index2;
PyObject* pnt;
if (!PyArg_ParseTuple(args, "dO!ii", &U, &(Base::VectorPy::Type),&pnt, &index1, &index2))
return nullptr;
try {
Base::Vector3d p = static_cast<Base::VectorPy*>(pnt)->value();
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
(getGeometryPtr()->handle());
int first, last;
curve->MovePoint(U, gp_Pnt(p.x,p.y,p.z), index1, index2, first, last);
return Py_BuildValue("(ii)",first, last);
}
catch (Standard_Failure& e) {
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
return nullptr;
}
}
PyObject* BSplineCurvePy::setNotPeriodic(PyObject * args)
{
if (!PyArg_ParseTuple(args, ""))
return nullptr;
try {
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
(getGeometryPtr()->handle());
curve->SetNotPeriodic();
Py_Return;
}
catch (Standard_Failure& e) {
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
return nullptr;
}
}
PyObject* BSplineCurvePy::setPeriodic(PyObject * args)
{
if (!PyArg_ParseTuple(args, ""))
return nullptr;
try {
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
(getGeometryPtr()->handle());
curve->SetPeriodic();
Py_Return;
}
catch (Standard_Failure& e) {
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
return nullptr;
}
}
PyObject* BSplineCurvePy::setOrigin(PyObject * args)
{
int index;
if (!PyArg_ParseTuple(args, "i", &index))
return nullptr;
try {
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
(getGeometryPtr()->handle());
curve->SetOrigin(index);
Py_Return;
}
catch (Standard_Failure& e) {
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
return nullptr;
}
}
PyObject* BSplineCurvePy::getMultiplicity(PyObject * args) const
{
int index;
if (!PyArg_ParseTuple(args, "i", &index))
return nullptr;
try {
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
(getGeometryPtr()->handle());
int mult = curve->Multiplicity(index);
return Py_BuildValue("i", mult);
}
catch (Standard_Failure& e) {
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
return nullptr;
}
}
PyObject* BSplineCurvePy::getMultiplicities(PyObject * args) const
{
if (!PyArg_ParseTuple(args, ""))
return nullptr;
try {
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
(getGeometryPtr()->handle());
TColStd_Array1OfInteger m(1,curve->NbKnots());
curve->Multiplicities(m);
Py::List mults;
for (Standard_Integer i=m.Lower(); i<=m.Upper(); i++) {
mults.append(Py::Long(m(i)));
}
return Py::new_reference_to(mults);
}
catch (Standard_Failure& e) {
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
return nullptr;
}
}
Py::Long BSplineCurvePy::getDegree() const
{
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
(getGeometryPtr()->handle());
return Py::Long(curve->Degree());
}
Py::Long BSplineCurvePy::getMaxDegree() const
{
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
(getGeometryPtr()->handle());
return Py::Long(curve->MaxDegree());
}
Py::Long BSplineCurvePy::getNbPoles() const
{
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
(getGeometryPtr()->handle());
return Py::Long(curve->NbPoles());
}
Py::Long BSplineCurvePy::getNbKnots() const
{
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
(getGeometryPtr()->handle());
return Py::Long(curve->NbKnots());
}
Py::Object BSplineCurvePy::getStartPoint() const
{
Handle(Geom_BSplineCurve) c = Handle(Geom_BSplineCurve)::DownCast
(getGeometryPtr()->handle());
gp_Pnt pnt = c->StartPoint();
return Py::Vector(Base::Vector3d(pnt.X(), pnt.Y(), pnt.Z()));
}
Py::Object BSplineCurvePy::getEndPoint() const
{
Handle(Geom_BSplineCurve) c = Handle(Geom_BSplineCurve)::DownCast
(getGeometryPtr()->handle());
gp_Pnt pnt = c->EndPoint();
return Py::Vector(Base::Vector3d(pnt.X(), pnt.Y(), pnt.Z()));
}
Py::Long BSplineCurvePy::getFirstUKnotIndex() const
{
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
(getGeometryPtr()->handle());
return Py::Long(curve->FirstUKnotIndex());
}
Py::Long BSplineCurvePy::getLastUKnotIndex() const
{
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
(getGeometryPtr()->handle());
return Py::Long(curve->LastUKnotIndex());
}
Py::List BSplineCurvePy::getKnotSequence() const
{
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
(getGeometryPtr()->handle());
Standard_Integer m = 0;
if (curve->IsPeriodic()) {
// knots=poles+2*degree-mult(1)+2
m = curve->NbPoles() + 2*curve->Degree() - curve->Multiplicity(1) + 2;
}
else {
// knots=poles+degree+1
for (int i=1; i<= curve->NbKnots(); i++)
m += curve->Multiplicity(i);
}
TColStd_Array1OfReal k(1,m);
curve->KnotSequence(k);
Py::List list;
for (Standard_Integer i=k.Lower(); i<=k.Upper(); i++) {
list.append(Py::Float(k(i)));
}
return list;
}
PyObject* BSplineCurvePy::toBiArcs(PyObject * args) const
{
double tolerance = 0.001;
if (!PyArg_ParseTuple(args, "d", &tolerance))
return nullptr;
try {
GeomBSplineCurve* curve = getGeomBSplineCurvePtr();
std::list<Geometry*> arcs;
arcs = curve->toBiArcs(tolerance);
Py::List list;
for (auto arc : arcs) {
list.append(Py::asObject(arc->getPyObject()));
delete arc;
}
return Py::new_reference_to(list);
}
catch (Standard_Failure& e) {
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
return nullptr;
}
}
PyObject* BSplineCurvePy::approximate(PyObject *args, PyObject *kwds)
{
PyObject *obj;
Standard_Integer degMin = 3;
Standard_Integer degMax = 8;
Standard_Integer segMax = 8;
const char *continuity = "C2";
double tol3d = 1e-3;
const char *parType = "ChordLength";
PyObject *par = nullptr;
double weight1 = 0;
double weight2 = 0;
double weight3 = 0;
// Approximate this curve with a given continuity and degree
static const std::array<const char *, 5> kwds_reapprox{"MaxDegree", "MaxSegments", "Continuity", "Tolerance",
nullptr};
if (Base::Wrapped_ParseTupleAndKeywords(args, kwds, "i|isd", kwds_reapprox,
&tol3d, &degMax, &segMax, &continuity)) {
GeomAbs_Shape c;
std::string str = continuity;
if (str == "C0")
c = GeomAbs_C0;
else if (str == "G1")
c = GeomAbs_G1;
else if (str == "C1")
c = GeomAbs_C1;
else if (str == "G2")
c = GeomAbs_G2;
else if (str == "C2")
c = GeomAbs_C2;
else if (str == "C3")
c = GeomAbs_C3;
else if (str == "CN")
c = GeomAbs_CN;
else
c = GeomAbs_C2;
this->getGeomBSplineCurvePtr()->approximate(tol3d, segMax, degMax, c);
Py_Return;
}
// Approximate a list of points
//
static const std::array<const char *, 11> kwds_interp{"Points", "DegMax", "Continuity", "Tolerance", "DegMin",
"ParamType", "Parameters", "LengthWeight", "CurvatureWeight",
"TorsionWeight", nullptr};
PyErr_Clear();
if (!Base::Wrapped_ParseTupleAndKeywords(args, kwds, "O|isdisOddd", kwds_interp,
&obj, &degMax,
&continuity, &tol3d, &degMin,
&parType, &par,
&weight1, &weight2, &weight3)) {
return nullptr;
}
try {
Py::Sequence list(obj);
TColgp_Array1OfPnt pnts(1, list.size());
Standard_Integer index = 1;
for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
Base::Vector3d vec = Py::Vector(*it).toVector();
pnts(index++) = gp_Pnt(vec.x,vec.y,vec.z);
}
if (degMin > degMax) {
Standard_Failure::Raise("DegMin must be lower or equal to DegMax");
}
GeomAbs_Shape c;
std::string str = continuity;
if (str == "C0")
c = GeomAbs_C0;
else if (str == "G1")
c = GeomAbs_G1;
else if (str == "C1")
c = GeomAbs_C1;
else if (str == "G2")
c = GeomAbs_G2;
else if (str == "C2")
c = GeomAbs_C2;
else if (str == "C3")
c = GeomAbs_C3;
else if (str == "CN")
c = GeomAbs_CN;
else
c = GeomAbs_C2;
if (weight1 || weight2 || weight3) {
// It seems that this function only works with Continuity = C0, C1 or C2
GeomAPI_PointsToBSpline fit(pnts, weight1, weight2, weight3, degMax, c, tol3d);
Handle(Geom_BSplineCurve) spline = fit.Curve();
if (!spline.IsNull()) {
this->getGeomBSplineCurvePtr()->setHandle(spline);
Py_Return;
}
else {
Standard_Failure::Raise("Smoothing approximation failed");
return nullptr; // goes to the catch block
}
}
if (par) {
Py::Sequence plist(par);
TColStd_Array1OfReal parameters(1,plist.size());
Standard_Integer index = 1;
for (Py::Sequence::iterator it = plist.begin(); it != plist.end(); ++it) {
Py::Float f(*it);
parameters(index++) = static_cast<double>(f);
}
GeomAPI_PointsToBSpline fit(pnts, parameters, degMin, degMax, c, tol3d);
Handle(Geom_BSplineCurve) spline = fit.Curve();
if (!spline.IsNull()) {
this->getGeomBSplineCurvePtr()->setHandle(spline);
Py_Return;
}
else {
Standard_Failure::Raise("Approximation with parameters failed");
return nullptr; // goes to the catch block
}
}
Approx_ParametrizationType pt;
std::string pstr = parType;
if (pstr == "Uniform")
pt = Approx_IsoParametric;
else if (pstr == "Centripetal")
pt = Approx_Centripetal;
else
pt = Approx_ChordLength;
GeomAPI_PointsToBSpline fit(pnts, pt, degMin, degMax, c, tol3d);
Handle(Geom_BSplineCurve) spline = fit.Curve();
if (!spline.IsNull()) {
this->getGeomBSplineCurvePtr()->setHandle(spline);
Py_Return;
}
else {
Standard_Failure::Raise("failed to approximate points");
return nullptr; // goes to the catch block
}
}
catch (Standard_Failure& e) {
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
return nullptr;
}
}
PyObject* BSplineCurvePy::getCardinalSplineTangents(PyObject *args, PyObject *kwds) const
{
PyObject* pts;
PyObject* tgs;
double parameter;
static const std::array<const char *, 3> kwds_interp1 {"Points", "Parameter", nullptr};
if (Base::Wrapped_ParseTupleAndKeywords(args, kwds, "Od",kwds_interp1, &pts, &parameter)) {
Py::Sequence list(pts);
std::vector<gp_Pnt> interpPoints;
interpPoints.reserve(list.size());
for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
Py::Vector v(*it);
Base::Vector3d pnt = v.toVector();
interpPoints.emplace_back(pnt.x,pnt.y,pnt.z);
}
GeomBSplineCurve* bspline = this->getGeomBSplineCurvePtr();
std::vector<gp_Vec> tangents;
bspline->getCardinalSplineTangents(interpPoints, parameter, tangents);
Py::List vec;
for (gp_Vec it : tangents)
vec.append(Py::Vector(Base::Vector3d(it.X(), it.Y(), it.Z())));
return Py::new_reference_to(vec);
}
PyErr_Clear();
static const std::array<const char *, 3> kwds_interp2 {"Points", "Parameters", nullptr};
if (Base::Wrapped_ParseTupleAndKeywords(args, kwds, "OO",kwds_interp2, &pts, &tgs)) {
Py::Sequence list(pts);
std::vector<gp_Pnt> interpPoints;
interpPoints.reserve(list.size());
for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
Py::Vector v(*it);
Base::Vector3d pnt = v.toVector();
interpPoints.emplace_back(pnt.x,pnt.y,pnt.z);
}
Py::Sequence list2(tgs);
std::vector<double> parameters;
parameters.reserve(list2.size());
for (Py::Sequence::iterator it = list2.begin(); it != list2.end(); ++it) {
Py::Float p(*it);
parameters.push_back(static_cast<double>(p));
}
GeomBSplineCurve* bspline = this->getGeomBSplineCurvePtr();
std::vector<gp_Vec> tangents;
bspline->getCardinalSplineTangents(interpPoints, parameters, tangents);
Py::List vec;
for (gp_Vec it : tangents)
vec.append(Py::Vector(Base::Vector3d(it.X(), it.Y(), it.Z())));
return Py::new_reference_to(vec);
}
return nullptr;
}
PyObject* BSplineCurvePy::interpolate(PyObject *args, PyObject *kwds)
{
PyObject* obj;
PyObject* par = nullptr;
double tol3d = Precision::Approximation();
PyObject* periodic = Py_False;
PyObject* t1 = nullptr; PyObject* t2 = nullptr;
PyObject* ts = nullptr; PyObject* fl = nullptr;
PyObject* scale = Py_True;
static const std::array<const char *, 10> kwds_interp{"Points", "PeriodicFlag", "Tolerance", "InitialTangent",
"FinalTangent", "Tangents", "TangentFlags", "Parameters",
"Scale", nullptr};
if (!Base::Wrapped_ParseTupleAndKeywords(args, kwds, "O|O!dO!O!OOOO!", kwds_interp,
&obj, &PyBool_Type, &periodic, &tol3d,
&Base::VectorPy::Type, &t1,
&Base::VectorPy::Type, &t2,
&ts, &fl, &par, &PyBool_Type, &scale)) {
return nullptr;
}
try {
Py::Sequence list(obj);
Handle(TColgp_HArray1OfPnt) interpolationPoints = new TColgp_HArray1OfPnt(1, list.size());
Standard_Integer index = 1;
for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
Py::Vector v(*it);
Base::Vector3d pnt = v.toVector();
interpolationPoints->SetValue(index++, gp_Pnt(pnt.x,pnt.y,pnt.z));
}
if (interpolationPoints->Length() < 2) {
Standard_Failure::Raise("not enough points given");
}
Handle(TColStd_HArray1OfReal) parameters;
if (par) {
Py::Sequence plist(par);
parameters = new TColStd_HArray1OfReal(1, plist.size());
Standard_Integer pindex = 1;
for (Py::Sequence::iterator it = plist.begin(); it != plist.end(); ++it) {
Py::Float f(*it);
parameters->SetValue(pindex++, static_cast<double>(f));
}
}
std::unique_ptr<GeomAPI_Interpolate> aBSplineInterpolation;
if (parameters.IsNull()) {
aBSplineInterpolation = std::make_unique<GeomAPI_Interpolate>(interpolationPoints,
Base::asBoolean(periodic), tol3d);
}
else {
aBSplineInterpolation = std::make_unique<GeomAPI_Interpolate>(interpolationPoints, parameters,
Base::asBoolean(periodic), tol3d);
}
if (t1 && t2) {
Base::Vector3d v1 = Py::Vector(t1,false).toVector();
Base::Vector3d v2 = Py::Vector(t2,false).toVector();
gp_Vec initTangent(v1.x,v1.y,v1.z), finalTangent(v2.x,v2.y,v2.z);
aBSplineInterpolation->Load(initTangent, finalTangent, Base::asBoolean(scale));
}
else if (ts && fl) {
Py::Sequence tlist(ts);
TColgp_Array1OfVec tangents(1, tlist.size());
Standard_Integer index = 1;
for (Py::Sequence::iterator it = tlist.begin(); it != tlist.end(); ++it) {
Py::Vector v(*it);
Base::Vector3d vec = v.toVector();
tangents.SetValue(index++, gp_Vec(vec.x,vec.y,vec.z));
}
Py::Sequence flist(fl);
Handle(TColStd_HArray1OfBoolean) tangentFlags = new TColStd_HArray1OfBoolean(1, flist.size());
Standard_Integer findex = 1;
for (Py::Sequence::iterator it = flist.begin(); it != flist.end(); ++it) {
Py::Boolean flag(*it);
tangentFlags->SetValue(findex++, static_cast<bool>(flag) ? Standard_True : Standard_False);
}
aBSplineInterpolation->Load(tangents, tangentFlags, Base::asBoolean(scale));
}
aBSplineInterpolation->Perform();
if (aBSplineInterpolation->IsDone()) {
Handle(Geom_BSplineCurve) aBSplineCurve(aBSplineInterpolation->Curve());
this->getGeomBSplineCurvePtr()->setHandle(aBSplineCurve);
Py_Return;
}
else {
Standard_Failure::Raise("failed to interpolate points");
return nullptr; // goes to the catch block
}
}
catch (Standard_Failure& e) {
std::string err = e.GetMessageString();
if (err.empty()) err = e.DynamicType()->Name();
PyErr_SetString(PartExceptionOCCError, err.c_str());
return nullptr;
}
}
PyObject* BSplineCurvePy::buildFromPoles(PyObject *args)
{
PyObject* obj;
int degree = 3;
PyObject* periodic = Py_False;
PyObject* interpolate = Py_False;
if (!PyArg_ParseTuple(args, "O|O!iO!",&obj, &PyBool_Type, &periodic, &degree, &PyBool_Type, interpolate))
return nullptr;
try {
Py::Sequence list(obj);
TColgp_Array1OfPnt poles(1, list.size());
Standard_Integer index = 1;
for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
Py::Vector v(*it);
Base::Vector3d pnt = v.toVector();
poles(index++) = gp_Pnt(pnt.x,pnt.y,pnt.z);
}
if (poles.Length() <= degree)
degree = poles.Length()-1;
if (Base::asBoolean(periodic)) {
int mult;
int len;
if (Base::asBoolean(interpolate)) {
mult = degree;
len = poles.Length() - mult + 2;
}
else {
mult = 1;
len = poles.Length() + 1;
}
TColStd_Array1OfReal knots(1, len);
TColStd_Array1OfInteger mults(1, len);
for (int i=1; i<=knots.Length(); i++){
knots.SetValue(i,(double)(i-1)/(knots.Length()-1));
mults.SetValue(i,1);
}
mults.SetValue(1, mult);
mults.SetValue(knots.Length(), mult);
Handle(Geom_BSplineCurve) spline = new Geom_BSplineCurve(poles, knots, mults, degree, Standard_True);
if (!spline.IsNull()) {
this->getGeomBSplineCurvePtr()->setHandle(spline);
Py_Return;
}
else {
Standard_Failure::Raise("failed to create spline");
return nullptr; // goes to the catch block
}
}
else {
TColStd_Array1OfReal knots(1, poles.Length()+degree+1-2*(degree));
TColStd_Array1OfInteger mults(1, poles.Length()+degree+1-2*(degree));
for (int i=1; i<=knots.Length(); i++){
knots.SetValue(i,(double)(i-1)/(knots.Length()-1));
mults.SetValue(i,1);
}
mults.SetValue(1, degree+1);
mults.SetValue(knots.Length(), degree+1);
Handle(Geom_BSplineCurve) spline = new Geom_BSplineCurve(poles, knots, mults, degree, Standard_False);
if (!spline.IsNull()) {
this->getGeomBSplineCurvePtr()->setHandle(spline);
Py_Return;
}
else {
Standard_Failure::Raise("failed to create spline");
return nullptr; // goes to the catch block
}
}
}
catch (Standard_Failure& e) {
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
return nullptr;
}
}
PyObject* BSplineCurvePy::buildFromPolesMultsKnots(PyObject *args, PyObject *keywds)
{
static const std::array<const char *, 8> kwlist{"poles", "mults", "knots", "periodic", "degree", "weights",
"CheckRational", nullptr};
PyObject* periodic = Py_False; // NOLINT
PyObject* CheckRational = Py_True; // NOLINT
PyObject* poles = Py_None;
PyObject* mults = Py_None;
PyObject* knots = Py_None;
PyObject* weights = Py_None;
int degree = 3;
int number_of_poles = 0;
int number_of_knots = 0;
int sum_of_mults = 0;
if (!Base::Wrapped_ParseTupleAndKeywords(args, keywds, "O|OOO!iOO!", kwlist,
&poles, &mults, &knots,
&PyBool_Type, &periodic,
&degree, &weights,
&PyBool_Type, &CheckRational)) {
return nullptr;
}
try {
// poles have to be present
Py::Sequence list(poles);
number_of_poles = list.size();
if ((number_of_poles) < 2) {
Standard_Failure::Raise("need two or more poles");
return nullptr;
}
TColgp_Array1OfPnt occpoles(1, number_of_poles);
Standard_Integer index = 1;
for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
Py::Vector v(*it);
Base::Vector3d pnt = v.toVector();
occpoles(index++) = gp_Pnt(pnt.x,pnt.y,pnt.z);
}
//Calculate the number of knots
if (mults != Py_None && knots != Py_None) {
number_of_knots = PyObject_Length(mults);
if (PyObject_Length(knots) != number_of_knots) {
Standard_Failure::Raise("number of knots and mults mismatch");
return nullptr;
}
}
else {
if (mults != Py_None) {
number_of_knots = PyObject_Length(mults);
}
else {
if (knots != Py_None) { number_of_knots = PyObject_Length(knots); }
else { //guess number of knots
if (Base::asBoolean(periodic)) {
if (number_of_poles < degree) {degree = number_of_poles;}
number_of_knots = number_of_poles+1;
}
else {
if (number_of_poles <= degree) {degree = number_of_poles-1;}
number_of_knots = number_of_poles-degree+1;
}
}
}
}
TColStd_Array1OfInteger occmults(1,number_of_knots);
TColStd_Array1OfReal occknots(1,number_of_knots);
TColStd_Array1OfReal occweights(1,number_of_poles);
if (mults != Py_None) { //mults are given
Py::Sequence multssq(mults);
Standard_Integer index = 1;
for (Py::Sequence::iterator it = multssq.begin(); it != multssq.end() && index <= occmults.Length(); ++it) {
Py::Long mult(*it);
if (index < occmults.Length() || !Base::asBoolean(periodic)) {
sum_of_mults += static_cast<int>(mult); //sum up the mults to compare them against the number of poles later
}
occmults(index++) = static_cast<int>(mult);
}
}
else { //mults are 1 or degree+1 at the ends
for (int i=1; i<=occmults.Length(); i++){
occmults.SetValue(i,1);
}
if (!Base::asBoolean(periodic) && occmults.Length() > 0) {
occmults.SetValue(1, degree+1);
occmults.SetValue(occmults.Length(), degree+1);
sum_of_mults = occmults.Length()+2*degree;
}
else {
sum_of_mults = occmults.Length()-1;
}
}
// check multiplicity of inner knots
for (Standard_Integer i=2; i < occmults.Length(); i++) {
if (occmults(i) > degree) {
Standard_Failure::Raise("multiplicity of inner knot higher than degree");
}
}
if (knots != Py_None) { //knots are given
Py::Sequence knotssq(knots);
index = 1;
for (Py::Sequence::iterator it = knotssq.begin(); it != knotssq.end() && index <= occknots.Length(); ++it) {
Py::Float knot(*it);
occknots(index++) = knot;
}
}
else { // knotes are uniformly spaced 0..1 if not given
for (int i=1; i<=occknots.Length(); i++){
occknots.SetValue(i,(double)(i-1)/(occknots.Length()-1));
}
}
if (weights != Py_None) { //weights are given
if (PyObject_Length(weights) != number_of_poles) {
Standard_Failure::Raise("number of poles and weights mismatch");
return nullptr;
} //complain about mismatch
Py::Sequence weightssq(weights);
Standard_Integer index = 1;
for (Py::Sequence::iterator it = weightssq.begin(); it != weightssq.end(); ++it) {
Py::Float weight(*it);
occweights(index++) = weight;
}
}
else { // weights are 1.0
for (int i=1; i<=occweights.Length(); i++){
occweights.SetValue(i,1.0);
}
}
// check if the number of poles matches the sum of mults
if ((Base::asBoolean(periodic) && sum_of_mults != number_of_poles) ||
(!Base::asBoolean(periodic) && sum_of_mults - degree -1 != number_of_poles)) {
Standard_Failure::Raise("number of poles and sum of mults mismatch");
return(nullptr);
}
Handle(Geom_BSplineCurve) spline = new Geom_BSplineCurve(occpoles,occweights,occknots,occmults,degree,
Base::asBoolean(periodic), Base::asBoolean(CheckRational));
if (!spline.IsNull()) {
this->getGeomBSplineCurvePtr()->setHandle(spline);
Py_Return;
}
else {
Standard_Failure::Raise("failed to create spline");
return nullptr; // goes to the catch block
}
}
catch (const Standard_Failure& e) {
Standard_CString msg = e.GetMessageString();
PyErr_SetString(PartExceptionOCCError, msg ? msg : "");
return nullptr;
}
}
PyObject* BSplineCurvePy::toBezier(PyObject *args) const
{
if (!PyArg_ParseTuple(args, ""))
return nullptr;
try {
Handle(Geom_BSplineCurve) spline = Handle(Geom_BSplineCurve)::DownCast
(this->getGeomBSplineCurvePtr()->handle());
GeomConvert_BSplineCurveToBezierCurve crt(spline);
Py::List list;
Standard_Integer arcs = crt.NbArcs();
for (Standard_Integer i=1; i<=arcs; i++) {
Handle(Geom_BezierCurve) bezier = crt.Arc(i);
list.append(Py::asObject(new BezierCurvePy(new GeomBezierCurve(bezier))));
}
return Py::new_reference_to(list);
}
catch (Standard_Failure& e) {
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
return nullptr;
}
}
PyObject* BSplineCurvePy::join(PyObject *args)
{
PyObject* c;
if (!PyArg_ParseTuple(args, "O!", &BSplineCurvePy::Type, &c))
return nullptr;
try {
GeomBSplineCurve* curve1 = this->getGeomBSplineCurvePtr();
BSplineCurvePy* curve2 = static_cast<BSplineCurvePy*>(c);
Handle(Geom_BSplineCurve) spline = Handle(Geom_BSplineCurve)::DownCast
(curve2->getGeomBSplineCurvePtr()->handle());
bool ok = curve1->join(spline);
return PyBool_FromLong(ok ? 1 : 0);
}
catch (Standard_Failure& e) {
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
return nullptr;
}
}
PyObject* BSplineCurvePy::makeC1Continuous(PyObject *args)
{
double tol = Precision::Approximation();
double ang_tol = 1.0e-7;
if (!PyArg_ParseTuple(args, "|dd", &tol, &ang_tol))
return nullptr;
try {
GeomBSplineCurve* spline = this->getGeomBSplineCurvePtr();
spline->makeC1Continuous(tol, ang_tol);
Py_Return;
}
catch (Standard_Failure& e) {
std::string err = e.GetMessageString();
if (err.empty()) err = e.DynamicType()->Name();
PyErr_SetString(PartExceptionOCCError, err.c_str());
return nullptr;
}
}
PyObject* BSplineCurvePy::scaleKnotsToBounds(PyObject *args)
{
double u0=0.0;
double u1=1.0;
if (!PyArg_ParseTuple(args, "|dd", &u0, &u1))
return nullptr;
try {
if (u0 >= u1) {
Standard_Failure::Raise("Bad parameter range");
return nullptr;
}
GeomBSplineCurve* curve = getGeomBSplineCurvePtr();
curve->scaleKnotsToBounds(u0, u1);
Py_Return;
}
catch (Standard_Failure& e) {
std::string err = e.GetMessageString();
if (err.empty()) err = e.DynamicType()->Name();
PyErr_SetString(PartExceptionOCCError, err.c_str());
return nullptr;
}
}
PyObject* BSplineCurvePy::getCustomAttributes(const char* /*attr*/) const
{
return nullptr;
}
int BSplineCurvePy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
{
return 0;
}