diff --git a/src/Mod/Sketcher/App/GeometryFacade.cpp b/src/Mod/Sketcher/App/GeometryFacade.cpp index ff8c73ed08..e86baed471 100644 --- a/src/Mod/Sketcher/App/GeometryFacade.cpp +++ b/src/Mod/Sketcher/App/GeometryFacade.cpp @@ -103,15 +103,24 @@ void GeometryFacade::initExtension() void GeometryFacade::initExtension() const { // const Geometry without SketchGeometryExtension cannot initialise a GeometryFacade - assert(Geo->hasExtension(SketchGeometryExtension::getClassTypeId())); + if(!Geo->hasExtension(SketchGeometryExtension::getClassTypeId())) + THROWM(Base::ValueError, "Cannot create a GeometryFacade out of a const Geometry pointer not having a SketchGeometryExtension!"); auto ext = std::static_pointer_cast(Geo->getExtension(SketchGeometryExtension::getClassTypeId()).lock()); const_cast(this)->SketchGeoExtension = ext; } +void GeometryFacade::throwOnNullPtr(const Part::Geometry * geo) +{ + if(geo == nullptr) + THROWM(Base::ValueError, "Geometry is nullptr!"); +} + void GeometryFacade::ensureSketchGeometryExtension(Part::Geometry * geometry) { + throwOnNullPtr(geometry); + if(!geometry->hasExtension(SketchGeometryExtension::getClassTypeId())) { geometry->setExtension(std::make_unique()); // Create getExtension } @@ -119,6 +128,9 @@ void GeometryFacade::ensureSketchGeometryExtension(Part::Geometry * geometry) void GeometryFacade::copyId(const Part::Geometry * src, Part::Geometry * dst) { + throwOnNullPtr(src); + throwOnNullPtr(dst); + auto gfsrc = GeometryFacade::getFacade(src); auto gfdst = GeometryFacade::getFacade(dst); gfdst->setId(gfsrc->getId()); @@ -126,24 +138,32 @@ void GeometryFacade::copyId(const Part::Geometry * src, Part::Geometry * dst) bool GeometryFacade::getConstruction(const Part::Geometry * geometry) { + throwOnNullPtr(geometry); + auto gf = GeometryFacade::getFacade(geometry); return gf->getConstruction(); } void GeometryFacade::setConstruction(Part::Geometry * geometry, bool construction) { + throwOnNullPtr(geometry); + auto gf = GeometryFacade::getFacade(geometry); return gf->setConstruction(construction); } bool GeometryFacade::isInternalType(const Part::Geometry * geometry, InternalType::InternalType type) { + throwOnNullPtr(geometry); + auto gf = GeometryFacade::getFacade(geometry); return gf->getInternalType() == type; } bool GeometryFacade::getBlocked(const Part::Geometry * geometry) { + throwOnNullPtr(geometry); + auto gf = GeometryFacade::getFacade(geometry); return gf->getBlocked(); } diff --git a/src/Mod/Sketcher/App/GeometryFacade.h b/src/Mod/Sketcher/App/GeometryFacade.h index abe021e343..4ca789bdbb 100644 --- a/src/Mod/Sketcher/App/GeometryFacade.h +++ b/src/Mod/Sketcher/App/GeometryFacade.h @@ -36,65 +36,73 @@ namespace Sketcher { class GeometryFacadePy; -// This class is a Facade to handle geometry and sketcher geometry extensions with a single sketcher specific interface -// -// The facade privately inherits from a common interface it shares with the extension thereby implementing a compiler enforced -// same interface as the extension. It does not inherit from Part::Geometry and thus is intended to provide, in part a convenience -// subset of the interface of Part::Geometry, in part a different interface. -// -// GeometryFacade has private constructors and objects may only be created using the getFacade factory methods. -// -// There is a version of getFacade taking a const Part::Geometry and producing a const GeometryFacade, and a non-const -// version producing a non-const GeometryFacade. So constness of the Part::Geometry object is preserved by the GeometryFacade -// container. -// -// The const factory method will throw if the geometry does not have a SketchGeometryExtension (being const, it commits not to -// create one and modify the const Part::Geometry object). The non-const factory method will create the extension if not existing. -// -// There are some static convenience utility functions to simplify common operations such as ID copy or to ensure that a geometry -// object has the extension (creating the extension if not existing). -// -// A simple usage example: -// -// const std::vector< Part::Geometry * > &vals = getInternalGeometry(); -// auto gf = GeometryFacade::getFacade(vals[GeoId]); -// id = gf->getId(); -// -// An example of static Id utility function -// -// const Part::Geometry *geo = getGeometry(GeoId); -// ... -// std::unique_ptr bspline(new Part::GeomBSplineCurve(curve)); -// ... -// -// Part::GeomBSplineCurve * gbsc = bspline.release(); -// GeometryFacade::copyId(geo, gbsc); -// -// Examples getting and setting the construction stations without creating a Facade: -// -// if ((*geo) && GeometryFacade::getConstruction(*geo) && -// (*geo)->getTypeId() == Part::GeomLineSegment::getClassTypeId()) -// count++; -// -// Part::Geometry* copy = v->copy(); -// -// if(construction && copy->getTypeId() != Part::GeomPoint::getClassTypeId()) { -// GeometryFacade::setConstruction(copy, construction); -// } -// -// -// Note: The standard GeometryFacade stores Part::Geometry derived classes as a Part::Geometry *, while -// it has the ability to return a dynamic_cast-ed version to a provided type as follows: -// -// HLine->getGeometry(); -// -// If for seamless operation it is convenient to have a given derived class of Part::Geometry, it is possible -// to use GeometryTypedFacade (see below). -// -// Summary Remarks: -// It is intended to have a separate type (not being a Geometry type). -// it is intended to have the relevant interface in full for the sketcher extension only -// It is intended to work on borrowed memory allocation. +/** @brief This class is a Facade to handle geometry and sketcher geometry extensions with a single sketcher specific interface + * + * @details + * The facade privately inherits from a common interface it shares with the extension thereby implementing a compiler enforced + * same interface as the extension. It does not inherit from Part::Geometry and thus is intended to provide, in part a convenience + * subset of the interface of Part::Geometry, in part a different interface. + * + * GeometryFacade has private constructors and objects may only be created using the getFacade factory methods. + * + * There is a version of getFacade taking a const Part::Geometry and producing a const GeometryFacade, and a non-const + * version producing a non-const GeometryFacade. So constness of the Part::Geometry object is preserved by the GeometryFacade + * container. + * + * There are some static convenience utility functions to simplify common operations such as ID copy or to ensure that a geometry + * object has the extension (creating the extension if not existing). + * + * @warning + * The const factory method will throw if the geometry does not have a SketchGeometryExtension (being const, it commits not to + * create one and modify the const Part::Geometry object). The non-const factory method will create the extension if not existing. + * + * @warning + * If the Geometry Pointer fed into the factory method is a nullptr, a nullptr GeometryFacade is created. It should not be possible + * to create a GeometryFacade having a Part::Geometry * being a nullptr. + * + * A simple usage example: + * + * const std::vector< Part::Geometry * > &vals = getInternalGeometry(); + * auto gf = GeometryFacade::getFacade(vals[GeoId]); + * id = gf->getId(); + * + * An example of static Id utility function + * + * const Part::Geometry *geo = getGeometry(GeoId); + * ... + * std::unique_ptr bspline(new Part::GeomBSplineCurve(curve)); + * ... + * + * Part::GeomBSplineCurve * gbsc = bspline.release(); + * GeometryFacade::copyId(geo, gbsc); + * + * Examples getting and setting the construction stations without creating a Facade: + * + * if ((*geo) && GeometryFacade::getConstruction(*geo) && + * (*geo)->getTypeId() == Part::GeomLineSegment::getClassTypeId()) + * count++; + * + * Part::Geometry* copy = v->copy(); + * + * if(construction && copy->getTypeId() != Part::GeomPoint::getClassTypeId()) { + * GeometryFacade::setConstruction(copy, construction); + * } + * + * Note: The standard GeometryFacade stores Part::Geometry derived classes as a Part::Geometry *, while + * it has the ability to return a dynamic_cast-ed version to a provided type as follows: + * + * HLine->getGeometry(); + * + * If for seamless operation it is convenient to have a given derived class of Part::Geometry, it is possible + * to use GeometryTypedFacade (see below). + * + * @remarks + * Summary Remarks: + * It is intended to have a separate type (not being a Geometry type). + * it is intended to have the relevant interface in full for the sketcher extension only + * It is intended to work on borrowed memory allocation. But the getFacade has an owner parameter to take ownership of the + * geometry pointer if that is intended (this can also be achieved via the setOwner method once created). + */ class SketcherExport GeometryFacade : public Base::BaseClass, private ISketchGeometryExtension { TYPESYSTEM_HEADER_WITH_OVERRIDE(); @@ -216,6 +224,8 @@ private: std::shared_ptr getGeoExt(void) const {return SketchGeoExtension;} std::shared_ptr getGeoExt (void) {return std::const_pointer_cast(SketchGeoExtension);} + static void throwOnNullPtr(const Part::Geometry * geo); + private: const Part::Geometry * Geo; bool OwnerGeo; @@ -227,39 +237,42 @@ private: /////////////////////////////////////////////////////////////////////////////////////// // // GeometryTypedFacade -// -// It provides all the funcionality of GeometryFacade (derives from it), but in addition -// allows to indicate the type of a Part::Geometry derived class. -// -// auto HLineF = GeometryTypedFacade::getTypedFacade(HLine); -// -// Then it is possible to get the typed geometry directly via: -// -// HLine->getTypedGeometry()->setPoints(Base::Vector3d(0,0,0),Base::Vector3d(1,0,0)); -// -// If a facade is requested without passing an Part::Geometry derived object, the constructor -// of the indicated geometry type is called with any parameter passed as argument (emplace style) -// -// Example of seamless operation with a GeomLineSegment: -// -// auto HLine = GeometryTypedFacade::getTypedFacade(); -// HLine->getTypedGeometry()->setPoints(Base::Vector3d(0,0,0),Base::Vector3d(1,0,0)); -// HLine->setConstruction(true); -// ExternalGeo.push_back(HLine->getGeometry()); +/** @brief It provides all the funcionality of GeometryFacade (derives from it), but in addition + * allows to indicate the type of a Part::Geometry derived class. + * + * @details + * + * auto HLineF = GeometryTypedFacade::getTypedFacade(HLine); + * + * Then it is possible to get the typed geometry directly via: + * + * HLine->getTypedGeometry()->setPoints(Base::Vector3d(0,0,0),Base::Vector3d(1,0,0)); + * + * If a facade is requested without passing an Part::Geometry derived object, the constructor + * of the indicated geometry type is called with any parameter passed as argument (emplace style). In + * this case the facade takes ownership of the newly created Part::Geometry object. + * + * Example of seamless operation with a GeomLineSegment: + * + * auto HLine = GeometryTypedFacade::getTypedFacade(); + * HLine->getTypedGeometry()->setPoints(Base::Vector3d(0,0,0),Base::Vector3d(1,0,0)); + * HLine->setConstruction(true); + * ExternalGeo.push_back(HLine->getGeometry()); + */ template < typename GeometryT > class SketcherExport GeometryTypedFacade : public GeometryFacade { static_assert( std::is_base_of::type>::value && !std::is_same::type>::value, "Only for classes derived from Geometry!"); private: - GeometryTypedFacade(const Part::Geometry * geometry):GeometryFacade(geometry) {} + GeometryTypedFacade(const Part::Geometry * geometry, bool owner = false):GeometryFacade(geometry, owner) {} GeometryTypedFacade():GeometryFacade() {} public: // Factory methods - static std::unique_ptr> getTypedFacade(GeometryT * geometry) { + static std::unique_ptr> getTypedFacade(GeometryT * geometry, bool owner = false) { if(geometry != nullptr) - return std::unique_ptr>(new GeometryTypedFacade(geometry)); + return std::unique_ptr>(new GeometryTypedFacade(geometry, owner)); else return std::unique_ptr>(nullptr); } @@ -270,9 +283,10 @@ public: // Factory methods return std::unique_ptr>(nullptr); } + // This function takes direct ownership of the object it creates. template < typename... Args > static std::unique_ptr> getTypedFacade(Args&&... args) { - return GeometryTypedFacade::getTypedFacade(new GeometryT(std::forward(args)...)); + return GeometryTypedFacade::getTypedFacade(new GeometryT(std::forward(args)...), true); } // Geometry Element