diff --git a/src/Mod/Sketcher/App/PythonConverter.cpp b/src/Mod/Sketcher/App/PythonConverter.cpp index d063378161..506463ae62 100644 --- a/src/Mod/Sketcher/App/PythonConverter.cpp +++ b/src/Mod/Sketcher/App/PythonConverter.cpp @@ -59,11 +59,11 @@ std::string PythonConverter::convert(const Part::Geometry* geo, Mode mode) return command; } -std::string PythonConverter::convert(const Sketcher::Constraint* constraint) +std::string PythonConverter::convert(const Sketcher::Constraint* constraint, GeoIdMode geoIdMode) { // addConstraint(Sketcher.Constraint('Distance',%d,%f)) std::string command; - auto cg = process(constraint); + auto cg = process(constraint, geoIdMode); command = boost::str(boost::format("addConstraint(%s)\n") % cg); @@ -85,13 +85,13 @@ std::string PythonConverter::convert(const std::string& doc, if (ngeos > 0) { if (construction) { command = boost::str( - boost::format("constrGeoList = []\n%s\n%s.addGeometry(constrGeoList,%s)\ndel " - "constrGeoList") + 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\n%s.addGeometry(geoList,%s)\ndel geoList") + boost::format("geoList = []\n%s%s.addGeometry(geoList,%s)\ndel geoList\n") % geolist % doc % "False"); } } @@ -134,10 +134,10 @@ std::string PythonConverter::convert(const std::string& doc, if (sg.construction) { geolist = - boost::str(boost::format("%s\nconstrGeoList.append(%s)\n") % geolist % sg.creation); + boost::str(boost::format("%sconstrGeoList.append(%s)\n") % geolist % sg.creation); } else { - geolist = boost::str(boost::format("%s\ngeoList.append(%s)\n") % geolist % sg.creation); + geolist = boost::str(boost::format("%sgeoList.append(%s)\n") % geolist % sg.creation); } ngeos++; @@ -165,7 +165,8 @@ std::string PythonConverter::convert(const std::string& doc, } std::string PythonConverter::convert(const std::string& doc, - const std::vector& constraints) + const std::vector& constraints, + GeoIdMode geoIdMode) { if (constraints.size() == 1) { auto cg = convert(constraints[0]); @@ -176,7 +177,7 @@ std::string PythonConverter::convert(const std::string& doc, std::string constraintlist = "constraintList = []"; for (auto constraint : constraints) { - auto cg = process(constraint); + auto cg = process(constraint, geoIdMode); constraintlist = boost::str(boost::format("%s\nconstraintList.append(%s)") % constraintlist % cg); @@ -200,7 +201,8 @@ PythonConverter::SingleGeometry PythonConverter::process(const Part::Geometry* g 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))") + 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); @@ -225,7 +227,7 @@ PythonConverter::SingleGeometry PythonConverter::process(const Part::Geometry* g auto sgeo = static_cast(geo); SingleGeometry sg; sg.creation = - boost::str(boost::format("Part.Point(App.Vector(%f,%f,%f))") + 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; @@ -309,10 +311,10 @@ PythonConverter::SingleGeometry PythonConverter::process(const Part::Geometry* g controlpoints.append(1, ']'); SingleGeometry sg; - sg.creation = - boost::str(boost::format("Part.BSplineCurve (%s,None,None,%s,%d,None,False)") - % controlpoints.c_str() % (bSpline->isPeriodic() ? "True" : "False") - % bSpline->getDegree()); + sg.creation = boost::str( + boost::format("Part.BSplineCurve (%s, None, None, %s, %d, None, False)") + % controlpoints.c_str() % (bSpline->isPeriodic() ? "True" : "False") + % bSpline->getDegree()); sg.construction = Sketcher::GeometryFacade::getConstruction(geo); return sg; }}, @@ -342,128 +344,159 @@ PythonConverter::SingleGeometry PythonConverter::process(const Part::Geometry* g return creator(geo); } -std::string PythonConverter::process(const Sketcher::Constraint* constraint) +std::string PythonConverter::process(const Sketcher::Constraint* constraint, GeoIdMode geoIdMode) { - static std::map> + bool addLastIdVar = geoIdMode == GeoIdMode::AddLastGeoIdToGeoIds; + std::string geoId1 = (addLastIdVar ? "lastGeoId + " : "") + std::to_string(constraint->First); + std::string geoId2 = (addLastIdVar ? "lastGeoId + " : "") + std::to_string(constraint->Second); + std::string geoId3 = (addLastIdVar ? "lastGeoId + " : "") + std::to_string(constraint->Third); + + static std::map< + const Sketcher::ConstraintType, + std::function< + std::string(const Sketcher::Constraint*, std::string&, std::string&, std::string&)>> converterMap = { {Sketcher::Coincident, - [](const Sketcher::Constraint* constr) { + [](const Sketcher::Constraint* constr, + std::string& geoId1, + std::string& geoId2, + [[maybe_unused]] std::string& geoId3) { return boost::str( - boost::format("Sketcher.Constraint('Coincident', %i, %i, %i, %i)") - % constr->First % static_cast(constr->FirstPos) % constr->Second + 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) { + [](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', %i)") - % constr->First); + return boost::str(boost::format("Sketcher.Constraint('Horizontal', %s)") + % geoId1); } else { return boost::str( - boost::format("Sketcher.Constraint('Horizontal', %i, %i, %i, %i)") - % constr->First % static_cast(constr->FirstPos) % constr->Second + 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) { + [](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', %i)") - % constr->First); + return boost::str(boost::format("Sketcher.Constraint('Vertical', %s)") + % geoId1); } else { return boost::str( - boost::format("Sketcher.Constraint('Vertical', %i, %i, %i, %i)") - % constr->First % static_cast(constr->FirstPos) % constr->Second + boost::format("Sketcher.Constraint('Vertical', %s, %i, %s, %i)") % geoId1 + % static_cast(constr->FirstPos) % geoId2 % static_cast(constr->SecondPos)); } }}, {Sketcher::Block, - [](const Sketcher::Constraint* constr) { - return boost::str(boost::format("Sketcher.Constraint('Block', %i)") - % constr->First); + []([[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) { + [](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', %i, %i)") - % constr->First % constr->Second); + 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', %i, %i, %i)") - % constr->First % static_cast(constr->FirstPos) - % constr->Second); + 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', %i, %i, %i, %i)") - % constr->First % static_cast(constr->FirstPos) % constr->Second + boost::format("Sketcher.Constraint('Tangent', %s, %i, %s, %i)") % geoId1 + % static_cast(constr->FirstPos) % geoId2 % static_cast(constr->SecondPos)); } }}, {Sketcher::Parallel, - [](const Sketcher::Constraint* constr) { - return boost::str(boost::format("Sketcher.Constraint('Parallel', %i, %i)") - % constr->First % constr->Second); + []([[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, - [](const Sketcher::Constraint* constr) { + []([[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', %i, %i)") - % constr->First % constr->Second); + 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', %i, %i, %i)") - % constr->First % static_cast(constr->FirstPos) % constr->Second); + boost::format("Sketcher.Constraint('Perpendicular', %s, %i, %s)") % geoId1 + % static_cast(constr->FirstPos) % geoId2); } else { return boost::str( - boost::format("Sketcher.Constraint('Perpendicular', %i, %i, %i, %i)") - % constr->First % static_cast(constr->FirstPos) % constr->Second + boost::format("Sketcher.Constraint('Perpendicular', %s, %i, %s, %i)") + % geoId1 % static_cast(constr->FirstPos) % geoId2 % static_cast(constr->SecondPos)); } }}, {Sketcher::Equal, - [](const Sketcher::Constraint* constr) { - return boost::str(boost::format("Sketcher.Constraint('Equal', %i, %i)") - % constr->First % constr->Second); + []([[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) { + [](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', %i, %i)") - % constr->internalAlignmentTypeToString() % constr->First - % constr->Second); + 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', %i, %i, %i)") - % constr->internalAlignmentTypeToString() % constr->First - % static_cast(constr->FirstPos) % constr->Second); + 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', %i, %i, %i, %i)") - % constr->internalAlignmentTypeToString() % constr->First - % static_cast(constr->FirstPos) % constr->Second + "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', %i, 1, %i, %i)") - % constr->internalAlignmentTypeToString() % constr->First % constr->Second + boost::format("Sketcher.Constraint('InternalAlignment:%s', %s, 1, %s, %i)") + % constr->internalAlignmentTypeToString() % geoId1 % geoId2 % constr->InternalAlignmentIndex); } @@ -471,124 +504,160 @@ std::string PythonConverter::process(const Sketcher::Constraint* constraint) "PythonConverter: Constraint Alignment Type not supported") }}, {Sketcher::Distance, - [](const Sketcher::Constraint* constr) { + [](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', %i, %f)") - % constr->First % constr->getValue()); + 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', %i, %i, %f)") - % constr->First % constr->Second % constr->getValue()); + 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', %i, %i, %i, %f)") - % constr->First % static_cast(constr->FirstPos) % constr->Second - % constr->getValue()); + 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', %i, %i, %i, %i, %f)") - % constr->First % static_cast(constr->FirstPos) % constr->Second + 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) { + [](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', %i, %f)") - % constr->First % constr->getValue()); + return boost::str(boost::format("Sketcher.Constraint('Angle', %s, %f)") + % geoId1 % constr->getValue()); } - else if (constr->SecondPos == Sketcher::PointPos::none) { - return boost::str(boost::format("Sketcher.Constraint('Angle', %i, %i, %f)") - % constr->First % constr->Second % 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('Angle', %i, %i, %i, %i, %f)") - % constr->First % static_cast(constr->FirstPos) % constr->Second - % static_cast(constr->SecondPos) % constr->getValue()); + 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) { + [](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('DistanceX', %i, %f)") - % constr->First % constr->getValue()); + 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', %i, %i, %f)") - % constr->First % static_cast(constr->FirstPos) + 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', %i, %i, %i, %i, %f)") - % constr->First % static_cast(constr->FirstPos) % constr->Second + 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) { + [](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('DistanceY', %i, %f)") - % constr->First % constr->getValue()); + 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', %i, %i, %f)") - % constr->First % static_cast(constr->FirstPos) + 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', %i, %i, %i, %i, %f)") - % constr->First % static_cast(constr->FirstPos) % constr->Second + 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) { - return boost::str(boost::format("Sketcher.Constraint('Radius', %i, %f)") - % constr->First % constr->getValue()); + [](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) { - return boost::str(boost::format("Sketcher.Constraint('Diameter', %i, %f)") - % constr->First % constr->getValue()); + [](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) { - return boost::str(boost::format("Sketcher.Constraint('Weight', %i, %f)") - % constr->First % constr->getValue()); + [](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) { - return boost::str(boost::format("Sketcher.Constraint('PointOnObject', %i, %i, %i)") - % constr->First % static_cast(constr->FirstPos) - % constr->Second); + [](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) { + [](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', %i, %i, %i, %i, %i)") - % constr->First % static_cast(constr->FirstPos) % constr->Second - % static_cast(constr->SecondPos) % constr->Third); + 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', %i, %i, %i, %i, %i, %i)") - % constr->First % static_cast(constr->FirstPos) % constr->Second - % static_cast(constr->SecondPos) % constr->Third + 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) { + [](const Sketcher::Constraint* constr, + std::string& geoId1, + std::string& geoId2, + std::string& geoId3) { return boost::str( - boost::format("Sketcher.Constraint('SnellsLaw', %i, %i, %i, %i, %i, %f)") - % constr->First % static_cast(constr->FirstPos) % constr->Second - % static_cast(constr->SecondPos) % constr->Third % constr->getValue()); + boost::format("Sketcher.Constraint('SnellsLaw', %s, %i, %s, %i, %s, %f)") + % geoId1 % static_cast(constr->FirstPos) % geoId2 + % static_cast(constr->SecondPos) % geoId3 % constr->getValue()); }}, }; @@ -600,7 +669,7 @@ std::string PythonConverter::process(const Sketcher::Constraint* constraint) auto creator = result->second; - return creator(constraint); + return creator(constraint, geoId1, geoId2, geoId3); } std::vector PythonConverter::multiLine(std::string&& singlestring) diff --git a/src/Mod/Sketcher/App/PythonConverter.h b/src/Mod/Sketcher/App/PythonConverter.h index 98535583b1..8062064589 100644 --- a/src/Mod/Sketcher/App/PythonConverter.h +++ b/src/Mod/Sketcher/App/PythonConverter.h @@ -24,6 +24,9 @@ #ifndef SKETCHER_PythonConverter_H #define SKETCHER_PythonConverter_H +#include +#include + #include namespace Part @@ -57,7 +60,13 @@ public: OmitInternalGeometry }; - explicit PythonConverter() = delete; + enum class GeoIdMode + { + DoNotChangeGeoIds, + AddLastGeoIdToGeoIds, + }; + + PythonConverter() = delete; ~PythonConverter() = delete; /// Convert a geometry into the string representing the command creating it @@ -68,17 +77,20 @@ public: const std::vector& geos, Mode mode = Mode::CreateInternalGeometry); - static std::string convert(const Sketcher::Constraint* constraint); + static std::string convert(const Sketcher::Constraint* constraint, + GeoIdMode geoIdMode = GeoIdMode::DoNotChangeGeoIds); static std::string convert(const std::string& doc, - const std::vector& constraints); + const std::vector& constraints, + GeoIdMode geoIdMode = GeoIdMode::DoNotChangeGeoIds); static std::vector multiLine(std::string&& singlestring); private: static SingleGeometry process(const Part::Geometry* geo); - static std::string process(const Sketcher::Constraint* constraint); + static std::string process(const Sketcher::Constraint* constraint, + GeoIdMode geoIdMode = GeoIdMode::DoNotChangeGeoIds); }; } // namespace Sketcher diff --git a/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp b/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp index c08e135aa2..3905fdcaaa 100644 --- a/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp +++ b/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -33,6 +34,8 @@ #include #include +#include +#include #include #include #include @@ -42,6 +45,7 @@ #include #include #include +#include #include #include @@ -140,6 +144,185 @@ Sketcher::SketchObject* getSketchObject() // ================================================================================ +// Copy + +bool copySelectionToClipboard(Sketcher::SketchObject* obj) { + std::vector listOfGeoId = getListOfSelectedGeoIds(true); + if (listOfGeoId.empty()) { return false; } + sort(listOfGeoId.begin(), listOfGeoId.end()); + + //Export selected geometries as a formatted string. + std::vector shapeGeometry; + for (auto geoId : listOfGeoId) { + Part::Geometry* geoNew = obj->getGeometry(geoId)->copy(); + shapeGeometry.push_back(geoNew); + } + std::string geosAsStr = Sketcher::PythonConverter::convert( + "objectStr", + shapeGeometry, + Sketcher::PythonConverter::Mode::OmitInternalGeometry); + + // Export constraints of selected geos. + std::vector shapeConstraints; + for (auto constr : obj->Constraints.getValues()) { + + auto isSelectedGeoOrAxis = [](const std::vector& vec, int value) { + return (std::find(vec.begin(), vec.end(), value) != vec.end()) + || value == GeoEnum::GeoUndef || value == GeoEnum::RtPnt + || value == GeoEnum::VAxis || value == GeoEnum::HAxis; + }; + + if (!isSelectedGeoOrAxis(listOfGeoId, constr->First) + || !isSelectedGeoOrAxis(listOfGeoId, constr->Second) + || !isSelectedGeoOrAxis(listOfGeoId, constr->Third)) { + continue; + } + + Constraint* temp = constr->copy(); + for (size_t j = 0; j < listOfGeoId.size(); j++) { + if (temp->First == listOfGeoId[j]) { + temp->First = j; + } + if (temp->Second == listOfGeoId[j]) { + temp->Second = j; + } + if (temp->Third == listOfGeoId[j]) { + temp->Third = j; + } + } + shapeConstraints.push_back(temp); + } + std::string cstrAsStr = Sketcher::PythonConverter::convert("objectStr", shapeConstraints, Sketcher::PythonConverter::GeoIdMode::AddLastGeoIdToGeoIds); + + std::string exportedData = "# Copied from sketcher. From:\n#objectStr = " + Gui::Command::getObjectCmd(obj) + "\n" + + geosAsStr + "\n" + cstrAsStr; + + if (!exportedData.empty()) { + QClipboard* clipboard = QGuiApplication::clipboard(); + clipboard->setText(QString::fromStdString(exportedData)); + return true; + } + return false; +} + +DEF_STD_CMD_A(CmdSketcherCopyClipboard) + +CmdSketcherCopyClipboard::CmdSketcherCopyClipboard() + : Command("Sketcher_CopyClipboard") +{ + sAppModule = "Sketcher"; + sGroup = "Sketcher"; + sMenuText = QT_TR_NOOP("C&opy in sketcher"); + sToolTipText = QT_TR_NOOP("Copy selected geometries and constraints to the clipboard"); + sWhatsThis = "Sketcher_CopyClipboard"; + sStatusTip = sToolTipText; + sPixmap = "edit-copy"; + sAccel = keySequenceToAccel(QKeySequence::Copy); + eType = ForEdit; +} + +void CmdSketcherCopyClipboard::activated(int iMsg) +{ + Q_UNUSED(iMsg); + copySelectionToClipboard(getSketchObject()); +} + +bool CmdSketcherCopyClipboard::isActive() +{ + return isCommandActive(getActiveGuiDocument(), true); +} + +// ================================================================================ + +// Cut + +DEF_STD_CMD_A(CmdSketcherCut) + +CmdSketcherCut::CmdSketcherCut() + : Command("Sketcher_Cut") +{ + sAppModule = "Sketcher"; + sGroup = "Sketcher"; + sMenuText = QT_TR_NOOP("C&ut in sketcher"); + sToolTipText = QT_TR_NOOP("Cut selected geometries and constraints to the clipboard"); + sWhatsThis = "Sketcher_Cut"; + sStatusTip = sToolTipText; + sPixmap = "edit-cut"; + sAccel = keySequenceToAccel(QKeySequence::Cut); + eType = ForEdit; +} + +void CmdSketcherCut::activated(int iMsg) +{ + Q_UNUSED(iMsg); + if (copySelectionToClipboard(getSketchObject())) { + + Gui::Document* doc = getActiveGuiDocument(); + ReleaseHandler(doc); + auto* vp = static_cast(doc->getInEdit()); + + Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Cut in Sketcher")); + vp->deleteSelected(); + Gui::Command::commitCommand(); + } +} + +bool CmdSketcherCut::isActive() +{ + return isCommandActive(getActiveGuiDocument(), true); +} + +// ================================================================================ + +// Paste + +DEF_STD_CMD_A(CmdSketcherPaste) + +CmdSketcherPaste::CmdSketcherPaste() + : Command("Sketcher_Paste") +{ + sAppModule = "Sketcher"; + sGroup = "Sketcher"; + sMenuText = QT_TR_NOOP("P&aste in sketcher"); + sToolTipText = QT_TR_NOOP("Paste selected geometries and constraints from the clipboard"); + sWhatsThis = "Sketcher_Paste"; + sStatusTip = sToolTipText; + sPixmap = "edit-paste"; + sAccel = keySequenceToAccel(QKeySequence::Paste); + eType = ForEdit; +} + +void CmdSketcherPaste::activated(int iMsg) +{ + Q_UNUSED(iMsg); + Gui::Document* doc = getActiveGuiDocument(); + ReleaseHandler(doc); + auto* vp = static_cast(doc->getInEdit()); + Sketcher::SketchObject* obj = vp->getSketchObject(); + + std::string data = QGuiApplication::clipboard()->text().toStdString(); + if (data.find("# Copied from sketcher.", 0) == std::string::npos) { + return; + } + data = "objectStr = " + Gui::Command::getObjectCmd(obj) +"\n" + data; + + Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Paste in Sketcher")); + + Gui::Command::doCommand(Gui::Command::Doc, data.c_str()); + + obj->solve(true); + vp->draw(false, false); + + Gui::Command::commitCommand(); +} + +bool CmdSketcherPaste::isActive() +{ + return isCommandActive(getActiveGuiDocument(), false); +} + +// ================================================================================ + // Select Constraints of selected elements DEF_STD_CMD_A(CmdSketcherSelectConstraints) @@ -2432,5 +2615,8 @@ void CreateSketcherCommandsConstraintAccel() rcCmdMgr.addCommand(new CmdSketcherDeleteAllGeometry()); rcCmdMgr.addCommand(new CmdSketcherDeleteAllConstraints()); rcCmdMgr.addCommand(new CmdSketcherRemoveAxesAlignment()); + rcCmdMgr.addCommand(new CmdSketcherCopyClipboard()); + rcCmdMgr.addCommand(new CmdSketcherCut()); + rcCmdMgr.addCommand(new CmdSketcherPaste()); } // clang-format on diff --git a/src/Mod/Sketcher/Gui/ShortcutListener.cpp b/src/Mod/Sketcher/Gui/ShortcutListener.cpp index 805e54f1f4..b161cb4194 100644 --- a/src/Mod/Sketcher/Gui/ShortcutListener.cpp +++ b/src/Mod/Sketcher/Gui/ShortcutListener.cpp @@ -31,12 +31,6 @@ using namespace SketcherGui; -// ******************** ViewProvider attorney *********************************************// -inline void ViewProviderSketchShortcutListenerAttorney::deleteSelected(ViewProviderSketch& vp) -{ - vp.deleteSelected(); -}; - // ******************** ShortcutListener *********************************************// ShortcutListener::ShortcutListener(ViewProviderSketch* vp) { @@ -55,7 +49,7 @@ bool ShortcutListener::eventFilter(QObject* obj, QEvent* event) switch (kevent->key()) { case Qt::Key_Delete: kevent->accept(); - ViewProviderSketchShortcutListenerAttorney::deleteSelected(*pViewProvider); + pViewProvider->deleteSelected(); return true; default: break; diff --git a/src/Mod/Sketcher/Gui/ShortcutListener.h b/src/Mod/Sketcher/Gui/ShortcutListener.h index 414da71fa3..70366adc83 100644 --- a/src/Mod/Sketcher/Gui/ShortcutListener.h +++ b/src/Mod/Sketcher/Gui/ShortcutListener.h @@ -31,15 +31,6 @@ namespace SketcherGui class ViewProviderSketch; -class ViewProviderSketchShortcutListenerAttorney -{ -private: - static inline void deleteSelected(ViewProviderSketch& vp); - - - friend class ShortcutListener; -}; - class ShortcutListener: public QObject { // Q_OBJECT diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.h b/src/Mod/Sketcher/Gui/ViewProviderSketch.h index e8e16c5c08..bcadc5bed6 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.h +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.h @@ -672,6 +672,7 @@ public: const Gui::View3DInventorViewer* viewer) override; //@} + void deleteSelected(); /// Control the overlays appearing on the Tree and reflecting different sketcher states QIcon mergeColorfulOverlayIcons(const QIcon& orig) const override; @@ -702,7 +703,6 @@ public: friend class ViewProviderSketchDrawSketchHandlerAttorney; friend class ViewProviderSketchCoinAttorney; friend class ViewProviderSketchSnapAttorney; - friend class ViewProviderSketchShortcutListenerAttorney; //@} protected: /** @name enter/exit edit mode */ @@ -867,9 +867,6 @@ private: bool isConstraintSelected(int constraintId) const; - //********* ViewProviderSketchShortcutListenerAttorney ***********// - void deleteSelected(); - //********* ViewProviderSketchDrawSketchHandlerAttorney **********// void setConstraintSelectability(bool enabled = true); void setPositionText(const Base::Vector2d& Pos, const SbString& txt); diff --git a/src/Mod/Sketcher/Gui/Workbench.cpp b/src/Mod/Sketcher/Gui/Workbench.cpp index 5c2d74ed2e..c1be2c1ac5 100644 --- a/src/Mod/Sketcher/Gui/Workbench.cpp +++ b/src/Mod/Sketcher/Gui/Workbench.cpp @@ -543,7 +543,11 @@ inline void SketcherAddWorkbenchTools(Gui::MenuItem& consaccel) << "Sketcher_RemoveAxesAlignment" << "Separator" << "Sketcher_DeleteAllGeometry" - << "Sketcher_DeleteAllConstraints"; + << "Sketcher_DeleteAllConstraints" + << "Separator" + << "Sketcher_CopyClipboard" + << "Sketcher_Cut" + << "Sketcher_Paste"; } template<>