From feba33a9b8c8c1dcb9785cda0f24d02ac2ebbc05 Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Tue, 7 Dec 2021 16:26:48 +0100 Subject: [PATCH] Sketcher: Create GeoList class ============================== Class for managing internal and external geometry as a single object. This is a light-weight alternative to passing the whole SketchObject. It reflects the format used in getCompleteGeometry of SketchObject and Sketch solver facade class, while providing several convenient conversion functions to map indices. Internal and external geometries are present in a single geometry vector one after the other. 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 static member functions). Internal implementation is as a template GeoListModel. The following types are instantiated. Specialisation is provided where necessary. GeoList = GeoListModel; GeoListFacade = GeoListModel>; This enables to use the lighter GeoList were sufficient, while enabling off-the-shelf replacement when switching to a GeoListFacade is necessary. --- src/Mod/Sketcher/App/CMakeLists.txt | 2 + src/Mod/Sketcher/App/GeoList.cpp | 273 ++++++++++++++++++++++++++++ src/Mod/Sketcher/App/GeoList.h | 166 +++++++++++++++++ 3 files changed, 441 insertions(+) create mode 100644 src/Mod/Sketcher/App/GeoList.cpp create mode 100644 src/Mod/Sketcher/App/GeoList.h 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 +