From cd087e8e165c06c13e68aa8b1ecb162bfe630f34 Mon Sep 17 00:00:00 2001 From: azv Date: Wed, 18 Mar 2015 10:36:20 +0300 Subject: [PATCH] Implemented processing of Mirror constraint by sketch solver Test case added --- src/SketchPlugin/CMakeLists.txt | 1 + .../SketchPlugin_ConstraintMirror.cpp | 3 +- src/SketchPlugin/Test/TestConstraintMirror.py | 32 ++++ src/SketchSolver/SketchSolver_Constraint.cpp | 32 +++- .../SketchSolver_ConstraintGroup.cpp | 157 +++++++++++++++++- .../SketchSolver_ConstraintGroup.h | 5 + 6 files changed, 222 insertions(+), 8 deletions(-) diff --git a/src/SketchPlugin/CMakeLists.txt b/src/SketchPlugin/CMakeLists.txt index b8e644cc6..1a70246b2 100644 --- a/src/SketchPlugin/CMakeLists.txt +++ b/src/SketchPlugin/CMakeLists.txt @@ -103,5 +103,6 @@ ADD_UNIT_TESTS(TestSketchPointLine.py TestConstraintVertical.py TestConstraintEqual.py TestConstraintTangent.py + TestConstraintMirror.py TestHighload.py TestSnowflake.py) diff --git a/src/SketchPlugin/SketchPlugin_ConstraintMirror.cpp b/src/SketchPlugin/SketchPlugin_ConstraintMirror.cpp index 633eed69e..8479e107d 100644 --- a/src/SketchPlugin/SketchPlugin_ConstraintMirror.cpp +++ b/src/SketchPlugin/SketchPlugin_ConstraintMirror.cpp @@ -64,7 +64,8 @@ void SketchPlugin_ConstraintMirror::execute() if (aMirrorIter != aMirroredList.end()) break; // the lists are inconsistent // There is no mirrored object yet, create it - FeaturePtr aNewFeature = aFeatureIn->document()->addFeature(aFeatureIn->getKind()); + FeaturePtr aNewFeature = sketch()->addFeature(aFeatureIn->getKind()); + aFeatureIn->data()->copyTo(aNewFeature->data()); aRefListOfMirrored->append(aNewFeature); continue; } diff --git a/src/SketchPlugin/Test/TestConstraintMirror.py b/src/SketchPlugin/Test/TestConstraintMirror.py index de1c0870e..3c3c2d052 100644 --- a/src/SketchPlugin/Test/TestConstraintMirror.py +++ b/src/SketchPlugin/Test/TestConstraintMirror.py @@ -122,5 +122,37 @@ aRefListB.append(aSketchLine2) aMirror.execute() aSession.finishOperation() #========================================================================= +# Verify the simmetricity of all mirrored objects +#========================================================================= +aRefListC = aMirror.reflist("ConstraintEntityC") +aListSize = aRefListB.size() +aLineDirX = aLineEndPoint.x() - aLineStartPoint.x() +aLineDirY = aLineEndPoint.y() - aLineStartPoint.y() + +for ind in range(0, aListSize): + aFeatureB = modelAPI_Feature(aRefListB.object(ind)) + aFeatureC = modelAPI_Feature(aRefListC.object(ind)) + assert(aFeatureB is not None) + assert(aFeatureC is not None) + assert(aFeatureB.getKind() == aFeatureC.getKind()) + anAttributes = {} + print aFeatureB.getKind() + if (aFeatureB.getKind() == "SketchLine"): + anAttributes = {'StartPoint':'StartPoint', 'EndPoint':'EndPoint'} + elif (aFeatureB.getKind() == "SketchArc"): + anAttributes = {'ArcCenter':'ArcCenter', 'ArcStartPoint':'ArcEndPoint', 'ArcEndPoint':'ArcStartPoint'} + + for key in anAttributes: + aPointB = geomDataAPI_Point2D(aFeatureB.attribute(key)) + aPointC = geomDataAPI_Point2D(aFeatureC.attribute(anAttributes[key])) + aDirX = aPointC.x() - aPointB.x() + aDirY = aPointC.y() - aPointB.y() + aDot = aLineDirX * aDirX + aLineDirY * aDirY + assert(math.fabs(aDot) < 1.e-10) + aDirX = aLineEndPoint.x() - 0.5 * (aPointB.x() + aPointC.x()) + aDirY = aLineEndPoint.y() - 0.5 * (aPointB.y() + aPointC.y()) + aCross = aLineDirX * aDirY - aLineDirY * aDirX + assert(math.fabs(aCross) < 1.e-10) +#========================================================================= # End of test #========================================================================= diff --git a/src/SketchSolver/SketchSolver_Constraint.cpp b/src/SketchSolver/SketchSolver_Constraint.cpp index e4af2a064..aed82cec5 100644 --- a/src/SketchSolver/SketchSolver_Constraint.cpp +++ b/src/SketchSolver/SketchSolver_Constraint.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -24,6 +25,7 @@ #include #include +#include #include #include #include @@ -217,8 +219,7 @@ const int& SketchSolver_Constraint::getType( return getType(); } - if (aConstraintKind.compare(SketchPlugin_ConstraintEqual::ID()) == 0) - { + if (aConstraintKind.compare(SketchPlugin_ConstraintEqual::ID()) == 0) { static const int aConstrType[3] = { SLVS_C_EQUAL_RADIUS, SLVS_C_EQUAL_LINE_ARC_LEN, @@ -242,8 +243,7 @@ const int& SketchSolver_Constraint::getType( return getType(); } - if (aConstraintKind.compare(SketchPlugin_ConstraintTangent::ID()) == 0) - { + if (aConstraintKind.compare(SketchPlugin_ConstraintTangent::ID()) == 0) { static const int anArcPosDefault = 2; static const int aLinePosDefault = 3; int anArcPos = anArcPosDefault; // arc in tangency constraint should be placed before line @@ -262,6 +262,30 @@ const int& SketchSolver_Constraint::getType( return getType(); } + if (aConstraintKind.compare(SketchPlugin_ConstraintMirror::ID()) == 0) { + int aNbAttrs = 0; + bool hasMirrorLine = false; + for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) { + AttributeRefListPtr anAttrRefList = std::dynamic_pointer_cast( + aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr))); + if (anAttrRefList) { + aNbAttrs++; + myAttributesList[aNbAttrs] = SketchPlugin_Constraint::ATTRIBUTE(indAttr); + } + else { + std::shared_ptr anAttr = + aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr)); + if (typeOfAttribute(anAttr) == LINE) { + hasMirrorLine = !hasMirrorLine; + myAttributesList[0] = SketchPlugin_Constraint::ATTRIBUTE(indAttr); + } + } + } + if (aNbAttrs == 2 && hasMirrorLine) + myType = SLVS_C_SYMMETRIC_LINE; + return getType(); + } + /// \todo Implement other kind of constraints return getType(); diff --git a/src/SketchSolver/SketchSolver_ConstraintGroup.cpp b/src/SketchSolver/SketchSolver_ConstraintGroup.cpp index 61299f8a7..9a0f29050 100644 --- a/src/SketchSolver/SketchSolver_ConstraintGroup.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintGroup.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -155,7 +156,19 @@ bool SketchSolver_ConstraintGroup::isInteract( std::list>::const_iterator anAttrIter = anAttrList.begin(); for ( ; anAttrIter != anAttrList.end(); anAttrIter++) { - std::shared_ptr aCAttrRef = + AttributeRefListPtr aCAttrRefList = + std::dynamic_pointer_cast(*anAttrIter); + if (aCAttrRefList) { + std::list anObjList = aCAttrRefList->list(); + std::list::iterator anIt = anObjList.begin(); + for ( ; anIt != anObjList.end(); anIt++) { + FeaturePtr aFeature = std::dynamic_pointer_cast(*anIt); + if (aFeature && myEntityFeatMap.find(aFeature) != myEntityFeatMap.end()) + return true; + } + continue; + } + AttributeRefAttrPtr aCAttrRef = std::dynamic_pointer_cast(*anAttrIter); if (!aCAttrRef || !aCAttrRef->isObject()) { std::shared_ptr anAttr = @@ -232,8 +245,12 @@ bool SketchSolver_ConstraintGroup::changeConstraint( if (myWorkplane.h == SLVS_E_UNKNOWN) return false; - if (theConstraint && theConstraint->getKind() == SketchPlugin_ConstraintRigid::ID()) - return changeRigidConstraint(theConstraint); + if (theConstraint) { + if (theConstraint->getKind() == SketchPlugin_ConstraintRigid::ID()) + return changeRigidConstraint(theConstraint); + if (theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID()) + return changeMirrorConstraint(theConstraint); + } // Search this constraint in the current group to update it ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint); @@ -582,6 +599,140 @@ bool SketchSolver_ConstraintGroup::changeRigidConstraint( return true; } +// ============================================================================ +// Function: changeMirrorConstraint +// Class: SketchSolver_ConstraintGroup +// Purpose: create/update the "Mirror" constraint in the group +// ============================================================================ +bool SketchSolver_ConstraintGroup::changeMirrorConstraint( + std::shared_ptr theConstraint) +{ + DataPtr aConstrData = theConstraint->data(); + + // Search this constraint in the current group to update it + ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint); + std::vector::iterator aConstrIter; + if (aConstrMapIter != myConstraintMap.end()) { + int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints); + aConstrIter = myConstraints.begin() + aConstrPos; + } + + // Get constraint type and verify the constraint parameters are correct + SketchSolver_Constraint aConstraint(theConstraint); + int aConstrType = aConstraint.getType(); + if (aConstrType == SLVS_C_UNKNOWN + || (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType)) + return false; + const std::vector& aConstraintAttributes = aConstraint.getAttributes(); + + Slvs_hEntity aMirrorLineEnt = SLVS_E_UNKNOWN; + AttributeRefAttrPtr aConstrAttr = std::dynamic_pointer_cast( + aConstrData->attribute(aConstraintAttributes[0])); + if (!aConstrAttr) + return false; + + // Convert the object of the attribute to the feature + FeaturePtr aMirrorLineFeat; + if (aConstrAttr->isObject() && aConstrAttr->object()) { + ResultConstructionPtr aRC = std::dynamic_pointer_cast( + aConstrAttr->object()); + if (!aRC) + return false; + std::shared_ptr aDoc = aRC->document(); + aMirrorLineFeat = aDoc->feature(aRC); + } + aMirrorLineEnt = aConstrAttr->isObject() ? + changeEntityFeature(aMirrorLineFeat) : changeEntity(aConstrAttr->attr()); + + if (aConstrMapIter == myConstraintMap.end()) { // Add new constraint + // Append symmetric constraint for each point of mirroring features + AttributeRefListPtr aBaseRefList = std::dynamic_pointer_cast( + aConstrData->attribute(aConstraintAttributes[1])); + AttributeRefListPtr aMirroredRefList = std::dynamic_pointer_cast( + aConstrData->attribute(aConstraintAttributes[2])); + if (!aBaseRefList || !aMirroredRefList) + return false; + + std::list aBaseList = aBaseRefList->list(); + std::list aMirroredList = aMirroredRefList->list(); + if (aBaseList.size() != aMirroredList.size()) + return false; + + myConstraintMap[theConstraint] = std::vector(); + + FeaturePtr aBaseFeature, aMirrorFeature; + ResultConstructionPtr aRC; + std::list::iterator aBaseIter = aBaseList.begin(); + std::list::iterator aMirIter = aMirroredList.begin(); + for ( ; aBaseIter != aBaseList.end(); aBaseIter++, aMirIter++) { + aRC = std::dynamic_pointer_cast(*aBaseIter); + aBaseFeature = aRC ? aRC->document()->feature(aRC) : + std::dynamic_pointer_cast(*aBaseIter); + aRC = std::dynamic_pointer_cast(*aMirIter); + aMirrorFeature = aRC ? aRC->document()->feature(aRC) : + std::dynamic_pointer_cast(*aMirIter); + + if (!aBaseFeature || !aMirrorFeature || + aBaseFeature->getKind() != aMirrorFeature->getKind()) + return false; + Slvs_hEntity aBaseEnt = changeEntityFeature(aBaseFeature); + Slvs_hEntity aMirrorEnt = changeEntityFeature(aMirrorFeature); + + if (aBaseFeature->getKind() == SketchPlugin_Point::ID()) { + Slvs_Constraint aConstraint = Slvs_MakeConstraint(++myConstrMaxID, myID, aConstrType, + myWorkplane.h, 0.0, aBaseEnt, aMirrorEnt, aMirrorLineEnt, SLVS_E_UNKNOWN); + myConstraints.push_back(aConstraint); + myConstraintMap[theConstraint].push_back(aConstraint.h); + } else { + int aBasePos = Search(aBaseEnt, myEntities); + int aMirrorPos = Search(aMirrorEnt, myEntities); + if (aBaseFeature->getKind() == SketchPlugin_Line::ID()) { + for (int ind = 0; ind < 2; ind++) { + Slvs_Constraint aConstraint = Slvs_MakeConstraint( + ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0, + myEntities[aBasePos].point[ind], myEntities[aMirrorPos].point[ind], + aMirrorLineEnt, SLVS_E_UNKNOWN); + myConstraints.push_back(aConstraint); + myConstraintMap[theConstraint].push_back(aConstraint.h); + } + } else if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) { + Slvs_Constraint aConstraint = Slvs_MakeConstraint( + ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0, + myEntities[aBasePos].point[0], myEntities[aMirrorPos].point[0], + aMirrorLineEnt, SLVS_E_UNKNOWN); + myConstraints.push_back(aConstraint); + myConstraintMap[theConstraint].push_back(aConstraint.h); + // Additional constraint for equal radii + Slvs_Constraint anEqRadConstr = Slvs_MakeConstraint( + ++myConstrMaxID, myID, SLVS_C_EQUAL_RADIUS, myWorkplane.h, 0.0, + SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aBaseEnt, aMirrorEnt); + myConstraints.push_back(anEqRadConstr); + myConstraintMap[theConstraint].push_back(anEqRadConstr.h); + } else if (aBaseFeature->getKind() == SketchPlugin_Arc::ID()) { + int aBaseArcInd[3] = {0, 1, 2}; // indices of points of arc, center corresponds center, first point corresponds last point + int aMirrorArcInd[3] = {0, 2, 1}; + for (int ind = 0; ind < 2; ind++) { + Slvs_Constraint aConstraint = Slvs_MakeConstraint( + ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0, + myEntities[aBasePos].point[aBaseArcInd[ind]], myEntities[aMirrorPos].point[aMirrorArcInd[ind]], + aMirrorLineEnt, SLVS_E_UNKNOWN); + myConstraints.push_back(aConstraint); + myConstraintMap[theConstraint].push_back(aConstraint.h); + } + } + } + } + } + + // Set the mirror line unchanged during constraint recalculation + if (aConstrAttr->isObject()) { + addTemporaryConstraintWhereDragged(aMirrorLineFeat->attribute(SketchPlugin_Line::START_ID())); + addTemporaryConstraintWhereDragged(aMirrorLineFeat->attribute(SketchPlugin_Line::END_ID())); + } + else addTemporaryConstraintWhereDragged(aConstrAttr->attr()); + return true; +} + // ============================================================================ // Function: changeEntity // Class: SketchSolver_ConstraintGroup diff --git a/src/SketchSolver/SketchSolver_ConstraintGroup.h b/src/SketchSolver/SketchSolver_ConstraintGroup.h index 36583e338..5816eee75 100644 --- a/src/SketchSolver/SketchSolver_ConstraintGroup.h +++ b/src/SketchSolver/SketchSolver_ConstraintGroup.h @@ -67,6 +67,11 @@ class SketchSolver_ConstraintGroup * \return \c true if the constraint added or updated successfully */ bool changeRigidConstraint(std::shared_ptr theConstraint); + /** \brief Adds or updates a mirror constraint in the group + * \param[in] theConstraint constraint to be changed + * \return \c true if the constraint added or updated successfully + */ + bool changeMirrorConstraint(std::shared_ptr theConstraint); /** \brief Verifies the feature attributes are used in this group * \param[in] theFeature constraint or any other object for verification of interaction -- 2.39.2