diff --git a/src/Mod/Part/App/Geometry.cpp b/src/Mod/Part/App/Geometry.cpp index fe7ac8e971..8759347ccd 100644 --- a/src/Mod/Part/App/Geometry.cpp +++ b/src/Mod/Part/App/Geometry.cpp @@ -23,6 +23,8 @@ #include "PreCompiled.h" #ifndef _PreComp_ # include +# include +# include # include # include # include @@ -68,7 +70,9 @@ # include # include # include +# include # include +# include # include # include # include @@ -87,15 +91,13 @@ # include # include # include -# include -# include # include # include # include -# include # include # if OCC_VERSION_HEX < 0x070600 +# include # include # endif @@ -107,6 +109,9 @@ #include #include #include +#include +#include +#include #include "Geometry.h" #include "ArcOfCirclePy.h" @@ -138,6 +143,7 @@ #include "SurfaceOfRevolutionPy.h" #include "Tools.h" #include "ToroidPy.h" +#include "TopoShape.h" #if OCC_VERSION_HEX >= 0x070600 @@ -186,21 +192,88 @@ const char* gce_ErrorStatusText(gce_ErrorType et) // --------------------------------------------------------------- -TYPESYSTEM_SOURCE_ABSTRACT(Part::Geometry,Base::Persistence) +TYPESYSTEM_SOURCE_ABSTRACT(Part::Geometry,Base::Persistence) // NOLINT -Geometry::Geometry() +Geometry::Geometry() // NOLINT { createNewTag(); } Geometry::~Geometry() = default; +bool Geometry::hasSameExtensions(const Geometry& other) const +{ + // We skip non persistent extension while doing comparison. Not sure if + // this will cause any problem. + size_t index = 0; + for (const auto& ext : extensions) { + if (auto persistExt = + Base::freecad_dynamic_cast(ext.get())) { + for (; index < other.extensions.size(); ++index) { + if (auto extOther = Base::freecad_dynamic_cast( + other.extensions[index].get())) { + if (!persistExt->isSame(*extOther)) { + return false; + } + break; + } + } + if (index >= other.extensions.size()) { + return false; + } + ++index; + } + } + for (; index < other.extensions.size(); ++index) { + if (Base::freecad_dynamic_cast( + other.extensions[index].get())) { + return false; + } + } + return true; +} + // Persistence implementer unsigned int Geometry::getMemSize () const { return 1; } +std::unique_ptr Geometry::fromShape(const TopoDS_Shape &shape, bool silent) +{ + std::unique_ptr geom; + + if (shape.IsNull()) { + if(!silent) + throw Base::ValueError("Null shape"); + return geom; + } + + switch (shape.ShapeType()) { + case TopAbs_VERTEX: { + gp_Pnt p = BRep_Tool::Pnt(TopoDS::Vertex(shape)); + geom = std::make_unique(Base::Vector3d(p.X(),p.Y(),p.Z())); + break; + } + case TopAbs_EDGE: { + const TopoDS_Edge& e = TopoDS::Edge(shape); + BRepAdaptor_Curve adapt(e); + geom = makeFromCurveAdaptor(adapt, silent); + break; + } + case TopAbs_FACE: { + const TopoDS_Face& f = TopoDS::Face(shape); + BRepAdaptor_Surface adapt(f); + geom = makeFromSurfaceAdaptor(adapt, silent); + break; + } + default: + if(!silent) + FC_THROWM(Base::TypeError, "Unsupported shape type " << TopoShape::shapeName(shape.ShapeType())); + } + return geom; +} + void Geometry::Save(Base::Writer &writer) const { // We always store an extension array even if empty, so that restoring is consistent. @@ -235,15 +308,15 @@ void Geometry::Restore(Base::XMLReader &reader) long count = reader.getAttributeAsInteger("count"); - for (long i = 0; i < count; i++) { + for (long index = 0; index < count; index++) { reader.readElement("GeoExtension"); const char* TypeName = reader.getAttribute("type"); Base::Type type = Base::Type::fromName(TypeName); - GeometryPersistenceExtension *newE = static_cast(type.createInstance()); - if (newE) { - newE->Restore(reader); + auto *newExtension = static_cast(type.createInstance()); + if (newExtension) { + newExtension->Restore(reader); - extensions.push_back(std::shared_ptr(newE)); + extensions.push_back(std::shared_ptr(newExtension)); } else { Base::Console().Warning("Cannot restore geometry extension of type: %s\n", TypeName); @@ -254,7 +327,7 @@ void Geometry::Restore(Base::XMLReader &reader) } else if(strcmp(reader.localName(),"Construction") == 0) { // legacy - bool construction = (int)reader.getAttributeAsInteger("value")==0?false:true; + bool construction = (int)reader.getAttributeAsInteger("value") != 0; // prepare migration if(!this->hasExtension(GeometryMigrationExtension::getClassTypeId())) @@ -278,30 +351,29 @@ std::vector> Geometry::getExtensions() co { std::vector> wp; - for(auto & ext:extensions) + for (auto& ext : extensions) { wp.push_back(ext); + } return wp; } bool Geometry::hasExtension(const Base::Type & type) const { - for(const auto& ext : extensions) { - if(ext->getTypeId() == type) - return true; - } - - return false; + return std::any_of(extensions.begin(), + extensions.end(), + [type](auto geoExt) { + return geoExt->getTypeId() == type; + }); } bool Geometry::hasExtension(const std::string & name) const { - for(const auto& ext : extensions) { - if(ext->getName() == name) - return true; - } - - return false; + return std::any_of(extensions.begin(), + extensions.end(), + [name](auto geoExt) { + return geoExt->getName() == name; + }); } std::weak_ptr Geometry::getExtension(const Base::Type & type) @@ -402,9 +474,9 @@ void Geometry::assignTag(const Part::Geometry * geo) throw Base::TypeError("Geometry tag can not be assigned as geometry types do not match."); } -void Geometry::copyNonTag(const Part::Geometry * src) +void Geometry::copyNonTag(const Part::Geometry* src) { - for(auto & ext: src->extensions) { + for (auto& ext : src->extensions) { this->extensions.push_back(ext->copy()); extensions.back()->notifyAttachment(this); } @@ -420,19 +492,19 @@ Geometry *Geometry::clone() const return cpy; } -void Geometry::mirror(const Base::Vector3d& point) +void Geometry::mirror(const Base::Vector3d& point) const { gp_Pnt pnt(point.x, point.y, point.z); handle()->Mirror(pnt); } -void Geometry::mirror(const Base::Vector3d& point, const Base::Vector3d& dir) +void Geometry::mirror(const Base::Vector3d& point, const Base::Vector3d& dir) const { gp_Ax1 ax1(gp_Pnt(point.x,point.y,point.z), gp_Dir(dir.x,dir.y,dir.z)); handle()->Mirror(ax1); } -void Geometry::rotate(const Base::Placement& plm) +void Geometry::rotate(const Base::Placement& plm) const { Base::Rotation rot(plm.getRotation()); Base::Vector3d pnt, dir; @@ -446,13 +518,13 @@ void Geometry::rotate(const Base::Placement& plm) handle()->Rotate(ax1, angle); } -void Geometry::scale(const Base::Vector3d& vec, double scale) +void Geometry::scale(const Base::Vector3d& vec, double scale) const { gp_Pnt pnt(vec.x, vec.y, vec.z); handle()->Scale(pnt, scale); } -void Geometry::transform(const Base::Matrix4D& mat) +void Geometry::transform(const Base::Matrix4D& mat) const { gp_Trsf trf; trf.SetValues(mat[0][0],mat[0][1],mat[0][2],mat[0][3], @@ -461,7 +533,7 @@ void Geometry::transform(const Base::Matrix4D& mat) handle()->Transform(trf); } -void Geometry::translate(const Base::Vector3d& vec) +void Geometry::translate(const Base::Vector3d& vec) const { gp_Vec trl(vec.x, vec.y, vec.z); handle()->Translate(trl); @@ -502,7 +574,7 @@ void GeomPoint::setHandle(const Handle(Geom_CartesianPoint)& p) Geometry *GeomPoint::copy() const { - GeomPoint *newPoint = new GeomPoint(myPoint); + auto newPoint = new GeomPoint(myPoint); newPoint->copyNonTag(this); return newPoint; } @@ -565,6 +637,12 @@ PyObject *GeomPoint::getPyObject() return new PointPy(new GeomPoint(getPoint())); } +bool GeomPoint::isSame(const Geometry &other, double tol, double) const +{ + return other.getTypeId() == getTypeId() + && Base::DistanceP2(dynamic_cast(other).getPoint(),getPoint()) <= tol*tol; +} + // ------------------------------------------------- TYPESYSTEM_SOURCE_ABSTRACT(Part::GeomCurve,Part::Geometry) @@ -580,6 +658,117 @@ TopoDS_Shape GeomCurve::toShape() const return mkBuilder.Shape(); } +// Copied from OCC BRepBndLib_1.cxx +//======================================================================= +// Function : IsLinear +// purpose : Returns TRUE if theC is line-like. +//======================================================================= +static Standard_Boolean IsLinear(const Adaptor3d_Curve& theC) +{ + const GeomAbs_CurveType aCT = theC.GetType(); + if(aCT == GeomAbs_OffsetCurve) + { + return IsLinear(GeomAdaptor_Curve(theC.OffsetCurve()->BasisCurve())); + } + + if((aCT == GeomAbs_BSplineCurve) || (aCT == GeomAbs_BezierCurve)) + { + // Indeed, curves with C0-continuity and degree==1, may be + // represented with set of points. It will be possible made + // in the future. + + return ((theC.Degree() == 1) && + (theC.Continuity() != GeomAbs_C0)); + } + + if(aCT == GeomAbs_Line) + { + return Standard_True; + } + + return Standard_False; +} + +bool GeomCurve::isLinear(Base::Vector3d *dir, Base::Vector3d *base) const +{ + Handle(Geom_Curve) curve = Handle(Geom_Curve)::DownCast(handle()); + return isLinear(curve, dir, base); +} + +bool GeomCurve::isLinear(const Handle(Geom_Curve) &curve, Base::Vector3d *dir, Base::Vector3d *base) +{ + GeomAdaptor_Curve adaptor(curve); + if (!IsLinear(adaptor)) + return false; + + if (dir || base) { + if (adaptor.GetType() == GeomAbs_Line) { + // Special treatment of Geom_Line because it is infinite + Handle(Geom_Line) curv = Handle(Geom_Line)::DownCast(curve); + if (base) { + gp_Pnt Pos = curv->Lin().Location(); + *base = Base::Vector3d(Pos.X(), Pos.Y(), Pos.Z()); + } + if (dir) { + gp_Dir Dir = curv->Lin().Direction(); + *dir = Base::Vector3d(Dir.X(), Dir.Y(), Dir.Z()); + } + return true; + } + try { + GeomLProp_CLProps prop1(curve,curve->FirstParameter(),0,Precision::Confusion()); + GeomLProp_CLProps prop2(curve,curve->LastParameter(),0,Precision::Confusion()); + const gp_Pnt &p1 = prop1.Value(); + const gp_Pnt &p2 = prop2.Value(); + if (base) + *base = Base::Vector3d(p1.X(), p1.Y(), p1.Z()); + if (dir) + *dir = Base::Vector3d(p2.X() - p1.X(), p2.Y() - p1.Y(), p2.Z() - p1.Z()); + } + catch (Standard_Failure& e) { + THROWM(Base::CADKernelError,e.GetMessageString()) + } + } + return true; +} + +GeomLine* GeomCurve::toLine(KeepTag clone) const +{ + if (!isLinear()) + return nullptr; + + auto p1 = pointAtParameter(getFirstParameter()); + auto p2 = pointAtParameter(getLastParameter()); + auto res = new GeomLine(p1, p2-p1); + res->copyNonTag(this); + if (clone == CopyTag) { + res->tag = this->tag; + } + return res; +} + +GeomLineSegment* GeomCurve::toLineSegment(KeepTag clone) const +{ + if (!isLinear()) + return nullptr; + + Base::Vector3d start, end; + if (isDerivedFrom(GeomBoundedCurve::getClassTypeId())) { + start = dynamic_cast(this)->getStartPoint(); + end = dynamic_cast(this)->getEndPoint(); + } else { + start = pointAtParameter(getFirstParameter()); + end = pointAtParameter(getLastParameter()); + } + auto res = new GeomLineSegment; + res->setPoints(start, end); + res->copyNonTag(this); + if (clone == CopyTag) { + res->tag = this->tag; + } + return res; +} + GeomBSplineCurve* GeomCurve::toBSpline(double first, double last) const { ShapeConstruct_Curve scc; @@ -597,8 +786,8 @@ GeomBSplineCurve* GeomCurve::toNurbs(double first, double last) const bool GeomCurve::tangent(double u, gp_Dir& dir) const { - Handle(Geom_Curve) c = Handle(Geom_Curve)::DownCast(handle()); - GeomLProp_CLProps prop(c,u,1,Precision::Confusion()); + Handle(Geom_Curve) curve = Handle(Geom_Curve)::DownCast(handle()); + GeomLProp_CLProps prop(curve, u,1,Precision::Confusion()); if (prop.IsTangentDefined()) { prop.Tangent(dir); return true; @@ -622,17 +811,17 @@ bool GeomCurve::tangent(double u, Base::Vector3d& dir) const Base::Vector3d GeomCurve::value(double u) const { - Handle(Geom_Curve) c = Handle(Geom_Curve)::DownCast(handle()); + Handle(Geom_Curve) curve = Handle(Geom_Curve)::DownCast(handle()); - const gp_Pnt &point = c->Value(u); + const gp_Pnt &point = curve->Value(u); return Base::Vector3d(point.X(),point.Y(),point.Z()); } Base::Vector3d GeomCurve::pointAtParameter(double u) const { - Handle(Geom_Curve) c = Handle(Geom_Curve)::DownCast(handle()); - GeomLProp_CLProps prop(c,u,0,Precision::Confusion()); + Handle(Geom_Curve) curve = Handle(Geom_Curve)::DownCast(handle()); + GeomLProp_CLProps prop(curve, u,0,Precision::Confusion()); const gp_Pnt &point=prop.Value(); @@ -641,8 +830,8 @@ Base::Vector3d GeomCurve::pointAtParameter(double u) const Base::Vector3d GeomCurve::firstDerivativeAtParameter(double u) const { - Handle(Geom_Curve) c = Handle(Geom_Curve)::DownCast(handle()); - GeomLProp_CLProps prop(c,u,1,Precision::Confusion()); + Handle(Geom_Curve) curve = Handle(Geom_Curve)::DownCast(handle()); + GeomLProp_CLProps prop(curve, u,1,Precision::Confusion()); const gp_Vec &vec=prop.D1(); @@ -651,8 +840,8 @@ Base::Vector3d GeomCurve::firstDerivativeAtParameter(double u) const Base::Vector3d GeomCurve::secondDerivativeAtParameter(double u) const { - Handle(Geom_Curve) c = Handle(Geom_Curve)::DownCast(handle()); - GeomLProp_CLProps prop(c,u,2,Precision::Confusion()); + Handle(Geom_Curve) curve = Handle(Geom_Curve)::DownCast(handle()); + GeomLProp_CLProps prop(curve, u,2,Precision::Confusion()); const gp_Vec &vec=prop.D2(); @@ -661,11 +850,11 @@ Base::Vector3d GeomCurve::secondDerivativeAtParameter(double u) const bool GeomCurve::normalAt(double u, Base::Vector3d& dir) const { - Handle(Geom_Curve) c = Handle(Geom_Curve)::DownCast(handle()); + Handle(Geom_Curve) curve = Handle(Geom_Curve)::DownCast(handle()); try { - if (!c.IsNull()) { - GeomLProp_CLProps prop(c,u,2,Precision::Confusion()); + if (!curve.IsNull()) { + GeomLProp_CLProps prop(curve, u,2,Precision::Confusion()); gp_Dir gdir; prop.Normal(gdir); dir = Base::Vector3d(gdir.X(), gdir.Y(), gdir.Z()); @@ -677,8 +866,8 @@ bool GeomCurve::normalAt(double u, Base::Vector3d& dir) const dir.Set(0,0,0); return false; } - catch (Standard_Failure& e) { - THROWM(Base::CADKernelError,e.GetMessageString()) + catch (Standard_Failure& exc) { + THROWM(Base::CADKernelError, exc.GetMessageString()) } return false; @@ -692,12 +881,12 @@ bool GeomCurve::normalAt(const Base::Vector3d & curvepoint, Base::Vector3d & dir return normalAt(u, dir); } -bool GeomCurve::intersect( const GeomCurve *c, +bool GeomCurve::intersect( const GeomCurve *curve, std::vector>& points, double tol) const { Handle(Geom_Curve) curve1 = Handle(Geom_Curve)::DownCast(handle()); - Handle(Geom_Curve) curve2 = Handle(Geom_Curve)::DownCast(c->handle()); + Handle(Geom_Curve) curve2 = Handle(Geom_Curve)::DownCast(curve->handle()); if(!curve1.IsNull() && !curve2.IsNull()) { return intersect(curve1,curve2,points, tol); @@ -707,7 +896,7 @@ bool GeomCurve::intersect( const GeomCurve *c, } -bool GeomCurve::intersect(const Handle(Geom_Curve) curve1, const Handle(Geom_Curve) curve2, +bool GeomCurve::intersect(const Handle(Geom_Curve)& curve1, const Handle(Geom_Curve)& curve2, std::vector>& points, double tol) { @@ -744,55 +933,55 @@ bool GeomCurve::intersect(const Handle(Geom_Curve) curve1, const Handle(Geom_Cur return false; } - for (int i = 1; i <= intersector.NbExtrema(); i++) { - if (intersector.Distance(i) > tol) + for (int index = 1; index <= intersector.NbExtrema(); index++) { + if (intersector.Distance(index) > tol) continue; gp_Pnt p1, p2; - intersector.Points(i, p1, p2); + intersector.Points(index, p1, p2); points.emplace_back(Base::Vector3d(p1.X(),p1.Y(),p1.Z()),Base::Vector3d(p2.X(),p2.Y(),p2.Z())); } } - catch (Standard_Failure& e) { + catch (Standard_Failure& exc) { // Yes Extrema finding failed, but if we got an intersection then go on with it if(!points.empty()) - return true; + return !points.empty(); else - THROWM(Base::CADKernelError,e.GetMessageString()) + THROWM(Base::CADKernelError,exc.GetMessageString()) } - return !points.empty()?true:false; + return !points.empty(); } bool GeomCurve::closestParameter(const Base::Vector3d& point, double &u) const { - Handle(Geom_Curve) c = Handle(Geom_Curve)::DownCast(handle()); + Handle(Geom_Curve) curve = Handle(Geom_Curve)::DownCast(handle()); try { - if (!c.IsNull()) { + if (!curve.IsNull()) { gp_Pnt pnt(point.x,point.y,point.z); - GeomAPI_ProjectPointOnCurve ppc(pnt, c); + GeomAPI_ProjectPointOnCurve ppc(pnt, curve); u = ppc.LowerDistanceParameter(); return true; } } - catch (StdFail_NotDone& e) { - if (c->IsKind(STANDARD_TYPE(Geom_BoundedCurve))){ - Base::Vector3d firstpoint = this->pointAtParameter(c->FirstParameter()); - Base::Vector3d lastpoint = this->pointAtParameter(c->LastParameter()); + catch (StdFail_NotDone& exc) { + if (curve->IsKind(STANDARD_TYPE(Geom_BoundedCurve))){ + Base::Vector3d firstpoint = this->pointAtParameter(curve->FirstParameter()); + Base::Vector3d lastpoint = this->pointAtParameter(curve->LastParameter()); if((firstpoint-point).Length() < (lastpoint-point).Length()) - u = c->FirstParameter(); + u = curve->FirstParameter(); else - u = c->LastParameter(); + u = curve->LastParameter(); } else - THROWM(Base::CADKernelError,e.GetMessageString()) + THROWM(Base::CADKernelError, exc.GetMessageString()) return true; } - catch (Standard_Failure& e) { - THROWM(Base::CADKernelError,e.GetMessageString()) + catch (Standard_Failure& exc) { + THROWM(Base::CADKernelError, exc.GetMessageString()) } return false; @@ -800,9 +989,9 @@ bool GeomCurve::closestParameter(const Base::Vector3d& point, double &u) const bool GeomCurve::closestParameterToBasisCurve(const Base::Vector3d& point, double &u) const { - Handle(Geom_Curve) c = Handle(Geom_Curve)::DownCast(handle()); + Handle(Geom_Curve) curve = Handle(Geom_Curve)::DownCast(handle()); - if (c->IsKind(STANDARD_TYPE(Geom_TrimmedCurve))){ + if (curve->IsKind(STANDARD_TYPE(Geom_TrimmedCurve))){ Handle(Geom_TrimmedCurve) tc = Handle(Geom_TrimmedCurve)::DownCast(handle()); Handle(Geom_Curve) bc = tc->BasisCurve(); try { @@ -813,8 +1002,8 @@ bool GeomCurve::closestParameterToBasisCurve(const Base::Vector3d& point, double return true; } } - catch (Standard_Failure& e) { - THROWM(Base::CADKernelError,e.GetMessageString()) + catch (Standard_Failure& exc) { + THROWM(Base::CADKernelError, exc.GetMessageString()) } return false; @@ -826,71 +1015,71 @@ bool GeomCurve::closestParameterToBasisCurve(const Base::Vector3d& point, double double GeomCurve::getFirstParameter() const { - Handle(Geom_Curve) c = Handle(Geom_Curve)::DownCast(handle()); + Handle(Geom_Curve) curve = Handle(Geom_Curve)::DownCast(handle()); try { // pending check for RealFirst RealLast in case of infinite curve - return c->FirstParameter(); + return curve->FirstParameter(); } - catch (Standard_Failure& e) { + catch (Standard_Failure& exc) { - THROWM(Base::CADKernelError,e.GetMessageString()) + THROWM(Base::CADKernelError, exc.GetMessageString()) } } double GeomCurve::getLastParameter() const { - Handle(Geom_Curve) c = Handle(Geom_Curve)::DownCast(handle()); + Handle(Geom_Curve) curve = Handle(Geom_Curve)::DownCast(handle()); try { // pending check for RealFirst RealLast in case of infinite curve - return c->LastParameter(); + return curve->LastParameter(); } - catch (Standard_Failure& e) { + catch (Standard_Failure& exc) { - THROWM(Base::CADKernelError,e.GetMessageString()) + THROWM(Base::CADKernelError, exc.GetMessageString()) } } double GeomCurve::curvatureAt(double u) const { - Handle(Geom_Curve) c = Handle(Geom_Curve)::DownCast(handle()); + Handle(Geom_Curve) curve = Handle(Geom_Curve)::DownCast(handle()); try { - GeomLProp_CLProps prop(c,u,2,Precision::Confusion()); + GeomLProp_CLProps prop(curve, u,2,Precision::Confusion()); return prop.Curvature(); } - catch (Standard_Failure& e) { + catch (Standard_Failure& exc) { - THROWM(Base::CADKernelError,e.GetMessageString()) + THROWM(Base::CADKernelError, exc.GetMessageString()) } } double GeomCurve::length(double u, double v) const { - Handle(Geom_Curve) c = Handle(Geom_Curve)::DownCast(handle()); + Handle(Geom_Curve) curve = Handle(Geom_Curve)::DownCast(handle()); try { - GeomAdaptor_Curve adaptor(c); + GeomAdaptor_Curve adaptor(curve); return GCPnts_AbscissaPoint::Length(adaptor,u,v,Precision::Confusion()); } - catch (Standard_Failure& e) { + catch (Standard_Failure& exc) { - THROWM(Base::CADKernelError,e.GetMessageString()) + THROWM(Base::CADKernelError, exc.GetMessageString()) } } void GeomCurve::reverse() { - Handle(Geom_Curve) c = Handle(Geom_Curve)::DownCast(handle()); + Handle(Geom_Curve) curve = Handle(Geom_Curve)::DownCast(handle()); try { - c->Reverse(); + curve->Reverse(); } - catch (Standard_Failure& e) { + catch (Standard_Failure& exc) { - THROWM(Base::CADKernelError,e.GetMessageString()) + THROWM(Base::CADKernelError, exc.GetMessageString()) } } @@ -922,20 +1111,20 @@ Base::Vector3d GeomBoundedCurve::getEndPoint() const // ------------------------------------------------- -TYPESYSTEM_SOURCE(Part::GeomBezierCurve,Part::GeomBoundedCurve) +TYPESYSTEM_SOURCE(Part::GeomBezierCurve, Part::GeomBoundedCurve) GeomBezierCurve::GeomBezierCurve() { TColgp_Array1OfPnt poles(1,2); poles(1) = gp_Pnt(0.0,0.0,0.0); poles(2) = gp_Pnt(0.0,0.0,1.0); - Handle(Geom_BezierCurve) b = new Geom_BezierCurve(poles); - this->myCurve = b; + Handle(Geom_BezierCurve) bezier = new Geom_BezierCurve(poles); + this->myCurve = bezier; } -GeomBezierCurve::GeomBezierCurve(const Handle(Geom_BezierCurve)& b) +GeomBezierCurve::GeomBezierCurve(const Handle(Geom_BezierCurve)& bezier) { - setHandle(b); + setHandle(bezier); } GeomBezierCurve::GeomBezierCurve( const std::vector& poles, const std::vector& weights) @@ -943,20 +1132,20 @@ GeomBezierCurve::GeomBezierCurve( const std::vector& poles, cons if (poles.size() != weights.size()) throw Base::ValueError("poles and weights mismatch"); - TColgp_Array1OfPnt p(1,poles.size()); - TColStd_Array1OfReal w(1,poles.size()); - for (std::size_t i = 1; i <= poles.size(); i++) { - p.SetValue(i, gp_Pnt(poles[i-1].x,poles[i-1].y,poles[i-1].z)); - w.SetValue(i, weights[i-1]); + TColgp_Array1OfPnt poleArray(1,poles.size()); + TColStd_Array1OfReal weightArray(1,poles.size()); + for (std::size_t index = 1; index <= poles.size(); index++) { + poleArray.SetValue(index, gp_Pnt(poles[index-1].x,poles[index-1].y,poles[index-1].z)); + weightArray.SetValue(index, weights[index-1]); } - this->myCurve = new Geom_BezierCurve (p, w); + this->myCurve = new Geom_BezierCurve (poleArray, weightArray); } GeomBezierCurve::~GeomBezierCurve() = default; -void GeomBezierCurve::setHandle(const Handle(Geom_BezierCurve)& c) +void GeomBezierCurve::setHandle(const Handle(Geom_BezierCurve)& curve) { - myCurve = Handle(Geom_BezierCurve)::DownCast(c->Copy()); + myCurve = Handle(Geom_BezierCurve)::DownCast(curve->Copy()); } const Handle(Geom_Geometry)& GeomBezierCurve::handle() const @@ -966,7 +1155,7 @@ const Handle(Geom_Geometry)& GeomBezierCurve::handle() const Geometry *GeomBezierCurve::copy() const { - GeomBezierCurve *newCurve = new GeomBezierCurve(myCurve); + auto *newCurve = new GeomBezierCurve(myCurve); newCurve->copyNonTag(this); return newCurve; } @@ -975,11 +1164,11 @@ std::vector GeomBezierCurve::getPoles() const { std::vector poles; poles.reserve(myCurve->NbPoles()); - TColgp_Array1OfPnt p(1,myCurve->NbPoles()); - myCurve->Poles(p); + TColgp_Array1OfPnt poleArray(1,myCurve->NbPoles()); + myCurve->Poles(poleArray); - for (Standard_Integer i=p.Lower(); i<=p.Upper(); i++) { - const gp_Pnt& pnt = p(i); + for (Standard_Integer index=poleArray.Lower(); index<=poleArray.Upper(); index++) { + const gp_Pnt& pnt = poleArray(index); poles.emplace_back(pnt.X(), pnt.Y(), pnt.Z()); } return poles; @@ -989,11 +1178,11 @@ std::vector GeomBezierCurve::getWeights() const { std::vector weights; weights.reserve(myCurve->NbPoles()); - TColStd_Array1OfReal w(1,myCurve->NbPoles()); - myCurve->Weights(w); + TColStd_Array1OfReal weightArray(1,myCurve->NbPoles()); + myCurve->Weights(weightArray); - for (Standard_Integer i=w.Lower(); i<=w.Upper(); i++) { - const Standard_Real& real = w(i); + for (Standard_Integer index=weightArray.Lower(); index<=weightArray.Upper(); index++) { + const Standard_Real& real = weightArray(index); weights.push_back(real); } return weights; @@ -1048,38 +1237,58 @@ void GeomBezierCurve::Restore(Base::XMLReader& reader) // get the value of my attribute int polescount = reader.getAttributeAsInteger("PolesCount"); - TColgp_Array1OfPnt p(1,polescount); - TColStd_Array1OfReal w(1,polescount); + TColgp_Array1OfPnt poleArray(1,polescount); + TColStd_Array1OfReal weightArray(1,polescount); - for (int i = 1; i <= polescount; i++) { + for (int index = 1; index <= polescount; index++) { reader.readElement("Pole"); double X = reader.getAttributeAsFloat("X"); double Y = reader.getAttributeAsFloat("Y"); double Z = reader.getAttributeAsFloat("Z"); double W = reader.getAttributeAsFloat("Weight"); - p.SetValue(i, gp_Pnt(X,Y,Z)); - w.SetValue(i, W); + poleArray.SetValue(index, gp_Pnt(X,Y,Z)); + weightArray.SetValue(index, W); } reader.readEndElement("BezierCurve"); try { - Handle(Geom_BezierCurve) bezier = new Geom_BezierCurve(p, w); + Handle(Geom_BezierCurve) bezier = new Geom_BezierCurve(poleArray, weightArray); if (!bezier.IsNull()) this->myCurve = bezier; else THROWM(Base::CADKernelError,"BezierCurve restore failed") } - catch (Standard_Failure& e) { + catch (Standard_Failure& exc) { - THROWM(Base::CADKernelError,e.GetMessageString()) + THROWM(Base::CADKernelError, exc.GetMessageString()) } } PyObject *GeomBezierCurve::getPyObject() { - return new BezierCurvePy(static_cast(this->clone())); + return new BezierCurvePy(dynamic_cast(this->clone())); +} + +bool GeomBezierCurve::isSame(const Geometry &_other, double tol, double) const +{ + if(_other.getTypeId() != getTypeId()) + return false; + + auto &other = dynamic_cast(_other); + + Standard_Integer c = myCurve->NbPoles(); + if(c!= other.myCurve->NbPoles()) + return false; + + double tol2 = tol*tol; + for(Standard_Integer index =1; index <=c; ++index) { + if(myCurve->Pole(index).SquareDistance(other.myCurve->Pole(index)) > tol2 + || fabs(myCurve->Weight(index) - other.myCurve->Weight(index)) > tol) + return false; + } + return true; } // ------------------------------------------------- @@ -1123,14 +1332,14 @@ GeomBSplineCurve::GeomBSplineCurve( const std::vector& poles, co TColStd_Array1OfReal k(1,knots.size()); TColStd_Array1OfInteger m(1,knots.size()); - for (std::size_t i = 1; i <= poles.size(); i++) { - p.SetValue(i, gp_Pnt(poles[i-1].x,poles[i-1].y,poles[i-1].z)); - w.SetValue(i, weights[i-1]); + for (int index = 1; index <= poles.size(); index++) { + p.SetValue(index, gp_Pnt(poles[index -1].x,poles[index -1].y,poles[index -1].z)); + w.SetValue(index, weights[index -1]); } - for (std::size_t i = 1; i <= knots.size(); i++) { - k.SetValue(i, knots[i-1]); - m.SetValue(i, multiplicities[i-1]); + for (int index = 1; index <= knots.size(); index++) { + k.SetValue(index, knots[index -1]); + m.SetValue(index, multiplicities[index -1]); } this->myCurve = new Geom_BSplineCurve (p, w, k, m, degree, periodic?Standard_True:Standard_False, checkrational?Standard_True:Standard_False); @@ -1140,9 +1349,9 @@ GeomBSplineCurve::GeomBSplineCurve( const std::vector& poles, co GeomBSplineCurve::~GeomBSplineCurve() = default; -void GeomBSplineCurve::setHandle(const Handle(Geom_BSplineCurve)& c) +void GeomBSplineCurve::setHandle(const Handle(Geom_BSplineCurve)& curve) { - myCurve = Handle(Geom_BSplineCurve)::DownCast(c->Copy()); + myCurve = Handle(Geom_BSplineCurve)::DownCast(curve->Copy()); } const Handle(Geom_Geometry)& GeomBSplineCurve::handle() const @@ -1153,12 +1362,12 @@ const Handle(Geom_Geometry)& GeomBSplineCurve::handle() const Geometry *GeomBSplineCurve::copy() const { try { - GeomBSplineCurve *newCurve = new GeomBSplineCurve(myCurve); + auto *newCurve = new GeomBSplineCurve(myCurve); newCurve->copyNonTag(this); return newCurve; } - catch (Standard_Failure& e) { - THROWM(Base::CADKernelError, e.GetMessageString()) + catch (Standard_Failure& exc) { + THROWM(Base::CADKernelError, exc.GetMessageString()) } } @@ -1229,7 +1438,7 @@ void GeomBSplineCurve::setPoles(const std::vector& poles) { Standard_Integer index=1; - for (std::vector::const_iterator it = poles.begin(); it != poles.end(); ++it, index++){ + for (auto it = poles.begin(); it != poles.end(); ++it, index++){ setPole(index, *it); } } @@ -1269,7 +1478,7 @@ void GeomBSplineCurve::setWeights(const std::vector& weights) try { Standard_Integer index=1; - for (std::vector::const_iterator it = weights.begin(); it != weights.end(); ++it, index++){ + for (auto it = weights.begin(); it != weights.end(); ++it, index++){ myCurve->SetWeight(index, *it); } } @@ -1297,7 +1506,7 @@ void GeomBSplineCurve::setKnots(const std::vector& knots) { Standard_Integer index=1; - for (std::vector::const_iterator it = knots.begin(); it != knots.end(); ++it, index++) { + for (auto it = knots.begin(); it != knots.end(); ++it, index++) { setKnot(index, *it); } } @@ -1591,9 +1800,19 @@ void GeomBSplineCurve::Trim(double u, double v) }; try { - if (isPeriodic() && (v < u)) - v = v + myCurve->LastParameter() - myCurve->FirstParameter(); // v needs one extra lap - splitUnwrappedBSpline(u, v); + if(!isPeriodic()) { + splitUnwrappedBSpline(u, v); + } + else { // periodic + if( v < u ) { // wraps over origin + v = v + 1.0; // v needs one extra lap (1.0) + + splitUnwrappedBSpline(u, v); + } + else { + splitUnwrappedBSpline(u, v); + } + } } catch (Standard_Failure& e) { THROWM(Base::CADKernelError,e.GetMessageString()) @@ -1738,9 +1957,45 @@ void GeomBSplineCurve::Restore(Base::XMLReader& reader) PyObject *GeomBSplineCurve::getPyObject() { - return new BSplineCurvePy(static_cast(this->clone())); + return new BSplineCurvePy(dynamic_cast(this->clone())); } +bool GeomBSplineCurve::isSame(const Geometry &_other, double tol, double atol) const +{ + if(_other.getTypeId() != getTypeId()) { + if (isLinear() && _other.isDerivedFrom(GeomCurve::getClassTypeId())) { + std::unique_ptr geo(toLineSegment()); + if (geo) + return geo->isSame(_other, tol, atol); + } + return false; + } + + auto &other = dynamic_cast(_other); + (void)atol; + + if(countPoles() != other.countPoles() + || countKnots() != other.countKnots() + || getDegree() != other.getDegree() + || isPeriodic() != other.isPeriodic()) + return false; + + double tol2 = tol*tol; + for(int i=1, c=countPoles(); i<=c; ++i) { + if(myCurve->Pole(i).SquareDistance(other.myCurve->Pole(i)) > tol2 + || fabs(myCurve->Weight(i) - other.myCurve->Weight(i)) > tol) + return false; + } + + + for(int i=1, c=countKnots(); i<=c; ++i) { + if(fabs(myCurve->Knot(i) - other.myCurve->Knot(i)) > tol) + return false; + } + return true; +} + + // ------------------------------------------------- TYPESYSTEM_SOURCE_ABSTRACT(Part::GeomConic, Part::GeomCurve) @@ -1884,6 +2139,21 @@ GeomBSplineCurve* GeomConic::toNurbs(double first, double last) const return new GeomBSplineCurve(bspline); } +bool GeomConic::isSame(const Geometry &_other, double tol, double atol) const +{ + if(!_other.isDerivedFrom(GeomConic::getClassTypeId())) + return false; + + auto &other = static_cast(_other); + + Handle(Geom_Conic) conic = Handle(Geom_Conic)::DownCast(handle()); + Handle(Geom_Conic) conic2 = Handle(Geom_Conic)::DownCast(other.handle()); + + return conic->Position().XDirection().Angle(conic2->Position().XDirection()) <= atol + && conic->Position().YDirection().Angle(conic2->Position().YDirection()) <= atol + && Base::DistanceP2(getLocation(),other.getLocation()) <= tol*tol; +} + // ------------------------------------------------- TYPESYSTEM_SOURCE(Part::GeomTrimmedCurve,Part::GeomBoundedCurve) @@ -1935,6 +2205,30 @@ PyObject *GeomTrimmedCurve::getPyObject() return new TrimmedCurvePy(static_cast(this->clone())); } +bool GeomTrimmedCurve::isSame(const Geometry &_other, double tol, double atol) const +{ + if(_other.getTypeId() != getTypeId()) + return false; + + auto &other = static_cast(_other); + double u,v,u1,v1; + getRange(u,v); + other.getRange(u1,v1); + if(fabs(u-u1)>tol || fabs(v-v1)>tol) + return false; + + Handle(Geom_Curve) basis = myCurve->BasisCurve(); + Handle(Geom_Curve) basis1 = other.myCurve->BasisCurve(); + if(basis.IsNull() || basis1.IsNull() || basis->DynamicType() != basis1->DynamicType()) + return false; + + std::unique_ptr b(makeFromCurve(basis)); + std::unique_ptr b1(makeFromCurve(basis1)); + if (b && b1 && b->isSame(*b1, tol, atol)) + return true; + return false; +} + bool GeomTrimmedCurve::intersectBasisCurves( const GeomTrimmedCurve * c, std::vector>& points, double tol) const @@ -2356,6 +2650,16 @@ PyObject *GeomCircle::getPyObject() return new CirclePy(static_cast(this->clone())); } +bool GeomCircle::isSame(const Geometry &_other, double tol, double atol) const +{ + if(_other.getTypeId() != getTypeId()) + return false; + + (void)atol; + auto &other = static_cast(_other); + return GeomConic::isSame(other,tol,atol) && fabs(getRadius() - other.getRadius()) <= tol; +} + // ------------------------------------------------- TYPESYSTEM_SOURCE(Part::GeomArcOfCircle,Part::GeomArcOfConic) @@ -2856,6 +3160,18 @@ PyObject *GeomEllipse::getPyObject() return new EllipsePy(static_cast(this->clone())); } +bool GeomEllipse::isSame(const Geometry &_other, double tol, double atol) const +{ + if(_other.getTypeId() != getTypeId()) + return false; + + (void)atol; + auto &other = static_cast(_other); + return GeomConic::isSame(other,tol,atol) + && fabs(getMajorRadius() - other.getMajorRadius()) <= tol + && fabs(getMinorRadius() - other.getMinorRadius()) <= tol; +} + // ------------------------------------------------- TYPESYSTEM_SOURCE(Part::GeomArcOfEllipse,Part::GeomArcOfConic) @@ -3297,6 +3613,19 @@ PyObject *GeomHyperbola::getPyObject() { return new HyperbolaPy(static_cast(this->clone())); } + +bool GeomHyperbola::isSame(const Geometry &_other, double tol, double atol) const +{ + if(_other.getTypeId() != getTypeId()) + return false; + + (void)atol; + auto &other = static_cast(_other); + return GeomConic::isSame(other,tol,atol) + && fabs(getMajorRadius() - other.getMajorRadius()) <= tol + && fabs(getMinorRadius() - other.getMinorRadius()) <= tol; +} + // ------------------------------------------------- TYPESYSTEM_SOURCE(Part::GeomArcOfHyperbola,Part::GeomArcOfConic) @@ -3610,7 +3939,7 @@ GeomBSplineCurve* GeomParabola::toNurbs(double first, double last) const { // the default implementation suffices because a non-rational B-spline with // one segment is a parabola - return GeomCurve::toNurbs(first, last); + return GeomCurve::toNurbs(first, last); // NOLINT } double GeomParabola::getFocal() const @@ -3711,6 +4040,15 @@ PyObject *GeomParabola::getPyObject() return new ParabolaPy(static_cast(this->clone())); } +bool GeomParabola::isSame(const Geometry &_other, double tol, double atol) const +{ + if(_other.getTypeId() != getTypeId()) + return false; + + (void)atol; + auto &other = static_cast(_other); + return GeomConic::isSame(other,tol,atol) && fabs(getFocal() - other.getFocal()) < tol; +} // ------------------------------------------------- TYPESYSTEM_SOURCE(Part::GeomArcOfParabola,Part::GeomArcOfConic) @@ -4030,6 +4368,22 @@ PyObject *GeomLine::getPyObject() return new LinePy(static_cast(this->clone())); } +bool GeomLine::isSame(const Geometry &_other, double tol, double atol) const +{ + if(_other.getTypeId() != getTypeId()) { + if (_other.isDerivedFrom(GeomCurve::getClassTypeId())) { + std::unique_ptr geo(dynamic_cast(_other).toLine()); + if (geo) + return isSame(*geo, tol, atol); + } + return false; + } + + auto &other = dynamic_cast(_other); + + return getDir().GetAngle(other.getDir()) <= atol + && Base::DistanceP2(getPos(), other.getPos()) <= tol*tol; +} // ------------------------------------------------- TYPESYSTEM_SOURCE(Part::GeomLineSegment,Part::GeomTrimmedCurve) @@ -4070,7 +4424,7 @@ const Handle(Geom_Geometry)& GeomLineSegment::handle() const Geometry *GeomLineSegment::copy()const { - GeomLineSegment *tempCurve = new GeomLineSegment(); + auto *tempCurve = new GeomLineSegment(); tempCurve->myCurve = Handle(Geom_TrimmedCurve)::DownCast(myCurve->Copy()); tempCurve->copyNonTag(this); return tempCurve; @@ -4108,7 +4462,8 @@ void GeomLineSegment::setPoints(const Base::Vector3d& Start, const Base::Vector3 // get Geom_Line of line segment Handle(Geom_Line) this_line = Handle(Geom_Line)::DownCast (this_curv->BasisCurve()); - Handle(Geom_TrimmedCurve) that_curv = ms.Value(); + Handle(Geom_TrimmedCurve)& that_curv = + const_cast&>(ms.Value()); Handle(Geom_Line) that_line = Handle(Geom_Line)::DownCast(that_curv->BasisCurve()); this_line->SetLin(that_line->Lin()); this_curv->SetTrim(that_curv->FirstParameter(), that_curv->LastParameter()); @@ -4186,7 +4541,7 @@ void GeomLineSegment::Restore (Base::XMLReader &reader) PyObject *GeomLineSegment::getPyObject() { - return new LineSegmentPy(static_cast(this->clone())); + return new LineSegmentPy(dynamic_cast(this->clone())); } // ------------------------------------------------- @@ -4213,11 +4568,22 @@ GeomOffsetCurve::~GeomOffsetCurve() = default; Geometry *GeomOffsetCurve::copy() const { - GeomOffsetCurve *newCurve = new GeomOffsetCurve(myCurve); + auto *newCurve = new GeomOffsetCurve(myCurve); newCurve->copyNonTag(this); return newCurve; } +Base::Vector3d GeomOffsetCurve::getDir() const +{ + gp_Dir Dir = this->myCurve->Direction(); + return Base::Vector3d(Dir.X(),Dir.Y(),Dir.Z()); +} + +double GeomOffsetCurve::getOffset() const +{ + return this->myCurve->Offset(); +} + void GeomOffsetCurve::setHandle(const Handle(Geom_OffsetCurve)& c) { this->myCurve = Handle(Geom_OffsetCurve)::DownCast(c->Copy()); @@ -4246,7 +4612,26 @@ void GeomOffsetCurve::Restore(Base::XMLReader &/*reader*/) PyObject *GeomOffsetCurve::getPyObject() { - return new OffsetCurvePy(static_cast(this->clone())); + return new OffsetCurvePy(dynamic_cast(this->clone())); +} + +bool GeomOffsetCurve::isSame(const Geometry &_other, double tol, double atol) const +{ + if(_other.getTypeId() != getTypeId()) + return false; + + auto &other = dynamic_cast(_other); + if(myCurve->Direction().Angle(other.myCurve->Direction()) > atol || fabs(getOffset() - other.getOffset()) > tol) + return false; + + Handle(Geom_Curve) basis = myCurve->BasisCurve(); + Handle(Geom_Curve) basis1 = other.myCurve->BasisCurve(); + if(basis.IsNull() || basis1.IsNull() || basis->DynamicType() != basis1->DynamicType()) + return false; + + std::unique_ptr b(makeFromCurve(basis)); + std::unique_ptr b1(makeFromCurve(basis1)); + return b && b1 && b->isSame(*b1, tol, atol); } // ------------------------------------------------- @@ -4258,6 +4643,43 @@ GeomSurface::GeomSurface() = default; GeomSurface::~GeomSurface() = default; +bool GeomSurface::isPlanar(gp_Pln *pln, double tol) const +{ + Handle(Geom_Surface) s = Handle(Geom_Surface)::DownCast(handle()); + return isPlanar(s, pln, tol); +} + +bool GeomSurface::isPlanar(const Handle(Geom_Surface) &s, gp_Pln *pln, double tol) +{ + GeomLib_IsPlanarSurface check(s, tol); + if (!check.IsPlanar()) + return false; + if (pln) + *pln = check.Plan(); + return true; +} + +GeomPlane* GeomSurface::toPlane(bool clone, double tol) const +{ + if (isDerivedFrom(GeomPlane::getClassTypeId())) { + if (clone) { + return dynamic_cast(this->clone()); + } else { + return dynamic_cast(this->copy()); + } + } + + gp_Pln pln; + if (!isPlanar(&pln, tol)) + return nullptr; + + auto res = new GeomPlane(pln); + res->copyNonTag(this); + if (clone) + res->tag = this->tag; + return res; +} + TopoDS_Shape GeomSurface::toShape() const { Handle(Geom_Surface) s = Handle(Geom_Surface)::DownCast(handle()); @@ -4392,7 +4814,7 @@ void GeomBezierSurface::setHandle(const Handle(Geom_BezierSurface)& b) Geometry *GeomBezierSurface::copy() const { - GeomBezierSurface *newSurf = new GeomBezierSurface(mySurface); + auto *newSurf = new GeomBezierSurface(mySurface); newSurf->copyNonTag(this); return newSurf; } @@ -4425,6 +4847,32 @@ PyObject *GeomBezierSurface::getPyObject() return new BezierSurfacePy(static_cast(this->clone())); } +bool GeomBezierSurface::isSame(const Geometry &_other, double tol, double atol) const +{ + if(_other.getTypeId() != getTypeId()) + return false; + + auto &other = static_cast(_other); + Standard_Integer uc = mySurface->NbUPoles(); + Standard_Integer vc = mySurface->NbVPoles(); + if(uc != other.mySurface->NbUPoles() + || vc != other.mySurface->NbVPoles() + || mySurface->UDegree() != other.mySurface->UDegree() + || mySurface->VDegree() != other.mySurface->VDegree()) + return false; + + (void)atol; + double tol2 = tol*tol; + for(Standard_Integer u=1; u<=uc; ++u) { + for(Standard_Integer v=1; v<=vc; ++v) { + if(mySurface->Pole(u,v).SquareDistance(other.mySurface->Pole(u,v)) > tol2 + || fabs(mySurface->Weight(u,v) - other.mySurface->Weight(u,v)) > tol) + return false; + } + } + return true; +} + // ------------------------------------------------- TYPESYSTEM_SOURCE(Part::GeomBSplineSurface,Part::GeomSurface) @@ -4531,6 +4979,112 @@ PyObject *GeomBSplineSurface::getPyObject() return new BSplineSurfacePy(static_cast(this->clone())); } +bool GeomBSplineSurface::isSame(const Geometry &_other, double tol, double atol) const +{ + if(_other.getTypeId() != getTypeId()) { + if (_other.isDerivedFrom(GeomSurface::getClassTypeId()) && isPlanar()) { + std::unique_ptr geo(toPlane()); + if (geo) + return geo->isSame(_other, tol, atol); + } + return false; + } + + auto &other = static_cast(_other); + Standard_Integer uc = mySurface->NbUPoles(); + Standard_Integer vc = mySurface->NbVPoles(); + Standard_Integer ukc = mySurface->NbUKnots(); + Standard_Integer vkc = mySurface->NbVKnots(); + if(uc != other.mySurface->NbUPoles() + || vc != other.mySurface->NbVPoles() + || ukc != other.mySurface->NbUKnots() + || vkc != other.mySurface->NbVKnots() + || mySurface->UDegree() != other.mySurface->UDegree() + || mySurface->VDegree() != other.mySurface->VDegree() + || mySurface->IsUPeriodic() != other.mySurface->IsUPeriodic() + || mySurface->IsVPeriodic() != other.mySurface->IsVPeriodic()) + return false; + + (void)atol; + double tol2 = tol*tol; + for(Standard_Integer u=1; u<=uc; ++u) { + for(Standard_Integer v=1; v<=vc; ++v) { + if(mySurface->Pole(u,v).SquareDistance(other.mySurface->Pole(u,v)) > tol2 + || fabs(mySurface->Weight(u,v) - other.mySurface->Weight(u,v)) > tol) + return false; + } + } + for(Standard_Integer u=1; u<=ukc; ++u) { + if(fabs(mySurface->UKnot(u) - other.mySurface->UKnot(u)) > tol + || fabs(mySurface->UMultiplicity(u) - other.mySurface->UMultiplicity(u)) > tol) + return false; + } + for(Standard_Integer v=1; v<=ukc; ++v) { + if(fabs(mySurface->VKnot(v) - other.mySurface->VKnot(v)) > tol + || fabs(mySurface->VMultiplicity(v) - other.mySurface->VMultiplicity(v)) > tol) + return false; + } + return true; +} + +// ------------------------------------------------- + +TYPESYSTEM_SOURCE_ABSTRACT(Part::GeomElementarySurface, Part::GeomSurface) + +GeomElementarySurface::GeomElementarySurface() +{ +} + +GeomElementarySurface::~GeomElementarySurface() +{ +} + +Base::Vector3d GeomElementarySurface::getLocation(void) const +{ + Handle(Geom_ElementarySurface) surf = Handle(Geom_ElementarySurface)::DownCast(handle()); + gp_Pnt loc = surf->Location(); + return Base::Vector3d(loc.X(),loc.Y(),loc.Z()); +} + +Base::Vector3d GeomElementarySurface::getDir(void) const +{ + Handle(Geom_ElementarySurface) surf = Handle(Geom_ElementarySurface)::DownCast(handle()); + const gp_Dir &dir = surf->Position().Direction(); + return Base::Vector3d(dir.X(),dir.Y(),dir.Z()); +} + +Base::Vector3d GeomElementarySurface::getXDir(void) const +{ + Handle(Geom_ElementarySurface) surf = Handle(Geom_ElementarySurface)::DownCast(handle()); + const gp_Dir &dir = surf->Position().XDirection(); + return Base::Vector3d(dir.X(),dir.Y(),dir.Z()); +} + +Base::Vector3d GeomElementarySurface::getYDir(void) const +{ + Handle(Geom_ElementarySurface) surf = Handle(Geom_ElementarySurface)::DownCast(handle()); + const gp_Dir &dir = surf->Position().YDirection(); + return Base::Vector3d(dir.X(),dir.Y(),dir.Z()); +} + +bool GeomElementarySurface::isSame(const Geometry &_other, double tol, double atol) const +{ + if(!_other.isDerivedFrom(GeomElementarySurface::getClassTypeId())) + return false; + + auto &other = static_cast(_other); + return Base::DistanceP2(getLocation(), other.getLocation()) <= tol*tol + && getDir().GetAngle(other.getDir()) <= atol + && ((getXDir().GetAngle(other.getXDir()) <= atol + && getYDir().GetAngle(other.getYDir()) <= atol) + // It seems that OCC may change some surface Position (gp_Ax3) to + // right hand coordinate. The following checks is to detect such cases. + || (getXDir().GetAngle(other.getYDir()) <= atol + && getYDir().GetAngle(-other.getXDir()) <= atol) + || (getYDir().GetAngle(other.getXDir()) <= atol + && getXDir().GetAngle(-other.getYDir()) <= atol)); +} + // ------------------------------------------------- TYPESYSTEM_SOURCE(Part::GeomCylinder,Part::GeomSurface) @@ -4587,6 +5141,23 @@ PyObject *GeomCylinder::getPyObject() return new CylinderPy(static_cast(this->clone())); } +double GeomCylinder::getRadius() const +{ + return mySurface->Radius(); +} + +bool GeomCylinder::isSame(const Geometry &_other, double tol, double atol) const +{ + if(_other.getTypeId() != getTypeId()) + return false; + + (void)atol; + auto &other = static_cast(_other); + return GeomElementarySurface::isSame(other,tol,atol) + && fabs(getRadius() - other.getRadius()) <= tol; +} + + // ------------------------------------------------- TYPESYSTEM_SOURCE(Part::GeomCone,Part::GeomSurface) @@ -4691,6 +5262,27 @@ gp_Vec GeomCone::getDN(double u, double v, int Nu, int Nv) const #endif } +double GeomCone::getRadius() const +{ + return mySurface->RefRadius(); +} + +double GeomCone::getSemiAngle() const +{ + return mySurface->SemiAngle(); +} + +bool GeomCone::isSame(const Geometry &_other, double tol, double atol) const +{ + if(_other.getTypeId() != getTypeId()) + return false; + + auto &other = static_cast(_other); + return GeomElementarySurface::isSame(other,tol,atol) + && fabs(getRadius() - other.getRadius()) <= tol + && fabs(getSemiAngle() - other.getSemiAngle()) <= atol; +} + // ------------------------------------------------- TYPESYSTEM_SOURCE(Part::GeomToroid,Part::GeomSurface) @@ -4747,6 +5339,29 @@ PyObject *GeomToroid::getPyObject() return new ToroidPy(static_cast(this->clone())); } +double GeomToroid::getMajorRadius() const +{ + return mySurface->MajorRadius(); +} + +double GeomToroid::getMinorRadius() const +{ + return mySurface->MinorRadius(); +} + +bool GeomToroid::isSame(const Geometry &_other, double tol, double atol) const +{ + if(_other.getTypeId() != getTypeId()) + return false; + + (void)atol; + auto &other = static_cast(_other); + return GeomElementarySurface::isSame(other,tol,atol) + && fabs(getMajorRadius() - other.getMajorRadius()) <= tol + && fabs(getMinorRadius() - other.getMinorRadius()) <= tol; +} + + // ------------------------------------------------- TYPESYSTEM_SOURCE(Part::GeomSphere,Part::GeomSurface) @@ -4803,6 +5418,23 @@ PyObject *GeomSphere::getPyObject() return new SpherePy(static_cast(this->clone())); } +double GeomSphere::getRadius() const +{ + return mySurface->Radius(); +} + +bool GeomSphere::isSame(const Geometry &_other, double tol, double atol) const +{ + if(_other.getTypeId() != getTypeId()) + return false; + + (void)atol; + auto &other = static_cast(_other); + return GeomElementarySurface::isSame(other,tol,atol) + && fabs(getRadius() - other.getRadius()) <= tol; +} + + // ------------------------------------------------- TYPESYSTEM_SOURCE(Part::GeomPlane,Part::GeomSurface) @@ -4813,6 +5445,12 @@ GeomPlane::GeomPlane() this->mySurface = s; } +GeomPlane::GeomPlane(const gp_Pln &pln) +{ + Handle(Geom_Plane) s = new Geom_Plane(pln); + this->mySurface = s; +} + GeomPlane::GeomPlane(const Handle(Geom_Plane)& p) { setHandle(p); @@ -4859,6 +5497,21 @@ PyObject *GeomPlane::getPyObject() return new PlanePy(static_cast(this->clone())); } +bool GeomPlane::isSame(const Geometry &_other, double tol, double atol) const +{ + if(_other.getTypeId() != getTypeId()) { + if (_other.isDerivedFrom(GeomSurface::getClassTypeId())) { + std::unique_ptr geo(static_cast(_other).toPlane()); + if (geo) + return isSame(*geo, tol, atol); + } + return false; + } + + auto &other = static_cast(_other); + return GeomElementarySurface::isSame(other,tol,atol); +} + // ------------------------------------------------- TYPESYSTEM_SOURCE(Part::GeomOffsetSurface,Part::GeomSurface) @@ -4915,6 +5568,30 @@ PyObject *GeomOffsetSurface::getPyObject() return new OffsetSurfacePy(static_cast(this->clone())); } +double GeomOffsetSurface::getOffset() const +{ + return mySurface->Offset(); +} + +bool GeomOffsetSurface::isSame(const Geometry &_other, double tol, double atol) const +{ + if(_other.getTypeId() != getTypeId()) + return false; + + auto &other = static_cast(_other); + if(fabs(getOffset() - other.getOffset()) > tol) + return false; + + Handle(Geom_Surface) basis = mySurface->BasisSurface(); + Handle(Geom_Surface) basis1 = other.mySurface->BasisSurface(); + if(basis.IsNull() || basis1.IsNull() || basis->DynamicType() != basis1->DynamicType()) + return false; + + std::unique_ptr b(makeFromSurface(basis)); + std::unique_ptr b1(makeFromSurface(basis1)); + return b && b1 && b->isSame(*b1,tol,atol); +} + // ------------------------------------------------- TYPESYSTEM_SOURCE(Part::GeomPlateSurface,Part::GeomSurface) @@ -4977,6 +5654,12 @@ PyObject *GeomPlateSurface::getPyObject() return new PlateSurfacePy(static_cast(this->clone())); } +bool GeomPlateSurface::isSame(const Geometry &, double, double) const +{ + // TODO: How to compare this type of surface? + return false; +} + // ------------------------------------------------- TYPESYSTEM_SOURCE(Part::GeomTrimmedSurface,Part::GeomSurface) @@ -5028,8 +5711,72 @@ PyObject *GeomTrimmedSurface::getPyObject() return new RectangularTrimmedSurfacePy(static_cast(this->clone())); } -// ------------------------------------------------- +bool GeomTrimmedSurface::isSame(const Geometry &_other, double tol, double atol) const +{ + if(_other.getTypeId() != getTypeId()) + return false; + auto &other = static_cast(_other); + + Standard_Real u1[2],u2[2],v1[2],v2[2]; + mySurface->Bounds(u1[0],u2[0],v1[0],v2[0]); + other.mySurface->Bounds(u1[1],u2[1],v1[1],v2[1]); + + if(fabs(u1[0]-u1[1])>tol || fabs(u2[0]-u2[1])>tol + || fabs(v1[0]-v1[1])>tol || fabs(v2[0]-v2[1])>tol) + return false; + + Handle(Geom_Surface) basis = mySurface->BasisSurface(); + Handle(Geom_Surface) basis1 = other.mySurface->BasisSurface(); + if(basis.IsNull() || basis1.IsNull() || basis->DynamicType() != basis1->DynamicType()) + return false; + + std::unique_ptr b(makeFromSurface(basis)); + std::unique_ptr b1(makeFromSurface(basis1)); + return b && b1 && b->isSame(*b1,tol,atol); +} + +// ------------------------------------------------- +TYPESYSTEM_SOURCE_ABSTRACT(Part::GeomSweptSurface, Part::GeomSurface) + +GeomSweptSurface::GeomSweptSurface() +{ +} + +GeomSweptSurface::~GeomSweptSurface() +{ +} + +Base::Vector3d GeomSweptSurface::getDir(void) const +{ + Handle(Geom_SweptSurface) surf = Handle(Geom_SweptSurface)::DownCast(handle()); + const gp_Dir &dir = surf->Direction(); + return Base::Vector3d(dir.X(),dir.Y(),dir.Z()); +} + +bool GeomSweptSurface::isSame(const Geometry &_other, double tol, double atol) const +{ + if(!_other.isDerivedFrom(GeomSweptSurface::getClassTypeId())) + return false; + + auto &other = static_cast(_other); + if(getDir().GetAngle(other.getDir()) > atol) + return false; + + Handle(Geom_SweptSurface) surf = Handle(Geom_SweptSurface)::DownCast(handle()); + Handle(Geom_SweptSurface) surf1 = Handle(Geom_SweptSurface)::DownCast(other.handle()); + + Handle(Geom_Curve) basis = surf->BasisCurve(); + Handle(Geom_Curve) basis1 = surf1->BasisCurve(); + if(basis.IsNull() || basis1.IsNull() || basis->DynamicType() != basis1->DynamicType()) + return false; + + std::unique_ptr b(makeFromCurve(basis)); + std::unique_ptr b1(makeFromCurve(basis1)); + return b && b1 && b->isSame(*b1,tol,atol); +} + +// ------------------------------------------------- TYPESYSTEM_SOURCE(Part::GeomSurfaceOfRevolution,Part::GeomSurface) GeomSurfaceOfRevolution::GeomSurfaceOfRevolution() = default; @@ -5312,9 +6059,16 @@ GeomArcOfCircle *createFilletGeometry(const GeomLineSegment *lineSeg1, const Geo return arc; } -std::unique_ptr makeFromSurface(const Handle(Geom_Surface)& s) +std::unique_ptr makeFromSurface(const Handle(Geom_Surface)& s, bool silent) { std::unique_ptr geoSurf; + + if (s.IsNull()) { + if (!silent) + throw Base::ValueError("Null surface"); + return geoSurf; + } + if (s->IsKind(STANDARD_TYPE(Geom_ToroidalSurface))) { Handle(Geom_ToroidalSurface) hSurf = Handle(Geom_ToroidalSurface)::DownCast(s); geoSurf = std::make_unique(hSurf); @@ -5372,9 +6126,126 @@ std::unique_ptr makeFromSurface(const Handle(Geom_Surface)& s) return geoSurf; } -std::unique_ptr makeFromCurve(const Handle(Geom_Curve)& c) +std::unique_ptr makeFromSurfaceAdaptor(const BRepAdaptor_Surface& adapt, bool silent) +{ + std::unique_ptr geoSurf; + + switch(adapt.GetType()) + { + case GeomAbs_Plane: + { + geoSurf.reset(new GeomPlane()); + Handle(Geom_Plane) this_surf = Handle(Geom_Plane)::DownCast + (geoSurf->handle()); + this_surf->SetPln(adapt.Plane()); + break; + } + case GeomAbs_Cylinder: + { + geoSurf.reset(new GeomCylinder()); + Handle(Geom_CylindricalSurface) this_surf = Handle(Geom_CylindricalSurface)::DownCast + (geoSurf->handle()); + this_surf->SetCylinder(adapt.Cylinder()); + break; + } + case GeomAbs_Cone: + { + geoSurf.reset(new GeomCone()); + Handle(Geom_ConicalSurface) this_surf = Handle(Geom_ConicalSurface)::DownCast + (geoSurf->handle()); + this_surf->SetCone(adapt.Cone()); + break; + } + case GeomAbs_Sphere: + { + geoSurf.reset(new GeomSphere()); + Handle(Geom_SphericalSurface) this_surf = Handle(Geom_SphericalSurface)::DownCast + (geoSurf->handle()); + this_surf->SetSphere(adapt.Sphere()); + break; + } + case GeomAbs_Torus: + { + geoSurf.reset(new GeomToroid()); + Handle(Geom_ToroidalSurface) this_surf = Handle(Geom_ToroidalSurface)::DownCast + (geoSurf->handle()); + this_surf->SetTorus(adapt.Torus()); + break; + } + case GeomAbs_BezierSurface: + { + geoSurf.reset(new GeomBezierSurface(adapt.Bezier())); + break; + } + case GeomAbs_BSplineSurface: + { + geoSurf.reset(new GeomBSplineSurface(adapt.BSpline())); + break; + } + case GeomAbs_SurfaceOfRevolution: + { + Handle(Geom_Surface) s = BRep_Tool::Surface(adapt.Face()); + Handle(Geom_SurfaceOfRevolution) rev = Handle(Geom_SurfaceOfRevolution)::DownCast(s); + if (rev.IsNull()) { + Handle(Geom_RectangularTrimmedSurface) rect = Handle(Geom_RectangularTrimmedSurface)::DownCast(s); + rev = Handle(Geom_SurfaceOfRevolution)::DownCast(rect->BasisSurface()); + } + if (!rev.IsNull()) + geoSurf.reset(new GeomSurfaceOfRevolution(rev)); + break; + } + case GeomAbs_SurfaceOfExtrusion: + { + Handle(Geom_Surface) s = BRep_Tool::Surface(adapt.Face()); + Handle(Geom_SurfaceOfLinearExtrusion) ext = Handle(Geom_SurfaceOfLinearExtrusion)::DownCast(s); + if (ext.IsNull()) { + Handle(Geom_RectangularTrimmedSurface) rect = Handle(Geom_RectangularTrimmedSurface)::DownCast(s); + ext = Handle(Geom_SurfaceOfLinearExtrusion)::DownCast(rect->BasisSurface()); + } + if (!ext.IsNull()) + geoSurf.reset(new GeomSurfaceOfExtrusion(ext)); + break; + } + case GeomAbs_OffsetSurface: + { + Handle(Geom_Surface) s = BRep_Tool::Surface(adapt.Face()); + Handle(Geom_OffsetSurface) off = Handle(Geom_OffsetSurface)::DownCast(s); + if (off.IsNull()) { + Handle(Geom_RectangularTrimmedSurface) rect = Handle(Geom_RectangularTrimmedSurface)::DownCast(s); + off = Handle(Geom_OffsetSurface)::DownCast(rect->BasisSurface()); + } + if (!off.IsNull()) + geoSurf.reset(new GeomOffsetSurface(off)); + break; + } + default: + break; + } + + if (!geoSurf && !silent) { + std::string err = "Cannot convert surface type "; + Handle(Geom_Surface) s = BRep_Tool::Surface(adapt.Face()); + if (s) + err += s->DynamicType()->Name(); + else + err += " unknown"; + throw Base::TypeError(err); + } + + return geoSurf; +} + + +std::unique_ptr makeFromCurve(const Handle(Geom_Curve)& c, bool silent) { std::unique_ptr geoCurve; + + if (c.IsNull()) { + if (!silent) + throw Base::ValueError("Null curve"); + return geoCurve; + } + if (c->IsKind(STANDARD_TYPE(Geom_Circle))) { Handle(Geom_Circle) circ = Handle(Geom_Circle)::DownCast(c); geoCurve = std::make_unique(circ); @@ -5423,8 +6294,14 @@ std::unique_ptr makeFromCurve(const Handle(Geom_Curve)& c) return geoCurve; } -std::unique_ptr makeFromTrimmedCurve(const Handle(Geom_Curve)& c, double f, double l) +std::unique_ptr makeFromTrimmedCurve(const Handle(Geom_Curve)& c, double f, double l, bool silent) { + if (c.IsNull()) { + if (!silent) + throw Base::ValueError("Null curve"); + return std::unique_ptr(); + } + if (c->IsKind(STANDARD_TYPE(Geom_Circle))) { Handle(Geom_Circle) circ = Handle(Geom_Circle)::DownCast(c); std::unique_ptr arc(new GeomArcOfCircle()); @@ -5505,14 +6382,16 @@ std::unique_ptr makeFromTrimmedCurve(const Handle(Geom_Curve)& c, dou Handle(Geom_BoundedCurve) bc = Handle(Geom_BoundedCurve)::DownCast(c); return Py::asObject(new GeometryCurvePy(new GeomBoundedCurve(bc))); }*/ - else { + else if (!silent) { std::string err = "Unhandled curve type "; err += c->DynamicType()->Name(); throw Base::TypeError(err); } + + return std::unique_ptr(); } -std::unique_ptr makeFromCurveAdaptor(const Adaptor3d_Curve& adapt) +std::unique_ptr makeFromCurveAdaptor(const Adaptor3d_Curve& adapt, bool silent) { std::unique_ptr geoCurve; switch (adapt.GetType()) @@ -5577,8 +6456,11 @@ std::unique_ptr makeFromCurveAdaptor(const Adaptor3d_Curve& adapt) break; } - if (!geoCurve) - throw Base::TypeError("Unhandled curve type"); + if (!geoCurve) { + if (!silent) + throw Base::TypeError("Unhandled curve type"); + return geoCurve; + } // Check if the curve must be trimmed Handle(Geom_Curve) curv3d = Handle(Geom_Curve)::DownCast @@ -5592,4 +6474,5 @@ std::unique_ptr makeFromCurveAdaptor(const Adaptor3d_Curve& adapt) return geoCurve; } -} +} // namespace Part + diff --git a/src/Mod/Part/App/Geometry.h b/src/Mod/Part/App/Geometry.h index c2027c9e27..183b5de2ba 100644 --- a/src/Mod/Part/App/Geometry.h +++ b/src/Mod/Part/App/Geometry.h @@ -65,18 +65,26 @@ #include #include #include +#include #include "GeometryExtension.h" namespace Part { +enum KeepTag +{ + NewTag, // Assign a new tag + CopyTag // Keep the existing tag +}; + class PartExport Geometry: public Base::Persistence { TYPESYSTEM_HEADER_WITH_OVERRIDE(); public: ~Geometry() override; + static std::unique_ptr fromShape(const TopoDS_Shape &s, bool silent=false); virtual TopoDS_Shape toShape() const = 0; virtual const Handle(Geom_Geometry)& handle() const = 0; // Persistence implementer --------------------- @@ -97,6 +105,9 @@ public: /// returns the tag of the geometry object boost::uuids::uuid getTag() const; + virtual bool isSame(const Geometry &other, double tol, double atol) const = 0; + bool hasSameExtensions(const Geometry &other) const; + std::vector> getExtensions() const; bool hasExtension(const Base::Type & type) const; @@ -109,12 +120,12 @@ public: void deleteExtension(const Base::Type & type); void deleteExtension(const std::string & name); - void mirror(const Base::Vector3d& point); - void mirror(const Base::Vector3d& point, const Base::Vector3d& dir); - void rotate(const Base::Placement& plm); - void scale(const Base::Vector3d& vec, double scale); - void transform(const Base::Matrix4D& mat); - void translate(const Base::Vector3d& vec); + void mirror(const Base::Vector3d& point) const; + void mirror(const Base::Vector3d& point, const Base::Vector3d& dir) const; + void rotate(const Base::Placement& plm) const; + void scale(const Base::Vector3d& vec, double scale) const; + void transform(const Base::Matrix4D& mat) const; + void translate(const Base::Vector3d& vec) const; protected: /// create a new tag for the geometry object @@ -141,8 +152,8 @@ class PartExport GeomPoint : public Geometry TYPESYSTEM_HEADER_WITH_OVERRIDE(); public: GeomPoint(); - GeomPoint(const Handle(Geom_CartesianPoint)&); - GeomPoint(const Base::Vector3d&); + explicit GeomPoint(const Handle(Geom_CartesianPoint)&); + explicit GeomPoint(const Base::Vector3d&); ~GeomPoint() override; Geometry *copy() const override; TopoDS_Shape toShape() const override; @@ -152,8 +163,15 @@ public: void Save(Base::Writer &/*writer*/) const override; void Restore(Base::XMLReader &/*reader*/) override; // Base implementer ---------------------------- - PyObject *getPyObject() override; - + PyObject* getPyObject() override; + /** + * Compare this point to another one. + * @param other Other geometry point. Can pass in Other geometry types but will not match + * @param tol Points meed to be within tol^2 to match. + * @param atol Angle tolerance is not used for points. + * @return True if a match is found. + */ + bool isSame(const Geometry& other, double tol, double atol) const override; const Handle(Geom_Geometry)& handle() const override; void setHandle(const Handle(Geom_CartesianPoint)&); @@ -165,6 +183,9 @@ private: }; class GeomBSplineCurve; +class GeomLine; +class GeomLineSegment; + class PartExport GeomCurve : public Geometry { TYPESYSTEM_HEADER_WITH_OVERRIDE(); @@ -172,6 +193,9 @@ public: GeomCurve(); ~GeomCurve() override; + static bool isLinear(const Handle(Geom_Curve) &c, Base::Vector3d *dir = nullptr, Base::Vector3d *base = nullptr); + bool isLinear(Base::Vector3d *dir = nullptr, Base::Vector3d *base = nullptr) const; + TopoDS_Shape toShape() const override; /*! * \brief toBSpline Converts the curve to a B-spline @@ -207,8 +231,11 @@ public: Base::Vector3d value(double u) const; + GeomLine* toLine(KeepTag clone = CopyTag) const; + GeomLineSegment* toLineSegment(KeepTag clone = CopyTag) const; + protected: - static bool intersect(const Handle(Geom_Curve) c, const Handle(Geom_Curve) c2, + static bool intersect(const Handle(Geom_Curve)& c, const Handle(Geom_Curve)& c2, std::vector>& points, double tol = Precision::Confusion()); }; @@ -230,7 +257,7 @@ class PartExport GeomBezierCurve : public GeomBoundedCurve TYPESYSTEM_HEADER_WITH_OVERRIDE(); public: GeomBezierCurve(); - GeomBezierCurve(const Handle(Geom_BezierCurve)&); + explicit GeomBezierCurve(const Handle(Geom_BezierCurve)&); GeomBezierCurve(const std::vector&, const std::vector&); ~GeomBezierCurve() override; Geometry *copy() const override; @@ -242,7 +269,8 @@ public: void Save (Base::Writer &/*writer*/) const override; void Restore(Base::XMLReader &/*reader*/) override; // Base implementer ---------------------------- - PyObject *getPyObject() override; + PyObject *getPyObject(void) override; + bool isSame(const Geometry &other, double tol, double atol) const override; void setHandle(const Handle(Geom_BezierCurve)&); const Handle(Geom_Geometry)& handle() const override; @@ -256,7 +284,7 @@ class PartExport GeomBSplineCurve : public GeomBoundedCurve TYPESYSTEM_HEADER_WITH_OVERRIDE(); public: GeomBSplineCurve(); - GeomBSplineCurve(const Handle(Geom_BSplineCurve)&); + explicit GeomBSplineCurve(const Handle(Geom_BSplineCurve)&); GeomBSplineCurve( const std::vector& poles, const std::vector& weights, const std::vector& knots, const std::vector& multiplicities, @@ -325,7 +353,9 @@ public: void Save(Base::Writer &/*writer*/) const override; void Restore(Base::XMLReader &/*reader*/) override; // Base implementer ---------------------------- - PyObject *getPyObject() override; + PyObject *getPyObject(void) override; + + bool isSame(const Geometry &other, double tol, double atol) const override; void setHandle(const Handle(Geom_BSplineCurve)&); const Handle(Geom_Geometry)& handle() const override; @@ -377,6 +407,8 @@ public: PyObject *getPyObject() override = 0; GeomBSplineCurve* toNurbs(double first, double last) const override; + bool isSame(const Geometry &other, double tol, double atol) const override; + const Handle(Geom_Geometry)& handle() const override = 0; }; @@ -385,7 +417,7 @@ class PartExport GeomTrimmedCurve : public GeomBoundedCurve TYPESYSTEM_HEADER_WITH_OVERRIDE(); public: GeomTrimmedCurve(); - GeomTrimmedCurve(const Handle(Geom_TrimmedCurve)&); + explicit GeomTrimmedCurve(const Handle(Geom_TrimmedCurve)&); ~GeomTrimmedCurve() override; Geometry *copy() const override; @@ -394,9 +426,11 @@ public: void Save(Base::Writer &/*writer*/) const override; void Restore(Base::XMLReader &/*reader*/) override; // Base implementer ---------------------------- - PyObject *getPyObject() override; + PyObject *getPyObject(void) override; - void setHandle(const Handle(Geom_TrimmedCurve)&); + bool isSame(const Geometry &other, double tol, double atol) const override; + + virtual void setHandle(const Handle(Geom_TrimmedCurve)&); const Handle(Geom_Geometry)& handle() const override; bool intersectBasisCurves( const GeomTrimmedCurve * c, @@ -467,7 +501,7 @@ class PartExport GeomCircle : public GeomConic TYPESYSTEM_HEADER_WITH_OVERRIDE(); public: GeomCircle(); - GeomCircle(const Handle(Geom_Circle)&); + explicit GeomCircle(const Handle(Geom_Circle)&); ~GeomCircle() override; Geometry *copy() const override; @@ -482,6 +516,8 @@ public: PyObject *getPyObject() override; GeomBSplineCurve* toNurbs(double first, double last) const override; + bool isSame(const Geometry &other, double tol, double atol) const override; + const Handle(Geom_Geometry)& handle() const override; void setHandle(const Handle(Geom_Circle)&); @@ -495,7 +531,7 @@ class PartExport GeomArcOfCircle : public GeomArcOfConic TYPESYSTEM_HEADER_WITH_OVERRIDE(); public: GeomArcOfCircle(); - GeomArcOfCircle(const Handle(Geom_Circle)&); + explicit GeomArcOfCircle(const Handle(Geom_Circle)&); ~GeomArcOfCircle() override; Geometry *copy() const override; @@ -515,7 +551,7 @@ public: PyObject *getPyObject() override; GeomBSplineCurve* toNurbs(double first, double last) const override; - void setHandle(const Handle(Geom_TrimmedCurve)&); + void setHandle(const Handle(Geom_TrimmedCurve)&) override; void setHandle(const Handle(Geom_Circle)&); const Handle(Geom_Geometry)& handle() const override; @@ -526,7 +562,7 @@ class PartExport GeomEllipse : public GeomConic TYPESYSTEM_HEADER_WITH_OVERRIDE(); public: GeomEllipse(); - GeomEllipse(const Handle(Geom_Ellipse)&); + explicit GeomEllipse(const Handle(Geom_Ellipse)&); ~GeomEllipse() override; Geometry *copy() const override; @@ -546,6 +582,8 @@ public: PyObject *getPyObject() override; GeomBSplineCurve* toNurbs(double first, double last) const override; + bool isSame(const Geometry &other, double tol, double atol) const override; + void setHandle(const Handle(Geom_Ellipse) &e); const Handle(Geom_Geometry)& handle() const override; @@ -558,7 +596,7 @@ class PartExport GeomArcOfEllipse : public GeomArcOfConic TYPESYSTEM_HEADER_WITH_OVERRIDE(); public: GeomArcOfEllipse(); - GeomArcOfEllipse(const Handle(Geom_Ellipse)&); + explicit GeomArcOfEllipse(const Handle(Geom_Ellipse)&); ~GeomArcOfEllipse() override; Geometry *copy() const override; @@ -581,7 +619,7 @@ public: PyObject *getPyObject() override; GeomBSplineCurve* toNurbs(double first, double last) const override; - void setHandle(const Handle(Geom_TrimmedCurve)&); + void setHandle(const Handle(Geom_TrimmedCurve)&) override; void setHandle(const Handle(Geom_Ellipse)&); const Handle(Geom_Geometry)& handle() const override; }; @@ -592,7 +630,7 @@ class PartExport GeomHyperbola : public GeomConic TYPESYSTEM_HEADER_WITH_OVERRIDE(); public: GeomHyperbola(); - GeomHyperbola(const Handle(Geom_Hyperbola)&); + explicit GeomHyperbola(const Handle(Geom_Hyperbola)&); ~GeomHyperbola() override; Geometry *copy() const override; @@ -609,6 +647,8 @@ public: PyObject *getPyObject() override; GeomBSplineCurve* toNurbs(double first, double last) const override; + bool isSame(const Geometry &other, double tol, double atol) const override; + const Handle(Geom_Geometry)& handle() const override; void setHandle(const Handle(Geom_Hyperbola)&); @@ -621,7 +661,7 @@ class PartExport GeomArcOfHyperbola : public GeomArcOfConic TYPESYSTEM_HEADER_WITH_OVERRIDE(); public: GeomArcOfHyperbola(); - GeomArcOfHyperbola(const Handle(Geom_Hyperbola)&); + explicit GeomArcOfHyperbola(const Handle(Geom_Hyperbola)&); ~GeomArcOfHyperbola() override; Geometry *copy() const override; @@ -644,7 +684,7 @@ public: PyObject *getPyObject() override; GeomBSplineCurve* toNurbs(double first, double last) const override; - void setHandle(const Handle(Geom_TrimmedCurve)&); + void setHandle(const Handle(Geom_TrimmedCurve)&) override; void setHandle(const Handle(Geom_Hyperbola)&); const Handle(Geom_Geometry)& handle() const override; }; @@ -654,7 +694,7 @@ class PartExport GeomParabola : public GeomConic TYPESYSTEM_HEADER_WITH_OVERRIDE(); public: GeomParabola(); - GeomParabola(const Handle(Geom_Parabola)&); + explicit GeomParabola(const Handle(Geom_Parabola)&); ~GeomParabola() override; Geometry *copy() const override; @@ -669,6 +709,8 @@ public: PyObject *getPyObject() override; GeomBSplineCurve* toNurbs(double first, double last) const override; + bool isSame(const Geometry &other, double tol, double atol) const override; + const Handle(Geom_Geometry)& handle() const override; void setHandle(const Handle(Geom_Parabola)&); @@ -681,7 +723,7 @@ class PartExport GeomArcOfParabola : public GeomArcOfConic TYPESYSTEM_HEADER_WITH_OVERRIDE(); public: GeomArcOfParabola(); - GeomArcOfParabola(const Handle(Geom_Parabola)&); + explicit GeomArcOfParabola(const Handle(Geom_Parabola)&); ~GeomArcOfParabola() override; Geometry *copy() const override; @@ -701,7 +743,7 @@ public: PyObject *getPyObject() override; GeomBSplineCurve* toNurbs(double first, double last) const override; - void setHandle(const Handle(Geom_TrimmedCurve)&); + void setHandle(const Handle(Geom_TrimmedCurve)&) override; void setHandle(const Handle(Geom_Parabola)&); const Handle(Geom_Geometry)& handle() const override; }; @@ -711,7 +753,7 @@ class PartExport GeomLine : public GeomCurve TYPESYSTEM_HEADER_WITH_OVERRIDE(); public: GeomLine(); - GeomLine(const Handle(Geom_Line)&); + explicit GeomLine(const Handle(Geom_Line)&); GeomLine(const Base::Vector3d& Pos, const Base::Vector3d& Dir); ~GeomLine() override; Geometry *copy() const override; @@ -727,6 +769,8 @@ public: // Base implementer ---------------------------- PyObject *getPyObject() override; + bool isSame(const Geometry &other, double tol, double atol) const override; + const Handle(Geom_Geometry)& handle() const override; void setHandle(const Handle(Geom_Line)&); @@ -739,7 +783,7 @@ class PartExport GeomLineSegment : public GeomTrimmedCurve TYPESYSTEM_HEADER_WITH_OVERRIDE(); public: GeomLineSegment(); - GeomLineSegment(const Handle(Geom_Line)& l); + explicit GeomLineSegment(const Handle(Geom_Line)& l); ~GeomLineSegment() override; Geometry *copy() const override; @@ -756,7 +800,7 @@ public: // Base implementer ---------------------------- PyObject *getPyObject() override; - void setHandle(const Handle(Geom_TrimmedCurve)&); + void setHandle(const Handle(Geom_TrimmedCurve)&) override; void setHandle(const Handle(Geom_Line)&); const Handle(Geom_Geometry)& handle() const override; @@ -769,10 +813,13 @@ public: GeomOffsetCurve(); GeomOffsetCurve(const Handle(Geom_Curve)&, double, const gp_Dir&); GeomOffsetCurve(const Handle(Geom_Curve)&, double, Base::Vector3d&); - GeomOffsetCurve(const Handle(Geom_OffsetCurve)&); + explicit GeomOffsetCurve(const Handle(Geom_OffsetCurve)&); ~GeomOffsetCurve() override; Geometry *copy() const override; + Base::Vector3d getDir() const; + double getOffset() const; + // Persistence implementer --------------------- unsigned int getMemSize() const override; void Save(Base::Writer &/*writer*/) const override; @@ -780,6 +827,8 @@ public: // Base implementer ---------------------------- PyObject *getPyObject() override; + bool isSame(const Geometry &other, double tol, double atol) const override; + void setHandle(const Handle(Geom_OffsetCurve)& c); const Handle(Geom_Geometry)& handle() const override; @@ -787,6 +836,8 @@ private: Handle(Geom_OffsetCurve) myCurve; }; +class GeomPlane; + class PartExport GeomSurface : public Geometry { TYPESYSTEM_HEADER_WITH_OVERRIDE(); @@ -801,7 +852,13 @@ public: GeomSurface(); ~GeomSurface() override; + static bool isPlanar(const Handle(Geom_Surface) &s, gp_Pln *pln=nullptr, double tol=1e-7); + bool isPlanar(gp_Pln *pln=nullptr, double tol=1e-7) const; + TopoDS_Shape toShape() const override; + + GeomPlane *toPlane(bool clone=true, double tol=1e-7) const; + bool tangentU(double u, double v, gp_Dir& dirU) const; bool tangentV(double u, double v, gp_Dir& dirV) const; bool normal(double u, double v, gp_Dir& dir) const; @@ -824,7 +881,7 @@ class PartExport GeomBezierSurface : public GeomSurface TYPESYSTEM_HEADER_WITH_OVERRIDE(); public: GeomBezierSurface(); - GeomBezierSurface(const Handle(Geom_BezierSurface)&); + explicit GeomBezierSurface(const Handle(Geom_BezierSurface)&); ~GeomBezierSurface() override; Geometry *copy() const override; @@ -835,6 +892,8 @@ public: // Base implementer ---------------------------- PyObject *getPyObject() override; + bool isSame(const Geometry &other, double tol, double atol) const override; + void setHandle(const Handle(Geom_BezierSurface)& b); const Handle(Geom_Geometry)& handle() const override; @@ -847,7 +906,7 @@ class PartExport GeomBSplineSurface : public GeomSurface TYPESYSTEM_HEADER_WITH_OVERRIDE(); public: GeomBSplineSurface(); - GeomBSplineSurface(const Handle(Geom_BSplineSurface)&); + explicit GeomBSplineSurface(const Handle(Geom_BSplineSurface)&); ~GeomBSplineSurface() override; Geometry *copy() const override; @@ -859,6 +918,8 @@ public: // Base implementer ---------------------------- PyObject *getPyObject() override; + bool isSame(const Geometry &other, double tol, double atol) const override; + void setHandle(const Handle(Geom_BSplineSurface)&); const Handle(Geom_Geometry)& handle() const override; @@ -866,12 +927,30 @@ private: Handle(Geom_BSplineSurface) mySurface; }; -class PartExport GeomCylinder : public GeomSurface +class PartExport GeomElementarySurface : public GeomSurface +{ + TYPESYSTEM_HEADER_WITH_OVERRIDE(); + +protected: + GeomElementarySurface(); + +public: + ~GeomElementarySurface() override; + + Base::Vector3d getLocation() const; + Base::Vector3d getDir() const; + Base::Vector3d getXDir() const; + Base::Vector3d getYDir() const; + + bool isSame(const Geometry &other, double tol, double atol) const override; +}; + +class PartExport GeomCylinder : public GeomElementarySurface { TYPESYSTEM_HEADER_WITH_OVERRIDE(); public: GeomCylinder(); - GeomCylinder(const Handle(Geom_CylindricalSurface)&); + explicit GeomCylinder(const Handle(Geom_CylindricalSurface)&); ~GeomCylinder() override; Geometry *copy() const override; @@ -882,6 +961,10 @@ public: // Base implementer ---------------------------- PyObject *getPyObject() override; + double getRadius() const; + + bool isSame(const Geometry &other, double tol, double atol) const override; + void setHandle(const Handle(Geom_CylindricalSurface)&); const Handle(Geom_Geometry)& handle() const override; @@ -889,12 +972,12 @@ private: Handle(Geom_CylindricalSurface) mySurface; }; -class PartExport GeomCone : public GeomSurface +class PartExport GeomCone : public GeomElementarySurface { TYPESYSTEM_HEADER_WITH_OVERRIDE(); public: GeomCone(); - GeomCone(const Handle(Geom_ConicalSurface)&); + explicit GeomCone(const Handle(Geom_ConicalSurface)&); ~GeomCone() override; Geometry *copy() const override; @@ -905,6 +988,11 @@ public: // Base implementer ---------------------------- PyObject *getPyObject() override; + double getRadius() const; + double getSemiAngle() const; + + bool isSame(const Geometry &other, double tol, double atol) const override; + void setHandle(const Handle(Geom_ConicalSurface)&); const Handle(Geom_Geometry)& handle() const override; @@ -915,12 +1003,12 @@ private: Handle(Geom_ConicalSurface) mySurface; }; -class PartExport GeomSphere : public GeomSurface +class PartExport GeomSphere : public GeomElementarySurface { TYPESYSTEM_HEADER_WITH_OVERRIDE(); public: GeomSphere(); - GeomSphere(const Handle(Geom_SphericalSurface)&); + explicit GeomSphere(const Handle(Geom_SphericalSurface)&); ~GeomSphere() override; Geometry *copy() const override; @@ -931,6 +1019,10 @@ public: // Base implementer ---------------------------- PyObject *getPyObject() override; + double getRadius(void) const; + + bool isSame(const Geometry &other, double tol, double atol) const override; + void setHandle(const Handle(Geom_SphericalSurface)&); const Handle(Geom_Geometry)& handle() const override; @@ -938,12 +1030,12 @@ private: Handle(Geom_SphericalSurface) mySurface; }; -class PartExport GeomToroid : public GeomSurface +class PartExport GeomToroid : public GeomElementarySurface { TYPESYSTEM_HEADER_WITH_OVERRIDE(); public: GeomToroid(); - GeomToroid(const Handle(Geom_ToroidalSurface)&); + explicit GeomToroid(const Handle(Geom_ToroidalSurface)&); ~GeomToroid() override; Geometry *copy() const override; @@ -954,6 +1046,11 @@ public: // Base implementer ---------------------------- PyObject *getPyObject() override; + double getMajorRadius() const; + double getMinorRadius() const; + + bool isSame(const Geometry &other, double tol, double atol) const override; + void setHandle(const Handle(Geom_ToroidalSurface)&); const Handle(Geom_Geometry)& handle() const override; @@ -961,12 +1058,13 @@ private: Handle(Geom_ToroidalSurface) mySurface; }; -class PartExport GeomPlane : public GeomSurface +class PartExport GeomPlane : public GeomElementarySurface { TYPESYSTEM_HEADER_WITH_OVERRIDE(); public: GeomPlane(); - GeomPlane(const Handle(Geom_Plane)&); + explicit GeomPlane(const Handle(Geom_Plane)&); + explicit GeomPlane(const gp_Pln &pln); ~GeomPlane() override; Geometry *copy() const override; @@ -977,6 +1075,8 @@ public: // Base implementer ---------------------------- PyObject *getPyObject() override; + bool isSame(const Geometry &other, double tol, double atol) const override; + void setHandle(const Handle(Geom_Plane)&); const Handle(Geom_Geometry)& handle() const override; @@ -990,7 +1090,7 @@ class PartExport GeomOffsetSurface : public GeomSurface public: GeomOffsetSurface(); GeomOffsetSurface(const Handle(Geom_Surface)&, double); - GeomOffsetSurface(const Handle(Geom_OffsetSurface)&); + explicit GeomOffsetSurface(const Handle(Geom_OffsetSurface)&); ~GeomOffsetSurface() override; Geometry *copy() const override; @@ -1001,6 +1101,10 @@ public: // Base implementer ---------------------------- PyObject *getPyObject() override; + double getOffset() const; + + bool isSame(const Geometry &other, double tol, double atol) const override; + void setHandle(const Handle(Geom_OffsetSurface)& s); const Handle(Geom_Geometry)& handle() const override; @@ -1014,8 +1118,8 @@ class PartExport GeomPlateSurface : public GeomSurface public: GeomPlateSurface(); GeomPlateSurface(const Handle(Geom_Surface)&, const Plate_Plate&); - GeomPlateSurface(const GeomPlate_BuildPlateSurface&); - GeomPlateSurface(const Handle(GeomPlate_Surface)&); + explicit GeomPlateSurface(const GeomPlate_BuildPlateSurface&); + explicit GeomPlateSurface(const Handle(GeomPlate_Surface)&); ~GeomPlateSurface() override; Geometry *copy() const override; @@ -1026,6 +1130,8 @@ public: // Base implementer ---------------------------- PyObject *getPyObject() override; + bool isSame(const Geometry &other, double tol, double atol) const override; + void setHandle(const Handle(GeomPlate_Surface)& s); const Handle(Geom_Geometry)& handle() const override; @@ -1038,7 +1144,7 @@ class PartExport GeomTrimmedSurface : public GeomSurface TYPESYSTEM_HEADER_WITH_OVERRIDE(); public: GeomTrimmedSurface(); - GeomTrimmedSurface(const Handle(Geom_RectangularTrimmedSurface)&); + explicit GeomTrimmedSurface(const Handle(Geom_RectangularTrimmedSurface)&); ~GeomTrimmedSurface() override; Geometry *copy() const override; @@ -1049,6 +1155,8 @@ public: // Base implementer ---------------------------- PyObject *getPyObject() override; + bool isSame(const Geometry &other, double tol, double atol) const override; + void setHandle(const Handle(Geom_RectangularTrimmedSurface)& s); const Handle(Geom_Geometry)& handle() const override; @@ -1056,13 +1164,28 @@ private: Handle(Geom_RectangularTrimmedSurface) mySurface; }; -class PartExport GeomSurfaceOfRevolution : public GeomSurface +class PartExport GeomSweptSurface : public GeomSurface +{ + TYPESYSTEM_HEADER_WITH_OVERRIDE(); + +protected: + GeomSweptSurface(); + +public: + ~GeomSweptSurface() override; + + Base::Vector3d getDir() const; + bool isSame(const Geometry &other, double tol, double atol) const override; +}; + + +class PartExport GeomSurfaceOfRevolution : public GeomSweptSurface { TYPESYSTEM_HEADER_WITH_OVERRIDE(); public: GeomSurfaceOfRevolution(); GeomSurfaceOfRevolution(const Handle(Geom_Curve)&, const gp_Ax1&); - GeomSurfaceOfRevolution(const Handle(Geom_SurfaceOfRevolution)&); + explicit GeomSurfaceOfRevolution(const Handle(Geom_SurfaceOfRevolution)&); ~GeomSurfaceOfRevolution() override; Geometry *copy() const override; @@ -1080,7 +1203,7 @@ private: Handle(Geom_SurfaceOfRevolution) mySurface; }; -class PartExport GeomSurfaceOfExtrusion : public GeomSurface +class PartExport GeomSurfaceOfExtrusion : public GeomSweptSurface { TYPESYSTEM_HEADER_WITH_OVERRIDE(); public: @@ -1127,16 +1250,19 @@ PartExport GeomArcOfCircle *createFilletGeometry(const GeomLineSegment *lineSeg1, const GeomLineSegment *lineSeg2, const Base::Vector3d ¢er, double radius); PartExport -std::unique_ptr makeFromSurface(const Handle(Geom_Surface)&); +std::unique_ptr makeFromSurface(const Handle(Geom_Surface)&, bool silent=false); PartExport -std::unique_ptr makeFromCurve(const Handle(Geom_Curve)&); + std::unique_ptr makeFromSurfaceAdaptor(const BRepAdaptor_Surface&, bool silent=false); PartExport -std::unique_ptr makeFromTrimmedCurve(const Handle(Geom_Curve)&, double f, double l); +std::unique_ptr makeFromCurve(const Handle(Geom_Curve)&, bool silent=false); PartExport -std::unique_ptr makeFromCurveAdaptor(const Adaptor3d_Curve&); +std::unique_ptr makeFromTrimmedCurve(const Handle(Geom_Curve)&, double f, double l, bool silent=false); + +PartExport +std::unique_ptr makeFromCurveAdaptor(const Adaptor3d_Curve&, bool silent=false); } #endif // PART_GEOMETRY_H diff --git a/src/Mod/Part/App/GeometryExtension.cpp b/src/Mod/Part/App/GeometryExtension.cpp index ba0feb760c..4ec85a08eb 100644 --- a/src/Mod/Part/App/GeometryExtension.cpp +++ b/src/Mod/Part/App/GeometryExtension.cpp @@ -78,3 +78,14 @@ void GeometryPersistenceExtension::Restore(Base::XMLReader &reader) { restoreAttributes(reader); } + +bool GeometryPersistenceExtension::isSame(const GeometryPersistenceExtension &other) const +{ + static Base::StringWriter writer,writer2; +// writer.clear(); + Save(writer); +// writer2.clear(); + other.Save(writer2); + return writer.getString() == writer2.getString(); +} + diff --git a/src/Mod/Part/App/GeometryExtension.h b/src/Mod/Part/App/GeometryExtension.h index 0626603020..1bf314adb3 100644 --- a/src/Mod/Part/App/GeometryExtension.h +++ b/src/Mod/Part/App/GeometryExtension.h @@ -75,6 +75,8 @@ public: void Save(Base::Writer &/*writer*/) const; void Restore(Base::XMLReader &/*reader*/); + bool isSame(const GeometryPersistenceExtension &other) const; + protected: virtual void restoreAttributes(Base::XMLReader &/*reader*/); virtual void saveAttributes(Base::Writer &writer) const;