FreeCAD

Форк
0
/
Geometry.cpp 
6563 строки · 203.8 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2008 Werner Mayer <wmayer[at]users.sourceforge.net>     *
3
 *                                                                         *
4
 *   This file is part of the FreeCAD CAx development system.              *
5
 *                                                                         *
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.      *
10
 *                                                                         *
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.                  *
15
 *                                                                         *
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                                *
20
 *                                                                         *
21
 ***************************************************************************/
22

23
#include "PreCompiled.h"
24
#ifndef _PreComp_
25
# include <Approx_Curve3d.hxx>
26
# include <BRepAdaptor_Curve.hxx>
27
# include <BRepAdaptor_Surface.hxx>
28
# include <BRepBuilderAPI_MakeEdge.hxx>
29
# include <BRepBuilderAPI_MakeFace.hxx>
30
# include <BRepBuilderAPI_MakeVertex.hxx>
31
# include <BSplCLib.hxx>
32
# include <GC_MakeArcOfCircle.hxx>
33
# include <GC_MakeArcOfEllipse.hxx>
34
# include <GC_MakeArcOfHyperbola.hxx>
35
# include <GC_MakeArcOfParabola.hxx>
36
# include <GC_MakeCircle.hxx>
37
# include <GC_MakeEllipse.hxx>
38
# include <GC_MakeHyperbola.hxx>
39
# include <GC_MakeSegment.hxx>
40
# include <GCPnts_AbscissaPoint.hxx>
41
# include <gce_ErrorType.hxx>
42
# include <gce_MakeParab.hxx>
43
# include <Geom_BezierCurve.hxx>
44
# include <Geom_BezierSurface.hxx>
45
# include <Geom_BSplineCurve.hxx>
46
# include <Geom_BSplineSurface.hxx>
47
# include <Geom_CartesianPoint.hxx>
48
# include <Geom_Circle.hxx>
49
# include <Geom_ConicalSurface.hxx>
50
# include <Geom_Curve.hxx>
51
# include <Geom_CylindricalSurface.hxx>
52
# include <Geom_Ellipse.hxx>
53
# include <Geom_Hyperbola.hxx>
54
# include <Geom_Line.hxx>
55
# include <Geom_OffsetCurve.hxx>
56
# include <Geom_OffsetSurface.hxx>
57
# include <Geom_Parabola.hxx>
58
# include <Geom_Plane.hxx>
59
# include <Geom_RectangularTrimmedSurface.hxx>
60
# include <Geom_SphericalSurface.hxx>
61
# include <Geom_Surface.hxx>
62
# include <Geom_SurfaceOfLinearExtrusion.hxx>
63
# include <Geom_SurfaceOfRevolution.hxx>
64
# include <Geom_ToroidalSurface.hxx>
65
# include <Geom_TrimmedCurve.hxx>
66
# include <GeomAPI_ExtremaCurveCurve.hxx>
67
# include <GeomAPI_Interpolate.hxx>
68
# include <GeomAPI_PointsToBSpline.hxx>
69
# include <GeomAPI_ProjectPointOnCurve.hxx>
70
# include <GeomConvert.hxx>
71
# include <GeomConvert_CompCurveToBSplineCurve.hxx>
72
# include <GeomLProp_CLProps.hxx>
73
# include <GeomLProp_SLProps.hxx>
74
# include <GeomLib_IsPlanarSurface.hxx>
75
# include <GeomPlate_Surface.hxx>
76
# include <gp.hxx>
77
# include <gp_Ax2.hxx>
78
# include <gp_Circ.hxx>
79
# include <gp_Cone.hxx>
80
# include <gp_Cylinder.hxx>
81
# include <gp_Elips.hxx>
82
# include <gp_Hypr.hxx>
83
# include <gp_Lin.hxx>
84
# include <gp_Parab.hxx>
85
# include <gp_Pln.hxx>
86
# include <gp_Pnt.hxx>
87
# include <gp_Sphere.hxx>
88
# include <gp_Torus.hxx>
89
# include <LProp_NotDefined.hxx>
90
# include <Precision.hxx>
91
# include <ShapeConstruct_Curve.hxx>
92
# include <Standard_ConstructionError.hxx>
93
# include <Standard_Real.hxx>
94
# include <Standard_Version.hxx>
95
# include <TColgp_Array2OfPnt.hxx>
96
# include <TColgp_HArray1OfPnt.hxx>
97
# include <TColStd_Array1OfReal.hxx>
98
# include <TColStd_HArray1OfBoolean.hxx>
99

100
# if OCC_VERSION_HEX < 0x070600
101
# include <GeomAdaptor_HSurface.hxx>
102
# include <GeomAdaptor_HCurve.hxx>
103
# endif
104

105
# include <boost/random.hpp>
106
# include <cmath>
107
# include <ctime>
108
#endif //_PreComp_
109

110
#include <Base/Console.h>
111
#include <Base/Exception.h>
112
#include <Base/Reader.h>
113
#include <Base/Writer.h>
114
#include <BRep_Tool.hxx>
115
#include <TopoDS.hxx>
116
#include <memory>
117
#include <boost/thread/mutex.hpp>
118
#include <boost/thread/thread.hpp>
119

120
#include "Geometry.h"
121
#include "ArcOfCirclePy.h"
122
#include "ArcOfEllipsePy.h"
123
#include "ArcOfHyperbolaPy.h"
124
#include "ArcOfParabolaPy.h"
125
#include "BezierCurvePy.h"
126
#include "BezierSurfacePy.h"
127
#include "BSplineCurveBiArcs.h"
128
#include "BSplineCurvePy.h"
129
#include "BSplineSurfacePy.h"
130
#include "CirclePy.h"
131
#include "ConePy.h"
132
#include "CylinderPy.h"
133
#include "EllipsePy.h"
134
#include "GeometryMigrationExtension.h"
135
#include "HyperbolaPy.h"
136
#include "LinePy.h"
137
#include "LineSegmentPy.h"
138
#include "OffsetCurvePy.h"
139
#include "OffsetSurfacePy.h"
140
#include "ParabolaPy.h"
141
#include "PlanePy.h"
142
#include "PlateSurfacePy.h"
143
#include "PointPy.h"
144
#include "RectangularTrimmedSurfacePy.h"
145
#include "SpherePy.h"
146
#include "SurfaceOfExtrusionPy.h"
147
#include "SurfaceOfRevolutionPy.h"
148
#include "Tools.h"
149
#include "ToroidPy.h"
150
#include "TopoShape.h"
151

152

153
#if OCC_VERSION_HEX >= 0x070600
154
using GeomAdaptor_HCurve = GeomAdaptor_Curve;
155
#endif
156

157
using namespace Part;
158

159

160
const char* gce_ErrorStatusText(gce_ErrorType et)
161
{
162
    switch (et)
163
    {
164
    case gce_Done:
165
        return "Construction was successful";
166
    case gce_ConfusedPoints:
167
        return "Two points are coincident";
168
    case gce_NegativeRadius:
169
        return "Radius value is negative";
170
    case gce_ColinearPoints:
171
        return "Three points are collinear";
172
    case gce_IntersectionError:
173
        return "Intersection cannot be computed";
174
    case gce_NullAxis:
175
        return "Axis is undefined";
176
    case gce_NullAngle:
177
        return "Angle value is invalid (usually null)";
178
    case gce_NullRadius:
179
        return "Radius is null";
180
    case gce_InvertAxis:
181
        return "Axis value is invalid";
182
    case gce_BadAngle:
183
        return "Angle value is invalid";
184
    case gce_InvertRadius:
185
        return "Radius value is incorrect (usually with respect to another radius)";
186
    case gce_NullFocusLength:
187
        return "Focal distance is null";
188
    case gce_NullVector:
189
        return "Vector is null";
190
    case gce_BadEquation:
191
        return "Coefficients are incorrect (applies to the equation of a geometric object)";
192
    default:
193
        return "Creation of geometry failed";
194
    }
195
}
196

197
// ---------------------------------------------------------------
198

199
TYPESYSTEM_SOURCE_ABSTRACT(Part::Geometry,Base::Persistence)    // NOLINT
200

201
Geometry::Geometry() // NOLINT
202
{
203
    createNewTag();
204
}
205

206
Geometry::~Geometry() = default;
207

208
bool Geometry::hasSameExtensions(const Geometry& other) const
209
{
210
    // We skip non persistent extension while doing comparison. Not sure if
211
    // this will cause any problem.
212
    size_t index = 0;
213
    for (const auto& ext : extensions) {
214
        if (auto persistExt =
215
                Base::freecad_dynamic_cast<const GeometryPersistenceExtension>(ext.get())) {
216
            for (; index < other.extensions.size(); ++index) {
217
                if (auto extOther = Base::freecad_dynamic_cast<const GeometryPersistenceExtension>(
218
                        other.extensions[index].get())) {
219
                    if (!persistExt->isSame(*extOther)) {
220
                        return false;
221
                    }
222
                    break;
223
                }
224
            }
225
            if (index >= other.extensions.size()) {
226
                return false;
227
            }
228
            ++index;
229
        }
230
    }
231
    for (; index < other.extensions.size(); ++index) {
232
        if (Base::freecad_dynamic_cast<const GeometryPersistenceExtension>(
233
                other.extensions[index].get())) {
234
            return false;
235
        }
236
    }
237
    return true;
238
}
239

240
// Persistence implementer
241
unsigned int Geometry::getMemSize () const
242
{
243
    return 1;
244
}
245

246
std::unique_ptr<Geometry> Geometry::fromShape(const TopoDS_Shape &shape, bool silent)
247
{
248
    std::unique_ptr<Geometry> geom;
249

250
    if (shape.IsNull()) {
251
        if(!silent)
252
            throw Base::ValueError("Null shape");
253
        return geom;
254
    }
255

256
    switch (shape.ShapeType()) {
257
    case TopAbs_VERTEX: {
258
        gp_Pnt p = BRep_Tool::Pnt(TopoDS::Vertex(shape));
259
        geom = std::make_unique<GeomPoint>(Base::Vector3d(p.X(),p.Y(),p.Z()));
260
        break;
261
    }
262
    case TopAbs_EDGE: {
263
        const TopoDS_Edge& e = TopoDS::Edge(shape);
264
        BRepAdaptor_Curve adapt(e);
265
        geom = makeFromCurveAdaptor(adapt, silent);
266
        break;
267
    }
268
    case TopAbs_FACE: {
269
        const TopoDS_Face& f = TopoDS::Face(shape);
270
        BRepAdaptor_Surface adapt(f);
271
        geom = makeFromSurfaceAdaptor(adapt, silent);
272
        break;
273
    }
274
    default:
275
        if(!silent)
276
            FC_THROWM(Base::TypeError, "Unsupported shape type " << TopoShape::shapeName(shape.ShapeType()));
277
    }
278
    return geom;
279
}
280

281
void Geometry::Save(Base::Writer &writer) const
282
{
283
    // We always store an extension array even if empty, so that restoring is consistent.
284

285
    // Get the number of persistent extensions
286
    int counter = 0;
287
    for(const auto& att : extensions) {
288
        if(att->isDerivedFrom(Part::GeometryPersistenceExtension::getClassTypeId()))
289
            counter++;
290
    }
291

292
    writer.Stream() << writer.ind() << "<GeoExtensions count=\"" << counter << "\">" << std::endl;
293

294
    writer.incInd();
295

296
    for(const auto& att : extensions) {
297
        if(att->isDerivedFrom(Part::GeometryPersistenceExtension::getClassTypeId()))
298
            std::static_pointer_cast<Part::GeometryPersistenceExtension>(att)->Save(writer);
299
    }
300

301
    writer.decInd();
302
    writer.Stream() << writer.ind() << "</GeoExtensions>" << std::endl;
303
}
304

305
void Geometry::Restore(Base::XMLReader &reader)
306
{
307
    // In legacy file format, there are no extensions and there is a construction XML tag
308
    // In the new format, this is migrated into extensions, and we get an array with extensions
309
    reader.readElement();
310

311
    if(strcmp(reader.localName(),"GeoExtensions") == 0) { // new format
312

313
        long count = reader.getAttributeAsInteger("count");
314

315
        for (long index = 0; index < count; index++) {
316
            reader.readElement("GeoExtension");
317
            const char* TypeName = reader.getAttribute("type");
318
            Base::Type type = Base::Type::fromName(TypeName);
319
            auto *newExtension = static_cast<GeometryPersistenceExtension *>(type.createInstance());
320
            if (newExtension) {
321
                newExtension->Restore(reader);
322

323
                extensions.push_back(std::shared_ptr<GeometryExtension>(newExtension));
324
            }
325
            else {
326
                Base::Console().Warning("Cannot restore geometry extension of type: %s\n", TypeName);
327
            }
328
        }
329

330
        reader.readEndElement("GeoExtensions");
331
    }
332
    else if(strcmp(reader.localName(),"Construction") == 0) { // legacy
333

334
        bool construction = (int)reader.getAttributeAsInteger("value") != 0;
335

336
        // prepare migration
337
        if(!this->hasExtension(GeometryMigrationExtension::getClassTypeId()))
338
            this->setExtension(std::make_unique<GeometryMigrationExtension>());
339

340
        auto ext = std::static_pointer_cast<GeometryMigrationExtension>(this->getExtension(GeometryMigrationExtension::getClassTypeId()).lock());
341

342
        ext->setMigrationType(GeometryMigrationExtension::Construction);
343
        ext->setConstruction(construction);
344

345
    }
346

347
}
348

349
boost::uuids::uuid Geometry::getTag() const
350
{
351
    return tag;
352
}
353

354
std::vector<std::weak_ptr<const GeometryExtension>> Geometry::getExtensions() const
355
{
356
    std::vector<std::weak_ptr<const GeometryExtension>> wp;
357

358
    for (auto& ext : extensions) {
359
        wp.push_back(ext);
360
    }
361

362
    return wp;
363
}
364

365
bool Geometry::hasExtension(const Base::Type & type) const
366
{
367
    return std::any_of(extensions.begin(),
368
                       extensions.end(),
369
                       [type](auto geoExt) {
370
                           return geoExt->getTypeId() == type;
371
                       });
372
}
373

374
bool Geometry::hasExtension(const std::string & name) const
375
{
376
    return std::any_of(extensions.begin(),
377
                       extensions.end(),
378
                       [name](auto geoExt) {
379
                           return geoExt->getName() == name;
380
                       });
381
}
382

383
std::weak_ptr<GeometryExtension> Geometry::getExtension(const Base::Type & type)
384
{
385
    for(const auto& ext : extensions) {
386
        if(ext->getTypeId() == type)
387
            return ext;
388
    }
389

390
    throw Base::ValueError("No geometry extension of the requested type.");
391
}
392

393
std::weak_ptr<GeometryExtension> Geometry::getExtension(const std::string & name)
394
{
395
    for(const auto& ext : extensions) {
396
        if(ext->getName() == name)
397
            return ext;
398
    }
399

400
    throw Base::ValueError("No geometry extension with the requested name.");
401
}
402

403
std::weak_ptr<const GeometryExtension> Geometry::getExtension(const Base::Type & type) const
404
{
405
    return const_cast<Geometry*>(this)->getExtension(type).lock();
406
}
407

408
std::weak_ptr<const GeometryExtension> Geometry::getExtension(const std::string & name) const
409
{
410
    return const_cast<Geometry*>(this)->getExtension(name).lock();
411
}
412

413

414
void Geometry::setExtension(std::unique_ptr<GeometryExtension> && geoext )
415
{
416
    bool hasext=false;
417

418
    for( auto & ext : extensions) {
419
        // if same type and name, this modifies the existing extension.
420
        if( ext->getTypeId() == geoext->getTypeId() &&
421
            ext->getName() == geoext->getName()){
422
            ext = std::move( geoext );
423
            ext->notifyAttachment(this);
424
            hasext = true;
425
            break;
426
        }
427
    }
428

429
    if(!hasext) { // new type-name unique id, so add.
430
        extensions.push_back(std::move( geoext ));
431
        extensions.back()->notifyAttachment(this);
432
    }
433
}
434

435
void Geometry::deleteExtension(const Base::Type & type)
436
{
437
    extensions.erase(
438
        std::remove_if( extensions.begin(),
439
                        extensions.end(),
440
                        [&type](const std::shared_ptr<GeometryExtension>& ext){
441
                            return ext->getTypeId() == type;
442
                        }),
443
        extensions.end());
444
}
445

446
void Geometry::deleteExtension(const std::string & name)
447
{
448
    extensions.erase(
449
        std::remove_if( extensions.begin(),
450
                        extensions.end(),
451
                        [&name](const std::shared_ptr<GeometryExtension>& ext){
452
                            return ext->getName() == name;
453
                        }),
454
        extensions.end());
455
}
456

457

458
void Geometry::createNewTag()
459
{
460
    // Initialize a random number generator, to avoid Valgrind false positives.
461
    // The random number generator is not threadsafe so we guard it.  See
462
    // https://www.boost.org/doc/libs/1_62_0/libs/uuid/uuid.html#Design%20notes
463
    static boost::mt19937 ran;
464
    static bool seeded = false;
465
    static boost::mutex random_number_mutex;
466

467
    boost::lock_guard<boost::mutex> guard(random_number_mutex);
468

469
    if (!seeded) {
470
        ran.seed(static_cast<unsigned int>(std::time(nullptr)));
471
        seeded = true;
472
    }
473
    static boost::uuids::basic_random_generator<boost::mt19937> gen(&ran);
474

475
    tag = gen();
476
}
477

478
void Geometry::assignTag(const Part::Geometry * geo)
479
{
480
    if(geo->getTypeId() == this->getTypeId())
481
        this->tag = geo->tag;
482
    else
483
        throw Base::TypeError("Geometry tag can not be assigned as geometry types do not match.");
484
}
485

486
void Geometry::copyNonTag(const Part::Geometry* src)
487
{
488
    for (auto& ext : src->extensions) {
489
        this->extensions.push_back(ext->copy());
490
        extensions.back()->notifyAttachment(this);
491
    }
492
}
493

494
Geometry *Geometry::clone() const
495
{
496
    Geometry* cpy = this->copy();
497
    cpy->tag = this->tag;
498

499
    // class copy is responsible for copying extensions
500

501
    return cpy;
502
}
503

504
void Geometry::mirror(const Base::Vector3d& point) const
505
{
506
    gp_Pnt pnt(point.x, point.y, point.z);
507
    handle()->Mirror(pnt);
508
}
509

510
void Geometry::mirror(const Base::Vector3d& point, const Base::Vector3d& dir) const
511
{
512
    gp_Ax1 ax1(gp_Pnt(point.x,point.y,point.z), gp_Dir(dir.x,dir.y,dir.z));
513
    handle()->Mirror(ax1);
514
}
515

516
void Geometry::rotate(const Base::Placement& plm) const
517
{
518
    Base::Rotation rot(plm.getRotation());
519
    Base::Vector3d pnt, dir;
520

521
    double angle;
522

523
    rot.getValue(dir, angle);
524
    pnt = plm.getPosition();
525

526
    gp_Ax1 ax1(gp_Pnt(pnt.x,pnt.y,pnt.z), gp_Dir(dir.x,dir.y,dir.z));
527
    handle()->Rotate(ax1, angle);
528
}
529

530
void Geometry::scale(const Base::Vector3d& vec, double scale) const
531
{
532
    gp_Pnt pnt(vec.x, vec.y, vec.z);
533
    handle()->Scale(pnt, scale);
534
}
535

536
void Geometry::transform(const Base::Matrix4D& mat) const
537
{
538
    gp_Trsf trf;
539
    trf.SetValues(mat[0][0],mat[0][1],mat[0][2],mat[0][3],
540
                mat[1][0],mat[1][1],mat[1][2],mat[1][3],
541
                mat[2][0],mat[2][1],mat[2][2],mat[2][3]);
542
    handle()->Transform(trf);
543
}
544

545
void Geometry::translate(const Base::Vector3d& vec) const
546
{
547
    gp_Vec trl(vec.x, vec.y, vec.z);
548
    handle()->Translate(trl);
549
}
550

551

552
// -------------------------------------------------
553

554
TYPESYSTEM_SOURCE(Part::GeomPoint,Part::Geometry)
555

556
GeomPoint::GeomPoint()
557
{
558
    this->myPoint = new Geom_CartesianPoint(0,0,0);
559
}
560

561
GeomPoint::GeomPoint(const Handle(Geom_CartesianPoint)& p)
562
{
563
    setHandle(p);
564
}
565

566
GeomPoint::GeomPoint(const Base::Vector3d& p)
567
{
568
    this->myPoint = new Geom_CartesianPoint(p.x,p.y,p.z);
569
}
570

571
GeomPoint::~GeomPoint() = default;
572

573
const Handle(Geom_Geometry)& GeomPoint::handle() const
574
{
575
    return myPoint;
576
}
577

578

579
void GeomPoint::setHandle(const Handle(Geom_CartesianPoint)& p)
580
{
581
    myPoint = Handle(Geom_CartesianPoint)::DownCast(p->Copy());
582
}
583

584
Geometry *GeomPoint::copy() const
585
{
586
    auto newPoint = new GeomPoint(myPoint);
587
    newPoint->copyNonTag(this);
588
    return newPoint;
589
}
590

591
TopoDS_Shape GeomPoint::toShape() const
592
{
593
    return BRepBuilderAPI_MakeVertex(myPoint->Pnt());
594
}
595

596
Base::Vector3d GeomPoint::getPoint()const
597
{
598
    return Base::Vector3d(myPoint->X(),myPoint->Y(),myPoint->Z());
599
}
600

601
void GeomPoint::setPoint(const Base::Vector3d& p)
602
{
603
    this->myPoint->SetCoord(p.x,p.y,p.z);
604
}
605

606
// Persistence implementer
607
unsigned int GeomPoint::getMemSize () const
608
{
609
    return sizeof(Geom_CartesianPoint);
610
}
611

612
void GeomPoint::Save(Base::Writer &writer) const
613
{
614
    // save the attributes of the father class
615
    Geometry::Save(writer);
616

617
    Base::Vector3d Point   =  getPoint();
618
    writer.Stream()
619
         << writer.ind()
620
             << "<GeomPoint "
621
                << "X=\"" <<  Point.x <<
622
                "\" Y=\"" <<  Point.y <<
623
                "\" Z=\"" <<  Point.z <<
624
             "\"/>" << std::endl;
625
}
626

627
void GeomPoint::Restore(Base::XMLReader &reader)
628
{
629
    // read the attributes of the father class
630
    Geometry::Restore(reader);
631

632
    double X,Y,Z;
633
    // read my Element
634
    reader.readElement("GeomPoint");
635
    // get the value of my Attribute
636
    X = reader.getAttributeAsFloat("X");
637
    Y = reader.getAttributeAsFloat("Y");
638
    Z = reader.getAttributeAsFloat("Z");
639

640
    // set the read geometry
641
    setPoint(Base::Vector3d(X,Y,Z) );
642
}
643

644
PyObject *GeomPoint::getPyObject()
645
{
646
    return new PointPy(new GeomPoint(getPoint()));
647
}
648

649
bool GeomPoint::isSame(const Geometry &other, double tol, double) const
650
{
651
    return other.getTypeId() == getTypeId()
652
        && Base::DistanceP2(dynamic_cast<const GeomPoint &>(other).getPoint(),getPoint()) <= tol*tol;
653
}
654

655
// -------------------------------------------------
656

657
TYPESYSTEM_SOURCE_ABSTRACT(Part::GeomCurve,Part::Geometry)
658

659
GeomCurve::GeomCurve() = default;
660

661
GeomCurve::~GeomCurve() = default;
662

663
TopoDS_Shape GeomCurve::toShape() const
664
{
665
    Handle(Geom_Curve) c = Handle(Geom_Curve)::DownCast(handle());
666
    BRepBuilderAPI_MakeEdge mkBuilder(c, c->FirstParameter(), c->LastParameter());
667
    return mkBuilder.Shape();
668
}
669

670
// Copied from OCC BRepBndLib_1.cxx
671
//=======================================================================
672
// Function : IsLinear
673
// purpose : Returns TRUE if theC is line-like.
674
//=======================================================================
675
static Standard_Boolean IsLinear(const Adaptor3d_Curve& theC)
676
{
677
    const GeomAbs_CurveType aCT = theC.GetType();
678
    if(aCT == GeomAbs_OffsetCurve)
679
    {
680
        return IsLinear(GeomAdaptor_Curve(theC.OffsetCurve()->BasisCurve()));
681
    }
682

683
    if((aCT == GeomAbs_BSplineCurve) || (aCT == GeomAbs_BezierCurve))
684
    {
685
        // Indeed, curves with C0-continuity and degree==1, may be
686
        // represented with set of points. It will be possible made
687
        // in the future.
688

689
        return ((theC.Degree() == 1) &&
690
                (theC.Continuity() != GeomAbs_C0));
691
    }
692

693
    if(aCT == GeomAbs_Line)
694
    {
695
        return Standard_True;
696
    }
697

698
    return Standard_False;
699
}
700

701
bool GeomCurve::isLinear(Base::Vector3d *dir, Base::Vector3d *base) const
702
{
703
    Handle(Geom_Curve) curve = Handle(Geom_Curve)::DownCast(handle());
704
    return isLinear(curve, dir, base);
705
}
706

707
bool GeomCurve::isLinear(const Handle(Geom_Curve) &curve, Base::Vector3d *dir, Base::Vector3d *base)
708
{
709
    GeomAdaptor_Curve adaptor(curve);
710
    if (!IsLinear(adaptor))
711
        return false;
712

713
    if (dir || base) {
714
        if (adaptor.GetType() == GeomAbs_Line) {
715
            // Special treatment of Geom_Line because it is infinite
716
            Handle(Geom_Line) curv = Handle(Geom_Line)::DownCast(curve);
717
            if (base) {
718
                gp_Pnt Pos = curv->Lin().Location();
719
                *base = Base::Vector3d(Pos.X(), Pos.Y(), Pos.Z());
720
            }
721
            if (dir) {
722
                gp_Dir Dir = curv->Lin().Direction();
723
                *dir = Base::Vector3d(Dir.X(), Dir.Y(), Dir.Z());
724
            }
725
            return true;
726
        }
727
        try {
728
            GeomLProp_CLProps prop1(curve,curve->FirstParameter(),0,Precision::Confusion());
729
            GeomLProp_CLProps prop2(curve,curve->LastParameter(),0,Precision::Confusion());
730
            const gp_Pnt &p1 = prop1.Value();
731
            const gp_Pnt &p2 = prop2.Value();
732
            if (base)
733
                *base = Base::Vector3d(p1.X(), p1.Y(), p1.Z());
734
            if (dir)
735
                *dir = Base::Vector3d(p2.X() - p1.X(), p2.Y() - p1.Y(), p2.Z() - p1.Z());
736
        }
737
        catch (Standard_Failure& e) {
738
            THROWM(Base::CADKernelError,e.GetMessageString())
739
        }
740
    }
741
    return true;
742
}
743

744
GeomLine* GeomCurve::toLine(KeepTag clone) const
745
{
746
    if (!isLinear())
747
        return nullptr;
748

749
    auto p1 = pointAtParameter(getFirstParameter());
750
    auto p2 = pointAtParameter(getLastParameter());
751
    auto res = new GeomLine(p1, p2-p1);
752
    res->copyNonTag(this);
753
    if (clone == CopyTag) {
754
        res->tag = this->tag;
755
    }
756
    return res;
757
}
758

759
GeomLineSegment* GeomCurve::toLineSegment(KeepTag clone) const
760
{
761
    if (!isLinear())
762
        return nullptr;
763

764
    Base::Vector3d start, end;
765
    if (isDerivedFrom(GeomBoundedCurve::getClassTypeId())) {
766
        start = dynamic_cast<const GeomBoundedCurve*>(this)->getStartPoint();
767
        end = dynamic_cast<const GeomBoundedCurve*>(this)->getEndPoint();
768
    } else {
769
        start = pointAtParameter(getFirstParameter());
770
        end = pointAtParameter(getLastParameter());
771
    }
772
    auto res = new GeomLineSegment;
773
    res->setPoints(start, end);
774
    res->copyNonTag(this);
775
    if (clone == CopyTag) {
776
        res->tag = this->tag;
777
    }
778
    return res;
779
}
780

781
GeomBSplineCurve* GeomCurve::toBSpline(double first, double last) const
782
{
783
    ShapeConstruct_Curve scc;
784
    Handle(Geom_Curve) c = Handle(Geom_Curve)::DownCast(handle());
785
    Handle(Geom_BSplineCurve) spline = scc.ConvertToBSpline(c, first, last, Precision::Confusion());
786
    if (spline.IsNull())
787
        THROWM(Base::CADKernelError,"Conversion to B-spline failed")
788
    return new GeomBSplineCurve(spline);
789
}
790

791
GeomBSplineCurve* GeomCurve::toNurbs(double first, double last) const
792
{
793
    return toBSpline(first, last);
794
}
795

796
bool GeomCurve::tangent(double u, gp_Dir& dir) const
797
{
798
    Handle(Geom_Curve) curve = Handle(Geom_Curve)::DownCast(handle());
799
    GeomLProp_CLProps prop(curve, u,1,Precision::Confusion());
800
    if (prop.IsTangentDefined()) {
801
        prop.Tangent(dir);
802
        return true;
803
    }
804

805
    return false;
806
}
807

808
bool GeomCurve::tangent(double u, Base::Vector3d& dir) const
809
{
810
    gp_Dir gdir;
811

812
    if (tangent(u, gdir)) {
813
        dir = Base::Vector3d(gdir.X(),gdir.Y(),gdir.Z());
814

815
        return true;
816
    }
817

818
    return false;
819
}
820

821
Base::Vector3d GeomCurve::value(double u) const
822
{
823
    Handle(Geom_Curve) curve = Handle(Geom_Curve)::DownCast(handle());
824

825
    const gp_Pnt &point = curve->Value(u);
826

827
    return Base::Vector3d(point.X(),point.Y(),point.Z());
828
}
829

830
Base::Vector3d GeomCurve::pointAtParameter(double u) const
831
{
832
    Handle(Geom_Curve) curve = Handle(Geom_Curve)::DownCast(handle());
833
    GeomLProp_CLProps prop(curve, u,0,Precision::Confusion());
834

835
    const gp_Pnt &point=prop.Value();
836

837
    return Base::Vector3d(point.X(),point.Y(),point.Z());
838
}
839

840
Base::Vector3d GeomCurve::firstDerivativeAtParameter(double u) const
841
{
842
    Handle(Geom_Curve) curve = Handle(Geom_Curve)::DownCast(handle());
843
    GeomLProp_CLProps prop(curve, u,1,Precision::Confusion());
844

845
    const gp_Vec &vec=prop.D1();
846

847
    return Base::Vector3d(vec.X(),vec.Y(),vec.Z());
848
}
849

850
Base::Vector3d GeomCurve::secondDerivativeAtParameter(double u) const
851
{
852
    Handle(Geom_Curve) curve = Handle(Geom_Curve)::DownCast(handle());
853
    GeomLProp_CLProps prop(curve, u,2,Precision::Confusion());
854

855
    const gp_Vec &vec=prop.D2();
856

857
    return Base::Vector3d(vec.X(),vec.Y(),vec.Z());
858
}
859

860
bool GeomCurve::normalAt(double u, Base::Vector3d& dir) const
861
{
862
    Handle(Geom_Curve) curve = Handle(Geom_Curve)::DownCast(handle());
863

864
    try {
865
        if (!curve.IsNull()) {
866
            GeomLProp_CLProps prop(curve, u,2,Precision::Confusion());
867
            gp_Dir gdir;
868
            prop.Normal(gdir);
869
            dir = Base::Vector3d(gdir.X(), gdir.Y(), gdir.Z());
870

871
            return true;
872
        }
873
    }
874
    catch (const LProp_NotDefined&) {
875
        dir.Set(0,0,0);
876
        return false;
877
    }
878
    catch (Standard_Failure& exc) {
879
        THROWM(Base::CADKernelError, exc.GetMessageString())
880
    }
881

882
    return false;
883
}
884

885
bool GeomCurve::normalAt(const Base::Vector3d & curvepoint, Base::Vector3d & dir) const
886
{
887
    double u;
888
    closestParameter(curvepoint, u);
889

890
    return normalAt(u, dir);
891
}
892

893
bool GeomCurve::intersect(  const GeomCurve *curve,
894
                            std::vector<std::pair<Base::Vector3d, Base::Vector3d>>& points,
895
                            double tol) const
896
{
897
    Handle(Geom_Curve) curve1 = Handle(Geom_Curve)::DownCast(handle());
898
    Handle(Geom_Curve) curve2 = Handle(Geom_Curve)::DownCast(curve->handle());
899

900
    if(!curve1.IsNull() && !curve2.IsNull()) {
901
        return intersect(curve1,curve2,points, tol);
902
    }
903
    else
904
        return false;
905

906
}
907

908
bool GeomCurve::intersect(const Handle(Geom_Curve)& curve1, const Handle(Geom_Curve)& curve2,
909
                std::vector<std::pair<Base::Vector3d, Base::Vector3d>>& points,
910
                double tol)
911
{
912
    // https://forum.freecad.org/viewtopic.php?f=10&t=31700
913
    if (curve1->IsKind(STANDARD_TYPE(Geom_BoundedCurve)) &&
914
        curve2->IsKind(STANDARD_TYPE(Geom_BoundedCurve))){
915

916
        Handle(Geom_BoundedCurve) bcurve1 = Handle(Geom_BoundedCurve)::DownCast(curve1);
917
        Handle(Geom_BoundedCurve) bcurve2 = Handle(Geom_BoundedCurve)::DownCast(curve2);
918

919
        gp_Pnt c1s = bcurve1->StartPoint();
920
        gp_Pnt c2s = bcurve2->StartPoint();
921
        gp_Pnt c1e = bcurve1->EndPoint();
922
        gp_Pnt c2e = bcurve2->EndPoint();
923

924
        auto checkendpoints = [&points,tol]( gp_Pnt p1, gp_Pnt p2) {
925
            if(p1.Distance(p2) < tol)
926
                points.emplace_back(Base::Vector3d(p1.X(),p1.Y(),p1.Z()),Base::Vector3d(p2.X(),p2.Y(),p2.Z()));
927
        };
928

929
        checkendpoints(c1s,c2s);
930
        checkendpoints(c1s,c2e);
931
        checkendpoints(c1e,c2s);
932
        checkendpoints(c1e,c2e);
933

934
    }
935

936
    try {
937

938
        GeomAPI_ExtremaCurveCurve intersector(curve1, curve2);
939

940
        if (intersector.NbExtrema() == 0 || intersector.LowerDistance() > tol) {
941
            // No intersection
942
            return false;
943
        }
944

945
        for (int index = 1; index <= intersector.NbExtrema(); index++) {
946
            if (intersector.Distance(index) > tol)
947
                continue;
948

949
            gp_Pnt p1, p2;
950
            intersector.Points(index, p1, p2);
951
            points.emplace_back(Base::Vector3d(p1.X(),p1.Y(),p1.Z()),Base::Vector3d(p2.X(),p2.Y(),p2.Z()));
952
        }
953
    }
954
    catch (Standard_Failure& exc) {
955
        // Yes Extrema finding failed, but if we got an intersection then go on with it
956
        if(!points.empty())
957
            return !points.empty();
958
        else
959
            THROWM(Base::CADKernelError,exc.GetMessageString())
960
    }
961

962

963
    return !points.empty();
964
}
965

966
bool GeomCurve::closestParameter(const Base::Vector3d& point, double &u) const
967
{
968
    Handle(Geom_Curve) curve = Handle(Geom_Curve)::DownCast(handle());
969
    try {
970
        if (!curve.IsNull()) {
971
            gp_Pnt pnt(point.x,point.y,point.z);
972
            GeomAPI_ProjectPointOnCurve ppc(pnt, curve);
973
            u = ppc.LowerDistanceParameter();
974
            return true;
975
        }
976
    }
977
    catch (StdFail_NotDone& exc) {
978
        if (curve->IsKind(STANDARD_TYPE(Geom_BoundedCurve))){
979
            Base::Vector3d firstpoint = this->pointAtParameter(curve->FirstParameter());
980
            Base::Vector3d lastpoint = this->pointAtParameter(curve->LastParameter());
981

982
            if((firstpoint-point).Length() < (lastpoint-point).Length())
983
                u = curve->FirstParameter();
984
            else
985
                u = curve->LastParameter();
986
        }
987
        else
988
            THROWM(Base::CADKernelError, exc.GetMessageString())
989

990
        return true;
991
    }
992
    catch (Standard_Failure& exc) {
993
        THROWM(Base::CADKernelError, exc.GetMessageString())
994
    }
995

996
    return false;
997
}
998

999
bool GeomCurve::closestParameterToBasisCurve(const Base::Vector3d& point, double &u) const
1000
{
1001
    Handle(Geom_Curve) curve = Handle(Geom_Curve)::DownCast(handle());
1002

1003
    if (curve->IsKind(STANDARD_TYPE(Geom_TrimmedCurve))){
1004
        Handle(Geom_TrimmedCurve) tc = Handle(Geom_TrimmedCurve)::DownCast(handle());
1005
        Handle(Geom_Curve) bc = tc->BasisCurve();
1006
        try {
1007
            if (!bc.IsNull()) {
1008
                gp_Pnt pnt(point.x,point.y,point.z);
1009
                GeomAPI_ProjectPointOnCurve ppc(pnt, bc);
1010
                u = ppc.LowerDistanceParameter();
1011
                return true;
1012
            }
1013
        }
1014
        catch (Standard_Failure& exc) {
1015
            THROWM(Base::CADKernelError, exc.GetMessageString())
1016
        }
1017

1018
        return false;
1019
    }
1020
    else {
1021
        return this->closestParameter(point, u);
1022
    }
1023
}
1024

1025
double GeomCurve::getFirstParameter() const
1026
{
1027
    Handle(Geom_Curve) curve = Handle(Geom_Curve)::DownCast(handle());
1028

1029
    try {
1030
        // pending check for RealFirst RealLast in case of infinite curve
1031
        return curve->FirstParameter();
1032
    }
1033
    catch (Standard_Failure& exc) {
1034

1035
        THROWM(Base::CADKernelError, exc.GetMessageString())
1036
    }
1037
}
1038

1039
double GeomCurve::getLastParameter() const
1040
{
1041
    Handle(Geom_Curve) curve = Handle(Geom_Curve)::DownCast(handle());
1042

1043
    try {
1044
        // pending check for RealFirst RealLast in case of infinite curve
1045
        return curve->LastParameter();
1046
    }
1047
    catch (Standard_Failure& exc) {
1048

1049
        THROWM(Base::CADKernelError, exc.GetMessageString())
1050
    }
1051
}
1052

1053
double GeomCurve::curvatureAt(double u) const
1054
{
1055
    Handle(Geom_Curve) curve = Handle(Geom_Curve)::DownCast(handle());
1056

1057
    try {
1058
        GeomLProp_CLProps prop(curve, u,2,Precision::Confusion());
1059
        return prop.Curvature();
1060
    }
1061
    catch (Standard_Failure& exc) {
1062

1063
        THROWM(Base::CADKernelError, exc.GetMessageString())
1064
    }
1065
}
1066

1067
double GeomCurve::length(double u, double v) const
1068
{
1069

1070
    Handle(Geom_Curve) curve = Handle(Geom_Curve)::DownCast(handle());
1071

1072
    try {
1073
        GeomAdaptor_Curve adaptor(curve);
1074
        return GCPnts_AbscissaPoint::Length(adaptor,u,v,Precision::Confusion());
1075
    }
1076
    catch (Standard_Failure& exc) {
1077

1078
        THROWM(Base::CADKernelError, exc.GetMessageString())
1079
    }
1080
}
1081

1082
void GeomCurve::reverse()
1083
{
1084
    Handle(Geom_Curve) curve = Handle(Geom_Curve)::DownCast(handle());
1085

1086
    try {
1087
        curve->Reverse();
1088
    }
1089
    catch (Standard_Failure& exc) {
1090

1091
        THROWM(Base::CADKernelError, exc.GetMessageString())
1092
    }
1093
}
1094

1095

1096
// -------------------------------------------------
1097

1098
TYPESYSTEM_SOURCE_ABSTRACT(Part::GeomBoundedCurve, Part::GeomCurve)
1099

1100
GeomBoundedCurve::GeomBoundedCurve() = default;
1101

1102
GeomBoundedCurve::~GeomBoundedCurve() = default;
1103

1104
Base::Vector3d GeomBoundedCurve::getStartPoint() const
1105
{
1106
    Handle(Geom_BoundedCurve) curve =  Handle(Geom_BoundedCurve)::DownCast(handle());
1107
    gp_Pnt pnt = curve->StartPoint();
1108

1109
    return Base::Vector3d(pnt.X(), pnt.Y(), pnt.Z());
1110
}
1111

1112
Base::Vector3d GeomBoundedCurve::getEndPoint() const
1113
{
1114
    Handle(Geom_BoundedCurve) curve =  Handle(Geom_BoundedCurve)::DownCast(handle());
1115
    gp_Pnt pnt = curve->EndPoint();
1116

1117
    return Base::Vector3d(pnt.X(), pnt.Y(), pnt.Z());
1118
}
1119

1120

1121
// -------------------------------------------------
1122

1123
TYPESYSTEM_SOURCE(Part::GeomBezierCurve, Part::GeomBoundedCurve)
1124

1125
GeomBezierCurve::GeomBezierCurve()
1126
{
1127
    TColgp_Array1OfPnt poles(1,2);
1128
    poles(1) = gp_Pnt(0.0,0.0,0.0);
1129
    poles(2) = gp_Pnt(0.0,0.0,1.0);
1130
    Handle(Geom_BezierCurve) bezier = new Geom_BezierCurve(poles);
1131
    this->myCurve = bezier;
1132
}
1133

1134
GeomBezierCurve::GeomBezierCurve(const Handle(Geom_BezierCurve)& bezier)
1135
{
1136
    setHandle(bezier);
1137
}
1138

1139
GeomBezierCurve::GeomBezierCurve( const std::vector<Base::Vector3d>& poles, const std::vector<double>& weights)
1140
{
1141
    if (poles.size() != weights.size())
1142
        throw Base::ValueError("poles and weights mismatch");
1143

1144
    TColgp_Array1OfPnt poleArray(1,poles.size());
1145
    TColStd_Array1OfReal weightArray(1,poles.size());
1146
    for (std::size_t index = 1; index <= poles.size(); index++) {
1147
        poleArray.SetValue(index, gp_Pnt(poles[index-1].x,poles[index-1].y,poles[index-1].z));
1148
        weightArray.SetValue(index, weights[index-1]);
1149
    }
1150
    this->myCurve = new Geom_BezierCurve (poleArray, weightArray);
1151
}
1152

1153
GeomBezierCurve::~GeomBezierCurve() = default;
1154

1155
void GeomBezierCurve::setHandle(const Handle(Geom_BezierCurve)& curve)
1156
{
1157
    myCurve = Handle(Geom_BezierCurve)::DownCast(curve->Copy());
1158
}
1159

1160
const Handle(Geom_Geometry)& GeomBezierCurve::handle() const
1161
{
1162
    return myCurve;
1163
}
1164

1165
Geometry *GeomBezierCurve::copy() const
1166
{
1167
    auto *newCurve = new GeomBezierCurve(myCurve);
1168
    newCurve->copyNonTag(this);
1169
    return newCurve;
1170
}
1171

1172
std::vector<Base::Vector3d> GeomBezierCurve::getPoles() const
1173
{
1174
    std::vector<Base::Vector3d> poles;
1175
    poles.reserve(myCurve->NbPoles());
1176
    TColgp_Array1OfPnt poleArray(1,myCurve->NbPoles());
1177
    myCurve->Poles(poleArray);
1178

1179
    for (Standard_Integer index=poleArray.Lower(); index<=poleArray.Upper(); index++) {
1180
        const gp_Pnt& pnt = poleArray(index);
1181
        poles.emplace_back(pnt.X(), pnt.Y(), pnt.Z());
1182
    }
1183
    return poles;
1184
}
1185

1186
std::vector<double> GeomBezierCurve::getWeights() const
1187
{
1188
    std::vector<double> weights;
1189
    weights.reserve(myCurve->NbPoles());
1190
    TColStd_Array1OfReal weightArray(1,myCurve->NbPoles());
1191
    myCurve->Weights(weightArray);
1192

1193
    for (Standard_Integer index=weightArray.Lower(); index<=weightArray.Upper(); index++) {
1194
        const Standard_Real& real = weightArray(index);
1195
        weights.push_back(real);
1196
    }
1197
    return weights;
1198
}
1199

1200
// Persistence implementer
1201
unsigned int GeomBezierCurve::getMemSize () const
1202
{
1203
    return sizeof(Geom_BezierCurve);
1204
}
1205

1206
void GeomBezierCurve::Save(Base::Writer& writer) const
1207
{
1208
    // save the attributes of the father class
1209
    GeomCurve::Save(writer);
1210

1211
    std::vector<Base::Vector3d> poles   = this->getPoles();
1212
    std::vector<double> weights         = this->getWeights();
1213

1214
    writer.Stream()
1215
         << writer.ind()
1216
             << "<BezierCurve "
1217
                << "PolesCount=\"" <<  poles.size() <<
1218
             "\">" << std::endl;
1219

1220
    writer.incInd();
1221

1222
    std::vector<Base::Vector3d>::const_iterator itp;
1223
    std::vector<double>::const_iterator itw;
1224

1225
    for (itp = poles.begin(), itw = weights.begin(); itp != poles.end() && itw != weights.end(); ++itp, ++itw) {
1226
        writer.Stream()
1227
            << writer.ind()
1228
            << "<Pole "
1229
            << "X=\"" << (*itp).x <<
1230
            "\" Y=\"" << (*itp).y <<
1231
            "\" Z=\"" << (*itp).z <<
1232
            "\" Weight=\"" << (*itw) <<
1233
        "\"/>" << std::endl;
1234
    }
1235

1236
    writer.decInd();
1237
    writer.Stream() << writer.ind() << "</BezierCurve>" << std::endl ;
1238
}
1239

1240
void GeomBezierCurve::Restore(Base::XMLReader& reader)
1241
{
1242
    // read the attributes of the father class
1243
    GeomCurve::Restore(reader);
1244

1245
    reader.readElement("BezierCurve");
1246
    // get the value of my attribute
1247
    int polescount = reader.getAttributeAsInteger("PolesCount");
1248

1249
    TColgp_Array1OfPnt poleArray(1,polescount);
1250
    TColStd_Array1OfReal weightArray(1,polescount);
1251

1252
    for (int index = 1; index <= polescount; index++) {
1253
        reader.readElement("Pole");
1254
        double X = reader.getAttributeAsFloat("X");
1255
        double Y = reader.getAttributeAsFloat("Y");
1256
        double Z = reader.getAttributeAsFloat("Z");
1257
        double W = reader.getAttributeAsFloat("Weight");
1258
        poleArray.SetValue(index, gp_Pnt(X,Y,Z));
1259
        weightArray.SetValue(index, W);
1260
    }
1261

1262
    reader.readEndElement("BezierCurve");
1263

1264
    try {
1265
        Handle(Geom_BezierCurve) bezier = new Geom_BezierCurve(poleArray, weightArray);
1266

1267
        if (!bezier.IsNull())
1268
            this->myCurve = bezier;
1269
        else
1270
            THROWM(Base::CADKernelError,"BezierCurve restore failed")
1271
    }
1272
    catch (Standard_Failure& exc) {
1273

1274
        THROWM(Base::CADKernelError, exc.GetMessageString())
1275
    }
1276
}
1277

1278
PyObject *GeomBezierCurve::getPyObject()
1279
{
1280
    return new BezierCurvePy(dynamic_cast<GeomBezierCurve*>(this->clone()));
1281
}
1282

1283
bool GeomBezierCurve::isSame(const Geometry &_other, double tol, double) const
1284
{
1285
    if(_other.getTypeId() != getTypeId())
1286
        return false;
1287

1288
    auto &other = dynamic_cast<const GeomBezierCurve &>(_other);
1289

1290
    Standard_Integer c = myCurve->NbPoles();
1291
    if(c!= other.myCurve->NbPoles())
1292
        return false;
1293

1294
    double tol2 = tol*tol;
1295
    for(Standard_Integer index =1; index <=c; ++index) {
1296
        if(myCurve->Pole(index).SquareDistance(other.myCurve->Pole(index)) > tol2
1297
                || fabs(myCurve->Weight(index) - other.myCurve->Weight(index)) > tol)
1298
            return false;
1299
    }
1300
    return true;
1301
}
1302

1303
// -------------------------------------------------
1304

1305
TYPESYSTEM_SOURCE(Part::GeomBSplineCurve,Part::GeomBoundedCurve)
1306

1307
GeomBSplineCurve::GeomBSplineCurve()
1308
{
1309
    TColgp_Array1OfPnt poles(1,2);
1310
    poles(1) = gp_Pnt(0.0,0.0,0.0);
1311
    poles(2) = gp_Pnt(1.0,0.0,0.0);
1312

1313
    TColStd_Array1OfReal knots(1,2);
1314
    knots(1) = 0.0;
1315
    knots(2) = 1.0;
1316

1317
    TColStd_Array1OfInteger mults(1,2);
1318
    mults(1) = 2;
1319
    mults(2) = 2;
1320

1321
    this->myCurve = new Geom_BSplineCurve(poles, knots, mults, 1);
1322
}
1323

1324
GeomBSplineCurve::GeomBSplineCurve(const Handle(Geom_BSplineCurve)& b)
1325
{
1326
    setHandle(b);
1327
}
1328

1329
GeomBSplineCurve::GeomBSplineCurve( const std::vector<Base::Vector3d>& poles, const std::vector<double>& weights,
1330
                  const std::vector<double>& knots, const std::vector<int>& multiplicities,
1331
                  int degree, bool periodic, bool checkrational)
1332
{
1333
    if (poles.size() != weights.size())
1334
        throw Base::ValueError("poles and weights mismatch");
1335

1336
    if (knots.size() != multiplicities.size())
1337
        throw Base::ValueError("knots and multiplicities mismatch");
1338

1339
    TColgp_Array1OfPnt p(1,poles.size());
1340
    TColStd_Array1OfReal w(1,poles.size());
1341
    TColStd_Array1OfReal k(1,knots.size());
1342
    TColStd_Array1OfInteger m(1,knots.size());
1343

1344
    for (std::size_t index = 1; index <= poles.size(); index++) {
1345
        p.SetValue(index, gp_Pnt(poles[index -1].x,poles[index -1].y,poles[index -1].z));
1346
        w.SetValue(index, weights[index -1]);
1347
    }
1348

1349
    for (std::size_t index = 1; index <= knots.size(); index++) {
1350
        k.SetValue(index, knots[index -1]);
1351
        m.SetValue(index, multiplicities[index -1]);
1352
    }
1353

1354
    this->myCurve = new Geom_BSplineCurve (p, w, k, m, degree, periodic?Standard_True:Standard_False, checkrational?Standard_True:Standard_False);
1355

1356
}
1357

1358

1359
GeomBSplineCurve::~GeomBSplineCurve() = default;
1360

1361
void GeomBSplineCurve::setHandle(const Handle(Geom_BSplineCurve)& curve)
1362
{
1363
    myCurve = Handle(Geom_BSplineCurve)::DownCast(curve->Copy());
1364
}
1365

1366
const Handle(Geom_Geometry)& GeomBSplineCurve::handle() const
1367
{
1368
    return myCurve;
1369
}
1370

1371
Geometry *GeomBSplineCurve::copy() const
1372
{
1373
    try {
1374
        auto *newCurve = new GeomBSplineCurve(myCurve);
1375
        newCurve->copyNonTag(this);
1376
        return newCurve;
1377
    }
1378
    catch (Standard_Failure& exc) {
1379
        THROWM(Base::CADKernelError, exc.GetMessageString())
1380
    }
1381
}
1382

1383
int GeomBSplineCurve::countPoles() const
1384
{
1385
    return myCurve->NbPoles();
1386
}
1387

1388
int GeomBSplineCurve::countKnots() const
1389
{
1390
    return myCurve->NbKnots();
1391
}
1392

1393
void GeomBSplineCurve::setPole(int index, const Base::Vector3d& pole, double weight)
1394
{
1395
    try {
1396
        gp_Pnt pnt(pole.x,pole.y,pole.z);
1397
        if (weight < 0.0)
1398
            myCurve->SetPole(index,pnt);
1399
        else
1400
            myCurve->SetPole(index,pnt,weight);
1401
    }
1402
    catch (Standard_Failure& e) {
1403
        THROWM(Base::CADKernelError,e.GetMessageString())
1404
    }
1405
}
1406

1407
std::list<Geometry*> GeomBSplineCurve::toBiArcs(double tolerance) const
1408
{
1409
    BSplineCurveBiArcs arcs(this->myCurve);
1410
    return arcs.toBiArcs(tolerance);
1411
}
1412

1413
void GeomBSplineCurve::workAroundOCCTBug(const std::vector<double>& weights)
1414
{
1415
    // If during assignment of weights (during the for loop below) all weights
1416
    // become (temporarily) equal even though weights does not have equal values
1417
    // OCCT will convert all the weights (the already assigned and those not yet assigned)
1418
    // to 1.0 (nonrational b-splines have 1.0 weights). This may lead to the assignment of wrong
1419
    // of weight values.
1420
    //
1421
    // Little hack is to set the last weight to a value different from last but one current and to-be-assigned
1422

1423
    if (weights.size() < 2) // at least two poles/weights
1424
        return;
1425

1426
    auto lastindex = myCurve->NbPoles(); // OCCT is base-1
1427
    auto lastbutonevalue = myCurve->Weight(lastindex-1);
1428
    double fakelastvalue = lastbutonevalue + weights[weights.size()-2];
1429
    myCurve->SetWeight(weights.size(),fakelastvalue);
1430
}
1431

1432
void GeomBSplineCurve::setPoles(const std::vector<Base::Vector3d>& poles, const std::vector<double>& weights)
1433
{
1434
    if (poles.size() != weights.size())
1435
        throw Base::ValueError("poles and weights mismatch");
1436

1437
    workAroundOCCTBug(weights);
1438

1439
    Standard_Integer index=1;
1440

1441
    for (std::size_t i = 0; i < poles.size(); i++, index++) {
1442
        setPole(index, poles[i], weights[i]);
1443
    }
1444
}
1445

1446
void GeomBSplineCurve::setPoles(const std::vector<Base::Vector3d>& poles)
1447
{
1448
    Standard_Integer index=1;
1449

1450
    for (auto it = poles.begin(); it != poles.end(); ++it, index++){
1451
        setPole(index, *it);
1452
    }
1453
}
1454

1455
std::vector<Base::Vector3d> GeomBSplineCurve::getPoles() const
1456
{
1457
    std::vector<Base::Vector3d> poles;
1458
    poles.reserve(myCurve->NbPoles());
1459
    TColgp_Array1OfPnt p(1,myCurve->NbPoles());
1460
    myCurve->Poles(p);
1461

1462
    for (Standard_Integer i=p.Lower(); i<=p.Upper(); i++) {
1463
        const gp_Pnt& pnt = p(i);
1464
        poles.emplace_back(pnt.X(), pnt.Y(), pnt.Z());
1465
    }
1466
    return poles;
1467
}
1468

1469
std::vector<double> GeomBSplineCurve::getWeights() const
1470
{
1471
    std::vector<double> weights;
1472
    weights.reserve(myCurve->NbPoles());
1473
    TColStd_Array1OfReal w(1,myCurve->NbPoles());
1474
    myCurve->Weights(w);
1475

1476
    for (Standard_Integer i=w.Lower(); i<=w.Upper(); i++) {
1477
        const Standard_Real& real = w(i);
1478
        weights.push_back(real);
1479
    }
1480
    return weights;
1481
}
1482

1483
void GeomBSplineCurve::setWeights(const std::vector<double>& weights)
1484
{
1485
    workAroundOCCTBug(weights);
1486

1487
    try {
1488
        Standard_Integer index=1;
1489

1490
        for (auto it = weights.begin(); it != weights.end(); ++it, index++){
1491
            myCurve->SetWeight(index, *it);
1492
        }
1493
    }
1494
    catch (Standard_Failure& e) {
1495

1496
        THROWM(Base::CADKernelError,e.GetMessageString())
1497
    }
1498
}
1499

1500
void GeomBSplineCurve::setKnot(int index, const double val, int mult)
1501
{
1502
    try {
1503
        if (mult < 0)
1504
            myCurve->SetKnot(index, val);
1505
        else
1506
            myCurve->SetKnot(index, val, mult);
1507
    }
1508
    catch (Standard_Failure& e) {
1509

1510
        THROWM(Base::CADKernelError,e.GetMessageString())
1511
    }
1512
}
1513

1514
void GeomBSplineCurve::setKnots(const std::vector<double>& knots)
1515
{
1516
    Standard_Integer index=1;
1517

1518
    for (auto it = knots.begin(); it != knots.end(); ++it, index++) {
1519
        setKnot(index, *it);
1520
    }
1521
}
1522

1523
void GeomBSplineCurve::setKnots(const std::vector<double>& knots, const std::vector<int>& multiplicities)
1524
{
1525
    if (knots.size() != multiplicities.size())
1526
        throw Base::ValueError("knots and multiplicities mismatch");
1527

1528
    Standard_Integer index=1;
1529

1530
    for (std::size_t it = 0; it < knots.size(); it++, index++) {
1531
        setKnot(index, knots[it], multiplicities[it]);
1532
    }
1533
}
1534

1535
std::vector<double> GeomBSplineCurve::getKnots() const
1536
{
1537
    std::vector<double> knots;
1538
    knots.reserve(myCurve->NbKnots());
1539
    TColStd_Array1OfReal k(1,myCurve->NbKnots());
1540
    myCurve->Knots(k);
1541

1542
    for (Standard_Integer i=k.Lower(); i<=k.Upper(); i++) {
1543
        const Standard_Real& real = k(i);
1544
        knots.push_back(real);
1545
    }
1546
    return knots;
1547
}
1548

1549
std::vector<int> GeomBSplineCurve::getMultiplicities() const
1550
{
1551
    std::vector<int> mults;
1552
    mults.reserve(myCurve->NbKnots());
1553
    TColStd_Array1OfInteger m(1,myCurve->NbKnots());
1554
    myCurve->Multiplicities(m);
1555

1556
    for (Standard_Integer i=m.Lower(); i<=m.Upper(); i++) {
1557
        const Standard_Integer& nm = m(i);
1558
        mults.push_back(nm);
1559
    }
1560
    return mults;
1561
}
1562

1563
int GeomBSplineCurve::getMultiplicity(int index) const
1564
{
1565
    try {
1566
        return myCurve->Multiplicity(index);
1567
    }
1568
    catch (Standard_Failure& e) {
1569

1570
        THROWM(Base::CADKernelError,e.GetMessageString())
1571
    }
1572
}
1573

1574
int GeomBSplineCurve::getDegree() const
1575
{
1576
    return myCurve->Degree();
1577
}
1578

1579
bool GeomBSplineCurve::isPeriodic() const
1580
{
1581
    return myCurve->IsPeriodic()==Standard_True;
1582
}
1583

1584
void GeomBSplineCurve::setPeriodic() const
1585
{
1586
    myCurve->SetPeriodic();
1587
}
1588

1589
bool GeomBSplineCurve::isRational() const
1590
{
1591
    return myCurve->IsRational()==Standard_True;
1592
}
1593

1594
bool GeomBSplineCurve::join(const Handle(Geom_BoundedCurve)& other)
1595
{
1596
    GeomConvert_CompCurveToBSplineCurve ccbc(this->myCurve);
1597
    if (!ccbc.Add(other, Precision::Approximation()))
1598
        return false;
1599
    this->myCurve = ccbc.BSplineCurve();
1600
    return true;
1601
}
1602

1603
void GeomBSplineCurve::interpolate(const std::vector<gp_Pnt>& p, Standard_Boolean periodic)
1604
{
1605
    if (p.size() < 2)
1606
        Standard_ConstructionError::Raise();
1607

1608
    double tol3d = Precision::Approximation();
1609
    Handle(TColgp_HArray1OfPnt) pts = new TColgp_HArray1OfPnt(1, p.size());
1610
    for (std::size_t i=0; i<p.size(); i++) {
1611
        pts->SetValue(i+1, p[i]);
1612
    }
1613

1614
    GeomAPI_Interpolate interpolate(pts, periodic, tol3d);
1615
    interpolate.Perform();
1616
    this->myCurve = interpolate.Curve();
1617
}
1618

1619
void GeomBSplineCurve::interpolate(const std::vector<gp_Pnt>& p,
1620
                                   const std::vector<gp_Vec>& t)
1621
{
1622
    if (p.size() < 2)
1623
        Standard_ConstructionError::Raise();
1624
    if (p.size() != t.size())
1625
        Standard_ConstructionError::Raise();
1626

1627
    double tol3d = Precision::Approximation();
1628
    Handle(TColgp_HArray1OfPnt) pts = new TColgp_HArray1OfPnt(1, p.size());
1629
    for (std::size_t i=0; i<p.size(); i++) {
1630
        pts->SetValue(i+1, p[i]);
1631
    }
1632

1633
    TColgp_Array1OfVec tgs(1, t.size());
1634
    Handle(TColStd_HArray1OfBoolean) fgs = new TColStd_HArray1OfBoolean(1, t.size());
1635
    for (std::size_t i=0; i<p.size(); i++) {
1636
        tgs.SetValue(i+1, t[i]);
1637
        fgs->SetValue(i+1, Standard_True);
1638
    }
1639

1640
    GeomAPI_Interpolate interpolate(pts, Standard_False, tol3d);
1641
    interpolate.Load(tgs, fgs);
1642
    interpolate.Perform();
1643
    this->myCurve = interpolate.Curve();
1644
}
1645

1646
void GeomBSplineCurve::getCardinalSplineTangents(const std::vector<gp_Pnt>& p,
1647
                                                 const std::vector<double>& c,
1648
                                                 std::vector<gp_Vec>& t) const
1649
{
1650
    // https://de.wikipedia.org/wiki/Kubisch_Hermitescher_Spline#Cardinal_Spline
1651
    if (p.size() < 2)
1652
        Standard_ConstructionError::Raise();
1653
    if (p.size() != c.size())
1654
        Standard_ConstructionError::Raise();
1655

1656
    t.resize(p.size());
1657
    if (p.size() == 2) {
1658
        t[0] = gp_Vec(p[0], p[1]);
1659
        t[1] = gp_Vec(p[0], p[1]);
1660
    }
1661
    else {
1662
        std::size_t e = p.size() - 1;
1663

1664
        for (std::size_t i = 1; i < e; i++) {
1665
            gp_Vec v = gp_Vec(p[i-1], p[i+1]);
1666
            double f = 0.5 * (1-c[i]);
1667
            v.Scale(f);
1668
            t[i] = v;
1669
        }
1670

1671
        t[0] = t[1];
1672
        t[t.size()-1] = t[t.size()-2];
1673
    }
1674
}
1675

1676
void GeomBSplineCurve::getCardinalSplineTangents(const std::vector<gp_Pnt>& p, double c,
1677
                                                 std::vector<gp_Vec>& t) const
1678
{
1679
    // https://de.wikipedia.org/wiki/Kubisch_Hermitescher_Spline#Cardinal_Spline
1680
    if (p.size() < 2)
1681
        Standard_ConstructionError::Raise();
1682

1683
    t.resize(p.size());
1684
    if (p.size() == 2) {
1685
        t[0] = gp_Vec(p[0], p[1]);
1686
        t[1] = gp_Vec(p[0], p[1]);
1687
    }
1688
    else {
1689
        std::size_t e = p.size() - 1;
1690
        double f = 0.5 * (1-c);
1691

1692
        for (std::size_t i = 1; i < e; i++) {
1693
            gp_Vec v = gp_Vec(p[i-1], p[i+1]);
1694
            v.Scale(f);
1695
            t[i] = v;
1696
        }
1697

1698
        t[0] = t[1];
1699
        t[t.size()-1] = t[t.size()-2];
1700
    }
1701
}
1702

1703
void GeomBSplineCurve::makeC1Continuous(double tol, double ang_tol)
1704
{
1705
    GeomConvert::C0BSplineToC1BSplineCurve(this->myCurve, tol, ang_tol);
1706
}
1707

1708
void GeomBSplineCurve::increaseDegree(int degree)
1709
{
1710
    try {
1711
        Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast(this->handle());
1712
        curve->IncreaseDegree(degree);
1713
    }
1714
    catch (Standard_Failure& e) {
1715
        THROWM(Base::CADKernelError,e.GetMessageString())
1716
    }
1717
}
1718

1719
/*!
1720
 * \brief GeomBSplineCurve::approximate
1721
 * \param tol3d
1722
 * \param maxSegments
1723
 * \param maxDegree
1724
 * \param continuity
1725
 */
1726
void GeomBSplineCurve::approximate(double tol3d, int maxSegments, int maxDegree,
1727
                                   GeomAbs_Shape continuity)
1728
{
1729
    try {
1730
        GeomAdaptor_Curve adapt(myCurve);
1731
        Handle(GeomAdaptor_HCurve) hCurve = new GeomAdaptor_HCurve(adapt);
1732
        Approx_Curve3d approx(hCurve, tol3d, continuity, maxSegments, maxDegree);
1733
        if (approx.IsDone()) {
1734
            this->setHandle(approx.Curve());
1735
        }
1736
        else if (approx.HasResult()) {
1737
            throw Standard_Failure("Approximation of B-Spline succeeded but is outside of tolerance");
1738
        }
1739
        else {
1740
            throw Standard_Failure("Approximation of B-Spline failed");
1741
        }
1742
    }
1743
    catch (Standard_Failure& e) {
1744
        THROWM(Base::CADKernelError, e.GetMessageString())
1745
    }
1746
}
1747

1748
void GeomBSplineCurve::approximate(const std::vector<Base::Vector3d>& pnts,
1749
                                   int minDegree, int maxDegree,
1750
                                   GeomAbs_Shape continuity, double tol3d)
1751
{
1752
    try {
1753
        TColgp_Array1OfPnt coords(1, static_cast<int>(pnts.size()));
1754
        Standard_Integer index = 1;
1755
        for (const auto& it : pnts) {
1756
            coords(index++) = gp_Pnt(it.x, it.y, it.z);
1757
        }
1758

1759
        GeomAPI_PointsToBSpline fit(coords, minDegree, maxDegree, continuity, tol3d);
1760
        const Handle(Geom_BSplineCurve)& spline = fit.Curve();
1761
        if (!spline.IsNull()) {
1762
            setHandle(spline);
1763
        }
1764
        else {
1765
            throw Standard_Failure("Failed to approximate B-Spline");
1766
        }
1767
    }
1768
    catch (Standard_Failure& e) {
1769
        THROWM(Base::CADKernelError, e.GetMessageString())
1770
    }
1771
}
1772

1773
void GeomBSplineCurve::approximate(const std::vector<Base::Vector3d>& pnts,
1774
                                   Approx_ParametrizationType parType,
1775
                                   int minDegree, int maxDegree,
1776
                                   GeomAbs_Shape continuity, double tol3d)
1777
{
1778
    try {
1779
        TColgp_Array1OfPnt coords(1, static_cast<int>(pnts.size()));
1780
        Standard_Integer index = 1;
1781
        for (const auto& it : pnts) {
1782
            coords(index++) = gp_Pnt(it.x, it.y, it.z);
1783
        }
1784

1785
        GeomAPI_PointsToBSpline fit(coords, parType, minDegree, maxDegree, continuity, tol3d);
1786
        const Handle(Geom_BSplineCurve)& spline = fit.Curve();
1787
        if (!spline.IsNull()) {
1788
            setHandle(spline);
1789
        }
1790
        else {
1791
            throw Standard_Failure("Failed to approximate B-Spline");
1792
        }
1793
    }
1794
    catch (Standard_Failure& e) {
1795
        THROWM(Base::CADKernelError, e.GetMessageString())
1796
    }
1797
}
1798

1799
/*!
1800
 * \brief GeomBSplineCurve::approximate
1801
 * \param pnts Points to fit
1802
 * \param weight1 Weight of curve length as smoothing criterion
1803
 * \param weight2 Weight of curvature as smoothing criterion
1804
 * \param weight3 Weight of torsion as smoothing criterion
1805
 * \param minDegree Minimum degree
1806
 * \param maxDegree Maximum degree
1807
 * \param continuity Continuity of the spline
1808
 * \param tol3d Tolerance to the data points
1809
 */
1810
void GeomBSplineCurve::approximate(const std::vector<Base::Vector3d>& pnts,
1811
                                   double weight1, double weight2, double weight3,
1812
                                   int maxDegree, GeomAbs_Shape continuity, double tol3d)
1813
{
1814
    try {
1815
        TColgp_Array1OfPnt coords(1, static_cast<int>(pnts.size()));
1816
        Standard_Integer index = 1;
1817
        for (const auto& it : pnts) {
1818
            coords(index++) = gp_Pnt(it.x, it.y, it.z);
1819
        }
1820

1821
        GeomAPI_PointsToBSpline fit(coords, weight1, weight2, weight3,
1822
                                    maxDegree, continuity, tol3d);
1823
        const Handle(Geom_BSplineCurve)& spline = fit.Curve();
1824
        if (!spline.IsNull()) {
1825
            setHandle(spline);
1826
        }
1827
        else {
1828
            throw Standard_Failure("Failed to approximate B-Spline");
1829
        }
1830
    }
1831
    catch (Standard_Failure& e) {
1832
        THROWM(Base::CADKernelError, e.GetMessageString())
1833
    }
1834
}
1835

1836
void GeomBSplineCurve::increaseMultiplicity(int index, int multiplicity)
1837
{
1838
    try {
1839
        Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast(this->handle());
1840
        curve->IncreaseMultiplicity(index, multiplicity);
1841
    }
1842
    catch (Standard_Failure& e) {
1843
        THROWM(Base::CADKernelError,e.GetMessageString())
1844
    }
1845
}
1846

1847
void GeomBSplineCurve::insertKnot(double param, int multiplicity)
1848
{
1849
    try {
1850
        Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast(this->handle());
1851
        curve->InsertKnot(param, multiplicity);
1852
        return;
1853
    }
1854
    catch (Standard_Failure& e) {
1855
        THROWM(Base::CADKernelError,e.GetMessageString())
1856
    }
1857
}
1858

1859
bool GeomBSplineCurve::removeKnot(int index, int multiplicity, double tolerance)
1860
{
1861
    try {
1862
        Handle(Geom_BSplineCurve) curve =Handle(Geom_BSplineCurve)::DownCast(myCurve->Copy());
1863
        if (curve->RemoveKnot(index, multiplicity, tolerance)) {
1864

1865
            // It can happen that OCCT computes a negative weight but still claims the removal was successful
1866
            TColStd_Array1OfReal weights(1, curve->NbPoles());
1867
            curve->Weights(weights);
1868
            for (Standard_Integer i = weights.Lower(); i <= weights.Upper(); i++) {
1869
                double v = weights(i);
1870
                if (v <= gp::Resolution())
1871
                    return false;
1872
            }
1873

1874
            myCurve = curve;
1875
            return true;
1876
        }
1877

1878
        return false;
1879
    }
1880
    catch (Standard_Failure& e) {
1881
        THROWM(Base::CADKernelError,e.GetMessageString())
1882
    }
1883
}
1884

1885
void GeomBSplineCurve::Trim(double u, double v)
1886
{
1887
    auto splitUnwrappedBSpline = [this](double u, double v) {
1888
        // it makes a copy internally (checked in the source code of OCCT)
1889
        auto handle = GeomConvert::SplitBSplineCurve (  myCurve,
1890
                                                            u,
1891
                                                            v,
1892
                                                            Precision::Confusion()
1893
                                                        );
1894
        setHandle(handle);
1895
    };
1896

1897
    try {
1898
        if (isPeriodic() && (v < u)) {
1899
            v = v + (getLastParameter() - getFirstParameter()); // v needs one extra lap
1900
        }
1901
        splitUnwrappedBSpline(u, v);
1902
    }
1903
    catch (Standard_Failure& e) {
1904
        THROWM(Base::CADKernelError,e.GetMessageString())
1905
    }
1906
}
1907

1908
void GeomBSplineCurve::scaleKnotsToBounds(double u0, double u1)
1909
{
1910
    try {
1911
        Handle(Geom_BSplineCurve) curve = Handle(Geom_BSplineCurve)::DownCast(myCurve->Copy());
1912
        Standard_RangeError_Raise_if (u1 <= u0, " ");
1913
        TColStd_Array1OfReal k(1,curve->NbKnots());
1914
        curve->Knots(k);
1915
        if ((abs(u0-k.First()) > Precision::Confusion()) || (abs(u1-k.Last()) > Precision::Confusion())) {
1916
            BSplCLib::Reparametrize(u0, u1, k);
1917
            curve->SetKnots(k);
1918
        }
1919
        myCurve = curve;
1920
        return;
1921
    }
1922
    catch (Standard_Failure& e) {
1923
        THROWM(Base::CADKernelError,e.GetMessageString())
1924
    }
1925
}
1926

1927
// Persistence implementer
1928
unsigned int GeomBSplineCurve::getMemSize () const
1929
{
1930
    return sizeof(Geom_BSplineCurve);
1931
}
1932

1933
void GeomBSplineCurve::Save(Base::Writer& writer) const
1934
{
1935
    // save the attributes of the father class
1936
    GeomCurve::Save(writer);
1937

1938
    std::vector<Base::Vector3d> poles   = this->getPoles();
1939
    std::vector<double> weights         = this->getWeights();
1940
    std::vector<double> knots           = this->getKnots();
1941
    std::vector<int> mults              = this->getMultiplicities();
1942
    int degree                          = this->getDegree();
1943
    bool isperiodic                     = this->isPeriodic();
1944

1945
    writer.Stream()
1946
         << writer.ind()
1947
             << "<BSplineCurve "
1948
                << "PolesCount=\"" <<  poles.size() <<
1949
                 "\" KnotsCount=\"" <<  knots.size() <<
1950
                 "\" Degree=\"" <<  degree <<
1951
                 "\" IsPeriodic=\"" <<  (int) isperiodic <<
1952
             "\">" << std::endl;
1953

1954
    writer.incInd();
1955

1956
    std::vector<Base::Vector3d>::const_iterator itp;
1957
    std::vector<double>::const_iterator itw;
1958

1959
    for (itp = poles.begin(), itw = weights.begin(); itp != poles.end() && itw != weights.end(); ++itp, ++itw) {
1960
        writer.Stream()
1961
            << writer.ind()
1962
            << "<Pole "
1963
            << "X=\"" << (*itp).x <<
1964
            "\" Y=\"" << (*itp).y <<
1965
            "\" Z=\"" << (*itp).z <<
1966
            "\" Weight=\"" << (*itw) <<
1967
        "\"/>" << std::endl;
1968
    }
1969

1970
    std::vector<double>::const_iterator itk;
1971
    std::vector<int>::const_iterator itm;
1972

1973
    for (itk = knots.begin(), itm = mults.begin(); itk != knots.end() && itm != mults.end(); ++itk, ++itm) {
1974
        writer.Stream()
1975
            << writer.ind()
1976
            << "<Knot "
1977
            << "Value=\"" << (*itk)
1978
            << "\" Mult=\"" << (*itm) <<
1979
        "\"/>" << std::endl;
1980
    }
1981

1982
    writer.decInd();
1983
    writer.Stream() << writer.ind() << "</BSplineCurve>" << std::endl ;
1984
}
1985

1986
void GeomBSplineCurve::Restore(Base::XMLReader& reader)
1987
{
1988
    // read the attributes of the father class
1989
    GeomCurve::Restore(reader);
1990

1991
    reader.readElement("BSplineCurve");
1992
    // get the value of my attribute
1993
    int polescount = reader.getAttributeAsInteger("PolesCount");
1994
    int knotscount = reader.getAttributeAsInteger("KnotsCount");
1995
    int degree = reader.getAttributeAsInteger("Degree");
1996
    bool isperiodic = (bool) reader.getAttributeAsInteger("IsPeriodic");
1997

1998
    // Handle(Geom_BSplineCurve) spline = new
1999
    // Geom_BSplineCurve(occpoles,occweights,occknots,occmults,degree,
2000
    // Base::asBoolean(periodic),
2001
    // Base::asBoolean(CheckRational));
2002

2003
    TColgp_Array1OfPnt p(1,polescount);
2004
    TColStd_Array1OfReal w(1,polescount);
2005
    TColStd_Array1OfReal k(1,knotscount);
2006
    TColStd_Array1OfInteger m(1,knotscount);
2007

2008
    for (int i = 1; i <= polescount; i++) {
2009
        reader.readElement("Pole");
2010
        double X = reader.getAttributeAsFloat("X");
2011
        double Y = reader.getAttributeAsFloat("Y");
2012
        double Z = reader.getAttributeAsFloat("Z");
2013
        double W = reader.getAttributeAsFloat("Weight");
2014
        p.SetValue(i, gp_Pnt(X,Y,Z));
2015
        w.SetValue(i, W);
2016
    }
2017

2018
    for (int i = 1; i <= knotscount; i++) {
2019
        reader.readElement("Knot");
2020
        double val = reader.getAttributeAsFloat("Value");
2021
        Standard_Integer mult = reader.getAttributeAsInteger("Mult");
2022
        k.SetValue(i, val);
2023
        m.SetValue(i, mult);
2024
    }
2025

2026
    reader.readEndElement("BSplineCurve");
2027
    // Geom_BSplineCurve(occpoles,occweights,occknots,occmults,degree,periodic,CheckRational
2028

2029
    try {
2030
        Handle(Geom_BSplineCurve) spline = new Geom_BSplineCurve(p, w, k, m, degree, isperiodic ? Standard_True : Standard_False, Standard_False);
2031

2032
        if (!spline.IsNull())
2033
            this->myCurve = spline;
2034
        else
2035
            THROWM(Base::CADKernelError,"BSpline restore failed")
2036
    }
2037
    catch (Standard_Failure& e) {
2038

2039
        THROWM(Base::CADKernelError,e.GetMessageString())
2040
    }
2041
}
2042

2043

2044
PyObject *GeomBSplineCurve::getPyObject()
2045
{
2046
    return new BSplineCurvePy(dynamic_cast<GeomBSplineCurve*>(this->clone()));
2047
}
2048

2049
bool GeomBSplineCurve::isSame(const Geometry &_other, double tol, double atol) const
2050
{
2051
    if(_other.getTypeId() != getTypeId()) {
2052
        if (isLinear() && _other.isDerivedFrom(GeomCurve::getClassTypeId())) {
2053
            std::unique_ptr<Geometry> geo(toLineSegment());
2054
            if (geo)
2055
                return geo->isSame(_other, tol, atol);
2056
        }
2057
        return false;
2058
    }
2059

2060
    auto &other = dynamic_cast<const GeomBSplineCurve &>(_other);
2061
    (void)atol;
2062

2063
    if(countPoles() != other.countPoles()
2064
        || countKnots() != other.countKnots()
2065
        || getDegree() != other.getDegree()
2066
        || isPeriodic() != other.isPeriodic())
2067
        return false;
2068

2069
    double tol2 = tol*tol;
2070
    for(int i=1, c=countPoles(); i<=c; ++i) {
2071
        if(myCurve->Pole(i).SquareDistance(other.myCurve->Pole(i)) > tol2
2072
                || fabs(myCurve->Weight(i) - other.myCurve->Weight(i)) > tol)
2073
            return false;
2074
    }
2075

2076

2077
    for(int i=1, c=countKnots(); i<=c; ++i) {
2078
        if(fabs(myCurve->Knot(i) - other.myCurve->Knot(i)) > tol)
2079
            return false;
2080
    }
2081
    return true;
2082
}
2083

2084

2085
// -------------------------------------------------
2086

2087
TYPESYSTEM_SOURCE_ABSTRACT(Part::GeomConic, Part::GeomCurve)
2088

2089
GeomConic::GeomConic() = default;
2090

2091
GeomConic::~GeomConic() = default;
2092

2093
Base::Vector3d GeomConic::getLocation() const
2094
{
2095
    Handle(Geom_Conic) conic =  Handle(Geom_Conic)::DownCast(handle());
2096
    gp_Ax1 axis = conic->Axis();
2097
    const gp_Pnt& loc = axis.Location();
2098
    return Base::Vector3d(loc.X(),loc.Y(),loc.Z());
2099
}
2100

2101
void GeomConic::setLocation(const Base::Vector3d& Center)
2102
{
2103
    gp_Pnt p1(Center.x,Center.y,Center.z);
2104
    Handle(Geom_Conic) conic =  Handle(Geom_Conic)::DownCast(handle());
2105

2106
    try {
2107
        conic->SetLocation(p1);
2108
    }
2109
    catch (Standard_Failure& e) {
2110

2111
        THROWM(Base::CADKernelError,e.GetMessageString())
2112
    }
2113
}
2114

2115
Base::Vector3d GeomConic::getCenter() const
2116
{
2117
    Handle(Geom_Conic) conic =  Handle(Geom_Conic)::DownCast(handle());
2118
    gp_Ax1 axis = conic->Axis();
2119
    const gp_Pnt& loc = axis.Location();
2120
    return Base::Vector3d(loc.X(),loc.Y(),loc.Z());
2121
}
2122

2123
void GeomConic::setCenter(const Base::Vector3d& Center)
2124
{
2125
    gp_Pnt p1(Center.x,Center.y,Center.z);
2126
    Handle(Geom_Conic) conic =  Handle(Geom_Conic)::DownCast(handle());
2127

2128
    try {
2129
        conic->SetLocation(p1);
2130
    }
2131
    catch (Standard_Failure& e) {
2132

2133
        THROWM(Base::CADKernelError,e.GetMessageString())
2134
    }
2135
}
2136

2137
Base::Vector3d GeomConic::getAxisDirection() const
2138
{
2139
    Handle(Geom_Conic) conic =  Handle(Geom_Conic)::DownCast(handle());
2140
    gp_Ax1 axis = conic->Axis();
2141
    const gp_Dir& dir = axis.Direction();
2142
    return Base::Vector3d( dir.X(),dir.Y(),dir.Z());
2143
}
2144

2145
/*!
2146
 * \brief GeomConic::getAngleXU
2147
 * \return The angle between ellipse's major axis (in direction to focus1) and
2148
 * X axis of a default axis system in the plane of ellipse. The angle is
2149
 * counted CCW as seen when looking at the ellipse so that ellipse's axis is
2150
 * pointing at you. Note that this function may give unexpected results when
2151
 * the ellipse is in XY, but reversed, because the X axis of the default axis
2152
 * system is reversed compared to the global X axis. This angle, in conjunction
2153
 * with ellipse's axis, fully defines the orientation of the ellipse.
2154
 */
2155
double GeomConic::getAngleXU() const
2156
{
2157
    Handle(Geom_Conic) conic =  Handle(Geom_Conic)::DownCast(handle());
2158

2159
    gp_Pnt center = conic->Axis().Location();
2160
    gp_Dir normal = conic->Axis().Direction();
2161
    gp_Dir xdir = conic->XAxis().Direction();
2162

2163

2164
    gp_Ax2 xdirref(center, normal); // this is a reference system, might be CCW or CW depending on the creation method
2165

2166
    return -xdir.AngleWithRef(xdirref.XDirection(),normal);
2167

2168
}
2169

2170
/*!
2171
 * \brief GeomConic::setAngleXU complements getAngleXU.
2172
 * \param angle
2173
 */
2174
void GeomConic::setAngleXU(double angle)
2175
{
2176
    Handle(Geom_Conic) conic =  Handle(Geom_Conic)::DownCast(handle());;
2177

2178
    try {
2179
        gp_Pnt center = conic->Axis().Location();
2180
        gp_Dir normal = conic->Axis().Direction();
2181

2182
        gp_Ax1 normaxis(center, normal);
2183
        gp_Ax2 xdirref(center, normal);
2184

2185
        xdirref.Rotate(normaxis,angle);
2186
        conic->SetPosition(xdirref);
2187
    }
2188
    catch (Standard_Failure& e) {
2189

2190
        THROWM(Base::CADKernelError,e.GetMessageString())
2191
    }
2192
}
2193

2194
/*!
2195
 * \brief GeomConic::isReversed tests if an ellipse that lies in XY plane
2196
 * is reversed (i.e. drawn from startpoint to endpoint in CW direction instead
2197
 * of CCW.)
2198
 * \return Returns True if the arc is CW and false if CCW.
2199
 */
2200
bool GeomConic::isReversed() const
2201
{
2202
    Handle(Geom_Conic) conic =  Handle(Geom_Conic)::DownCast(handle());
2203
    assert(!conic.IsNull());
2204
    return conic->Axis().Direction().Z() < 0;
2205
}
2206

2207
GeomBSplineCurve* GeomConic::toNurbs(double first, double last) const
2208
{
2209
    Handle(Geom_Conic) conic =  Handle(Geom_Conic)::DownCast(handle());
2210
    Handle(Geom_Curve) curve = new Geom_TrimmedCurve(conic, first, last);
2211

2212
    // pass the trimmed conic
2213
    Handle(Geom_BSplineCurve) bspline = GeomConvert::CurveToBSplineCurve(curve);
2214
    Standard_Real fnew = bspline->FirstParameter(), lnew = bspline->LastParameter(), UTol;
2215
    if (!bspline->IsPeriodic()) {
2216
        bspline->Resolution(Precision::Confusion(), UTol);
2217
        if (Abs(first - fnew) > UTol || Abs(last - lnew) > UTol) {
2218
            TColStd_Array1OfReal knots(1,bspline->NbKnots());
2219
            bspline->Knots(knots);
2220
            BSplCLib::Reparametrize(first, last, knots);
2221
            bspline->SetKnots(knots);
2222
        }
2223
    }
2224

2225
    return new GeomBSplineCurve(bspline);
2226
}
2227

2228
bool GeomConic::isSame(const Geometry &_other, double tol, double atol) const
2229
{
2230
    if(!_other.isDerivedFrom(GeomConic::getClassTypeId()))
2231
        return false;
2232

2233
    auto &other = static_cast<const GeomConic &>(_other);
2234

2235
    Handle(Geom_Conic) conic =  Handle(Geom_Conic)::DownCast(handle());
2236
    Handle(Geom_Conic) conic2 =  Handle(Geom_Conic)::DownCast(other.handle());
2237

2238
    return conic->Position().XDirection().Angle(conic2->Position().XDirection()) <= atol
2239
        && conic->Position().YDirection().Angle(conic2->Position().YDirection()) <= atol
2240
        && Base::DistanceP2(getLocation(),other.getLocation()) <= tol*tol;
2241
}
2242

2243
// -------------------------------------------------
2244

2245
TYPESYSTEM_SOURCE(Part::GeomTrimmedCurve,Part::GeomBoundedCurve)
2246

2247
GeomTrimmedCurve::GeomTrimmedCurve() = default;
2248

2249
GeomTrimmedCurve::GeomTrimmedCurve(const Handle(Geom_TrimmedCurve)& c)
2250
{
2251
    setHandle(c);
2252
}
2253

2254
GeomTrimmedCurve::~GeomTrimmedCurve() = default;
2255

2256
void GeomTrimmedCurve::setHandle(const Handle(Geom_TrimmedCurve)& c)
2257
{
2258
    this->myCurve = Handle(Geom_TrimmedCurve)::DownCast(c->Copy());
2259
}
2260

2261
const Handle(Geom_Geometry)& GeomTrimmedCurve::handle() const
2262
{
2263
    return myCurve;
2264
}
2265

2266
Geometry *GeomTrimmedCurve::copy() const
2267
{
2268
    GeomTrimmedCurve *newCurve =  new GeomTrimmedCurve(myCurve);
2269
    newCurve->copyNonTag(this);
2270
    return newCurve;
2271
}
2272

2273
// Persistence implementer
2274
unsigned int GeomTrimmedCurve::getMemSize () const
2275
{
2276
    return sizeof(Geom_TrimmedCurve);
2277
}
2278

2279
void GeomTrimmedCurve::Save(Base::Writer &/*writer*/) const
2280
{
2281
    throw Base::NotImplementedError("GeomTrimmedCurve::Save");
2282
}
2283

2284
void GeomTrimmedCurve::Restore(Base::XMLReader &/*reader*/)
2285
{
2286
    throw Base::NotImplementedError("GeomTrimmedCurve::Restore");
2287
}
2288

2289
PyObject *GeomTrimmedCurve::getPyObject()
2290
{
2291
    return new TrimmedCurvePy(static_cast<GeomTrimmedCurve*>(this->clone()));
2292
}
2293

2294
bool GeomTrimmedCurve::isSame(const Geometry &_other, double tol, double atol) const
2295
{
2296
    if(_other.getTypeId() != getTypeId())
2297
        return false;
2298

2299
    auto &other = static_cast<const GeomTrimmedCurve &>(_other);
2300
    double u,v,u1,v1;
2301
    getRange(u,v);
2302
    other.getRange(u1,v1);
2303
    if(fabs(u-u1)>tol || fabs(v-v1)>tol)
2304
        return false;
2305

2306
    Handle(Geom_Curve) basis = myCurve->BasisCurve();
2307
    Handle(Geom_Curve) basis1 = other.myCurve->BasisCurve();
2308
    if(basis.IsNull() || basis1.IsNull() || basis->DynamicType() != basis1->DynamicType())
2309
        return false;
2310

2311
    std::unique_ptr<Geometry> b(makeFromCurve(basis));
2312
    std::unique_ptr<Geometry> b1(makeFromCurve(basis1));
2313
    if (b && b1 && b->isSame(*b1, tol, atol))
2314
        return true;
2315
    return false;
2316
}
2317

2318
bool GeomTrimmedCurve::intersectBasisCurves(  const GeomTrimmedCurve * c,
2319
                                std::vector<std::pair<Base::Vector3d, Base::Vector3d>>& points,
2320
                                double tol) const
2321
{
2322
    Handle(Geom_TrimmedCurve) curve1 =  Handle(Geom_TrimmedCurve)::DownCast(handle());
2323
    Handle(Geom_TrimmedCurve) curve2 =  Handle(Geom_TrimmedCurve)::DownCast(c->handle());
2324

2325
    Handle(Geom_Curve) bcurve1 = curve1->BasisCurve();
2326
    Handle(Geom_Curve) bcurve2 = curve2->BasisCurve();
2327

2328

2329
    if(!bcurve1.IsNull() && !bcurve2.IsNull()) {
2330

2331
        return intersect(bcurve1, bcurve2, points, tol);
2332
    }
2333
    else
2334
        return false;
2335

2336
}
2337

2338
void GeomTrimmedCurve::getRange(double& u, double& v) const
2339
{
2340
    Handle(Geom_TrimmedCurve) curve =  Handle(Geom_TrimmedCurve)::DownCast(handle());
2341
    u = curve->FirstParameter();
2342
    v = curve->LastParameter();
2343
}
2344

2345
void GeomTrimmedCurve::setRange(double u, double v)
2346
{
2347
    try {
2348
        Handle(Geom_TrimmedCurve) curve =  Handle(Geom_TrimmedCurve)::DownCast(handle());
2349

2350
        curve->SetTrim(u, v);
2351
    }
2352
    catch (Standard_Failure& e) {
2353
        THROWM(Base::CADKernelError,e.GetMessageString())
2354
    }
2355
}
2356

2357
// -------------------------------------------------
2358
TYPESYSTEM_SOURCE_ABSTRACT(Part::GeomArcOfConic,Part::GeomTrimmedCurve)
2359

2360
GeomArcOfConic::GeomArcOfConic() = default;
2361

2362
GeomArcOfConic::~GeomArcOfConic() = default;
2363

2364
/*!
2365
 * \brief GeomArcOfConic::getStartPoint
2366
 * \param emulateCCWXY: if true, the arc will pretent to be a CCW arc in XY plane.
2367
 * For this to work, the arc must lie in XY plane (i.e. Axis is either +Z or -Z).
2368
 * \return XYZ of the arc's starting point.
2369
 */
2370
Base::Vector3d GeomArcOfConic::getStartPoint(bool emulateCCWXY) const
2371
{
2372
    Handle(Geom_TrimmedCurve) curve =  Handle(Geom_TrimmedCurve)::DownCast(handle());
2373
    gp_Pnt pnt = curve->StartPoint();
2374
    if (emulateCCWXY) {
2375
        if (isReversed())
2376
            pnt = curve->EndPoint();
2377
    }
2378
    return Base::Vector3d(pnt.X(), pnt.Y(), pnt.Z());
2379
}
2380

2381
/*!
2382
 * \brief GeomArcOfConic::getEndPoint
2383
 * \param emulateCCWXY: if true, the arc will pretent to be a CCW arc in XY plane.
2384
 * For this to work, the arc must lie in XY plane (i.e. Axis is either +Z or -Z).
2385
 * \return
2386
 */
2387
Base::Vector3d GeomArcOfConic::getEndPoint(bool emulateCCWXY) const
2388
{
2389
    Handle(Geom_TrimmedCurve) curve =  Handle(Geom_TrimmedCurve)::DownCast(handle());
2390
    gp_Pnt pnt = curve->EndPoint();
2391
    if (emulateCCWXY) {
2392
        if (isReversed())
2393
            pnt = curve->StartPoint();
2394
    }
2395
    return Base::Vector3d(pnt.X(), pnt.Y(), pnt.Z());
2396
}
2397

2398
Base::Vector3d GeomArcOfConic::getCenter() const
2399
{
2400
    Handle(Geom_TrimmedCurve) curve =  Handle(Geom_TrimmedCurve)::DownCast(handle());
2401
    Handle(Geom_Conic) conic = Handle(Geom_Conic)::DownCast(curve->BasisCurve());
2402
    gp_Ax1 axis = conic->Axis();
2403
    const gp_Pnt& loc = axis.Location();
2404
    return Base::Vector3d(loc.X(),loc.Y(),loc.Z());
2405
}
2406

2407
Base::Vector3d GeomArcOfConic::getLocation() const
2408
{
2409
    Handle(Geom_TrimmedCurve) curve =  Handle(Geom_TrimmedCurve)::DownCast(handle());
2410
    Handle(Geom_Conic) conic = Handle(Geom_Conic)::DownCast(curve->BasisCurve());
2411
    gp_Ax1 axis = conic->Axis();
2412
    const gp_Pnt& loc = axis.Location();
2413
    return Base::Vector3d(loc.X(),loc.Y(),loc.Z());
2414
}
2415

2416
void GeomArcOfConic::setCenter(const Base::Vector3d& Center)
2417
{
2418
    gp_Pnt p1(Center.x,Center.y,Center.z);
2419
    Handle(Geom_TrimmedCurve) curve =  Handle(Geom_TrimmedCurve)::DownCast(handle());
2420
    Handle(Geom_Conic) conic = Handle(Geom_Conic)::DownCast(curve->BasisCurve());
2421

2422
    try {
2423
        conic->SetLocation(p1);
2424
    }
2425
    catch (Standard_Failure& e) {
2426

2427
        THROWM(Base::CADKernelError,e.GetMessageString())
2428
    }
2429
}
2430

2431
void GeomArcOfConic::setLocation(const Base::Vector3d& Center)
2432
{
2433
    gp_Pnt p1(Center.x,Center.y,Center.z);
2434
    Handle(Geom_TrimmedCurve) curve =  Handle(Geom_TrimmedCurve)::DownCast(handle());
2435
    Handle(Geom_Conic) conic = Handle(Geom_Conic)::DownCast(curve->BasisCurve());
2436

2437
    try {
2438
        conic->SetLocation(p1);
2439
    }
2440
    catch (Standard_Failure& e) {
2441

2442
       THROWM(Base::CADKernelError,e.GetMessageString())
2443
    }
2444
}
2445

2446
Base::Vector3d GeomArcOfConic::getAxisDirection() const
2447
{
2448
    Handle(Geom_TrimmedCurve) curve =  Handle(Geom_TrimmedCurve)::DownCast(handle());
2449
    Handle(Geom_Conic) conic = Handle(Geom_Conic)::DownCast(curve->BasisCurve());
2450
    gp_Ax1 axis = conic->Axis();
2451
    const gp_Dir& dir = axis.Direction();
2452
    return Base::Vector3d( dir.X(),dir.Y(),dir.Z());
2453
}
2454

2455
/*!
2456
 * \brief GeomArcOfConic::isReversed
2457
 * \return tests if an arc that lies in XY plane is reversed (i.e. drawn from
2458
 * startpoint to endpoint in CW direction instead of CCW.). Returns True if the
2459
 * arc is CW and false if CCW.
2460
 */
2461
bool GeomArcOfConic::isReversed() const
2462
{
2463
    Handle(Geom_TrimmedCurve) curve =  Handle(Geom_TrimmedCurve)::DownCast(handle());
2464
    Handle(Geom_Conic) conic = Handle(Geom_Conic)::DownCast(curve->BasisCurve());
2465
    assert(!conic.IsNull());
2466
    return conic->Axis().Direction().Z() < 0;
2467
}
2468

2469
/*!
2470
 * \brief GeomArcOfConic::getAngleXU
2471
 * \return The angle between ellipse's major axis (in direction to focus1) and
2472
 * X axis of a default axis system in the plane of ellipse. The angle is
2473
 * counted CCW as seen when looking at the ellipse so that ellipse's axis is
2474
 * pointing at you. Note that this function may give unexpected results when
2475
 * the ellipse is in XY, but reversed, because the X axis of the default axis
2476
 * system is reversed compared to the global X axis. This angle, in conjunction
2477
 * with ellipse's axis, fully defines the orientation of the ellipse.
2478
 */
2479
double GeomArcOfConic::getAngleXU() const
2480
{
2481
    Handle(Geom_TrimmedCurve) curve =  Handle(Geom_TrimmedCurve)::DownCast(handle());
2482
    Handle(Geom_Conic) conic = Handle(Geom_Conic)::DownCast(curve->BasisCurve());
2483

2484
    gp_Pnt center = conic->Axis().Location();
2485
    gp_Dir normal = conic->Axis().Direction();
2486
    gp_Dir xdir = conic->XAxis().Direction();
2487

2488
    gp_Ax2 xdirref(center, normal); // this is a reference system, might be CCW or CW depending on the creation method
2489

2490
    return -xdir.AngleWithRef(xdirref.XDirection(),normal);
2491
}
2492

2493
/*!
2494
 * \brief GeomArcOfConic::setAngleXU complements getAngleXU.
2495
 */
2496
void GeomArcOfConic::setAngleXU(double angle)
2497
{
2498
    Handle(Geom_TrimmedCurve) curve =  Handle(Geom_TrimmedCurve)::DownCast(handle());
2499
    Handle(Geom_Conic) conic = Handle(Geom_Conic)::DownCast(curve->BasisCurve());
2500

2501
    try {
2502
        gp_Pnt center = conic->Axis().Location();
2503
        gp_Dir normal = conic->Axis().Direction();
2504

2505
        gp_Ax1 normaxis(center, normal);
2506
        gp_Ax2 xdirref(center, normal);
2507

2508
        xdirref.Rotate(normaxis,angle);
2509
        conic->SetPosition(xdirref);
2510
    }
2511
    catch (Standard_Failure& e) {
2512

2513
        THROWM(Base::CADKernelError,e.GetMessageString())
2514
    }
2515
}
2516

2517
/*!
2518
 * \brief GeomArcOfConic::getXAxisDir
2519
 * \return the direction vector (unit-length) of symmetry axis of the conic. The
2520
 * direction also points to the focus of a parabola.
2521
 */
2522
Base::Vector3d GeomArcOfConic::getXAxisDir() const
2523
{
2524
    Handle(Geom_TrimmedCurve) curve =  Handle(Geom_TrimmedCurve)::DownCast(handle());
2525
    Handle(Geom_Conic) c = Handle(Geom_Conic)::DownCast( curve->BasisCurve() );
2526
    assert(!c.IsNull());
2527
    gp_Dir xdir = c->XAxis().Direction();
2528
    return Base::Vector3d(xdir.X(), xdir.Y(), xdir.Z());
2529
}
2530

2531
/*!
2532
 * \brief GeomArcOfConic::setXAxisDir Rotates the conic in its plane, so
2533
 * that its symmetry axis is as close as possible to the provided direction.
2534
 * \param newdir [in] is the new direction. If the vector is small, the
2535
 * orientation of the conic will be preserved. If the vector is not small,
2536
 * but its projection onto plane of the conic is small, an exception will be
2537
 * thrown.
2538
 */
2539
void GeomArcOfConic::setXAxisDir(const Base::Vector3d& newdir)
2540
{
2541
    Handle(Geom_TrimmedCurve) curve =  Handle(Geom_TrimmedCurve)::DownCast(handle());
2542
    Handle(Geom_Conic) c = Handle(Geom_Conic)::DownCast( curve->BasisCurve() );
2543
    assert(!c.IsNull());
2544

2545
    if (newdir.Sqr() < Precision::SquareConfusion())
2546
        return;//zero vector was passed. Keep the old orientation.
2547

2548
    try {
2549
        gp_Ax2 pos = c->Position();
2550
        //OCC should keep the old main Direction (Z), and change YDirection to accommodate the new XDirection.
2551
        pos.SetXDirection(gp_Dir(newdir.x, newdir.y, newdir.z));
2552
        c->SetPosition(pos);
2553
    }
2554
    catch (Standard_Failure& e) {
2555

2556
        THROWM(Base::CADKernelError,e.GetMessageString())
2557
    }
2558
}
2559

2560
// -------------------------------------------------
2561

2562
TYPESYSTEM_SOURCE(Part::GeomCircle,Part::GeomConic)
2563

2564
GeomCircle::GeomCircle()
2565
{
2566
    Handle(Geom_Circle) c = new Geom_Circle(gp_Circ());
2567
    this->myCurve = c;
2568
}
2569

2570
GeomCircle::GeomCircle(const Handle(Geom_Circle)& c)
2571
{
2572
    setHandle(c);
2573
}
2574

2575
GeomCircle::~GeomCircle() = default;
2576

2577
const Handle(Geom_Geometry)& GeomCircle::handle() const
2578
{
2579
    return myCurve;
2580
}
2581

2582

2583
void GeomCircle::setHandle(const Handle(Geom_Circle)& c)
2584
{
2585
    myCurve = Handle(Geom_Circle)::DownCast(c->Copy());
2586
}
2587

2588
Geometry *GeomCircle::copy() const
2589
{
2590
    GeomCircle *newCirc = new GeomCircle(myCurve);
2591
    newCirc->copyNonTag(this);
2592
    return newCirc;
2593
}
2594

2595
GeomBSplineCurve* GeomCircle::toNurbs(double first, double last) const
2596
{
2597
    // for an arc of circle use the generic method
2598
    if (first != 0 || last != 2*M_PI) {
2599
        return GeomConic::toNurbs(first, last);
2600
    }
2601

2602
    Handle(Geom_Circle) conic =  Handle(Geom_Circle)::DownCast(handle());
2603
    double radius = conic->Radius();
2604

2605
    TColgp_Array1OfPnt poles(1, 7);
2606
    poles(1) = gp_Pnt(radius, 0, 0);
2607
    poles(2) = gp_Pnt(radius, 2*radius, 0);
2608
    poles(3) = gp_Pnt(-radius, 2*radius, 0);
2609
    poles(4) = gp_Pnt(-radius, 0, 0);
2610
    poles(5) = gp_Pnt(-radius, -2*radius, 0);
2611
    poles(6) = gp_Pnt(radius, -2*radius, 0);
2612
    poles(7) = gp_Pnt(radius, 0, 0);
2613

2614
    gp_Trsf trsf;
2615
    trsf.SetTransformation(conic->Position(), gp_Ax3());
2616
    TColStd_Array1OfReal weights(1,7);
2617
    for (int i=1; i<=7; i++) {
2618
        poles(i).Transform(trsf);
2619
        weights(i) = 1;
2620
    }
2621
    weights(1) = 3;
2622
    weights(4) = 3;
2623
    weights(7) = 3;
2624

2625
    TColStd_Array1OfInteger mults(1, 3);
2626
    mults(1) = 4;
2627
    mults(2) = 3;
2628
    mults(3) = 4;
2629

2630
    TColStd_Array1OfReal knots(1, 3);
2631
    knots(1) = 0;
2632
    knots(2) = M_PI;
2633
    knots(3) = 2*M_PI;
2634

2635
    Handle(Geom_BSplineCurve) spline = new Geom_BSplineCurve(poles, weights,knots, mults, 3,
2636
        Standard_False, Standard_True);
2637
    return new GeomBSplineCurve(spline);
2638
}
2639

2640
double GeomCircle::getRadius() const
2641
{
2642
    Handle(Geom_Circle) circle = Handle(Geom_Circle)::DownCast(handle());
2643
    return circle->Radius();
2644
}
2645

2646
void GeomCircle::setRadius(double Radius)
2647
{
2648
    Handle(Geom_Circle) circle = Handle(Geom_Circle)::DownCast(handle());
2649

2650
    try {
2651
        gp_Circ c = circle->Circ();
2652
        c.SetRadius(Radius);
2653
        circle->SetCirc(c);
2654
    }
2655
    catch (Standard_Failure& e) {
2656

2657
        THROWM(Base::CADKernelError,e.GetMessageString())
2658
    }
2659
}
2660

2661
// Persistence implementer
2662
unsigned int GeomCircle::getMemSize () const
2663
{
2664
    return sizeof(Geom_Circle);
2665
}
2666

2667
void GeomCircle::Save(Base::Writer& writer) const
2668
{
2669
    // save the attributes of the father class
2670
    GeomCurve::Save(writer);
2671

2672
    gp_Pnt center = this->myCurve->Axis().Location();
2673
    gp_Dir normal = this->myCurve->Axis().Direction();
2674
    gp_Dir xdir = this->myCurve->XAxis().Direction();
2675

2676
    gp_Ax2 xdirref(center, normal); // this is a reference XY for the circle
2677
    double AngleXU = -xdir.AngleWithRef(xdirref.XDirection(),normal);
2678

2679
    writer.Stream()
2680
         << writer.ind()
2681
             << "<Circle "
2682
                << "CenterX=\"" <<  center.X() <<
2683
                "\" CenterY=\"" <<  center.Y() <<
2684
                "\" CenterZ=\"" <<  center.Z() <<
2685
                "\" NormalX=\"" <<  normal.X() <<
2686
                "\" NormalY=\"" <<  normal.Y() <<
2687
                "\" NormalZ=\"" <<  normal.Z() <<
2688
                "\" AngleXU=\"" <<  AngleXU <<
2689
                "\" Radius=\"" <<  this->myCurve->Radius() <<
2690
             "\"/>" << std::endl;
2691
}
2692

2693
void GeomCircle::Restore(Base::XMLReader& reader)
2694
{
2695
    // read the attributes of the father class
2696
    GeomCurve::Restore(reader);
2697

2698
    double CenterX,CenterY,CenterZ,NormalX,NormalY,NormalZ,Radius;
2699
    double AngleXU=0;
2700
    // read my Element
2701
    reader.readElement("Circle");
2702
    // get the value of my Attribute
2703
    CenterX = reader.getAttributeAsFloat("CenterX");
2704
    CenterY = reader.getAttributeAsFloat("CenterY");
2705
    CenterZ = reader.getAttributeAsFloat("CenterZ");
2706
    NormalX = reader.getAttributeAsFloat("NormalX");
2707
    NormalY = reader.getAttributeAsFloat("NormalY");
2708
    NormalZ = reader.getAttributeAsFloat("NormalZ");
2709
    if (reader.hasAttribute("AngleXU"))
2710
        AngleXU = reader.getAttributeAsFloat("AngleXU");
2711
    Radius = reader.getAttributeAsFloat("Radius");
2712

2713
    // set the read geometry
2714
    gp_Pnt p1(CenterX,CenterY,CenterZ);
2715
    gp_Dir norm(NormalX,NormalY,NormalZ);
2716

2717
    gp_Ax1 normaxis(p1,norm);
2718
    gp_Ax2 xdir(p1, norm);
2719
    xdir.Rotate(normaxis,AngleXU);
2720

2721
    try {
2722
        GC_MakeCircle mc(xdir, Radius);
2723
        if (!mc.IsDone())
2724
            THROWM(Base::CADKernelError,gce_ErrorStatusText(mc.Status()))
2725

2726
        this->myCurve = mc.Value();
2727
    }
2728
    catch (Standard_Failure& e) {
2729

2730
        THROWM(Base::CADKernelError,e.GetMessageString())
2731
    }
2732
}
2733

2734
PyObject *GeomCircle::getPyObject()
2735
{
2736
    return new CirclePy(static_cast<GeomCircle*>(this->clone()));
2737
}
2738

2739
bool GeomCircle::isSame(const Geometry &_other, double tol, double atol) const
2740
{
2741
    if(_other.getTypeId() != getTypeId())
2742
        return false;
2743

2744
    (void)atol;
2745
    auto &other = static_cast<const GeomCircle &>(_other);
2746
    return GeomConic::isSame(other,tol,atol) && fabs(getRadius() - other.getRadius()) <= tol;
2747
}
2748

2749
// -------------------------------------------------
2750

2751
TYPESYSTEM_SOURCE(Part::GeomArcOfCircle,Part::GeomArcOfConic)
2752

2753
GeomArcOfCircle::GeomArcOfCircle()
2754
{
2755
    Handle(Geom_Circle) c = new Geom_Circle(gp_Circ());
2756
    this->myCurve = new Geom_TrimmedCurve(c, c->FirstParameter(),c->LastParameter());
2757
}
2758

2759
GeomArcOfCircle::GeomArcOfCircle(const Handle(Geom_Circle)& c)
2760
{
2761
    setHandle(c);
2762
}
2763

2764
GeomArcOfCircle::~GeomArcOfCircle() = default;
2765

2766
void GeomArcOfCircle::setHandle(const Handle(Geom_TrimmedCurve)& c)
2767
{
2768
    Handle(Geom_Circle) basis = Handle(Geom_Circle)::DownCast(c->BasisCurve());
2769
    if (basis.IsNull())
2770
        Standard_Failure::Raise("Basis curve is not a circle");
2771
    this->myCurve = Handle(Geom_TrimmedCurve)::DownCast(c->Copy());
2772
}
2773

2774
void GeomArcOfCircle::setHandle(const Handle(Geom_Circle)& c)
2775
{
2776
    this->myCurve = new Geom_TrimmedCurve(c, c->FirstParameter(),c->LastParameter());
2777
}
2778

2779

2780
const Handle(Geom_Geometry)& GeomArcOfCircle::handle() const
2781
{
2782
    return myCurve;
2783
}
2784

2785
Geometry *GeomArcOfCircle::copy() const
2786
{
2787
    GeomArcOfCircle* copy = new GeomArcOfCircle();
2788
    copy->setHandle(this->myCurve);
2789
    copy->copyNonTag(this);
2790
    return copy;
2791
}
2792

2793
GeomBSplineCurve* GeomArcOfCircle::toNurbs(double first, double last) const
2794
{
2795
    Handle(Geom_TrimmedCurve) curve =  Handle(Geom_TrimmedCurve)::DownCast(handle());
2796
    Handle(Geom_Circle) circle = Handle(Geom_Circle)::DownCast(curve->BasisCurve());
2797
    return GeomCircle(circle).toNurbs(first, last);
2798
}
2799

2800
double GeomArcOfCircle::getRadius() const
2801
{
2802
    Handle(Geom_Circle) circle = Handle(Geom_Circle)::DownCast(myCurve->BasisCurve());
2803
    return circle->Radius();
2804
}
2805

2806
void GeomArcOfCircle::setRadius(double Radius)
2807
{
2808
    Handle(Geom_Circle) circle = Handle(Geom_Circle)::DownCast(myCurve->BasisCurve());
2809

2810
    try {
2811
        gp_Circ c = circle->Circ();
2812
        c.SetRadius(Radius);
2813
        circle->SetCirc(c);
2814
    }
2815
    catch (Standard_Failure& e) {
2816

2817
        THROWM(Base::CADKernelError,e.GetMessageString())
2818
    }
2819
}
2820

2821
/*!
2822
 * \brief GeomArcOfCircle::getAngle
2823
 * \param emulateCCWXY: if true, the arc will pretend to be a CCW arc in XY plane.
2824
 * For this to work, the arc must lie in XY plane (i.e. Axis is either +Z or -Z).
2825
 */
2826
double GeomArcOfCircle::getAngle(bool emulateCCWXY) const
2827
{
2828
    double startangle, endangle;
2829
    getRange(startangle, endangle, emulateCCWXY);
2830
    double angle = endangle - startangle;
2831
    return angle;
2832
}
2833

2834
/*!
2835
 * \brief GeomArcOfCircle::getRange
2836
 * \param u [out] start angle of the arc, in radians.
2837
 * \param v [out] end angle of the arc, in radians.
2838
 * \param emulateCCWXY: if true, the arc will pretend to be a CCW arc in XY plane.
2839
 * For this to work, the arc must lie in XY plane (i.e. Axis is either +Z or -Z).
2840
 * Additionally, arc's rotation as a whole will be included in the returned u,v
2841
 * (ArcOfCircle specific).
2842
 */
2843
void GeomArcOfCircle::getRange(double& u, double& v, bool emulateCCWXY) const
2844
{
2845
    Handle(Geom_TrimmedCurve) curve =  Handle(Geom_TrimmedCurve)::DownCast(handle());
2846
    u = curve->FirstParameter();
2847
    v = curve->LastParameter();
2848
    if (emulateCCWXY){
2849
        Handle(Geom_Conic) conic = Handle(Geom_Conic)::DownCast(curve->BasisCurve());
2850
        double angleXU = -conic->Position().XDirection().AngleWithRef(gp_Dir(1.0,0.0,0.0), gp_Dir(0.0,0.0,1.0));
2851
        double u1 = u, v1 = v;//the true arc curve parameters, cached. u,v will contain the rotation-corrected and swapped angles.
2852
        if (conic->Axis().Direction().Z() > 0.0){
2853
            //normal CCW arc
2854
            u = u1 + angleXU;
2855
            v = v1 + angleXU;
2856
        }
2857
        else {
2858
            //reversed (CW) arc
2859
            u = angleXU - v1;
2860
            v = angleXU - u1;
2861
        }
2862

2863
        if (v < u)
2864
            v += 2*M_PI;
2865
        if (v-u > 2*M_PI)
2866
            v -= 2*M_PI;
2867
    }
2868
}
2869

2870
/*!
2871
 * \brief GeomArcOfCircle::setRange
2872
 * \param u [in] start angle of the arc, in radians.
2873
 * \param v [in] end angle of the arc, in radians.
2874
 * \param emulateCCWXY: if true, the arc will pretent to be a CCW arc in XY plane.
2875
 * For this to work, the arc must lie in XY plane (i.e. Axis is either +Z or -Z).
2876
 * Additionally, arc's rotation as a whole will be subtracted from u,v
2877
 * (ArcOfCircle specific).
2878
 */
2879
void GeomArcOfCircle::setRange(double u, double v, bool emulateCCWXY)
2880
{
2881
    try {
2882
        Handle(Geom_TrimmedCurve) curve =  Handle(Geom_TrimmedCurve)::DownCast(handle());
2883
        if (emulateCCWXY){
2884
            Handle(Geom_Conic) conic = Handle(Geom_Conic)::DownCast(curve->BasisCurve());
2885
            double angleXU = -conic->Position().XDirection().AngleWithRef(gp_Dir(1.0,0.0,0.0), gp_Dir(0.0,0.0,1.0));
2886
            double u1 = u, v1 = v;//the values that were passed, ccw angles from X axis. u,v will contain the rotation-corrected and swapped angles.
2887
            if (conic->Axis().Direction().Z() > 0.0){
2888
                //normal CCW arc
2889
                u = u1 - angleXU;
2890
                v = v1 - angleXU;
2891
            }
2892
            else {
2893
                //reversed (CW) arc
2894
                u = angleXU - v1;
2895
                v = angleXU - u1;
2896
            }
2897
        }
2898

2899
        curve->SetTrim(u, v);
2900
    }
2901
    catch (Standard_Failure& e) {
2902

2903
        THROWM(Base::CADKernelError,e.GetMessageString())
2904
    }
2905
}
2906

2907
// Persistence implementer
2908
unsigned int GeomArcOfCircle::getMemSize () const
2909
{
2910
    return sizeof(Geom_Circle) + 2 *sizeof(double);
2911
}
2912

2913
void GeomArcOfCircle::Save(Base::Writer &writer) const
2914
{
2915
    // save the attributes of the father class
2916
    Geometry::Save(writer);
2917

2918
    Handle(Geom_Circle) circle = Handle(Geom_Circle)::DownCast(this->myCurve->BasisCurve());
2919

2920
    gp_Pnt center = circle->Axis().Location();
2921
    gp_Dir normal = circle->Axis().Direction();
2922
    gp_Dir xdir = circle->XAxis().Direction();
2923

2924
    gp_Ax2 xdirref(center, normal); // this is a reference XY for the arc
2925
    double AngleXU = -xdir.AngleWithRef(xdirref.XDirection(),normal);
2926

2927
    writer.Stream()
2928
         << writer.ind()
2929
             << "<ArcOfCircle "
2930
                << "CenterX=\"" <<  center.X() <<
2931
                "\" CenterY=\"" <<  center.Y() <<
2932
                "\" CenterZ=\"" <<  center.Z() <<
2933
                "\" NormalX=\"" <<  normal.X() <<
2934
                "\" NormalY=\"" <<  normal.Y() <<
2935
                "\" NormalZ=\"" <<  normal.Z() <<
2936
                "\" AngleXU=\"" <<  AngleXU <<
2937
                "\" Radius=\"" <<  circle->Radius() <<
2938
                "\" StartAngle=\"" <<  this->myCurve->FirstParameter() <<
2939
                "\" EndAngle=\"" <<  this->myCurve->LastParameter() <<
2940
             "\"/>" << std::endl;
2941
}
2942

2943
void GeomArcOfCircle::Restore(Base::XMLReader &reader)
2944
{
2945
    // read the attributes of the father class
2946
    Geometry::Restore(reader);
2947

2948
    double CenterX,CenterY,CenterZ,NormalX,NormalY,NormalZ,Radius,StartAngle,EndAngle;
2949
    double AngleXU=0;
2950
    // read my Element
2951
    reader.readElement("ArcOfCircle");
2952
    // get the value of my Attribute
2953
    CenterX = reader.getAttributeAsFloat("CenterX");
2954
    CenterY = reader.getAttributeAsFloat("CenterY");
2955
    CenterZ = reader.getAttributeAsFloat("CenterZ");
2956
    NormalX = reader.getAttributeAsFloat("NormalX");
2957
    NormalY = reader.getAttributeAsFloat("NormalY");
2958
    NormalZ = reader.getAttributeAsFloat("NormalZ");
2959
    if (reader.hasAttribute("AngleXU"))
2960
        AngleXU = reader.getAttributeAsFloat("AngleXU");
2961
    Radius = reader.getAttributeAsFloat("Radius");
2962
    StartAngle = reader.getAttributeAsFloat("StartAngle");
2963
    EndAngle = reader.getAttributeAsFloat("EndAngle");
2964

2965
    // set the read geometry
2966
    gp_Pnt p1(CenterX,CenterY,CenterZ);
2967
    gp_Dir norm(NormalX,NormalY,NormalZ);
2968

2969
    gp_Ax1 normaxis(p1,norm);
2970
    gp_Ax2 xdir(p1, norm);
2971
    xdir.Rotate(normaxis,AngleXU);
2972

2973
    try {
2974
        GC_MakeCircle mc(xdir, Radius);
2975
        if (!mc.IsDone())
2976
            THROWM(Base::CADKernelError,gce_ErrorStatusText(mc.Status()))
2977
        GC_MakeArcOfCircle ma(mc.Value()->Circ(), StartAngle, EndAngle, Standard_True);
2978
        if (!ma.IsDone())
2979
            THROWM(Base::CADKernelError,gce_ErrorStatusText(ma.Status()))
2980

2981
        Handle(Geom_TrimmedCurve) tmpcurve = ma.Value();
2982
        Handle(Geom_Circle) tmpcircle = Handle(Geom_Circle)::DownCast(tmpcurve->BasisCurve());
2983
        Handle(Geom_Circle) circle = Handle(Geom_Circle)::DownCast(this->myCurve->BasisCurve());
2984

2985
        circle->SetCirc(tmpcircle->Circ());
2986
        this->myCurve->SetTrim(tmpcurve->FirstParameter(), tmpcurve->LastParameter());
2987
    }
2988
    catch (Standard_Failure& e) {
2989

2990
        THROWM(Base::CADKernelError,e.GetMessageString())
2991
    }
2992
}
2993

2994
PyObject *GeomArcOfCircle::getPyObject()
2995
{
2996
    return new ArcOfCirclePy(static_cast<GeomArcOfCircle*>(this->clone()));
2997
}
2998

2999
// -------------------------------------------------
3000

3001
TYPESYSTEM_SOURCE(Part::GeomEllipse,Part::GeomConic)
3002

3003
GeomEllipse::GeomEllipse()
3004
{
3005
    Handle(Geom_Ellipse) e = new Geom_Ellipse(gp_Elips());
3006
    this->myCurve = e;
3007
}
3008

3009
GeomEllipse::GeomEllipse(const Handle(Geom_Ellipse)& e)
3010
{
3011
    setHandle(e);
3012
}
3013

3014
GeomEllipse::~GeomEllipse() = default;
3015

3016
const Handle(Geom_Geometry)& GeomEllipse::handle() const
3017
{
3018
    return myCurve;
3019
}
3020

3021
void GeomEllipse::setHandle(const Handle(Geom_Ellipse) &e)
3022
{
3023
    this->myCurve = Handle(Geom_Ellipse)::DownCast(e->Copy());
3024
}
3025

3026
Geometry *GeomEllipse::copy() const
3027
{
3028
    GeomEllipse *newEllipse = new GeomEllipse(myCurve);
3029
    newEllipse->copyNonTag(this);
3030
    return newEllipse;
3031
}
3032

3033
GeomBSplineCurve* GeomEllipse::toNurbs(double first, double last) const
3034
{
3035
    // for an arc of ellipse use the generic method
3036
    if (first != 0 || last != 2*M_PI) {
3037
        return GeomConic::toNurbs(first, last);
3038
    }
3039

3040
    Handle(Geom_Ellipse) conic =  Handle(Geom_Ellipse)::DownCast(handle());
3041
    Standard_Real majorRadius = conic->MajorRadius();
3042
    Standard_Real minorRadius = conic->MinorRadius();
3043

3044
    TColgp_Array1OfPnt poles(1, 7);
3045
    poles(1) = gp_Pnt(majorRadius, 0, 0);
3046
    poles(2) = gp_Pnt(majorRadius, 2*minorRadius, 0);
3047
    poles(3) = gp_Pnt(-majorRadius, 2*minorRadius, 0);
3048
    poles(4) = gp_Pnt(-majorRadius, 0, 0);
3049
    poles(5) = gp_Pnt(-majorRadius, -2*minorRadius, 0);
3050
    poles(6) = gp_Pnt(majorRadius, -2*minorRadius, 0);
3051
    poles(7) = gp_Pnt(majorRadius, 0, 0);
3052

3053
    gp_Trsf trsf;
3054
    trsf.SetTransformation(conic->Position(), gp_Ax3());
3055
    TColStd_Array1OfReal weights(1,7);
3056
    for (int i=1; i<=7; i++) {
3057
        poles(i).Transform(trsf);
3058
        weights(i) = 1;
3059
    }
3060
    weights(1) = 3;
3061
    weights(4) = 3;
3062
    weights(7) = 3;
3063

3064
    TColStd_Array1OfInteger mults(1, 3);
3065
    mults(1) = 4;
3066
    mults(2) = 3;
3067
    mults(3) = 4;
3068

3069
    TColStd_Array1OfReal knots(1, 3);
3070
    knots(1) = 0;
3071
    knots(2) = 1;
3072
    knots(3) = 2;
3073

3074
    Handle(Geom_BSplineCurve) spline = new Geom_BSplineCurve(poles, weights,knots, mults, 3,
3075
        Standard_False, Standard_True);
3076
    return new GeomBSplineCurve(spline);
3077
}
3078

3079
double GeomEllipse::getMajorRadius() const
3080
{
3081
    Handle(Geom_Ellipse) ellipse = Handle(Geom_Ellipse)::DownCast(handle());
3082
    return ellipse->MajorRadius();
3083
}
3084

3085
void GeomEllipse::setMajorRadius(double Radius)
3086
{
3087
    Handle(Geom_Ellipse) ellipse = Handle(Geom_Ellipse)::DownCast(handle());
3088

3089
    try {
3090
        ellipse->SetMajorRadius(Radius);
3091
    }
3092
    catch (Standard_Failure& e) {
3093

3094
        THROWM(Base::CADKernelError,e.GetMessageString())
3095
    }
3096
}
3097

3098
double GeomEllipse::getMinorRadius() const
3099
{
3100
    Handle(Geom_Ellipse) ellipse = Handle(Geom_Ellipse)::DownCast(handle());
3101
    return ellipse->MinorRadius();
3102
}
3103

3104
void GeomEllipse::setMinorRadius(double Radius)
3105
{
3106
    Handle(Geom_Ellipse) ellipse = Handle(Geom_Ellipse)::DownCast(handle());
3107

3108
    try {
3109
        ellipse->SetMinorRadius(Radius);
3110
    }
3111
    catch (Standard_Failure& e) {
3112

3113
        THROWM(Base::CADKernelError,e.GetMessageString())
3114
    }
3115
}
3116

3117
/*!
3118
 * \brief GeomEllipse::getMajorAxisDir
3119
 * \return the direction vector (unit-length) of major axis of the ellipse. The
3120
 * direction also points to the first focus.
3121
 */
3122
Base::Vector3d GeomEllipse::getMajorAxisDir() const
3123
{
3124
    gp_Dir xdir = myCurve->XAxis().Direction();
3125
    return Base::Vector3d(xdir.X(), xdir.Y(), xdir.Z());
3126
}
3127

3128
/*!
3129
 * \brief GeomEllipse::getMinorAxisDir
3130
 * \return the direction vector (unit-length) of minor axis of the ellipse.
3131
 */
3132
Base::Vector3d GeomEllipse::getMinorAxisDir() const
3133
{
3134
    gp_Dir ydir = myCurve->YAxis().Direction();
3135
    return Base::Vector3d(ydir.X(), ydir.Y(), ydir.Z());
3136
}
3137

3138

3139
/*!
3140
 * \brief GeomEllipse::setMajorAxisDir Rotates the ellipse in its plane, so
3141
 * that its major axis is as close as possible to the provided direction.
3142
 * \param newdir [in] is the new direction. If the vector is small, the
3143
 * orientation of the ellipse will be preserved. If the vector is not small,
3144
 * but its projection onto plane of the ellipse is small, an exception will be
3145
 * thrown.
3146
 */
3147
void GeomEllipse::setMajorAxisDir(Base::Vector3d newdir)
3148
{
3149
    if (newdir.Sqr() < Precision::SquareConfusion())
3150
        return;//zero vector was passed. Keep the old orientation.
3151
    try {
3152
        gp_Ax2 pos = myCurve->Position();
3153
        pos.SetXDirection(gp_Dir(newdir.x, newdir.y, newdir.z));//OCC should keep the old main Direction (Z), and change YDirection to accommodate the new XDirection.
3154
        myCurve->SetPosition(pos);
3155
    }
3156
    catch (Standard_Failure& e) {
3157

3158
        THROWM(Base::CADKernelError,e.GetMessageString())
3159
    }
3160
}
3161

3162
// Persistence implementer
3163
unsigned int GeomEllipse::getMemSize () const
3164
{
3165
    return sizeof(Geom_Ellipse);
3166
}
3167

3168
void GeomEllipse::Save(Base::Writer& writer) const
3169
{
3170
    // save the attributes of the father class
3171
    GeomCurve::Save(writer);
3172

3173
    gp_Pnt center = this->myCurve->Axis().Location();
3174
    gp_Dir normal = this->myCurve->Axis().Direction();
3175
    gp_Dir xdir = this->myCurve->XAxis().Direction();
3176

3177
    gp_Ax2 xdirref(center, normal); // this is a reference XY for the ellipse
3178

3179
    double AngleXU = -xdir.AngleWithRef(xdirref.XDirection(),normal);
3180

3181

3182
    writer.Stream()
3183
         << writer.ind()
3184
            << "<Ellipse "
3185
            << "CenterX=\"" <<  center.X() << "\" "
3186
            << "CenterY=\"" <<  center.Y() << "\" "
3187
            << "CenterZ=\"" <<  center.Z() << "\" "
3188
            << "NormalX=\"" <<  normal.X() << "\" "
3189
            << "NormalY=\"" <<  normal.Y() << "\" "
3190
            << "NormalZ=\"" <<  normal.Z() << "\" "
3191
            << "MajorRadius=\"" <<  this->myCurve->MajorRadius() << "\" "
3192
            << "MinorRadius=\"" <<  this->myCurve->MinorRadius() << "\" "
3193
            << "AngleXU=\"" << AngleXU << "\" "
3194
            << "/>" << std::endl;
3195
}
3196

3197
void GeomEllipse::Restore(Base::XMLReader& reader)
3198
{
3199
    // read the attributes of the father class
3200
    GeomCurve::Restore(reader);
3201

3202
    double CenterX,CenterY,CenterZ,NormalX,NormalY,NormalZ,MajorRadius,MinorRadius,AngleXU;
3203
    // read my Element
3204
    reader.readElement("Ellipse");
3205
    // get the value of my Attribute
3206
    CenterX = reader.getAttributeAsFloat("CenterX");
3207
    CenterY = reader.getAttributeAsFloat("CenterY");
3208
    CenterZ = reader.getAttributeAsFloat("CenterZ");
3209
    NormalX = reader.getAttributeAsFloat("NormalX");
3210
    NormalY = reader.getAttributeAsFloat("NormalY");
3211
    NormalZ = reader.getAttributeAsFloat("NormalZ");
3212
    MajorRadius = reader.getAttributeAsFloat("MajorRadius");
3213
    MinorRadius = reader.getAttributeAsFloat("MinorRadius");
3214

3215
    // This is for backwards compatibility
3216
    if(reader.hasAttribute("AngleXU"))
3217
        AngleXU = reader.getAttributeAsFloat("AngleXU");
3218
    else
3219
        AngleXU = 0;
3220

3221
    // set the read geometry
3222
    gp_Pnt p1(CenterX,CenterY,CenterZ);
3223
    gp_Dir norm(NormalX,NormalY,NormalZ);
3224

3225
    gp_Ax1 normaxis(p1,norm);
3226

3227
    gp_Ax2 xdir(p1, norm);
3228

3229
    xdir.Rotate(normaxis,AngleXU);
3230

3231
    try {
3232
        GC_MakeEllipse mc(xdir, MajorRadius, MinorRadius);
3233
        if (!mc.IsDone())
3234
            THROWM(Base::CADKernelError,gce_ErrorStatusText(mc.Status()))
3235

3236
        this->myCurve = mc.Value();
3237
    }
3238
    catch (Standard_Failure& e) {
3239

3240
        THROWM(Base::CADKernelError,e.GetMessageString())
3241
    }
3242
}
3243

3244
PyObject *GeomEllipse::getPyObject()
3245
{
3246
    return new EllipsePy(static_cast<GeomEllipse*>(this->clone()));
3247
}
3248

3249
bool GeomEllipse::isSame(const Geometry &_other, double tol, double atol) const
3250
{
3251
    if(_other.getTypeId() != getTypeId())
3252
        return false;
3253

3254
    (void)atol;
3255
    auto &other = static_cast<const GeomEllipse &>(_other);
3256
    return GeomConic::isSame(other,tol,atol)
3257
        && fabs(getMajorRadius() - other.getMajorRadius()) <= tol
3258
        && fabs(getMinorRadius() - other.getMinorRadius()) <= tol;
3259
}
3260

3261
// -------------------------------------------------
3262

3263
TYPESYSTEM_SOURCE(Part::GeomArcOfEllipse,Part::GeomArcOfConic)
3264

3265
GeomArcOfEllipse::GeomArcOfEllipse()
3266
{
3267
    Handle(Geom_Ellipse) e = new Geom_Ellipse(gp_Elips());
3268
    this->myCurve = new Geom_TrimmedCurve(e, e->FirstParameter(),e->LastParameter());
3269
}
3270

3271
GeomArcOfEllipse::GeomArcOfEllipse(const Handle(Geom_Ellipse)& e)
3272
{
3273
    setHandle(e);
3274
}
3275

3276
GeomArcOfEllipse::~GeomArcOfEllipse() = default;
3277

3278
void GeomArcOfEllipse::setHandle(const Handle(Geom_TrimmedCurve)& c)
3279
{
3280
    Handle(Geom_Ellipse) basis = Handle(Geom_Ellipse)::DownCast(c->BasisCurve());
3281
    if (basis.IsNull())
3282
        Standard_Failure::Raise("Basis curve is not an ellipse");
3283
    this->myCurve = Handle(Geom_TrimmedCurve)::DownCast(c->Copy());
3284
}
3285

3286
void GeomArcOfEllipse::setHandle(const Handle(Geom_Ellipse)& e)
3287
{
3288
    this->myCurve = new Geom_TrimmedCurve(e, e->FirstParameter(),e->LastParameter());
3289
}
3290

3291
const Handle(Geom_Geometry)& GeomArcOfEllipse::handle() const
3292
{
3293
    return myCurve;
3294
}
3295

3296
Geometry *GeomArcOfEllipse::copy() const
3297
{
3298
    GeomArcOfEllipse* copy = new GeomArcOfEllipse();
3299
    copy->setHandle(this->myCurve);
3300
    copy->copyNonTag(this);
3301
    return copy;
3302
}
3303

3304
GeomBSplineCurve* GeomArcOfEllipse::toNurbs(double first, double last) const
3305
{
3306
    Handle(Geom_TrimmedCurve) curve =  Handle(Geom_TrimmedCurve)::DownCast(handle());
3307
    Handle(Geom_Ellipse) ellipse = Handle(Geom_Ellipse)::DownCast(curve->BasisCurve());
3308
    return GeomEllipse(ellipse).toNurbs(first, last);
3309
}
3310

3311
double GeomArcOfEllipse::getMajorRadius() const
3312
{
3313
    Handle(Geom_Ellipse) ellipse = Handle(Geom_Ellipse)::DownCast(myCurve->BasisCurve());
3314
    return ellipse->MajorRadius();
3315
}
3316

3317
void GeomArcOfEllipse::setMajorRadius(double Radius)
3318
{
3319
    Handle(Geom_Ellipse) ellipse = Handle(Geom_Ellipse)::DownCast(myCurve->BasisCurve());
3320

3321
    try {
3322
        ellipse->SetMajorRadius(Radius);
3323
    }
3324
    catch (Standard_Failure& e) {
3325

3326
        THROWM(Base::CADKernelError,e.GetMessageString())
3327
    }
3328
}
3329

3330
double GeomArcOfEllipse::getMinorRadius() const
3331
{
3332
    Handle(Geom_Ellipse) ellipse = Handle(Geom_Ellipse)::DownCast(myCurve->BasisCurve());
3333
    return ellipse->MinorRadius();
3334
}
3335

3336
void GeomArcOfEllipse::setMinorRadius(double Radius)
3337
{
3338
    Handle(Geom_Ellipse) ellipse = Handle(Geom_Ellipse)::DownCast(myCurve->BasisCurve());
3339

3340
    try {
3341
        ellipse->SetMinorRadius(Radius);
3342
    }
3343
    catch (Standard_Failure& e) {
3344

3345
        THROWM(Base::CADKernelError,e.GetMessageString())
3346
    }
3347
}
3348

3349
/*!
3350
 * \brief GeomArcOfEllipse::getMajorAxisDir
3351
 * \return the direction vector (unit-length) of major axis of the ellipse. The
3352
 * direction also points to the first focus.
3353
 */
3354
Base::Vector3d GeomArcOfEllipse::getMajorAxisDir() const
3355
{
3356
    Handle(Geom_Ellipse) c = Handle(Geom_Ellipse)::DownCast( myCurve->BasisCurve() );
3357
    assert(!c.IsNull());
3358
    gp_Dir xdir = c->XAxis().Direction();
3359
    return Base::Vector3d(xdir.X(), xdir.Y(), xdir.Z());
3360
}
3361

3362
/*!
3363
 * \brief GeomArcOfEllipse::getMinorAxisDir
3364
 * \return the direction vector (unit-length) of minor axis of the ellipse.
3365
 */
3366
Base::Vector3d GeomArcOfEllipse::getMinorAxisDir() const
3367
{
3368
    Handle(Geom_Ellipse) c = Handle(Geom_Ellipse)::DownCast(myCurve->BasisCurve());
3369
    assert(!c.IsNull());
3370
    gp_Dir ydir = c->YAxis().Direction();
3371
    return Base::Vector3d(ydir.X(), ydir.Y(), ydir.Z());
3372
}
3373

3374
/*!
3375
 * \brief GeomArcOfEllipse::setMajorAxisDir Rotates the ellipse in its plane, so
3376
 * that its major axis is as close as possible to the provided direction.
3377
 * \param newdir [in] is the new direction. If the vector is small, the
3378
 * orientation of the ellipse will be preserved. If the vector is not small,
3379
 * but its projection onto plane of the ellipse is small, an exception will be
3380
 * thrown.
3381
 */
3382
void GeomArcOfEllipse::setMajorAxisDir(Base::Vector3d newdir)
3383
{
3384
    Handle(Geom_Ellipse) c = Handle(Geom_Ellipse)::DownCast( myCurve->BasisCurve() );
3385
    assert(!c.IsNull());
3386
    if (newdir.Sqr() < Precision::SquareConfusion())
3387
        return;//zero vector was passed. Keep the old orientation.
3388
    try {
3389
        gp_Ax2 pos = c->Position();
3390
        pos.SetXDirection(gp_Dir(newdir.x, newdir.y, newdir.z));//OCC should keep the old main Direction (Z), and change YDirection to accommodate the new XDirection.
3391
        c->SetPosition(pos);
3392
    }
3393
    catch (Standard_Failure& e) {
3394

3395
        THROWM(Base::CADKernelError,e.GetMessageString())
3396
    }
3397
}
3398

3399
/*!
3400
 * \brief GeomArcOfEllipse::getRange
3401
 * \param u [out] start angle of the arc, in radians.
3402
 * \param v [out] end angle of the arc, in radians.
3403
 * \param emulateCCWXY: if true, the arc will pretent to be a CCW arc in XY plane.
3404
 * For this to work, the arc must lie in XY plane (i.e. Axis is either +Z or -Z).
3405
 */
3406
void GeomArcOfEllipse::getRange(double& u, double& v, bool emulateCCWXY) const
3407
{
3408
    u = myCurve->FirstParameter();
3409
    v = myCurve->LastParameter();
3410
    if (emulateCCWXY) {
3411
        if (isReversed()) {
3412
            std::swap(u,v);
3413
            u = -u; v = -v;
3414
            if (v < u)
3415
                v += 2*M_PI;
3416
            if (v-u > 2*M_PI)
3417
                v -= 2*M_PI;
3418
        }
3419
    }
3420
}
3421

3422
/*!
3423
 * \brief GeomArcOfEllipse::setRange
3424
 * \param u [in] start angle of the arc, in radians.
3425
 * \param v [in] end angle of the arc, in radians.
3426
 * \param emulateCCWXY: if true, the arc will pretent to be a CCW arc in XY plane.
3427
 * For this to work, the arc must lie in XY plane (i.e. Axis is either +Z or -Z).
3428
 */
3429
void GeomArcOfEllipse::setRange(double u, double v, bool emulateCCWXY)
3430
{
3431
    try {
3432
        if (emulateCCWXY) {
3433
            if (isReversed()) {
3434
                std::swap(u,v);
3435
                u = -u; v = -v;
3436
            }
3437
        }
3438
        myCurve->SetTrim(u, v);
3439
    }
3440
    catch (Standard_Failure& e) {
3441

3442
        THROWM(Base::CADKernelError,e.GetMessageString())
3443
    }
3444
}
3445

3446
// Persistence implementer
3447
unsigned int GeomArcOfEllipse::getMemSize () const
3448
{
3449
    return sizeof(Geom_Ellipse) + 2 *sizeof(double);
3450
}
3451

3452
void GeomArcOfEllipse::Save(Base::Writer &writer) const
3453
{
3454
    // save the attributes of the father class
3455
    GeomCurve::Save(writer);
3456

3457
    Handle(Geom_Ellipse) ellipse = Handle(Geom_Ellipse)::DownCast(this->myCurve->BasisCurve());
3458

3459
    gp_Pnt center = ellipse->Axis().Location();
3460
    gp_Dir normal = ellipse->Axis().Direction();
3461
    gp_Dir xdir = ellipse->XAxis().Direction();
3462

3463
    gp_Ax2 xdirref(center, normal); // this is a reference XY for the ellipse
3464

3465
    double AngleXU = -xdir.AngleWithRef(xdirref.XDirection(),normal);
3466

3467

3468
    writer.Stream()
3469
         << writer.ind()
3470
            << "<ArcOfEllipse "
3471
            << "CenterX=\"" <<  center.X() << "\" "
3472
            << "CenterY=\"" <<  center.Y() << "\" "
3473
            << "CenterZ=\"" <<  center.Z() << "\" "
3474
            << "NormalX=\"" <<  normal.X() << "\" "
3475
            << "NormalY=\"" <<  normal.Y() << "\" "
3476
            << "NormalZ=\"" <<  normal.Z() << "\" "
3477
            << "MajorRadius=\"" <<  ellipse->MajorRadius() << "\" "
3478
            << "MinorRadius=\"" <<  ellipse->MinorRadius() << "\" "
3479
            << "AngleXU=\"" << AngleXU << "\" "
3480
            << "StartAngle=\"" <<  this->myCurve->FirstParameter() << "\" "
3481
            << "EndAngle=\"" <<  this->myCurve->LastParameter() << "\" "
3482
            << "/>" << std::endl;
3483
}
3484

3485
void GeomArcOfEllipse::Restore(Base::XMLReader &reader)
3486
{
3487
    // read the attributes of the father class
3488
    GeomCurve::Restore(reader);
3489

3490
    double CenterX,CenterY,CenterZ,NormalX,NormalY,NormalZ,MajorRadius,MinorRadius,AngleXU,StartAngle,EndAngle;
3491
    // read my Element
3492
    reader.readElement("ArcOfEllipse");
3493
    // get the value of my Attribute
3494
    CenterX = reader.getAttributeAsFloat("CenterX");
3495
    CenterY = reader.getAttributeAsFloat("CenterY");
3496
    CenterZ = reader.getAttributeAsFloat("CenterZ");
3497
    NormalX = reader.getAttributeAsFloat("NormalX");
3498
    NormalY = reader.getAttributeAsFloat("NormalY");
3499
    NormalZ = reader.getAttributeAsFloat("NormalZ");
3500
    MajorRadius = reader.getAttributeAsFloat("MajorRadius");
3501
    MinorRadius = reader.getAttributeAsFloat("MinorRadius");
3502
    AngleXU = reader.getAttributeAsFloat("AngleXU");
3503
    StartAngle = reader.getAttributeAsFloat("StartAngle");
3504
    EndAngle = reader.getAttributeAsFloat("EndAngle");
3505

3506

3507
    // set the read geometry
3508
    gp_Pnt p1(CenterX,CenterY,CenterZ);
3509
    gp_Dir norm(NormalX,NormalY,NormalZ);
3510

3511
    gp_Ax1 normaxis(p1,norm);
3512

3513
    gp_Ax2 xdir(p1, norm);
3514

3515
    xdir.Rotate(normaxis,AngleXU);
3516

3517
    try {
3518
        GC_MakeEllipse mc(xdir, MajorRadius, MinorRadius);
3519
        if (!mc.IsDone())
3520
            THROWM(Base::CADKernelError,gce_ErrorStatusText(mc.Status()))
3521

3522
        GC_MakeArcOfEllipse ma(mc.Value()->Elips(), StartAngle, EndAngle, Standard_True);
3523
        if (!ma.IsDone())
3524
            THROWM(Base::CADKernelError,gce_ErrorStatusText(ma.Status()))
3525

3526
        Handle(Geom_TrimmedCurve) tmpcurve = ma.Value();
3527
        Handle(Geom_Ellipse) tmpellipse = Handle(Geom_Ellipse)::DownCast(tmpcurve->BasisCurve());
3528
        Handle(Geom_Ellipse) ellipse = Handle(Geom_Ellipse)::DownCast(this->myCurve->BasisCurve());
3529

3530
        ellipse->SetElips(tmpellipse->Elips());
3531
        this->myCurve->SetTrim(tmpcurve->FirstParameter(), tmpcurve->LastParameter());
3532
    }
3533
    catch (Standard_Failure& e) {
3534

3535
        THROWM(Base::CADKernelError,e.GetMessageString())
3536
    }
3537
}
3538

3539
PyObject *GeomArcOfEllipse::getPyObject()
3540
{
3541
    return new ArcOfEllipsePy(static_cast<GeomArcOfEllipse*>(this->clone()));
3542
}
3543

3544
// -------------------------------------------------
3545

3546
TYPESYSTEM_SOURCE(Part::GeomHyperbola,Part::GeomConic)
3547

3548
GeomHyperbola::GeomHyperbola()
3549
{
3550
    Handle(Geom_Hyperbola) h = new Geom_Hyperbola(gp_Hypr());
3551
    this->myCurve = h;
3552
}
3553

3554
GeomHyperbola::GeomHyperbola(const Handle(Geom_Hyperbola)& h)
3555
{
3556
    setHandle(h);
3557
}
3558

3559
GeomHyperbola::~GeomHyperbola() = default;
3560

3561
const Handle(Geom_Geometry)& GeomHyperbola::handle() const
3562
{
3563
    return myCurve;
3564
}
3565

3566

3567
void GeomHyperbola::setHandle(const Handle(Geom_Hyperbola)& c)
3568
{
3569
    myCurve = Handle(Geom_Hyperbola)::DownCast(c->Copy());
3570
}
3571

3572
Geometry *GeomHyperbola::copy() const
3573
{
3574
    GeomHyperbola *newHyp = new GeomHyperbola(myCurve);
3575
    newHyp->copyNonTag(this);
3576
    return newHyp;
3577
}
3578

3579
GeomBSplineCurve* GeomHyperbola::toNurbs(double first, double last) const
3580
{
3581
    return GeomConic::toNurbs(first, last);
3582
}
3583

3584
double GeomHyperbola::getMajorRadius() const
3585
{
3586
    Handle(Geom_Hyperbola) h = Handle(Geom_Hyperbola)::DownCast(handle());
3587
    return h->MajorRadius();
3588
}
3589

3590
void GeomHyperbola::setMajorRadius(double Radius)
3591
{
3592
    Handle(Geom_Hyperbola) h = Handle(Geom_Hyperbola)::DownCast(handle());
3593

3594
    try {
3595
        h->SetMajorRadius(Radius);
3596
    }
3597
    catch (Standard_Failure& e) {
3598

3599
        THROWM(Base::CADKernelError,e.GetMessageString())
3600
    }
3601
}
3602

3603
double GeomHyperbola::getMinorRadius() const
3604
{
3605
    Handle(Geom_Hyperbola) h = Handle(Geom_Hyperbola)::DownCast(handle());
3606
    return h->MinorRadius();
3607
}
3608

3609
void GeomHyperbola::setMinorRadius(double Radius)
3610
{
3611
    Handle(Geom_Hyperbola) h = Handle(Geom_Hyperbola)::DownCast(handle());
3612

3613
    try {
3614
        h->SetMinorRadius(Radius);
3615
    }
3616
    catch (Standard_Failure& e) {
3617

3618
        THROWM(Base::CADKernelError,e.GetMessageString())
3619
    }
3620
}
3621

3622
// Persistence implementer
3623
unsigned int GeomHyperbola::getMemSize () const
3624
{
3625
    return sizeof(Geom_Hyperbola);
3626
}
3627

3628
void GeomHyperbola::Save(Base::Writer& writer) const
3629
{
3630
    // save the attributes of the father class
3631
    GeomCurve::Save(writer);
3632

3633
    gp_Pnt center = this->myCurve->Axis().Location();
3634
    gp_Dir normal = this->myCurve->Axis().Direction();
3635
    gp_Dir xdir = this->myCurve->XAxis().Direction();
3636

3637
    gp_Ax2 xdirref(center, normal); // this is a reference XY for the ellipse
3638

3639
    double AngleXU = -xdir.AngleWithRef(xdirref.XDirection(),normal);
3640

3641
    writer.Stream()
3642
         << writer.ind()
3643
            << "<Hyperbola "
3644
            << "CenterX=\"" <<  center.X() << "\" "
3645
            << "CenterY=\"" <<  center.Y() << "\" "
3646
            << "CenterZ=\"" <<  center.Z() << "\" "
3647
            << "NormalX=\"" <<  normal.X() << "\" "
3648
            << "NormalY=\"" <<  normal.Y() << "\" "
3649
            << "NormalZ=\"" <<  normal.Z() << "\" "
3650
            << "MajorRadius=\"" <<  this->myCurve->MajorRadius() << "\" "
3651
            << "MinorRadius=\"" <<  this->myCurve->MinorRadius() << "\" "
3652
            << "AngleXU=\"" << AngleXU << "\" "
3653
            << "/>" << std::endl;
3654
}
3655

3656
void GeomHyperbola::Restore(Base::XMLReader& reader)
3657
{
3658
    // read the attributes of the father class
3659
    GeomCurve::Restore(reader);
3660

3661
    double CenterX,CenterY,CenterZ,NormalX,NormalY,NormalZ,MajorRadius,MinorRadius,AngleXU;
3662
    // read my Element
3663
    reader.readElement("Hyperbola");
3664
    // get the value of my Attribute
3665
    CenterX = reader.getAttributeAsFloat("CenterX");
3666
    CenterY = reader.getAttributeAsFloat("CenterY");
3667
    CenterZ = reader.getAttributeAsFloat("CenterZ");
3668
    NormalX = reader.getAttributeAsFloat("NormalX");
3669
    NormalY = reader.getAttributeAsFloat("NormalY");
3670
    NormalZ = reader.getAttributeAsFloat("NormalZ");
3671
    MajorRadius = reader.getAttributeAsFloat("MajorRadius");
3672
    MinorRadius = reader.getAttributeAsFloat("MinorRadius");
3673
    AngleXU = reader.getAttributeAsFloat("AngleXU");
3674

3675
    // set the read geometry
3676
    gp_Pnt p1(CenterX,CenterY,CenterZ);
3677
    gp_Dir norm(NormalX,NormalY,NormalZ);
3678

3679
    gp_Ax1 normaxis(p1,norm);
3680

3681
    gp_Ax2 xdir(p1, norm);
3682

3683
    xdir.Rotate(normaxis,AngleXU);
3684

3685
    try {
3686
        GC_MakeHyperbola mc(xdir, MajorRadius, MinorRadius);
3687
        if (!mc.IsDone())
3688
            THROWM(Base::CADKernelError,gce_ErrorStatusText(mc.Status()))
3689

3690
        this->myCurve = mc.Value();
3691
    }
3692
    catch (Standard_Failure& e) {
3693

3694
        THROWM(Base::CADKernelError,e.GetMessageString())
3695
    }
3696
}
3697

3698
PyObject *GeomHyperbola::getPyObject()
3699
{
3700
    return new HyperbolaPy(static_cast<GeomHyperbola*>(this->clone()));
3701
}
3702

3703
bool GeomHyperbola::isSame(const Geometry &_other, double tol, double atol) const
3704
{
3705
    if(_other.getTypeId() != getTypeId())
3706
        return false;
3707

3708
    (void)atol;
3709
    auto &other = static_cast<const GeomHyperbola &>(_other);
3710
    return GeomConic::isSame(other,tol,atol)
3711
        && fabs(getMajorRadius() - other.getMajorRadius()) <= tol
3712
        && fabs(getMinorRadius() - other.getMinorRadius()) <= tol;
3713
}
3714

3715
// -------------------------------------------------
3716

3717
TYPESYSTEM_SOURCE(Part::GeomArcOfHyperbola,Part::GeomArcOfConic)
3718

3719
GeomArcOfHyperbola::GeomArcOfHyperbola()
3720
{
3721
    gp_Ax2 ax2 = gp_Ax2();
3722
    Handle(Geom_Hyperbola) h = new Geom_Hyperbola(gp_Hypr(ax2, 1,1));
3723
    this->myCurve = new Geom_TrimmedCurve(h, h->FirstParameter(),h->LastParameter());
3724
}
3725

3726
GeomArcOfHyperbola::GeomArcOfHyperbola(const Handle(Geom_Hyperbola)& h)
3727
{
3728
    setHandle(h);
3729
}
3730

3731
GeomArcOfHyperbola::~GeomArcOfHyperbola() = default;
3732

3733
void GeomArcOfHyperbola::setHandle(const Handle(Geom_TrimmedCurve)& c)
3734
{
3735
    Handle(Geom_Hyperbola) basis = Handle(Geom_Hyperbola)::DownCast(c->BasisCurve());
3736
    if (basis.IsNull())
3737
        Standard_Failure::Raise("Basis curve is not an hyperbola");
3738
    this->myCurve = Handle(Geom_TrimmedCurve)::DownCast(c->Copy());
3739
}
3740

3741
void GeomArcOfHyperbola::setHandle(const Handle(Geom_Hyperbola)& h)
3742
{
3743
    this->myCurve = new Geom_TrimmedCurve(h, h->FirstParameter(),h->LastParameter());
3744
}
3745

3746
const Handle(Geom_Geometry)& GeomArcOfHyperbola::handle() const
3747
{
3748
    return myCurve;
3749
}
3750

3751
Geometry *GeomArcOfHyperbola::copy() const
3752
{
3753
    GeomArcOfHyperbola* copy = new GeomArcOfHyperbola();
3754
    copy->setHandle(this->myCurve);
3755
    copy->copyNonTag(this);
3756
    return copy;
3757
}
3758

3759
GeomBSplineCurve* GeomArcOfHyperbola::toNurbs(double first, double last) const
3760
{
3761
    Handle(Geom_TrimmedCurve) curve =  Handle(Geom_TrimmedCurve)::DownCast(handle());
3762
    Handle(Geom_Hyperbola) hyperbola = Handle(Geom_Hyperbola)::DownCast(curve->BasisCurve());
3763
    return GeomHyperbola(hyperbola).toNurbs(first, last);
3764
}
3765

3766
double GeomArcOfHyperbola::getMajorRadius() const
3767
{
3768
    Handle(Geom_Hyperbola) h = Handle(Geom_Hyperbola)::DownCast(myCurve->BasisCurve());
3769
    return h->MajorRadius();
3770
}
3771

3772
void GeomArcOfHyperbola::setMajorRadius(double Radius)
3773
{
3774
    Handle(Geom_Hyperbola) h = Handle(Geom_Hyperbola)::DownCast(myCurve->BasisCurve());
3775

3776
    try {
3777
        h->SetMajorRadius(Radius);
3778
    }
3779
    catch (Standard_Failure& e) {
3780

3781
        THROWM(Base::CADKernelError,e.GetMessageString())
3782
    }
3783
}
3784

3785
double GeomArcOfHyperbola::getMinorRadius() const
3786
{
3787
    Handle(Geom_Hyperbola) h = Handle(Geom_Hyperbola)::DownCast(myCurve->BasisCurve());
3788
    return h->MinorRadius();
3789
}
3790

3791
void GeomArcOfHyperbola::setMinorRadius(double Radius)
3792
{
3793
    Handle(Geom_Hyperbola) h = Handle(Geom_Hyperbola)::DownCast(myCurve->BasisCurve());
3794

3795
    try {
3796
        h->SetMinorRadius(Radius);
3797
    }
3798
    catch (Standard_Failure& e) {
3799

3800
        THROWM(Base::CADKernelError,e.GetMessageString())
3801
    }
3802
}
3803

3804
/*!
3805
 * \brief GeomArcOfHyperbola::getMajorAxisDir
3806
 * \return the direction vector (unit-length) of major axis of the hyperbola. The
3807
 * direction also points to the first focus.
3808
 */
3809
Base::Vector3d GeomArcOfHyperbola::getMajorAxisDir() const
3810
{
3811
    Handle(Geom_Hyperbola) c = Handle(Geom_Hyperbola)::DownCast( myCurve->BasisCurve() );
3812
    assert(!c.IsNull());
3813
    gp_Dir xdir = c->XAxis().Direction();
3814
    return Base::Vector3d(xdir.X(), xdir.Y(), xdir.Z());
3815
}
3816

3817
/*!
3818
 * \brief GeomArcOfHyperbola::getMinorAxisDir
3819
 * \return the direction vector (unit-length) of minor axis of the hyperbola.
3820
 */
3821
Base::Vector3d GeomArcOfHyperbola::getMinorAxisDir() const
3822
{
3823
    Handle(Geom_Hyperbola) c = Handle(Geom_Hyperbola)::DownCast( myCurve->BasisCurve() );
3824
    assert(!c.IsNull());
3825
    gp_Dir ydir = c->YAxis().Direction();
3826
    return Base::Vector3d(ydir.X(), ydir.Y(), ydir.Z());
3827
}
3828

3829
/*!
3830
 * \brief GeomArcOfHyperbola::setMajorAxisDir Rotates the hyperbola in its plane, so
3831
 * that its major axis is as close as possible to the provided direction.
3832
 * \param newdir [in] is the new direction. If the vector is small, the
3833
 * orientation of the ellipse will be preserved. If the vector is not small,
3834
 * but its projection onto plane of the ellipse is small, an exception will be
3835
 * thrown.
3836
 */
3837
void GeomArcOfHyperbola::setMajorAxisDir(Base::Vector3d newdir)
3838
{
3839
    Handle(Geom_Hyperbola) c = Handle(Geom_Hyperbola)::DownCast( myCurve->BasisCurve() );
3840
    assert(!c.IsNull());
3841
    if (newdir.Sqr() < Precision::SquareConfusion())
3842
        return;//zero vector was passed. Keep the old orientation.
3843

3844
    try {
3845
        gp_Ax2 pos = c->Position();
3846
        pos.SetXDirection(gp_Dir(newdir.x, newdir.y, newdir.z));//OCC should keep the old main Direction (Z), and change YDirection to accommodate the new XDirection.
3847
        c->SetPosition(pos);
3848
    }
3849
    catch (Standard_Failure& e) {
3850

3851
        THROWM(Base::CADKernelError,e.GetMessageString())
3852
    }
3853
}
3854

3855
void GeomArcOfHyperbola::getRange(double& u, double& v, bool emulateCCWXY) const
3856
{
3857
    try {
3858
        if (emulateCCWXY){
3859
            if (isReversed()) {
3860
                Handle(Geom_Hyperbola) c = Handle(Geom_Hyperbola)::DownCast(myCurve->BasisCurve());
3861
                assert(!c.IsNull());
3862
                c->Reverse();
3863
            }
3864
        }
3865
    }
3866
    catch (Standard_Failure& e) {
3867

3868
        THROWM(Base::CADKernelError,e.GetMessageString())
3869
    }
3870

3871
    u = myCurve->FirstParameter();
3872
    v = myCurve->LastParameter();
3873
}
3874

3875
void GeomArcOfHyperbola::setRange(double u, double v, bool emulateCCWXY)
3876
{
3877
    try {
3878
        myCurve->SetTrim(u, v);
3879

3880
        if (emulateCCWXY) {
3881
            if (isReversed()) {
3882
                Handle(Geom_Hyperbola) c = Handle(Geom_Hyperbola)::DownCast(myCurve->BasisCurve());
3883
                assert(!c.IsNull());
3884
                c->Reverse();
3885
            }
3886
        }
3887
    }
3888
    catch (Standard_Failure& e) {
3889

3890
        THROWM(Base::CADKernelError,e.GetMessageString())
3891
    }
3892
}
3893

3894
// Persistence implementer
3895
unsigned int GeomArcOfHyperbola::getMemSize () const
3896
{
3897
    return sizeof(Geom_Hyperbola) + 2 *sizeof(double);
3898
}
3899

3900
void GeomArcOfHyperbola::Save(Base::Writer &writer) const
3901
{
3902
    // save the attributes of the father class
3903
    GeomCurve::Save(writer);
3904

3905
    Handle(Geom_Hyperbola) h = Handle(Geom_Hyperbola)::DownCast(this->myCurve->BasisCurve());
3906

3907
    gp_Pnt center = h->Axis().Location();
3908
    gp_Dir normal = h->Axis().Direction();
3909
    gp_Dir xdir = h->XAxis().Direction();
3910

3911
    gp_Ax2 xdirref(center, normal); // this is a reference XY for the ellipse
3912

3913
    double AngleXU = -xdir.AngleWithRef(xdirref.XDirection(),normal);
3914

3915
    writer.Stream()
3916
         << writer.ind()
3917
            << "<ArcOfHyperbola "
3918
            << "CenterX=\"" <<  center.X() << "\" "
3919
            << "CenterY=\"" <<  center.Y() << "\" "
3920
            << "CenterZ=\"" <<  center.Z() << "\" "
3921
            << "NormalX=\"" <<  normal.X() << "\" "
3922
            << "NormalY=\"" <<  normal.Y() << "\" "
3923
            << "NormalZ=\"" <<  normal.Z() << "\" "
3924
            << "MajorRadius=\"" <<  h->MajorRadius() << "\" "
3925
            << "MinorRadius=\"" <<  h->MinorRadius() << "\" "
3926
            << "AngleXU=\"" << AngleXU << "\" "
3927
            << "StartAngle=\"" <<  this->myCurve->FirstParameter() << "\" "
3928
            << "EndAngle=\"" <<  this->myCurve->LastParameter() << "\" "
3929
            << "/>" << std::endl;
3930
}
3931

3932
void GeomArcOfHyperbola::Restore(Base::XMLReader &reader)
3933
{
3934
    // read the attributes of the father class
3935
    GeomCurve::Restore(reader);
3936

3937
    double CenterX,CenterY,CenterZ,NormalX,NormalY,NormalZ,MajorRadius,MinorRadius,AngleXU,StartAngle,EndAngle;
3938
    // read my Element
3939
    reader.readElement("ArcOfHyperbola");
3940
    // get the value of my Attribute
3941
    CenterX = reader.getAttributeAsFloat("CenterX");
3942
    CenterY = reader.getAttributeAsFloat("CenterY");
3943
    CenterZ = reader.getAttributeAsFloat("CenterZ");
3944
    NormalX = reader.getAttributeAsFloat("NormalX");
3945
    NormalY = reader.getAttributeAsFloat("NormalY");
3946
    NormalZ = reader.getAttributeAsFloat("NormalZ");
3947
    MajorRadius = reader.getAttributeAsFloat("MajorRadius");
3948
    MinorRadius = reader.getAttributeAsFloat("MinorRadius");
3949
    AngleXU = reader.getAttributeAsFloat("AngleXU");
3950
    StartAngle = reader.getAttributeAsFloat("StartAngle");
3951
    EndAngle = reader.getAttributeAsFloat("EndAngle");
3952

3953

3954
    // set the read geometry
3955
    gp_Pnt p1(CenterX,CenterY,CenterZ);
3956
    gp_Dir norm(NormalX,NormalY,NormalZ);
3957

3958
    gp_Ax1 normaxis(p1,norm);
3959

3960
    gp_Ax2 xdir(p1, norm);
3961

3962
    xdir.Rotate(normaxis,AngleXU);
3963

3964
    try {
3965
        GC_MakeHyperbola mc(xdir, MajorRadius, MinorRadius);
3966
        if (!mc.IsDone())
3967
            THROWM(Base::CADKernelError,gce_ErrorStatusText(mc.Status()))
3968

3969
        GC_MakeArcOfHyperbola ma(mc.Value()->Hypr(), StartAngle, EndAngle, Standard_True);
3970
        if (!ma.IsDone())
3971
            THROWM(Base::CADKernelError,gce_ErrorStatusText(ma.Status()))
3972

3973
        Handle(Geom_TrimmedCurve) tmpcurve = ma.Value();
3974
        Handle(Geom_Hyperbola) tmphyperbola = Handle(Geom_Hyperbola)::DownCast(tmpcurve->BasisCurve());
3975
        Handle(Geom_Hyperbola) hyperbola = Handle(Geom_Hyperbola)::DownCast(this->myCurve->BasisCurve());
3976

3977
        hyperbola->SetHypr(tmphyperbola->Hypr());
3978
        this->myCurve->SetTrim(tmpcurve->FirstParameter(), tmpcurve->LastParameter());
3979
    }
3980
    catch (Standard_Failure& e) {
3981

3982
        THROWM(Base::CADKernelError,e.GetMessageString())
3983
    }
3984
}
3985

3986
PyObject *GeomArcOfHyperbola::getPyObject()
3987
{
3988
    return new ArcOfHyperbolaPy(static_cast<GeomArcOfHyperbola*>(this->clone()));
3989
}
3990
// -------------------------------------------------
3991

3992
TYPESYSTEM_SOURCE(Part::GeomParabola,Part::GeomConic)
3993

3994
GeomParabola::GeomParabola()
3995
{
3996
    Handle(Geom_Parabola) p = new Geom_Parabola(gp_Parab());
3997
    this->myCurve = p;
3998
}
3999

4000
GeomParabola::GeomParabola(const Handle(Geom_Parabola)& p)
4001
{
4002
    setHandle(p);
4003
}
4004

4005
GeomParabola::~GeomParabola() = default;
4006

4007
const Handle(Geom_Geometry)& GeomParabola::handle() const
4008
{
4009
    return myCurve;
4010
}
4011

4012
void GeomParabola::setHandle(const Handle(Geom_Parabola)& c)
4013
{
4014
    myCurve = Handle(Geom_Parabola)::DownCast(c->Copy());
4015
}
4016

4017
Geometry *GeomParabola::copy() const
4018
{
4019
    GeomParabola *newPar = new GeomParabola(myCurve);
4020
    newPar->copyNonTag(this);
4021
    return newPar;
4022
}
4023

4024
GeomBSplineCurve* GeomParabola::toNurbs(double first, double last) const
4025
{
4026
    // the default implementation suffices because a non-rational B-spline with
4027
    // one segment is a parabola
4028
    return GeomCurve::toNurbs(first, last); // NOLINT
4029
}
4030

4031
double GeomParabola::getFocal() const
4032
{
4033
    Handle(Geom_Parabola) p = Handle(Geom_Parabola)::DownCast(handle());
4034
    return p->Focal();
4035
}
4036

4037
void GeomParabola::setFocal(double length)
4038
{
4039
    Handle(Geom_Parabola) p = Handle(Geom_Parabola)::DownCast(handle());
4040

4041
    try {
4042
        p->SetFocal(length);
4043
    }
4044
    catch (Standard_Failure& e) {
4045

4046
        THROWM(Base::CADKernelError,e.GetMessageString())
4047
    }
4048
}
4049

4050
// Persistence implementer
4051
unsigned int GeomParabola::getMemSize () const
4052
{
4053
    return sizeof(Geom_Parabola);
4054
}
4055

4056
void GeomParabola::Save(Base::Writer& writer) const
4057
{
4058
    // save the attributes of the father class
4059
    GeomCurve::Save(writer);
4060

4061
    gp_Pnt center = this->myCurve->Axis().Location();
4062
    gp_Dir normal = this->myCurve->Axis().Direction();
4063
    gp_Dir xdir = this->myCurve->XAxis().Direction();
4064

4065
    gp_Ax2 xdirref(center, normal); // this is a reference XY for the ellipse
4066

4067
    double AngleXU = -xdir.AngleWithRef(xdirref.XDirection(),normal);
4068

4069
    writer.Stream()
4070
         << writer.ind()
4071
            << "<Parabola "
4072
            << "CenterX=\"" <<  center.X() << "\" "
4073
            << "CenterY=\"" <<  center.Y() << "\" "
4074
            << "CenterZ=\"" <<  center.Z() << "\" "
4075
            << "NormalX=\"" <<  normal.X() << "\" "
4076
            << "NormalY=\"" <<  normal.Y() << "\" "
4077
            << "NormalZ=\"" <<  normal.Z() << "\" "
4078
            << "Focal=\"" <<  this->myCurve->Focal() << "\" "
4079
            << "AngleXU=\"" << AngleXU << "\" "
4080
            << "/>" << std::endl;
4081
}
4082

4083
void GeomParabola::Restore(Base::XMLReader& reader)
4084
{
4085
    // read the attributes of the father class
4086
    GeomCurve::Restore(reader);
4087

4088
    double CenterX,CenterY,CenterZ,NormalX,NormalY,NormalZ,Focal,AngleXU;
4089
    // read my Element
4090
    reader.readElement("Parabola");
4091
    // get the value of my Attribute
4092
    CenterX = reader.getAttributeAsFloat("CenterX");
4093
    CenterY = reader.getAttributeAsFloat("CenterY");
4094
    CenterZ = reader.getAttributeAsFloat("CenterZ");
4095
    NormalX = reader.getAttributeAsFloat("NormalX");
4096
    NormalY = reader.getAttributeAsFloat("NormalY");
4097
    NormalZ = reader.getAttributeAsFloat("NormalZ");
4098
    Focal = reader.getAttributeAsFloat("Focal");
4099
    AngleXU = reader.getAttributeAsFloat("AngleXU");
4100

4101
    // set the read geometry
4102
    gp_Pnt p1(CenterX,CenterY,CenterZ);
4103
    gp_Dir norm(NormalX,NormalY,NormalZ);
4104

4105
    gp_Ax1 normaxis(p1,norm);
4106

4107
    gp_Ax2 xdir(p1, norm);
4108

4109
    xdir.Rotate(normaxis,AngleXU);
4110

4111
    try {
4112
        gce_MakeParab mc(xdir, Focal);
4113
        if (!mc.IsDone())
4114
            THROWM(Base::CADKernelError,gce_ErrorStatusText(mc.Status()))
4115

4116
        this->myCurve = new Geom_Parabola(mc.Value());
4117
    }
4118
    catch (Standard_Failure& e) {
4119

4120
        THROWM(Base::CADKernelError,e.GetMessageString())
4121
    }
4122
}
4123

4124
PyObject *GeomParabola::getPyObject()
4125
{
4126
    return new ParabolaPy(static_cast<GeomParabola*>(this->clone()));
4127
}
4128

4129
bool GeomParabola::isSame(const Geometry &_other, double tol, double atol) const
4130
{
4131
    if(_other.getTypeId() != getTypeId())
4132
        return false;
4133

4134
    (void)atol;
4135
    auto &other = static_cast<const GeomParabola &>(_other);
4136
    return GeomConic::isSame(other,tol,atol) && fabs(getFocal() - other.getFocal()) < tol;
4137
}
4138
// -------------------------------------------------
4139

4140
TYPESYSTEM_SOURCE(Part::GeomArcOfParabola,Part::GeomArcOfConic)
4141

4142
GeomArcOfParabola::GeomArcOfParabola()
4143
{
4144
    Handle(Geom_Parabola) p = new Geom_Parabola(gp_Parab());
4145
    this->myCurve = new Geom_TrimmedCurve(p, p->FirstParameter(),p->LastParameter());
4146
}
4147

4148
GeomArcOfParabola::GeomArcOfParabola(const Handle(Geom_Parabola)& h)
4149
{
4150
    setHandle(h);
4151
}
4152

4153
GeomArcOfParabola::~GeomArcOfParabola() = default;
4154

4155
void GeomArcOfParabola::setHandle(const Handle(Geom_TrimmedCurve)& c)
4156
{
4157
    Handle(Geom_Parabola) basis = Handle(Geom_Parabola)::DownCast(c->BasisCurve());
4158
    if (basis.IsNull())
4159
        Standard_Failure::Raise("Basis curve is not a parabola");
4160
    this->myCurve = Handle(Geom_TrimmedCurve)::DownCast(c->Copy());
4161
}
4162

4163
void GeomArcOfParabola::setHandle(const Handle(Geom_Parabola)& h)
4164
{
4165
    this->myCurve = new Geom_TrimmedCurve(h, h->FirstParameter(),h->LastParameter());
4166
}
4167

4168
const Handle(Geom_Geometry)& GeomArcOfParabola::handle() const
4169
{
4170
    return myCurve;
4171
}
4172

4173
Geometry *GeomArcOfParabola::copy() const
4174
{
4175
    GeomArcOfParabola* copy = new GeomArcOfParabola();
4176
    copy->setHandle(this->myCurve);
4177
    copy->copyNonTag(this);
4178
    return copy;
4179
}
4180

4181
GeomBSplineCurve* GeomArcOfParabola::toNurbs(double first, double last) const
4182
{
4183
    Handle(Geom_TrimmedCurve) curve =  Handle(Geom_TrimmedCurve)::DownCast(handle());
4184
    Handle(Geom_Parabola) parabola = Handle(Geom_Parabola)::DownCast(curve->BasisCurve());
4185
    return GeomParabola(parabola).toNurbs(first, last);
4186
}
4187

4188
double GeomArcOfParabola::getFocal() const
4189
{
4190
    Handle(Geom_Parabola) p = Handle(Geom_Parabola)::DownCast(myCurve->BasisCurve());
4191
    return p->Focal();
4192
}
4193

4194
void GeomArcOfParabola::setFocal(double length)
4195
{
4196
    Handle(Geom_Parabola) p = Handle(Geom_Parabola)::DownCast(myCurve->BasisCurve());
4197

4198
    try {
4199
        p->SetFocal(length);
4200
    }
4201
    catch (Standard_Failure& e) {
4202

4203
        THROWM(Base::CADKernelError,e.GetMessageString())
4204
    }
4205
}
4206

4207
Base::Vector3d GeomArcOfParabola::getFocus() const
4208
{
4209
    Handle(Geom_Parabola) p = Handle(Geom_Parabola)::DownCast(myCurve->BasisCurve());
4210
    gp_Pnt gp = p->Focus();
4211

4212
    return Base::Vector3d(gp.X(),gp.Y(),gp.Z());
4213
}
4214

4215
void GeomArcOfParabola::getRange(double& u, double& v, bool emulateCCWXY) const
4216
{
4217
    try {
4218
        if (emulateCCWXY) {
4219
            if (isReversed()) {
4220
                Handle(Geom_Parabola) c = Handle(Geom_Parabola)::DownCast(myCurve->BasisCurve());
4221
                assert(!c.IsNull());
4222
                c->Reverse();
4223
            }
4224
        }
4225
    }
4226
    catch (Standard_Failure& e) {
4227

4228
        THROWM(Base::CADKernelError,e.GetMessageString())
4229
    }
4230

4231
    u = myCurve->FirstParameter();
4232
    v = myCurve->LastParameter();
4233
}
4234

4235
void GeomArcOfParabola::setRange(double u, double v, bool emulateCCWXY)
4236
{
4237
    try {
4238
        myCurve->SetTrim(u, v);
4239
        if (emulateCCWXY) {
4240
            if (isReversed()) {
4241
                Handle(Geom_Parabola) c = Handle(Geom_Parabola)::DownCast(myCurve->BasisCurve());
4242
                assert(!c.IsNull());
4243
                c->Reverse();
4244
            }
4245
        }
4246
    }
4247
    catch (Standard_Failure& e) {
4248

4249
        THROWM(Base::CADKernelError,e.GetMessageString())
4250
    }
4251
}
4252

4253
// Persistence implementer
4254
unsigned int GeomArcOfParabola::getMemSize () const
4255
{
4256
    return sizeof(Geom_Parabola) + 2 *sizeof(double);
4257
}
4258

4259
void GeomArcOfParabola::Save(Base::Writer &writer) const
4260
{
4261
    // save the attributes of the father class
4262
    GeomCurve::Save(writer);
4263

4264
    Handle(Geom_Parabola) p = Handle(Geom_Parabola)::DownCast(this->myCurve->BasisCurve());
4265

4266
    gp_Pnt center = p->Axis().Location();
4267
    gp_Dir normal = p->Axis().Direction();
4268
    gp_Dir xdir = p->XAxis().Direction();
4269

4270
    gp_Ax2 xdirref(center, normal); // this is a reference XY for the ellipse
4271

4272
    double AngleXU = -xdir.AngleWithRef(xdirref.XDirection(),normal);
4273

4274
    writer.Stream()
4275
         << writer.ind()
4276
            << "<ArcOfParabola "
4277
            << "CenterX=\"" <<  center.X() << "\" "
4278
            << "CenterY=\"" <<  center.Y() << "\" "
4279
            << "CenterZ=\"" <<  center.Z() << "\" "
4280
            << "NormalX=\"" <<  normal.X() << "\" "
4281
            << "NormalY=\"" <<  normal.Y() << "\" "
4282
            << "NormalZ=\"" <<  normal.Z() << "\" "
4283
            << "Focal=\"" <<  p->Focal() << "\" "
4284
            << "AngleXU=\"" << AngleXU << "\" "
4285
            << "StartAngle=\"" <<  this->myCurve->FirstParameter() << "\" "
4286
            << "EndAngle=\"" <<  this->myCurve->LastParameter() << "\" "
4287
            << "/>" << std::endl;
4288
}
4289

4290
void GeomArcOfParabola::Restore(Base::XMLReader &reader)
4291
{
4292
    // read the attributes of the father class
4293
    GeomCurve::Restore(reader);
4294

4295
    double CenterX,CenterY,CenterZ,NormalX,NormalY,NormalZ,Focal,AngleXU,StartAngle,EndAngle;
4296
    // read my Element
4297
    reader.readElement("ArcOfParabola");
4298
    // get the value of my Attribute
4299
    CenterX = reader.getAttributeAsFloat("CenterX");
4300
    CenterY = reader.getAttributeAsFloat("CenterY");
4301
    CenterZ = reader.getAttributeAsFloat("CenterZ");
4302
    NormalX = reader.getAttributeAsFloat("NormalX");
4303
    NormalY = reader.getAttributeAsFloat("NormalY");
4304
    NormalZ = reader.getAttributeAsFloat("NormalZ");
4305
    Focal = reader.getAttributeAsFloat("Focal");
4306
    AngleXU = reader.getAttributeAsFloat("AngleXU");
4307
    StartAngle = reader.getAttributeAsFloat("StartAngle");
4308
    EndAngle = reader.getAttributeAsFloat("EndAngle");
4309

4310

4311
    // set the read geometry
4312
    gp_Pnt p1(CenterX,CenterY,CenterZ);
4313
    gp_Dir norm(NormalX,NormalY,NormalZ);
4314

4315
    gp_Ax1 normaxis(p1,norm);
4316

4317
    gp_Ax2 xdir(p1, norm);
4318

4319
    xdir.Rotate(normaxis,AngleXU);
4320

4321
    try {
4322
        gce_MakeParab mc(xdir, Focal);
4323
        if (!mc.IsDone())
4324
            THROWM(Base::CADKernelError,gce_ErrorStatusText(mc.Status()))
4325

4326
        GC_MakeArcOfParabola ma(mc.Value(), StartAngle, EndAngle, Standard_True);
4327
        if (!ma.IsDone())
4328
            THROWM(Base::CADKernelError,gce_ErrorStatusText(ma.Status()))
4329

4330
        Handle(Geom_TrimmedCurve) tmpcurve = ma.Value();
4331
        Handle(Geom_Parabola) tmpparabola = Handle(Geom_Parabola)::DownCast(tmpcurve->BasisCurve());
4332
        Handle(Geom_Parabola) parabola = Handle(Geom_Parabola)::DownCast(this->myCurve->BasisCurve());
4333

4334
        parabola->SetParab(tmpparabola->Parab());
4335
        this->myCurve->SetTrim(tmpcurve->FirstParameter(), tmpcurve->LastParameter());
4336
    }
4337
    catch (Standard_Failure& e) {
4338

4339
        THROWM(Base::CADKernelError,e.GetMessageString())
4340
    }
4341
}
4342

4343
PyObject *GeomArcOfParabola::getPyObject()
4344
{
4345
    return new ArcOfParabolaPy(static_cast<GeomArcOfParabola*>(this->clone()));
4346
}
4347

4348
// -------------------------------------------------
4349

4350
TYPESYSTEM_SOURCE(Part::GeomLine,Part::GeomCurve)
4351

4352
GeomLine::GeomLine()
4353
{
4354
    Handle(Geom_Line) c = new Geom_Line(gp_Lin());
4355
    this->myCurve = c;
4356
}
4357

4358
GeomLine::GeomLine(const Handle(Geom_Line)& l)
4359
{
4360
    setHandle(l);
4361
}
4362

4363
GeomLine::GeomLine(const Base::Vector3d& Pos, const Base::Vector3d& Dir)
4364
{
4365
    this->myCurve = new Geom_Line(gp_Pnt(Pos.x,Pos.y,Pos.z),gp_Dir(Dir.x,Dir.y,Dir.z));
4366
}
4367

4368

4369
GeomLine::~GeomLine() = default;
4370

4371
void GeomLine::setLine(const Base::Vector3d& Pos, const Base::Vector3d& Dir)
4372
{
4373
    this->myCurve->SetLocation(gp_Pnt(Pos.x,Pos.y,Pos.z));
4374
    this->myCurve->SetDirection(gp_Dir(Dir.x,Dir.y,Dir.z));
4375
}
4376

4377
Base::Vector3d GeomLine::getPos() const
4378
{
4379
    gp_Pnt Pos = this->myCurve->Lin().Location();
4380
    return Base::Vector3d(Pos.X(),Pos.Y(),Pos.Z());
4381
}
4382

4383
Base::Vector3d GeomLine::getDir() const
4384
{
4385
    gp_Dir Dir = this->myCurve->Lin().Direction();
4386
    return Base::Vector3d(Dir.X(),Dir.Y(),Dir.Z());
4387
}
4388

4389
const Handle(Geom_Geometry)& GeomLine::handle() const
4390
{
4391
    return myCurve;
4392
}
4393

4394

4395
void GeomLine::setHandle(const Handle(Geom_Line)& l)
4396
{
4397
    this->myCurve = Handle(Geom_Line)::DownCast(l->Copy());
4398
}
4399

4400
Geometry *GeomLine::copy() const
4401
{
4402
    GeomLine *newLine = new GeomLine(myCurve);
4403
    newLine->copyNonTag(this);
4404
    return newLine;
4405
}
4406

4407
// Persistence implementer
4408
unsigned int GeomLine::getMemSize () const
4409
{
4410
    return sizeof(Geom_Line);
4411
}
4412

4413
void GeomLine::Save(Base::Writer &writer) const
4414
{
4415
    // save the attributes of the father class
4416
    Geometry::Save(writer);
4417

4418
    Base::Vector3d Pos   =  getPos();
4419
    Base::Vector3d Dir   =  getDir();
4420

4421
    writer.Stream()
4422
         << writer.ind()
4423
             << "<GeomLine "
4424
                << "PosX=\"" <<  Pos.x <<
4425
                "\" PosY=\"" <<  Pos.y <<
4426
                "\" PosZ=\"" <<  Pos.z <<
4427
                "\" DirX=\"" <<  Dir.x <<
4428
                "\" DirY=\"" <<  Dir.y <<
4429
                "\" DirZ=\"" <<  Dir.z <<
4430
             "\"/>" << std::endl;
4431
}
4432
void GeomLine::Restore(Base::XMLReader &reader)
4433
{
4434
    // read the attributes of the father class
4435
    Geometry::Restore(reader);
4436

4437
    double PosX,PosY,PosZ,DirX,DirY,DirZ;
4438
    // read my Element
4439
    reader.readElement("GeomLine");
4440
    // get the value of my Attribute
4441
    PosX = reader.getAttributeAsFloat("PosX");
4442
    PosY = reader.getAttributeAsFloat("PosY");
4443
    PosZ = reader.getAttributeAsFloat("PosZ");
4444
    DirX = reader.getAttributeAsFloat("DirX");
4445
    DirY = reader.getAttributeAsFloat("DirY");
4446
    DirZ = reader.getAttributeAsFloat("DirZ");
4447

4448
    // set the read geometry
4449
    setLine(Base::Vector3d(PosX,PosY,PosZ),Base::Vector3d(DirX,DirY,DirZ) );
4450
}
4451

4452
PyObject *GeomLine::getPyObject()
4453
{
4454
    return new LinePy(static_cast<GeomLine*>(this->clone()));
4455
}
4456

4457
bool GeomLine::isSame(const Geometry &_other, double tol, double atol) const
4458
{
4459
    if(_other.getTypeId() != getTypeId()) {
4460
        if (_other.isDerivedFrom(GeomCurve::getClassTypeId())) {
4461
            std::unique_ptr<Geometry> geo(dynamic_cast<const GeomCurve&>(_other).toLine());
4462
            if (geo)
4463
                return isSame(*geo, tol, atol);
4464
        }
4465
        return false;
4466
    }
4467

4468
    auto &other = dynamic_cast<const GeomLine &>(_other);
4469

4470
    return getDir().GetAngle(other.getDir()) <= atol
4471
            && Base::DistanceP2(getPos(), other.getPos()) <= tol*tol;
4472
}
4473
// -------------------------------------------------
4474

4475
TYPESYSTEM_SOURCE(Part::GeomLineSegment,Part::GeomTrimmedCurve)
4476

4477
GeomLineSegment::GeomLineSegment()
4478
{
4479
    gp_Lin line;
4480
    line.SetLocation(gp_Pnt(0.0,0.0,0.0));
4481
    line.SetDirection(gp_Dir(0.0,0.0,1.0));
4482
    Handle(Geom_Line) c = new Geom_Line(line);
4483
    this->myCurve = new Geom_TrimmedCurve(c, 0.0,1.0);
4484
}
4485

4486
GeomLineSegment::GeomLineSegment(const Handle(Geom_Line)& l)
4487
{
4488
    setHandle(l);
4489
}
4490

4491
GeomLineSegment::~GeomLineSegment() = default;
4492

4493
void GeomLineSegment::setHandle(const Handle(Geom_TrimmedCurve)& c)
4494
{
4495
    Handle(Geom_Line) basis = Handle(Geom_Line)::DownCast(c->BasisCurve());
4496
    if (basis.IsNull())
4497
        Standard_Failure::Raise("Basis curve is not a line");
4498
    this->myCurve = Handle(Geom_TrimmedCurve)::DownCast(c->Copy());
4499
}
4500

4501
void GeomLineSegment::setHandle(const Handle(Geom_Line)& l)
4502
{
4503
    this->myCurve = new Geom_TrimmedCurve(l, l->FirstParameter(),l->LastParameter());
4504
}
4505

4506
const Handle(Geom_Geometry)& GeomLineSegment::handle() const
4507
{
4508
    return myCurve;
4509
}
4510

4511
Geometry *GeomLineSegment::copy()const
4512
{
4513
    auto *tempCurve = new GeomLineSegment();
4514
    tempCurve->myCurve = Handle(Geom_TrimmedCurve)::DownCast(myCurve->Copy());
4515
    tempCurve->copyNonTag(this);
4516
    return tempCurve;
4517
}
4518

4519
Base::Vector3d GeomLineSegment::getStartPoint() const
4520
{
4521
    Handle(Geom_TrimmedCurve) this_curve = Handle(Geom_TrimmedCurve)::DownCast(handle());
4522
    gp_Pnt pnt = this_curve->StartPoint();
4523
    return Base::Vector3d(pnt.X(), pnt.Y(), pnt.Z());
4524
}
4525

4526
Base::Vector3d GeomLineSegment::getEndPoint() const
4527
{
4528
    Handle(Geom_TrimmedCurve) this_curve = Handle(Geom_TrimmedCurve)::DownCast(handle());
4529
    gp_Pnt pnt = this_curve->EndPoint();
4530
    return Base::Vector3d(pnt.X(), pnt.Y(), pnt.Z());
4531
}
4532

4533
void GeomLineSegment::setPoints(const Base::Vector3d& Start, const Base::Vector3d& End)
4534
{
4535
    gp_Pnt p1(Start.x,Start.y,Start.z), p2(End.x,End.y,End.z);
4536
    Handle(Geom_TrimmedCurve) this_curv = Handle(Geom_TrimmedCurve)::DownCast(handle());
4537

4538
    try {
4539
        // Create line out of two points
4540
        if (p1.Distance(p2) < gp::Resolution())
4541
            THROWM(Base::ValueError,"Both points are equal");
4542

4543
        GC_MakeSegment ms(p1, p2);
4544
        if (!ms.IsDone()) {
4545
            THROWM(Base::CADKernelError,gce_ErrorStatusText(ms.Status()))
4546
        }
4547

4548
        // get Geom_Line of line segment
4549
        Handle(Geom_Line) this_line = Handle(Geom_Line)::DownCast
4550
            (this_curv->BasisCurve());
4551
        Handle(Geom_TrimmedCurve)& that_curv =
4552
            const_cast<opencascade::handle<Geom_TrimmedCurve>&>(ms.Value());
4553
        Handle(Geom_Line) that_line = Handle(Geom_Line)::DownCast(that_curv->BasisCurve());
4554
        this_line->SetLin(that_line->Lin());
4555
        this_curv->SetTrim(that_curv->FirstParameter(), that_curv->LastParameter());
4556
    }
4557
    catch (Standard_Failure& e) {
4558

4559
        THROWM(Base::CADKernelError,e.GetMessageString())
4560
    }
4561
}
4562

4563
// Persistence implementer
4564
unsigned int GeomLineSegment::getMemSize () const
4565
{
4566
    return sizeof(Geom_TrimmedCurve) + sizeof(Geom_Line);
4567
}
4568

4569
void GeomLineSegment::Save       (Base::Writer &writer) const
4570
{
4571
    // save the attributes of the father class
4572
    Geometry::Save(writer);
4573

4574
    Base::Vector3d End   =  getEndPoint();
4575
    Base::Vector3d Start =  getStartPoint();
4576

4577
    writer.Stream()
4578
         << writer.ind()
4579
             << "<LineSegment "
4580
                << "StartX=\"" <<  Start.x <<
4581
                "\" StartY=\"" <<  Start.y <<
4582
                "\" StartZ=\"" <<  Start.z <<
4583
                "\" EndX=\"" <<  End.x <<
4584
                "\" EndY=\"" <<  End.y <<
4585
                "\" EndZ=\"" <<  End.z <<
4586
             "\"/>" << std::endl;
4587
}
4588

4589
void GeomLineSegment::Restore    (Base::XMLReader &reader)
4590
{
4591
    // read the attributes of the father class
4592
    Geometry::Restore(reader);
4593

4594
    double StartX,StartY,StartZ,EndX,EndY,EndZ;
4595
    // read my Element
4596
    reader.readElement("LineSegment");
4597
    // get the value of my Attribute
4598
    StartX = reader.getAttributeAsFloat("StartX");
4599
    StartY = reader.getAttributeAsFloat("StartY");
4600
    StartZ = reader.getAttributeAsFloat("StartZ");
4601
    EndX   = reader.getAttributeAsFloat("EndX");
4602
    EndY   = reader.getAttributeAsFloat("EndY");
4603
    EndZ   = reader.getAttributeAsFloat("EndZ");
4604

4605
    Base::Vector3d start(StartX,StartY,StartZ);
4606
    Base::Vector3d end(EndX,EndY,EndZ);
4607
    // set the read geometry
4608
    try {
4609
        setPoints(start, end);
4610
    }
4611
    catch(Base::ValueError&) {
4612
        // for a line segment construction, the only possibility of a value error is that
4613
        // the points are too close. The best try to restore is incrementing the distance.
4614
        // for other objects, the best effort may be just to leave default values.
4615
        reader.setPartialRestore(true);
4616

4617
        if(start.x == 0) {
4618
            end = start + Base::Vector3d(DBL_EPSILON,0,0);
4619
        }
4620
        else {
4621
            end = start + Base::Vector3d(start.x*DBL_EPSILON,0,0);
4622
        }
4623

4624
        setPoints(start, end);
4625
    }
4626
}
4627

4628
PyObject *GeomLineSegment::getPyObject()
4629
{
4630
    return new LineSegmentPy(dynamic_cast<GeomLineSegment*>(this->clone()));
4631
}
4632

4633
// -------------------------------------------------
4634

4635
TYPESYSTEM_SOURCE(Part::GeomOffsetCurve,Part::GeomCurve)
4636

4637
GeomOffsetCurve::GeomOffsetCurve() = default;
4638

4639
GeomOffsetCurve::GeomOffsetCurve(const Handle(Geom_Curve)& c, double offset, const gp_Dir& dir)
4640
{
4641
    this->myCurve = new Geom_OffsetCurve(c, offset, dir);
4642
}
4643

4644
GeomOffsetCurve::GeomOffsetCurve(const Handle(Geom_Curve)& c, double offset, Base::Vector3d& dir):GeomOffsetCurve(c,offset,gp_Dir(dir.x,dir.y,dir.z))
4645
{
4646
}
4647

4648
GeomOffsetCurve::GeomOffsetCurve(const Handle(Geom_OffsetCurve)& c)
4649
{
4650
    setHandle(c);
4651
}
4652

4653
GeomOffsetCurve::~GeomOffsetCurve() = default;
4654

4655
Geometry *GeomOffsetCurve::copy() const
4656
{
4657
    auto *newCurve = new GeomOffsetCurve(myCurve);
4658
    newCurve->copyNonTag(this);
4659
    return newCurve;
4660
}
4661

4662
Base::Vector3d GeomOffsetCurve::getDir() const
4663
{
4664
    gp_Dir Dir = this->myCurve->Direction();
4665
    return Base::Vector3d(Dir.X(),Dir.Y(),Dir.Z());
4666
}
4667

4668
double GeomOffsetCurve::getOffset() const
4669
{
4670
    return this->myCurve->Offset();
4671
}
4672

4673
void GeomOffsetCurve::setHandle(const Handle(Geom_OffsetCurve)& c)
4674
{
4675
    this->myCurve = Handle(Geom_OffsetCurve)::DownCast(c->Copy());
4676
}
4677

4678
const Handle(Geom_Geometry)& GeomOffsetCurve::handle() const
4679
{
4680
    return this->myCurve;
4681
}
4682

4683
// Persistence implementer
4684
unsigned int GeomOffsetCurve::getMemSize () const
4685
{
4686
    return sizeof(Geom_OffsetCurve);
4687
}
4688

4689
void GeomOffsetCurve::Save(Base::Writer &/*writer*/) const
4690
{
4691
    throw Base::NotImplementedError("GeomOffsetCurve::Save");
4692
}
4693

4694
void GeomOffsetCurve::Restore(Base::XMLReader &/*reader*/)
4695
{
4696
    throw Base::NotImplementedError("GeomOffsetCurve::Restore");
4697
}
4698

4699
PyObject *GeomOffsetCurve::getPyObject()
4700
{
4701
    return new OffsetCurvePy(dynamic_cast<GeomOffsetCurve*>(this->clone()));
4702
}
4703

4704
bool GeomOffsetCurve::isSame(const Geometry &_other, double tol, double atol) const
4705
{
4706
    if(_other.getTypeId() != getTypeId())
4707
        return false;
4708

4709
    auto &other = dynamic_cast<const GeomOffsetCurve &>(_other);
4710
    if(myCurve->Direction().Angle(other.myCurve->Direction()) > atol || fabs(getOffset() - other.getOffset()) > tol)
4711
        return false;
4712

4713
    Handle(Geom_Curve) basis = myCurve->BasisCurve();
4714
    Handle(Geom_Curve) basis1 = other.myCurve->BasisCurve();
4715
    if(basis.IsNull() || basis1.IsNull() || basis->DynamicType() != basis1->DynamicType())
4716
        return false;
4717

4718
    std::unique_ptr<Geometry> b(makeFromCurve(basis));
4719
    std::unique_ptr<Geometry> b1(makeFromCurve(basis1));
4720
    return b && b1 && b->isSame(*b1, tol, atol);
4721
}
4722

4723
// -------------------------------------------------
4724

4725

4726
TYPESYSTEM_SOURCE_ABSTRACT(Part::GeomSurface,Part::Geometry)
4727

4728
GeomSurface::GeomSurface() = default;
4729

4730
GeomSurface::~GeomSurface() = default;
4731

4732
bool GeomSurface::isPlanar(gp_Pln *pln, double tol) const
4733
{
4734
    Handle(Geom_Surface) s = Handle(Geom_Surface)::DownCast(handle());
4735
    return isPlanar(s, pln, tol);
4736
}
4737

4738
bool GeomSurface::isPlanar(const Handle(Geom_Surface) &s, gp_Pln *pln, double tol)
4739
{
4740
    GeomLib_IsPlanarSurface check(s, tol);
4741
    if (!check.IsPlanar())
4742
        return false;
4743
    if (pln)
4744
        *pln = check.Plan();
4745
    return true;
4746
}
4747

4748
GeomPlane* GeomSurface::toPlane(bool clone, double tol) const
4749
{
4750
    if (isDerivedFrom(GeomPlane::getClassTypeId())) {
4751
        if (clone) {
4752
            return dynamic_cast<GeomPlane*>(this->clone());
4753
        } else {
4754
            return dynamic_cast<GeomPlane*>(this->copy());
4755
        }
4756
    }
4757

4758
    gp_Pln pln;
4759
    if (!isPlanar(&pln, tol))
4760
        return nullptr;
4761

4762
    auto res = new GeomPlane(pln);
4763
    res->copyNonTag(this);
4764
    if (clone)
4765
        res->tag = this->tag;
4766
    return res;
4767
}
4768

4769
TopoDS_Shape GeomSurface::toShape() const
4770
{
4771
    Handle(Geom_Surface) s = Handle(Geom_Surface)::DownCast(handle());
4772
    Standard_Real u1,u2,v1,v2;
4773
    s->Bounds(u1,u2,v1,v2);
4774
    BRepBuilderAPI_MakeFace mkBuilder(s, u1, u2, v1, v2, Precision::Confusion() );
4775
    return mkBuilder.Shape();
4776
}
4777

4778
bool GeomSurface::tangentU(double u, double v, gp_Dir& dirU) const
4779
{
4780
    Handle(Geom_Surface) s = Handle(Geom_Surface)::DownCast(handle());
4781
    GeomLProp_SLProps prop(s,u,v,2,Precision::Confusion());
4782
    if (prop.IsTangentUDefined()) {
4783
        prop.TangentU(dirU);
4784
        return true;
4785
    }
4786
    return false;
4787
}
4788

4789
bool GeomSurface::tangentV(double u, double v, gp_Dir& dirV) const
4790
{
4791
    Handle(Geom_Surface) s = Handle(Geom_Surface)::DownCast(handle());
4792
    GeomLProp_SLProps prop(s,u,v,2,Precision::Confusion());
4793
    if (prop.IsTangentVDefined()) {
4794
        prop.TangentV(dirV);
4795
        return true;
4796
    }
4797

4798
    return false;
4799
}
4800

4801
bool GeomSurface::normal(double u, double v, gp_Dir& dir) const
4802
{
4803
    Handle(Geom_Surface) s = Handle(Geom_Surface)::DownCast(handle());
4804
    Standard_Boolean done;
4805

4806
    Tools::getNormal(s, u, v, Precision::Confusion(), dir, done);
4807

4808
    if (done)
4809
        return true;
4810

4811
    return false;
4812
}
4813

4814
gp_Vec GeomSurface::getDN(double u, double v, int Nu, int Nv) const
4815
{
4816
    Handle(Geom_Surface) s = Handle(Geom_Surface)::DownCast(handle());
4817
    return s->DN(u, v, Nu, Nv);
4818
}
4819

4820
bool GeomSurface::isUmbillic(double u, double v) const
4821
{
4822
    Handle(Geom_Surface) s = Handle(Geom_Surface)::DownCast(handle());
4823
    GeomLProp_SLProps prop(s,u,v,2,Precision::Confusion());
4824
    if (prop.IsCurvatureDefined()) {
4825
        return prop.IsUmbilic();
4826
    }
4827

4828
    THROWM(Base::RuntimeError,"No curvature defined")
4829
}
4830

4831
double GeomSurface::curvature(double u, double v, Curvature type) const
4832
{
4833
    Handle(Geom_Surface) s = Handle(Geom_Surface)::DownCast(handle());
4834
    GeomLProp_SLProps prop(s,u,v,2,Precision::Confusion());
4835
    if (prop.IsCurvatureDefined()) {
4836
        double value = 0;
4837
        switch (type) {
4838
        case Maximum:
4839
            value = prop.MaxCurvature();
4840
            break;
4841
        case Minimum:
4842
            value = prop.MinCurvature();
4843
            break;
4844
        case Mean:
4845
            value = prop.MeanCurvature();
4846
            break;
4847
        case Gaussian:
4848
            value = prop.GaussianCurvature();
4849
            break;
4850
        }
4851

4852
        return value;
4853
    }
4854

4855
    THROWM(Base::RuntimeError,"No curvature defined")
4856
}
4857

4858
void GeomSurface::curvatureDirections(double u, double v, gp_Dir& maxD, gp_Dir& minD) const
4859
{
4860
    Handle(Geom_Surface) s = Handle(Geom_Surface)::DownCast(handle());
4861
    GeomLProp_SLProps prop(s,u,v,2,Precision::Confusion());
4862
    if (prop.IsCurvatureDefined()) {
4863
        prop.CurvatureDirections(maxD, minD);
4864
        return;
4865
    }
4866

4867
    THROWM(Base::RuntimeError,"No curvature defined")
4868
}
4869

4870
// -------------------------------------------------
4871

4872
TYPESYSTEM_SOURCE(Part::GeomBezierSurface,Part::GeomSurface)
4873

4874
GeomBezierSurface::GeomBezierSurface()
4875
{
4876
    TColgp_Array2OfPnt poles(1,2,1,2);
4877
    poles(1,1) = gp_Pnt(0.0,0.0,0.0);
4878
    poles(2,1) = gp_Pnt(1.0,0.0,0.0);
4879
    poles(1,2) = gp_Pnt(0.0,1.0,0.0);
4880
    poles(2,2) = gp_Pnt(1.0,1.0,0.0);
4881
    this->mySurface = new Geom_BezierSurface(poles);
4882
}
4883

4884
GeomBezierSurface::GeomBezierSurface(const Handle(Geom_BezierSurface)& b)
4885
{
4886
    setHandle(b);
4887
}
4888

4889
GeomBezierSurface::~GeomBezierSurface() = default;
4890

4891
const Handle(Geom_Geometry)& GeomBezierSurface::handle() const
4892
{
4893
    return mySurface;
4894
}
4895

4896
void GeomBezierSurface::setHandle(const Handle(Geom_BezierSurface)& b)
4897
{
4898
    this->mySurface = Handle(Geom_BezierSurface)::DownCast(b->Copy());
4899
}
4900

4901
Geometry *GeomBezierSurface::copy() const
4902
{
4903
    auto *newSurf =  new GeomBezierSurface(mySurface);
4904
    newSurf->copyNonTag(this);
4905
    return newSurf;
4906
}
4907

4908
// Persistence implementer
4909
unsigned int GeomBezierSurface::getMemSize () const
4910
{
4911
    unsigned int size = sizeof(Geom_BezierSurface);
4912
    if (!mySurface.IsNull()) {
4913
        unsigned int poles = mySurface->NbUPoles();
4914
        poles *= mySurface->NbVPoles();
4915
        size += poles * sizeof(gp_Pnt);
4916
        size += poles * sizeof(Standard_Real);
4917
    }
4918
    return size;
4919
}
4920

4921
void GeomBezierSurface::Save(Base::Writer &/*writer*/) const
4922
{
4923
    throw Base::NotImplementedError("GeomBezierSurface::Save");
4924
}
4925

4926
void GeomBezierSurface::Restore(Base::XMLReader &/*reader*/)
4927
{
4928
    throw Base::NotImplementedError("GeomBezierSurface::Restore");
4929
}
4930

4931
PyObject *GeomBezierSurface::getPyObject()
4932
{
4933
    return new BezierSurfacePy(static_cast<GeomBezierSurface*>(this->clone()));
4934
}
4935

4936
bool GeomBezierSurface::isSame(const Geometry &_other, double tol, double atol) const
4937
{
4938
    if(_other.getTypeId() != getTypeId())
4939
        return false;
4940

4941
    auto &other = static_cast<const GeomBezierSurface &>(_other);
4942
    Standard_Integer uc = mySurface->NbUPoles();
4943
    Standard_Integer vc = mySurface->NbVPoles();
4944
    if(uc != other.mySurface->NbUPoles()
4945
            || vc != other.mySurface->NbVPoles()
4946
            || mySurface->UDegree() != other.mySurface->UDegree()
4947
            || mySurface->VDegree() != other.mySurface->VDegree())
4948
        return false;
4949

4950
    (void)atol;
4951
    double tol2 = tol*tol;
4952
    for(Standard_Integer u=1; u<=uc; ++u) {
4953
        for(Standard_Integer v=1; v<=vc; ++v) {
4954
            if(mySurface->Pole(u,v).SquareDistance(other.mySurface->Pole(u,v)) > tol2
4955
                    || fabs(mySurface->Weight(u,v) - other.mySurface->Weight(u,v)) > tol)
4956
                return false;
4957
        }
4958
    }
4959
    return true;
4960
}
4961

4962
// -------------------------------------------------
4963

4964
TYPESYSTEM_SOURCE(Part::GeomBSplineSurface,Part::GeomSurface)
4965

4966
GeomBSplineSurface::GeomBSplineSurface()
4967
{
4968
    TColgp_Array2OfPnt poles(1,2,1,2);
4969
    poles(1,1) = gp_Pnt(0.0,0.0,0.0);
4970
    poles(2,1) = gp_Pnt(1.0,0.0,0.0);
4971
    poles(1,2) = gp_Pnt(0.0,1.0,0.0);
4972
    poles(2,2) = gp_Pnt(1.0,1.0,0.0);
4973

4974
    TColStd_Array1OfReal knots(1,2);
4975
    knots(1) = 0.0;
4976
    knots(2) = 1.0;
4977

4978
    TColStd_Array1OfInteger mults(1,2);
4979
    mults(1) = 2;
4980
    mults(2) = 2;
4981

4982
    this->mySurface = new Geom_BSplineSurface(poles, knots, knots, mults, mults, 1, 1);
4983
}
4984

4985
GeomBSplineSurface::GeomBSplineSurface(const Handle(Geom_BSplineSurface)& b)
4986
{
4987
    setHandle(b);
4988
}
4989

4990
GeomBSplineSurface::~GeomBSplineSurface() = default;
4991

4992
void GeomBSplineSurface::setHandle(const Handle(Geom_BSplineSurface)& s)
4993
{
4994
    mySurface = Handle(Geom_BSplineSurface)::DownCast(s->Copy());
4995
}
4996

4997
const Handle(Geom_Geometry)& GeomBSplineSurface::handle() const
4998
{
4999
    return mySurface;
5000
}
5001

5002
Geometry *GeomBSplineSurface::copy() const
5003
{
5004
    GeomBSplineSurface *newSurf =  new GeomBSplineSurface(mySurface);
5005
    newSurf->copyNonTag(this);
5006
    return newSurf;
5007
}
5008

5009
void GeomBSplineSurface::scaleKnotsToBounds(double u0, double u1, double v0, double v1)
5010
{
5011
    try {
5012
        Handle(Geom_BSplineSurface) surf = Handle(Geom_BSplineSurface)::DownCast(mySurface->Copy());
5013
        Standard_RangeError_Raise_if (u1 <= u0 || v1 <= v0, " ");
5014
        Standard_Real bu0,bu1,bv0,bv1;
5015
        surf->Bounds(bu0,bu1,bv0,bv1);
5016
        if ((abs(u0-bu0) > Precision::Confusion()) || (abs(u1-bu1) > Precision::Confusion())) {
5017
            TColStd_Array1OfReal uk(1,surf->NbUKnots());
5018
            surf->UKnots(uk);
5019
            BSplCLib::Reparametrize(u0, u1, uk);
5020
            surf->SetUKnots(uk);
5021
        }
5022
        if ((abs(v0-bv0) > Precision::Confusion()) || (abs(v1-bv1) > Precision::Confusion())) {
5023
            TColStd_Array1OfReal vk(1,surf->NbVKnots());
5024
            surf->VKnots(vk);
5025
            BSplCLib::Reparametrize(v0, v1, vk);
5026
            surf->SetVKnots(vk);
5027
        }
5028
        mySurface = surf;
5029
        return;
5030
    }
5031
    catch (Standard_Failure& e) {
5032
        THROWM(Base::CADKernelError,e.GetMessageString())
5033
    }
5034
}
5035

5036
// Persistence implementer
5037
unsigned int GeomBSplineSurface::getMemSize () const
5038
{
5039
    unsigned int size = sizeof(Geom_BSplineSurface);
5040
    if (!mySurface.IsNull()) {
5041
        size += mySurface->NbUKnots() * sizeof(Standard_Real);
5042
        size += mySurface->NbUKnots() * sizeof(Standard_Integer);
5043
        size += mySurface->NbVKnots() * sizeof(Standard_Real);
5044
        size += mySurface->NbVKnots() * sizeof(Standard_Integer);
5045
        unsigned int poles = mySurface->NbUPoles();
5046
        poles *= mySurface->NbVPoles();
5047
        size += poles * sizeof(gp_Pnt);
5048
        size += poles * sizeof(Standard_Real);
5049
    }
5050
    return size;
5051
}
5052

5053
void GeomBSplineSurface::Save(Base::Writer &/*writer*/) const
5054
{
5055
    throw Base::NotImplementedError("GeomBSplineSurface::Save");
5056
}
5057

5058
void GeomBSplineSurface::Restore(Base::XMLReader &/*reader*/)
5059
{
5060
    throw Base::NotImplementedError("GeomBSplineSurface::Restore");
5061
}
5062

5063
PyObject *GeomBSplineSurface::getPyObject()
5064
{
5065
    return new BSplineSurfacePy(static_cast<GeomBSplineSurface*>(this->clone()));
5066
}
5067

5068
bool GeomBSplineSurface::isSame(const Geometry &_other, double tol, double atol) const
5069
{
5070
    if(_other.getTypeId() != getTypeId()) {
5071
        if (_other.isDerivedFrom(GeomSurface::getClassTypeId()) && isPlanar()) {
5072
            std::unique_ptr<Geometry> geo(toPlane());
5073
            if (geo)
5074
                return geo->isSame(_other, tol, atol);
5075
        }
5076
        return false;
5077
    }
5078

5079
    auto &other = static_cast<const GeomBSplineSurface &>(_other);
5080
    Standard_Integer uc = mySurface->NbUPoles();
5081
    Standard_Integer vc = mySurface->NbVPoles();
5082
    Standard_Integer ukc = mySurface->NbUKnots();
5083
    Standard_Integer vkc = mySurface->NbVKnots();
5084
    if(uc != other.mySurface->NbUPoles()
5085
            || vc != other.mySurface->NbVPoles()
5086
            || ukc != other.mySurface->NbUKnots()
5087
            || vkc != other.mySurface->NbVKnots()
5088
            || mySurface->UDegree() != other.mySurface->UDegree()
5089
            || mySurface->VDegree() != other.mySurface->VDegree()
5090
            || mySurface->IsUPeriodic() != other.mySurface->IsUPeriodic()
5091
            || mySurface->IsVPeriodic() != other.mySurface->IsVPeriodic())
5092
        return false;
5093

5094
    (void)atol;
5095
    double tol2 = tol*tol;
5096
    for(Standard_Integer u=1; u<=uc; ++u) {
5097
        for(Standard_Integer v=1; v<=vc; ++v) {
5098
            if(mySurface->Pole(u,v).SquareDistance(other.mySurface->Pole(u,v)) > tol2
5099
                    || fabs(mySurface->Weight(u,v) - other.mySurface->Weight(u,v)) > tol)
5100
                return false;
5101
        }
5102
    }
5103
    for(Standard_Integer u=1; u<=ukc; ++u) {
5104
        if(fabs(mySurface->UKnot(u) - other.mySurface->UKnot(u)) > tol
5105
                || fabs(mySurface->UMultiplicity(u) - other.mySurface->UMultiplicity(u)) > tol)
5106
            return false;
5107
    }
5108
    for(Standard_Integer v=1; v<=ukc; ++v) {
5109
        if(fabs(mySurface->VKnot(v) - other.mySurface->VKnot(v)) > tol
5110
                || fabs(mySurface->VMultiplicity(v) - other.mySurface->VMultiplicity(v)) > tol)
5111
            return false;
5112
    }
5113
    return true;
5114
}
5115

5116
// -------------------------------------------------
5117

5118
TYPESYSTEM_SOURCE_ABSTRACT(Part::GeomElementarySurface, Part::GeomSurface)
5119

5120
GeomElementarySurface::GeomElementarySurface()
5121
{
5122
}
5123

5124
GeomElementarySurface::~GeomElementarySurface()
5125
{
5126
}
5127

5128
Base::Vector3d GeomElementarySurface::getLocation(void) const
5129
{
5130
    Handle(Geom_ElementarySurface) surf =  Handle(Geom_ElementarySurface)::DownCast(handle());
5131
    gp_Pnt loc = surf->Location();
5132
    return Base::Vector3d(loc.X(),loc.Y(),loc.Z());
5133
}
5134

5135
Base::Vector3d GeomElementarySurface::getDir(void) const
5136
{
5137
    Handle(Geom_ElementarySurface) surf =  Handle(Geom_ElementarySurface)::DownCast(handle());
5138
    const gp_Dir &dir = surf->Position().Direction();
5139
    return Base::Vector3d(dir.X(),dir.Y(),dir.Z());
5140
}
5141

5142
Base::Vector3d GeomElementarySurface::getXDir(void) const
5143
{
5144
    Handle(Geom_ElementarySurface) surf =  Handle(Geom_ElementarySurface)::DownCast(handle());
5145
    const gp_Dir &dir = surf->Position().XDirection();
5146
    return Base::Vector3d(dir.X(),dir.Y(),dir.Z());
5147
}
5148

5149
Base::Vector3d GeomElementarySurface::getYDir(void) const
5150
{
5151
    Handle(Geom_ElementarySurface) surf =  Handle(Geom_ElementarySurface)::DownCast(handle());
5152
    const gp_Dir &dir = surf->Position().YDirection();
5153
    return Base::Vector3d(dir.X(),dir.Y(),dir.Z());
5154
}
5155

5156
bool GeomElementarySurface::isSame(const Geometry &_other, double tol, double atol) const
5157
{
5158
    if(!_other.isDerivedFrom(GeomElementarySurface::getClassTypeId()))
5159
        return false;
5160

5161
    auto &other = static_cast<const GeomElementarySurface &>(_other);
5162
    return Base::DistanceP2(getLocation(), other.getLocation()) <= tol*tol
5163
        && getDir().GetAngle(other.getDir()) <= atol
5164
        && ((getXDir().GetAngle(other.getXDir()) <= atol
5165
                && getYDir().GetAngle(other.getYDir()) <= atol)
5166
            // It seems that OCC may change some surface Position (gp_Ax3) to
5167
            // right hand coordinate. The following checks is to detect such cases.
5168
            || (getXDir().GetAngle(other.getYDir()) <= atol
5169
                && getYDir().GetAngle(-other.getXDir()) <= atol)
5170
            || (getYDir().GetAngle(other.getXDir()) <= atol
5171
                && getXDir().GetAngle(-other.getYDir()) <= atol));
5172
}
5173

5174
// -------------------------------------------------
5175

5176
TYPESYSTEM_SOURCE(Part::GeomCylinder,Part::GeomSurface)
5177

5178
GeomCylinder::GeomCylinder()
5179
{
5180
    Handle(Geom_CylindricalSurface) s = new Geom_CylindricalSurface(gp_Cylinder());
5181
    this->mySurface = s;
5182
}
5183

5184
GeomCylinder::GeomCylinder(const Handle(Geom_CylindricalSurface)& c)
5185
{
5186
    setHandle(c);
5187
}
5188

5189
GeomCylinder::~GeomCylinder() = default;
5190

5191
void GeomCylinder::setHandle(const Handle(Geom_CylindricalSurface)& s)
5192
{
5193
    mySurface = Handle(Geom_CylindricalSurface)::DownCast(s->Copy());
5194
}
5195

5196
const Handle(Geom_Geometry)& GeomCylinder::handle() const
5197
{
5198
    return mySurface;
5199
}
5200

5201
Geometry *GeomCylinder::copy() const
5202
{
5203
    GeomCylinder *tempCurve = new GeomCylinder();
5204
    tempCurve->mySurface = Handle(Geom_CylindricalSurface)::DownCast(mySurface->Copy());
5205
    tempCurve->copyNonTag(this);
5206
    return tempCurve;
5207
}
5208

5209
// Persistence implementer
5210
unsigned int GeomCylinder::getMemSize () const
5211
{
5212
    return sizeof(Geom_CylindricalSurface);
5213
}
5214

5215
void GeomCylinder::Save(Base::Writer &/*writer*/) const
5216
{
5217
    throw Base::NotImplementedError("GeomCylinder::Save");
5218
}
5219

5220
void GeomCylinder::Restore(Base::XMLReader &/*reader*/)
5221
{
5222
    throw Base::NotImplementedError("GeomCylinder::Restore");
5223
}
5224

5225
PyObject *GeomCylinder::getPyObject()
5226
{
5227
    return new CylinderPy(static_cast<GeomCylinder*>(this->clone()));
5228
}
5229

5230
double GeomCylinder::getRadius() const
5231
{
5232
    return mySurface->Radius();
5233
}
5234

5235
bool GeomCylinder::isSame(const Geometry &_other, double tol, double atol) const
5236
{
5237
    if(_other.getTypeId() != getTypeId())
5238
        return false;
5239

5240
    (void)atol;
5241
    auto &other = static_cast<const GeomCylinder &>(_other);
5242
    return GeomElementarySurface::isSame(other,tol,atol)
5243
        && fabs(getRadius() - other.getRadius()) <= tol;
5244
}
5245

5246

5247
// -------------------------------------------------
5248

5249
TYPESYSTEM_SOURCE(Part::GeomCone,Part::GeomSurface)
5250

5251
GeomCone::GeomCone()
5252
{
5253
    Handle(Geom_ConicalSurface) s = new Geom_ConicalSurface(gp_Cone());
5254
    this->mySurface = s;
5255
}
5256

5257
GeomCone::GeomCone(const Handle(Geom_ConicalSurface)& c)
5258
{
5259
    setHandle(c);
5260
}
5261

5262
GeomCone::~GeomCone() = default;
5263

5264
void GeomCone::setHandle(const Handle(Geom_ConicalSurface)& s)
5265
{
5266
    mySurface = Handle(Geom_ConicalSurface)::DownCast(s->Copy());
5267
}
5268

5269
const Handle(Geom_Geometry)& GeomCone::handle() const
5270
{
5271
    return mySurface;
5272
}
5273

5274
Geometry *GeomCone::copy() const
5275
{
5276
    GeomCone *tempCurve = new GeomCone();
5277
    tempCurve->mySurface = Handle(Geom_ConicalSurface)::DownCast(mySurface->Copy());
5278
    tempCurve->copyNonTag(this);
5279
    return tempCurve;
5280
}
5281

5282
// Persistence implementer
5283
unsigned int GeomCone::getMemSize () const
5284
{
5285
    return sizeof(Geom_ConicalSurface);
5286
}
5287

5288
void GeomCone::Save(Base::Writer &/*writer*/) const
5289
{
5290
    throw Base::NotImplementedError("GeomCone::Save");
5291
}
5292

5293
void GeomCone::Restore(Base::XMLReader &/*reader*/)
5294
{
5295
    throw Base::NotImplementedError("GeomCone::Restore");
5296
}
5297

5298
PyObject *GeomCone::getPyObject()
5299
{
5300
    return new ConePy(static_cast<GeomCone*>(this->clone()));
5301
}
5302

5303
gp_Vec GeomCone::getDN(double u, double v, int Nu, int Nv) const
5304
{
5305
    // Will be fixed in OCC 7.7
5306
#if OCC_VERSION_HEX >= 0x070700
5307
    return GeomSurface::getDN(u, v, Nu, Nv);
5308
#else
5309
    // Copied from ElSLib::ConeDN() and applied the needed fix
5310
    auto ElSLib__ConeDN = [](const Standard_Real U,
5311
                             const Standard_Real V,
5312
                             const gp_Ax3& Pos,
5313
                             const Standard_Real Radius,
5314
                             const Standard_Real SAngle,
5315
                             const Standard_Integer Nu,
5316
                             const Standard_Integer Nv)
5317
    {
5318
       gp_XYZ Xdir = Pos.XDirection().XYZ();
5319
       gp_XYZ Ydir = Pos.YDirection().XYZ();
5320
       Standard_Real Um = U + Nu * M_PI_2;  // M_PI * 0.5
5321
       Xdir.Multiply(cos(Um));
5322
       Ydir.Multiply(sin(Um));
5323
       Xdir.Add(Ydir);
5324
       if(Nv == 0) {
5325
         Xdir.Multiply(Radius + V * sin(SAngle));
5326
         if(Nu == 0) Xdir.Add(Pos.Location().XYZ());
5327
         return gp_Vec(Xdir);
5328
       }
5329
       else if(Nv == 1) {
5330
         Xdir.Multiply(sin(SAngle));
5331
         if (Nu == 0)
5332
           Xdir.Add(Pos.Direction().XYZ() * cos(SAngle));
5333
         return gp_Vec(Xdir);
5334
       }
5335
       return gp_Vec(0.0,0.0,0.0);
5336
    };
5337

5338
    // Workaround for cones to get the correct derivatives
5339
    // https://forum.freecad.org/viewtopic.php?f=10&t=66677
5340
    Handle(Geom_ConicalSurface) s = Handle(Geom_ConicalSurface)::DownCast(handle());
5341
    Standard_RangeError_Raise_if (Nu + Nv < 1 || Nu < 0 || Nv < 0, " ");
5342
    if (Nv > 1) {
5343
        return {0.0, 0.0, 0.0};
5344
    }
5345
    else {
5346
      return ElSLib__ConeDN(u, v, s->Position(), s->RefRadius(), s->SemiAngle(), Nu, Nv);
5347
    }
5348
#endif
5349
}
5350

5351
double GeomCone::getRadius() const
5352
{
5353
    return mySurface->RefRadius();
5354
}
5355

5356
double GeomCone::getSemiAngle() const
5357
{
5358
    return mySurface->SemiAngle();
5359
}
5360

5361
bool GeomCone::isSame(const Geometry &_other, double tol, double atol) const
5362
{
5363
    if(_other.getTypeId() != getTypeId())
5364
        return false;
5365

5366
    auto &other = static_cast<const GeomCone &>(_other);
5367
    return GeomElementarySurface::isSame(other,tol,atol)
5368
        && fabs(getRadius() - other.getRadius()) <= tol
5369
        && fabs(getSemiAngle() - other.getSemiAngle()) <= atol;
5370
}
5371

5372
// -------------------------------------------------
5373

5374
TYPESYSTEM_SOURCE(Part::GeomToroid,Part::GeomSurface)
5375

5376
GeomToroid::GeomToroid()
5377
{
5378
    Handle(Geom_ToroidalSurface) s = new Geom_ToroidalSurface(gp_Torus());
5379
    this->mySurface = s;
5380
}
5381

5382
GeomToroid::GeomToroid(const Handle(Geom_ToroidalSurface)& t)
5383
{
5384
    setHandle(t);
5385
}
5386

5387
GeomToroid::~GeomToroid() = default;
5388

5389
void GeomToroid::setHandle(const Handle(Geom_ToroidalSurface)& s)
5390
{
5391
    mySurface = Handle(Geom_ToroidalSurface)::DownCast(s->Copy());
5392
}
5393

5394
const Handle(Geom_Geometry)& GeomToroid::handle() const
5395
{
5396
    return mySurface;
5397
}
5398

5399
Geometry *GeomToroid::copy() const
5400
{
5401
    GeomToroid *tempCurve = new GeomToroid();
5402
    tempCurve->mySurface = Handle(Geom_ToroidalSurface)::DownCast(mySurface->Copy());
5403
    tempCurve->copyNonTag(this);
5404
    return tempCurve;
5405
}
5406

5407
// Persistence implementer
5408
unsigned int GeomToroid::getMemSize () const
5409
{
5410
    return sizeof(Geom_ToroidalSurface);
5411
}
5412

5413
void GeomToroid::Save(Base::Writer &/*writer*/) const
5414
{
5415
    throw Base::NotImplementedError("GeomToroid::Save");
5416
}
5417

5418
void GeomToroid::Restore(Base::XMLReader &/*reader*/)
5419
{
5420
    throw Base::NotImplementedError("GeomToroid::Restore");
5421
}
5422

5423
PyObject *GeomToroid::getPyObject()
5424
{
5425
    return new ToroidPy(static_cast<GeomToroid*>(this->clone()));
5426
}
5427

5428
double GeomToroid::getMajorRadius() const
5429
{
5430
    return mySurface->MajorRadius();
5431
}
5432

5433
double GeomToroid::getMinorRadius() const
5434
{
5435
    return mySurface->MinorRadius();
5436
}
5437

5438
bool GeomToroid::isSame(const Geometry &_other, double tol, double atol) const
5439
{
5440
    if(_other.getTypeId() != getTypeId())
5441
        return false;
5442

5443
    (void)atol;
5444
    auto &other = static_cast<const GeomToroid &>(_other);
5445
    return GeomElementarySurface::isSame(other,tol,atol)
5446
        && fabs(getMajorRadius() - other.getMajorRadius()) <= tol
5447
        && fabs(getMinorRadius() - other.getMinorRadius()) <= tol;
5448
}
5449

5450

5451
// -------------------------------------------------
5452

5453
TYPESYSTEM_SOURCE(Part::GeomSphere,Part::GeomSurface)
5454

5455
GeomSphere::GeomSphere()
5456
{
5457
    Handle(Geom_SphericalSurface) s = new Geom_SphericalSurface(gp_Sphere());
5458
    this->mySurface = s;
5459
}
5460

5461
GeomSphere::GeomSphere(const Handle(Geom_SphericalSurface)& s)
5462
{
5463
    setHandle(s);
5464
}
5465

5466
GeomSphere::~GeomSphere() = default;
5467

5468
void GeomSphere::setHandle(const Handle(Geom_SphericalSurface)& s)
5469
{
5470
    mySurface = Handle(Geom_SphericalSurface)::DownCast(s->Copy());
5471
}
5472

5473
const Handle(Geom_Geometry)& GeomSphere::handle() const
5474
{
5475
    return mySurface;
5476
}
5477

5478
Geometry *GeomSphere::copy() const
5479
{
5480
    GeomSphere *tempCurve = new GeomSphere();
5481
    tempCurve->mySurface = Handle(Geom_SphericalSurface)::DownCast(mySurface->Copy());
5482
    tempCurve->copyNonTag(this);
5483
    return tempCurve;
5484
}
5485

5486
// Persistence implementer
5487
unsigned int GeomSphere::getMemSize () const
5488
{
5489
    return sizeof(Geom_SphericalSurface);
5490
}
5491

5492
void GeomSphere::Save(Base::Writer &/*writer*/) const
5493
{
5494
    throw Base::NotImplementedError("GeomSphere::Save");
5495
}
5496

5497
void GeomSphere::Restore(Base::XMLReader &/*reader*/)
5498
{
5499
    throw Base::NotImplementedError("GeomSphere::Restore");
5500
}
5501

5502
PyObject *GeomSphere::getPyObject()
5503
{
5504
    return new SpherePy(static_cast<GeomSphere*>(this->clone()));
5505
}
5506

5507
double GeomSphere::getRadius() const
5508
{
5509
    return mySurface->Radius();
5510
}
5511

5512
bool GeomSphere::isSame(const Geometry &_other, double tol, double atol) const
5513
{
5514
    if(_other.getTypeId() != getTypeId())
5515
        return false;
5516

5517
    (void)atol;
5518
    auto &other = static_cast<const GeomSphere &>(_other);
5519
    return GeomElementarySurface::isSame(other,tol,atol)
5520
        && fabs(getRadius() - other.getRadius()) <= tol;
5521
}
5522

5523

5524
// -------------------------------------------------
5525

5526
TYPESYSTEM_SOURCE(Part::GeomPlane,Part::GeomSurface)
5527

5528
GeomPlane::GeomPlane()
5529
{
5530
    Handle(Geom_Plane) s = new Geom_Plane(gp_Pln());
5531
    this->mySurface = s;
5532
}
5533

5534
GeomPlane::GeomPlane(const gp_Pln &pln)
5535
{
5536
    Handle(Geom_Plane) s = new Geom_Plane(pln);
5537
    this->mySurface = s;
5538
}
5539

5540
GeomPlane::GeomPlane(const Handle(Geom_Plane)& p)
5541
{
5542
    setHandle(p);
5543
}
5544

5545
GeomPlane::~GeomPlane() = default;
5546

5547
void GeomPlane::setHandle(const Handle(Geom_Plane)& s)
5548
{
5549
    mySurface = Handle(Geom_Plane)::DownCast(s->Copy());
5550
}
5551

5552
const Handle(Geom_Geometry)& GeomPlane::handle() const
5553
{
5554
    return mySurface;
5555
}
5556

5557
Geometry *GeomPlane::copy() const
5558
{
5559
    GeomPlane *tempCurve = new GeomPlane();
5560
    tempCurve->mySurface = Handle(Geom_Plane)::DownCast(mySurface->Copy());
5561
    tempCurve->copyNonTag(this);
5562
    return tempCurve;
5563
}
5564

5565
// Persistence implementer
5566
unsigned int GeomPlane::getMemSize () const
5567
{
5568
    return sizeof(Geom_Plane);
5569
}
5570

5571
void GeomPlane::Save(Base::Writer &/*writer*/) const
5572
{
5573
    throw Base::NotImplementedError("GeomPlane::Save");
5574
}
5575

5576
void GeomPlane::Restore(Base::XMLReader &/*reader*/)
5577
{
5578
    throw Base::NotImplementedError("GeomPlane::Restore");
5579
}
5580

5581
PyObject *GeomPlane::getPyObject()
5582
{
5583
    return new PlanePy(static_cast<GeomPlane*>(this->clone()));
5584
}
5585

5586
bool GeomPlane::isSame(const Geometry &_other, double tol, double atol) const
5587
{
5588
    if(_other.getTypeId() != getTypeId()) {
5589
        if (_other.isDerivedFrom(GeomSurface::getClassTypeId())) {
5590
            std::unique_ptr<Geometry> geo(static_cast<const GeomSurface&>(_other).toPlane());
5591
            if (geo)
5592
                return isSame(*geo, tol, atol);
5593
        }
5594
        return false;
5595
    }
5596

5597
    auto &other = static_cast<const GeomPlane &>(_other);
5598
    return GeomElementarySurface::isSame(other,tol,atol);
5599
}
5600

5601
// -------------------------------------------------
5602

5603
TYPESYSTEM_SOURCE(Part::GeomOffsetSurface,Part::GeomSurface)
5604

5605
GeomOffsetSurface::GeomOffsetSurface() = default;
5606

5607
GeomOffsetSurface::GeomOffsetSurface(const Handle(Geom_Surface)& s, double offset)
5608
{
5609
    this->mySurface = new Geom_OffsetSurface(s, offset);
5610
}
5611

5612
GeomOffsetSurface::GeomOffsetSurface(const Handle(Geom_OffsetSurface)& s)
5613
{
5614
    setHandle(s);
5615
}
5616

5617
GeomOffsetSurface::~GeomOffsetSurface() = default;
5618

5619
void GeomOffsetSurface::setHandle(const Handle(Geom_OffsetSurface)& s)
5620
{
5621
    mySurface = Handle(Geom_OffsetSurface)::DownCast(s->Copy());
5622
}
5623

5624
const Handle(Geom_Geometry)& GeomOffsetSurface::handle() const
5625
{
5626
    return mySurface;
5627
}
5628

5629
Geometry *GeomOffsetSurface::copy() const
5630
{
5631
    GeomOffsetSurface *newSurf = new GeomOffsetSurface(mySurface);
5632
    newSurf->copyNonTag(this);
5633
    return newSurf;
5634
}
5635

5636
// Persistence implementer
5637
unsigned int GeomOffsetSurface::getMemSize () const
5638
{
5639
    return sizeof(Geom_OffsetSurface);
5640
}
5641

5642
void GeomOffsetSurface::Save(Base::Writer &/*writer*/) const
5643
{
5644
    throw Base::NotImplementedError("GeomOffsetSurface::Save");
5645
}
5646

5647
void GeomOffsetSurface::Restore(Base::XMLReader &/*reader*/)
5648
{
5649
    throw Base::NotImplementedError("GeomOffsetSurface::Restore");
5650
}
5651

5652
PyObject *GeomOffsetSurface::getPyObject()
5653
{
5654
    return new OffsetSurfacePy(static_cast<GeomOffsetSurface*>(this->clone()));
5655
}
5656

5657
double GeomOffsetSurface::getOffset() const
5658
{
5659
    return mySurface->Offset();
5660
}
5661

5662
bool GeomOffsetSurface::isSame(const Geometry &_other, double tol, double atol) const
5663
{
5664
    if(_other.getTypeId() != getTypeId())
5665
        return false;
5666

5667
    auto &other = static_cast<const GeomOffsetSurface &>(_other);
5668
    if(fabs(getOffset() - other.getOffset()) > tol)
5669
        return false;
5670

5671
    Handle(Geom_Surface) basis = mySurface->BasisSurface();
5672
    Handle(Geom_Surface) basis1 = other.mySurface->BasisSurface();
5673
    if(basis.IsNull() || basis1.IsNull() || basis->DynamicType() != basis1->DynamicType())
5674
        return false;
5675

5676
    std::unique_ptr<Geometry> b(makeFromSurface(basis));
5677
    std::unique_ptr<Geometry> b1(makeFromSurface(basis1));
5678
    return b && b1 && b->isSame(*b1,tol,atol);
5679
}
5680

5681
// -------------------------------------------------
5682

5683
TYPESYSTEM_SOURCE(Part::GeomPlateSurface,Part::GeomSurface)
5684

5685
GeomPlateSurface::GeomPlateSurface() = default;
5686

5687
GeomPlateSurface::GeomPlateSurface(const Handle(Geom_Surface)& s, const Plate_Plate& plate)
5688
{
5689
    this->mySurface = new GeomPlate_Surface(s, plate);
5690
}
5691

5692
GeomPlateSurface::GeomPlateSurface(const GeomPlate_BuildPlateSurface& buildPlate)
5693
{
5694
    Handle(GeomPlate_Surface) s = buildPlate.Surface();
5695
    this->mySurface = Handle(GeomPlate_Surface)::DownCast(s->Copy());
5696
}
5697

5698
GeomPlateSurface::GeomPlateSurface(const Handle(GeomPlate_Surface)& s)
5699
{
5700
    setHandle(s);
5701
}
5702

5703
GeomPlateSurface::~GeomPlateSurface() = default;
5704

5705
void GeomPlateSurface::setHandle(const Handle(GeomPlate_Surface)& s)
5706
{
5707
    mySurface = Handle(GeomPlate_Surface)::DownCast(s->Copy());
5708
}
5709

5710
const Handle(Geom_Geometry)& GeomPlateSurface::handle() const
5711
{
5712
    return mySurface;
5713
}
5714

5715
Geometry *GeomPlateSurface::copy() const
5716
{
5717
    GeomPlateSurface *newSurf = new GeomPlateSurface(mySurface);
5718
    newSurf->copyNonTag(this);
5719
    return newSurf;
5720
}
5721

5722
// Persistence implementer
5723
unsigned int GeomPlateSurface::getMemSize () const
5724
{
5725
    throw Base::NotImplementedError("GeomPlateSurface::getMemSize");
5726
}
5727

5728
void GeomPlateSurface::Save(Base::Writer &/*writer*/) const
5729
{
5730
    throw Base::NotImplementedError("GeomPlateSurface::Save");
5731
}
5732

5733
void GeomPlateSurface::Restore(Base::XMLReader &/*reader*/)
5734
{
5735
    throw Base::NotImplementedError("GeomPlateSurface::Restore");
5736
}
5737

5738
PyObject *GeomPlateSurface::getPyObject()
5739
{
5740
    return new PlateSurfacePy(static_cast<GeomPlateSurface*>(this->clone()));
5741
}
5742

5743
bool GeomPlateSurface::isSame(const Geometry &, double, double) const
5744
{
5745
    // TODO: How to compare this type of surface?
5746
    return false;
5747
}
5748

5749
// -------------------------------------------------
5750

5751
TYPESYSTEM_SOURCE(Part::GeomTrimmedSurface,Part::GeomSurface)
5752

5753
GeomTrimmedSurface::GeomTrimmedSurface() = default;
5754

5755
GeomTrimmedSurface::GeomTrimmedSurface(const Handle(Geom_RectangularTrimmedSurface)& s)
5756
{
5757
   setHandle(s);
5758
}
5759

5760
GeomTrimmedSurface::~GeomTrimmedSurface() = default;
5761

5762
void GeomTrimmedSurface::setHandle(const Handle(Geom_RectangularTrimmedSurface)& s)
5763
{
5764
    mySurface = Handle(Geom_RectangularTrimmedSurface)::DownCast(s->Copy());
5765
}
5766

5767
const Handle(Geom_Geometry)& GeomTrimmedSurface::handle() const
5768
{
5769
    return mySurface;
5770
}
5771

5772
Geometry *GeomTrimmedSurface::copy() const
5773
{
5774
    GeomTrimmedSurface *newSurf = new GeomTrimmedSurface(mySurface);
5775
    newSurf->copyNonTag(this);
5776
    return newSurf;
5777
}
5778

5779
// Persistence implementer
5780
unsigned int GeomTrimmedSurface::getMemSize () const
5781
{
5782
    return sizeof(Geom_RectangularTrimmedSurface);
5783
}
5784

5785
void GeomTrimmedSurface::Save(Base::Writer &/*writer*/) const
5786
{
5787
    throw Base::NotImplementedError("GeomTrimmedSurface::Save");
5788
}
5789

5790
void GeomTrimmedSurface::Restore(Base::XMLReader &/*reader*/)
5791
{
5792
    throw Base::NotImplementedError("GeomTrimmedSurface::Restore");
5793
}
5794

5795
PyObject *GeomTrimmedSurface::getPyObject()
5796
{
5797
    return new RectangularTrimmedSurfacePy(static_cast<GeomTrimmedSurface*>(this->clone()));
5798
}
5799

5800
bool GeomTrimmedSurface::isSame(const Geometry &_other, double tol, double atol) const
5801
{
5802
    if(_other.getTypeId() != getTypeId())
5803
        return false;
5804

5805
    auto &other = static_cast<const GeomTrimmedSurface &>(_other);
5806

5807
    Standard_Real u1[2],u2[2],v1[2],v2[2];
5808
    mySurface->Bounds(u1[0],u2[0],v1[0],v2[0]);
5809
    other.mySurface->Bounds(u1[1],u2[1],v1[1],v2[1]);
5810

5811
    if(fabs(u1[0]-u1[1])>tol || fabs(u2[0]-u2[1])>tol
5812
            || fabs(v1[0]-v1[1])>tol || fabs(v2[0]-v2[1])>tol)
5813
        return false;
5814

5815
    Handle(Geom_Surface) basis = mySurface->BasisSurface();
5816
    Handle(Geom_Surface) basis1 = other.mySurface->BasisSurface();
5817
    if(basis.IsNull() || basis1.IsNull() || basis->DynamicType() != basis1->DynamicType())
5818
        return false;
5819

5820
    std::unique_ptr<Geometry> b(makeFromSurface(basis));
5821
    std::unique_ptr<Geometry> b1(makeFromSurface(basis1));
5822
    return b && b1 && b->isSame(*b1,tol,atol);
5823
}
5824

5825
// -------------------------------------------------
5826
TYPESYSTEM_SOURCE_ABSTRACT(Part::GeomSweptSurface, Part::GeomSurface)
5827

5828
GeomSweptSurface::GeomSweptSurface()
5829
{
5830
}
5831

5832
GeomSweptSurface::~GeomSweptSurface()
5833
{
5834
}
5835

5836
Base::Vector3d GeomSweptSurface::getDir(void) const
5837
{
5838
    Handle(Geom_SweptSurface) surf =  Handle(Geom_SweptSurface)::DownCast(handle());
5839
    const gp_Dir &dir = surf->Direction();
5840
    return Base::Vector3d(dir.X(),dir.Y(),dir.Z());
5841
}
5842

5843
bool GeomSweptSurface::isSame(const Geometry &_other, double tol, double atol) const
5844
{
5845
    if(!_other.isDerivedFrom(GeomSweptSurface::getClassTypeId()))
5846
        return false;
5847

5848
    auto &other = static_cast<const GeomSweptSurface &>(_other);
5849
    if(getDir().GetAngle(other.getDir()) > atol)
5850
        return false;
5851

5852
    Handle(Geom_SweptSurface) surf =  Handle(Geom_SweptSurface)::DownCast(handle());
5853
    Handle(Geom_SweptSurface) surf1 =  Handle(Geom_SweptSurface)::DownCast(other.handle());
5854

5855
    Handle(Geom_Curve) basis = surf->BasisCurve();
5856
    Handle(Geom_Curve) basis1 = surf1->BasisCurve();
5857
    if(basis.IsNull() || basis1.IsNull() || basis->DynamicType() != basis1->DynamicType())
5858
        return false;
5859

5860
    std::unique_ptr<Geometry> b(makeFromCurve(basis));
5861
    std::unique_ptr<Geometry> b1(makeFromCurve(basis1));
5862
    return b && b1 && b->isSame(*b1,tol,atol);
5863
}
5864

5865
// -------------------------------------------------
5866
TYPESYSTEM_SOURCE(Part::GeomSurfaceOfRevolution,Part::GeomSurface)
5867

5868
GeomSurfaceOfRevolution::GeomSurfaceOfRevolution() = default;
5869

5870
GeomSurfaceOfRevolution::GeomSurfaceOfRevolution(const Handle(Geom_Curve)& c, const gp_Ax1& a)
5871
{
5872
    this->mySurface = new Geom_SurfaceOfRevolution(c,a);
5873
}
5874

5875
GeomSurfaceOfRevolution::GeomSurfaceOfRevolution(const Handle(Geom_SurfaceOfRevolution)& s)
5876
{
5877
    setHandle(s);
5878
}
5879

5880
GeomSurfaceOfRevolution::~GeomSurfaceOfRevolution() = default;
5881

5882
void GeomSurfaceOfRevolution::setHandle(const Handle(Geom_SurfaceOfRevolution)& c)
5883
{
5884
    mySurface = Handle(Geom_SurfaceOfRevolution)::DownCast(c->Copy());
5885
}
5886

5887
const Handle(Geom_Geometry)& GeomSurfaceOfRevolution::handle() const
5888
{
5889
    return mySurface;
5890
}
5891

5892
Geometry *GeomSurfaceOfRevolution::copy() const
5893
{
5894
    GeomSurfaceOfRevolution *newSurf = new GeomSurfaceOfRevolution(mySurface);
5895
    newSurf->copyNonTag(this);
5896
    return newSurf;
5897
}
5898

5899
// Persistence implementer
5900
unsigned int GeomSurfaceOfRevolution::getMemSize () const
5901
{
5902
    return sizeof(Geom_SurfaceOfRevolution);
5903
}
5904

5905
void GeomSurfaceOfRevolution::Save(Base::Writer &/*writer*/) const
5906
{
5907
    throw Base::NotImplementedError("GeomSurfaceOfRevolution::Save");
5908
}
5909

5910
void GeomSurfaceOfRevolution::Restore(Base::XMLReader &/*reader*/)
5911
{
5912
    throw Base::NotImplementedError("GeomSurfaceOfRevolution::Restore");
5913
}
5914

5915
PyObject *GeomSurfaceOfRevolution::getPyObject()
5916
{
5917
    return new SurfaceOfRevolutionPy(static_cast<GeomSurfaceOfRevolution*>(this->clone()));
5918
}
5919

5920
// -------------------------------------------------
5921

5922
TYPESYSTEM_SOURCE(Part::GeomSurfaceOfExtrusion,Part::GeomSurface)
5923

5924
GeomSurfaceOfExtrusion::GeomSurfaceOfExtrusion() = default;
5925

5926
GeomSurfaceOfExtrusion::GeomSurfaceOfExtrusion(const Handle(Geom_Curve)& c, const gp_Dir& d)
5927
{
5928
    this->mySurface = new Geom_SurfaceOfLinearExtrusion(c,d);
5929
}
5930

5931
GeomSurfaceOfExtrusion::GeomSurfaceOfExtrusion(const Handle(Geom_SurfaceOfLinearExtrusion)& s)
5932
{
5933
    setHandle(s);
5934
}
5935

5936
GeomSurfaceOfExtrusion::~GeomSurfaceOfExtrusion() = default;
5937

5938
void GeomSurfaceOfExtrusion::setHandle(const Handle(Geom_SurfaceOfLinearExtrusion)& c)
5939
{
5940
    mySurface = Handle(Geom_SurfaceOfLinearExtrusion)::DownCast(c->Copy());
5941
}
5942

5943
const Handle(Geom_Geometry)& GeomSurfaceOfExtrusion::handle() const
5944
{
5945
    return mySurface;
5946
}
5947

5948
Geometry *GeomSurfaceOfExtrusion::copy() const
5949
{
5950
    GeomSurfaceOfExtrusion *newSurf = new GeomSurfaceOfExtrusion(mySurface);
5951
    newSurf->copyNonTag(this);
5952
    return newSurf;
5953
}
5954

5955
// Persistence implementer
5956
unsigned int GeomSurfaceOfExtrusion::getMemSize () const
5957
{
5958
   return sizeof(Geom_SurfaceOfLinearExtrusion);
5959
}
5960

5961
void GeomSurfaceOfExtrusion::Save(Base::Writer &/*writer*/) const
5962
{
5963
    throw Base::NotImplementedError("GeomSurfaceOfExtrusion::Save");
5964
}
5965

5966
void GeomSurfaceOfExtrusion::Restore(Base::XMLReader &/*reader*/)
5967
{
5968
    throw Base::NotImplementedError("GeomSurfaceOfExtrusion::Restore");
5969
}
5970

5971
PyObject *GeomSurfaceOfExtrusion::getPyObject()
5972
{
5973
    return new SurfaceOfExtrusionPy(static_cast<GeomSurfaceOfExtrusion*>(this->clone()));
5974
}
5975

5976

5977
// Helper functions for fillet tools
5978
// -------------------------------------------------
5979
namespace Part {
5980

5981
bool find2DLinesIntersection(const Base::Vector3d &orig1, const Base::Vector3d &dir1,
5982
                             const Base::Vector3d &orig2, const Base::Vector3d &dir2,
5983
                             Base::Vector3d &point)
5984
{
5985
    double det = dir1.x*dir2.y - dir1.y*dir2.x;
5986
    if ((det > 0 ? det : -det) < 1e-10)
5987
        return false;
5988
    double c1 = dir1.y*orig1.x - dir1.x*orig1.y;
5989
    double c2 = dir2.y*orig2.x - dir2.x*orig2.y;
5990
    double x = (dir1.x*c2 - dir2.x*c1)/det;
5991
    double y = (dir1.y*c2 - dir2.y*c1)/det;
5992
    point = Base::Vector3d(x,y,0.f);
5993
    return true;
5994
}
5995

5996
bool find2DLinesIntersection(const GeomLineSegment *lineSeg1, const GeomLineSegment *lineSeg2,
5997
                             Base::Vector3d &point)
5998
{
5999
    Base::Vector3d orig1 = lineSeg1->getStartPoint();
6000
    Base::Vector3d orig2 = lineSeg2->getStartPoint();
6001
    Base::Vector3d dir1 = (lineSeg1->getEndPoint()-lineSeg1->getStartPoint());
6002
    Base::Vector3d dir2 = (lineSeg2->getEndPoint()-lineSeg2->getStartPoint());
6003
    return find2DLinesIntersection(orig1, dir1, orig2, dir2, point);
6004
}
6005

6006
bool findFilletCenter(const GeomLineSegment *lineSeg1, const GeomLineSegment *lineSeg2, double radius,
6007
                      Base::Vector3d &center)
6008
{
6009
    Base::Vector3d midPoint1 = (lineSeg1->getStartPoint()+lineSeg1->getEndPoint())/2;
6010
    Base::Vector3d midPoint2 = (lineSeg2->getStartPoint()+lineSeg2->getEndPoint())/2;
6011
    return findFilletCenter(lineSeg1, lineSeg2, radius, midPoint1, midPoint2, center);
6012
}
6013

6014
bool findFilletCenter(const GeomLineSegment *lineSeg1, const GeomLineSegment *lineSeg2, double radius,
6015
                      const Base::Vector3d &refPnt1, const Base::Vector3d &refPnt2, Base::Vector3d &center)
6016
{
6017
    //Calculate directions and normals for each straight line
6018
    Base::Vector3d l1p1, l1p2, l2p1, l2p2, dir1, dir2, norm1, norm2;
6019
    l1p1 = lineSeg1->getStartPoint();
6020
    l1p2 = lineSeg1->getEndPoint();
6021
    l2p1 = lineSeg2->getStartPoint();
6022
    l2p2 = lineSeg2->getEndPoint();
6023

6024
    dir1 = (l1p1 - l1p2).Normalize();
6025
    dir2 = (l2p1 - l2p2).Normalize();
6026

6027
    norm1 = Base::Vector3d(dir1.y, -dir1.x, 0.).Normalize();
6028
    norm2 = Base::Vector3d(dir2.y, -dir2.x, 0.).Normalize();
6029

6030
    // calculate the intersections between the normals to find inwards direction
6031

6032
    // find intersection of lines
6033
    Base::Vector3d corner;
6034
    if (!find2DLinesIntersection(lineSeg1,lineSeg2,corner))
6035
        return false;
6036

6037
    // Just project the given reference points onto the lines, just in case they are not already lying on
6038
    Base::Vector3d normPnt1, normPnt2;
6039
    normPnt1.ProjectToLine(refPnt1-l1p1, l1p2-l1p1);
6040
    normPnt2.ProjectToLine(refPnt2-l2p1, l2p2-l2p1);
6041
    normPnt1 += refPnt1;
6042
    normPnt2 += refPnt2;
6043

6044
    //Angle bisector
6045
    Base::Vector3d bisectDir = ((normPnt1 - corner).Normalize() + (normPnt2-corner).Normalize()).Normalize();
6046

6047
    //redefine norms pointing towards bisect line
6048
    Base::Vector3d normIntersection1, normIntersection2;
6049
    if (find2DLinesIntersection(normPnt1, norm1, corner, bisectDir, normIntersection1) &&
6050
        find2DLinesIntersection(normPnt2, norm2, corner, bisectDir, normIntersection2)) {
6051
        norm1 = (normIntersection1 - normPnt1).Normalize();
6052
        norm2 = (normIntersection2 - normPnt2).Normalize();
6053
    } else {
6054
        return false;
6055
    }
6056

6057
    // Project lines to find mid point of fillet arc
6058
    Base::Vector3d tmpPoint1 = l1p1 + (norm1 * radius);
6059
    Base::Vector3d tmpPoint2 = l2p1 + (norm2 * radius);
6060

6061
    // found center point
6062
    if (find2DLinesIntersection(tmpPoint1, dir1, tmpPoint2, dir2, center))
6063
        return true;
6064
    else
6065
        return false;
6066
}
6067

6068
// Returns -1 if radius cannot be suggested
6069
double suggestFilletRadius(const GeomLineSegment *lineSeg1, const GeomLineSegment *lineSeg2,
6070
                           const Base::Vector3d &refPnt1, const Base::Vector3d &refPnt2)
6071
{
6072
    Base::Vector3d corner;
6073
    if (!Part::find2DLinesIntersection(lineSeg1, lineSeg2, corner))
6074
        return -1;
6075

6076
    Base::Vector3d dir1 = lineSeg1->getEndPoint() - lineSeg1->getStartPoint();
6077
    Base::Vector3d dir2 = lineSeg2->getEndPoint() - lineSeg2->getStartPoint();
6078

6079
    // Decide the line directions depending on the reference points
6080
    if (dir1*(refPnt1-corner) < 0)
6081
        dir1 *= -1;
6082
    if (dir2*(refPnt2-corner) < 0)
6083
        dir2 *= -1;
6084

6085
    //Angle bisector
6086
    Base::Vector3d dirBisect = (dir1.Normalize() + dir2.Normalize()).Normalize();
6087

6088
    Base::Vector3d projPnt1, projPnt2;
6089
    projPnt1.ProjectToLine(refPnt1-corner, dir1);
6090
    projPnt2.ProjectToLine(refPnt2-corner, dir2);
6091
    projPnt1 += refPnt1;
6092
    projPnt2 += refPnt2;
6093

6094
    Base::Vector3d norm1(dir1.y, -dir1.x, 0.f);
6095
    Base::Vector3d norm2(dir2.y, -dir2.x, 0.f);
6096

6097
    double r1=-1, r2=-1;
6098
    Base::Vector3d center1, center2;
6099
    if (find2DLinesIntersection(projPnt1, norm1, corner, dirBisect, center1))
6100
        r1 = (projPnt1 - center1).Length();
6101
    if (find2DLinesIntersection(projPnt2, norm2, corner, dirBisect, center2))
6102
        r2 = (projPnt1 - center2).Length();
6103

6104
    return r1 < r2 ? r1 : r2;
6105
}
6106

6107
GeomArcOfCircle *createFilletGeometry(const GeomLineSegment *lineSeg1, const GeomLineSegment *lineSeg2,
6108
                                      const Base::Vector3d &center, double radius)
6109
{
6110
    Base::Vector3d corner;
6111
    if (!Part::find2DLinesIntersection(lineSeg1, lineSeg2, corner))
6112
        // Parallel Lines so return null pointer
6113
        return nullptr;
6114

6115
    Base::Vector3d dir1 = lineSeg1->getEndPoint() - lineSeg1->getStartPoint();
6116
    Base::Vector3d dir2 = lineSeg2->getEndPoint() - lineSeg2->getStartPoint();
6117

6118
    Base::Vector3d radDir1, radDir2;
6119
    radDir1.ProjectToLine(center - corner, dir1);
6120
    radDir2.ProjectToLine(center - corner, dir2);
6121

6122
    // Angle Variables
6123
    double startAngle, endAngle, range;
6124

6125
    startAngle = atan2(radDir1.y, radDir1.x);
6126
    range = atan2(-radDir1.y*radDir2.x+radDir1.x*radDir2.y,
6127
                   radDir1.x*radDir2.x+radDir1.y*radDir2.y);
6128
    endAngle = startAngle + range;
6129

6130
    if (endAngle < startAngle)
6131
        std::swap(startAngle, endAngle);
6132

6133
    if (endAngle > 2*M_PI )
6134
        endAngle -= 2*M_PI;
6135

6136
    if (startAngle < 0 )
6137
        endAngle += 2*M_PI;
6138

6139
    // Create Arc Segment
6140
    GeomArcOfCircle *arc = new GeomArcOfCircle();
6141
    arc->setRadius(radius);
6142
    arc->setCenter(center);
6143
    arc->setRange(startAngle, endAngle, /*emulateCCWXY=*/true);
6144

6145
    return arc;
6146
}
6147

6148
std::unique_ptr<GeomSurface> makeFromSurface(const Handle(Geom_Surface)& s, bool silent)
6149
{
6150
    std::unique_ptr<GeomSurface> geoSurf;
6151

6152
    if (s.IsNull()) {
6153
        if (!silent)
6154
            throw Base::ValueError("Null surface");
6155
        return geoSurf;
6156
    }
6157

6158
    if (s->IsKind(STANDARD_TYPE(Geom_ToroidalSurface))) {
6159
        Handle(Geom_ToroidalSurface) hSurf = Handle(Geom_ToroidalSurface)::DownCast(s);
6160
        geoSurf = std::make_unique<GeomToroid>(hSurf);
6161
    }
6162
    else if (s->IsKind(STANDARD_TYPE(Geom_BezierSurface))) {
6163
        Handle(Geom_BezierSurface) hSurf = Handle(Geom_BezierSurface)::DownCast(s);
6164
        geoSurf = std::make_unique<GeomBezierSurface>(hSurf);
6165
    }
6166
    else if (s->IsKind(STANDARD_TYPE(Geom_BSplineSurface))) {
6167
        Handle(Geom_BSplineSurface) hSurf = Handle(Geom_BSplineSurface)::DownCast(s);
6168
        geoSurf = std::make_unique<GeomBSplineSurface>(hSurf);
6169
    }
6170
    else if (s->IsKind(STANDARD_TYPE(Geom_CylindricalSurface))) {
6171
        Handle(Geom_CylindricalSurface) hSurf = Handle(Geom_CylindricalSurface)::DownCast(s);
6172
        geoSurf = std::make_unique<GeomCylinder>(hSurf);
6173
    }
6174
    else if (s->IsKind(STANDARD_TYPE(Geom_ConicalSurface))) {
6175
        Handle(Geom_ConicalSurface) hSurf = Handle(Geom_ConicalSurface)::DownCast(s);
6176
        geoSurf = std::make_unique<GeomCone>(hSurf);
6177
    }
6178
    else if (s->IsKind(STANDARD_TYPE(Geom_SphericalSurface))) {
6179
        Handle(Geom_SphericalSurface) hSurf = Handle(Geom_SphericalSurface)::DownCast(s);
6180
        geoSurf = std::make_unique<GeomSphere>(hSurf);
6181
    }
6182
    else if (s->IsKind(STANDARD_TYPE(Geom_Plane))) {
6183
        Handle(Geom_Plane) hSurf = Handle(Geom_Plane)::DownCast(s);
6184
        geoSurf = std::make_unique<GeomPlane>(hSurf);
6185
    }
6186
    else if (s->IsKind(STANDARD_TYPE(Geom_OffsetSurface))) {
6187
        Handle(Geom_OffsetSurface) hSurf = Handle(Geom_OffsetSurface)::DownCast(s);
6188
        geoSurf = std::make_unique<GeomOffsetSurface>(hSurf);
6189
    }
6190
    else if (s->IsKind(STANDARD_TYPE(GeomPlate_Surface))) {
6191
        Handle(GeomPlate_Surface) hSurf = Handle(GeomPlate_Surface)::DownCast(s);
6192
        geoSurf = std::make_unique<GeomPlateSurface>(hSurf);
6193
    }
6194
    else if (s->IsKind(STANDARD_TYPE(Geom_RectangularTrimmedSurface))) {
6195
        Handle(Geom_RectangularTrimmedSurface) hSurf = Handle(Geom_RectangularTrimmedSurface)::DownCast(s);
6196
        geoSurf = std::make_unique<GeomTrimmedSurface>(hSurf);
6197
    }
6198
    else if (s->IsKind(STANDARD_TYPE(Geom_SurfaceOfRevolution))) {
6199
        Handle(Geom_SurfaceOfRevolution) hSurf = Handle(Geom_SurfaceOfRevolution)::DownCast(s);
6200
        geoSurf = std::make_unique<GeomSurfaceOfRevolution>(hSurf);
6201
    }
6202
    else if (s->IsKind(STANDARD_TYPE(Geom_SurfaceOfLinearExtrusion))) {
6203
        Handle(Geom_SurfaceOfLinearExtrusion) hSurf = Handle(Geom_SurfaceOfLinearExtrusion)::DownCast(s);
6204
        geoSurf = std::make_unique<GeomSurfaceOfExtrusion>(hSurf);
6205
    }
6206
    else {
6207
        std::string err = "Unhandled surface type ";
6208
        err += s->DynamicType()->Name();
6209
        throw Base::TypeError(err);
6210
    }
6211

6212
    return geoSurf;
6213
}
6214

6215
std::unique_ptr<GeomSurface> makeFromSurfaceAdaptor(const BRepAdaptor_Surface& adapt, bool silent)
6216
{
6217
    std::unique_ptr<GeomSurface> geoSurf;
6218

6219
    switch(adapt.GetType())
6220
    {
6221
    case GeomAbs_Plane:
6222
        {
6223
            geoSurf.reset(new GeomPlane());
6224
            Handle(Geom_Plane) this_surf = Handle(Geom_Plane)::DownCast
6225
                (geoSurf->handle());
6226
            this_surf->SetPln(adapt.Plane());
6227
            break;
6228
        }
6229
    case GeomAbs_Cylinder:
6230
        {
6231
            geoSurf.reset(new GeomCylinder());
6232
            Handle(Geom_CylindricalSurface) this_surf = Handle(Geom_CylindricalSurface)::DownCast
6233
                (geoSurf->handle());
6234
            this_surf->SetCylinder(adapt.Cylinder());
6235
            break;
6236
        }
6237
    case GeomAbs_Cone:
6238
        {
6239
            geoSurf.reset(new GeomCone());
6240
            Handle(Geom_ConicalSurface) this_surf = Handle(Geom_ConicalSurface)::DownCast
6241
                (geoSurf->handle());
6242
            this_surf->SetCone(adapt.Cone());
6243
            break;
6244
        }
6245
    case GeomAbs_Sphere:
6246
        {
6247
            geoSurf.reset(new GeomSphere());
6248
            Handle(Geom_SphericalSurface) this_surf = Handle(Geom_SphericalSurface)::DownCast
6249
                (geoSurf->handle());
6250
            this_surf->SetSphere(adapt.Sphere());
6251
            break;
6252
        }
6253
    case GeomAbs_Torus:
6254
        {
6255
            geoSurf.reset(new GeomToroid());
6256
            Handle(Geom_ToroidalSurface) this_surf = Handle(Geom_ToroidalSurface)::DownCast
6257
                (geoSurf->handle());
6258
            this_surf->SetTorus(adapt.Torus());
6259
            break;
6260
        }
6261
    case GeomAbs_BezierSurface:
6262
        {
6263
            geoSurf.reset(new GeomBezierSurface(adapt.Bezier()));
6264
            break;
6265
        }
6266
    case GeomAbs_BSplineSurface:
6267
        {
6268
            geoSurf.reset(new GeomBSplineSurface(adapt.BSpline()));
6269
            break;
6270
        }
6271
    case GeomAbs_SurfaceOfRevolution:
6272
        {
6273
            Handle(Geom_Surface) s = BRep_Tool::Surface(adapt.Face());
6274
            Handle(Geom_SurfaceOfRevolution) rev = Handle(Geom_SurfaceOfRevolution)::DownCast(s);
6275
            if (rev.IsNull()) {
6276
                Handle(Geom_RectangularTrimmedSurface) rect = Handle(Geom_RectangularTrimmedSurface)::DownCast(s);
6277
                rev = Handle(Geom_SurfaceOfRevolution)::DownCast(rect->BasisSurface());
6278
            }
6279
            if (!rev.IsNull())
6280
                geoSurf.reset(new GeomSurfaceOfRevolution(rev));
6281
            break;
6282
        }
6283
    case GeomAbs_SurfaceOfExtrusion:
6284
        {
6285
            Handle(Geom_Surface) s = BRep_Tool::Surface(adapt.Face());
6286
            Handle(Geom_SurfaceOfLinearExtrusion) ext = Handle(Geom_SurfaceOfLinearExtrusion)::DownCast(s);
6287
            if (ext.IsNull()) {
6288
                Handle(Geom_RectangularTrimmedSurface) rect = Handle(Geom_RectangularTrimmedSurface)::DownCast(s);
6289
                ext = Handle(Geom_SurfaceOfLinearExtrusion)::DownCast(rect->BasisSurface());
6290
            }
6291
            if (!ext.IsNull())
6292
                geoSurf.reset(new GeomSurfaceOfExtrusion(ext));
6293
            break;
6294
        }
6295
    case GeomAbs_OffsetSurface:
6296
        {
6297
            Handle(Geom_Surface) s = BRep_Tool::Surface(adapt.Face());
6298
            Handle(Geom_OffsetSurface) off = Handle(Geom_OffsetSurface)::DownCast(s);
6299
            if (off.IsNull()) {
6300
                Handle(Geom_RectangularTrimmedSurface) rect = Handle(Geom_RectangularTrimmedSurface)::DownCast(s);
6301
                off = Handle(Geom_OffsetSurface)::DownCast(rect->BasisSurface());
6302
            }
6303
            if (!off.IsNull())
6304
                geoSurf.reset(new GeomOffsetSurface(off));
6305
            break;
6306
        }
6307
    default:
6308
        break;
6309
    }
6310

6311
    if (!geoSurf && !silent) {
6312
        std::string err = "Cannot convert surface type ";
6313
        Handle(Geom_Surface) s = BRep_Tool::Surface(adapt.Face());
6314
        if (s)
6315
            err += s->DynamicType()->Name();
6316
        else
6317
            err += " unknown";
6318
        throw Base::TypeError(err);
6319
    }
6320

6321
    return geoSurf;
6322
}
6323

6324

6325
std::unique_ptr<GeomCurve> makeFromCurve(const Handle(Geom_Curve)& c, bool silent)
6326
{
6327
    std::unique_ptr<GeomCurve> geoCurve;
6328

6329
    if (c.IsNull()) {
6330
        if (!silent)
6331
            throw Base::ValueError("Null curve");
6332
        return geoCurve;
6333
    }
6334

6335
    if (c->IsKind(STANDARD_TYPE(Geom_Circle))) {
6336
        Handle(Geom_Circle) circ = Handle(Geom_Circle)::DownCast(c);
6337
        geoCurve = std::make_unique<GeomCircle>(circ);
6338
    }
6339
    else if (c->IsKind(STANDARD_TYPE(Geom_Ellipse))) {
6340
        Handle(Geom_Ellipse) ell = Handle(Geom_Ellipse)::DownCast(c);
6341
        geoCurve = std::make_unique<GeomEllipse>(ell);
6342
    }
6343
    else if (c->IsKind(STANDARD_TYPE(Geom_Hyperbola))) {
6344
        Handle(Geom_Hyperbola) hyp = Handle(Geom_Hyperbola)::DownCast(c);
6345
        geoCurve = std::make_unique<GeomHyperbola>(hyp);
6346
    }
6347
    else if (c->IsKind(STANDARD_TYPE(Geom_Line))) {
6348
        Handle(Geom_Line) lin = Handle(Geom_Line)::DownCast(c);
6349
        geoCurve = std::make_unique<GeomLine>(lin);
6350
    }
6351
    else if (c->IsKind(STANDARD_TYPE(Geom_OffsetCurve))) {
6352
        Handle(Geom_OffsetCurve) oc = Handle(Geom_OffsetCurve)::DownCast(c);
6353
        geoCurve = std::make_unique<GeomOffsetCurve>(oc);
6354
    }
6355
    else if (c->IsKind(STANDARD_TYPE(Geom_Parabola))) {
6356
        Handle(Geom_Parabola) par = Handle(Geom_Parabola)::DownCast(c);
6357
        geoCurve = std::make_unique<GeomParabola>(par);
6358
    }
6359
    else if (c->IsKind(STANDARD_TYPE(Geom_TrimmedCurve))) {
6360
        return makeFromTrimmedCurve(c, c->FirstParameter(), c->LastParameter());
6361
    }
6362
    /*else if (c->IsKind(STANDARD_TYPE(Geom_BoundedCurve))) {
6363
        Handle(Geom_BoundedCurve) bc = Handle(Geom_BoundedCurve)::DownCast(c);
6364
        return Py::asObject(new GeometryCurvePy(new GeomBoundedCurve(bc)));
6365
    }*/
6366
    else if (c->IsKind(STANDARD_TYPE(Geom_BezierCurve))) {
6367
        Handle(Geom_BezierCurve) bezier = Handle(Geom_BezierCurve)::DownCast(c);
6368
        geoCurve = std::make_unique<GeomBezierCurve>(bezier);
6369
    }
6370
    else if (c->IsKind(STANDARD_TYPE(Geom_BSplineCurve))) {
6371
        Handle(Geom_BSplineCurve) bspline = Handle(Geom_BSplineCurve)::DownCast(c);
6372
        geoCurve = std::make_unique<GeomBSplineCurve>(bspline);
6373
    }
6374
    else {
6375
        std::string err = "Unhandled curve type ";
6376
        err += c->DynamicType()->Name();
6377
        throw Base::TypeError(err);
6378
    }
6379

6380
    return geoCurve;
6381
}
6382

6383
std::unique_ptr<GeomCurve> makeFromTrimmedCurve(const Handle(Geom_Curve)& c, double f, double l, bool silent)
6384
{
6385
    if (c.IsNull()) {
6386
        if (!silent)
6387
            throw Base::ValueError("Null curve");
6388
        return std::unique_ptr<GeomCurve>();
6389
    }
6390

6391
    if (c->IsKind(STANDARD_TYPE(Geom_Circle))) {
6392
        Handle(Geom_Circle) circ = Handle(Geom_Circle)::DownCast(c);
6393
        std::unique_ptr<GeomCurve> arc(new GeomArcOfCircle());
6394
        Handle(Geom_TrimmedCurve) this_arc = Handle(Geom_TrimmedCurve)::DownCast
6395
            (arc->handle());
6396
        Handle(Geom_Circle) this_circ = Handle(Geom_Circle)::DownCast
6397
            (this_arc->BasisCurve());
6398
        this_circ->SetCirc(circ->Circ());
6399
        this_arc->SetTrim(f, l);
6400
        return arc;
6401
    }
6402
    else if (c->IsKind(STANDARD_TYPE(Geom_Ellipse))) {
6403
        Handle(Geom_Ellipse) ellp = Handle(Geom_Ellipse)::DownCast(c);
6404
        std::unique_ptr<GeomCurve> arc(new GeomArcOfEllipse());
6405
        Handle(Geom_TrimmedCurve) this_arc = Handle(Geom_TrimmedCurve)::DownCast
6406
            (arc->handle());
6407
        Handle(Geom_Ellipse) this_ellp = Handle(Geom_Ellipse)::DownCast
6408
            (this_arc->BasisCurve());
6409
        this_ellp->SetElips(ellp->Elips());
6410
        this_arc->SetTrim(f, l);
6411
        return arc;
6412
    }
6413
    else if (c->IsKind(STANDARD_TYPE(Geom_Hyperbola))) {
6414
        Handle(Geom_Hyperbola) hypr = Handle(Geom_Hyperbola)::DownCast(c);
6415
        std::unique_ptr<GeomCurve> arc(new GeomArcOfHyperbola());
6416
        Handle(Geom_TrimmedCurve) this_arc = Handle(Geom_TrimmedCurve)::DownCast
6417
            (arc->handle());
6418
        Handle(Geom_Hyperbola) this_hypr = Handle(Geom_Hyperbola)::DownCast
6419
            (this_arc->BasisCurve());
6420
        this_hypr->SetHypr(hypr->Hypr());
6421
        this_arc->SetTrim(f, l);
6422
        return arc;
6423
    }
6424
    else if (c->IsKind(STANDARD_TYPE(Geom_Line))) {
6425
        Handle(Geom_Line) line = Handle(Geom_Line)::DownCast(c);
6426
        std::unique_ptr<GeomCurve> segm(new GeomLineSegment());
6427
        Handle(Geom_TrimmedCurve) this_segm = Handle(Geom_TrimmedCurve)::DownCast
6428
            (segm->handle());
6429
        Handle(Geom_Line) this_line = Handle(Geom_Line)::DownCast
6430
            (this_segm->BasisCurve());
6431
        this_line->SetLin(line->Lin());
6432
        this_segm->SetTrim(f, l);
6433
        return segm;
6434
    }
6435
    else if (c->IsKind(STANDARD_TYPE(Geom_Parabola))) {
6436
        Handle(Geom_Parabola) para = Handle(Geom_Parabola)::DownCast(c);
6437
        std::unique_ptr<GeomCurve> arc(new GeomArcOfParabola());
6438
        Handle(Geom_TrimmedCurve) this_arc = Handle(Geom_TrimmedCurve)::DownCast
6439
            (arc->handle());
6440
        Handle(Geom_Parabola) this_para = Handle(Geom_Parabola)::DownCast
6441
            (this_arc->BasisCurve());
6442
        this_para->SetParab(para->Parab());
6443
        this_arc->SetTrim(f, l);
6444
        return arc;
6445
    }
6446
    else if (c->IsKind(STANDARD_TYPE(Geom_BezierCurve))) {
6447
        Handle(Geom_BezierCurve) bezier = Handle(Geom_BezierCurve)::DownCast(c->Copy());
6448
        bezier->Segment(f, l);
6449
        return std::unique_ptr<GeomCurve>(new GeomBezierCurve(bezier));
6450
    }
6451
    else if (c->IsKind(STANDARD_TYPE(Geom_BSplineCurve))) {
6452
        Handle(Geom_BSplineCurve) bspline = Handle(Geom_BSplineCurve)::DownCast(c->Copy());
6453
        bspline->Segment(f, l);
6454
        return std::unique_ptr<GeomCurve>(new GeomBSplineCurve(bspline));
6455
    }
6456
    else if (c->IsKind(STANDARD_TYPE(Geom_OffsetCurve))) {
6457
        Handle(Geom_OffsetCurve) oc = Handle(Geom_OffsetCurve)::DownCast(c);
6458
        double v = oc->Offset();
6459
        gp_Dir dir = oc->Direction();
6460
        std::unique_ptr<GeomCurve> bc(makeFromTrimmedCurve(oc->BasisCurve(), f, l));
6461
        return std::unique_ptr<GeomCurve>(new GeomOffsetCurve(Handle(Geom_Curve)::DownCast(bc->handle()), v, dir));
6462
    }
6463
    else if (c->IsKind(STANDARD_TYPE(Geom_TrimmedCurve))) {
6464
        Handle(Geom_TrimmedCurve) trc = Handle(Geom_TrimmedCurve)::DownCast(c);
6465
        return makeFromTrimmedCurve(trc->BasisCurve(), f, l);
6466
    }
6467
    /*else if (c->IsKind(STANDARD_TYPE(Geom_BoundedCurve))) {
6468
        Handle(Geom_BoundedCurve) bc = Handle(Geom_BoundedCurve)::DownCast(c);
6469
        return Py::asObject(new GeometryCurvePy(new GeomBoundedCurve(bc)));
6470
    }*/
6471
    else if (!silent) {
6472
        std::string err = "Unhandled curve type ";
6473
        err += c->DynamicType()->Name();
6474
        throw Base::TypeError(err);
6475
    }
6476

6477
    return std::unique_ptr<GeomCurve>();
6478
}
6479

6480
std::unique_ptr<GeomCurve> makeFromCurveAdaptor(const Adaptor3d_Curve& adapt, bool silent)
6481
{
6482
    std::unique_ptr<GeomCurve> geoCurve;
6483
    switch (adapt.GetType())
6484
    {
6485
    case GeomAbs_Line:
6486
        {
6487
            geoCurve = std::make_unique<GeomLine>();
6488
            Handle(Geom_Line) this_curv = Handle(Geom_Line)::DownCast
6489
                (geoCurve->handle());
6490
            this_curv->SetLin(adapt.Line());
6491
            break;
6492
        }
6493
    case GeomAbs_Circle:
6494
        {
6495
            geoCurve = std::make_unique<GeomCircle>();
6496
            Handle(Geom_Circle) this_curv = Handle(Geom_Circle)::DownCast
6497
                (geoCurve->handle());
6498
            this_curv->SetCirc(adapt.Circle());
6499
            break;
6500
        }
6501
    case GeomAbs_Ellipse:
6502
        {
6503
            geoCurve = std::make_unique<GeomEllipse>();
6504
            Handle(Geom_Ellipse) this_curv = Handle(Geom_Ellipse)::DownCast
6505
                (geoCurve->handle());
6506
            this_curv->SetElips(adapt.Ellipse());
6507
            break;
6508
        }
6509
    case GeomAbs_Hyperbola:
6510
        {
6511
            geoCurve = std::make_unique<GeomHyperbola>();
6512
            Handle(Geom_Hyperbola) this_curv = Handle(Geom_Hyperbola)::DownCast
6513
                (geoCurve->handle());
6514
            this_curv->SetHypr(adapt.Hyperbola());
6515
            break;
6516
        }
6517
    case GeomAbs_Parabola:
6518
        {
6519
            geoCurve = std::make_unique<GeomParabola>();
6520
            Handle(Geom_Parabola) this_curv = Handle(Geom_Parabola)::DownCast
6521
                (geoCurve->handle());
6522
            this_curv->SetParab(adapt.Parabola());
6523
            break;
6524
        }
6525
    case GeomAbs_BezierCurve:
6526
        {
6527
            geoCurve = std::make_unique<GeomBezierCurve>(adapt.Bezier());
6528
            break;
6529
        }
6530
    case GeomAbs_BSplineCurve:
6531
        {
6532
            geoCurve = std::make_unique<GeomBSplineCurve>(adapt.BSpline());
6533
            break;
6534
        }
6535
    case GeomAbs_OffsetCurve:
6536
        {
6537
            geoCurve = std::make_unique<GeomOffsetCurve>(adapt.OffsetCurve());
6538
            break;
6539
        }
6540
    case GeomAbs_OtherCurve:
6541
    default:
6542
        break;
6543
    }
6544

6545
    if (!geoCurve) {
6546
        if (!silent)
6547
            throw Base::TypeError("Unhandled curve type");
6548
        return geoCurve;
6549
    }
6550

6551
    // Check if the curve must be trimmed
6552
    Handle(Geom_Curve) curv3d = Handle(Geom_Curve)::DownCast
6553
        (geoCurve->handle());
6554
    double u = curv3d->FirstParameter();
6555
    double v = curv3d->LastParameter();
6556
    if (u != adapt.FirstParameter() || v != adapt.LastParameter()) {
6557
        geoCurve = makeFromTrimmedCurve(curv3d, adapt.FirstParameter(), adapt.LastParameter());
6558
    }
6559

6560
    return geoCurve;
6561
}
6562

6563
} // namespace Part
6564

6565

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.