[Sketcher] Auto horizontal/vertical (#11330)

* Refactor sketcher horizontal / vertical constraints and adds a horizontal/vertical command.

* Sketcher : HorVer : change tool icon.

---------

Co-authored-by: Paddle <PaddleStroke@users.noreply.github.com>
This commit is contained in:
PaddleStroke
2023-11-20 18:00:22 +01:00
committed by GitHub
parent 0148cbaac1
commit cce89e4fec
5 changed files with 571 additions and 490 deletions

View File

@@ -2592,6 +2592,347 @@ bool CmdSketcherDimension::isActive(void)
return isCommandActive(getActiveGuiDocument());
}
// Comp for horizontal/vertical =============================================
class CmdSketcherCompHorizontalVertical : public Gui::GroupCommand
{
public:
CmdSketcherCompHorizontalVertical()
: GroupCommand("Sketcher_CompHorVer")
{
sAppModule = "Sketcher";
sGroup = "Sketcher";
sMenuText = QT_TR_NOOP("Horizontal/Vertical");
sToolTipText = QT_TR_NOOP("Constrains a single line to either horizontal or vertical.");
sWhatsThis = "Sketcher_CompHorVer";
sStatusTip = sToolTipText;
eType = ForEdit;
setCheckable(false);
addCommand("Sketcher_ConstrainHorVer");
addCommand("Sketcher_ConstrainHorizontal");
addCommand("Sketcher_ConstrainVertical");
}
const char* className() const override { return "CmdSketcherCompDimensionTools"; }
};
// ============================================================================
bool canHorVerBlock(Sketcher::SketchObject* Obj, int geoId)
{
const std::vector<Sketcher::Constraint*>& vals = Obj->Constraints.getValues();
// check if the edge already has a Horizontal/Vertical/Block constraint
for (auto& constr : vals) {
if (constr->Type == Sketcher::Horizontal && constr->First == geoId
&& constr->FirstPos == Sketcher::PointPos::none) {
Gui::TranslatedUserWarning(
Obj,
QObject::tr("Double constraint"),
QObject::tr("The selected edge already has a horizontal constraint!"));
return false;
}
if (constr->Type == Sketcher::Vertical && constr->First == geoId
&& constr->FirstPos == Sketcher::PointPos::none) {
Gui::TranslatedUserWarning(
Obj,
QObject::tr("Impossible constraint"),
QObject::tr("The selected edge already has a vertical constraint!"));
return false;
}
// check if the edge already has a Block constraint
if (constr->Type == Sketcher::Block && constr->First == geoId
&& constr->FirstPos == Sketcher::PointPos::none) {
Gui::TranslatedUserWarning(
Obj,
QObject::tr("Impossible constraint"),
QObject::tr("The selected edge already has a Block constraint!"));
return false;
}
}
return true;
}
void horVerActivated(CmdSketcherConstraint* cmd, std::string type)
{
// get the selection
std::vector<Gui::SelectionObject> selection = Gui::Command::getSelection().getSelectionEx();
// only one sketch with its subelements are allowed to be selected
if (selection.size() != 1
|| !selection[0].isObjectTypeOf(Sketcher::SketchObject::getClassTypeId())) {
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath(
"User parameter:BaseApp/Preferences/Mod/Sketcher");
bool constraintMode = hGrp->GetBool("ContinuousConstraintMode", true);
if (constraintMode) {
ActivateHandler(cmd->getActiveGuiDocument(), new DrawSketchHandlerGenConstraint(cmd));
Gui::Command::getSelection().clearSelection();
}
else {
Gui::TranslatedUserWarning(cmd->getActiveGuiDocument(),
QObject::tr("Wrong selection"),
QObject::tr("Select an edge from the sketch."));
}
return;
}
// get the needed lists and objects
const std::vector<std::string>& SubNames = selection[0].getSubNames();
auto* Obj = static_cast<Sketcher::SketchObject*>(selection[0].getObject());
const std::vector<Sketcher::Constraint*>& vals = Obj->Constraints.getValues();
std::vector<int> edgegeoids;
std::vector<int> pointgeoids;
std::vector<Sketcher::PointPos> pointpos;
int fixedpoints = 0;
for (auto& name : SubNames) {
int GeoId;
Sketcher::PointPos PosId;
getIdsFromName(name, Obj, GeoId, PosId);
if (isEdge(GeoId, PosId)) {// it is an edge
const Part::Geometry* geo = Obj->getGeometry(GeoId);
if (!isLineSegment(*geo)) {
Gui::TranslatedUserWarning(Obj,
QObject::tr("Impossible constraint"),
QObject::tr("The selected edge is not a line segment."));
return;
}
if (canHorVerBlock(Obj, GeoId)) {
edgegeoids.push_back(GeoId);
}
}
else if (isVertex(GeoId, PosId)) {
// can be a point, a construction point, an external point or root
if (isPointOrSegmentFixed(Obj, GeoId)) {
fixedpoints++;
}
pointgeoids.push_back(GeoId);
pointpos.push_back(PosId);
}
}
if (edgegeoids.empty() && pointgeoids.empty()) {
Gui::TranslatedUserWarning(
Obj,
QObject::tr("Impossible constraint"),
QObject::tr("The selected item(s) can't accept a horizontal or vertical constraint!"));
return;
}
// if there is at least one edge selected, ignore the point alignment functionality
if (!edgegeoids.empty()) {
// undo command open
const char* cmdName = type == "Horizontal" ? "Add horizontal constraint" : type == "Vertical" ? "Add vertical constraint" : "Add horizontal/vertical constraint";
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", cmdName));
for (auto& geoId : edgegeoids) {
std::string typeToApply = type;
if (type == "HorVer") {
const Part::Geometry* geo = Obj->getGeometry(geoId);
auto* line = static_cast<const Part::GeomLineSegment*>(geo);
double angle = toVector2d(line->getEndPoint() - line->getStartPoint()).Angle();
typeToApply = fabs(sin(angle)) < fabs(cos(angle)) ? "Horizontal" : "Vertical";
}
Gui::cmdAppObjectArgs(selection[0].getObject(),
"addConstraint(Sketcher.Constraint('%s',%d))",
typeToApply,
geoId);
}
}
else if (fixedpoints <= 1) {// pointgeoids
// undo command open
const char* cmdName = type == "Horizontal" ? "Add horizontal alignment" : type == "Vertical" ? "Add vertical alignment" : "Add horizontal/vertical alignment";
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", cmdName));
std::vector<int>::iterator it;
std::vector<Sketcher::PointPos>::iterator itp;
for (it = pointgeoids.begin(), itp = pointpos.begin();
it != std::prev(pointgeoids.end()) && itp != std::prev(pointpos.end());
it++, itp++) {
std::string typeToApply = type;
if (type == "HorVer") {
auto point1 = Obj->getPoint(*it, *itp);
auto point2 = Obj->getPoint(*std::next(it), *std::next(itp));
double angle = toVector2d(point2 - point1).Angle();
typeToApply = fabs(sin(angle)) < fabs(cos(angle)) ? "Horizontal" : "Vertical";
}
Gui::cmdAppObjectArgs(selection[0].getObject(),
"addConstraint(Sketcher.Constraint('%s',%d,%d,%d,%d))",
typeToApply,
*it,
static_cast<int>(*itp),
*std::next(it),
static_cast<int>(*std::next(itp)));
}
}
else {// vertex mode, fixedpoints > 1
Gui::TranslatedUserWarning(Obj,
QObject::tr("Impossible constraint"),
QObject::tr("There are more than one fixed points selected. "
"Select a maximum of one fixed point!"));
return;
}
// finish the transaction and update
Gui::Command::commitCommand();
tryAutoRecompute(Obj);
// clear the selection (convenience)
Gui::Command::getSelection().clearSelection();
}
void horVerApplyConstraint(CmdSketcherConstraint* cmd, std::string type, std::vector<SelIdPair>& selSeq, int seqIndex)
{
auto* sketchgui =
static_cast<SketcherGui::ViewProviderSketch*>(cmd->getActiveGuiDocument()->getInEdit());
Sketcher::SketchObject* Obj = sketchgui->getSketchObject();
switch (seqIndex) {
case 0:// {Edge}
{
// create the constraint
const std::vector<Sketcher::Constraint*>& vals = Obj->Constraints.getValues();
int CrvId = selSeq.front().GeoId;
if (CrvId != -1) {
const Part::Geometry* geo = Obj->getGeometry(CrvId);
if (!isLineSegment(*geo)) {
Gui::TranslatedUserWarning(
Obj,
QObject::tr("Impossible constraint"),
QObject::tr("The selected edge is not a line segment."));
return;
}
// check if the edge already has a Horizontal/Vertical/Block constraint
if (!canHorVerBlock(Obj, CrvId)) {
return;
}
std::string typeToApply = type;
if (type == "HorVer") {
const Part::Geometry* geo = Obj->getGeometry(CrvId);
auto* line = static_cast<const Part::GeomLineSegment*>(geo);
double angle = toVector2d(line->getEndPoint() - line->getStartPoint()).Angle();
typeToApply = fabs(sin(angle)) < fabs(cos(angle)) ? "Horizontal" : "Vertical";
}
const char* cmdName = typeToApply == "Horizontal" ? "Add horizontal constraint" : "Add vertical constraint";
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", cmdName));
// issue the actual commands to create the constraint
Gui::cmdAppObjectArgs(sketchgui->getObject(),
"addConstraint(Sketcher.Constraint('%s',%d))",
typeToApply,
CrvId);
// finish the transaction and update
Gui::Command::commitCommand();
tryAutoRecompute(Obj);
}
break;
}
case 1:// {SelVertex, SelVertexOrRoot}
case 2:// {SelRoot, SelVertex}
{
int GeoId1, GeoId2;
Sketcher::PointPos PosId1, PosId2;
GeoId1 = selSeq.at(0).GeoId;
GeoId2 = selSeq.at(1).GeoId;
PosId1 = selSeq.at(0).PosId;
PosId2 = selSeq.at(1).PosId;
if (areBothPointsOrSegmentsFixed(Obj, GeoId1, GeoId2)) {
showNoConstraintBetweenFixedGeometry(Obj);
return;
}
std::string typeToApply = type;
if (type == "HorVer") {
auto point1 = Obj->getPoint(GeoId1, PosId1);
auto point2 = Obj->getPoint(GeoId2, PosId2);
double angle = toVector2d(point2 - point1).Angle();
typeToApply = fabs(sin(angle)) < fabs(cos(angle)) ? "Horizontal" : "Vertical";
}
// undo command open
const char* cmdName = type == "Horizontal" ? "Add horizontal alignment" : "Add vertical alignment";
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", cmdName));
// issue the actual commands to create the constraint
Gui::cmdAppObjectArgs(sketchgui->getObject(),
"addConstraint(Sketcher.Constraint('%s',%d,%d,%d,%d))",
typeToApply,
GeoId1,
static_cast<int>(PosId1),
GeoId2,
static_cast<int>(PosId2));
// finish the transaction and update
Gui::Command::commitCommand();
tryAutoRecompute(Obj);
break;
}
}
}
class CmdSketcherConstrainHorVer : public CmdSketcherConstraint
{
public:
CmdSketcherConstrainHorVer();
~CmdSketcherConstrainHorVer() override
{}
const char* className() const override
{
return "CmdSketcherConstrainHorVer";
}
protected:
void activated(int iMsg) override;
void applyConstraint(std::vector<SelIdPair>& selSeq, int seqIndex) override;
};
CmdSketcherConstrainHorVer::CmdSketcherConstrainHorVer()
: CmdSketcherConstraint("Sketcher_ConstrainHorVer")
{
sAppModule = "Sketcher";
sGroup = "Sketcher";
sMenuText = QT_TR_NOOP("Horizontal/Vertical");
sToolTipText = QT_TR_NOOP("Constrains a single line to either horizontal or vertical, whichever is closer to current alignment.");
sWhatsThis = "Sketcher_ConstrainHorVer";
sStatusTip = sToolTipText;
sPixmap = "Constraint_HorVer";
sAccel = "A";
eType = ForEdit;
allowedSelSequences = { {SelEdge}, {SelVertex, SelVertexOrRoot}, {SelRoot, SelVertex} };
}
void CmdSketcherConstrainHorVer::activated(int iMsg)
{
Q_UNUSED(iMsg);
horVerActivated(this, "HorVer");
}
void CmdSketcherConstrainHorVer::applyConstraint(std::vector<SelIdPair>& selSeq, int seqIndex)
{
horVerApplyConstraint(this, "HorVer", selSeq, seqIndex);
}
// ============================================================================
@@ -2630,255 +2971,12 @@ CmdSketcherConstrainHorizontal::CmdSketcherConstrainHorizontal()
void CmdSketcherConstrainHorizontal::activated(int iMsg)
{
Q_UNUSED(iMsg);
// get the selection
std::vector<Gui::SelectionObject> selection = getSelection().getSelectionEx();
// only one sketch with its subelements are allowed to be selected
if (selection.size() != 1
|| !selection[0].isObjectTypeOf(Sketcher::SketchObject::getClassTypeId())) {
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath(
"User parameter:BaseApp/Preferences/Mod/Sketcher");
bool constraintMode = hGrp->GetBool("ContinuousConstraintMode", true);
if (constraintMode) {
ActivateHandler(getActiveGuiDocument(), new DrawSketchHandlerGenConstraint(this));
getSelection().clearSelection();
}
else {
Gui::TranslatedUserWarning(getActiveGuiDocument(),
QObject::tr("Wrong selection"),
QObject::tr("Select an edge from the sketch."));
}
return;
}
// get the needed lists and objects
const std::vector<std::string>& SubNames = selection[0].getSubNames();
Sketcher::SketchObject* Obj = static_cast<Sketcher::SketchObject*>(selection[0].getObject());
const std::vector<Sketcher::Constraint*>& vals = Obj->Constraints.getValues();
std::vector<int> edgegeoids;
std::vector<int> pointgeoids;
std::vector<Sketcher::PointPos> pointpos;
int fixedpoints = 0;
// go through the selected subelements
for (std::vector<std::string>::const_iterator it = SubNames.begin(); it != SubNames.end();
++it) {
int GeoId;
Sketcher::PointPos PosId;
getIdsFromName((*it), Obj, GeoId, PosId);
if (isEdge(GeoId, PosId)) {// it is an edge
const Part::Geometry* geo = Obj->getGeometry(GeoId);
if (! isLineSegment(*geo)) {
Gui::TranslatedUserWarning(Obj,
QObject::tr("Impossible constraint"),
QObject::tr("The selected edge is not a line segment."));
return;
}
// check if the edge already has a Horizontal/Vertical/Block constraint
for (std::vector<Sketcher::Constraint*>::const_iterator it = vals.begin();
it != vals.end();
++it) {
if ((*it)->Type == Sketcher::Horizontal && (*it)->First == GeoId
&& (*it)->FirstPos == Sketcher::PointPos::none) {
Gui::TranslatedUserWarning(
Obj,
QObject::tr("Double constraint"),
QObject::tr("The selected edge already has a horizontal constraint!"));
return;
}
if ((*it)->Type == Sketcher::Vertical && (*it)->First == GeoId
&& (*it)->FirstPos == Sketcher::PointPos::none) {
Gui::TranslatedUserWarning(
Obj,
QObject::tr("Impossible constraint"),
QObject::tr("The selected edge already has a vertical constraint!"));
return;
}
// check if the edge already has a Block constraint
if ((*it)->Type == Sketcher::Block && (*it)->First == GeoId
&& (*it)->FirstPos == Sketcher::PointPos::none) {
Gui::TranslatedUserWarning(
Obj,
QObject::tr("Impossible constraint"),
QObject::tr("The selected edge already has a Block constraint!"));
return;
}
}
edgegeoids.push_back(GeoId);
}
else if (isVertex(GeoId, PosId)) {
// can be a point, a construction point, an external point or root
if (isPointOrSegmentFixed(Obj, GeoId)) {
fixedpoints++;
}
pointgeoids.push_back(GeoId);
pointpos.push_back(PosId);
}
}
if (edgegeoids.empty() && pointgeoids.empty()) {
Gui::TranslatedUserWarning(
Obj,
QObject::tr("Impossible constraint"),
QObject::tr("The selected item(s) can't accept a horizontal constraint!"));
return;
}
// if there is at least one edge selected, ignore the point alignment functionality
if (!edgegeoids.empty()) {
// undo command open
openCommand(QT_TRANSLATE_NOOP("Command", "Add horizontal constraint"));
for (std::vector<int>::iterator it = edgegeoids.begin(); it != edgegeoids.end(); it++) {
// issue the actual commands to create the constraint
Gui::cmdAppObjectArgs(selection[0].getObject(),
"addConstraint(Sketcher.Constraint('Horizontal',%d))",
*it);
}
}
else if (fixedpoints <= 1) {// pointgeoids
// undo command open
openCommand(QT_TRANSLATE_NOOP("Command", "Add horizontal alignment"));
std::vector<int>::iterator it;
std::vector<Sketcher::PointPos>::iterator itp;
for (it = pointgeoids.begin(), itp = pointpos.begin();
it != std::prev(pointgeoids.end()) && itp != std::prev(pointpos.end());
it++, itp++) {
// issue the actual commands to create the constraint
Gui::cmdAppObjectArgs(selection[0].getObject(),
"addConstraint(Sketcher.Constraint('Horizontal',%d,%d,%d,%d))",
*it,
static_cast<int>(*itp),
*std::next(it),
static_cast<int>(*std::next(itp)));
}
}
else {// vertex mode, fixedpoints > 1
Gui::TranslatedUserWarning(Obj,
QObject::tr("Impossible constraint"),
QObject::tr("There are more than one fixed points selected. "
"Select a maximum of one fixed point!"));
return;
}
// finish the transaction and update
commitCommand();
tryAutoRecompute(Obj);
// clear the selection (convenience)
getSelection().clearSelection();
horVerActivated(this, "Horizontal");
}
void CmdSketcherConstrainHorizontal::applyConstraint(std::vector<SelIdPair>& selSeq, int seqIndex)
{
SketcherGui::ViewProviderSketch* sketchgui =
static_cast<SketcherGui::ViewProviderSketch*>(getActiveGuiDocument()->getInEdit());
Sketcher::SketchObject* Obj = sketchgui->getSketchObject();
switch (seqIndex) {
case 0:// {Edge}
{
// create the constraint
const std::vector<Sketcher::Constraint*>& vals = Obj->Constraints.getValues();
int CrvId = selSeq.front().GeoId;
if (CrvId != -1) {
const Part::Geometry* geo = Obj->getGeometry(CrvId);
if (! isLineSegment(*geo)) {
Gui::TranslatedUserWarning(
Obj,
QObject::tr("Impossible constraint"),
QObject::tr("The selected edge is not a line segment."));
return;
}
// check if the edge already has a Horizontal/Vertical/Block constraint
for (std::vector<Sketcher::Constraint*>::const_iterator it = vals.begin();
it != vals.end();
++it) {
if ((*it)->Type == Sketcher::Horizontal && (*it)->First == CrvId
&& (*it)->FirstPos == Sketcher::PointPos::none) {
Gui::TranslatedUserWarning(
Obj,
QObject::tr("Double constraint"),
QObject::tr("The selected edge already has a horizontal constraint!"));
return;
}
if ((*it)->Type == Sketcher::Vertical && (*it)->First == CrvId
&& (*it)->FirstPos == Sketcher::PointPos::none) {
Gui::TranslatedUserWarning(
Obj,
QObject::tr("Impossible constraint"),
QObject::tr("The selected edge already has a vertical constraint!"));
return;
}
// check if the edge already has a Block constraint
if ((*it)->Type == Sketcher::Block && (*it)->First == CrvId
&& (*it)->FirstPos == Sketcher::PointPos::none) {
Gui::TranslatedUserWarning(
Obj,
QObject::tr("Impossible constraint"),
QObject::tr("The selected edge already has a Block constraint!"));
return;
}
}
// undo command open
Gui::Command::openCommand(
QT_TRANSLATE_NOOP("Command", "Add horizontal constraint"));
// issue the actual commands to create the constraint
Gui::cmdAppObjectArgs(sketchgui->getObject(),
"addConstraint(Sketcher.Constraint('Horizontal',%d))",
CrvId);
// finish the transaction and update
Gui::Command::commitCommand();
tryAutoRecompute(Obj);
}
break;
}
case 1:// {SelVertex, SelVertexOrRoot}
case 2:// {SelRoot, SelVertex}
{
int GeoId1, GeoId2;
Sketcher::PointPos PosId1, PosId2;
GeoId1 = selSeq.at(0).GeoId;
GeoId2 = selSeq.at(1).GeoId;
PosId1 = selSeq.at(0).PosId;
PosId2 = selSeq.at(1).PosId;
if (areBothPointsOrSegmentsFixed(Obj, GeoId1, GeoId2)) {
showNoConstraintBetweenFixedGeometry(Obj);
return;
}
// undo command open
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Add horizontal alignment"));
// issue the actual commands to create the constraint
Gui::cmdAppObjectArgs(sketchgui->getObject(),
"addConstraint(Sketcher.Constraint('Horizontal',%d,%d,%d,%d))",
GeoId1,
static_cast<int>(PosId1),
GeoId2,
static_cast<int>(PosId2));
// finish the transaction and update
Gui::Command::commitCommand();
tryAutoRecompute(Obj);
break;
}
}
horVerApplyConstraint(this, "Horizontal", selSeq, seqIndex);
}
// ================================================================================
@@ -2918,253 +3016,12 @@ CmdSketcherConstrainVertical::CmdSketcherConstrainVertical()
void CmdSketcherConstrainVertical::activated(int iMsg)
{
Q_UNUSED(iMsg);
// get the selection
std::vector<Gui::SelectionObject> selection = getSelection().getSelectionEx();
// only one sketch with its subelements are allowed to be selected
if (selection.size() != 1
|| !selection[0].isObjectTypeOf(Sketcher::SketchObject::getClassTypeId())) {
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath(
"User parameter:BaseApp/Preferences/Mod/Sketcher");
bool constraintMode = hGrp->GetBool("ContinuousConstraintMode", true);
if (constraintMode) {
ActivateHandler(getActiveGuiDocument(), new DrawSketchHandlerGenConstraint(this));
getSelection().clearSelection();
}
else {
Gui::TranslatedUserWarning(getActiveGuiDocument(),
QObject::tr("Wrong selection"),
QObject::tr("Select an edge from the sketch."));
}
return;
}
// get the needed lists and objects
const std::vector<std::string>& SubNames = selection[0].getSubNames();
Sketcher::SketchObject* Obj = static_cast<Sketcher::SketchObject*>(selection[0].getObject());
const std::vector<Sketcher::Constraint*>& vals = Obj->Constraints.getValues();
std::vector<int> edgegeoids;
std::vector<int> pointgeoids;
std::vector<Sketcher::PointPos> pointpos;
int fixedpoints = 0;
// go through the selected subelements
for (std::vector<std::string>::const_iterator it = SubNames.begin(); it != SubNames.end();
++it) {
int GeoId;
Sketcher::PointPos PosId;
getIdsFromName((*it), Obj, GeoId, PosId);
if (isEdge(GeoId, PosId)) {// it is an edge
const Part::Geometry* geo = Obj->getGeometry(GeoId);
if (! isLineSegment(*geo)) {
Gui::TranslatedUserWarning(Obj,
QObject::tr("Impossible constraint"),
QObject::tr("The selected edge is not a line segment."));
return;
}
// check if the edge already has a Horizontal/Vertical/Block constraint
for (std::vector<Sketcher::Constraint*>::const_iterator it = vals.begin();
it != vals.end();
++it) {
if ((*it)->Type == Sketcher::Vertical && (*it)->First == GeoId
&& (*it)->FirstPos == Sketcher::PointPos::none) {
Gui::TranslatedUserWarning(
Obj,
QObject::tr("Double constraint"),
QObject::tr("The selected edge already has a horizontal constraint!"));
return;
}
if ((*it)->Type == Sketcher::Horizontal && (*it)->First == GeoId
&& (*it)->FirstPos == Sketcher::PointPos::none) {
Gui::TranslatedUserWarning(
Obj,
QObject::tr("Impossible constraint"),
QObject::tr("The selected edge already has a horizontal constraint!"));
return;
}
// check if the edge already has a Block constraint
if ((*it)->Type == Sketcher::Block && (*it)->First == GeoId
&& (*it)->FirstPos == Sketcher::PointPos::none) {
Gui::TranslatedUserWarning(
Obj,
QObject::tr("Impossible constraint"),
QObject::tr("The selected edge already has a Block constraint!"));
return;
}
}
edgegeoids.push_back(GeoId);
}
else if (isVertex(GeoId, PosId)) {
// can be a point, a construction point, an external point, root or a blocked geometry
if (isPointOrSegmentFixed(Obj, GeoId)) {
fixedpoints++;
}
pointgeoids.push_back(GeoId);
pointpos.push_back(PosId);
}
}
if (edgegeoids.empty() && pointgeoids.empty()) {
Gui::TranslatedUserWarning(
Obj,
QObject::tr("Impossible constraint"),
QObject::tr("The selected item(s) can't accept a vertical constraint!"));
return;
}
// if there is at least one edge selected, ignore the point alignment functionality
if (!edgegeoids.empty()) {
// undo command open
openCommand(QT_TRANSLATE_NOOP("Command", "Add vertical constraint"));
for (std::vector<int>::iterator it = edgegeoids.begin(); it != edgegeoids.end(); it++) {
// issue the actual commands to create the constraint
Gui::cmdAppObjectArgs(selection[0].getObject(),
"addConstraint(Sketcher.Constraint('Vertical',%d))",
*it);
}
}
else if (fixedpoints <= 1) {// vertex mode, maximum one fixed point
// undo command open
openCommand(QT_TRANSLATE_NOOP("Command", "Add vertical alignment"));
std::vector<int>::iterator it;
std::vector<Sketcher::PointPos>::iterator itp;
for (it = pointgeoids.begin(), itp = pointpos.begin();
it != std::prev(pointgeoids.end()) && itp != std::prev(pointpos.end());
it++, itp++) {
// issue the actual commands to create the constraint
Gui::cmdAppObjectArgs(selection[0].getObject(),
"addConstraint(Sketcher.Constraint('Vertical',%d,%d,%d,%d))",
*it,
static_cast<int>(*itp),
*std::next(it),
static_cast<int>(*std::next(itp)));
}
}
else {// vertex mode, fixedpoints > 1
Gui::TranslatedUserWarning(Obj,
QObject::tr("Impossible constraint"),
QObject::tr("There are more than one fixed points selected. "
"Select a maximum of one fixed point!"));
return;
}
// finish the transaction and update
commitCommand();
tryAutoRecompute(Obj);
// clear the selection (convenience)
getSelection().clearSelection();
horVerActivated(this, "Vertical");
}
void CmdSketcherConstrainVertical::applyConstraint(std::vector<SelIdPair>& selSeq, int seqIndex)
{
SketcherGui::ViewProviderSketch* sketchgui =
static_cast<SketcherGui::ViewProviderSketch*>(getActiveGuiDocument()->getInEdit());
Sketcher::SketchObject* Obj = sketchgui->getSketchObject();
switch (seqIndex) {
case 0:// {Edge}
{
// create the constraint
const std::vector<Sketcher::Constraint*>& vals = Obj->Constraints.getValues();
int CrvId = selSeq.front().GeoId;
if (CrvId != -1) {
const Part::Geometry* geo = Obj->getGeometry(CrvId);
if (! isLineSegment(*geo)) {
Gui::TranslatedUserWarning(
Obj,
QObject::tr("Impossible constraint"),
QObject::tr("The selected edge is not a line segment."));
return;
}
// check if the edge already has a Horizontal or Vertical constraint
for (std::vector<Sketcher::Constraint*>::const_iterator it = vals.begin();
it != vals.end();
++it) {
if ((*it)->Type == Sketcher::Horizontal && (*it)->First == CrvId
&& (*it)->FirstPos == Sketcher::PointPos::none) {
Gui::TranslatedUserWarning(
Obj,
QObject::tr("Impossible constraint"),
QObject::tr("The selected edge already has a horizontal constraint!"));
return;
}
if ((*it)->Type == Sketcher::Vertical && (*it)->First == CrvId
&& (*it)->FirstPos == Sketcher::PointPos::none) {
Gui::TranslatedUserWarning(
Obj,
QObject::tr("Double constraint"),
QObject::tr("The selected edge already has a vertical constraint!"));
return;
}
// check if the edge already has a Block constraint
if ((*it)->Type == Sketcher::Block && (*it)->First == CrvId
&& (*it)->FirstPos == Sketcher::PointPos::none) {
Gui::TranslatedUserWarning(
Obj,
QObject::tr("Impossible constraint"),
QObject::tr("The selected edge already has a Block constraint!"));
return;
}
}
// undo command open
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Add vertical constraint"));
// issue the actual commands to create the constraint
Gui::cmdAppObjectArgs(sketchgui->getObject(),
"addConstraint(Sketcher.Constraint('Vertical',%d))",
CrvId);
// finish the transaction and update
Gui::Command::commitCommand();
tryAutoRecompute(Obj);
}
break;
}
case 1:// {SelVertex, SelVertexOrRoot}
case 2:// {SelRoot, SelVertex}
{
int GeoId1, GeoId2;
Sketcher::PointPos PosId1, PosId2;
GeoId1 = selSeq.at(0).GeoId;
GeoId2 = selSeq.at(1).GeoId;
PosId1 = selSeq.at(0).PosId;
PosId2 = selSeq.at(1).PosId;
if (areBothPointsOrSegmentsFixed(Obj, GeoId1, GeoId2)) {
showNoConstraintBetweenFixedGeometry(Obj);
return;
}
// undo command open
Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Add horizontal alignment"));
// issue the actual commands to create the constraint
Gui::cmdAppObjectArgs(sketchgui->getObject(),
"addConstraint(Sketcher.Constraint('Vertical',%d,%d,%d,%d))",
GeoId1,
static_cast<int>(PosId1),
GeoId2,
static_cast<int>(PosId2));
// finish the transaction and update
Gui::Command::commitCommand();
tryAutoRecompute(Obj);
break;
}
}
horVerApplyConstraint(this, "Vertical", selSeq, seqIndex);
}
// ======================================================================================
@@ -10069,6 +9926,8 @@ void CreateSketcherCommandsConstraints()
rcCmdMgr.addCommand(new CmdSketcherConstrainHorizontal());
rcCmdMgr.addCommand(new CmdSketcherConstrainVertical());
rcCmdMgr.addCommand(new CmdSketcherConstrainHorVer());
rcCmdMgr.addCommand(new CmdSketcherCompHorizontalVertical());
rcCmdMgr.addCommand(new CmdSketcherConstrainLock());
rcCmdMgr.addCommand(new CmdSketcherConstrainBlock());
rcCmdMgr.addCommand(new CmdSketcherConstrainCoincident());

View File

@@ -20,6 +20,7 @@
<file>icons/constraints/Constraint_Horizontal.svg</file>
<file>icons/constraints/Constraint_HorizontalDistance.svg</file>
<file>icons/constraints/Constraint_HorizontalDistance_Driven.svg</file>
<file>icons/constraints/Constraint_HorVer.svg</file>
<file>icons/constraints/Constraint_InternalAlignment.svg</file>
<file>icons/constraints/Constraint_InternalAlignment_Ellipse_Focus1.svg</file>
<file>icons/constraints/Constraint_InternalAlignment_Ellipse_Focus2.svg</file>

View File

@@ -0,0 +1,215 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="64px"
height="64px"
id="svg2816"
version="1.1"
sodipodi:docname="Constraint_HorVer.svg"
inkscape:version="1.1-beta1 (77e7b44db3, 2021-03-28)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<sodipodi:namedview
id="namedview26"
pagecolor="#505050"
bordercolor="#eeeeee"
borderopacity="1"
objecttolerance="10.0"
gridtolerance="10.0"
guidetolerance="10.0"
inkscape:pageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="8.3195532"
inkscape:cx="35.518734"
inkscape:cy="1.262087"
inkscape:window-width="3840"
inkscape:window-height="1571"
inkscape:window-x="-9"
inkscape:window-y="-9"
inkscape:window-maximized="1"
inkscape:current-layer="svg2816" />
<defs
id="defs2818">
<linearGradient
id="linearGradient3602">
<stop
style="stop-color:#ff2600;stop-opacity:1"
offset="0"
id="stop3604" />
<stop
style="stop-color:#ff5f00;stop-opacity:1"
offset="1"
id="stop3606" />
</linearGradient>
<linearGradient
xlink:href="#linearGradient3602"
id="linearGradient3608"
x1="3.909091"
y1="14.363636"
x2="24.818181"
y2="14.363636"
gradientUnits="userSpaceOnUse" />
<linearGradient
xlink:href="#linearGradient3602-7"
id="linearGradient3608-5"
x1="3.909091"
y1="14.363636"
x2="24.81818"
y2="14.363636"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="linearGradient3602-7">
<stop
style="stop-color:#c51900;stop-opacity:1"
offset="0"
id="stop3604-1" />
<stop
style="stop-color:#ff5f00;stop-opacity:1"
offset="1"
id="stop3606-3" />
</linearGradient>
<linearGradient
xlink:href="#linearGradient3602-5"
id="linearGradient3608-1"
x1="3.909091"
y1="14.363636"
x2="24.81818"
y2="14.363636"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="linearGradient3602-5">
<stop
style="stop-color:#c51900;stop-opacity:1"
offset="0"
id="stop3604-9" />
<stop
style="stop-color:#ff5f00;stop-opacity:1"
offset="1"
id="stop3606-9" />
</linearGradient>
<linearGradient
y2="14.363636"
x2="24.81818"
y1="14.363636"
x1="3.909091"
gradientUnits="userSpaceOnUse"
id="linearGradient3686"
xlink:href="#linearGradient3602-5" />
<linearGradient
xlink:href="#linearGradient3602-58"
id="linearGradient3608-8"
x1="3.909091"
y1="14.363636"
x2="24.81818"
y2="14.363636"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="linearGradient3602-58">
<stop
style="stop-color:#c51900;stop-opacity:1"
offset="0"
id="stop3604-2" />
<stop
style="stop-color:#ff5f00;stop-opacity:1"
offset="1"
id="stop3606-2" />
</linearGradient>
<linearGradient
y2="14.363636"
x2="24.81818"
y1="14.363636"
x1="3.909091"
gradientUnits="userSpaceOnUse"
id="linearGradient3726"
xlink:href="#linearGradient3602-58" />
</defs>
<metadata
id="metadata2821">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:creator>
<cc:Agent>
<dc:title>[wmayer]</dc:title>
</cc:Agent>
</dc:creator>
<dc:date>2011-10-10</dc:date>
<dc:relation>https://www.freecad.org/wiki/index.php?title=Artwork</dc:relation>
<dc:publisher>
<cc:Agent>
<dc:title>FreeCAD</dc:title>
</cc:Agent>
</dc:publisher>
<dc:identifier>FreeCAD/src/Mod/Sketcher/Gui/Resources/icons/Constraint_Horizontal.svg</dc:identifier>
<dc:rights>
<cc:Agent>
<dc:title>FreeCAD LGPL2+</dc:title>
</cc:Agent>
</dc:rights>
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
<dc:contributor>
<cc:Agent>
<dc:title>[agryson] Alexander Gryson</dc:title>
</cc:Agent>
</dc:contributor>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1-75">
<rect
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#cc0000;fill-opacity:1;fill-rule:nonzero;stroke:#280000;stroke-width:2;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
id="rect3770-7"
width="57.992863"
height="9.9582825"
x="3.0265496"
y="26.997831"
rx="0"
ry="0"
transform="matrix(0.99999974,7.1938714e-4,-7.1838503e-4,0.99999974,0,0)" />
<rect
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:#ef2929;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
id="rect3770-3-2"
width="53.993343"
height="5.9749722"
x="5.0389857"
y="28.997681"
rx="0"
ry="0"
transform="matrix(0.99999989,4.636052e-4,-0.00111473,0.99999938,0,0)" />
</g>
<g
id="layer1-75-9"
transform="rotate(-90,31.999999,32.000001)">
<rect
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#cc0000;fill-opacity:1;fill-rule:nonzero;stroke:#280000;stroke-width:2;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
id="rect3770-7-3"
width="57.992863"
height="9.9582825"
x="3.0265496"
y="26.997831"
rx="0"
ry="0"
transform="matrix(0.99999974,7.1938714e-4,-7.1838503e-4,0.99999974,0,0)" />
<rect
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:#ef2929;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
id="rect3770-3-2-2"
width="53.993343"
height="5.9749722"
x="5.0389857"
y="28.997681"
rx="0"
ry="0"
transform="matrix(0.99999989,4.636052e-4,-0.00111473,0.99999938,0,0)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.0 KiB

View File

@@ -211,6 +211,12 @@ inline Base::Vector3d toVector3d(const Base::Vector2d& vector2d)
return Base::Vector3d(vector2d.x, vector2d.y, 0.);
}
/// converts a 3D vector in the XY plane into a 2D vector
inline Base::Vector2d toVector2d(const Base::Vector3d& vector3d)
{
return Base::Vector2d(vector3d.x, vector3d.y);
}
template<typename T>
auto toPointerVector(const std::vector<std::unique_ptr<T>>& vector)

View File

@@ -432,6 +432,7 @@ inline void SketcherAddWorkbenchConstraints<Gui::MenuItem>(Gui::MenuItem& cons)
<< "Sketcher_ConstrainPointOnObject"
<< "Sketcher_ConstrainVertical"
<< "Sketcher_ConstrainHorizontal"
<< "Sketcher_ConstrainHorVer"
<< "Sketcher_ConstrainParallel"
<< "Sketcher_ConstrainPerpendicular"
<< "Sketcher_ConstrainTangent"
@@ -462,8 +463,7 @@ inline void SketcherAddWorkbenchConstraints<Gui::ToolBarItem>(Gui::ToolBarItem&
cons << "Sketcher_ConstrainCoincident"
<< "Sketcher_ConstrainPointOnObject"
<< "Sketcher_ConstrainVertical"
<< "Sketcher_ConstrainHorizontal"
<< "Sketcher_CompHorVer"
<< "Sketcher_ConstrainParallel"
<< "Sketcher_ConstrainPerpendicular"
<< "Sketcher_ConstrainTangent"