// SPDX-License-Identifier: LGPL-2.1-or-later /*************************************************************************** * Copyright (c) 2022 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 #include #include "PythonConverter.h" using namespace Sketcher; std::string PythonConverter::convert(const Part::Geometry* geo, Mode mode) { // "addGeometry(Part.LineSegment(App.Vector(%f,%f,0),App.Vector(%f,%f,0)),%s)" std::string command; auto sg = process(geo); command = boost::str( boost::format("addGeometry(%s,%s)\n") % sg.creation % (sg.construction ? "True" : "False") ); // clang-format off: keep line breaks for readability if ((!geo->is() || !geo->is() || !geo->is() || !geo->is() || !geo->is()) && mode == Mode::CreateInternalGeometry) { command += boost::str(boost::format("exposeInternalGeometry(len(ActiveSketch.Geometry))\n")); } // clang-format on return command; } std::string PythonConverter::convert(const Sketcher::Constraint* constraint, GeoIdMode geoIdMode) { // addConstraint(Sketcher.Constraint('Distance',%d,%f)) std::string command; auto cg = process(constraint, geoIdMode); command = boost::str(boost::format("addConstraint(%s)\n") % cg); return command; } std::string PythonConverter::convert( const std::string& doc, const std::vector& geos, Mode mode ) { if (geos.empty()) { return std::string(); } // Generates a list for consecutive geometries of construction type, or of normal type auto printGeoList = [&doc](const std::string& geolist, int ngeos, bool construction) { std::string command; if (ngeos > 0) { if (construction) { command = boost::str( boost::format( "constrGeoList = []\n%s%s.addGeometry(constrGeoList,%s)\n" "del constrGeoList\n" ) % geolist % doc % "True" ); } else { command = boost::str( boost::format("geoList = []\n%s%s.addGeometry(geoList,%s)\ndel geoList\n") % geolist % doc % "False" ); } } return command; }; std::string command = boost::str(boost::format("lastGeoId = len(ActiveSketch.Geometry)\n")); // Adds a list of consecutive geometries of a same construction type to the generating command auto addToCommands = [&command, &printGeoList](const std::string& geolist, int ngeos, bool construction) { auto newcommand = printGeoList(geolist, ngeos, construction); if (command.empty()) { command = std::move(newcommand); } else { command += "\n"; command += newcommand; } }; std::string geolist; int ngeos = 0; bool currentconstruction = Sketcher::GeometryFacade::getConstruction(geos[0]); for (auto geo : geos) { auto sg = process(geo); if (sg.construction != currentconstruction) { // if it switches from construction to normal or vice versa, flush elements so far in // order to keep order of creation addToCommands(geolist, ngeos, currentconstruction); geolist.clear(); ngeos = 0; currentconstruction = sg.construction; } if (sg.construction) { geolist = boost::str(boost::format("%sconstrGeoList.append(%s)\n") % geolist % sg.creation); } else { geolist = boost::str(boost::format("%sgeoList.append(%s)\n") % geolist % sg.creation); } ngeos++; } addToCommands(geolist, ngeos, currentconstruction); int index = 0; if (mode == Mode::CreateInternalGeometry) { for (auto geo : geos) { index++; // clang-format off: keep line breaks for readability if (!geo->is() || !geo->is() || !geo->is() || !geo->is() || !geo->is()) { std::string newcommand = boost::str(boost::format("exposeInternalGeometry(lastGeoId + %d)\n") % (index)); command += newcommand; } // clang-format on } } return command; } std::string PythonConverter::convert( const std::string& doc, const std::vector& constraints, GeoIdMode geoIdMode ) { if (constraints.size() == 1) { auto cg = convert(constraints[0], geoIdMode); return boost::str(boost::format("%s.%s\n") % doc % cg); } std::string constraintlist = "constraintList = []"; for (auto constraint : constraints) { auto cg = process(constraint, geoIdMode); constraintlist = boost::str( boost::format("%s\nconstraintList.append(%s)") % constraintlist % cg ); } if (!constraints.empty()) { constraintlist = boost::str( boost::format("%s\n%s.addConstraint(constraintList)\ndel constraintList\n") % constraintlist % doc ); } return constraintlist; } template std::string makeSplineInfoArrayString(const std::vector& rInfoVec) { std::stringstream stream; if constexpr (std::is_same_v) { for (const auto& rInfo : rInfoVec) { stream << "App.Vector(" << rInfo.x << ", " << rInfo.y << "), "; } } else { for (const auto& rInfo : rInfoVec) { stream << rInfo << ", "; } } std::string res = stream.str(); // remove last comma and add brackets int index = res.rfind(','); res.resize(index); return fmt::format("[{}]", res); ; } PythonConverter::SingleGeometry PythonConverter::process(const Part::Geometry* geo) { static std::map> converterMap = { {Part::GeomLineSegment::getClassTypeId(), [](const Part::Geometry* geo) { auto sgeo = static_cast(geo); SingleGeometry sg; sg.creation = boost::str( boost::format("Part.LineSegment(App.Vector(%f, %f, %f),App.Vector(%f, %f, %f))") % sgeo->getStartPoint().x % sgeo->getStartPoint().y % sgeo->getStartPoint().z % sgeo->getEndPoint().x % sgeo->getEndPoint().y % sgeo->getEndPoint().z ); sg.construction = Sketcher::GeometryFacade::getConstruction(geo); return sg; }}, {Part::GeomArcOfCircle::getClassTypeId(), [](const Part::Geometry* geo) { auto arc = static_cast(geo); double startAngle, endAngle; arc->getRange(startAngle, endAngle, /*emulateCCWXY=*/true); SingleGeometry sg; sg.creation = boost::str( boost::format( "Part.ArcOfCircle(Part.Circle(App.Vector(%f, %f, " "%f), App.Vector(%f, %f, %f), %f), %f, %f)" ) % arc->getCenter().x % arc->getCenter().y % arc->getCenter().z % arc->getAxisDirection().x % arc->getAxisDirection().y % arc->getAxisDirection().z % arc->getRadius() % startAngle % endAngle ); sg.construction = Sketcher::GeometryFacade::getConstruction(geo); return sg; }}, {Part::GeomPoint::getClassTypeId(), [](const Part::Geometry* geo) { auto sgeo = static_cast(geo); SingleGeometry sg; sg.creation = boost::str( boost::format("Part.Point(App.Vector(%f, %f, %f))") % sgeo->getPoint().x % sgeo->getPoint().y % sgeo->getPoint().z ); sg.construction = Sketcher::GeometryFacade::getConstruction(geo); return sg; }}, {Part::GeomEllipse::getClassTypeId(), [](const Part::Geometry* geo) { auto ellipse = static_cast(geo); SingleGeometry sg; auto center = ellipse->getCenter(); auto periapsis = center + ellipse->getMajorAxisDir() * ellipse->getMajorRadius(); auto positiveB = center + ellipse->getMinorAxisDir() * ellipse->getMinorRadius(); sg.creation = boost::str( boost::format( "Part.Ellipse(App.Vector(%f, %f, %f), App.Vector(%f, " "%f, %f), App.Vector(%f, %f, %f))" ) % periapsis.x % periapsis.y % periapsis.z % positiveB.x % positiveB.y % positiveB.z % center.x % center.y % center.z ); sg.construction = Sketcher::GeometryFacade::getConstruction(geo); return sg; }}, {Part::GeomArcOfEllipse::getClassTypeId(), [](const Part::Geometry* geo) { auto aoe = static_cast(geo); double startAngle, endAngle; aoe->getRange(startAngle, endAngle, /*emulateCCWXY=*/true); SingleGeometry sg; auto center = aoe->getCenter(); auto periapsis = center + aoe->getMajorAxisDir() * aoe->getMajorRadius(); auto positiveB = center + aoe->getMinorAxisDir() * aoe->getMinorRadius(); sg.creation = boost::str( boost::format( "Part.ArcOfEllipse(Part.Ellipse(App.Vector(%f, %f, %f), App.Vector(%f, " "%f, %f), App.Vector(%f, %f, %f)), %f, %f)" ) % periapsis.x % periapsis.y % periapsis.z % positiveB.x % positiveB.y % positiveB.z % center.x % center.y % center.z % startAngle % endAngle ); sg.construction = Sketcher::GeometryFacade::getConstruction(geo); return sg; }}, {Part::GeomArcOfHyperbola::getClassTypeId(), [](const Part::Geometry* geo) { auto aoh = static_cast(geo); double startAngle, endAngle; aoh->getRange(startAngle, endAngle, /*emulateCCWXY=*/true); SingleGeometry sg; auto center = aoh->getCenter(); auto majAxisPoint = center + aoh->getMajorAxisDir() * aoh->getMajorRadius(); auto minAxisPoint = center + aoh->getMinorAxisDir() * aoh->getMinorRadius(); sg.creation = boost::str( boost::format( "Part.ArcOfHyperbola(Part.Hyperbola(App.Vector(%f, %f, %f), " "App.Vector(%f, %f, %f), App.Vector(%f, %f, %f)), %f, %f)" ) % majAxisPoint.x % majAxisPoint.y % majAxisPoint.z % minAxisPoint.x % minAxisPoint.y % minAxisPoint.z % center.x % center.y % center.z % startAngle % endAngle ); sg.construction = Sketcher::GeometryFacade::getConstruction(geo); return sg; }}, {Part::GeomArcOfParabola::getClassTypeId(), [](const Part::Geometry* geo) { auto aop = static_cast(geo); double startAngle, endAngle; aop->getRange(startAngle, endAngle, /*emulateCCWXY=*/true); SingleGeometry sg; auto focus = aop->getFocus(); auto axisPoint = aop->getCenter(); sg.creation = boost::str( boost::format( "Part.ArcOfParabola(Part.Parabola(App.Vector(%f, %f, %f), " "App.Vector(%f, %f, %f), App.Vector(0, 0, 1)), %f, %f)" ) % focus.x % focus.y % focus.z % axisPoint.x % axisPoint.y % axisPoint.z % startAngle % endAngle ); sg.construction = Sketcher::GeometryFacade::getConstruction(geo); return sg; }}, {Part::GeomBSplineCurve::getClassTypeId(), [](const Part::Geometry* geo) { auto bSpline = static_cast(geo); std::string controlpoints = makeSplineInfoArrayString(bSpline->getPoles()); std::string mults = makeSplineInfoArrayString(bSpline->getMultiplicities()); std::string knots = makeSplineInfoArrayString(bSpline->getKnots()); std::string weights = makeSplineInfoArrayString(bSpline->getWeights()); SingleGeometry sg; sg.creation = boost::str( boost::format("Part.BSplineCurve(%s, %s, %s, %s, %d, %s, False)") % controlpoints.c_str() % mults.c_str() % knots.c_str() % (bSpline->isPeriodic() ? "True" : "False") % bSpline->getDegree() % weights.c_str() ); sg.construction = Sketcher::GeometryFacade::getConstruction(geo); return sg; }}, {Part::GeomCircle::getClassTypeId(), [](const Part::Geometry* geo) { auto circle = static_cast(geo); SingleGeometry sg; sg.creation = boost::str( boost::format("Part.Circle(App.Vector(%f, %f, %f), App.Vector(%f, %f, %f), %f)") % circle->getCenter().x % circle->getCenter().y % circle->getCenter().z % circle->getAxisDirection().x % circle->getAxisDirection().y % circle->getAxisDirection().z % circle->getRadius() ); sg.construction = Sketcher::GeometryFacade::getConstruction(geo); return sg; }}, }; auto result = converterMap.find(geo->getTypeId()); if (result == converterMap.end()) { THROWM(Base::ValueError, "PythonConverter: Geometry Type not supported") } auto creator = result->second; return creator(geo); } std::string PythonConverter::process(const Sketcher::Constraint* constraint, GeoIdMode geoIdMode) { bool addLastIdVar = geoIdMode == GeoIdMode::AddLastGeoIdToGeoIds; bool addLastIdVar1 = constraint->First >= 0 && addLastIdVar; bool addLastIdVar2 = constraint->Second >= 0 && addLastIdVar; bool addLastIdVar3 = constraint->Third >= 0 && addLastIdVar; std::string geoId1 = (addLastIdVar1 ? "lastGeoId + " : "") + std::to_string(constraint->First); std::string geoId2 = (addLastIdVar2 ? "lastGeoId + " : "") + std::to_string(constraint->Second); std::string geoId3 = (addLastIdVar3 ? "lastGeoId + " : "") + std::to_string(constraint->Third); static std::map< const Sketcher::ConstraintType, std::function> converterMap = { {Sketcher::Coincident, [](const Sketcher::Constraint* constr, std::string& geoId1, std::string& geoId2, [[maybe_unused]] std::string& geoId3) { return boost::str( boost::format("Sketcher.Constraint('Coincident', %s, %i, %s, %i") % geoId1 % static_cast(constr->FirstPos) % geoId2 % static_cast(constr->SecondPos) ); }}, {Sketcher::Horizontal, [](const Sketcher::Constraint* constr, std::string& geoId1, std::string& geoId2, [[maybe_unused]] std::string& geoId3) { if (constr->Second == GeoEnum::GeoUndef) { return boost::str(boost::format("Sketcher.Constraint('Horizontal', %s") % geoId1); } else { return boost::str( boost::format("Sketcher.Constraint('Horizontal', %s, %i, %s, %i") % geoId1 % static_cast(constr->FirstPos) % geoId2 % static_cast(constr->SecondPos) ); } }}, {Sketcher::Vertical, [](const Sketcher::Constraint* constr, std::string& geoId1, std::string& geoId2, [[maybe_unused]] std::string& geoId3) { if (constr->Second == GeoEnum::GeoUndef) { return boost::str(boost::format("Sketcher.Constraint('Vertical', %s") % geoId1); } else { return boost::str( boost::format("Sketcher.Constraint('Vertical', %s, %i, %s, %i") % geoId1 % static_cast(constr->FirstPos) % geoId2 % static_cast(constr->SecondPos) ); } }}, {Sketcher::Block, []([[maybe_unused]] const Sketcher::Constraint* constr, std::string& geoId1, [[maybe_unused]] std::string& geoId2, [[maybe_unused]] std::string& geoId3) { return boost::str(boost::format("Sketcher.Constraint('Block', %s") % geoId1); }}, {Sketcher::Tangent, [](const Sketcher::Constraint* constr, std::string& geoId1, std::string& geoId2, [[maybe_unused]] std::string& geoId3) { if (constr->FirstPos == Sketcher::PointPos::none) { return boost::str( boost::format("Sketcher.Constraint('Tangent', %s, %s") % geoId1 % geoId2 ); } else if (constr->SecondPos == Sketcher::PointPos::none) { return boost::str( boost::format("Sketcher.Constraint('Tangent', %s, %i, %s") % geoId1 % static_cast(constr->FirstPos) % geoId2 ); } else { return boost::str( boost::format("Sketcher.Constraint('Tangent', %s, %i, %s, %i") % geoId1 % static_cast(constr->FirstPos) % geoId2 % static_cast(constr->SecondPos) ); } }}, {Sketcher::Parallel, []([[maybe_unused]] const Sketcher::Constraint* constr, std::string& geoId1, std::string& geoId2, [[maybe_unused]] std::string& geoId3) { return boost::str( boost::format("Sketcher.Constraint('Parallel', %s, %s") % geoId1 % geoId2 ); }}, {Sketcher::Perpendicular, []([[maybe_unused]] const Sketcher::Constraint* constr, std::string& geoId1, std::string& geoId2, [[maybe_unused]] std::string& geoId3) { if (constr->FirstPos == Sketcher::PointPos::none) { return boost::str( boost::format("Sketcher.Constraint('Perpendicular', %s, %s") % geoId1 % geoId2 ); } else if (constr->SecondPos == Sketcher::PointPos::none) { return boost::str( boost::format("Sketcher.Constraint('Perpendicular', %s, %i, %s") % geoId1 % static_cast(constr->FirstPos) % geoId2 ); } else { return boost::str( boost::format("Sketcher.Constraint('Perpendicular', %s, %i, %s, %i") % geoId1 % static_cast(constr->FirstPos) % geoId2 % static_cast(constr->SecondPos) ); } }}, {Sketcher::Equal, []([[maybe_unused]] const Sketcher::Constraint* constr, std::string& geoId1, std::string& geoId2, [[maybe_unused]] std::string& geoId3) { return boost::str( boost::format("Sketcher.Constraint('Equal', %s, %s") % geoId1 % geoId2 ); }}, {Sketcher::InternalAlignment, [](const Sketcher::Constraint* constr, std::string& geoId1, std::string& geoId2, [[maybe_unused]] std::string& geoId3) { if (constr->AlignmentType == EllipseMajorDiameter || constr->AlignmentType == EllipseMinorDiameter || constr->AlignmentType == HyperbolaMajor || constr->AlignmentType == HyperbolaMinor || constr->AlignmentType == ParabolaFocalAxis) { return boost::str( boost::format("Sketcher.Constraint('InternalAlignment:%s', %s, %s") % constr->internalAlignmentTypeToString() % geoId1 % geoId2 ); } else if (constr->AlignmentType == EllipseFocus1 || constr->AlignmentType == EllipseFocus2 || constr->AlignmentType == HyperbolaFocus || constr->AlignmentType == ParabolaFocus) { return boost::str( boost::format("Sketcher.Constraint('InternalAlignment:%s', %s, %i, %s") % constr->internalAlignmentTypeToString() % geoId1 % static_cast(constr->FirstPos) % geoId2 ); } else if (constr->AlignmentType == BSplineControlPoint) { return boost::str( boost::format("Sketcher.Constraint('InternalAlignment:%s', %s, %i, %s, %i") % constr->internalAlignmentTypeToString() % geoId1 % static_cast(constr->FirstPos) % geoId2 % constr->InternalAlignmentIndex ); } else if (constr->AlignmentType == BSplineKnotPoint) { return boost::str( boost::format("Sketcher.Constraint('InternalAlignment:%s', %s, 1, %s, %i") % constr->internalAlignmentTypeToString() % geoId1 % geoId2 % constr->InternalAlignmentIndex ); } THROWM(Base::ValueError, "PythonConverter: Constraint Alignment Type not supported") }}, {Sketcher::Distance, [](const Sketcher::Constraint* constr, std::string& geoId1, std::string& geoId2, [[maybe_unused]] std::string& geoId3) { if (constr->Second == GeoEnum::GeoUndef) { return boost::str( boost::format("Sketcher.Constraint('Distance', %s, %f") % geoId1 % constr->getValue() ); } else if (constr->FirstPos == Sketcher::PointPos::none) { return boost::str( boost::format("Sketcher.Constraint('Distance', %s, %s, %f") % geoId1 % geoId2 % constr->getValue() ); } else if (constr->SecondPos == Sketcher::PointPos::none) { return boost::str( boost::format("Sketcher.Constraint('Distance', %s, %i, %s, %f") % geoId1 % static_cast(constr->FirstPos) % geoId2 % constr->getValue() ); } else { return boost::str( boost::format("Sketcher.Constraint('Distance', %s, %i, %s, %i, %f") % geoId1 % static_cast(constr->FirstPos) % geoId2 % static_cast(constr->SecondPos) % constr->getValue() ); } }}, {Sketcher::Angle, [](const Sketcher::Constraint* constr, std::string& geoId1, std::string& geoId2, std::string& geoId3) { if (constr->Second == GeoEnum::GeoUndef) { return boost::str( boost::format("Sketcher.Constraint('Angle', %s, %f") % geoId1 % constr->getValue() ); } else if (constr->Third == GeoEnum::GeoUndef) { if (constr->SecondPos == Sketcher::PointPos::none) { return boost::str( boost::format("Sketcher.Constraint('Angle', %s, %s, %f") % geoId1 % geoId2 % constr->getValue() ); } else { return boost::str( boost::format("Sketcher.Constraint('Angle', %s, %i, %s, %i, %f") % geoId1 % static_cast(constr->FirstPos) % geoId2 % static_cast(constr->SecondPos) % constr->getValue() ); } } else { return boost::str( boost::format("Sketcher.Constraint('AngleViaPoint', %s, %s, %s, %i, %f") % geoId1 % geoId2 % geoId3 % static_cast(constr->ThirdPos) % constr->getValue() ); } }}, {Sketcher::DistanceX, [](const Sketcher::Constraint* constr, std::string& geoId1, std::string& geoId2, [[maybe_unused]] std::string& geoId3) { if (constr->FirstPos == Sketcher::PointPos::none && constr->Second == GeoEnum::GeoUndef) { return boost::str( boost::format("Sketcher.Constraint('DistanceX', %s, %f") % geoId1 % constr->getValue() ); } else if (constr->SecondPos == Sketcher::PointPos::none) { return boost::str( boost::format("Sketcher.Constraint('DistanceX', %s, %i, %f") % geoId1 % static_cast(constr->FirstPos) % constr->getValue() ); } else { return boost::str( boost::format("Sketcher.Constraint('DistanceX', %s, %i, %s, %i, %f") % geoId1 % static_cast(constr->FirstPos) % geoId2 % static_cast(constr->SecondPos) % constr->getValue() ); } }}, {Sketcher::DistanceY, [](const Sketcher::Constraint* constr, std::string& geoId1, std::string& geoId2, [[maybe_unused]] std::string& geoId3) { if (constr->FirstPos == Sketcher::PointPos::none && constr->Second == GeoEnum::GeoUndef) { return boost::str( boost::format("Sketcher.Constraint('DistanceY', %s, %f") % geoId1 % constr->getValue() ); } else if (constr->SecondPos == Sketcher::PointPos::none) { return boost::str( boost::format("Sketcher.Constraint('DistanceY', %s, %i, %f") % geoId1 % static_cast(constr->FirstPos) % constr->getValue() ); } else { return boost::str( boost::format("Sketcher.Constraint('DistanceY', %s, %i, %s, %i, %f") % geoId1 % static_cast(constr->FirstPos) % geoId2 % static_cast(constr->SecondPos) % constr->getValue() ); } }}, {Sketcher::Radius, [](const Sketcher::Constraint* constr, std::string& geoId1, [[maybe_unused]] std::string& geoId2, [[maybe_unused]] std::string& geoId3) { return boost::str( boost::format("Sketcher.Constraint('Radius', %s, %f") % geoId1 % constr->getValue() ); }}, {Sketcher::Diameter, [](const Sketcher::Constraint* constr, std::string& geoId1, [[maybe_unused]] std::string& geoId2, [[maybe_unused]] std::string& geoId3) { return boost::str( boost::format("Sketcher.Constraint('Diameter', %s, %f") % geoId1 % constr->getValue() ); }}, {Sketcher::Weight, [](const Sketcher::Constraint* constr, std::string& geoId1, [[maybe_unused]] std::string& geoId2, [[maybe_unused]] std::string& geoId3) { return boost::str( boost::format("Sketcher.Constraint('Weight', %s, %f") % geoId1 % constr->getValue() ); }}, {Sketcher::PointOnObject, [](const Sketcher::Constraint* constr, std::string& geoId1, std::string& geoId2, [[maybe_unused]] std::string& geoId3) { return boost::str( boost::format("Sketcher.Constraint('PointOnObject', %s, %i, %s") % geoId1 % static_cast(constr->FirstPos) % geoId2 ); }}, {Sketcher::Symmetric, [](const Sketcher::Constraint* constr, std::string& geoId1, std::string& geoId2, std::string& geoId3) { if (constr->ThirdPos == Sketcher::PointPos::none) { return boost::str( boost::format("Sketcher.Constraint('Symmetric', %s, %i, %s, %i, %s") % geoId1 % static_cast(constr->FirstPos) % geoId2 % static_cast(constr->SecondPos) % geoId3 ); } else { return boost::str( boost::format("Sketcher.Constraint('Symmetric', %s, %i, %s, %i, %s, %i") % geoId1 % static_cast(constr->FirstPos) % geoId2 % static_cast(constr->SecondPos) % geoId3 % static_cast(constr->ThirdPos) ); } }}, {Sketcher::SnellsLaw, [](const Sketcher::Constraint* constr, std::string& geoId1, std::string& geoId2, std::string& geoId3) { return boost::str( boost::format("Sketcher.Constraint('SnellsLaw', %s, %i, %s, %i, %s, %f") % geoId1 % static_cast(constr->FirstPos) % geoId2 % static_cast(constr->SecondPos) % geoId3 % constr->getValue() ); }}, }; auto result = converterMap.find(constraint->Type); if (result == converterMap.end()) { THROWM(Base::ValueError, "PythonConverter: Constraint Type not supported") } auto creator = result->second; std::string resultStr = creator(constraint, geoId1, geoId2, geoId3); if (!constraint->isActive || !constraint->isDriving) { std::string active = constraint->isActive ? "True" : "False"; resultStr += ", " + active; if (constraint->isDimensional()) { std::string driving = constraint->isDriving ? "True" : "False"; resultStr += ", " + driving; } } resultStr += ")"; return resultStr; } std::vector PythonConverter::multiLine(std::string&& singlestring) { std::vector tokens; split_regex(tokens, singlestring, boost::regex("(\n)+")); return tokens; }