diff --git a/src/Mod/Sketcher/App/planegcs/Constraints.cpp b/src/Mod/Sketcher/App/planegcs/Constraints.cpp index c56e652721..f225958ef3 100644 --- a/src/Mod/Sketcher/App/planegcs/Constraints.cpp +++ b/src/Mod/Sketcher/App/planegcs/Constraints.cpp @@ -1588,10 +1588,10 @@ double ConstraintTangentCircumf::error() double dx = (*c1x() - *c2x()); double dy = (*c1y() - *c2y()); if (internal) { - return scale * (sqrt(dx * dx + dy * dy) - std::abs(*r1() - *r2())); + return scale * ((dx * dx + dy * dy) - (*r1() - *r2()) * (*r1() - *r2())); } else { - return scale * (sqrt(dx * dx + dy * dy) - (*r1() + *r2())); + return scale * ((dx * dx + dy * dy) - (*r1() + *r2()) * (*r1() + *r2())); } } @@ -1602,33 +1602,32 @@ double ConstraintTangentCircumf::grad(double* param) || param == r2()) { double dx = (*c1x() - *c2x()); double dy = (*c1y() - *c2y()); - double d = sqrt(dx * dx + dy * dy); if (param == c1x()) { - deriv += dx / d; + deriv += 2 * dx; } if (param == c1y()) { - deriv += dy / d; + deriv += 2 * dy; } if (param == c2x()) { - deriv += -dx / d; + deriv += 2 * -dx; } if (param == c2y()) { - deriv += -dy / d; + deriv += 2 * -dy; } if (internal) { if (param == r1()) { - deriv += (*r1() > *r2()) ? -1 : 1; + deriv += 2 * (*r2() - *r1()); } if (param == r2()) { - deriv += (*r1() > *r2()) ? 1 : -1; + deriv += 2 * (*r1() - *r2()); } } else { if (param == r1()) { - deriv += -1; + deriv += 2 * (*r1() + *r2()); } if (param == r2()) { - deriv += -1; + deriv += 2 * (*r1() + *r2()); } } } diff --git a/src/Mod/Sketcher/Gui/CommandConstraints.cpp b/src/Mod/Sketcher/Gui/CommandConstraints.cpp index 8911caec31..cc38f23b54 100644 --- a/src/Mod/Sketcher/Gui/CommandConstraints.cpp +++ b/src/Mod/Sketcher/Gui/CommandConstraints.cpp @@ -3777,7 +3777,9 @@ bool CmdSketcherConstrainCoincidentUnified::substituteConstraintCombinationsPoin if ((*it)->Type == Sketcher::Tangent && (*it)->FirstPos == Sketcher::PointPos::none && (*it)->SecondPos == Sketcher::PointPos::none && (*it)->Third == GeoEnum::GeoUndef && (((*it)->First == GeoId1 && (*it)->Second == GeoId2) - || ((*it)->Second == GeoId1 && (*it)->First == GeoId2))) { + || ((*it)->Second == GeoId1 && (*it)->First == GeoId2)) + && (PosId1 == Sketcher::PointPos::start + || PosId1 == Sketcher::PointPos::end)) { // NOTE: This function does not either open or commit a command as it is used for group // addition it relies on such infrastructure being provided by the caller. @@ -3813,6 +3815,12 @@ bool CmdSketcherConstrainCoincidentUnified::substituteConstraintCombinationsCoin if ((*it)->Type == Sketcher::Tangent && (*it)->Third == GeoEnum::GeoUndef && (((*it)->First == GeoId1 && (*it)->Second == GeoId2) || ((*it)->Second == GeoId1 && (*it)->First == GeoId2))) { + if (!(PosId1 == Sketcher::PointPos::start + || PosId1 == Sketcher::PointPos::end) + || !(PosId2 == Sketcher::PointPos::start + || PosId2 == Sketcher::PointPos::end)) { + continue; + } if ((*it)->FirstPos == Sketcher::PointPos::none && (*it)->SecondPos == Sketcher::PointPos::none) { @@ -6569,8 +6577,11 @@ bool CmdSketcherConstrainTangent::substituteConstraintCombinations(SketchObject* ++it, ++cid) { if ((*it)->Type == Sketcher::Coincident && (((*it)->First == GeoId1 && (*it)->Second == GeoId2) - || ((*it)->Second == GeoId1 && (*it)->First == GeoId2))) { - + || ((*it)->Second == GeoId1 && (*it)->First == GeoId2)) + && ((*it)->FirstPos == Sketcher::PointPos::start + || (*it)->FirstPos == Sketcher::PointPos::end) + && ((*it)->SecondPos == Sketcher::PointPos::start + || (*it)->SecondPos == Sketcher::PointPos::end)) { // save values because 'doEndpointTangency' changes the // constraint property and thus invalidates this iterator int first = (*it)->First; @@ -6596,8 +6607,9 @@ bool CmdSketcherConstrainTangent::substituteConstraintCombinations(SketchObject* } else if ((*it)->Type == Sketcher::PointOnObject && (((*it)->First == GeoId1 && (*it)->Second == GeoId2) - || ((*it)->Second == GeoId1 && (*it)->First == GeoId2))) { - + || ((*it)->Second == GeoId1 && (*it)->First == GeoId2)) + && ((*it)->FirstPos == Sketcher::PointPos::start + || (*it)->FirstPos == Sketcher::PointPos::end)) { Gui::Command::openCommand( QT_TRANSLATE_NOOP("Command", "Swap point on object and tangency with point to curve tangency")); diff --git a/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp b/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp index bc2785dea0..a2ddc72884 100644 --- a/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp +++ b/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp @@ -1387,7 +1387,7 @@ void SketcherCopy::activate(SketcherCopy::Op op) int GeoId; Sketcher::PointPos PosId; Obj->getGeoVertexIndex(VtId, GeoId, PosId); - if (Obj->getGeometry(GeoId)->getTypeId() != Part::GeomPoint::getClassTypeId()) { + if (!Obj->getGeometry(GeoId)->is()) { LastGeoId = GeoId; LastPointPos = PosId; } @@ -1990,7 +1990,7 @@ void CmdSketcherRectangularArray::activated(int iMsg) int GeoId; Sketcher::PointPos PosId; Obj->getGeoVertexIndex(VtId, GeoId, PosId); - if (Obj->getGeometry(GeoId)->getTypeId() != Part::GeomPoint::getClassTypeId()) { + if (!Obj->getGeometry(GeoId)->is()) { LastGeoId = GeoId; LastPointPos = PosId; } diff --git a/src/Mod/Sketcher/Gui/DrawSketchDefaultHandler.h b/src/Mod/Sketcher/Gui/DrawSketchDefaultHandler.h index dbe4eeca71..2a98091feb 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchDefaultHandler.h +++ b/src/Mod/Sketcher/Gui/DrawSketchDefaultHandler.h @@ -497,8 +497,6 @@ protected: createAutoConstraints(); } - - tryAutoRecomputeIfNotSolve(sketchgui->getSketchObject()); } catch (const Base::RuntimeError& e) { // RuntimeError exceptions inside of the block above must provide a translatable @@ -507,6 +505,17 @@ protected: Base::Console().Error(e.what()); } + // Keep the recompute separate so that everything is drawn even if execution fails + // partially + try { + tryAutoRecomputeIfNotSolve(sketchgui->getSketchObject()); + } + catch (const Base::RuntimeError& e) { + // RuntimeError exceptions inside of the block above must provide a translatable + // message. It is reported both to developer (report view) and user (notifications + // area). + Base::Console().Error(e.what()); + } return handleContinuousMode(); } return false; @@ -666,19 +675,26 @@ protected: } // find if there is already a matching tangency - auto result = std::find_if(AutoConstraints.begin(), - AutoConstraints.end(), - [&](const auto& ace) { - return ace->Type == Sketcher::Tangent - && ace->First == geoId1 - && ace->Second == ac.GeoId; - }); + auto itOfTangentConstraint = AutoConstraints.end(); + if ((posId1 == Sketcher::PointPos::start + || posId1 == Sketcher::PointPos::end) + && (ac.PosId == Sketcher::PointPos::start + || ac.PosId == Sketcher::PointPos::end)) { + itOfTangentConstraint = + std::find_if(AutoConstraints.begin(), + AutoConstraints.end(), + [&](const auto& ace) { + return ace->Type == Sketcher::Tangent + && ace->First == geoId1 + && ace->Second == ac.GeoId; + }); + } - if (result - != AutoConstraints.end()) { // modify tangency to endpoint-to-endpoint - (*result)->FirstPos = posId1; - (*result)->SecondPos = ac.PosId; + if (itOfTangentConstraint != AutoConstraints.end()) { + // modify tangency to endpoint-to-endpoint + (*itOfTangentConstraint)->FirstPos = posId1; + (*itOfTangentConstraint)->SecondPos = ac.PosId; } else { auto c = std::make_unique(); @@ -699,21 +715,27 @@ protected: std::swap(posId1, posId2); } - auto result = std::find_if(AutoConstraints.begin(), - AutoConstraints.end(), - [&](const auto& ace) { - return ace->Type == Sketcher::Tangent - && ace->First == geoId1 - && ace->Second == ac.GeoId; - }); + auto itOfTangentConstraint = AutoConstraints.end(); + if (posId1 == Sketcher::PointPos::start + || posId1 == Sketcher::PointPos::end) { + itOfTangentConstraint = + std::find_if(AutoConstraints.begin(), + AutoConstraints.end(), + [&](const auto& ace) { + return ace->Type == Sketcher::Tangent + && ace->First == geoId1 + && ace->Second == ac.GeoId; + }); + } // if tangency, convert to point-to-edge tangency - if (result != AutoConstraints.end()) { - (*result)->FirstPos = posId1; - - if ((*result)->First != geoId1) { - std::swap((*result)->Second, (*result)->First); + if (itOfTangentConstraint != AutoConstraints.end()) { + if ((*itOfTangentConstraint)->First != geoId1) { + std::swap((*itOfTangentConstraint)->Second, + (*itOfTangentConstraint)->First); } + + (*itOfTangentConstraint)->FirstPos = posId1; } else { auto c = std::make_unique(); @@ -735,11 +757,11 @@ protected: c->ThirdPos = posId1; AutoConstraints.push_back(std::move(c)); } break; - // In special case of Horizontal/Vertical constraint, geoId2 is normally unused - // and should be 'Constraint::GeoUndef' However it can be used as a way to - // require the function to apply these constraints on another geometry In this - // case the caller as to set geoId2, then it will be used as target instead of - // geoId2 + // In special case of Horizontal/Vertical constraint, geoId2 is normally + // unused and should be 'Constraint::GeoUndef' However it can be used as a + // way to require the function to apply these constraints on another + // geometry In this case the caller as to set geoId2, then it will be used + // as target instead of geoId2 case Sketcher::Horizontal: { auto c = std::make_unique(); c->Type = Sketcher::Horizontal; @@ -761,10 +783,8 @@ protected: // ellipse tangency support using construction elements (lines) if (geom1 && geom2 - && (geom1->getTypeId() == Part::GeomEllipse::getClassTypeId() - || geom2->getTypeId() == Part::GeomEllipse::getClassTypeId())) { - - if (geom1->getTypeId() != Part::GeomEllipse::getClassTypeId()) { + && (geom1->is() || geom2->is())) { + if (!geom1->is()) { std::swap(geoId1, geoId2); } @@ -772,14 +792,15 @@ protected: geom1 = Obj->getGeometry(geoId1); geom2 = Obj->getGeometry(geoId2); - if (geom2->getTypeId() == Part::GeomEllipse::getClassTypeId() - || geom2->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() - || geom2->getTypeId() == Part::GeomCircle::getClassTypeId() - || geom2->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) { + if (geom2->is() + || geom2->is() + || geom2->is() + || geom2->is()) { // in all these cases an intermediate element is needed - /*makeTangentToEllipseviaNewPoint(Obj, - static_cast(geom1), geom2, geoId1, geoId2);*/ + // makeTangentToEllipseviaNewPoint( + // Obj, + // static_cast(geom1), + // geom2, geoId1, geoId2); // NOTE: Temporarily deactivated return; } @@ -787,11 +808,10 @@ protected: // arc of ellipse tangency support using external elements if (geom1 && geom2 - && (geom1->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() - || geom2->getTypeId() - == Part::GeomArcOfEllipse::getClassTypeId())) { + && (geom1->is() + || geom2->is())) { - if (geom1->getTypeId() != Part::GeomArcOfEllipse::getClassTypeId()) { + if (!geom1->is()) { std::swap(geoId1, geoId2); } @@ -799,15 +819,13 @@ protected: geom1 = Obj->getGeometry(geoId1); geom2 = Obj->getGeometry(geoId2); - if (geom2->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() - || geom2->getTypeId() == Part::GeomCircle::getClassTypeId() - || geom2->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) { + if (geom2->is() || geom2->is() + || geom2->is()) { // in all these cases an intermediate element is needed - // makeTangentToArcOfEllipseviaNewPoint(Obj, - // static_cast(geom1), geom2, geoId1, - // geoId2); + // makeTangentToArcOfEllipseviaNewPoint( + // Obj, + // static_cast(geom1), geom2, + // geoId1, geoId2); // NOTE: Temporarily deactivated return; } @@ -830,12 +848,18 @@ protected: || (ace->First == ac.GeoId && ace->Second == geoId1)); }); - if (resultcoincident - != AutoConstraints.end()) { // endpoint-to-endpoint tangency + if (resultcoincident != AutoConstraints.end() + && ((*resultcoincident)->FirstPos == Sketcher::PointPos::start + || (*resultcoincident)->FirstPos == Sketcher::PointPos::end) + && ((*resultcoincident)->SecondPos == Sketcher::PointPos::start + || (*resultcoincident)->SecondPos == Sketcher::PointPos::end)) { + // endpoint-to-endpoint tangency (*resultcoincident)->Type = Sketcher::Tangent; } - else if (resultpointonobject - != AutoConstraints.end()) { // endpoint-to-edge tangency + else if (resultpointonobject != AutoConstraints.end() + && ((*resultcoincident)->FirstPos == Sketcher::PointPos::start + || (*resultcoincident)->FirstPos == Sketcher::PointPos::end)) { + // endpoint-to-edge tangency (*resultpointonobject)->Type = Sketcher::Tangent; } else { // regular edge to edge tangency diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandler.cpp b/src/Mod/Sketcher/Gui/DrawSketchHandler.cpp index 0740f2fba9..a8383e8a90 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandler.cpp +++ b/src/Mod/Sketcher/Gui/DrawSketchHandler.cpp @@ -440,8 +440,8 @@ int DrawSketchHandler::seekAutoConstraint(std::vector& suggested int preSelPnt = getPreselectPoint(); int preSelCrv = getPreselectCurve(); int preSelCrs = getPreselectCross(); - int GeoId = GeoEnum::GeoUndef; + int GeoId = GeoEnum::GeoUndef; PointPos PosId = PointPos::none; if (preSelPnt != -1) { @@ -459,15 +459,18 @@ int DrawSketchHandler::seekAutoConstraint(std::vector& suggested } } } - else if (preSelCrs == 0) { // root point + else if (preSelCrs == 0) { + // root point GeoId = Sketcher::GeoEnum::RtPnt; PosId = PointPos::start; } - else if (preSelCrs == 1) { // x axis + else if (preSelCrs == 1) { + // x axis GeoId = Sketcher::GeoEnum::HAxis; hitShapeDir = Base::Vector3d(1, 0, 0); } - else if (preSelCrs == 2) { // y axis + else if (preSelCrs == 2) { + // y axis GeoId = Sketcher::GeoEnum::VAxis; hitShapeDir = Base::Vector3d(0, 1, 0); } @@ -819,7 +822,7 @@ void DrawSketchHandler::createAutoConstraints(const std::vector& if (geom1 && geom2 && (geom1->is() || geom2->is())) { - if (geom1->getTypeId() != Part::GeomEllipse::getClassTypeId()) { + if (!geom1->is()) { std::swap(geoId1, geoId2); } @@ -846,7 +849,7 @@ void DrawSketchHandler::createAutoConstraints(const std::vector& && (geom1->is() || geom2->is())) { - if (geom1->getTypeId() != Part::GeomArcOfEllipse::getClassTypeId()) { + if (!geom1->is()) { std::swap(geoId1, geoId2); } diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandlerEllipse.h b/src/Mod/Sketcher/Gui/DrawSketchHandlerEllipse.h index 4a0fca3da4..5c319ba18a 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandlerEllipse.h +++ b/src/Mod/Sketcher/Gui/DrawSketchHandlerEllipse.h @@ -162,8 +162,7 @@ private: // in the exceptional event that this may lead to a circle, do not // exposeInternalGeometry - if (!ShapeGeometry.empty() - && ShapeGeometry[0]->getTypeId() == Part::GeomEllipse::getClassTypeId()) { + if (!ShapeGeometry.empty() && ShapeGeometry[0]->is()) { Gui::cmdAppObjectArgs(sketchgui->getObject(), "exposeInternalGeometry(%d)", ellipseGeoId); @@ -713,8 +712,7 @@ void DSHEllipseController::addConstraints() using namespace Sketcher; - if (!handler->ShapeGeometry.empty() - && handler->ShapeGeometry[0]->getTypeId() == Part::GeomEllipse::getClassTypeId()) { + if (!handler->ShapeGeometry.empty() && handler->ShapeGeometry[0]->is()) { int firstLine = firstCurve + 1; // this is always the major axis int secondLine = firstCurve + 2; // this is always the minor axis diff --git a/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.cpp b/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.cpp index 3a4827273e..d2762cd688 100644 --- a/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.cpp +++ b/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.cpp @@ -564,8 +564,7 @@ Restart: Base::Vector3d midpos1, dir1, norm1; Base::Vector3d midpos2, dir2, norm2; - if (geo1->getTypeId() != Part::GeomLineSegment::getClassTypeId() - || geo2->getTypeId() != Part::GeomLineSegment::getClassTypeId()) { + if (!geo1->is() || !geo2->is()) { if (Constr->Type == Equal) { double r1a = 0, r1b = 0, r2a = 0, r2b = 0; double angle1, @@ -731,8 +730,7 @@ Restart: if (geo2->is() || geo2->is() - || geo2->getTypeId() - == Part::GeomArcOfHyperbola::getClassTypeId()) { + || geo2->is()) { Base::Vector3d majDir, minDir, rvec; majDir = Base::Vector3d(cos(angle2),