From fb2cd4d7b3543fb651c4b3d28f23cc768d2cb512 Mon Sep 17 00:00:00 2001 From: AjinkyaDahale Date: Fri, 27 Jan 2017 21:37:15 +0530 Subject: [PATCH] Moved Perpendicular to constraint mode framework A couple of combinations, endpoint-endpoint and endpoint-curve, do not work, and the latter probably should not work ever since endpoint-curve- curve exists. --- src/Mod/Sketcher/Gui/CommandConstraints.cpp | 249 +++++++++++++++++++- 1 file changed, 243 insertions(+), 6 deletions(-) diff --git a/src/Mod/Sketcher/Gui/CommandConstraints.cpp b/src/Mod/Sketcher/Gui/CommandConstraints.cpp index 8a539a564e76..c2e74627deac 100644 --- a/src/Mod/Sketcher/Gui/CommandConstraints.cpp +++ b/src/Mod/Sketcher/Gui/CommandConstraints.cpp @@ -2859,6 +2859,7 @@ CmdSketcherConstrainPerpendicular::CmdSketcherConstrainPerpendicular() sAccel = "N"; eType = ForEdit; + // TODO: there are two more combos: endpoint then curve and endpoint then endpoint allowedSelSequences = {{SelEdge, SelEdge}, {SelEdge, SelHAxis}, {SelEdge, SelVAxis}, {SelHAxis, SelEdge}, {SelVAxis, SelEdge}, {SelVertex, SelEdge, SelEdge}, {SelVertex, SelEdge, SelHAxis}, @@ -2892,10 +2893,14 @@ void CmdSketcherConstrainPerpendicular::activated(int iMsg) // only one sketch with its subelements are allowed to be selected if (selection.size() != 1) { - strError = QObject::tr("Select some geometry from the sketch.", "perpendicular constraint"); - if (!strError.isEmpty()) strError.append(QString::fromLatin1("\n\n")); - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - strError+strBasicHelp); +// strError = QObject::tr("Select some geometry from the sketch.", "perpendicular constraint"); +// if (!strError.isEmpty()) strError.append(QString::fromLatin1("\n\n")); +// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), +// strError+strBasicHelp); + + ActivateHandler(getActiveGuiDocument(), + new DrawSketchHandlerGenConstraint(constraintCursor, this)); + getSelection().clearSelection(); return; } @@ -2916,7 +2921,7 @@ void CmdSketcherConstrainPerpendicular::activated(int iMsg) getIdsFromName(SubNames[0], Obj, GeoId1, PosId1); getIdsFromName(SubNames[1], Obj, GeoId2, PosId2); - if (checkBothExternal(GeoId1, GeoId2)){ //checkBothExternal displays error message + if (checkBothExternal(GeoId1, GeoId2)) { //checkBothExternal displays error message showNoConstraintBetweenExternal(); return; } @@ -3241,12 +3246,173 @@ void CmdSketcherConstrainPerpendicular::activated(int iMsg) void CmdSketcherConstrainPerpendicular::applyConstraint(std::vector &selSeq, int seqIndex) { + SketcherGui::ViewProviderSketch* sketchgui = static_cast(getActiveGuiDocument()->getInEdit()); + Sketcher::SketchObject* Obj = sketchgui->getSketchObject(); + QString strError; + + int GeoId1 = Constraint::GeoUndef, GeoId2 = Constraint::GeoUndef, GeoId3 = Constraint::GeoUndef; + Sketcher::PointPos PosId1 = Sketcher::none, PosId2 = Sketcher::none, PosId3 = Sketcher::none; + switch (seqIndex) { case 0: // {SelEdge, SelEdge} case 1: // {SelEdge, SelHAxis} case 2: // {SelEdge, SelVAxis} case 3: // {SelHAxis, SelEdge} case 4: // {SelVAxis, SelEdge} + { + GeoId1 = selSeq.at(0).GeoId; GeoId2 = selSeq.at(1).GeoId; + + const Part::Geometry *geo1 = Obj->getGeometry(GeoId1); + const Part::Geometry *geo2 = Obj->getGeometry(GeoId2); + + if (geo1->getTypeId() != Part::GeomLineSegment::getClassTypeId() && + geo2->getTypeId() != Part::GeomLineSegment::getClassTypeId()) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("One of the selected edges should be a line.")); + return; + } + + if( geo1 && geo2 && + ( geo1->getTypeId() == Part::GeomBSplineCurve::getClassTypeId() || + geo2->getTypeId() == Part::GeomBSplineCurve::getClassTypeId() )){ + + // unsupported until tangent to BSpline at any point implemented. + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Perpendicular to BSpline edge currently unsupported.")); + return; + } + + if (geo1->getTypeId() == Part::GeomLineSegment::getClassTypeId()) + std::swap(GeoId1,GeoId2); + + // GeoId2 is the line + geo1 = Obj->getGeometry(GeoId1); + geo2 = Obj->getGeometry(GeoId2); + + if( geo1->getTypeId() == Part::GeomEllipse::getClassTypeId() || + geo1->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() || + geo1->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId() || + geo1->getTypeId() == Part::GeomArcOfParabola::getClassTypeId() ) { + + Base::Vector3d center; + Base::Vector3d majdir; + Base::Vector3d focus; + double majord = 0; + double minord = 0; + double phi = 0; + + if( geo1->getTypeId() == Part::GeomEllipse::getClassTypeId() ){ + const Part::GeomEllipse *ellipse = static_cast(geo1); + + center=ellipse->getCenter(); + majord=ellipse->getMajorRadius(); + minord=ellipse->getMinorRadius(); + majdir=ellipse->getMajorAxisDir(); + phi=atan2(majdir.y, majdir.x); + } + else if( geo1->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() ){ + const Part::GeomArcOfEllipse *aoe = static_cast(geo1); + + center=aoe->getCenter(); + majord=aoe->getMajorRadius(); + minord=aoe->getMinorRadius(); + majdir=aoe->getMajorAxisDir(); + phi=atan2(majdir.y, majdir.x); + } + else if( geo1->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId() ){ + const Part::GeomArcOfHyperbola *aoh = static_cast(geo1); + + center=aoh->getCenter(); + majord=aoh->getMajorRadius(); + minord=aoh->getMinorRadius(); + majdir=aoh->getMajorAxisDir(); + phi=atan2(majdir.y, majdir.x); + } + else if( geo1->getTypeId() == Part::GeomArcOfParabola::getClassTypeId() ){ + const Part::GeomArcOfParabola *aop = static_cast(geo1); + + center=aop->getCenter(); + focus=aop->getFocus(); + } + + const Part::GeomLineSegment *line = static_cast(geo2); + + Base::Vector3d point1=line->getStartPoint(); + Base::Vector3d PoO; + + if( geo1->getTypeId() == Part::GeomArcOfHyperbola::getClassTypeId() ) { + double df=sqrt(majord*majord+minord*minord); + Base::Vector3d direction=point1-(center+majdir*df); // towards the focus + double tapprox=atan2(direction.y,direction.x)-phi; + + PoO = Base::Vector3d(center.x+majord*cosh(tapprox)*cos(phi)-minord*sinh(tapprox)*sin(phi), + center.y+majord*cosh(tapprox)*sin(phi)+minord*sinh(tapprox)*cos(phi), 0); + } + else if( geo1->getTypeId() == Part::GeomArcOfParabola::getClassTypeId() ) { + Base::Vector3d direction=point1-focus; // towards the focus + + PoO = point1 + direction / 2; + } + else { + Base::Vector3d direction=point1-center; + double tapprox=atan2(direction.y,direction.x)-phi; // we approximate the eccentric anomally by the polar + + PoO = Base::Vector3d(center.x+majord*cos(tapprox)*cos(phi)-minord*sin(tapprox)*sin(phi), + center.y+majord*cos(tapprox)*sin(phi)+minord*sin(tapprox)*cos(phi), 0); + } + openCommand("add perpendicular constraint"); + + try { + // Add a point + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addGeometry(Part.Point(App.Vector(%f,%f,0)))", + Obj->getNameInDocument(), PoO.x,PoO.y); + int GeoIdPoint = Obj->getHighestCurveIndex(); + + // Point on first object (ellipse, arc of ellipse) + Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ", + Obj->getNameInDocument(),GeoIdPoint,Sketcher::start,GeoId1); + // Point on second object + Gui::Command::doCommand(Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ", + Obj->getNameInDocument(),GeoIdPoint,Sketcher::start,GeoId2); + + // add constraint: Perpendicular-via-point + Gui::Command::doCommand( + Gui::Command::Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('PerpendicularViaPoint',%d,%d,%d,%d))", + Obj->getNameInDocument(), GeoId1, GeoId2 ,GeoIdPoint, Sketcher::start); + + commitCommand(); + } + catch (const Base::Exception& e) { + Base::Console().Error("%s\n", e.what()); + Gui::Command::abortCommand(); + } + + + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher"); + bool autoRecompute = hGrp->GetBool("AutoRecompute",false); + + if(autoRecompute) + Gui::Command::updateActive(); + + getSelection().clearSelection(); + return; + + } + + openCommand("add perpendicular constraint"); + Gui::Command::doCommand( + Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Perpendicular',%d,%d)) ", + Obj->getNameInDocument(),GeoId1,GeoId2); + commitCommand(); + + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher"); + bool autoRecompute = hGrp->GetBool("AutoRecompute",false); + + if(autoRecompute) + Gui::Command::updateActive(); + + return; + } case 5: // {SelVertex, SelEdge, SelEdge} case 6: // {SelVertex, SelEdge, SelHAxis} case 7: // {SelVertex, SelEdge, SelVAxis} @@ -3257,6 +3423,13 @@ void CmdSketcherConstrainPerpendicular::applyConstraint(std::vector & case 12: // {SelRoot, SelEdge, SelVAxis} case 13: // {SelRoot, SelHAxis, SelEdge} case 14: // {SelRoot, SelVAxis, SelEdge} + { + //let's sink the point to be GeoId3. + GeoId1 = selSeq.at(1).GeoId; GeoId2 = selSeq.at(2).GeoId; GeoId3 = selSeq.at(0).GeoId; + PosId3 = selSeq.at(0).PosId; + + break; + } case 15: // {SelEdge, SelVertex, SelEdge} case 16: // {SelEdge, SelVertex, SelHAxis} case 17: // {SelEdge, SelVertex, SelVAxis} @@ -3267,11 +3440,75 @@ void CmdSketcherConstrainPerpendicular::applyConstraint(std::vector & case 22: // {SelEdge, SelRoot, SelVAxis} case 23: // {SelHAxis, SelRoot, SelEdge} case 24: // {SelVAxis, SelRoot, SelEdge} + { + //let's sink the point to be GeoId3. + GeoId1 = selSeq.at(0).GeoId; GeoId2 = selSeq.at(2).GeoId; GeoId3 = selSeq.at(1).GeoId; + PosId3 = selSeq.at(1).PosId; break; + } default: - break; + return; } + + if (isEdge(GeoId1, PosId1) && isEdge(GeoId2, PosId2) && isVertex(GeoId3, PosId3)) { + + openCommand("add perpendicular constraint"); + + try{ + //add missing point-on-object constraints + if(! IsPointAlreadyOnCurve(GeoId1, GeoId3, PosId3, Obj)){ + Gui::Command::doCommand( + Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ", + Obj->getNameInDocument(),GeoId3,PosId3,GeoId1); + }; + + if(! IsPointAlreadyOnCurve(GeoId2, GeoId3, PosId3, Obj)){ + Gui::Command::doCommand( + Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ", + Obj->getNameInDocument(),GeoId3,PosId3,GeoId2); + }; + + if(! IsPointAlreadyOnCurve(GeoId1, GeoId3, PosId3, Obj)){//FIXME: it's a good idea to add a check if the sketch is solved + Gui::Command::doCommand( + Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('PointOnObject',%d,%d,%d)) ", + Obj->getNameInDocument(),GeoId3,PosId3,GeoId1); + }; + + Gui::Command::doCommand( + Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('PerpendicularViaPoint',%d,%d,%d,%d)) ", + Obj->getNameInDocument(),GeoId1,GeoId2,GeoId3,PosId3); + } catch (const Base::Exception& e) { + Base::Console().Error("%s\n", e.what()); + QMessageBox::warning(Gui::getMainWindow(), + QObject::tr("Error"), + QString::fromLatin1(e.what())); + Gui::Command::abortCommand(); + + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher"); + bool autoRecompute = hGrp->GetBool("AutoRecompute",false); + + if(autoRecompute) // toggling does not modify the DoF of the solver, however it may affect features depending on the sketch + Gui::Command::updateActive(); + + return; + } + + commitCommand(); + + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher"); + bool autoRecompute = hGrp->GetBool("AutoRecompute",false); + + if(autoRecompute) + Gui::Command::updateActive(); + + getSelection().clearSelection(); + + return; + + }; + strError = QObject::tr("With 3 objects, there must be 2 curves and 1 point.", "tangent constraint"); + } // ======================================================================================