From 695f56200bde96dac6886d3f5d966d740debaa0a Mon Sep 17 00:00:00 2001 From: azv Date: Tue, 6 Sep 2016 18:26:14 +0300 Subject: [PATCH] Fix incorrect tangency between arcs when one arc changes its direction (issue #1291) --- .../PlaneGCSSolver/PlaneGCSSolver_Builder.cpp | 18 ++++++ .../PlaneGCSSolver/PlaneGCSSolver_Builder.h | 4 ++ src/SketchSolver/SketchSolver_Builder.h | 5 ++ .../SketchSolver_ConstraintTangent.cpp | 60 ++++++++++++------- .../SketchSolver_ConstraintTangent.h | 6 +- src/SketchSolver/SketchSolver_Group.cpp | 2 +- 6 files changed, 72 insertions(+), 23 deletions(-) diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Builder.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Builder.cpp index a7c348db7..fd02a9d20 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Builder.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Builder.cpp @@ -1213,3 +1213,21 @@ void adjustMirror(ConstraintWrapperPtr theConstraint) (*aCIt)->rescale(); } +bool PlaneGCSSolver_Builder::isArcArcTangencyInternal( + EntityWrapperPtr theArc1, EntityWrapperPtr theArc2) const +{ + std::shared_ptr aCirc1 = std::dynamic_pointer_cast( + GCS_ENTITY_WRAPPER(theArc1)->entity()); + std::shared_ptr aCirc2 = std::dynamic_pointer_cast( + GCS_ENTITY_WRAPPER(theArc2)->entity()); + + if (!aCirc1 || !aCirc2) + return false; + + double aDX = *(aCirc1->center.x) - *(aCirc2->center.x); + double aDY = *(aCirc1->center.y) - *(aCirc2->center.y); + double aDist = sqrt(aDX * aDX + aDY * aDY); + + return (aDist < *(aCirc1->rad) || aDist < *(aCirc2->rad)); +} + diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Builder.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Builder.h index ae534dafa..a1402237c 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Builder.h +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Builder.h @@ -109,6 +109,10 @@ public: /// \return Created wrapper for parameter ParameterWrapperPtr createParameter(const GroupID& theGroupID, double theValue = 0.0) const; + /// \brief Check if two connected arcs have centers + /// in same direction relatively to connection point + virtual bool isArcArcTangencyInternal(EntityWrapperPtr theArc1, EntityWrapperPtr theArc2) const; + private: /// \brief Create necessary constraints to make two object symmetric relatively a given line std::list createMirror(ConstraintPtr theConstraint, diff --git a/src/SketchSolver/SketchSolver_Builder.h b/src/SketchSolver/SketchSolver_Builder.h index 86a395bc2..fe34cb06e 100644 --- a/src/SketchSolver/SketchSolver_Builder.h +++ b/src/SketchSolver/SketchSolver_Builder.h @@ -113,6 +113,11 @@ public: /// \brief Convert entity to line /// \return empty pointer if the entity is not a line SKETCHSOLVER_EXPORT std::shared_ptr line(EntityWrapperPtr theEntity) const; + + /// \brief Check if two connected arcs have centers + /// in same direction relatively to connection point + SKETCHSOLVER_EXPORT virtual bool isArcArcTangencyInternal(EntityWrapperPtr theArc1, EntityWrapperPtr theArc2) const + { return false; } }; typedef std::shared_ptr BuilderPtr; diff --git a/src/SketchSolver/SketchSolver_ConstraintTangent.cpp b/src/SketchSolver/SketchSolver_ConstraintTangent.cpp index 299ed53fa..29744ea32 100644 --- a/src/SketchSolver/SketchSolver_ConstraintTangent.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintTangent.cpp @@ -38,6 +38,14 @@ static bool hasSingleCoincidence(EntityWrapperPtr theEntity1, EntityWrapperPtr t return aNbCoinc == 1; } +/// \brief Check if two connected arcs have centers +/// in same direction relatively to connection point +static bool isInternalTangency(EntityWrapperPtr theEntity1, EntityWrapperPtr theEntity2) +{ + BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); + return aBuilder->isArcArcTangencyInternal(theEntity1, theEntity2); +} + void SketchSolver_ConstraintTangent::getAttributes( double& theValue, @@ -78,8 +86,10 @@ void SketchSolver_ConstraintTangent::getAttributes( else if (aNbCircles == 1) myType = CONSTRAINT_TANGENT_CIRCLE_LINE; } - else if (aNbArcs == 2) + else if (aNbArcs == 2) { myType = CONSTRAINT_TANGENT_ARC_ARC; + isArcArcInternal = isInternalTangency(theAttributes[2], theAttributes[3]); + } else { myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE(); return; @@ -98,24 +108,32 @@ void SketchSolver_ConstraintTangent::getAttributes( void SketchSolver_ConstraintTangent::adjustConstraint() { - if (myType != CONSTRAINT_TANGENT_CIRCLE_LINE) - return; - - ConstraintWrapperPtr aConstraint = myStorage->constraint(myBaseConstraint).front(); - AttributePtr aCircleCenter = aConstraint->entities().front()->baseAttribute(); - if (!aCircleCenter) - return; - FeaturePtr aCircle = ModelAPI_Feature::feature(aCircleCenter->owner()); - AttributeDoublePtr aRadius = std::dynamic_pointer_cast( - aCircle->attribute(SketchPlugin_Circle::RADIUS_ID())); - - if (fabs(aRadius->value()) == fabs(aConstraint->value())) - return; - - aConstraint->setValue(aRadius->value()); - - // Adjust the sign of constraint value - BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); - aBuilder->adjustConstraint(aConstraint); - myStorage->addConstraint(myBaseConstraint, aConstraint); + if (myType == CONSTRAINT_TANGENT_CIRCLE_LINE) { + ConstraintWrapperPtr aConstraint = myStorage->constraint(myBaseConstraint).front(); + AttributePtr aCircleCenter = aConstraint->entities().front()->baseAttribute(); + if (!aCircleCenter) + return; + FeaturePtr aCircle = ModelAPI_Feature::feature(aCircleCenter->owner()); + AttributeDoublePtr aRadius = std::dynamic_pointer_cast( + aCircle->attribute(SketchPlugin_Circle::RADIUS_ID())); + + if (fabs(aRadius->value()) == fabs(aConstraint->value())) + return; + + aConstraint->setValue(aRadius->value()); + + // Adjust the sign of constraint value + BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); + aBuilder->adjustConstraint(aConstraint); + myStorage->addConstraint(myBaseConstraint, aConstraint); + } + else if (myType == CONSTRAINT_TANGENT_ARC_ARC) { + ConstraintWrapperPtr aConstraint = myStorage->constraint(myBaseConstraint).front(); + if (isArcArcInternal != isInternalTangency( + aConstraint->entities().front(), aConstraint->entities().back())) { + // fully rebuld constraint, because it is unable to access attributes of PlaneGCS constraint + remove(); + process(); + } + } } diff --git a/src/SketchSolver/SketchSolver_ConstraintTangent.h b/src/SketchSolver/SketchSolver_ConstraintTangent.h index 2ffa8de02..589d1ab45 100644 --- a/src/SketchSolver/SketchSolver_ConstraintTangent.h +++ b/src/SketchSolver/SketchSolver_ConstraintTangent.h @@ -19,7 +19,8 @@ class SketchSolver_ConstraintTangent : public SketchSolver_Constraint public: /// Constructor based on SketchPlugin constraint SketchSolver_ConstraintTangent(ConstraintPtr theConstraint) : - SketchSolver_Constraint(theConstraint) + SketchSolver_Constraint(theConstraint), + isArcArcInternal(false) {} protected: @@ -31,6 +32,9 @@ protected: /// \brief This method is used in derived objects to check consistency of constraint. /// E.g. the distance between line and point may be signed. virtual void adjustConstraint(); + +private: + bool isArcArcInternal; }; #endif diff --git a/src/SketchSolver/SketchSolver_Group.cpp b/src/SketchSolver/SketchSolver_Group.cpp index 0e4211a3a..5a1ff49fb 100644 --- a/src/SketchSolver/SketchSolver_Group.cpp +++ b/src/SketchSolver/SketchSolver_Group.cpp @@ -220,7 +220,7 @@ static void updateMultiConstraints(ConstraintConstraintMap& theConstraints, Feat aType == CONSTRAINT_MULTI_TRANSLATION) && aCIt->second->isUsed(theFeature)) std::dynamic_pointer_cast(aCIt->second)->update(true); - else if ((aType == CONSTRAINT_TANGENT_CIRCLE_LINE || + else if ((aType == CONSTRAINT_TANGENT_CIRCLE_LINE || aType == CONSTRAINT_TANGENT_ARC_ARC || aType == CONSTRAINT_SYMMETRIC || aType == CONSTRAINT_ANGLE) && aCIt->second->isUsed(theFeature)) aCIt->second->update(); -- 2.39.2