X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FSketchSolver%2FSketchSolver_Manager.cpp;h=3a8f8ea86b9c0fafd2fb13b64f5c93c6bfae9677;hb=801131b41013eeb97fe917311b47bff78fb86d86;hp=f83e7fe48413165d7bceb71b032a8b0a8db36ad5;hpb=3a60523c3fa0af9d8daf760fcf13f7f2c45836de;p=modules%2Fshaper.git diff --git a/src/SketchSolver/SketchSolver_Manager.cpp b/src/SketchSolver/SketchSolver_Manager.cpp index f83e7fe48..3a8f8ea86 100644 --- a/src/SketchSolver/SketchSolver_Manager.cpp +++ b/src/SketchSolver/SketchSolver_Manager.cpp @@ -8,6 +8,9 @@ #include "SketchSolver_Error.h" #include + +#include + #include #include #include @@ -48,7 +51,7 @@ #include #include #include -#include +#include static const Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED); @@ -110,6 +113,10 @@ void SketchSolver_Manager::processEvent( if (myIsComputed) return; myIsComputed = true; + + // Shows that the message has at least one feature applicable for solver + bool hasProperFeature = false; + if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED) || theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_UPDATED) || theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED)) { @@ -118,8 +125,6 @@ void SketchSolver_Manager::processEvent( std::set aFeatures = anUpdateMsg->objects(); bool isUpdateFlushed = stopSendUpdate(); - // Shows the message has at least one feature applicable for solver - bool hasProperFeature = false; bool isMovedEvt = theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED); @@ -128,11 +133,16 @@ void SketchSolver_Manager::processEvent( for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++) { std::shared_ptr aSFeature = std::dynamic_pointer_cast(*aFeatIter); - if (aSFeature) { - moveEntity(aSFeature); + if (aSFeature && moveEntity(aSFeature)) { + // Want to avoid recalculation of DoF too frequently. + // So, set the flag when the feature is really moved. hasProperFeature = true; } } + if (!hasProperFeature) // in this iteration it will compute nothing, so, no problem with recursion + // it is important that solver flushes signal updated after processing move signal as there is + // optimization that relies on this update, might be found by key "optimization" + myIsComputed = false; } else { std::list aSketchFeatures = SketchSolver_Group::selectApplicableFeatures(aFeatures); std::list::iterator aFeatIter = aSketchFeatures.begin(); @@ -176,6 +186,7 @@ void SketchSolver_Manager::processEvent( break; if (aFGrIter != aFeatureGroups.end()) { + hasProperFeature = true; std::list aGroupsToResolve; std::list::iterator aGroupIter = myGroups.begin(); std::list aSeparatedGroups; @@ -188,8 +199,9 @@ void SketchSolver_Manager::processEvent( } if (!(*aGroupIter)->isConsistent()) { // some constraints were removed, try to split the group (*aGroupIter)->splitGroup(aSeparatedGroups); - //if (!(*aGroupIter)->getWorkplane()->string( - // SketchPlugin_Sketch::SOLVER_ERROR())->value().empty()) + if (!(*aGroupIter)->getWorkplane()->string( + SketchPlugin_Sketch::SOLVER_ERROR())->value().empty() || + (*aGroupIter)->isFailed()) aGroupsToResolve.push_back(*aGroupIter); } aGroupIter++; @@ -204,7 +216,9 @@ void SketchSolver_Manager::processEvent( resolveConstraints(aGroupsToResolve); } } - degreesOfFreedom(); + + if (hasProperFeature) + degreesOfFreedom(); myIsComputed = false; } @@ -235,7 +249,6 @@ void SketchSolver_Manager::checkConflictingConstraints(const std::shared_ptrgetWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue( SketchSolver_Error::CONSTRAINTS()); - Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED)); break; } } @@ -269,7 +282,7 @@ bool SketchSolver_Manager::changeWorkplane(CompositeFeaturePtr theSketch) } myGroups.push_back(aNewGroup); } - return aResult; + return aResult || isUpdated; } // ============================================================================ @@ -356,23 +369,44 @@ bool SketchSolver_Manager::changeFeature(std::shared_ptr t // Function: moveEntity // Purpose: update element moved on the sketch, which is used by constraints // ============================================================================ -void SketchSolver_Manager::moveEntity(std::shared_ptr theFeature) +bool SketchSolver_Manager::moveEntity(std::shared_ptr theFeature) { bool isMoved = false; std::list::iterator aGroupIt = myGroups.begin(); for (; aGroupIt != myGroups.end(); aGroupIt++) - if (!(*aGroupIt)->isEmpty() && (*aGroupIt)->isInteract(theFeature)) { - (*aGroupIt)->moveFeature(theFeature); - isMoved = true; - } + if (!(*aGroupIt)->isEmpty() && (*aGroupIt)->isInteract(theFeature)) + isMoved = (*aGroupIt)->moveFeature(theFeature) || isMoved; if (!isMoved && theFeature->getKind() == SketchPlugin_Arc::ID()) { // Workaround to move arc. // If the arc has not been constrained, we will push it into empty group and apply movement. + bool hasEmptyGroup = false; for (aGroupIt = myGroups.begin(); aGroupIt != myGroups.end(); aGroupIt++) - if ((*aGroupIt)->isEmpty()) - (*aGroupIt)->moveFeature(theFeature); + if ((*aGroupIt)->isEmpty()) { + isMoved = (*aGroupIt)->moveFeature(theFeature) || isMoved; + hasEmptyGroup = true; + } + // There is no empty group, create it explicitly + if (!hasEmptyGroup) { + // find sketch containing the arc + CompositeFeaturePtr aWP; + const std::set& aRefs = theFeature->data()->refsToMe(); + std::set::const_iterator aRefIt = aRefs.begin(); + for (; aRefIt != aRefs.end(); ++aRefIt) { + FeaturePtr anOwner = ModelAPI_Feature::feature((*aRefIt)->owner()); + if (anOwner && anOwner->getKind() == SketchPlugin_Sketch::ID()) { + aWP = std::dynamic_pointer_cast(anOwner); + break; + } + } + if (aWP) { + SketchSolver_Group* aGroup = new SketchSolver_Group(aWP); + isMoved = aGroup->moveFeature(theFeature) || isMoved; + myGroups.push_back(aGroup); + } + } } + return isMoved; } // ============================================================================ @@ -447,6 +481,87 @@ bool SketchSolver_Manager::resolveConstraints(const std::list >& thePoints) +{ + typedef std::list strlist; + static strlist aPointAttributes(1, SketchPlugin_Point::COORD_ID()); + static strlist aLineAttributes; + if (aLineAttributes.empty()) { + aLineAttributes.push_back(SketchPlugin_Line::START_ID()); + aLineAttributes.push_back(SketchPlugin_Line::END_ID()); + }; + static strlist aCircleAttributes(1, SketchPlugin_Circle::CENTER_ID()); + static strlist anArcAttributes; + if (anArcAttributes.empty()) { + anArcAttributes.push_back(SketchPlugin_Arc::CENTER_ID()); + anArcAttributes.push_back(SketchPlugin_Arc::START_ID()); + anArcAttributes.push_back(SketchPlugin_Arc::END_ID()); + }; + + static std::map aFeatureAttributes; + if (aFeatureAttributes.empty()) { + aFeatureAttributes[SketchPlugin_Point::ID()] = aPointAttributes; + aFeatureAttributes[SketchPlugin_Line::ID()] = aLineAttributes; + aFeatureAttributes[SketchPlugin_Circle::ID()] = aCircleAttributes; + aFeatureAttributes[SketchPlugin_Arc::ID()] = anArcAttributes; + } + + + std::set aPoints; + if (theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID()) { + AttributeRefListPtr aBaseRefList = theConstraint->reflist(SketchPlugin_Constraint::ENTITY_B()); + AttributeRefListPtr aMirrRefList = theConstraint->reflist(SketchPlugin_Constraint::ENTITY_C()); + + std::list aBaseList = aBaseRefList->list(); + std::list aMirrList = aMirrRefList->list(); + std::list::const_iterator aBIt, aMIt; + for (aBIt = aBaseList.begin(), aMIt = aMirrList.begin(); + aBIt != aBaseList.end() && aMIt != aMirrList.end(); ++aBIt, ++aMIt) { + FeaturePtr aBaseFeature = ModelAPI_Feature::feature(*aBIt); + FeaturePtr aMirrFeature = ModelAPI_Feature::feature(*aMIt); + + strlist anAttrList = aFeatureAttributes[aBaseFeature->getKind()]; + strlist::iterator anIt = anAttrList.begin(); + for (; anIt != anAttrList.end(); ++anIt) { + aPoints.clear(); + aPoints.insert(aBaseFeature->attribute(*anIt)); + aPoints.insert(aMirrFeature->attribute(*anIt)); + thePoints.push_back(aPoints); + } + } + } + else { // the "Multi" constraints + std::string aNbObjName; + if (theConstraint->getKind() == SketchPlugin_MultiRotation::ID()) + aNbObjName = SketchPlugin_MultiRotation::NUMBER_OF_OBJECTS_ID(); + else + aNbObjName = SketchPlugin_MultiTranslation::NUMBER_OF_OBJECTS_ID(); + int aNbCopies = theConstraint->integer(aNbObjName)->value(); + + AttributeRefListPtr aRefList = theConstraint->reflist(SketchPlugin_Constraint::ENTITY_B()); + std::list aFullList = aRefList->list(); + std::list::const_iterator anObjIt = aFullList.begin(); + std::list::const_iterator aCopyIt; + while (anObjIt != aFullList.end()) { + FeaturePtr aBaseFeature = ModelAPI_Feature::feature(*anObjIt); + strlist anAttrList = aFeatureAttributes[aBaseFeature->getKind()]; + strlist::iterator anIt = anAttrList.begin(); + for (; anIt != anAttrList.end(); ++anIt) { + aPoints.clear(); + aCopyIt = anObjIt; + for (int i = 0; i < aNbCopies && aCopyIt != aFullList.end(); ++i, ++aCopyIt) { + FeaturePtr aFeature = ModelAPI_Feature::feature(*aCopyIt); + aPoints.insert(aFeature->attribute(*anIt)); + } + thePoints.push_back(aPoints); + } + anObjIt = aCopyIt; + } + } +} + // ============================================================================ // Function: degreesOfFreedom // Purpose: calculate DoFs for each sketch @@ -467,7 +582,6 @@ void SketchSolver_Manager::degreesOfFreedom() aDoFDelta[SketchPlugin_ConstraintEqual::ID()] = -1; aDoFDelta[SketchPlugin_ConstraintHorizontal::ID()] = -1; aDoFDelta[SketchPlugin_ConstraintLength::ID()] = -1; - aDoFDelta[SketchPlugin_ConstraintMiddle::ID()] = -1; aDoFDelta[SketchPlugin_ConstraintParallel::ID()] = -1; aDoFDelta[SketchPlugin_ConstraintPerpendicular::ID()] = -1; aDoFDelta[SketchPlugin_ConstraintRadius::ID()] = -1; @@ -482,6 +596,18 @@ void SketchSolver_Manager::degreesOfFreedom() std::list::const_iterator aGroupIt = myGroups.begin(); for (; aGroupIt != myGroups.end(); ++aGroupIt) { CompositeFeaturePtr aSketch = (*aGroupIt)->getWorkplane(); + bool isSketchValid = aSketch->data() && aSketch->data()->isValid(); + + if (isSketchValid) { + std::shared_ptr aNormal = + std::dynamic_pointer_cast(aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID())); + isSketchValid = aNormal && aNormal->isInitialized(); + } + + if (!isSketchValid) { + myDoF.erase(aSketch); + continue; + } // check conflicting constraints in the group if ((*aGroupIt)->isFailed()) @@ -490,6 +616,10 @@ void SketchSolver_Manager::degreesOfFreedom() if (aSketchDoF.find(aSketch) != aSketchDoF.end() || aSketchDoF[aSketch] < 0) continue; + std::set aCoincidentPoints; + std::set aFixedPoints; + std::map > aPointOnLine; + std::list > aPointsInMultiConstraints; int aDoF = 0; int aNbSubs = aSketch->numberOfSubs(); for (int i = 0; i < aNbSubs; ++i) { @@ -503,31 +633,144 @@ void SketchSolver_Manager::degreesOfFreedom() // DoF delta in specific cases if (aFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) { + AttributePtr aCoincPoint[2] = {AttributePtr(), AttributePtr()}; + FeaturePtr aCoincLine; for (int j = 0; j < 2; ++j) { AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast( aFeature->attribute(SketchPlugin_Constraint::ATTRIBUTE(j))); if (!aRefAttr) continue; - bool isPoint = !aRefAttr->isObject(); - if (!isPoint) { + if (!aRefAttr->isObject()) + aCoincPoint[j] = aRefAttr->attr(); + else { FeaturePtr anAttr = ModelAPI_Feature::feature(aRefAttr->object()); - isPoint = anAttr && anAttr->getKind() == SketchPlugin_Point::ID(); + if (!anAttr) + continue; + if (anAttr->getKind() == SketchPlugin_Point::ID()) + aCoincPoint[j] = anAttr->attribute(SketchPlugin_Point::COORD_ID()); + else if (anAttr->getKind() == SketchPlugin_Line::ID()) + aCoincLine = anAttr; + } + } + if (aCoincPoint[0] && aCoincPoint[1]) { + bool isDoFDecreased = false; + // point-point coincidence + if (aCoincidentPoints.find(aCoincPoint[0]) == aCoincidentPoints.end() || + aCoincidentPoints.find(aCoincPoint[1]) == aCoincidentPoints.end()) { + aDoF -= 2; + isDoFDecreased = true; } - if (isPoint) + // check the coincident point is used in "multi" constraints + std::list >::const_iterator + aPtIt = aPointsInMultiConstraints.begin(); + bool isFound[2] = {false, false}; + for (; aPtIt != aPointsInMultiConstraints.end(); ++aPtIt) { + if ((!isFound[0] && (isFound[0] = (aPtIt->find(aCoincPoint[0]) != aPtIt->end()))) + || (!isFound[1] && (isFound[1] = (aPtIt->find(aCoincPoint[1]) != aPtIt->end())))) + aCoincidentPoints.insert(aPtIt->begin(), aPtIt->end()); + if (isFound[0] && isFound[1]) + break; + } + // check both points are fixed => not need to decrease DoF + bool isFixed[2] = { aFixedPoints.find(aCoincPoint[0]) != aFixedPoints.end(), + aFixedPoints.find(aCoincPoint[1]) != aFixedPoints.end() }; + if (isFixed[0] && isFixed[1] && isDoFDecreased) + aDoF += 2; // revert decrease of DoF + else if (isFixed[0] && !isFixed[1]) + aFixedPoints.insert(aCoincPoint[1]); + else if (!isFixed[0] && isFixed[1]) + aFixedPoints.insert(aCoincPoint[0]); + } else { + aDoF -= 1; + if (aCoincPoint[0] && aCoincLine) { + // if the point is already coincident to a line (by middle point constraint), do not decrease DoF + std::map >::iterator + aPtFound = aPointOnLine.find(aCoincPoint[0]); + if (aPtFound != aPointOnLine.end() && + aPtFound->second.find(aCoincLine) != aPtFound->second.end()) + aDoF += 1; // restore value decreased above + else + aPointOnLine[aCoincPoint[0]].insert(aCoincLine); + } + } + for (int j = 0; j < 2; ++j) + if (aCoincPoint[j]) + aCoincidentPoints.insert(aCoincPoint[j]); + } + else if (aFeature->getKind() == SketchPlugin_ConstraintMiddle::ID()) { + AttributePtr aPoint; + FeaturePtr aLine; + for (int j = 0; j < 2; ++j) { + AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast( + aFeature->attribute(SketchPlugin_Constraint::ATTRIBUTE(j))); + if (!aRefAttr) + continue; + if (aRefAttr->isObject()) + aLine = ModelAPI_Feature::feature(aRefAttr->object()); + else + aPoint = aRefAttr->attr(); + } + if (aPoint && aLine) { + // if the point is already on the line, decrease 1 DoF, instead decrease 2 DoF + std::map >::iterator + aPtFound = aPointOnLine.find(aPoint); + if (aPtFound != aPointOnLine.end() && + aPtFound->second.find(aLine) != aPtFound->second.end()) aDoF -= 1; + else { + aDoF -= 2; + aPointOnLine[aPoint].insert(aLine); + } } } else if (aFeature->getKind() == SketchPlugin_ConstraintRigid::ID()) { AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast( aFeature->attribute(SketchPlugin_Constraint::ENTITY_A())); assert(aRefAttr); - if (!aRefAttr->isObject()) + std::set aPoints; + if (!aRefAttr->isObject()) { aDoF -= 2; // attribute is a point - else { + aPoints.insert(aRefAttr->attr()); + } else { FeaturePtr anAttr = ModelAPI_Feature::feature(aRefAttr->object()); - assert(anAttr); - aDoF -= aDoFDelta[anAttr->getKind()]; + if (anAttr) { + aDoF -= aDoFDelta[anAttr->getKind()]; + std::list aPtAttrs = anAttr->data()->attributes(GeomDataAPI_Point2D::typeId()); + aPoints.insert(aPtAttrs.begin(), aPtAttrs.end()); + } } + + // Check whether feature's points are already coincident with fixed points. + // In this case we need to revert decrease of DoF for these points. + // If the coordinates of fixed points are different, it will be processed by solver. + for (int k = 0; k < i; ++k) { + FeaturePtr aFeature = aSketch->subFeature(k); + if (aFeature->getKind() != SketchPlugin_ConstraintCoincidence::ID()) + continue; + AttributePtr aCoincPoint[2] = {AttributePtr(), AttributePtr()}; + for (int j = 0; j < 2; ++j) { + AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast( + aFeature->attribute(SketchPlugin_Constraint::ATTRIBUTE(j))); + if (!aRefAttr) + continue; + if (!aRefAttr->isObject()) + aCoincPoint[j] = aRefAttr->attr(); + else { + FeaturePtr anAttr = ModelAPI_Feature::feature(aRefAttr->object()); + if (anAttr && anAttr->getKind() == SketchPlugin_Point::ID()) + aCoincPoint[j] = anAttr->attribute(SketchPlugin_Point::COORD_ID()); + } + } + if (aCoincPoint[0] && aCoincPoint[1]) { + if ((aFixedPoints.find(aCoincPoint[0]) != aFixedPoints.end() && + aPoints.find(aCoincPoint[1]) != aPoints.end()) || + (aFixedPoints.find(aCoincPoint[1]) != aFixedPoints.end() && + aPoints.find(aCoincPoint[0]) != aPoints.end())) + aDoF += 2; // point already fixed + } + } + // store fixed points + aFixedPoints.insert(aPoints.begin(), aPoints.end()); } else if (aFeature->getKind() == SketchPlugin_ConstraintMirror::ID() || aFeature->getKind() == SketchPlugin_MultiRotation::ID() || @@ -552,6 +795,8 @@ void SketchSolver_Manager::degreesOfFreedom() FeaturePtr aSub = ModelAPI_Feature::feature(*anObjIt); aDoF -= aDoFDelta[aSub->getKind()] * aNbCopies; } + // collect points and their copies for correct calculation of DoF for coincident points + collectPointsAndCopies(aFeature, aPointsInMultiConstraints); } } @@ -569,11 +814,12 @@ void SketchSolver_Manager::degreesOfFreedom() continue; // nothing is changed myDoF[aDoFIt->first] = aDoFIt->second; // change attribute value - char aValue[10]; - _itoa_s(aDoFIt->second, aValue, 10); - aDoFIt->first->data()->string(SketchPlugin_Sketch::SOLVER_DOF())->setValue( - "DOF(degree of freedom) = "+ std::string(aValue)); - Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED)); + std::ostringstream aStream; + if (aDoFIt->second == 0) + aStream << "Sketch fully fixed (DOF = " << aDoFIt->second << ")"; + else + aStream << "DOF (degree of freedom) = " << aDoFIt->second; + aDoFIt->first->data()->string(SketchPlugin_Sketch::SOLVER_DOF())->setValue(aStream.str()); } }