From af68f1a45db8f50e0786190d56b8c71ab732eac4 Mon Sep 17 00:00:00 2001 From: azv Date: Wed, 27 Jan 2016 15:08:07 +0300 Subject: [PATCH] Tangency constraint between circle and linear segment --- src/SketchPlugin/SketchPlugin_Validators.cpp | 67 +++++++++++++++++-- src/SketchPlugin/plugin-Sketch.xml | 3 +- .../PlaneGCSSolver/PlaneGCSSolver_Builder.cpp | 28 +++++++- .../SketchSolver_ConstraintDistance.cpp | 22 +----- .../SketchSolver_ConstraintTangent.cpp | 45 +++++++++++-- .../SketchSolver_ConstraintTangent.h | 4 ++ src/SketchSolver/SketchSolver_Group.cpp | 3 + .../SketchSolver_IConstraintWrapper.h | 1 + .../SolveSpaceSolver_Builder.cpp | 38 ++++++++++- 9 files changed, 177 insertions(+), 34 deletions(-) diff --git a/src/SketchPlugin/SketchPlugin_Validators.cpp b/src/SketchPlugin/SketchPlugin_Validators.cpp index 3b79ad68c..66fc18d8b 100755 --- a/src/SketchPlugin/SketchPlugin_Validators.cpp +++ b/src/SketchPlugin/SketchPlugin_Validators.cpp @@ -89,6 +89,47 @@ bool SketchPlugin_DistanceAttrValidator::isValid(const AttributePtr& theAttribut return true; } + +static bool hasCoincidentPoint(FeaturePtr theFeature1, FeaturePtr theFeature2) +{ + FeaturePtr aConstrFeature; + std::list anAttrList; + if (theFeature1->getKind() == SketchPlugin_Circle::ID() || + theFeature2->getKind() == SketchPlugin_Circle::ID()) + return false; + if (theFeature2->getKind() == SketchPlugin_Line::ID()) { + anAttrList.push_back(theFeature2->attribute(SketchPlugin_Line::START_ID())); + anAttrList.push_back(theFeature2->attribute(SketchPlugin_Line::END_ID())); + } else if (theFeature2->getKind() == SketchPlugin_Arc::ID()) { + anAttrList.push_back(theFeature2->attribute(SketchPlugin_Arc::START_ID())); + anAttrList.push_back(theFeature2->attribute(SketchPlugin_Arc::END_ID())); + } + + const std::set& aRefsList = theFeature1->data()->refsToMe(); + std::set::const_iterator aRefIt = aRefsList.begin(); + for (; aRefIt != aRefsList.end(); ++aRefIt) { + aConstrFeature = std::dynamic_pointer_cast((*aRefIt)->owner()); + if (aConstrFeature->getKind() != SketchPlugin_ConstraintCoincidence::ID()) + continue; + AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(*aRefIt); + AttributePtr anAttr = aRefAttr->attr(); + if (anAttr->id() == SketchPlugin_Arc::CENTER_ID()) + continue; + + anAttr = aConstrFeature->attribute(SketchPlugin_Constraint::ENTITY_A()); + if (anAttr == *aRefIt) + anAttr = aConstrFeature->attribute(SketchPlugin_Constraint::ENTITY_B()); + + aRefAttr = std::dynamic_pointer_cast(anAttr); + anAttr = aRefAttr->attr(); + for (std::list::const_iterator anIt = anAttrList.begin(); + anIt != anAttrList.end(); ++anIt) + if (*anIt == anAttr) + return true; + } + return false; +} + bool SketchPlugin_TangentAttrValidator::isValid(const AttributePtr& theAttribute, const std::list& theArguments, std::string& theError) const @@ -114,11 +155,19 @@ bool SketchPlugin_TangentAttrValidator::isValid(const AttributePtr& theAttribute AttributeRefAttrPtr aOtherAttr = anAttributeFeature->data()->refattr(aParamA); ObjectPtr aOtherObject = aOtherAttr->object(); FeaturePtr aOtherFea = ModelAPI_Feature::feature(aOtherObject); + if (!aOtherFea) + return true; + + if ((aRefFea->getKind() == SketchPlugin_Arc::ID() || + aOtherFea->getKind() == SketchPlugin_Arc::ID()) && + !hasCoincidentPoint(aRefFea, aOtherFea)) + return false; if (aRefFea->getKind() == SketchPlugin_Line::ID()) { - if (aOtherFea->getKind() != SketchPlugin_Arc::ID()) { - theError = "It refers to a " + SketchPlugin_Line::ID() + ", but " + aParamA + " is not an " - + SketchPlugin_Arc::ID(); + if (aOtherFea->getKind() != SketchPlugin_Arc::ID() && + aOtherFea->getKind() != SketchPlugin_Circle::ID()) { + theError = "It refers to a " + SketchPlugin_Line::ID() + ", but " + aParamA + " is neither an " + + SketchPlugin_Arc::ID() + " nor " + SketchPlugin_Circle::ID(); return false; } } @@ -130,9 +179,16 @@ bool SketchPlugin_TangentAttrValidator::isValid(const AttributePtr& theAttribute return false; } } + else if (aRefFea->getKind() == SketchPlugin_Circle::ID()) { + if (aOtherFea->getKind() != SketchPlugin_Line::ID()) { + theError = "It refers to an " + SketchPlugin_Circle::ID() + ", but " + aParamA + " is not a " + + SketchPlugin_Line::ID(); + return false; + } + } else { - theError = "It refers to " + aRefFea->getKind() + "but should refer to " + SketchPlugin_Line::ID() - + " or " + SketchPlugin_Arc::ID(); + theError = "It refers to " + aRefFea->getKind() + ", but should refer to " + SketchPlugin_Line::ID() + + " or " + SketchPlugin_Arc::ID() + " or " + SketchPlugin_Circle::ID(); return false; } return true; @@ -279,7 +335,6 @@ bool SketchPlugin_MirrorAttrValidator::isValid(const AttributePtr& theAttribute, return true; } - bool SketchPlugin_CoincidenceAttrValidator::isValid(const AttributePtr& theAttribute, const std::list& theArguments, std::string& theError) const diff --git a/src/SketchPlugin/plugin-Sketch.xml b/src/SketchPlugin/plugin-Sketch.xml index b28114bf9..fd1d6f4e5 100644 --- a/src/SketchPlugin/plugin-Sketch.xml +++ b/src/SketchPlugin/plugin-Sketch.xml @@ -240,13 +240,12 @@ - + - diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Builder.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Builder.cpp index dd1d542fb..95e01be60 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Builder.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Builder.cpp @@ -135,6 +135,8 @@ static ConstraintWrapperPtr static void adjustAngle(ConstraintWrapperPtr theConstraint); /// \brief Update mirror points static void adjustMirror(ConstraintWrapperPtr theConstraint); +/// \brief Update a sign of the point-line distance constraint +static void adjustPtLineDistance(ConstraintWrapperPtr theConstraint); /// \brief Transform points to be symmetric regarding to the mirror line static void makeMirrorPoints(EntityWrapperPtr theOriginal, @@ -240,6 +242,7 @@ std::list PlaneGCSSolver_Builder::createConstraint( GCS_PARAMETER_WRAPPER(anIntermediate)); break; case CONSTRAINT_TANGENT_ARC_LINE: + case CONSTRAINT_TANGENT_CIRCLE_LINE: case CONSTRAINT_TANGENT_ARC_ARC: aResult = createConstraintTangent(theConstraint, theGroupID, theType, GCS_ENTITY_WRAPPER(theEntity1), GCS_ENTITY_WRAPPER(theEntity2)); @@ -439,6 +442,8 @@ void PlaneGCSSolver_Builder::adjustConstraint(ConstraintWrapperPtr theConstraint // Update flags and parameters in constraints if (aType == CONSTRAINT_ANGLE) adjustAngle(theConstraint); + else if (aType == CONSTRAINT_PT_LINE_DISTANCE) + adjustPtLineDistance(theConstraint); } EntityWrapperPtr PlaneGCSSolver_Builder::createFeature( @@ -990,7 +995,7 @@ ConstraintWrapperPtr createConstraintTangent( std::shared_ptr theEntity2) { GCSConstraintPtr aNewConstr; - if (theType == CONSTRAINT_TANGENT_ARC_LINE) { + if (theType == CONSTRAINT_TANGENT_ARC_LINE || theType == CONSTRAINT_TANGENT_CIRCLE_LINE) { std::shared_ptr aCirc = std::dynamic_pointer_cast(theEntity1->entity()); std::shared_ptr aLine = std::dynamic_pointer_cast(theEntity2->entity()); @@ -1113,3 +1118,24 @@ void makeMirrorPoints(EntityWrapperPtr theOriginal, } } +void adjustPtLineDistance(ConstraintWrapperPtr theConstraint) +{ + BuilderPtr aBuilder = PlaneGCSSolver_Builder::getInstance(); + + std::shared_ptr aPoint; + std::shared_ptr aLine; + std::list aSubs = theConstraint->entities(); + std::list::const_iterator aSIt = aSubs.begin(); + for (; aSIt != aSubs.end(); ++aSIt) { + if ((*aSIt)->type() == ENTITY_POINT) + aPoint = aBuilder->point(*aSIt); + else if ((*aSIt)->type() == ENTITY_LINE) + aLine = aBuilder->line(*aSIt); + } + + std::shared_ptr aLineVec = aLine->direction()->xy(); + std::shared_ptr aPtLineVec = aPoint->xy()->decreased(aLine->location()->xy()); + if (aPtLineVec->cross(aLineVec) * theConstraint->value() < 0.0) + theConstraint->setValue(theConstraint->value() * (-1.0)); +} + diff --git a/src/SketchSolver/SketchSolver_ConstraintDistance.cpp b/src/SketchSolver/SketchSolver_ConstraintDistance.cpp index 2a75e1293..5bbcd7919 100644 --- a/src/SketchSolver/SketchSolver_ConstraintDistance.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintDistance.cpp @@ -54,26 +54,10 @@ void SketchSolver_ConstraintDistance::adjustConstraint() return; } - // Get constraint parameters and check the sign of constraint value + // Adjust the sign of constraint value BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); - std::shared_ptr aPoint; - std::shared_ptr aLine; - std::list aSubs = aConstraint->entities(); - std::list::const_iterator aSIt = aSubs.begin(); - for (; aSIt != aSubs.end(); ++aSIt) { - if ((*aSIt)->type() == ENTITY_POINT) - aPoint = aBuilder->point(*aSIt); - else if ((*aSIt)->type() == ENTITY_LINE) - aLine = aBuilder->line(*aSIt); - } - - std::shared_ptr aLineVec = aLine->direction()->xy(); - std::shared_ptr aPtLineVec = aPoint->xy()->decreased(aLine->location()->xy()); - if (aPtLineVec->cross(aLineVec) * aConstraint->value() < 0.0 || myIsNegative) { - aConstraint->setValue(aConstraint->value() * (-1.0)); - myStorage->addConstraint(myBaseConstraint, aConstraint); - myIsNegative = true; - } + aBuilder->adjustConstraint(aConstraint); + myStorage->addConstraint(myBaseConstraint, aConstraint); } void SketchSolver_ConstraintDistance::update() diff --git a/src/SketchSolver/SketchSolver_ConstraintTangent.cpp b/src/SketchSolver/SketchSolver_ConstraintTangent.cpp index 51d87e276..0bd02bf0b 100644 --- a/src/SketchSolver/SketchSolver_ConstraintTangent.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintTangent.cpp @@ -3,6 +3,9 @@ #include #include +#include + +#include /// \brief Check whether the entities has only one shared point @@ -49,6 +52,7 @@ void SketchSolver_ConstraintTangent::getAttributes( // Check the quantity of entities of each type and their order (arcs first) int aNbLines = 0; int aNbArcs = 0; + int aNbCircles = 0; bool isSwap = false; // whether need to swap arguments (arc goes before line) std::vector::iterator anEntIt = theAttributes.begin() + 2; for (; anEntIt != theAttributes.end(); ++anEntIt) { @@ -58,14 +62,22 @@ void SketchSolver_ConstraintTangent::getAttributes( ++aNbArcs; isSwap = aNbLines > 0; } + else if ((*anEntIt)->type() == ENTITY_CIRCLE) { + ++aNbCircles; + isSwap = aNbLines > 0; + } } - if (aNbArcs < 1) { + if (aNbArcs < 1 && aNbCircles < 1) { myErrorMsg = SketchSolver_Error::INCORRECT_TANGENCY_ATTRIBUTE(); return; } - if (aNbLines == 1 && aNbArcs == 1) - myType = CONSTRAINT_TANGENT_ARC_LINE; + if (aNbLines == 1) { + if (aNbArcs == 1) + myType = CONSTRAINT_TANGENT_ARC_LINE; + else if (aNbCircles == 1) + myType = CONSTRAINT_TANGENT_CIRCLE_LINE; + } else if (aNbArcs == 2) myType = CONSTRAINT_TANGENT_ARC_ARC; else { @@ -73,7 +85,8 @@ void SketchSolver_ConstraintTangent::getAttributes( return; } - if (!hasSingleCoincidence(theAttributes[2], theAttributes[3])) + if (myType != CONSTRAINT_TANGENT_CIRCLE_LINE && + !hasSingleCoincidence(theAttributes[2], theAttributes[3])) myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE(); if (isSwap) { @@ -82,3 +95,27 @@ void SketchSolver_ConstraintTangent::getAttributes( theAttributes[3] = aTemp; } } + +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); +} diff --git a/src/SketchSolver/SketchSolver_ConstraintTangent.h b/src/SketchSolver/SketchSolver_ConstraintTangent.h index e1716bf74..2ffa8de02 100644 --- a/src/SketchSolver/SketchSolver_ConstraintTangent.h +++ b/src/SketchSolver/SketchSolver_ConstraintTangent.h @@ -27,6 +27,10 @@ protected: /// \param[out] theValue numerical characteristic of constraint (e.g. distance) /// \param[out] theAttributes list of attributes to be filled virtual void getAttributes(double& theValue, std::vector& theAttributes); + + /// \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(); }; #endif diff --git a/src/SketchSolver/SketchSolver_Group.cpp b/src/SketchSolver/SketchSolver_Group.cpp index 4b50f0253..84d6a0bb2 100644 --- a/src/SketchSolver/SketchSolver_Group.cpp +++ b/src/SketchSolver/SketchSolver_Group.cpp @@ -190,6 +190,9 @@ static void updateMultiConstraints(ConstraintConstraintMap& theConstraints, Feat aCIt->second->getType() == CONSTRAINT_MULTI_TRANSLATION) && aCIt->second->isUsed(theFeature)) std::dynamic_pointer_cast(aCIt->second)->update(true); + else if (aCIt->second->getType() == CONSTRAINT_TANGENT_CIRCLE_LINE + && aCIt->second->isUsed(theFeature)) + aCIt->second->update(); } } diff --git a/src/SketchSolver/SketchSolver_IConstraintWrapper.h b/src/SketchSolver/SketchSolver_IConstraintWrapper.h index 813e8dede..01020e923 100644 --- a/src/SketchSolver/SketchSolver_IConstraintWrapper.h +++ b/src/SketchSolver/SketchSolver_IConstraintWrapper.h @@ -38,6 +38,7 @@ enum SketchSolver_ConstraintType { CONSTRAINT_EQUAL_RADIUS, CONSTRAINT_TANGENT, // base tangency if we don't know the measured objects yet CONSTRAINT_TANGENT_ARC_LINE, + CONSTRAINT_TANGENT_CIRCLE_LINE, CONSTRAINT_TANGENT_ARC_ARC, CONSTRAINT_MULTI_TRANSLATION, CONSTRAINT_MULTI_ROTATION diff --git a/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Builder.cpp b/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Builder.cpp index 9d7339ac7..11b634a89 100644 --- a/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Builder.cpp +++ b/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Builder.cpp @@ -51,6 +51,8 @@ static void adjustTangency(ConstraintWrapperPtr theConstraint); static void adjustAngle(ConstraintWrapperPtr theConstraint); /// \brief Update mirror points static void adjustMirror(ConstraintWrapperPtr theConstraint); +/// \brief Update a sign of the point-line distance constraint +static void adjustPtLineDistance(ConstraintWrapperPtr theConstraint); /// \brief Transform points to be symmetric regarding to the mirror line static void makeMirrorPoints(EntityWrapperPtr theOriginal, @@ -96,6 +98,15 @@ std::list SolveSpaceSolver_Builder::createConstraint( if (theType == CONSTRAINT_SYMMETRIC) return createMirror(theConstraint, theGroupID, theSketchID, thePoint1, thePoint2, theEntity1); + else if (theType == CONSTRAINT_TANGENT_CIRCLE_LINE) { + // replace by distance from center of circle to the line + const std::list& aSubs = theEntity1->subEntities(); + EntityWrapperPtr aCenter = aSubs.front(); + AttributeDoublePtr aRadius = std::dynamic_pointer_cast( + aSubs.back()->baseAttribute()); + return createConstraint(theConstraint, theGroupID, theSketchID, + CONSTRAINT_PT_LINE_DISTANCE, aRadius->value(), aCenter, EntityWrapperPtr(), theEntity2); + } int aType = ConstraintType::toSolveSpace(theType); if (aType == SLVS_C_UNKNOWN) @@ -264,6 +275,8 @@ void SolveSpaceSolver_Builder::adjustConstraint(ConstraintWrapperPtr theConstrai adjustAngle(theConstraint); else if (aType == CONSTRAINT_SYMMETRIC) adjustMirror(theConstraint); + else if (aType == CONSTRAINT_PT_LINE_DISTANCE) + adjustPtLineDistance(theConstraint); } EntityWrapperPtr SolveSpaceSolver_Builder::createFeature( @@ -294,10 +307,10 @@ EntityWrapperPtr SolveSpaceSolver_Builder::createFeature( return createLine(theFeature, theAttributes, theGroupID, theSketchID); // Circle else if (aFeatureKind == SketchPlugin_Circle::ID()) - return createCircle(theFeature, theAttributes,theGroupID, theSketchID); + return createCircle(theFeature, theAttributes, theGroupID, theSketchID); // Arc else if (aFeatureKind == SketchPlugin_Arc::ID()) - return createArc(theFeature, theAttributes,theGroupID, theSketchID); + return createArc(theFeature, theAttributes, theGroupID, theSketchID); // Point (it has low probability to be an attribute of constraint, so it is checked at the end) else if (aFeatureKind == SketchPlugin_Point::ID()) { AttributePtr aPoint = theFeature->attribute(SketchPlugin_Point::COORD_ID()); @@ -784,3 +797,24 @@ void makeMirrorPoints(EntityWrapperPtr theOriginal, aMirroredPnt->setValue(aCoord[0], aCoord[1]); } } + +void adjustPtLineDistance(ConstraintWrapperPtr theConstraint) +{ + BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance(); + + std::shared_ptr aPoint; + std::shared_ptr aLine; + std::list aSubs = theConstraint->entities(); + std::list::const_iterator aSIt = aSubs.begin(); + for (; aSIt != aSubs.end(); ++aSIt) { + if ((*aSIt)->type() == ENTITY_POINT) + aPoint = aBuilder->point(*aSIt); + else if ((*aSIt)->type() == ENTITY_LINE) + aLine = aBuilder->line(*aSIt); + } + + std::shared_ptr aLineVec = aLine->direction()->xy(); + std::shared_ptr aPtLineVec = aPoint->xy()->decreased(aLine->location()->xy()); + if (aPtLineVec->cross(aLineVec) * theConstraint->value() < 0.0) + theConstraint->setValue(theConstraint->value() * (-1.0)); +} -- 2.39.2