diff --git a/src/Mod/Sketcher/App/CMakeLists.txt b/src/Mod/Sketcher/App/CMakeLists.txt index c934e31fe5..3436e230ed 100644 --- a/src/Mod/Sketcher/App/CMakeLists.txt +++ b/src/Mod/Sketcher/App/CMakeLists.txt @@ -73,6 +73,8 @@ SET(Datatypes_SRCS Constraint.h Sketch.cpp Sketch.h + GeoList.h + GeoList.cpp GeometryFacade.cpp GeometryFacade.h ExternalGeometryFacade.cpp diff --git a/src/Mod/Sketcher/App/GeoList.cpp b/src/Mod/Sketcher/App/GeoList.cpp new file mode 100644 index 0000000000..6b668515e1 --- /dev/null +++ b/src/Mod/Sketcher/App/GeoList.cpp @@ -0,0 +1,273 @@ +/*************************************************************************** + * Copyright (c) 2021 Abdullah Tahiri * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" + +#ifndef _PreComp_ + +#endif // #ifndef _PreComp_ + +#include + +#include + +#include + +#include + +#include "GeoList.h" + +using namespace Sketcher; + +// Vector is moved +template +GeoListModel::GeoListModel( std::vector && geometrylist, + int intgeocount, + bool ownerT): geomlist(std::move(geometrylist)), + intGeoCount(intgeocount), + OwnerT(ownerT) +{ + +} + +// Vector is shallow copied (copy constructed) +template +GeoListModel::GeoListModel( const std::vector & geometrylist, + int intgeocount, + bool ownerT): geomlist(geometrylist), // copy constructed here + intGeoCount(intgeocount), + OwnerT(ownerT) +{ + +} + +template +GeoListModel::~GeoListModel() +{ + if(OwnerT) { + for(auto & g : geomlist) + delete g; + } +} + +template +GeoListModel GeoListModel::getGeoListModel(std::vector && geometrylist, int intgeocount, bool ownerT) +{ + return GeoListModel(std::move(geometrylist), intgeocount, ownerT); +} + +template +const GeoListModel GeoListModel::getGeoListModel(const std::vector &geometrylist, int intgeocount, bool ownerT) +{ + return GeoListModel(geometrylist, intgeocount, ownerT); +} + + +template +int GeoListModel::getGeoIdFromGeomListIndex(int index) const +{ + assert(index < int(geomlist.size())); + + if(index < intGeoCount) + return index; + else + return -( index - intGeoCount); +} + +template +const T GeoListModel::getGeometryFromGeoId(const std::vector & geometrylist, int geoId) +{ + if (geoId >= 0) + return geometrylist[geoId]; + else + return geometrylist[geometrylist.size()+geoId]; +} + +// this function is used to simulate cyclic periodic negative geometry indices (for external geometry) +template +const T GeoListModel::getGeometryFromGeoId(int geoId) const +{ + return GeoListModel::getGeometryFromGeoId(geomlist, geoId); +} + +template +Base::Vector3d GeoListModel::getPoint(int geoId, Sketcher::PointPos pos) const +{ + Part::Geometry * geo = getGeometryFromGeoId(geoId); + + return getPoint(geo, pos); +} + +template +Base::Vector3d GeoListModel::getPoint(const Part::Geometry * geo, Sketcher::PointPos pos) const +{ + using namespace Sketcher; + + if (geo->getTypeId() == Part::GeomPoint::getClassTypeId()) { + const Part::GeomPoint *p = static_cast(geo); + if (pos == start || pos == mid || pos == end) + return p->getPoint(); + } else if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { + const Part::GeomLineSegment *lineSeg = static_cast(geo); + if (pos == start) + return lineSeg->getStartPoint(); + else if (pos == end) + return lineSeg->getEndPoint(); + } else if (geo->getTypeId() == Part::GeomCircle::getClassTypeId()) { + const Part::GeomCircle *circle = static_cast(geo); + if (pos == mid) + return circle->getCenter(); + } else if (geo->getTypeId() == Part::GeomEllipse::getClassTypeId()) { + const Part::GeomEllipse *ellipse = static_cast(geo); + if (pos == mid) + return ellipse->getCenter(); + } else if (geo->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) { + const Part::GeomArcOfCircle *aoc = static_cast(geo); + if (pos == start) + return aoc->getStartPoint(/*emulateCCW=*/true); + else if (pos == end) + return aoc->getEndPoint(/*emulateCCW=*/true); + else if (pos == mid) + return aoc->getCenter(); + } else if (geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) { + const Part::GeomArcOfEllipse *aoc = static_cast(geo); + if (pos == start) + return aoc->getStartPoint(/*emulateCCW=*/true); + else if (pos == end) + return aoc->getEndPoint(/*emulateCCW=*/true); + else if (pos == mid) + return aoc->getCenter(); + } else if (geo->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId()) { + const Part::GeomArcOfHyperbola *aoh = static_cast(geo); + if (pos == start) + return aoh->getStartPoint(); + else if (pos == end) + return aoh->getEndPoint(); + else if (pos == mid) + return aoh->getCenter(); + } else if (geo->getTypeId() == Part::GeomArcOfParabola::getClassTypeId()) { + const Part::GeomArcOfParabola *aop = static_cast(geo); + if (pos == start) + return aop->getStartPoint(); + else if (pos == end) + return aop->getEndPoint(); + else if (pos == mid) + return aop->getCenter(); + } else if (geo->getTypeId() == Part::GeomBSplineCurve::getClassTypeId()) { + const Part::GeomBSplineCurve *bsp = static_cast(geo); + if (pos == start) + return bsp->getStartPoint(); + else if (pos == end) + return bsp->getEndPoint(); + } + + return Base::Vector3d(); +} + +namespace Sketcher { + +// Template specialisations +template <> +GeoListModel>::GeoListModel( + std::vector> && geometrylist, + int intgeocount, + bool ownerT) : geomlist(std::move(geometrylist)), + intGeoCount(intgeocount), + OwnerT(false) +{ + // GeometryFacades hold the responsibility for releasing the resources. + // + // This means that each GeometryFacade that is passed to the GeoListModel, + // must set the ownership (GF->setOwner(true)), if it should be the owner. + // Otherwise, it follows the default behaviour that some other class, which + // created the pointer, is responsible for freeing it. + // + // Under the Single Responsibility Principle GeoListModel cannot be made + // responsible for releasing those pointers. + assert(ownerT == false); +} + +template <> +GeoListModel>::GeoListModel( + const std::vector> & geometrylist, + int intgeocount, + bool ownerT): intGeoCount(intgeocount), + OwnerT(false) +{ + // GeometryFacades are movable, but not copiable, so they need to be reconstructed (shallow copy of vector) + // Under the Single Responsibility Principle, these will not take over a responsibility that shall be enforced + // on the original GeometryFacade. Use the move version of getGeoListModel if moving the responsibility is intended. + assert(ownerT == false); + + geomlist.reserve(geometrylist.size()); + + for(auto & v : geometrylist) { + geomlist.push_back(GeometryFacade::getFacade(v->getGeometry())); + } +} + +template <> +GeoListModel>::~GeoListModel() +{ + // GeometryFacade is responsible for taken ownership of its pointers and deleting them. + +} + +template < > +const std::unique_ptr +GeoListModel>::getGeometryFromGeoId + (const std::vector> & geometrylist, int geoId) +{ + if (geoId >= 0) + return Sketcher::GeometryFacade::getFacade(geometrylist[geoId]->getGeometry()); + else + return Sketcher::GeometryFacade::getFacade(geometrylist[geometrylist.size()+geoId]->getGeometry()); +} + +template < > +Base::Vector3d GeoListModel>::getPoint(int geoId, Sketcher::PointPos pos) const +{ + const Part::Geometry * geo = getGeometryFromGeoId(geoId)->getGeometry(); + + return getPoint(geo, pos); +} + +// instantiate the types so that other translation units can access template constructors +template class GeoListModel; +template class GeoListModel>; + + +} // namespace Sketcher + +GeoListFacade Sketcher::getGeoListFacade(const GeoList & geolist) +{ + std::vector> facade; + facade.reserve( geolist.geomlist.size()); + + for(auto geo : geolist.geomlist) + facade.push_back(GeometryFacade::getFacade(geo)); + + auto geolistfacade = GeoListFacade::getGeoListModel(std::move(facade), geolist.getInternalCount()); + + return geolistfacade; +} diff --git a/src/Mod/Sketcher/App/GeoList.h b/src/Mod/Sketcher/App/GeoList.h new file mode 100644 index 0000000000..515c1cd08b --- /dev/null +++ b/src/Mod/Sketcher/App/GeoList.h @@ -0,0 +1,166 @@ +/*************************************************************************** + * Copyright (c) 2021 Abdullah Tahiri * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#ifndef SKETCHER_GeoList_H +#define SKETCHER_GeoList_H + +#ifndef _PreComp_ + +#endif // #ifndef _PreComp_ + +#include +#include + +#include + +namespace Base { + template< typename T > + class Vector3; +} + +namespace Part { + class Geometry; +} + +namespace Sketcher { + enum PointPos : int; + + class GeometryFacade; +} + +namespace Sketcher { + +// TODO: This class is half-cooked and needs to be reviewed. Specially the const/non-const aspect +// as well as the ability to take ownership of deepcopied vectors. + +/** @brief Class for managing internal and external geometry as a single object + * @details + * Internal and external geometries are present in a single geometry vector one after the other. + * + * N.B.: Note that the index of the geomlist (all layers) and the GeoId can be converted + * from each other at needed using the member fuctions (and sometimes the statics). + */ +template +class GeoListModel { + using Vector3d = Base::Vector3; + + +protected: + /** + * Constructs the object from a list of geometry in geomlist format and the number of internal + * geometries (non external) present in the list. + * + * @param geometrylist: the geometry in geomlist format (external after internal in a single vector). + * @param intgeocount: the number of internal geometries (non external) in the list. + * @param ownerT: indicates whether the GeoListModel takes ownership of the elements of the std::vector (for pointers) + */ + explicit GeoListModel(std::vector && geometrylist, int intgeocount, bool ownerT = false); + + explicit GeoListModel(const std::vector & geometrylist, int intgeocount, bool ownerT = false); + +public: + ~GeoListModel(); + + // Explicit deletion to show intent (not that it is needed) + GeoListModel(const GeoListModel &) = delete; + GeoListModel& operator=(const GeoListModel&) = delete; + + // enable move syntaxis + GeoListModel(GeoListModel &&) = default; + GeoListModel& operator=(GeoListModel&&) = default; + + /** + * GeoListModel manages the lifetime of its internal std::vector. This means that while the actual ownership + * of the T parameter needs to be specified or separately handled, a new vector will be created and the T elements + * shallow copied to the internal vector. + * + * The constness of the GeoListModel is tied to the constness of the std::vector from which it is constructed, + * except when the vector is not const, but the user uses the factory method to create a const model. + */ + static GeoListModel getGeoListModel(std::vector && geometrylist, int intgeocount, bool ownerT = false); + static const GeoListModel getGeoListModel(const std::vector & geometrylist, int intgeocount, bool ownerT = false); + + + /** + * returns the geometry given by the GeoId + */ + const T getGeometryFromGeoId(int geoId) const; + + /** + * returns the GeoId index from the index in the geometry in geomlist format with which it was constructed. + * + * @param index: the index of the list of geometry in geomlist format. + */ + int getGeoIdFromGeomListIndex(int index) const; + + /** + * returns the geometry given by the GeoId in the geometrylist in geomlist format provided as a parameter. + * + * @param geometrylist: the geometry in geomlist format (external after internal in a single vector). + * + * @param index: the index of the list of geometry in geomlist format. + */ + static const T getGeometryFromGeoId(const std::vector & geometrylist, int geoId); + + + Vector3d getPoint(int geoId, Sketcher::PointPos pos) const; + + /** + * returns the amount of internal geometry objects. + */ + int getInternalCount() const { return intGeoCount;} + + /** + * returns the amount of external geometry objects. + */ + int getExternalCount() const { return int(geomlist.size()) - intGeoCount;} + + /** + * return a reference to the internal geometry list vector. + * + * @warning { It returns a reference to the internal list vector. The validity of the + * reference depends on the lifetime of the GeoListModel object.} + */ + std::vector & geometryList() { return const_cast &>(geomlist);} + +public: + std::vector geomlist; + +private: + Vector3d getPoint(const Part::Geometry * geo, Sketcher::PointPos pos) const; + +private: + int intGeoCount; + bool OwnerT; +}; + +using GeoList = GeoListModel; +using GeoListFacade = GeoListModel>; + +GeoListFacade getGeoListFacade(const GeoList & geolist); + +} // namespace Sketcher + + +#endif // SKETCHER_GeoList_H +