// SPDX-License-Identifier: LGPL-2.1-or-later /*************************************************************************** * 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 #include #include #include #include "GeoList.h" #include "GeometryFacade.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) , indexInit(false) {} // Vector is shallow copied (copy constructed) template GeoListModel::GeoListModel( const std::vector& geometrylist, int intgeocount ) : geomlist(geometrylist) , // copy constructed here intGeoCount(intgeocount) , OwnerT(false) , indexInit(false) {} 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) { return GeoListModel(geometrylist, intgeocount); } template int GeoListModel::getGeoIdFromGeomListIndex(int index) const { assert(index < int(geomlist.size())); if (index < intGeoCount) { return index; } else { return (index - geomlist.size()); } } template const Part::Geometry* GeoListModel::getGeometryFromGeoId(const std::vector& geometrylist, int geoId) { if constexpr (std::is_same()) { if (geoId >= 0) { return geometrylist[geoId]; } else { return geometrylist[geometrylist.size() + geoId]; } } else if constexpr (std::is_same()) { if (geoId >= 0) { return geometrylist[geoId]->getGeometry(); } else { return geometrylist[geometrylist.size() + geoId]->getGeometry(); } } } template const Sketcher::GeometryFacade* GeoListModel::getGeometryFacadeFromGeoId( const std::vector& geometrylist, int geoId ) { if constexpr (std::is_same()) { if (geoId >= 0) { return GeometryFacade::getFacade(geometrylist[geoId]).release(); } else { return GeometryFacade::getFacade(geometrylist[geometrylist.size() + geoId]).release(); } } else if constexpr (std::is_same()) { if (geoId >= 0) { return geometrylist[geoId].get(); } else { return geometrylist[geometrylist.size() + geoId].get(); } } } // this function is used to simulate cyclic periodic negative geometry indices (for external // geometry) template const Part::Geometry* GeoListModel::getGeometryFromGeoId(int geoId) const { return GeoListModel::getGeometryFromGeoId(geomlist, geoId); } template const Sketcher::GeometryFacade* GeoListModel::getGeometryFacadeFromGeoId(int geoId) const { return GeoListModel::getGeometryFacadeFromGeoId(geomlist, geoId); } template Base::Vector3d GeoListModel::getPoint(int geoId, Sketcher::PointPos pos) const { const Part::Geometry* geo = getGeometryFromGeoId(geoId); return getPoint(geo, pos); } template Base::Vector3d GeoListModel::getPoint(const GeoElementId& geid) const { return getPoint(geid.GeoId, geid.Pos); } template Base::Vector3d GeoListModel::getPoint(const Part::Geometry* geo, Sketcher::PointPos pos) const { using namespace Sketcher; if (geo->is()) { const Part::GeomPoint* p = static_cast(geo); if (pos == PointPos::start || pos == PointPos::mid || pos == PointPos::end) { return p->getPoint(); } } else if (geo->is()) { const Part::GeomLineSegment* lineSeg = static_cast(geo); if (pos == PointPos::start) { return lineSeg->getStartPoint(); } else if (pos == PointPos::end) { return lineSeg->getEndPoint(); } } else if (geo->is()) { const Part::GeomCircle* circle = static_cast(geo); if (pos == PointPos::mid) { return circle->getCenter(); } } else if (geo->is()) { const Part::GeomEllipse* ellipse = static_cast(geo); if (pos == PointPos::mid) { return ellipse->getCenter(); } } else if (geo->is()) { const Part::GeomArcOfCircle* aoc = static_cast(geo); if (pos == PointPos::start) { return aoc->getStartPoint(/*emulateCCW=*/true); } else if (pos == PointPos::end) { return aoc->getEndPoint(/*emulateCCW=*/true); } else if (pos == PointPos::mid) { return aoc->getCenter(); } } else if (geo->is()) { const Part::GeomArcOfEllipse* aoc = static_cast(geo); if (pos == PointPos::start) { return aoc->getStartPoint(/*emulateCCW=*/true); } else if (pos == PointPos::end) { return aoc->getEndPoint(/*emulateCCW=*/true); } else if (pos == PointPos::mid) { return aoc->getCenter(); } } else if (geo->is()) { const Part::GeomArcOfHyperbola* aoh = static_cast(geo); if (pos == PointPos::start) { return aoh->getStartPoint(); } else if (pos == PointPos::end) { return aoh->getEndPoint(); } else if (pos == PointPos::mid) { return aoh->getCenter(); } } else if (geo->is()) { const Part::GeomArcOfParabola* aop = static_cast(geo); if (pos == PointPos::start) { return aop->getStartPoint(); } else if (pos == PointPos::end) { return aop->getEndPoint(); } else if (pos == PointPos::mid) { return aop->getCenter(); } } else if (geo->is()) { const Part::GeomBSplineCurve* bsp = static_cast(geo); if (pos == PointPos::start) { return bsp->getStartPoint(); } else if (pos == PointPos::end) { return bsp->getEndPoint(); } } return Base::Vector3d(); } template void GeoListModel::rebuildVertexIndex() const { VertexId2GeoElementId.clear(); GeoElementId2VertexId.clear(); int geoId = 0; int pointId = 0; auto addGeoElement = [this, &pointId](int geoId, PointPos pos) { VertexId2GeoElementId.emplace_back(geoId, pos); GeoElementId2VertexId.emplace( std::piecewise_construct, std::forward_as_tuple(geoId, pos), std::forward_as_tuple(pointId++) ); }; if (geomlist.size() <= 2) { return; } for (auto it = geomlist.begin(); it != geomlist.end(); ++it, geoId++) { Base::Type type; if constexpr (std::is_same::value) { type = (*it)->getTypeId(); } else if constexpr (std::is_same>::value) { type = (*it)->getGeometry()->getTypeId(); } if (geoId > getInternalCount()) { geoId = -getExternalCount(); } if (type == Part::GeomPoint::getClassTypeId()) { addGeoElement(geoId, PointPos::start); } else if (type == Part::GeomLineSegment::getClassTypeId() || type == Part::GeomBSplineCurve::getClassTypeId()) { addGeoElement(geoId, PointPos::start); addGeoElement(geoId, PointPos::end); } else if (type == Part::GeomCircle::getClassTypeId() || type == Part::GeomEllipse::getClassTypeId()) { addGeoElement(geoId, PointPos::mid); } else if (type == Part::GeomArcOfCircle::getClassTypeId() || type == Part::GeomArcOfEllipse::getClassTypeId() || type == Part::GeomArcOfHyperbola::getClassTypeId() || type == Part::GeomArcOfParabola::getClassTypeId()) { addGeoElement(geoId, PointPos::start); addGeoElement(geoId, PointPos::end); addGeoElement(geoId, PointPos::mid); } } indexInit = true; } template Sketcher::GeoElementId GeoListModel::getGeoElementIdFromVertexId(int vertexId) { if (!indexInit) { // lazy initialised rebuildVertexIndex(); } return VertexId2GeoElementId[vertexId]; } template int GeoListModel::getVertexIdFromGeoElementId(const Sketcher::GeoElementId& geoelementId) const { if (!indexInit) { rebuildVertexIndex(); // lazy initialised } if (const auto found = std::ranges::find(VertexId2GeoElementId, geoelementId); found != VertexId2GeoElementId.end()) { return std::distance(found, VertexId2GeoElementId.begin()); } THROWM(Base::IndexError, "GeoElementId not indexed"); } namespace Sketcher { // Template specialisations template<> GeoListModel::GeoListModel( std::vector&& geometrylist, int intgeocount, bool ownerT ) : geomlist(std::move(geometrylist)) , intGeoCount(intgeocount) , OwnerT(false) , indexInit(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); boost::ignore_unused(ownerT); } template<> GeoListModel::GeoListModel( const std::vector& geometrylist, int intgeocount ) : intGeoCount(intgeocount) , OwnerT(false) , indexInit(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. geomlist.reserve(geometrylist.size()); for (auto& v : geometrylist) { geomlist.push_back(GeometryFacade::getFacade(v->getGeometry())); } } template<> SketcherExport GeoListModel>::~GeoListModel() { // GeometryFacade is responsible for taken ownership of its pointers and deleting them. } // instantiate the types so that other translation units can access template constructors template class SketcherExport GeoListModel; #if !defined(__MINGW32__) template class SketcherExport GeoListModel>; #else // Remark: It looks like when implementing a method of GeoListModel for GeometryFacadeUniquePtr then // under MinGW the explicit template instantiation doesn't do anything. As workaround all other // methods must be declared separately template SketcherExport const Part::Geometry* GeoListModel::getGeometryFromGeoId( int geoId ) const; template SketcherExport const Sketcher::GeometryFacade* GeoListModel< GeometryFacadeUniquePtr>::getGeometryFacadeFromGeoId(int geoId) const; template SketcherExport int GeoListModel::getGeoIdFromGeomListIndex( int index ) const; template SketcherExport int GeoListModel::getVertexIdFromGeoElementId( const Sketcher::GeoElementId& ) const; template SketcherExport GeoElementId GeoListModel::getGeoElementIdFromVertexId(int); template SketcherExport Base::Vector3d GeoListModel::getPoint( int geoId, Sketcher::PointPos pos ) const; template SketcherExport Base::Vector3d GeoListModel::getPoint( const GeoElementId& ) const; template SketcherExport GeoListModel GeoListModel::getGeoListModel( std::vector&& geometrylist, int intgeocount, bool ownerT ); #endif } // 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; }