1
/***************************************************************************
2
* Copyright (c) 2008 Werner Mayer <wmayer[at]users.sourceforge.net> *
4
* This file is part of the FreeCAD CAx development system. *
6
* This library is free software; you can redistribute it and/or *
7
* modify it under the terms of the GNU Library General Public *
8
* License as published by the Free Software Foundation; either *
9
* version 2 of the License, or (at your option) any later version. *
11
* This library is distributed in the hope that it will be useful, *
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14
* GNU Library General Public License for more details. *
16
* You should have received a copy of the GNU Library General Public *
17
* License along with this library; see the file COPYING.LIB. If not, *
18
* write to the Free Software Foundation, Inc., 59 Temple Place, *
19
* Suite 330, Boston, MA 02111-1307, USA *
21
***************************************************************************/
23
#include "PreCompiled.h"
26
# include <Geom_BSplineCurve.hxx>
27
# include <GeomAPI_Interpolate.hxx>
28
# include <GeomAPI_PointsToBSpline.hxx>
29
# include <GeomConvert_BSplineCurveToBezierCurve.hxx>
31
# include <Precision.hxx>
32
# include <TColgp_Array1OfPnt.hxx>
33
# include <TColgp_Array1OfVec.hxx>
34
# include <TColgp_HArray1OfPnt.hxx>
35
# include <TColStd_Array1OfInteger.hxx>
36
# include <TColStd_Array1OfReal.hxx>
37
# include <TColStd_HArray1OfBoolean.hxx>
38
# include <TColStd_HArray1OfReal.hxx>
41
#include <Base/GeometryPyCXX.h>
42
#include <Base/PyWrapParseTupleAndKeywords.h>
43
#include <Base/VectorPy.h>
45
#include "BSplineCurvePy.h"
46
#include "BSplineCurvePy.cpp"
47
#include "BezierCurvePy.h"
53
// returns a string which represents the object e.g. when printed in python
54
std::string BSplineCurvePy::representation() const
56
return "<BSplineCurve object>";
59
PyObject *BSplineCurvePy::PyMake(struct _typeobject *, PyObject *, PyObject *) // Python wrapper
61
// create a new instance of BSplineCurvePy and the Twin object
62
return new BSplineCurvePy(new GeomBSplineCurve);
66
int BSplineCurvePy::PyInit(PyObject* args, PyObject* kwd)
68
if (PyArg_ParseTuple(args, "")) {
74
// poles, [ periodic, degree, interpolate ]
75
// {"poles", "mults", "knots", "periodic", "degree", "weights", "CheckRational", NULL};
76
obj = buildFromPolesMultsKnots(args, kwd);
82
else if (PyErr_ExceptionMatches(PartExceptionOCCError)) {
86
PyErr_SetString(PyExc_TypeError, "B-spline constructor accepts:\n"
87
"-- poles, [ periodic, degree, interpolate ]\n"
88
"-- empty parameter list\n");
92
PyObject* BSplineCurvePy::__reduce__(PyObject *args)
94
if (!PyArg_ParseTuple(args, ""))
99
// type object to create an instance
100
Py::Object type(Base::getTypeAsObject(&BSplineCurvePy::Type));
101
tuple.setItem(0, type);
103
// create an argument tuple to create a copy
104
Py::Object self(this);
106
data.setItem(0, Py::Callable(self.getAttr("getPoles")).apply());
107
data.setItem(1, Py::Callable(self.getAttr("getMultiplicities")).apply());
108
data.setItem(2, Py::Callable(self.getAttr("getKnots")).apply());
109
data.setItem(3, Py::Callable(self.getAttr("isPeriodic")).apply());
110
data.setItem(4, self.getAttr("Degree"));
111
data.setItem(5, Py::Callable(self.getAttr("getWeights")).apply());
112
data.setItem(6, Py::Callable(self.getAttr("isRational")).apply());
113
tuple.setItem(1, data);
115
return Py::new_reference_to(tuple);
118
PyObject* BSplineCurvePy::isRational(PyObject *args)
120
if (!PyArg_ParseTuple(args, ""))
122
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
123
(getGeometryPtr()->handle());
124
Standard_Boolean val = curve->IsRational();
125
return PyBool_FromLong(val ? 1 : 0);
128
PyObject* BSplineCurvePy::isPeriodic(PyObject *args)
130
if (!PyArg_ParseTuple(args, ""))
132
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
133
(getGeometryPtr()->handle());
134
Standard_Boolean val = curve->IsPeriodic();
135
return PyBool_FromLong(val ? 1 : 0);
138
PyObject* BSplineCurvePy::isClosed(PyObject *args)
140
if (!PyArg_ParseTuple(args, ""))
142
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
143
(getGeometryPtr()->handle());
144
Standard_Boolean val = curve->IsClosed();
145
return PyBool_FromLong(val ? 1 : 0);
148
PyObject* BSplineCurvePy::increaseDegree(PyObject * args)
151
if (!PyArg_ParseTuple(args, "i", °ree))
154
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
155
(getGeometryPtr()->handle());
156
curve->IncreaseDegree(degree);
161
PyObject* BSplineCurvePy::increaseMultiplicity(PyObject * args)
165
if (!PyArg_ParseTuple(args, "ii|i", &start, &end, &mult))
169
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
170
(getGeometryPtr()->handle());
173
curve->IncreaseMultiplicity(start, mult);
176
curve->IncreaseMultiplicity(start, end, mult);
181
catch (Standard_Failure& e) {
182
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
187
PyObject* BSplineCurvePy::incrementMultiplicity(PyObject * args)
189
int start, end, mult;
190
if (!PyArg_ParseTuple(args, "iii", &start, &end, &mult))
194
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
195
(getGeometryPtr()->handle());
196
curve->IncrementMultiplicity(start, end, mult);
198
catch (Standard_Failure& e) {
199
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
206
PyObject* BSplineCurvePy::insertKnot(PyObject * args)
210
PyObject* add = Py_True;
211
if (!PyArg_ParseTuple(args, "d|idO!", &U, &M, &tol, &PyBool_Type, &add))
215
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
216
(getGeometryPtr()->handle());
217
curve->InsertKnot(U, M, tol, Base::asBoolean(add));
219
catch (Standard_Failure& e) {
220
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
227
PyObject* BSplineCurvePy::insertKnots(PyObject * args)
230
PyObject* add = Py_True;
233
if (!PyArg_ParseTuple(args, "OO|dO!", &obj1,
235
&tol, &PyBool_Type, &add))
239
Py::Sequence knots(obj1);
240
TColStd_Array1OfReal k(1, knots.size());
242
for (Py::Sequence::iterator it = knots.begin(); it != knots.end(); ++it) {
244
k(index++) = (double)val;
246
Py::Sequence mults(obj2);
247
TColStd_Array1OfInteger m(1, mults.size());
249
for (Py::Sequence::iterator it = mults.begin(); it != mults.end(); ++it) {
251
m(index++) = (int)val;
254
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
255
(getGeometryPtr()->handle());
256
curve->InsertKnots(k, m, tol, Base::asBoolean(add));
259
catch (Standard_Failure& e) {
260
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
267
PyObject* BSplineCurvePy::removeKnot(PyObject * args)
271
if (!PyArg_ParseTuple(args, "iid", &Index, &M, &tol))
275
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
276
(getGeometryPtr()->handle());
277
Standard_Boolean ok = curve->RemoveKnot(Index, M, tol);
278
return PyBool_FromLong(ok ? 1 : 0);
280
catch (Standard_Failure& e) {
281
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
286
PyObject* BSplineCurvePy::segment(PyObject * args)
289
if (!PyArg_ParseTuple(args, "dd", &u1, &u2))
292
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
293
(getGeometryPtr()->handle());
294
Handle(Geom_BSplineCurve) tempCurve = Handle(Geom_BSplineCurve)::DownCast
296
tempCurve->Segment(u1, u2);
297
if (std::abs(tempCurve->FirstParameter()-u1) > Precision::Approximation() ||
298
std::abs(tempCurve->LastParameter()-u2) > Precision::Approximation()) {
299
Standard_Failure::Raise("Failed to segment BSpline curve");
303
curve->Segment(u1, u2);
307
catch (Standard_Failure& e) {
308
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
313
PyObject* BSplineCurvePy::setKnot(PyObject * args)
317
if (!PyArg_ParseTuple(args, "id|i", &Index, &K, &M))
321
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
322
(getGeometryPtr()->handle());
324
curve->SetKnot(Index, K);
327
curve->SetKnot(Index, K, M);
332
catch (Standard_Failure& e) {
333
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
338
PyObject* BSplineCurvePy::getKnot(PyObject * args)
341
if (!PyArg_ParseTuple(args, "i", &Index))
345
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
346
(getGeometryPtr()->handle());
347
double M = curve->Knot(Index);
349
return Py_BuildValue("d",M);
351
catch (Standard_Failure& e) {
352
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
357
PyObject* BSplineCurvePy::setKnots(PyObject * args)
360
if (!PyArg_ParseTuple(args, "O", &obj))
363
Py::Sequence list(obj);
364
TColStd_Array1OfReal k(1,list.size());
366
for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
368
k(index++) = (double)val;
371
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
372
(getGeometryPtr()->handle());
376
catch (Standard_Failure& e) {
377
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
382
PyObject* BSplineCurvePy::getKnots(PyObject * args)
384
if (!PyArg_ParseTuple(args, ""))
387
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
388
(getGeometryPtr()->handle());
389
TColStd_Array1OfReal w(1,curve->NbKnots());
392
for (Standard_Integer i=w.Lower(); i<=w.Upper(); i++) {
393
knots.append(Py::Float(w(i)));
395
return Py::new_reference_to(knots);
397
catch (Standard_Failure& e) {
398
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
403
PyObject* BSplineCurvePy::setPole(PyObject * args)
408
if (!PyArg_ParseTuple(args, "iO!|d", &index, &(Base::VectorPy::Type), &p, &weight))
410
Base::Vector3d vec = static_cast<Base::VectorPy*>(p)->value();
411
gp_Pnt pnt(vec.x, vec.y, vec.z);
413
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
414
(getGeometryPtr()->handle());
416
curve->SetPole(index,pnt);
418
curve->SetPole(index,pnt,weight);
421
catch (Standard_Failure& e) {
422
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
427
PyObject* BSplineCurvePy::getPole(PyObject * args)
430
if (!PyArg_ParseTuple(args, "i", &index))
433
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
434
(getGeometryPtr()->handle());
435
Standard_OutOfRange_Raise_if
436
(index < 1 || index > curve->NbPoles(), "Pole index out of range");
437
gp_Pnt pnt = curve->Pole(index);
438
Base::VectorPy* vec = new Base::VectorPy(Base::Vector3d(
439
pnt.X(), pnt.Y(), pnt.Z()));
442
catch (Standard_Failure& e) {
443
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
448
PyObject* BSplineCurvePy::getPoles(PyObject * args)
450
if (!PyArg_ParseTuple(args, ""))
453
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
454
(getGeometryPtr()->handle());
455
TColgp_Array1OfPnt p(1,curve->NbPoles());
458
for (Standard_Integer i=p.Lower(); i<=p.Upper(); i++) {
460
Base::VectorPy* vec = new Base::VectorPy(Base::Vector3d(
461
pnt.X(), pnt.Y(), pnt.Z()));
462
poles.append(Py::asObject(vec));
464
return Py::new_reference_to(poles);
466
catch (Standard_Failure& e) {
467
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
472
PyObject* BSplineCurvePy::getPolesAndWeights(PyObject * args)
474
if (!PyArg_ParseTuple(args, ""))
477
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
478
(getGeometryPtr()->handle());
479
TColgp_Array1OfPnt p(1,curve->NbPoles());
481
TColStd_Array1OfReal w(1,curve->NbPoles());
485
for (Standard_Integer i=p.Lower(); i<=p.Upper(); i++) {
487
double weight = w(i);
489
t.setItem(0, Py::Float(pnt.X()));
490
t.setItem(1, Py::Float(pnt.Y()));
491
t.setItem(2, Py::Float(pnt.Z()));
492
t.setItem(3, Py::Float(weight));
495
return Py::new_reference_to(poles);
497
catch (Standard_Failure& e) {
498
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
503
PyObject* BSplineCurvePy::setWeight(PyObject * args)
507
if (!PyArg_ParseTuple(args, "id", &index,&weight))
510
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
511
(getGeometryPtr()->handle());
512
curve->SetWeight(index,weight);
515
catch (Standard_Failure& e) {
516
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
521
PyObject* BSplineCurvePy::getWeight(PyObject * args)
524
if (!PyArg_ParseTuple(args, "i", &index))
527
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
528
(getGeometryPtr()->handle());
529
Standard_OutOfRange_Raise_if
530
(index < 1 || index > curve->NbPoles() , "Weight index out of range");
531
double weight = curve->Weight(index);
532
return Py_BuildValue("d", weight);
534
catch (Standard_Failure& e) {
535
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
540
PyObject* BSplineCurvePy::getWeights(PyObject * args)
542
if (!PyArg_ParseTuple(args, ""))
545
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
546
(getGeometryPtr()->handle());
547
TColStd_Array1OfReal w(1,curve->NbPoles());
550
for (Standard_Integer i=w.Lower(); i<=w.Upper(); i++) {
551
weights.append(Py::Float(w(i)));
553
return Py::new_reference_to(weights);
555
catch (Standard_Failure& e) {
556
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
561
PyObject* BSplineCurvePy::getResolution(PyObject * args)
564
if (!PyArg_ParseTuple(args, "d", &tol))
567
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
568
(getGeometryPtr()->handle());
570
curve->Resolution(tol,utol);
571
return Py_BuildValue("d",utol);
573
catch (Standard_Failure& e) {
574
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
579
PyObject* BSplineCurvePy::movePoint(PyObject * args)
584
if (!PyArg_ParseTuple(args, "dO!ii", &U, &(Base::VectorPy::Type),&pnt, &index1, &index2))
587
Base::Vector3d p = static_cast<Base::VectorPy*>(pnt)->value();
588
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
589
(getGeometryPtr()->handle());
591
curve->MovePoint(U, gp_Pnt(p.x,p.y,p.z), index1, index2, first, last);
592
return Py_BuildValue("(ii)",first, last);
594
catch (Standard_Failure& e) {
595
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
600
PyObject* BSplineCurvePy::setNotPeriodic(PyObject * args)
602
if (!PyArg_ParseTuple(args, ""))
605
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
606
(getGeometryPtr()->handle());
607
curve->SetNotPeriodic();
610
catch (Standard_Failure& e) {
611
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
616
PyObject* BSplineCurvePy::setPeriodic(PyObject * args)
618
if (!PyArg_ParseTuple(args, ""))
621
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
622
(getGeometryPtr()->handle());
623
curve->SetPeriodic();
626
catch (Standard_Failure& e) {
627
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
632
PyObject* BSplineCurvePy::setOrigin(PyObject * args)
635
if (!PyArg_ParseTuple(args, "i", &index))
638
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
639
(getGeometryPtr()->handle());
640
curve->SetOrigin(index);
643
catch (Standard_Failure& e) {
644
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
649
PyObject* BSplineCurvePy::getMultiplicity(PyObject * args)
652
if (!PyArg_ParseTuple(args, "i", &index))
655
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
656
(getGeometryPtr()->handle());
657
int mult = curve->Multiplicity(index);
658
return Py_BuildValue("i", mult);
660
catch (Standard_Failure& e) {
661
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
666
PyObject* BSplineCurvePy::getMultiplicities(PyObject * args)
668
if (!PyArg_ParseTuple(args, ""))
671
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
672
(getGeometryPtr()->handle());
673
TColStd_Array1OfInteger m(1,curve->NbKnots());
674
curve->Multiplicities(m);
676
for (Standard_Integer i=m.Lower(); i<=m.Upper(); i++) {
677
mults.append(Py::Long(m(i)));
679
return Py::new_reference_to(mults);
681
catch (Standard_Failure& e) {
682
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
686
Py::Long BSplineCurvePy::getDegree() const
688
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
689
(getGeometryPtr()->handle());
690
return Py::Long(curve->Degree());
693
Py::Long BSplineCurvePy::getMaxDegree() const
695
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
696
(getGeometryPtr()->handle());
697
return Py::Long(curve->MaxDegree());
700
Py::Long BSplineCurvePy::getNbPoles() const
702
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
703
(getGeometryPtr()->handle());
704
return Py::Long(curve->NbPoles());
707
Py::Long BSplineCurvePy::getNbKnots() const
709
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
710
(getGeometryPtr()->handle());
711
return Py::Long(curve->NbKnots());
714
Py::Object BSplineCurvePy::getStartPoint() const
716
Handle(Geom_BSplineCurve) c = Handle(Geom_BSplineCurve)::DownCast
717
(getGeometryPtr()->handle());
718
gp_Pnt pnt = c->StartPoint();
719
return Py::Vector(Base::Vector3d(pnt.X(), pnt.Y(), pnt.Z()));
722
Py::Object BSplineCurvePy::getEndPoint() const
724
Handle(Geom_BSplineCurve) c = Handle(Geom_BSplineCurve)::DownCast
725
(getGeometryPtr()->handle());
726
gp_Pnt pnt = c->EndPoint();
727
return Py::Vector(Base::Vector3d(pnt.X(), pnt.Y(), pnt.Z()));
730
Py::Object BSplineCurvePy::getFirstUKnotIndex() const
732
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
733
(getGeometryPtr()->handle());
734
return Py::Long(curve->FirstUKnotIndex());
737
Py::Object BSplineCurvePy::getLastUKnotIndex() const
739
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
740
(getGeometryPtr()->handle());
741
return Py::Long(curve->LastUKnotIndex());
744
Py::List BSplineCurvePy::getKnotSequence() const
746
Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast
747
(getGeometryPtr()->handle());
748
Standard_Integer m = 0;
749
if (curve->IsPeriodic()) {
750
// knots=poles+2*degree-mult(1)+2
751
m = curve->NbPoles() + 2*curve->Degree() - curve->Multiplicity(1) + 2;
754
// knots=poles+degree+1
755
for (int i=1; i<= curve->NbKnots(); i++)
756
m += curve->Multiplicity(i);
759
TColStd_Array1OfReal k(1,m);
760
curve->KnotSequence(k);
762
for (Standard_Integer i=k.Lower(); i<=k.Upper(); i++) {
763
list.append(Py::Float(k(i)));
768
PyObject* BSplineCurvePy::toBiArcs(PyObject * args)
770
double tolerance = 0.001;
771
if (!PyArg_ParseTuple(args, "d", &tolerance))
774
GeomBSplineCurve* curve = getGeomBSplineCurvePtr();
775
std::list<Geometry*> arcs;
776
arcs = curve->toBiArcs(tolerance);
779
for (auto arc : arcs) {
780
list.append(Py::asObject(arc->getPyObject()));
784
return Py::new_reference_to(list);
786
catch (Standard_Failure& e) {
787
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
792
PyObject* BSplineCurvePy::approximate(PyObject *args, PyObject *kwds)
795
Standard_Integer degMin = 3;
796
Standard_Integer degMax = 8;
797
Standard_Integer segMax = 8;
798
const char *continuity = "C2";
800
const char *parType = "ChordLength";
801
PyObject *par = nullptr;
806
// Approximate this curve with a given continuity and degree
807
static const std::array<const char *, 5> kwds_reapprox{"MaxDegree", "MaxSegments", "Continuity", "Tolerance",
809
if (Base::Wrapped_ParseTupleAndKeywords(args, kwds, "i|isd", kwds_reapprox,
810
&tol3d, °Max, &segMax, &continuity)) {
813
std::string str = continuity;
816
else if (str == "G1")
818
else if (str == "C1")
820
else if (str == "G2")
822
else if (str == "C2")
824
else if (str == "C3")
826
else if (str == "CN")
831
this->getGeomBSplineCurvePtr()->approximate(tol3d, segMax, degMax, c);
835
// Approximate a list of points
837
static const std::array<const char *, 11> kwds_interp{"Points", "DegMax", "Continuity", "Tolerance", "DegMin",
838
"ParamType", "Parameters", "LengthWeight", "CurvatureWeight",
839
"TorsionWeight", nullptr};
842
if (!Base::Wrapped_ParseTupleAndKeywords(args, kwds, "O|isdisOddd", kwds_interp,
844
&continuity, &tol3d, °Min,
846
&weight1, &weight2, &weight3)) {
851
Py::Sequence list(obj);
852
TColgp_Array1OfPnt pnts(1, list.size());
853
Standard_Integer index = 1;
854
for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
855
Base::Vector3d vec = Py::Vector(*it).toVector();
856
pnts(index++) = gp_Pnt(vec.x,vec.y,vec.z);
859
if (degMin > degMax) {
860
Standard_Failure::Raise("DegMin must be lower or equal to DegMax");
864
std::string str = continuity;
867
else if (str == "G1")
869
else if (str == "C1")
871
else if (str == "G2")
873
else if (str == "C2")
875
else if (str == "C3")
877
else if (str == "CN")
882
if (weight1 || weight2 || weight3) {
883
// It seems that this function only works with Continuity = C0, C1 or C2
884
GeomAPI_PointsToBSpline fit(pnts, weight1, weight2, weight3, degMax, c, tol3d);
885
Handle(Geom_BSplineCurve) spline = fit.Curve();
886
if (!spline.IsNull()) {
887
this->getGeomBSplineCurvePtr()->setHandle(spline);
891
Standard_Failure::Raise("Smoothing approximation failed");
892
return nullptr; // goes to the catch block
897
Py::Sequence plist(par);
898
TColStd_Array1OfReal parameters(1,plist.size());
899
Standard_Integer index = 1;
900
for (Py::Sequence::iterator it = plist.begin(); it != plist.end(); ++it) {
902
parameters(index++) = static_cast<double>(f);
905
GeomAPI_PointsToBSpline fit(pnts, parameters, degMin, degMax, c, tol3d);
906
Handle(Geom_BSplineCurve) spline = fit.Curve();
907
if (!spline.IsNull()) {
908
this->getGeomBSplineCurvePtr()->setHandle(spline);
912
Standard_Failure::Raise("Approximation with parameters failed");
913
return nullptr; // goes to the catch block
917
Approx_ParametrizationType pt;
918
std::string pstr = parType;
919
if (pstr == "Uniform")
920
pt = Approx_IsoParametric;
921
else if (pstr == "Centripetal")
922
pt = Approx_Centripetal;
924
pt = Approx_ChordLength;
926
GeomAPI_PointsToBSpline fit(pnts, pt, degMin, degMax, c, tol3d);
927
Handle(Geom_BSplineCurve) spline = fit.Curve();
928
if (!spline.IsNull()) {
929
this->getGeomBSplineCurvePtr()->setHandle(spline);
933
Standard_Failure::Raise("failed to approximate points");
934
return nullptr; // goes to the catch block
937
catch (Standard_Failure& e) {
938
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
943
PyObject* BSplineCurvePy::getCardinalSplineTangents(PyObject *args, PyObject *kwds)
949
static const std::array<const char *, 3> kwds_interp1 {"Points", "Parameter", nullptr};
950
if (Base::Wrapped_ParseTupleAndKeywords(args, kwds, "Od",kwds_interp1, &pts, ¶meter)) {
951
Py::Sequence list(pts);
952
std::vector<gp_Pnt> interpPoints;
953
interpPoints.reserve(list.size());
954
for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
956
Base::Vector3d pnt = v.toVector();
957
interpPoints.emplace_back(pnt.x,pnt.y,pnt.z);
960
GeomBSplineCurve* bspline = this->getGeomBSplineCurvePtr();
961
std::vector<gp_Vec> tangents;
962
bspline->getCardinalSplineTangents(interpPoints, parameter, tangents);
965
for (gp_Vec it : tangents)
966
vec.append(Py::Vector(Base::Vector3d(it.X(), it.Y(), it.Z())));
967
return Py::new_reference_to(vec);
971
static const std::array<const char *, 3> kwds_interp2 {"Points", "Parameters", nullptr};
972
if (Base::Wrapped_ParseTupleAndKeywords(args, kwds, "OO",kwds_interp2, &pts, &tgs)) {
973
Py::Sequence list(pts);
974
std::vector<gp_Pnt> interpPoints;
975
interpPoints.reserve(list.size());
976
for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
978
Base::Vector3d pnt = v.toVector();
979
interpPoints.emplace_back(pnt.x,pnt.y,pnt.z);
982
Py::Sequence list2(tgs);
983
std::vector<double> parameters;
984
parameters.reserve(list2.size());
985
for (Py::Sequence::iterator it = list2.begin(); it != list2.end(); ++it) {
987
parameters.push_back(static_cast<double>(p));
990
GeomBSplineCurve* bspline = this->getGeomBSplineCurvePtr();
991
std::vector<gp_Vec> tangents;
992
bspline->getCardinalSplineTangents(interpPoints, parameters, tangents);
995
for (gp_Vec it : tangents)
996
vec.append(Py::Vector(Base::Vector3d(it.X(), it.Y(), it.Z())));
997
return Py::new_reference_to(vec);
1003
PyObject* BSplineCurvePy::interpolate(PyObject *args, PyObject *kwds)
1006
PyObject* par = nullptr;
1007
double tol3d = Precision::Approximation();
1008
PyObject* periodic = Py_False;
1009
PyObject* t1 = nullptr; PyObject* t2 = nullptr;
1010
PyObject* ts = nullptr; PyObject* fl = nullptr;
1011
PyObject* scale = Py_True;
1013
static const std::array<const char *, 10> kwds_interp{"Points", "PeriodicFlag", "Tolerance", "InitialTangent",
1014
"FinalTangent", "Tangents", "TangentFlags", "Parameters",
1017
if (!Base::Wrapped_ParseTupleAndKeywords(args, kwds, "O|O!dO!O!OOOO!", kwds_interp,
1018
&obj, &PyBool_Type, &periodic, &tol3d,
1019
&Base::VectorPy::Type, &t1,
1020
&Base::VectorPy::Type, &t2,
1021
&ts, &fl, &par, &PyBool_Type, &scale)) {
1026
Py::Sequence list(obj);
1027
Handle(TColgp_HArray1OfPnt) interpolationPoints = new TColgp_HArray1OfPnt(1, list.size());
1028
Standard_Integer index = 1;
1029
for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
1031
Base::Vector3d pnt = v.toVector();
1032
interpolationPoints->SetValue(index++, gp_Pnt(pnt.x,pnt.y,pnt.z));
1035
if (interpolationPoints->Length() < 2) {
1036
Standard_Failure::Raise("not enough points given");
1039
Handle(TColStd_HArray1OfReal) parameters;
1041
Py::Sequence plist(par);
1042
parameters = new TColStd_HArray1OfReal(1, plist.size());
1043
Standard_Integer pindex = 1;
1044
for (Py::Sequence::iterator it = plist.begin(); it != plist.end(); ++it) {
1046
parameters->SetValue(pindex++, static_cast<double>(f));
1050
std::unique_ptr<GeomAPI_Interpolate> aBSplineInterpolation;
1051
if (parameters.IsNull()) {
1052
aBSplineInterpolation = std::make_unique<GeomAPI_Interpolate>(interpolationPoints,
1053
Base::asBoolean(periodic), tol3d);
1056
aBSplineInterpolation = std::make_unique<GeomAPI_Interpolate>(interpolationPoints, parameters,
1057
Base::asBoolean(periodic), tol3d);
1061
Base::Vector3d v1 = Py::Vector(t1,false).toVector();
1062
Base::Vector3d v2 = Py::Vector(t2,false).toVector();
1063
gp_Vec initTangent(v1.x,v1.y,v1.z), finalTangent(v2.x,v2.y,v2.z);
1064
aBSplineInterpolation->Load(initTangent, finalTangent, Base::asBoolean(scale));
1066
else if (ts && fl) {
1067
Py::Sequence tlist(ts);
1068
TColgp_Array1OfVec tangents(1, tlist.size());
1069
Standard_Integer index = 1;
1070
for (Py::Sequence::iterator it = tlist.begin(); it != tlist.end(); ++it) {
1072
Base::Vector3d vec = v.toVector();
1073
tangents.SetValue(index++, gp_Vec(vec.x,vec.y,vec.z));
1076
Py::Sequence flist(fl);
1077
Handle(TColStd_HArray1OfBoolean) tangentFlags = new TColStd_HArray1OfBoolean(1, flist.size());
1078
Standard_Integer findex = 1;
1079
for (Py::Sequence::iterator it = flist.begin(); it != flist.end(); ++it) {
1080
Py::Boolean flag(*it);
1081
tangentFlags->SetValue(findex++, static_cast<bool>(flag) ? Standard_True : Standard_False);
1084
aBSplineInterpolation->Load(tangents, tangentFlags, Base::asBoolean(scale));
1087
aBSplineInterpolation->Perform();
1088
if (aBSplineInterpolation->IsDone()) {
1089
Handle(Geom_BSplineCurve) aBSplineCurve(aBSplineInterpolation->Curve());
1090
this->getGeomBSplineCurvePtr()->setHandle(aBSplineCurve);
1094
Standard_Failure::Raise("failed to interpolate points");
1095
return nullptr; // goes to the catch block
1098
catch (Standard_Failure& e) {
1099
std::string err = e.GetMessageString();
1100
if (err.empty()) err = e.DynamicType()->Name();
1101
PyErr_SetString(PartExceptionOCCError, err.c_str());
1106
PyObject* BSplineCurvePy::buildFromPoles(PyObject *args)
1110
PyObject* periodic = Py_False;
1111
PyObject* interpolate = Py_False;
1112
if (!PyArg_ParseTuple(args, "O|O!iO!",&obj, &PyBool_Type, &periodic, °ree, &PyBool_Type, interpolate))
1115
Py::Sequence list(obj);
1116
TColgp_Array1OfPnt poles(1, list.size());
1117
Standard_Integer index = 1;
1118
for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
1120
Base::Vector3d pnt = v.toVector();
1121
poles(index++) = gp_Pnt(pnt.x,pnt.y,pnt.z);
1124
if (poles.Length() <= degree)
1125
degree = poles.Length()-1;
1127
if (Base::asBoolean(periodic)) {
1130
if (Base::asBoolean(interpolate)) {
1132
len = poles.Length() - mult + 2;
1136
len = poles.Length() + 1;
1138
TColStd_Array1OfReal knots(1, len);
1139
TColStd_Array1OfInteger mults(1, len);
1140
for (int i=1; i<=knots.Length(); i++){
1141
knots.SetValue(i,(double)(i-1)/(knots.Length()-1));
1142
mults.SetValue(i,1);
1144
mults.SetValue(1, mult);
1145
mults.SetValue(knots.Length(), mult);
1147
Handle(Geom_BSplineCurve) spline = new Geom_BSplineCurve(poles, knots, mults, degree, Standard_True);
1148
if (!spline.IsNull()) {
1149
this->getGeomBSplineCurvePtr()->setHandle(spline);
1153
Standard_Failure::Raise("failed to create spline");
1154
return nullptr; // goes to the catch block
1158
TColStd_Array1OfReal knots(1, poles.Length()+degree+1-2*(degree));
1159
TColStd_Array1OfInteger mults(1, poles.Length()+degree+1-2*(degree));
1160
for (int i=1; i<=knots.Length(); i++){
1161
knots.SetValue(i,(double)(i-1)/(knots.Length()-1));
1162
mults.SetValue(i,1);
1164
mults.SetValue(1, degree+1);
1165
mults.SetValue(knots.Length(), degree+1);
1167
Handle(Geom_BSplineCurve) spline = new Geom_BSplineCurve(poles, knots, mults, degree, Standard_False);
1168
if (!spline.IsNull()) {
1169
this->getGeomBSplineCurvePtr()->setHandle(spline);
1173
Standard_Failure::Raise("failed to create spline");
1174
return nullptr; // goes to the catch block
1178
catch (Standard_Failure& e) {
1179
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
1184
PyObject* BSplineCurvePy::buildFromPolesMultsKnots(PyObject *args, PyObject *keywds)
1186
static const std::array<const char *, 8> kwlist{"poles", "mults", "knots", "periodic", "degree", "weights",
1187
"CheckRational", nullptr};
1188
PyObject* periodic = Py_False; // NOLINT
1189
PyObject* CheckRational = Py_True; // NOLINT
1190
PyObject* poles = Py_None;
1191
PyObject* mults = Py_None;
1192
PyObject* knots = Py_None;
1193
PyObject* weights = Py_None;
1195
int number_of_poles = 0;
1196
int number_of_knots = 0;
1197
int sum_of_mults = 0;
1198
if (!Base::Wrapped_ParseTupleAndKeywords(args, keywds, "O|OOO!iOO!", kwlist,
1199
&poles, &mults, &knots,
1200
&PyBool_Type, &periodic,
1202
&PyBool_Type, &CheckRational)) {
1206
// poles have to be present
1207
Py::Sequence list(poles);
1209
number_of_poles = list.size();
1210
if ((number_of_poles) < 2) {
1211
Standard_Failure::Raise("need two or more poles");
1214
TColgp_Array1OfPnt occpoles(1, number_of_poles);
1215
Standard_Integer index = 1;
1216
for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
1218
Base::Vector3d pnt = v.toVector();
1219
occpoles(index++) = gp_Pnt(pnt.x,pnt.y,pnt.z);
1221
//Calculate the number of knots
1222
if (mults != Py_None && knots != Py_None) {
1223
number_of_knots = PyObject_Length(mults);
1224
if (PyObject_Length(knots) != number_of_knots) {
1225
Standard_Failure::Raise("number of knots and mults mismatch");
1230
if (mults != Py_None) {
1231
number_of_knots = PyObject_Length(mults);
1234
if (knots != Py_None) { number_of_knots = PyObject_Length(knots); }
1235
else { //guess number of knots
1236
if (Base::asBoolean(periodic)) {
1237
if (number_of_poles < degree) {degree = number_of_poles;}
1238
number_of_knots = number_of_poles+1;
1241
if (number_of_poles <= degree) {degree = number_of_poles-1;}
1242
number_of_knots = number_of_poles-degree+1;
1247
TColStd_Array1OfInteger occmults(1,number_of_knots);
1248
TColStd_Array1OfReal occknots(1,number_of_knots);
1249
TColStd_Array1OfReal occweights(1,number_of_poles);
1250
if (mults != Py_None) { //mults are given
1251
Py::Sequence multssq(mults);
1252
Standard_Integer index = 1;
1253
for (Py::Sequence::iterator it = multssq.begin(); it != multssq.end() && index <= occmults.Length(); ++it) {
1255
if (index < occmults.Length() || !Base::asBoolean(periodic)) {
1256
sum_of_mults += static_cast<int>(mult); //sum up the mults to compare them against the number of poles later
1258
occmults(index++) = static_cast<int>(mult);
1261
else { //mults are 1 or degree+1 at the ends
1262
for (int i=1; i<=occmults.Length(); i++){
1263
occmults.SetValue(i,1);
1265
if (!Base::asBoolean(periodic) && occmults.Length() > 0) {
1266
occmults.SetValue(1, degree+1);
1267
occmults.SetValue(occmults.Length(), degree+1);
1268
sum_of_mults = occmults.Length()+2*degree;
1271
sum_of_mults = occmults.Length()-1;
1274
// check multiplicity of inner knots
1275
for (Standard_Integer i=2; i < occmults.Length(); i++) {
1276
if (occmults(i) > degree) {
1277
Standard_Failure::Raise("multiplicity of inner knot higher than degree");
1280
if (knots != Py_None) { //knots are given
1281
Py::Sequence knotssq(knots);
1283
for (Py::Sequence::iterator it = knotssq.begin(); it != knotssq.end() && index <= occknots.Length(); ++it) {
1284
Py::Float knot(*it);
1285
occknots(index++) = knot;
1288
else { // knotes are uniformly spaced 0..1 if not given
1289
for (int i=1; i<=occknots.Length(); i++){
1290
occknots.SetValue(i,(double)(i-1)/(occknots.Length()-1));
1293
if (weights != Py_None) { //weights are given
1294
if (PyObject_Length(weights) != number_of_poles) {
1295
Standard_Failure::Raise("number of poles and weights mismatch");
1297
} //complain about mismatch
1298
Py::Sequence weightssq(weights);
1299
Standard_Integer index = 1;
1300
for (Py::Sequence::iterator it = weightssq.begin(); it != weightssq.end(); ++it) {
1301
Py::Float weight(*it);
1302
occweights(index++) = weight;
1305
else { // weights are 1.0
1306
for (int i=1; i<=occweights.Length(); i++){
1307
occweights.SetValue(i,1.0);
1310
// check if the number of poles matches the sum of mults
1311
if ((Base::asBoolean(periodic) && sum_of_mults != number_of_poles) ||
1312
(!Base::asBoolean(periodic) && sum_of_mults - degree -1 != number_of_poles)) {
1313
Standard_Failure::Raise("number of poles and sum of mults mismatch");
1317
Handle(Geom_BSplineCurve) spline = new Geom_BSplineCurve(occpoles,occweights,occknots,occmults,degree,
1318
Base::asBoolean(periodic), Base::asBoolean(CheckRational));
1319
if (!spline.IsNull()) {
1320
this->getGeomBSplineCurvePtr()->setHandle(spline);
1324
Standard_Failure::Raise("failed to create spline");
1325
return nullptr; // goes to the catch block
1328
catch (const Standard_Failure& e) {
1329
Standard_CString msg = e.GetMessageString();
1330
PyErr_SetString(PartExceptionOCCError, msg ? msg : "");
1336
PyObject* BSplineCurvePy::toBezier(PyObject *args)
1338
if (!PyArg_ParseTuple(args, ""))
1342
Handle(Geom_BSplineCurve) spline = Handle(Geom_BSplineCurve)::DownCast
1343
(this->getGeomBSplineCurvePtr()->handle());
1344
GeomConvert_BSplineCurveToBezierCurve crt(spline);
1347
Standard_Integer arcs = crt.NbArcs();
1348
for (Standard_Integer i=1; i<=arcs; i++) {
1349
Handle(Geom_BezierCurve) bezier = crt.Arc(i);
1350
list.append(Py::asObject(new BezierCurvePy(new GeomBezierCurve(bezier))));
1353
return Py::new_reference_to(list);
1355
catch (Standard_Failure& e) {
1356
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
1361
PyObject* BSplineCurvePy::join(PyObject *args)
1364
if (!PyArg_ParseTuple(args, "O!", &BSplineCurvePy::Type, &c))
1368
GeomBSplineCurve* curve1 = this->getGeomBSplineCurvePtr();
1369
BSplineCurvePy* curve2 = static_cast<BSplineCurvePy*>(c);
1370
Handle(Geom_BSplineCurve) spline = Handle(Geom_BSplineCurve)::DownCast
1371
(curve2->getGeomBSplineCurvePtr()->handle());
1373
bool ok = curve1->join(spline);
1375
return PyBool_FromLong(ok ? 1 : 0);
1377
catch (Standard_Failure& e) {
1378
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
1383
PyObject* BSplineCurvePy::makeC1Continuous(PyObject *args)
1385
double tol = Precision::Approximation();
1386
double ang_tol = 1.0e-7;
1387
if (!PyArg_ParseTuple(args, "|dd", &tol, &ang_tol))
1391
GeomBSplineCurve* spline = this->getGeomBSplineCurvePtr();
1392
spline->makeC1Continuous(tol, ang_tol);
1395
catch (Standard_Failure& e) {
1396
std::string err = e.GetMessageString();
1397
if (err.empty()) err = e.DynamicType()->Name();
1398
PyErr_SetString(PartExceptionOCCError, err.c_str());
1403
PyObject* BSplineCurvePy::scaleKnotsToBounds(PyObject *args)
1407
if (!PyArg_ParseTuple(args, "|dd", &u0, &u1))
1411
Standard_Failure::Raise("Bad parameter range");
1414
GeomBSplineCurve* curve = getGeomBSplineCurvePtr();
1415
curve->scaleKnotsToBounds(u0, u1);
1418
catch (Standard_Failure& e) {
1419
std::string err = e.GetMessageString();
1420
if (err.empty()) err = e.DynamicType()->Name();
1421
PyErr_SetString(PartExceptionOCCError, err.c_str());
1426
PyObject* BSplineCurvePy::getCustomAttributes(const char* /*attr*/) const
1431
int BSplineCurvePy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)